]> mj.ucw.cz Git - libucw.git/blob - sherlock/xml/dtd.c
fbe7a325e128335bd724fab3c66841a17b356b65
[libucw.git] / sherlock / xml / dtd.c
1 /*
2  *      Sherlock Library -- A simple XML parser
3  *
4  *      (c) 2007 Pavel Charvat <pchar@ucw.cz>
5  *
6  *      This software may be freely distributed and used according to the terms
7  *      of the GNU Lesser General Public License.
8  */
9
10 #undef LOCAL_DEBUG
11
12 #include "sherlock/sherlock.h"
13 #include "sherlock/xml/xml.h"
14 #include "sherlock/xml/dtd.h"
15 #include "sherlock/xml/common.h"
16 #include "lib/fastbuf.h"
17 #include "lib/ff-unicode.h"
18
19 /* Notations */
20
21 #define HASH_PREFIX(x) xml_dtd_notns_##x
22 #define HASH_NODE struct xml_dtd_notn
23 #define HASH_KEY_STRING name
24 #define HASH_ZERO_FILL
25 #define HASH_TABLE_DYNAMIC
26 #define HASH_WANT_LOOKUP
27 #define HASH_GIVE_ALLOC
28 #define HASH_TABLE_ALLOC
29 XML_HASH_GIVE_ALLOC
30 #include "lib/hashtable.h"
31
32 /* General entities */
33
34 #define HASH_PREFIX(x) xml_dtd_ents_##x
35 #define HASH_NODE struct xml_dtd_ent
36 #define HASH_KEY_STRING name
37 #define HASH_ZERO_FILL
38 #define HASH_TABLE_DYNAMIC
39 #define HASH_WANT_FIND
40 #define HASH_WANT_LOOKUP
41 #define HASH_GIVE_ALLOC
42 #define HASH_TABLE_ALLOC
43 XML_HASH_GIVE_ALLOC
44 #include "lib/hashtable.h"
45
46 static struct xml_dtd_ent *
47 xml_dtd_declare_trivial_ent(struct xml_context *ctx, char *name, uns uni)
48 {
49   struct xml_dtd *dtd = ctx->dtd;
50   struct xml_dtd_ent *ent = xml_dtd_ents_lookup(dtd->tab_ents, name);
51   if (ent->flags & XML_DTD_ENT_DECLARED)
52     {
53       xml_warn(ctx, "Entity &%s; already declared", name);
54       return NULL;
55     }
56   slist_add_tail(&dtd->ents, &ent->n);
57   ent->flags = XML_DTD_ENT_DECLARED | XML_DTD_ENT_TRIVIAL_UNI;
58   ent->uni = uni;
59   return ent;
60 }
61
62 static void
63 xml_dtd_declare_default_ents(struct xml_context *ctx)
64 {
65   xml_dtd_declare_trivial_ent(ctx, "lt", 60);
66   xml_dtd_declare_trivial_ent(ctx, "gt", 62);
67   xml_dtd_declare_trivial_ent(ctx, "amp", 38);
68   xml_dtd_declare_trivial_ent(ctx, "apos", 39);
69   xml_dtd_declare_trivial_ent(ctx, "quot", 34);
70 }
71
72 struct xml_dtd_ent *
73 xml_dtd_find_ent(struct xml_context *ctx, char *name)
74 {
75   struct xml_dtd *dtd = ctx->dtd;
76   if (ctx->h_resolve_entity)
77     return ctx->h_resolve_entity(ctx, name);
78   else if (dtd)
79     {
80       struct xml_dtd_ent *ent = xml_dtd_ents_find(dtd->tab_ents, name);
81       return !ent ? NULL : (ent->flags & XML_DTD_ENT_DECLARED) ? ent : NULL;
82     }
83   else
84     {
85 #define ENT(n, u) ent_##n = { .name = #n, .uni = u, .flags = XML_DTD_ENT_DECLARED | XML_DTD_ENT_TRIVIAL_UNI }
86       static struct xml_dtd_ent ENT(lt, 60), ENT(gt, 62), ENT(amp, 38), ENT(apos, 39), ENT(quot, 34);
87 #undef ENT
88       switch (name[0])
89         {
90           case 'l':
91             if (!strcmp(name, "lt"))
92               return &ent_lt;
93             break;
94           case 'g':
95             if (!strcmp(name, "gt"))
96               return &ent_gt;
97             break;
98           case 'a':
99             if (!strcmp(name, "amp"))
100               return &ent_amp;
101             if (!strcmp(name, "apos"))
102               return &ent_apos;
103             break;
104           case 'q':
105             if (!strcmp(name, "quot"))
106               return &ent_quot;
107             break;
108         }
109       return NULL;
110     }
111 }
112
113 /* Parameter entities */
114
115 static struct xml_dtd_ent *
116 xml_dtd_find_pent(struct xml_context *ctx, char *name)
117 {
118   struct xml_dtd *dtd = ctx->dtd;
119   struct xml_dtd_ent *ent = xml_dtd_ents_find(dtd->tab_pents, name);
120   return !ent ? NULL : (ent->flags & XML_DTD_ENT_DECLARED) ? ent : NULL;
121 }
122
123 /* Elements */
124
125 #define HASH_PREFIX(x) xml_dtd_elems_##x
126 #define HASH_NODE struct xml_dtd_elem
127 #define HASH_KEY_STRING name
128 #define HASH_TABLE_DYNAMIC
129 #define HASH_ZERO_FILL
130 #define HASH_WANT_FIND
131 #define HASH_WANT_LOOKUP
132 #define HASH_GIVE_ALLOC
133 #define HASH_TABLE_ALLOC
134 XML_HASH_GIVE_ALLOC
135 #include "lib/hashtable.h"
136
137 struct xml_dtd_elem *
138 xml_dtd_find_elem(struct xml_context *ctx, char *name)
139 {
140   return ctx->dtd ? xml_dtd_elems_find(ctx->dtd->tab_elems, name) : NULL;
141 }
142
143 /* Element sons */
144
145 struct xml_dtd_enodes_table;
146
147 static inline uns
148 xml_dtd_enodes_hash(struct xml_dtd_enodes_table *tab UNUSED, struct xml_dtd_elem_node *parent, struct xml_dtd_elem *elem)
149 {
150   return hash_pointer(parent) ^ hash_pointer(elem);
151 }
152
153 static inline int
154 xml_dtd_enodes_eq(struct xml_dtd_enodes_table *tab UNUSED, struct xml_dtd_elem_node *parent1, struct xml_dtd_elem *elem1, struct xml_dtd_elem_node *parent2, struct xml_dtd_elem *elem2)
155 {
156   return (parent1 == parent2) && (elem1 == elem2);
157 }
158
159 static inline void
160 xml_dtd_enodes_init_key(struct xml_dtd_enodes_table *tab UNUSED, struct xml_dtd_elem_node *node, struct xml_dtd_elem_node *parent, struct xml_dtd_elem *elem)
161 {
162   node->parent = parent;
163   node->elem = elem;
164 }
165
166 #define HASH_PREFIX(x) xml_dtd_enodes_##x
167 #define HASH_NODE struct xml_dtd_elem_node
168 #define HASH_KEY_COMPLEX(x) x parent, x elem
169 #define HASH_KEY_DECL struct xml_dtd_elem_node *parent, struct xml_dtd_elem *elem
170 #define HASH_GIVE_HASHFN
171 #define HASH_GIVE_EQ
172 #define HASH_GIVE_INIT_KEY
173 #define HASH_TABLE_DYNAMIC
174 #define HASH_ZERO_FILL
175 #define HASH_WANT_FIND
176 #define HASH_WANT_NEW
177 #define HASH_GIVE_ALLOC
178 #define HASH_TABLE_ALLOC
179 XML_HASH_GIVE_ALLOC
180 #include "lib/hashtable.h"
181
182 /* Element attributes */
183
184 struct xml_dtd_attrs_table;
185
186 static inline uns
187 xml_dtd_attrs_hash(struct xml_dtd_attrs_table *tab UNUSED, struct xml_dtd_elem *elem, char *name)
188 {
189   return hash_pointer(elem) ^ hash_string(name);
190 }
191
192 static inline int
193 xml_dtd_attrs_eq(struct xml_dtd_attrs_table *tab UNUSED, struct xml_dtd_elem *elem1, char *name1, struct xml_dtd_elem *elem2, char *name2)
194 {
195   return (elem1 == elem2) && !strcmp(name1, name2);
196 }
197
198 static inline void
199 xml_dtd_attrs_init_key(struct xml_dtd_attrs_table *tab UNUSED, struct xml_dtd_attr *attr, struct xml_dtd_elem *elem, char *name)
200 {
201   attr->elem = elem;
202   attr->name = name;
203 }
204
205 #define HASH_PREFIX(x) xml_dtd_attrs_##x
206 #define HASH_NODE struct xml_dtd_attr
207 #define HASH_ZERO_FILL
208 #define HASH_TABLE_DYNAMIC
209 #define HASH_KEY_COMPLEX(x) x elem, x name
210 #define HASH_KEY_DECL struct xml_dtd_elem *elem, char *name
211 #define HASH_GIVE_HASHFN
212 #define HASH_GIVE_EQ
213 #define HASH_GIVE_INIT_KEY
214 #define HASH_WANT_FIND
215 #define HASH_WANT_NEW
216 #define HASH_GIVE_ALLOC
217 #define HASH_TABLE_ALLOC
218 XML_HASH_GIVE_ALLOC
219 #include "lib/hashtable.h"
220
221 struct xml_dtd_attr *
222 xml_dtd_find_attr(struct xml_context *ctx, struct xml_dtd_elem *elem, char *name)
223 {
224   return ctx->dtd ? xml_dtd_attrs_find(ctx->dtd->tab_attrs, elem, name) : NULL;
225 }
226
227 /* Enumerated attribute values */
228
229 struct xml_dtd_evals_table;
230
231 static inline uns
232 xml_dtd_evals_hash(struct xml_dtd_evals_table *tab UNUSED, struct xml_dtd_attr *attr, char *val)
233 {
234   return hash_pointer(attr) ^ hash_string(val);
235 }
236
237 static inline int
238 xml_dtd_evals_eq(struct xml_dtd_evals_table *tab UNUSED, struct xml_dtd_attr *attr1, char *val1, struct xml_dtd_attr *attr2, char *val2)
239 {
240   return (attr1 == attr2) && !strcmp(val1, val2);
241 }
242
243 static inline void
244 xml_dtd_evals_init_key(struct xml_dtd_evals_table *tab UNUSED, struct xml_dtd_eval *eval, struct xml_dtd_attr *attr, char *val)
245 {
246   eval->attr = attr;
247   eval->val = val;
248 }
249
250 #define HASH_PREFIX(x) xml_dtd_evals_##x
251 #define HASH_NODE struct xml_dtd_eval
252 #define HASH_TABLE_DYNAMIC
253 #define HASH_KEY_COMPLEX(x) x attr, x val
254 #define HASH_KEY_DECL struct xml_dtd_attr *attr, char *val
255 #define HASH_GIVE_HASHFN
256 #define HASH_GIVE_EQ
257 #define HASH_GIVE_INIT_KEY
258 #define HASH_WANT_FIND
259 #define HASH_WANT_NEW
260 #define HASH_GIVE_ALLOC
261 #define HASH_TABLE_ALLOC
262 XML_HASH_GIVE_ALLOC
263 #include "lib/hashtable.h"
264
265 /* Enumerated attribute notations */
266
267 struct xml_dtd_enotns_table;
268
269 static inline uns
270 xml_dtd_enotns_hash(struct xml_dtd_enotns_table *tab UNUSED, struct xml_dtd_attr *attr, struct xml_dtd_notn *notn)
271 {
272   return hash_pointer(attr) ^ hash_pointer(notn);
273 }
274
275 static inline int
276 xml_dtd_enotns_eq(struct xml_dtd_enotns_table *tab UNUSED, struct xml_dtd_attr *attr1, struct xml_dtd_notn *notn1, struct xml_dtd_attr *attr2, struct xml_dtd_notn *notn2)
277 {
278   return (attr1 == attr2) && (notn1 == notn2);
279 }
280
281 static inline void
282 xml_dtd_enotns_init_key(struct xml_dtd_enotns_table *tab UNUSED, struct xml_dtd_enotn *enotn, struct xml_dtd_attr *attr, struct xml_dtd_notn *notn)
283 {
284   enotn->attr = attr;
285   enotn->notn = notn;
286 }
287
288 #define HASH_PREFIX(x) xml_dtd_enotns_##x
289 #define HASH_NODE struct xml_dtd_enotn
290 #define HASH_TABLE_DYNAMIC
291 #define HASH_KEY_COMPLEX(x) x attr, x notn
292 #define HASH_KEY_DECL struct xml_dtd_attr *attr, struct xml_dtd_notn *notn
293 #define HASH_GIVE_HASHFN
294 #define HASH_GIVE_EQ
295 #define HASH_GIVE_INIT_KEY
296 #define HASH_WANT_FIND
297 #define HASH_WANT_NEW
298 #define HASH_GIVE_ALLOC
299 #define HASH_TABLE_ALLOC
300 XML_HASH_GIVE_ALLOC
301 #include "lib/hashtable.h"
302
303 /* DTD initialization/cleanup */
304
305 void
306 xml_dtd_init(struct xml_context *ctx)
307 {
308   if (ctx->dtd)
309     return;
310   struct mempool *pool = mp_new(4096);
311   struct xml_dtd *dtd = ctx->dtd = mp_alloc_zero(pool, sizeof(*ctx->dtd));
312   dtd->pool = pool;
313   xml_dtd_ents_init(dtd->tab_ents = xml_hash_new(pool, sizeof(struct xml_dtd_ents_table)));
314   xml_dtd_ents_init(dtd->tab_pents = xml_hash_new(pool, sizeof(struct xml_dtd_ents_table)));
315   xml_dtd_notns_init(dtd->tab_notns = xml_hash_new(pool, sizeof(struct xml_dtd_notns_table)));
316   xml_dtd_elems_init(dtd->tab_elems = xml_hash_new(pool, sizeof(struct xml_dtd_elems_table)));
317   xml_dtd_enodes_init(dtd->tab_enodes = xml_hash_new(pool, sizeof(struct xml_dtd_enodes_table)));
318   xml_dtd_attrs_init(dtd->tab_attrs = xml_hash_new(pool, sizeof(struct xml_dtd_attrs_table)));
319   xml_dtd_evals_init(dtd->tab_evals = xml_hash_new(pool, sizeof(struct xml_dtd_evals_table)));
320   xml_dtd_enotns_init(dtd->tab_enotns = xml_hash_new(pool, sizeof(struct xml_dtd_enotns_table)));
321   xml_dtd_declare_default_ents(ctx);
322 }
323
324 void
325 xml_dtd_cleanup(struct xml_context *ctx)
326 {
327   if (!ctx->dtd)
328     return;
329   mp_delete(ctx->dtd->pool);
330   ctx->dtd = NULL;
331 }
332
333 void
334 xml_dtd_finish(struct xml_context *ctx)
335 {
336   if (!ctx->dtd)
337     return;
338   // FIXME: validity checks
339 }
340
341 /*** Parsing functions ***/
342
343 /* References to parameter entities */
344
345 void
346 xml_parse_pe_ref(struct xml_context *ctx)
347 {
348   /* PEReference ::= '%' Name ';'
349    * Already parsed: '%' */
350   struct mempool_state state;
351   mp_save(ctx->stack, &state);
352   char *name = xml_parse_name(ctx, ctx->stack);
353   xml_parse_char(ctx, ';');
354   struct xml_dtd_ent *ent = xml_dtd_find_pent(ctx, name);
355   if (!ent)
356     xml_error(ctx, "Unknown entity %%%s;", name);
357   else
358     {
359       TRACE(ctx, "Pushed entity %%%s;", name);
360       mp_restore(ctx->stack, &state);
361       xml_dec(ctx);
362       xml_push_entity(ctx, ent);
363       return;
364     }
365   mp_restore(ctx->stack, &state);
366   xml_dec(ctx);
367 }
368
369 static void
370 xml_parse_dtd_pe(struct xml_context *ctx)
371 {
372   do
373     {
374       xml_skip_char(ctx);
375       xml_inc(ctx);
376       while (xml_peek_cat(ctx) & XML_CHAR_WHITE)
377         xml_skip_char(ctx);
378       xml_parse_pe_ref(ctx);
379     }
380   while (xml_peek_char(ctx) != '%');
381 }
382
383 static inline uns
384 xml_parse_dtd_white(struct xml_context *ctx, uns mandatory)
385 {
386   /* Whitespace or parameter entity */
387   uns cnt = 0;
388   while (xml_peek_cat(ctx) & XML_CHAR_WHITE)
389     {
390       xml_skip_char(ctx);
391       cnt = 1;
392     }
393   if (xml_peek_char(ctx) == '%')
394     {
395       xml_parse_dtd_pe(ctx);
396       return 1;
397     }
398   else if (unlikely(mandatory && !cnt))
399     xml_fatal_expected_white(ctx);
400   return cnt;
401 }
402
403 static void
404 xml_dtd_parse_external_id(struct xml_context *ctx, struct xml_ext_id *eid, uns allow_public)
405 {
406   struct xml_dtd *dtd = ctx->dtd;
407   bzero(eid, sizeof(*eid));
408   uns c = xml_peek_char(ctx);
409   if (c == 'S')
410     {
411       xml_parse_seq(ctx, "SYSTEM");
412       xml_parse_dtd_white(ctx, 1);
413       eid->system_id = xml_parse_system_literal(ctx, dtd->pool);
414     }
415   else if (c == 'P')
416     {
417       xml_parse_seq(ctx, "PUBLIC");
418       xml_parse_dtd_white(ctx, 1);
419       eid->public_id = xml_parse_pubid_literal(ctx, dtd->pool);
420       if (xml_parse_dtd_white(ctx, 0)) // FIXME
421         if ((c = xml_peek_char(ctx)) == '\'' || c == '"' || !allow_public)
422           eid->system_id = xml_parse_system_literal(ctx, dtd->pool);
423     }
424   else
425     xml_fatal(ctx, "Expected an external ID");
426 }
427
428 /* DTD: <!NOTATION ...> */
429
430 void
431 xml_parse_notation_decl(struct xml_context *ctx)
432 {
433   /* NotationDecl ::= '<!NOTATION' S Name S (ExternalID | PublicID) S? '>'
434    * Already parsed: '<!NOTATION' */
435   TRACE(ctx, "parse_notation_decl");
436   struct xml_dtd *dtd = ctx->dtd;
437   xml_parse_dtd_white(ctx, 1);
438
439   struct xml_dtd_notn *notn = xml_dtd_notns_lookup(dtd->tab_notns, xml_parse_name(ctx, dtd->pool));
440   xml_parse_dtd_white(ctx, 1);
441   struct xml_ext_id eid;
442   xml_dtd_parse_external_id(ctx, &eid, 1);
443   xml_parse_dtd_white(ctx, 0);
444   xml_parse_char(ctx, '>');
445
446   if (notn->flags & XML_DTD_NOTN_DECLARED)
447     xml_warn(ctx, "Notation %s already declared", notn->name);
448   else
449     {
450       notn->flags = XML_DTD_NOTN_DECLARED;
451       notn->eid = eid;
452       slist_add_tail(&dtd->notns, &notn->n);
453     }
454   xml_dec(ctx);
455 }
456
457 /* DTD: <!ENTITY ...> */
458
459 void
460 xml_parse_entity_decl(struct xml_context *ctx)
461 {
462   /* Already parsed: '<!ENTITY' */
463   TRACE(ctx, "parse_entity_decl");
464   struct xml_dtd *dtd = ctx->dtd;
465   xml_parse_dtd_white(ctx, 1);
466
467   uns flags = (xml_get_char(ctx) == '%') ? XML_DTD_ENT_PARAMETER : 0;
468   if (flags)
469     xml_parse_dtd_white(ctx, 1);
470   else
471     xml_unget_char(ctx);
472
473   struct xml_dtd_ent *ent = xml_dtd_ents_lookup(flags ? dtd->tab_pents : dtd->tab_ents, xml_parse_name(ctx, dtd->pool));
474   slist *list = flags ? &dtd->pents : &dtd->ents;
475   xml_parse_dtd_white(ctx, 1);
476   if (ent->flags & XML_DTD_ENT_DECLARED)
477     {
478        xml_fatal(ctx, "Entity &%s; already declared, skipping not implemented", ent->name);
479        // FIXME: should be only warning
480     }
481
482   uns c, sep = xml_get_char(ctx);
483   if (sep == '\'' || sep == '"')
484     {
485       /* Internal entity:
486        * EntityValue ::= '"' ([^%&"] | PEReference | Reference)* '"' | "'" ([^%&'] | PEReference | Reference)* "'" */
487       char *p = mp_start_noalign(dtd->pool, 1);
488       while (1)
489         {
490           if ((c = xml_get_char(ctx)) == sep)
491             break;
492           if (c == '%')
493             {
494               // FIXME
495               ASSERT(0);
496               //xml_parse_parameter_ref(ctx);
497               continue;
498             }
499           if (c == '&')
500             {
501               xml_inc(ctx);
502               if (xml_peek_char(ctx) != '#')
503                 {
504                   /* Bypass references to general entities */
505                   struct mempool_state state;
506                   mp_save(ctx->stack, &state);
507                   char *n = xml_parse_name(ctx, ctx->stack);
508                   xml_parse_char(ctx, ';');
509                   xml_dec(ctx);
510                   uns l = strlen(n);
511                   p = mp_spread(dtd->pool, p, 3 + l);
512                   *p++ = '&';
513                   memcpy(p, n, l);
514                   *p++ = ';';;
515                   mp_restore(ctx->stack, &state);
516                   continue;
517                 }
518               else
519                 {
520                   xml_skip_char(ctx);
521                   c = xml_parse_char_ref(ctx);
522                 }
523             }
524           p = mp_spread(dtd->pool, p, 5);
525           p = utf8_32_put(p, c);
526         }
527       *p = 0;
528       ent->len = p - (char *)mp_ptr(dtd->pool);
529       ent->text = mp_end(dtd->pool, p + 1);
530       slist_add_tail(list, &ent->n);
531       ent->flags = flags | XML_DTD_ENT_DECLARED;
532     }
533   else
534     {
535       /* External entity */
536       struct xml_ext_id eid;
537       struct xml_dtd_notn *notn = NULL;
538       xml_dtd_parse_external_id(ctx, &eid, 0);
539       if (!xml_parse_dtd_white(ctx, 0) || !flags)
540         xml_parse_char(ctx, '>');
541       else if (xml_get_char(ctx) != '>')
542         {
543           /* General external unparsed entity */
544           flags |= XML_DTD_ENT_UNPARSED;
545           xml_parse_seq(ctx, "NDATA");
546           xml_parse_dtd_white(ctx, 1);
547           notn = xml_dtd_notns_lookup(dtd->tab_notns, xml_parse_name(ctx, dtd->pool));
548         }
549       slist_add_tail(list, &ent->n);
550       ent->flags = flags | XML_DTD_ENT_DECLARED | XML_DTD_ENT_EXTERNAL;
551       ent->eid = eid;
552       ent->notn = notn;
553     }
554   xml_parse_dtd_white(ctx, 0);
555   xml_parse_char(ctx, '>');
556   xml_dec(ctx);
557 }
558
559 /* DTD: <!ELEMENT ...> */
560
561 void
562 xml_parse_element_decl(struct xml_context *ctx)
563 {
564   /* Elementdecl ::= '<!ELEMENT' S  Name  S  contentspec  S? '>'
565    * Already parsed: '<!ELEMENT' */
566   struct xml_dtd *dtd = ctx->dtd;
567   xml_parse_dtd_white(ctx, 1);
568   char *name = xml_parse_name(ctx, dtd->pool);
569   xml_parse_dtd_white(ctx, 1);
570   struct xml_dtd_elem *elem = xml_dtd_elems_lookup(dtd->tab_elems, name);
571   if (elem->flags & XML_DTD_ELEM_DECLARED)
572     xml_fatal(ctx, "Element <%s> already declared", name);
573
574   /* contentspec ::= 'EMPTY' | 'ANY' | Mixed | children */
575   uns c = xml_peek_char(ctx);
576   if (c == 'E')
577     {
578       xml_parse_seq(ctx, "EMPTY");
579       elem->type = XML_DTD_ELEM_EMPTY;
580     }
581   else if (c == 'A')
582     {
583       xml_parse_seq(ctx, "ANY");
584       elem->type = XML_DTD_ELEM_ANY;
585     }
586   else if (c == '(')
587     {
588       xml_skip_char(ctx);
589       xml_inc(ctx);
590       xml_parse_dtd_white(ctx, 0);
591       struct xml_dtd_elem_node *parent = elem->node = mp_alloc_zero(dtd->pool, sizeof(*parent));
592       if (xml_peek_char(ctx) == '#')
593         {
594           /* Mixed ::= '(' S? '#PCDATA' (S? '|' S? Name)* S? ')*' | '(' S? '#PCDATA' S? ')' */
595           xml_skip_char(ctx);
596           xml_parse_seq(ctx, "PCDATA");
597           elem->type = XML_DTD_ELEM_MIXED;
598           parent->type = XML_DTD_ELEM_PCDATA;
599           while (1)
600             {
601               xml_parse_dtd_white(ctx, 0);
602               if ((c = xml_get_char(ctx)) == ')')
603                 break;
604               else if (c != '|')
605                 xml_fatal_expected(ctx, ')');
606               xml_parse_dtd_white(ctx, 0);
607               struct xml_dtd_elem *son_elem = xml_dtd_elems_lookup(dtd->tab_elems, xml_parse_name(ctx, dtd->pool));
608               if (xml_dtd_enodes_find(dtd->tab_enodes, parent, son_elem))
609                 xml_error(ctx, "Duplicate content '%s'", son_elem->name);
610               else
611                 {
612                   struct xml_dtd_elem_node *son = xml_dtd_enodes_new(dtd->tab_enodes, parent, son_elem);
613                   slist_add_tail(&parent->sons, &son->n);
614                 }
615             }
616           xml_dec(ctx);
617           if (xml_peek_char(ctx) == '*')
618             {
619               xml_skip_char(ctx);
620               parent->occur = XML_DTD_ELEM_OCCUR_MULT;
621             }
622           else if (!slist_head(&parent->sons))
623             parent->occur = XML_DTD_ELEM_OCCUR_ONCE;
624           else
625             xml_fatal_expected(ctx, '*');
626         }
627       else
628         {
629           /* children ::= (choice | seq) ('?' | '*' | '+')?
630            * cp ::= (Name | choice | seq) ('?' | '*' | '+')?
631            * choice ::= '(' S? cp ( S? '|' S? cp )+ S? ')'
632            * seq ::= '(' S? cp ( S? ',' S? cp )* S? ')' */
633
634           elem->type = XML_DTD_ELEM_CHILDREN;
635           parent->type = XML_DTD_ELEM_PCDATA;
636           uns c;
637           goto first;
638
639           while (1)
640             {
641               /* After name */
642               xml_parse_dtd_white(ctx, 0);
643               if ((c = xml_get_char(ctx)) ==  ')')
644                 {
645                   xml_dec(ctx);
646                   if (parent->type == XML_DTD_ELEM_PCDATA)
647                     parent->type = XML_DTD_ELEM_SEQ;
648                   if ((c = xml_get_char(ctx)) == '?')
649                     parent->occur = XML_DTD_ELEM_OCCUR_OPT;
650                   else if (c == '*')
651                     parent->occur = XML_DTD_ELEM_OCCUR_MULT;
652                   else if (c == '+')
653                     parent->occur = XML_DTD_ELEM_OCCUR_PLUS;
654                   else
655                     {
656                       xml_unget_char(ctx);
657                       parent->occur = XML_DTD_ELEM_OCCUR_ONCE;
658                     }
659                   if (!parent->parent)
660                     break;
661                   parent = parent->parent;
662                   continue;
663                 }
664               else if (c == '|')
665                 {
666                   if (parent->type == XML_DTD_ELEM_PCDATA)
667                     parent->type = XML_DTD_ELEM_OR;
668                   else if (parent->type != XML_DTD_ELEM_OR)
669                     xml_fatal(ctx, "Mixed operators in the list of element children");
670                 }
671               else if (c == ',')
672                 {
673                   if (parent->type == XML_DTD_ELEM_PCDATA)
674                     parent->type = XML_DTD_ELEM_SEQ;
675                   else if (parent->type != XML_DTD_ELEM_SEQ)
676                     xml_fatal(ctx, "Mixed operators in the list of element children");
677                 }
678               else if (c == '(')
679                 {
680                   xml_inc(ctx);
681                   struct xml_dtd_elem_node *son = mp_alloc_zero(dtd->pool, sizeof(*son));
682                   son->parent = parent;
683                   slist_add_tail(&parent->sons, &son->n);
684                   parent = son->parent;
685                   son->type = XML_DTD_ELEM_MIXED;
686                 }
687               else
688                 xml_unget_char(ctx);
689
690               /* Before name */
691               xml_parse_dtd_white(ctx, 0);
692 first:;
693               struct xml_dtd_elem *son_elem = xml_dtd_elems_lookup(dtd->tab_elems, xml_parse_name(ctx, dtd->pool));
694               // FIXME: duplicates, occurance
695               //struct xml_dtd_elem_node *son = xml_dtd_enodes_new(dtd->tab_enodes, parent, son_elem);
696               struct xml_dtd_elem_node *son = mp_alloc_zero(dtd->pool, sizeof(*son));
697               son->parent = parent;
698               son->elem = son_elem;
699               slist_add_tail(&parent->sons, &son->n);
700             }
701         }
702     }
703   else
704     xml_fatal(ctx, "Expected element content specification");
705
706   xml_parse_dtd_white(ctx, 0);
707   xml_parse_char(ctx, '>');
708   xml_dec(ctx);
709 }
710
711 void
712 xml_parse_attr_list_decl(struct xml_context *ctx)
713 {
714   /* AttlistDecl ::= '<!ATTLIST' S Name AttDef* S? '>'
715    * AttDef ::= S Name S AttType S DefaultDecl
716    * Already parsed: '<!ATTLIST' */
717   struct xml_dtd *dtd = ctx->dtd;
718   xml_parse_dtd_white(ctx, 1);
719   struct xml_dtd_elem *elem = xml_dtd_elems_lookup(ctx->dtd->tab_elems, xml_parse_name(ctx, dtd->pool));
720
721   while (xml_parse_dtd_white(ctx, 0) && xml_peek_char(ctx) != '>')
722     {
723       char *name = xml_parse_name(ctx, dtd->pool);
724       struct xml_dtd_attr *attr = xml_dtd_attrs_find(dtd->tab_attrs, elem, name);
725       uns ignored = 0;
726       if (attr)
727         {
728           xml_warn(ctx, "Duplicate attribute definition");
729           ignored++;
730         }
731       else
732         attr = xml_dtd_attrs_new(ctx->dtd->tab_attrs, elem, name);
733       xml_parse_dtd_white(ctx, 1);
734       if (xml_peek_char(ctx) == '(')
735         {
736           xml_skip_char(ctx); // FIXME: xml_inc/dec ?
737           if (!ignored)
738             attr->type = XML_ATTR_ENUM;
739           do
740             {
741               xml_parse_dtd_white(ctx, 0);
742               char *value = xml_parse_nmtoken(ctx, dtd->pool);
743               if (!ignored)
744                 if (xml_dtd_evals_find(ctx->dtd->tab_evals, attr, value))
745                   xml_error(ctx, "Duplicate enumeration value");
746                 else
747                   xml_dtd_evals_new(ctx->dtd->tab_evals, attr, value);
748               xml_parse_dtd_white(ctx, 0);
749             }
750           while (xml_get_char(ctx) == '|');
751           xml_unget_char(ctx);
752           xml_parse_char(ctx, ')');
753         }
754       else
755         {
756           char *type = xml_parse_name(ctx, dtd->pool);
757           enum xml_dtd_attribute_type t = XML_ATTR_CDATA;
758           if (!strcmp(type, "CDATA"))
759             t = XML_ATTR_CDATA;
760           else if (!strcmp(type, "ID"))
761             t = XML_ATTR_ID;
762           else if (!strcmp(type, "IDREF"))
763             t = XML_ATTR_IDREF;
764           else if (!strcmp(type, "IDREFS"))
765             t = XML_ATTR_IDREFS;
766           else if (!strcmp(type, "ENTITY"))
767             t = XML_ATTR_ENTITY;
768           else if (!strcmp(type, "ENTITIES"))
769             t = XML_ATTR_ENTITIES;
770           else if (!strcmp(type, "NMTOKEN"))
771             t = XML_ATTR_NMTOKEN;
772           else if (!strcmp(type, "NMTOKENS"))
773             t = XML_ATTR_NMTOKENS;
774           else if (!strcmp(type, "NOTATION"))
775             {
776               if (elem->type == XML_DTD_ELEM_EMPTY)
777                 xml_fatal(ctx, "Empty element must not have notation attribute");
778               // FIXME: An element type MUST NOT have more than one NOTATION attribute specified.
779               t = XML_ATTR_NOTATION;
780               xml_parse_dtd_white(ctx, 1);
781               xml_parse_char(ctx, '(');
782               do
783                 {
784                   xml_parse_dtd_white(ctx, 0);
785                   struct xml_dtd_notn *n = xml_dtd_notns_lookup(ctx->dtd->tab_notns, xml_parse_name(ctx, dtd->pool));
786                   if (!ignored)
787                     if (xml_dtd_enotns_find(ctx->dtd->tab_enotns, attr, n))
788                       xml_error(ctx, "Duplicate enumerated notation");
789                     else
790                       xml_dtd_enotns_new(ctx->dtd->tab_enotns, attr, n);
791                   xml_parse_dtd_white(ctx, 0);
792                 }
793               while (xml_get_char(ctx) == '|');
794               xml_unget_char(ctx);
795               xml_parse_char(ctx, ')');
796             }
797           else
798             xml_fatal(ctx, "Unknown attribute type");
799           if (!ignored)
800             attr->type = t;
801         }
802       xml_parse_dtd_white(ctx, 1);
803       enum xml_dtd_attribute_default def = XML_ATTR_NONE;
804       if (xml_get_char(ctx) == '#')
805         switch (xml_peek_char(ctx))
806           {
807             case 'R':
808               xml_parse_seq(ctx, "REQUIRED");
809               def = XML_ATTR_REQUIRED;
810               break;
811             case 'I':
812               xml_parse_seq(ctx, "IMPLIED");
813               def = XML_ATTR_IMPLIED;
814               break;
815             case 'F':
816               xml_parse_seq(ctx, "FIXED");
817               def = XML_ATTR_FIXED;
818               xml_parse_dtd_white(ctx, 1);
819               break;
820             default:
821               xml_fatal(ctx, "Expected a modifier for default attribute value");
822           }
823       else
824         xml_unget_char(ctx);
825       if (def != XML_ATTR_REQUIRED && def != XML_ATTR_IMPLIED)
826         {
827           char *v = xml_parse_attr_value(ctx, attr);
828           if (!ignored)
829             attr->default_value = v;
830         }
831       if (!ignored)
832         attr->default_mode = def;
833     }
834   xml_skip_char(ctx);
835   xml_dec(ctx);
836 }
837
838 void
839 xml_skip_internal_subset(struct xml_context *ctx)
840 {
841   TRACE(ctx, "skip_internal_subset");
842   /* AlreadyParsed: '[' */
843   uns c;
844   while ((c = xml_get_char(ctx)) != ']')
845     {
846       if (c != '<')
847         continue;
848       if ((c = xml_get_char(ctx)) == '?')
849         {
850           xml_inc(ctx);
851           xml_skip_pi(ctx);
852         }
853       else if (c != '!')
854         xml_dec(ctx);
855       else if (xml_get_char(ctx) == '-')
856         {
857           xml_inc(ctx);
858           xml_skip_comment(ctx);
859         }
860       else
861         while ((c = xml_get_char(ctx)) != '>')
862           if (c == '\'' || c == '"')
863             while (xml_get_char(ctx) != c);
864     }
865   xml_dec(ctx);
866 }