Edinburgh Speech Tools  2.4-release
 All Classes Functions Variables Typedefs Enumerations Enumerator Friends Pages
dtd.c
1 /*************************************************************************/
2 /* */
3 /* Copyright (c) 1997-98 Richard Tobin, Language Technology Group, HCRC, */
4 /* University of Edinburgh. */
5 /* */
6 /* THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, */
7 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
8 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
9 /* IN NO EVENT SHALL THE AUTHOR OR THE UNIVERSITY OF EDINBURGH BE LIABLE */
10 /* FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF */
11 /* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION */
12 /* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
13 /* */
14 /*************************************************************************/
15 #include <string.h>
16 
17 #ifdef FOR_LT
18 
19 #include "lt-memory.h"
20 #include "nsllib.h"
21 
22 #define Malloc salloc
23 #define Realloc srealloc
24 #define Free sfree
25 
26 #else
27 
28 #include "system.h"
29 
30 #endif
31 
32 #include "charset.h"
33 #include "string16.h"
34 #include "dtd.h"
35 #include "url.h"
36 
37 const char8 *DefaultTypeName[DT_enum_count] = {
38  "#required",
39  "bogus1",
40  "#implied",
41  "bogus2"
42  "none",
43  "#fixed",
44 };
45 
46 const char8 *ContentTypeName[CT_enum_count] = {
47  "mixed",
48  "any",
49  "bogus1",
50  "bogus2",
51  "empty",
52  "element"
53 };
54 
55 const char8 *AttributeTypeName[AT_enum_count] = {
56  "cdata",
57  "bogus1",
58  "bogus2",
59  "nmtoken",
60  "bogus3",
61  "entity",
62  "idref",
63  "bogus4",
64  "bogus5",
65  "nmtokens",
66  "bogus6",
67  "entities",
68  "idrefs",
69  "id",
70  "notation",
71  "enumeration"
72 };
73 
74 const char8 *StandaloneDeclarationName[SDD_enum_count] = {
75  "unspecified", "no", "yes"
76 };
77 
78 static Char *Strndup(const Char *old, int len)
79 {
80  Char *new = Malloc((len+1) * sizeof(Char));
81 
82  if(!new)
83  return 0;
84 
85  memcpy(new, old, len * sizeof(Char));
86  new[len] = 0;
87 
88  return new;
89 }
90 
91 /* DTDs */
92 
93 Dtd NewDtd(void)
94 {
95  Dtd d;
96 
97  if(!(d = Malloc(sizeof(*d))))
98  return 0;
99 
100  d->name = 0;
101  d->internal_part = 0;
102  d->external_part = 0;
103  d->entities = 0;
104  d->parameter_entities = 0;
105  d->predefined_entities = 0;
106 #ifdef FOR_LT
107  d->doctype = 0;
108 #else
109  d->elements = 0;
110 #endif
111  d->notations = 0;
112 
113  return d;
114 }
115 
116 /* Free a DTD and everything in it */
117 
118 void FreeDtd(Dtd dtd)
119 {
120  Entity ent, ent1;
121 #ifndef FOR_LT
122  ElementDefinition elem, elem1;
123 #endif
124  NotationDefinition not, not1;
125 
126  if(!dtd)
127  return;
128 
129  /* Free the name */
130 
131  Free((Char *)dtd->name); /* cast is to get rid of const */
132 
133  /* Free the entities */
134 
135  FreeEntity(dtd->internal_part);
136  FreeEntity(dtd->external_part);
137 
138  for(ent = dtd->entities; ent; ent = ent1)
139  {
140  ent1 = ent->next; /* get it before we free ent! */
141  FreeEntity(ent);
142  }
143 
144  for(ent = dtd->parameter_entities; ent; ent = ent1)
145  {
146  ent1 = ent->next;
147  FreeEntity(ent);
148  }
149 
150  /* The predefined entities are shared, so we don't free them */
151 
152 #ifndef FOR_LT
153  /* Free the elements (kept elsewhere in NSL) */
154 
155  for(elem = dtd->elements; elem; elem = elem1)
156  {
157  elem1 = elem->next;
158  FreeElementDefinition(elem); /* Frees the attributes too */
159  }
160 #endif
161 
162  /* Free the notations */
163 
164  for(not = dtd->notations; not; not = not1)
165  {
166  not1 = not->next;
167  FreeNotationDefinition(not);
168  }
169 
170  /* Free the dtd itself */
171 
172  Free(dtd);
173 }
174 
175 /* Entities */
176 
177 /*
178  * Make a new entity. The name is copied, none of the other
179  * arguments are, but they are freed when the entity is freed!
180  */
181 
182 Entity NewExternalEntityN(const Char *name, int namelen, const char8 *publicid,
183  const char8 *systemid, NotationDefinition notation,
184  Entity parent)
185 {
186  Entity e;
187 
188  if(!(e = Malloc(sizeof(*e))))
189  return 0;
190  if(name && !(name = Strndup(name, namelen)))
191  return 0;
192 
193  e->type = ET_external;
194  e->name = name;
195  e->base_url = 0;
196  e->encoding = CE_unknown;
197  e->next = 0;
198  e->parent = parent;
199 
200  e->publicid = publicid;
201  e->systemid = systemid;
202  e->notation = notation;
203 
204  e->version_decl = 0;
205  e->encoding_decl = CE_unknown;
206  e->standalone_decl = SDD_unspecified;
207  e->ddb_filename = 0;
208 
209  e->url = 0;
210 
211  return (Entity)e;
212 }
213 
214 Entity NewInternalEntityN(const Char *name, int namelen,
215  const Char *text, Entity parent,
216  int line_offset, int line1_char_offset,
217  int matches_parent_text)
218 {
219  Entity e;
220 
221  if(!(e = Malloc(sizeof(*e))))
222  return 0;
223  if(name)
224  if(!(name = Strndup(name, namelen)))
225  return 0;
226 
227  e->type = ET_internal;
228  e->name = name;
229  e->base_url = 0;
230  e->encoding = InternalCharacterEncoding;
231  e->next = 0;
232  e->parent = parent;
233 
234  e->text = text;
235  e->line_offset = line_offset;
236  e->line1_char_offset = line1_char_offset;
237  e->matches_parent_text = matches_parent_text;
238 
239  e->url = 0;
240 
241  return (Entity)e;
242 }
243 
244 void FreeEntity(Entity e)
245 {
246  if(!e)
247  return;
248 
249  Free((void *)e->name); /* The casts are to get rid of the const */
250  Free((void *)e->base_url);
251  Free((void *)e->url);
252 
253  switch(e->type)
254  {
255  case ET_internal:
256  Free((void *)e->text);
257  break;
258  case ET_external:
259  Free((void *)e->systemid);
260  Free((void *)e->publicid);
261  Free((void *)e->version_decl);
262  Free((void *)e->ddb_filename);
263  break;
264  }
265 
266  Free(e);
267 }
268 
269 const char8 *EntityURL(Entity e)
270 {
271  /* Have we already determined the URL? */
272 
273  if(e->url)
274  return e->url;
275 
276  if(e->type == ET_internal)
277  {
278  if(e->parent)
279  {
280  const char8 *url = EntityURL(e->parent);
281  if(url)
282  e->url = strdup8(url);
283  }
284  }
285  else
286  e->url = url_merge(e->systemid,
287  e->parent ? EntityBaseURL(e->parent) : 0,
288  0, 0, 0, 0);
289 
290  return e->url;
291 }
292 
293 /* Returns the URL of the entity if it has one, otherwise the system ID.
294  It will certainly have a URL if it was successfully opened by EntityOpen.
295  Intended for error messages, so never returns NULL. */
296 
297 const char8 *EntityDescription(Entity e)
298 {
299  if(e->url)
300  return e->url;
301 
302  if(e->type == ET_external)
303  return e->systemid;
304 
305  if(e->parent)
306  return EntityDescription(e->parent);
307 
308  return "<unknown>";
309 }
310 
311 void EntitySetBaseURL(Entity e, const char8 *url)
312 {
313  e->base_url = url;
314 }
315 
316 const char8 *EntityBaseURL(Entity e)
317 {
318  if(e->base_url)
319  return e->base_url;
320 
321  if(e->type == ET_internal)
322  {
323  if(e->parent)
324  return EntityBaseURL(e->parent);
325  else
326  return 0;
327  }
328 
329  return EntityURL(e);
330 }
331 
332 Entity DefineEntity(Dtd dtd, Entity e, int pe)
333 {
334  if(pe)
335  {
336  e->next = dtd->parameter_entities;
337  dtd->parameter_entities = e;
338  }
339  else
340  {
341  e->next = dtd->entities;
342  dtd->entities = e;
343  }
344 
345  return e;
346 }
347 
348 Entity FindEntityN(Dtd dtd, const Char *name, int namelen, int pe)
349 {
350  Entity e;
351 
352  if(!pe)
353  for(e = dtd->predefined_entities; e; e = e->next)
354  if(Strncmp(name, e->name, namelen) == 0 && e->name[namelen] == 0)
355  return e;
356 
357 
358  for(e = pe ? dtd->parameter_entities : dtd->entities; e; e=e->next)
359  if(Strncmp(name, e->name, namelen) == 0 && e->name[namelen] == 0)
360  return e;
361 
362  return 0;
363 }
364 
365 /* Elements */
366 
367 /*
368  * Define a new element. The name is copied, the content model is not,
369  * but it is freed when the element definition is freed!
370  */
371 
372 ElementDefinition DefineElementN(Dtd dtd, const Char *name, int namelen,
373  ContentType type, Char *content)
374 {
375 #ifdef FOR_LT
376  static struct element_definition e;
377  RHTEntry *entry;
378  struct element_content *c;
379 
380  if (!(entry = DeclareElement(dtd->doctype, name, namelen, 0,
381  (ctVals)type))) {
382  return NULL;
383  };
384 
385  e.doctype = dtd->doctype;
386  e.name = (Char *)dtd->doctype->elements+entry->keyptr;
387  e.elsum = (NSL_ElementSummary_I *)(dtd->doctype->permanentBase+entry->eval);
388 
389  if(type == CT_element || type == CT_mixed)
390  {
391  if(!(c = Malloc(sizeof(*c))))
392  return 0;
393  c->elsum = e.elsum;
394  c->content = content;
395  c->next = e.doctype->element_content;
396  e.doctype->element_content = c;
397  }
398 
399  return &e;
400 #else
401  ElementDefinition e;
402 
403  if(!(e = Malloc(sizeof(*e))) || !(name = Strndup(name, namelen)))
404  return 0;
405 
406  e->tentative = 0;
407  e->name = name;
408  e->namelen = namelen;
409  e->type = type;
410  e->content = content;
411  e->attributes = 0;
412  e->next = dtd->elements;
413  dtd->elements = e;
414 
415  return e;
416 #endif
417 }
418 
419 ElementDefinition TentativelyDefineElementN(Dtd dtd,
420  const Char *name, int namelen)
421 {
422 #ifdef FOR_LT
423  static struct element_definition e;
424  RHTEntry *entry;
425 
426  if (!(entry = DeclareElement(dtd->doctype, name, namelen, 0, (ctVals)CT_any))) {
427  return NULL;
428  };
429  e.doctype = dtd->doctype;
430  e.name = (Char *)dtd->doctype->elements+entry->keyptr;
431  e.elsum = (NSL_ElementSummary_I *)(dtd->doctype->permanentBase+entry->eval);
432  /* XXX use the omitStart field to note that it's tentative. */
433  e.elsum->omitStart |= 2;
434  return &e;
435 #else
436  ElementDefinition e;
437 
438  if(!(e = Malloc(sizeof(*e))) || !(name = Strndup(name, namelen)))
439  return 0;
440 
441  e->tentative = 1;
442  e->name = name;
443  e->namelen = namelen;
444  e->type = CT_any;
445  e->content = 0;
446  e->attributes = 0;
447  e->next = dtd->elements;
448  dtd->elements = e;
449 
450  return e;
451 #endif
452 }
453 
454 ElementDefinition RedefineElement(ElementDefinition e, ContentType type,
455  Char *content)
456 {
457 #ifdef FOR_LT
458  struct element_content *c;
459 
460  e->elsum->contentType = type;
461  e->elsum->omitStart &= ~2;
462  if(type == CT_element)
463  {
464  if(!(c = Malloc(sizeof(*c))))
465  return 0;
466  c->elsum = e->elsum;
467  c->content = content;
468  c->next = e->doctype->element_content;
469  e->doctype->element_content = c;
470  }
471 #else
472  e->tentative = 0;
473  e->type = type;
474  e->content = content;
475 #endif
476  return e;
477 }
478 
479 ElementDefinition FindElementN(Dtd dtd, const Char *name, int namelen)
480 {
481 #ifdef FOR_LT
482  /* Derived from FindElementAndName */
483 
484  static struct element_definition e;
485  RHTEntry *entry;
486  NSL_ElementSummary_I *elsum;
487 
488  if(!dtd->doctype)
489  return 0;
490 
491  entry = rsearch(name, namelen, dtd->doctype->elements);
492  if(!entry)
493  return 0;
494 
495  elsum = (NSL_ElementSummary_I *)(dtd->doctype->permanentBase+entry->eval);
496 
497  e.doctype = dtd->doctype;
498  e.name = (Char *)dtd->doctype->elements+entry->keyptr;
499 #if 0
500  /* We don't use this so don't waste time on it XXX */
501  e.namelen = Strlen(e.name);
502 #endif
503  e.elsum = elsum;
504  e.tentative = ((e.elsum->omitStart & 2) != 0);
505 
506  return &e;
507 #else
508  ElementDefinition e, *p;
509 
510  for(p = &dtd->elements, e = *p; e; p = &e->next, e = *p)
511  if(namelen == e->namelen && *name == *e->name &&
512  memcmp(name, e->name, namelen*sizeof(Char)) == 0)
513  {
514  *p = e->next;
515  e->next = dtd->elements;
516  dtd->elements = e;
517  return e;
518  }
519 
520  return 0;
521 #endif
522 }
523 
524 /* Free an element definition and its attribute definitions */
525 
526 void FreeElementDefinition(ElementDefinition e)
527 {
528 #ifndef FOR_LT
529  AttributeDefinition a, a1;
530 #endif
531 
532  if(!e)
533  return;
534 
535  /* Free the element name */
536 
537  Free((void *)e->name);
538 
539 #ifndef FOR_LT
540  /* Free the content model (kept elsewhere in NSL) */
541 
542  Free(e->content);
543 
544  /* Free the attributes (kept elsewhere in NSL) */
545 
546  for(a = e->attributes; a; a = a1)
547  {
548  a1 = a->next;
549  FreeAttributeDefinition(a);
550  }
551 
552  /* Free the ElementDefinition itself */
553 #endif
554 
555  Free(e);
556 }
557 
558 /* Attributes */
559 
560 /*
561  * Define a new attribute. The name is copied, the allowed values and
562  * default are not, but they are freed when the attribute definition is freed!
563  */
564 
565 AttributeDefinition
566  DefineAttributeN(ElementDefinition element, const Char *name, int namelen,
567  AttributeType type, Char **allowed_values,
568  DefaultType default_type, const Char *default_value)
569 {
570 #ifdef FOR_LT
571  int nav = 0;
572  Char *av = allowed_values ? allowed_values[0] : 0;
573  Char **avp;
574  NSL_Doctype_I *doctype = element->doctype;
575 
576  if(!doctype)
577  return 0;
578 
579  if(allowed_values)
580  {
581  for(avp = allowed_values; *avp; avp++)
582  nav++;
583  Free(allowed_values);
584  }
585 
586  if (!(name = DeclareAttr(doctype, name, namelen,
587  (NSL_Attr_Declared_Value)type,
588  av, nav,
589  (NSL_ADefType)default_type, default_value,
590  &element->elsum, element->name))) {
591  return 0;
592  };
593 
594  return (AttributeDefinition)FindAttrSpec(element->elsum,
595  doctype,
596  name);
597 #else
598  AttributeDefinition a;
599 
600  if(!(a= Malloc(sizeof(*a))) || !(name = Strndup(name, namelen)))
601  return 0;
602 
603  a->name = name;
604  a->namelen = namelen;
605  a->type = type;
606  a->allowed_values = allowed_values;
607  a->default_type = default_type;
608  a->default_value = default_value;
609  a->next = element->attributes;
610  element->attributes = a;
611 
612  return a;
613 #endif
614 }
615 
616 AttributeDefinition FindAttributeN(ElementDefinition element,
617  const Char *name, int namelen)
618 {
619 #ifdef FOR_LT
620  if(!element->doctype)
621  return 0;
622 
623  if(!(name = AttrUniqueName(element->doctype, name, namelen)))
624  return 0;
625  return (AttributeDefinition)FindAttrSpec(element->elsum,
626  element->doctype,
627  name);
628 #else
629  AttributeDefinition a;
630 
631  for(a = element->attributes; a; a = a->next)
632  if(namelen == a->namelen &&
633  memcmp(name, a->name, namelen * sizeof(Char)) == 0)
634  return a;
635 
636  return 0;
637 #endif
638 }
639 
640 AttributeDefinition NextAttributeDefinition(ElementDefinition element,
641  AttributeDefinition previous)
642 {
643 #ifdef FOR_LT
644  return 0; /* not implemented */
645 #else
646  if(previous)
647  return previous->next;
648  else
649  return element->attributes;
650 #endif
651 }
652 
653 /* Free an attribute definition */
654 
655 void FreeAttributeDefinition(AttributeDefinition a)
656 {
657 #ifndef FOR_LT
658  /* We don't keep anything in the NSL case */
659 
660  if(!a)
661  return;
662 
663  /* Free the name */
664 
665  Free((void *)a->name);
666 
667  /* Free the allowed values - we rely on them being allocated as in
668  xmlparser.c: the Char * pointers point into one single block. */
669 
670  if(a->allowed_values)
671  Free(a->allowed_values[0]);
672  Free(a->allowed_values);
673 
674  /* Free the default value */
675 
676  Free((void *)a->default_value);
677 
678  /* Free the attribute definition itself */
679 
680  Free(a);
681 #endif
682 }
683 
684 /* Notations */
685 
686 /*
687  * Define a new notation. The name is copied, the system and public ids are
688  * not, but they are freed when the notation definition is freed!
689  */
690 
691 NotationDefinition DefineNotationN(Dtd dtd, const Char *name, int namelen,
692  const char8 *publicid, const char8 *systemid)
693 {
694  NotationDefinition n;
695 
696  if(!(n = Malloc(sizeof(*n))) || !(name = Strndup(name, namelen)))
697  return 0;
698 
699  n->name = name;
700  n->tentative = 1;
701  n->systemid = systemid;
702  n->publicid = publicid;
703  n->next = dtd->notations;
704  dtd->notations = n;
705 
706  return n;
707 }
708 
709 NotationDefinition TentativelyDefineNotationN(Dtd dtd,
710  const Char *name, int namelen)
711 {
712  NotationDefinition n;
713 
714  if(!(n = Malloc(sizeof(*n))) || !(name = Strndup(name, namelen)))
715  return 0;
716 
717  n->name = name;
718  n->tentative = 1;
719  n->systemid = 0;
720  n->publicid = 0;
721  n->next = dtd->notations;
722  dtd->notations = n;
723 
724  return n;
725 }
726 
727 NotationDefinition RedefineNotation(NotationDefinition n,
728  const char8 *publicid, const char8 *systemid)
729 {
730  n->tentative = 0;
731  n->systemid = systemid;
732  n->publicid = publicid;
733 
734  return n;
735 }
736 
737 NotationDefinition FindNotationN(Dtd dtd, const Char *name, int namelen)
738 {
739  NotationDefinition n;
740 
741  for(n = dtd->notations; n; n = n->next)
742  if(Strncmp(name, n->name, namelen) == 0 && n->name[namelen] == 0)
743  return n;
744 
745  return 0;
746 }
747 
748 void FreeNotationDefinition(NotationDefinition n)
749 {
750  if(!n)
751  return;
752 
753  /* Free the name */
754 
755  Free((void *)n->name);
756 
757  /* Free the ids */
758 
759  Free((void *)n->systemid);
760  Free((void *)n->publicid);
761 
762  /* Free the notation definition itself */
763 
764  Free(n);
765 }