Comment node. Extra root level for XML parsed data1
[yaz-moved-to-github.git] / retrieval / d1_read.c
1 /*
2  * Copyright (c) 1995-2002, Index Data.
3  * See the file LICENSE for details.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Id: d1_read.c,v 1.43 2002-05-21 07:43:16 adam Exp $
7  */
8
9 #include <assert.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12
13 #include <yaz/xmalloc.h>
14 #include <yaz/log.h>
15 #include <yaz/data1.h>
16
17 /*
18  * get the tag which is the immediate parent of this node (this may mean
19  * traversing intermediate things like variants and stuff.
20  */
21 data1_node *get_parent_tag (data1_handle dh, data1_node *n)
22 {
23     for (; n && n->which != DATA1N_root; n = n->parent)
24         if (n->which == DATA1N_tag)
25             return n;
26     return 0;
27 }
28
29 data1_node *data1_mk_node (data1_handle dh, NMEM m)
30 {
31     return data1_mk_node2 (dh, m, DATA1N_root, 0);
32 }
33
34 data1_node *data1_mk_node_type (data1_handle dh, NMEM m, int type)
35 {
36     return data1_mk_node2 (dh, m, type, 0);
37 }
38
39 data1_node *data1_mk_node2 (data1_handle dh, NMEM m, int type,
40                             data1_node *parent)
41 {
42     data1_node *r;
43     
44     r = (data1_node *)nmem_malloc(m, sizeof(*r));
45     r->next = r->child = r->last_child = 0;
46     r->destroy = 0;
47
48     if (!parent)
49     {
50         r->root = r;
51     }
52     else
53     {
54         r->root = parent->root;
55         r->parent = parent;
56         if (!parent->child)
57             parent->child = parent->last_child = r;
58         else
59             parent->last_child->next = r;
60         parent->last_child = r;
61     }
62     r->which = type;
63     switch(type)
64     {
65     case DATA1N_tag:
66         r->u.tag.tag = 0;
67         r->u.tag.element = 0;
68         r->u.tag.no_data_requested = 0;
69         r->u.tag.node_selected = 0;
70         r->u.tag.make_variantlist = 0;
71         r->u.tag.get_bytes = -1;
72         r->u.tag.attributes = 0;
73         break;
74     case DATA1N_root:
75         r->u.root.type = 0;
76         r->u.root.absyn = 0;
77         break;
78     case DATA1N_data:
79         r->u.data.data = 0;
80         r->u.data.len = 0;
81         r->u.data.what = 0;
82         r->u.data.formatted_text = 0;
83         break;
84     case DATA1N_variant:
85         r->u.variant.type = 0;
86         r->u.variant.value = 0;
87         break;
88     default:
89         logf (LOG_WARN, "data_mk_node_type. bad type = %d\n", type);
90     }
91     return r;
92 }
93
94 void data1_free_tree (data1_handle dh, data1_node *t)
95 {
96     data1_node *p = t->child, *pn;
97
98     while (p)
99     {
100         pn = p->next;
101         data1_free_tree (dh, p);
102         p = pn;
103     }
104     if (t->destroy)
105         (*t->destroy)(t);
106 }
107
108 data1_node *data1_mk_root (data1_handle dh, NMEM nmem,  const char *name)
109 {
110     data1_absyn *absyn = data1_get_absyn (dh, name);
111     data1_node *res;
112     if (!absyn)
113     {
114         yaz_log(LOG_WARN, "Unable to acquire abstract syntax " "for '%s'",
115                 name); 
116         /* It's now OK for a record not to have an absyn */
117     }
118     res = data1_mk_node2 (dh, nmem, DATA1N_root, 0);
119     res->u.root.type = data1_insert_string (dh, res, nmem, name);
120     res->u.root.absyn = absyn;
121     return res;
122 }
123
124 data1_node *data1_mk_tag_n (data1_handle dh, NMEM nmem, 
125                             const char *tag, size_t len, const char **attr,
126                             data1_node *at)
127 {
128     data1_node *partag = get_parent_tag(dh, at);
129     data1_node *res = data1_mk_node2 (dh, nmem, DATA1N_tag, at);
130     data1_element *e = NULL;
131     data1_xattr **p;
132     
133     res->u.tag.tag = data1_insert_string_n (dh, res, nmem, tag, len);
134     
135     if (partag)
136         e = partag->u.tag.element;
137     res->u.tag.element =
138         data1_getelementbytagname (dh, at->root->u.root.absyn,
139                                    e, res->u.tag.tag);
140     p = &res->u.tag.attributes;
141     while (attr && *attr)
142     {
143         *p = (data1_xattr*) nmem_malloc (nmem, sizeof(**p));
144         (*p)->name = nmem_strdup (nmem, *attr++);
145         (*p)->value = nmem_strdup (nmem, *attr++);
146         p = &(*p)->next;
147     }
148     *p = 0;
149     return res;
150 }
151
152 data1_node *data1_mk_tag (data1_handle dh, NMEM nmem,
153                           const char *tag, const char **attr, data1_node *at) 
154 {
155     return data1_mk_tag_n (dh, nmem, tag, strlen(tag), attr, at);
156 }
157
158 data1_node *data1_search_tag (data1_handle dh, data1_node *n,
159                               const char *tag)
160 {
161     for (; n; n = n->next)
162         if (n->which == DATA1N_tag && n->u.tag.tag &&
163             !yaz_matchstr (tag, n->u.tag.tag))
164         {
165             return n;
166         }
167     return 0;
168 }
169
170 data1_node *data1_mk_tag_uni (data1_handle dh, NMEM nmem, 
171                               const char *tag, data1_node *at)
172 {
173     data1_node *node = data1_search_tag (dh, at->child, tag);
174     if (!node)
175         node = data1_mk_tag (dh, nmem, tag, 0 /* attr */, at);
176     else
177         node->child = node->last_child = 0;
178     return node;
179 }
180
181
182 data1_node *data1_mk_text_n (data1_handle dh, NMEM mem,
183                              const char *buf, size_t len, data1_node *parent)
184 {
185     data1_node *res = data1_mk_node2 (dh, mem, DATA1N_data, parent);
186     res->u.data.what = DATA1I_text;
187     res->u.data.len = len;
188     
189     res->u.data.data = data1_insert_string_n (dh, res, mem, buf, len);
190     return res;
191 }
192
193 data1_node *data1_mk_text (data1_handle dh, NMEM mem,
194                            const char *buf, data1_node *parent)
195 {
196     return data1_mk_text_n (dh, mem, buf, strlen(buf), parent);
197 }
198
199 data1_node *data1_mk_comment_n (data1_handle dh, NMEM mem,
200                                 const char *buf, size_t len,
201                                 data1_node *parent)
202 {
203     data1_node *res = data1_mk_node2 (dh, mem, DATA1N_comment, parent);
204     res->u.data.what = DATA1I_text;
205     res->u.data.len = len;
206     
207     res->u.data.data = data1_insert_string_n (dh, res, mem, buf, len);
208     return res;
209 }
210
211 data1_node *data1_mk_comment (data1_handle dh, NMEM mem,
212                               const char *buf, data1_node *parent)
213 {
214     return data1_mk_comment_n (dh, mem, buf, strlen(buf), parent);
215 }
216
217 char *data1_insert_string_n (data1_handle dh, data1_node *res,
218                              NMEM m, const char *str, size_t len)
219 {
220     char *b;
221     if (len >= DATA1_LOCALDATA)
222         b = nmem_malloc (m, len+1);
223     else
224         b = res->lbuf;
225     memcpy (b, str, len);
226     b[len] = 0;
227     return b;
228 }
229
230 char *data1_insert_string (data1_handle dh, data1_node *res,
231                            NMEM m, const char *str)
232 {
233     return data1_insert_string_n (dh, res, m, str, strlen(str));
234 }
235
236 static data1_node *data1_add_insert_taggeddata(data1_handle dh,
237                                                data1_node *at,
238                                                const char *tagname, NMEM m,
239                                                int local_allowed)
240 {
241     data1_node *root = at->root;
242     data1_node *partag = get_parent_tag (dh, at);
243     data1_element *e = NULL;
244     data1_node *datn = 0;
245     data1_node *tagn = 0;
246
247     if (partag)
248         e = partag->u.tag.element;
249     e = data1_getelementbytagname (dh, root->u.root.absyn, e, tagname);
250     if (local_allowed || e)
251     {
252         tagn = data1_mk_node2 (dh, m, DATA1N_tag, at);
253         tagn->u.tag.tag = data1_insert_string (dh, tagn, m, tagname);
254         tagn->u.tag.element = e;
255         datn = data1_mk_node2 (dh, m, DATA1N_data, tagn);
256     }
257     return datn;
258 }
259
260 data1_node *data1_mk_tag_data(data1_handle dh, data1_node *at,
261                               const char *tagname, NMEM m)
262 {
263     return data1_add_insert_taggeddata (dh, at, tagname, m, 1);
264 }
265
266
267 /*
268  * Insert a tagged node into the record root as first child of the node at
269  * which should be root or tag itself). Returns pointer to the data node,
270  * which can then be modified.
271  */
272 data1_node *data1_mk_tag_data_wd(data1_handle dh, data1_node *at,
273                                  const char *tagname, NMEM m)
274 {
275     return data1_add_insert_taggeddata (dh, at, tagname, m, 0);
276 }
277
278 data1_node *data1_insert_taggeddata (data1_handle dh, data1_node *root,
279                                      data1_node *at, const char *tagname,
280                                      NMEM m)
281 {
282     return data1_add_insert_taggeddata (dh, at, tagname, m, 0);
283 }
284
285 data1_node *data1_add_taggeddata (data1_handle dh, data1_node *root,
286                                   data1_node *at, const char *tagname,
287                                   NMEM m)
288 {
289     return data1_add_insert_taggeddata (dh, at, tagname, m, 1);
290 }
291
292 data1_node *data1_mk_tag_data_int (data1_handle dh, data1_node *at,
293                                    const char *tag, int num,
294                                    NMEM nmem)
295 {
296     data1_node *node_data;
297     
298     node_data = data1_mk_tag_data (dh, at, tag, nmem);
299     if (!node_data)
300         return 0;
301     node_data->u.data.what = DATA1I_num;
302     node_data->u.data.data = node_data->lbuf;
303     sprintf (node_data->u.data.data, "%d", num);
304     node_data->u.data.len = strlen (node_data->u.data.data);
305     return node_data;
306 }
307
308 data1_node *data1_mk_tag_data_oid (data1_handle dh, data1_node *at,
309                                    const char *tag, Odr_oid *oid,
310                                    NMEM nmem)
311 {
312     data1_node *node_data;
313     char str[128], *p = str;
314     Odr_oid *ii;
315     
316     node_data = data1_mk_tag_data (dh, at, tag, nmem);
317     if (!node_data)
318         return 0;
319     
320     for (ii = oid; *ii >= 0; ii++)
321     {
322         if (ii != oid)
323             *p++ = '.';
324         sprintf (p, "%d", *ii);
325         p += strlen (p);
326     }
327     node_data->u.data.what = DATA1I_oid;
328     node_data->u.data.len = strlen (str);
329     node_data->u.data.data = data1_insert_string (dh, node_data, nmem, str);
330     return node_data;
331 }
332
333
334 data1_node *data1_mk_tag_data_text (data1_handle dh, data1_node *at,
335                                     const char *tag, const char *str,
336                                     NMEM nmem)
337 {
338     data1_node *node_data;
339     
340     node_data = data1_mk_tag_data (dh, at, tag, nmem);
341     if (!node_data)
342         return 0;
343     node_data->u.data.what = DATA1I_text;
344     node_data->u.data.len = strlen (str);
345     node_data->u.data.data = data1_insert_string (dh, node_data, nmem, str);
346     return node_data;
347 }
348
349
350 data1_node *data1_mk_tag_data_text_uni (data1_handle dh, data1_node *at,
351                                         const char *tag, const char *str,
352                                         NMEM nmem)
353 {
354     data1_node *node = data1_search_tag (dh, at->child, tag);
355     if (!node)
356         return data1_mk_tag_data_text (dh, at, tag, str, nmem);
357     else
358     {
359         data1_node *node_data = node->child;
360         node_data->u.data.what = DATA1I_text;
361         node_data->u.data.len = strlen (str);
362         node_data->u.data.data = data1_insert_string (dh, node_data,
363                                                       nmem, str);
364         node_data->child = node_data->last_child = 0;
365         return node_data;
366     }
367 }
368
369
370 data1_xattr *data1_read_xattr (data1_handle dh, NMEM m,
371                                int (*get_byte)(void *fh), void *fh,
372                                WRBUF wrbuf, int *ch)
373 {
374     data1_xattr *p_first = 0;
375     data1_xattr **pp = &p_first;
376     int c = *ch;
377     for (;;)
378     {
379         data1_xattr *p;
380         int len;
381         while (c && d1_isspace(c))
382             c = (*get_byte)(fh);
383         if (!c  || c == '>' || c == '/')
384             break;
385         *pp = p = (data1_xattr *) nmem_malloc (m, sizeof(*p));
386         p->next = 0;
387         pp = &p->next;
388         p->value = 0;
389         
390         wrbuf_rewind(wrbuf);
391         while (c && c != '=' && c != '>' && c != '/' && !d1_isspace(c))
392         {
393             wrbuf_putc (wrbuf, c);
394             c = (*get_byte)(fh);
395         }
396         wrbuf_putc (wrbuf, '\0');
397         len = wrbuf_len(wrbuf);
398         p->name = (char*) nmem_malloc (m, len);
399         strcpy (p->name, wrbuf_buf(wrbuf));
400         if (c == '=')
401         {
402             c = (*get_byte)(fh);
403             if (c == '"')
404             {
405                 c = (*get_byte)(fh);    
406                 wrbuf_rewind(wrbuf);
407                 while (c && c != '"')
408                 {
409                     wrbuf_putc (wrbuf, c);
410                     c = (*get_byte)(fh);
411                 }
412                 if (c)
413                     c = (*get_byte)(fh);        
414             }
415             else
416             {
417                 wrbuf_rewind(wrbuf);
418                 while (c && c != '>' && c != '/')
419                 {
420                     wrbuf_putc (wrbuf, c);
421                     c = (*get_byte)(fh);
422                 }
423             }
424             wrbuf_putc (wrbuf, '\0');
425             len = wrbuf_len(wrbuf);
426             p->value = (char*) nmem_malloc (m, len);
427             strcpy (p->value, wrbuf_buf(wrbuf));
428         }
429     }
430     *ch = c;
431     return p_first;
432 }
433
434 /*
435  * Ugh. Sometimes functions just grow and grow on you. This one reads a
436  * 'node' and its children.
437  */
438 data1_node *data1_read_nodex (data1_handle dh, NMEM m,
439                               int (*get_byte)(void *fh), void *fh, WRBUF wrbuf)
440 {
441     data1_node *d1_stack[256];
442     data1_node *res;
443     int c;
444     int level = 0;
445     int line = 1;
446
447     d1_stack[level] = 0;
448     c = (*get_byte)(fh);
449     while (1)
450     {
451         data1_node *parent = level ? d1_stack[level-1] : 0;
452         while (c != '\0' && d1_isspace(c))
453         {
454             if (c == '\n')
455                 line++;
456             c = (*get_byte)(fh);
457         }
458         if (c == '\0')
459             break;
460         
461         if (c == '<') /* beginning of tag */
462         {
463             data1_xattr *xattr;
464
465             char tag[64];
466             char args[256];
467             int null_tag = 0;
468             int end_tag = 0;
469             size_t i = 0;
470
471             c = (*get_byte)(fh);
472             if (c == '/')
473             {
474                 end_tag = 1;
475                 c = (*get_byte)(fh);
476             }
477             else if (c == '!')  /* tags/comments that we don't deal with yet */
478             {
479                 while (c && c != '>')
480                     c = (*get_byte)(fh);
481                 if (c)
482                     c = (*get_byte)(fh);
483                 continue;
484             }
485             while (c && c != '>' && c != '/' && !d1_isspace(c))
486             {
487                 if (i < (sizeof(tag)-1))
488                     tag[i++] = c;
489                 c = (*get_byte)(fh);
490             }
491             tag[i] = '\0';
492             xattr = data1_read_xattr (dh, m, get_byte, fh, wrbuf, &c);
493             args[0] = '\0';
494             if (c == '/')
495             {    /* <tag attrs/> or <tag/> */
496                 null_tag = 1;
497                 c = (*get_byte)(fh);
498             }
499             if (c != '>')
500             {
501                 yaz_log(LOG_WARN, "d1: %d: Malformed tag", line);
502                 return 0;
503             }
504             else
505                 c = (*get_byte)(fh);
506
507             /* End tag? */
508             if (end_tag)       
509             {
510                 if (*tag == '\0')
511                     --level;        /* </> */
512                 else
513                 {                   /* </tag> */
514                     int i = level;
515                     while (i > 0)
516                     {
517                         parent = d1_stack[--i];
518                         if ((parent->which == DATA1N_root &&
519                              !strcmp(tag, parent->u.root.type)) ||
520                             (parent->which == DATA1N_tag &&
521                              !strcmp(tag, parent->u.tag.tag)))
522                         {
523                             level = i;
524                             break;
525                         }
526                     }
527                     if (i != level)
528                     {
529                         yaz_log (LOG_WARN, "%d: no begin tag for %s",
530                                  line, tag);
531                         break;
532                     }
533                 }
534                 if (level == 0)
535                     return d1_stack[0];
536                 continue;
537             }   
538             if (level == 0) /* root ? */
539             {
540                 res = data1_mk_root (dh, m, tag);
541             }
542             else if (!strcmp(tag, "var"))
543             {
544                 char tclass[DATA1_MAX_SYMBOL], type[DATA1_MAX_SYMBOL];
545                 data1_vartype *tp;
546                 int val_offset;
547                 
548                 if (sscanf(args, "%s %s %n", tclass, type, &val_offset) != 2)
549                 {
550                     yaz_log(LOG_WARN, "Malformed variant triple at '%s'", tag);
551                     continue;
552                 }
553                 if (!(tp =
554                       data1_getvartypebyct(dh,
555                                            parent->root->u.root.absyn->varset,
556                                            tclass, type)))
557                     continue;
558                 /*
559                  * If we're the first variant in this group, create a parent 
560                  * variant, and insert it before the current variant.
561                  */
562                 if (parent->which != DATA1N_variant)
563                 {
564                     res = data1_mk_node2 (dh, m, DATA1N_variant, parent);
565                 }
566                 else
567                 {
568                     /*
569                      * now determine if one of our ancestor triples is of
570                      * same type. If so, we break here.
571                      */
572                     int i;
573                     for (i = level-1; d1_stack[i]->which==DATA1N_variant; --i)
574                         if (d1_stack[i]->u.variant.type == tp)
575                         {
576                             level = i;
577                             break;
578                         }
579                     res = data1_mk_node2 (dh, m, DATA1N_variant, parent);
580                     res->u.variant.type = tp;
581                     res->u.variant.value =
582                         data1_insert_string (dh, res, m, args + val_offset);
583                 }
584             }
585             else 
586             {
587                 /* tag.. acquire our element in the abstract syntax */
588                 res = data1_mk_tag (dh, m, tag, 0 /* attr */, parent);
589                 res->u.tag.attributes = xattr;
590             }
591             d1_stack[level] = res;
592             d1_stack[level+1] = 0;
593             if (level < 250 && !null_tag)
594                 ++level;
595         }
596         else /* != '<'... this is a body of text */
597         {
598             const char *src;
599             char *dst;
600             int len, prev_char = 0;
601             
602             if (level == 0)
603             {
604                 c = (*get_byte)(fh);
605                 continue;
606             }
607             res = data1_mk_node2 (dh, m, DATA1N_data, parent);
608             res->u.data.what = DATA1I_text;
609             res->u.data.formatted_text = 0;
610             d1_stack[level] = res;
611             
612             wrbuf_rewind(wrbuf);
613
614             while (c && c != '<')
615             {
616                 wrbuf_putc (wrbuf, c);
617                 c = (*get_byte)(fh);
618             }
619             len = wrbuf_len(wrbuf);
620
621             /* use local buffer of nmem if too large */
622             if (len >= DATA1_LOCALDATA)
623                 res->u.data.data = (char*) nmem_malloc (m, len);
624             else
625                 res->u.data.data = res->lbuf;
626             
627             /* read "data" and transfer while removing white space */
628             dst = res->u.data.data;
629             for (src = wrbuf_buf(wrbuf); --len >= 0; src++)
630             {
631                 if (*src == '\n')
632                     line++;
633                 if (d1_isspace (*src))
634                     prev_char = ' ';
635                 else
636                 {
637                     if (prev_char)
638                     {
639                         *dst++ = prev_char;
640                         prev_char = 0;
641                     }
642                     *dst++ = *src;
643                 }
644             }
645             res->u.data.len = dst - res->u.data.data;
646         }
647     }
648     return 0;
649 }
650
651 int getc_mem (void *fh)
652 {
653     const char **p = (const char **) fh;
654     if (**p)
655         return *(*p)++;
656     return 0;
657 }
658
659 data1_node *data1_read_node (data1_handle dh, const char **buf, NMEM m)
660 {
661     WRBUF wrbuf = wrbuf_alloc();
662     data1_node *node;
663
664     node = data1_read_nodex(dh, m, getc_mem, (void *) (buf), wrbuf);
665     wrbuf_free (wrbuf, 1);
666     return node;
667 }
668
669 /*
670  * Read a record in the native syntax.
671  */
672 data1_node *data1_read_record(data1_handle dh,
673                               int (*rf)(void *, char *, size_t), void *fh,
674                               NMEM m)
675 {
676     int *size;
677     char **buf = data1_get_read_buf (dh, &size);
678     const char *bp;
679     int rd = 0, res;
680     
681     if (!*buf)
682         *buf = (char *)xmalloc(*size = 4096);
683     
684     for (;;)
685     {
686         if (rd + 2048 >= *size && !(*buf =(char *)xrealloc(*buf, *size *= 2)))
687             abort();
688         if ((res = (*rf)(fh, *buf + rd, 2048)) <= 0)
689         {
690             if (!res)
691             {
692                 bp = *buf;
693                 (*buf)[rd] = '\0';
694                 return data1_read_node(dh, &bp, m);
695             }
696             else
697                 return 0;
698         }
699         rd += res;
700     }
701 }
702
703 data1_node *data1_read_sgml (data1_handle dh, NMEM m, const char *buf)
704 {
705     const char *bp = buf;
706     return data1_read_node (dh, &bp, m);
707 }
708