2 * Sherlock Library -- A simple XML parser
4 * (c) 2007 Pavel Charvat <pchar@ucw.cz>
6 * This software may be freely distributed and used according to the terms
7 * of the GNU Lesser General Public License.
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"
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
30 #include "lib/hashtable.h"
32 /* General entities */
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
44 #include "lib/hashtable.h"
46 static struct xml_dtd_ent *
47 xml_dtd_declare_trivial_ent(struct xml_context *ctx, char *name, uns uni)
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)
53 xml_warn(ctx, "Entity &%s; already declared", name);
56 slist_add_tail(&dtd->ents, &ent->n);
57 ent->flags = XML_DTD_ENT_DECLARED | XML_DTD_ENT_TRIVIAL_UNI;
63 xml_dtd_declare_default_ents(struct xml_context *ctx)
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);
73 xml_dtd_find_ent(struct xml_context *ctx, char *name)
75 struct xml_dtd *dtd = ctx->dtd;
76 if (ctx->h_resolve_entity)
77 return ctx->h_resolve_entity(ctx, name);
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;
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);
91 if (!strcmp(name, "lt"))
95 if (!strcmp(name, "gt"))
99 if (!strcmp(name, "amp"))
101 if (!strcmp(name, "apos"))
105 if (!strcmp(name, "quot"))
113 /* Parameter entities */
115 static struct xml_dtd_ent *
116 xml_dtd_find_pent(struct xml_context *ctx, char *name)
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;
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
135 #include "lib/hashtable.h"
137 struct xml_dtd_elem *
138 xml_dtd_find_elem(struct xml_context *ctx, char *name)
140 return ctx->dtd ? xml_dtd_elems_find(ctx->dtd->tab_elems, name) : NULL;
145 struct xml_dtd_enodes_table;
148 xml_dtd_enodes_hash(struct xml_dtd_enodes_table *tab UNUSED, struct xml_dtd_elem_node *parent, struct xml_dtd_elem *elem)
150 return hash_pointer(parent) ^ hash_pointer(elem);
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)
156 return (parent1 == parent2) && (elem1 == elem2);
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)
162 node->parent = parent;
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
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
180 #include "lib/hashtable.h"
182 /* Element attributes */
184 struct xml_dtd_attrs_table;
187 xml_dtd_attrs_hash(struct xml_dtd_attrs_table *tab UNUSED, struct xml_dtd_elem *elem, char *name)
189 return hash_pointer(elem) ^ hash_string(name);
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)
195 return (elem1 == elem2) && !strcmp(name1, name2);
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)
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
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
219 #include "lib/hashtable.h"
221 struct xml_dtd_attr *
222 xml_dtd_find_attr(struct xml_context *ctx, struct xml_dtd_elem *elem, char *name)
224 return ctx->dtd ? xml_dtd_attrs_find(ctx->dtd->tab_attrs, elem, name) : NULL;
227 /* Enumerated attribute values */
229 struct xml_dtd_evals_table;
232 xml_dtd_evals_hash(struct xml_dtd_evals_table *tab UNUSED, struct xml_dtd_attr *attr, char *val)
234 return hash_pointer(attr) ^ hash_string(val);
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)
240 return (attr1 == attr2) && !strcmp(val1, val2);
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)
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
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
263 #include "lib/hashtable.h"
265 /* Enumerated attribute notations */
267 struct xml_dtd_enotns_table;
270 xml_dtd_enotns_hash(struct xml_dtd_enotns_table *tab UNUSED, struct xml_dtd_attr *attr, struct xml_dtd_notn *notn)
272 return hash_pointer(attr) ^ hash_pointer(notn);
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)
278 return (attr1 == attr2) && (notn1 == notn2);
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)
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
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
301 #include "lib/hashtable.h"
303 /* DTD initialization/cleanup */
306 xml_dtd_init(struct xml_context *ctx)
310 struct mempool *pool = mp_new(4096);
311 struct xml_dtd *dtd = ctx->dtd = mp_alloc_zero(pool, sizeof(*ctx->dtd));
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);
325 xml_dtd_cleanup(struct xml_context *ctx)
329 mp_delete(ctx->dtd->pool);
334 xml_dtd_finish(struct xml_context *ctx)
338 // FIXME: validity checks
341 /*** Parsing functions ***/
343 /* References to parameter entities */
346 xml_parse_pe_ref(struct xml_context *ctx)
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);
356 xml_error(ctx, "Unknown entity %%%s;", name);
359 TRACE(ctx, "Pushed entity %%%s;", name);
360 mp_restore(ctx->stack, &state);
362 xml_push_entity(ctx, ent);
365 mp_restore(ctx->stack, &state);
370 xml_parse_dtd_pe(struct xml_context *ctx)
376 while (xml_peek_cat(ctx) & XML_CHAR_WHITE)
378 xml_parse_pe_ref(ctx);
380 while (xml_peek_char(ctx) != '%');
384 xml_parse_dtd_white(struct xml_context *ctx, uns mandatory)
386 /* Whitespace or parameter entity */
388 while (xml_peek_cat(ctx) & XML_CHAR_WHITE)
393 if (xml_peek_char(ctx) == '%')
395 xml_parse_dtd_pe(ctx);
398 else if (unlikely(mandatory && !cnt))
399 xml_fatal_expected_white(ctx);
404 xml_dtd_parse_external_id(struct xml_context *ctx, struct xml_ext_id *eid, uns allow_public)
406 struct xml_dtd *dtd = ctx->dtd;
407 bzero(eid, sizeof(*eid));
408 uns c = xml_peek_char(ctx);
411 xml_parse_seq(ctx, "SYSTEM");
412 xml_parse_dtd_white(ctx, 1);
413 eid->system_id = xml_parse_system_literal(ctx, dtd->pool);
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);
425 xml_fatal(ctx, "Expected an external ID");
428 /* DTD: <!NOTATION ...> */
431 xml_parse_notation_decl(struct xml_context *ctx)
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);
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, '>');
446 if (notn->flags & XML_DTD_NOTN_DECLARED)
447 xml_warn(ctx, "Notation %s already declared", notn->name);
450 notn->flags = XML_DTD_NOTN_DECLARED;
452 slist_add_tail(&dtd->notns, ¬n->n);
457 /* DTD: <!ENTITY ...> */
460 xml_parse_entity_decl(struct xml_context *ctx)
462 /* Already parsed: '<!ENTITY' */
463 TRACE(ctx, "parse_entity_decl");
464 struct xml_dtd *dtd = ctx->dtd;
465 xml_parse_dtd_white(ctx, 1);
467 uns flags = (xml_get_char(ctx) == '%') ? XML_DTD_ENT_PARAMETER : 0;
469 xml_parse_dtd_white(ctx, 1);
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)
478 xml_fatal(ctx, "Entity &%s; already declared, skipping not implemented", ent->name);
479 // FIXME: should be only warning
482 uns c, sep = xml_get_char(ctx);
483 if (sep == '\'' || sep == '"')
486 * EntityValue ::= '"' ([^%&"] | PEReference | Reference)* '"' | "'" ([^%&'] | PEReference | Reference)* "'" */
487 char *p = mp_start_noalign(dtd->pool, 1);
490 if ((c = xml_get_char(ctx)) == sep)
496 //xml_parse_parameter_ref(ctx);
502 if (xml_peek_char(ctx) != '#')
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, ';');
511 p = mp_spread(dtd->pool, p, 3 + l);
515 mp_restore(ctx->stack, &state);
521 c = xml_parse_char_ref(ctx);
524 p = mp_spread(dtd->pool, p, 5);
525 p = utf8_32_put(p, c);
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;
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) != '>')
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));
549 slist_add_tail(list, &ent->n);
550 ent->flags = flags | XML_DTD_ENT_DECLARED | XML_DTD_ENT_EXTERNAL;
554 xml_parse_dtd_white(ctx, 0);
555 xml_parse_char(ctx, '>');
559 /* DTD: <!ELEMENT ...> */
562 xml_parse_element_decl(struct xml_context *ctx)
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);
574 /* contentspec ::= 'EMPTY' | 'ANY' | Mixed | children */
575 uns c = xml_peek_char(ctx);
578 xml_parse_seq(ctx, "EMPTY");
579 elem->type = XML_DTD_ELEM_EMPTY;
583 xml_parse_seq(ctx, "ANY");
584 elem->type = XML_DTD_ELEM_ANY;
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) == '#')
594 /* Mixed ::= '(' S? '#PCDATA' (S? '|' S? Name)* S? ')*' | '(' S? '#PCDATA' S? ')' */
596 xml_parse_seq(ctx, "PCDATA");
597 elem->type = XML_DTD_ELEM_MIXED;
598 parent->type = XML_DTD_ELEM_PCDATA;
601 xml_parse_dtd_white(ctx, 0);
602 if ((c = xml_get_char(ctx)) == ')')
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);
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);
617 if (xml_peek_char(ctx) == '*')
620 parent->occur = XML_DTD_ELEM_OCCUR_MULT;
622 else if (!slist_head(&parent->sons))
623 parent->occur = XML_DTD_ELEM_OCCUR_ONCE;
625 xml_fatal_expected(ctx, '*');
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? ')' */
634 elem->type = XML_DTD_ELEM_CHILDREN;
635 parent->type = XML_DTD_ELEM_PCDATA;
642 xml_parse_dtd_white(ctx, 0);
643 if ((c = xml_get_char(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;
651 parent->occur = XML_DTD_ELEM_OCCUR_MULT;
653 parent->occur = XML_DTD_ELEM_OCCUR_PLUS;
657 parent->occur = XML_DTD_ELEM_OCCUR_ONCE;
661 parent = parent->parent;
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");
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");
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;
691 xml_parse_dtd_white(ctx, 0);
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);
704 xml_fatal(ctx, "Expected element content specification");
706 xml_parse_dtd_white(ctx, 0);
707 xml_parse_char(ctx, '>');
712 xml_parse_attr_list_decl(struct xml_context *ctx)
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));
721 while (xml_parse_dtd_white(ctx, 0) && xml_peek_char(ctx) != '>')
723 char *name = xml_parse_name(ctx, dtd->pool);
724 struct xml_dtd_attr *attr = xml_dtd_attrs_find(dtd->tab_attrs, elem, name);
728 xml_warn(ctx, "Duplicate attribute definition");
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) == '(')
736 xml_skip_char(ctx); // FIXME: xml_inc/dec ?
738 attr->type = XML_ATTR_ENUM;
741 xml_parse_dtd_white(ctx, 0);
742 char *value = xml_parse_nmtoken(ctx, dtd->pool);
744 if (xml_dtd_evals_find(ctx->dtd->tab_evals, attr, value))
745 xml_error(ctx, "Duplicate enumeration value");
747 xml_dtd_evals_new(ctx->dtd->tab_evals, attr, value);
748 xml_parse_dtd_white(ctx, 0);
750 while (xml_get_char(ctx) == '|');
752 xml_parse_char(ctx, ')');
756 char *type = xml_parse_name(ctx, dtd->pool);
757 enum xml_dtd_attribute_type t = XML_ATTR_CDATA;
758 if (!strcmp(type, "CDATA"))
760 else if (!strcmp(type, "ID"))
762 else if (!strcmp(type, "IDREF"))
764 else if (!strcmp(type, "IDREFS"))
766 else if (!strcmp(type, "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"))
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, '(');
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));
787 if (xml_dtd_enotns_find(ctx->dtd->tab_enotns, attr, n))
788 xml_error(ctx, "Duplicate enumerated notation");
790 xml_dtd_enotns_new(ctx->dtd->tab_enotns, attr, n);
791 xml_parse_dtd_white(ctx, 0);
793 while (xml_get_char(ctx) == '|');
795 xml_parse_char(ctx, ')');
798 xml_fatal(ctx, "Unknown attribute type");
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))
808 xml_parse_seq(ctx, "REQUIRED");
809 def = XML_ATTR_REQUIRED;
812 xml_parse_seq(ctx, "IMPLIED");
813 def = XML_ATTR_IMPLIED;
816 xml_parse_seq(ctx, "FIXED");
817 def = XML_ATTR_FIXED;
818 xml_parse_dtd_white(ctx, 1);
821 xml_fatal(ctx, "Expected a modifier for default attribute value");
825 if (def != XML_ATTR_REQUIRED && def != XML_ATTR_IMPLIED)
827 char *v = xml_parse_attr_value(ctx, attr);
829 attr->default_value = v;
832 attr->default_mode = def;
839 xml_skip_internal_subset(struct xml_context *ctx)
841 TRACE(ctx, "skip_internal_subset");
842 /* AlreadyParsed: '[' */
844 while ((c = xml_get_char(ctx)) != ']')
848 if ((c = xml_get_char(ctx)) == '?')
855 else if (xml_get_char(ctx) == '-')
858 xml_skip_comment(ctx);
861 while ((c = xml_get_char(ctx)) != '>')
862 if (c == '\'' || c == '"')
863 while (xml_get_char(ctx) != c);