MARC XML
[yaz-moved-to-github.git] / util / marcdisp.c
1 /*
2  * Copyright (c) 1995-2002, Index Data
3  * See the file LICENSE for details.
4  *
5  * $Id: marcdisp.c,v 1.24 2002-12-03 10:03:27 adam Exp $
6  */
7
8 #if HAVE_CONFIG_H
9 #include <config.h>
10 #endif
11
12 #include <stdio.h>
13 #include <string.h>
14 #include <ctype.h>
15 #include <yaz/marcdisp.h>
16 #include <yaz/wrbuf.h>
17 #include <yaz/yaz-util.h>
18
19 int yaz_marc_decode (const char *buf, WRBUF wr, int debug, int bsize, int xml)
20 {
21     int entry_p;
22     int record_length;
23     int indicator_length;
24     int identifier_length;
25     int base_address;
26     int length_data_entry;
27     int length_starting;
28     int length_implementation;
29
30     record_length = atoi_n (buf, 5);
31     if (record_length < 25)
32     {
33         if (debug)
34         {
35             char str[40];
36             
37             sprintf (str, "Record length %d - aborting\n", record_length);
38             wrbuf_puts (wr, str);
39         }
40         return -1;
41     }
42     /* ballout if bsize is known and record_length is than that */
43     if (bsize != -1 && record_length > bsize)
44         return -1;
45     if (isdigit(buf[10]))
46         indicator_length = atoi_n (buf+10, 1);
47     else
48         indicator_length = 2;
49     if (isdigit(buf[11]))
50         identifier_length = atoi_n (buf+11, 1);
51     else
52         identifier_length = 2;
53     base_address = atoi_n (buf+12, 5);
54
55     length_data_entry = atoi_n (buf+20, 1);
56     length_starting = atoi_n (buf+21, 1);
57     length_implementation = atoi_n (buf+22, 1);
58
59     if (xml)
60     {
61         char str[80];
62         int i;
63         switch(xml)
64         {
65         case YAZ_MARC_XML:
66             wrbuf_puts (wr, "<iso2709\n");
67             sprintf (str, " RecordStatus=\"%c\"\n", buf[5]);
68             wrbuf_puts (wr, str);
69             sprintf (str, " TypeOfRecord=\"%c\"\n", buf[6]);
70             wrbuf_puts (wr, str);
71             for (i = 1; i<=19; i++)
72             {
73                 sprintf (str, " ImplDefined%d=\"%c\"\n", i, buf[6+i]);
74                 wrbuf_puts (wr, str);
75             }
76             wrbuf_puts (wr, ">\n");
77             break;
78         case YAZ_MARC_OAIMARC:
79             wrbuf_puts(
80                 wr,
81                 "<oai_marc xmlns=\"http://www.openarchives.org/OIA/oai_marc\""
82                 "\n"
83                 " xmlns:xsi=\"http://www.w3.org/2000/10/XMLSchema-instance\""
84                 "\n"
85                 " xsi:schemaLocation=\"http://www.openarchives.org/OAI/oai_marc.xsd\""
86                 "\n"
87                 );
88             
89             sprintf (str, " status=\"%c\" type=\"%c\" catForm=\"%c\">\n",
90                      buf[5], buf[6], buf[7]);
91             wrbuf_puts (wr, str);
92             break;
93         case YAZ_MARC_MARCXML:
94             wrbuf_printf(
95                 wr,
96                 "<collection xmlns=\"http://www.loc.gov/MARC21/slim\">\n"
97                 "  <record>\n"
98                 "    <leader>%.24s</leader>\n", buf);
99             break;
100         }
101     }
102     if (debug)
103     {
104         char str[40];
105
106         if (xml)
107             wrbuf_puts (wr, "<!--\n");
108         sprintf (str, "Record length         %5d\n", record_length);
109         wrbuf_puts (wr, str);
110         sprintf (str, "Indicator length      %5d\n", indicator_length);
111         wrbuf_puts (wr, str);
112         sprintf (str, "Identifier length     %5d\n", identifier_length);
113         wrbuf_puts (wr, str);
114         sprintf (str, "Base address          %5d\n", base_address);
115         wrbuf_puts (wr, str);
116         sprintf (str, "Length data entry     %5d\n", length_data_entry);
117         wrbuf_puts (wr, str);
118         sprintf (str, "Length starting       %5d\n", length_starting);
119         wrbuf_puts (wr, str);
120         sprintf (str, "Length implementation %5d\n", length_implementation);
121         wrbuf_puts (wr, str);
122         if (xml)
123             wrbuf_puts (wr, "-->\n");
124     }
125
126     for (entry_p = 24; buf[entry_p] != ISO2709_FS; )
127     {
128         entry_p += 3+length_data_entry+length_starting;
129         if (entry_p >= record_length)
130             return -1;
131     }
132     base_address = entry_p+1;
133     for (entry_p = 24; buf[entry_p] != ISO2709_FS; )
134     {
135         int data_length;
136         int data_offset;
137         int end_offset;
138         int i, j;
139         char tag[4];
140         int identifier_flag = 1;
141
142         memcpy (tag, buf+entry_p, 3);
143         entry_p += 3;
144         tag[3] = '\0';
145         data_length = atoi_n (buf+entry_p, length_data_entry);
146         entry_p += length_data_entry;
147         data_offset = atoi_n (buf+entry_p, length_starting);
148         entry_p += length_starting;
149         i = data_offset + base_address;
150         end_offset = i+data_length-1;
151         
152         if (indicator_length < 4 && indicator_length > 0)
153         {
154             if (buf[i + indicator_length] != ISO2709_IDFS)
155                 identifier_flag = 0;
156         }
157         else if (!memcmp (tag, "00", 2))
158             identifier_flag = 0;
159         
160         switch(xml)
161         {
162         case YAZ_MARC_LINE:
163             if (debug)
164                 wrbuf_puts (wr, "Tag: ");
165             wrbuf_puts (wr, tag);
166             wrbuf_puts (wr, " ");
167             break;
168         case YAZ_MARC_XML:
169             wrbuf_printf (wr, "<field tag=\"%s\"", tag);
170             break;
171         case YAZ_MARC_OAIMARC:
172             if (identifier_flag)
173                 wrbuf_printf (wr, "  <varfield id=\"%s\"", tag);
174             else
175                 wrbuf_printf (wr, "  <fixfield id=\"%s\"", tag);
176             break;
177         case YAZ_MARC_MARCXML:
178             if (identifier_flag)
179                 wrbuf_printf (wr, "    <datafield tag=\"%s\"", tag);
180             else
181                 wrbuf_printf (wr, "    <controlfield tag=\"%s\"", tag);
182         }
183         
184         if (identifier_flag)
185         {
186             for (j = 0; j<indicator_length; j++, i++)
187             {
188                 switch(xml)
189                 {
190                 case YAZ_MARC_LINE:
191                     if (debug)
192                         wrbuf_puts (wr, " Ind: ");
193                     wrbuf_putc (wr, buf[i]);
194                     break;
195                 case YAZ_MARC_XML:
196                     wrbuf_printf (wr, " Indicator%d=\"%c\"", j+1, buf[i]);
197                     break;
198                 case YAZ_MARC_OAIMARC:
199                     wrbuf_printf (wr, " i%d=\"%c\"", j+1, buf[i]);
200                     break;
201                 case YAZ_MARC_MARCXML:
202                     wrbuf_printf (wr, " ind%d=\"%c\"", j+1, buf[i]);
203                 }
204             }
205         }
206         if (xml)
207         {
208             wrbuf_puts (wr, ">");
209             if (identifier_flag)
210                 wrbuf_puts (wr, "\n");
211         }
212         else
213         {
214             if (debug && !xml)
215                 wrbuf_puts (wr, " Fields: ");
216         }
217         while (buf[i] != ISO2709_RS && buf[i] != ISO2709_FS && i < end_offset)
218         {
219             if (identifier_flag)
220             {
221                 i++;
222                 switch(xml)
223                 {
224                 case YAZ_MARC_LINE: 
225                     wrbuf_puts (wr, " $"); 
226                     for (j = 1; j<identifier_length; j++, i++)
227                         wrbuf_putc (wr, buf[i]);
228                     wrbuf_putc (wr, ' ');
229                     break;
230                 case YAZ_MARC_XML:
231                         wrbuf_puts (wr, "  <subfield code=\"");
232                     for (j = 1; j<identifier_length; j++, i++)
233                         wrbuf_putc (wr, buf[i]);
234                     wrbuf_puts (wr, "\">");
235                     break;
236                 case YAZ_MARC_OAIMARC:
237                     wrbuf_puts (wr, "    <subfield label=\"");
238                     for (j = 1; j<identifier_length; j++, i++)
239                         wrbuf_putc (wr, buf[i]);
240                     wrbuf_puts (wr, "\">");
241                     break;
242                 case YAZ_MARC_MARCXML:
243                     wrbuf_puts (wr, "      <subfield code=\"");
244                     for (j = 1; j<identifier_length; j++, i++)
245                         wrbuf_putc (wr, buf[i]);
246                     wrbuf_puts (wr, "\">");
247                     break;
248                 }
249                 while (buf[i] != ISO2709_RS && buf[i] != ISO2709_IDFS &&
250                        buf[i] != ISO2709_FS && i < end_offset)
251                 {
252                     if (xml && buf[i] == '<')
253                         wrbuf_puts(wr, "&#x003C;");
254                     else if (xml && buf[i] == '&')
255                         wrbuf_puts(wr, "&#x0026;");
256                     else
257                         wrbuf_putc (wr, buf[i]);
258                     i++;
259                 }
260                 if (xml)
261                     wrbuf_puts (wr, "</subfield>\n");
262             }
263             else
264             {
265                 if (xml && buf[i] == '<')
266                     wrbuf_puts(wr, "&lt;");
267                 else if (xml && buf[i] == '&')
268                     wrbuf_puts(wr, "&amp;");
269                 else if (xml && buf[i] == '"')
270                     wrbuf_puts(wr, "&quot;");
271                 else
272                     wrbuf_putc (wr, buf[i]);
273                 i++;
274             }
275         }
276         if (!xml)
277             wrbuf_putc (wr, '\n');
278         if (i < end_offset)
279             wrbuf_puts (wr, "  <!-- separator but not at end of field -->\n");
280         if (buf[i] != ISO2709_RS && buf[i] != ISO2709_FS)
281             wrbuf_puts (wr, "  <!-- no separator at end of field -->\n");
282         switch(xml)
283         {
284         case YAZ_MARC_LINE: 
285             break;
286         case YAZ_MARC_XML:
287             wrbuf_puts (wr, "</field>\n");
288             break;
289         case YAZ_MARC_OAIMARC:
290             if (identifier_flag)
291                 wrbuf_puts (wr, "  </varfield>\n");
292             else
293                 wrbuf_puts (wr, "  </fixfield>\n");
294             break;
295         case YAZ_MARC_MARCXML:
296             if (identifier_flag)
297                 wrbuf_puts (wr, "    </datafield>\n");
298             else
299                 wrbuf_puts (wr, "    </controlfield>\n");
300             break;
301         }
302     }
303     switch(xml)
304     {
305     case YAZ_MARC_LINE:
306         wrbuf_puts (wr, "");
307         break;
308     case YAZ_MARC_XML:
309         wrbuf_puts (wr, "</iso2709>\n");
310         break;
311     case YAZ_MARC_OAIMARC:
312         wrbuf_puts (wr, "</oai_marc>\n");
313         break;
314     case YAZ_MARC_MARCXML:
315         wrbuf_puts (wr, "  </record>\n</collection>\n");
316         break;
317     }
318     return record_length;
319 }
320
321 int marc_display_wrbuf (const char *buf, WRBUF wr, int debug,
322                         int bsize)
323 {
324     return yaz_marc_decode (buf, wr, debug, bsize, 0);
325 }
326
327 int marc_display_exl (const char *buf, FILE *outf, int debug, int length)
328 {
329     int record_length;
330
331     WRBUF wrbuf = wrbuf_alloc ();
332     record_length = marc_display_wrbuf (buf, wrbuf, debug, length);
333     if (!outf)
334         outf = stdout;
335     if (record_length > 0)
336         fwrite (wrbuf_buf(wrbuf), 1, wrbuf_len(wrbuf), outf);
337     wrbuf_free (wrbuf, 1);
338     return record_length;
339 }
340
341 int marc_display_ex (const char *buf, FILE *outf, int debug)
342 {
343     return marc_display_exl (buf, outf, debug, -1);
344 }
345
346 int marc_display (const char *buf, FILE *outf)
347 {
348     return marc_display_ex (buf, outf, 0);
349 }
350
351