#include #ifdef FOR_LT #include "lt-memory.h" #include "nsllib.h" #define Malloc salloc #define Realloc srealloc #define Free sfree #else #include "system.h" #endif #include "charset.h" #include "string16.h" #include "dtd.h" #include "url.h" extern void FreeFSM(FSM fsm); /* XXX should be in header */ const char8 *DefaultTypeName[DT_enum_count] = { "#REQUIRED", "bogus1", "#IMPLIED", "bogus2", "NONE", "#FIXED", }; const char8 *ContentParticleTypeName[CP_enum_count] = { "#PCDATA", "NAME", "SEQUENCE", "CHOICE" }; const char8 *ContentTypeName[CT_enum_count] = { "MIXED", "ANY", "bogus1", "bogus2", "EMPTY", "ELEMENT" }; const char8 *AttributeTypeName[AT_enum_count] = { "CDATA", "bogus1", "bogus2", "NMTOKEN", "bogus3", "ENTITY", "IDREF", "bogus4", "bogus5", "NMTOKENS", "bogus6", "ENTITIES", "IDREFS", "ID", "NOTATION", "ENUMERATION" }; const char8 *StandaloneDeclarationName[SDD_enum_count] = { "unspecified", "no", "yes" }; static Char *Strndup(const Char *old, int len) { Char *new = Malloc((len+1) * sizeof(Char)); if(!new) return 0; memcpy(new, old, len * sizeof(Char)); new[len] = 0; return new; } /* DTDs */ Dtd NewDtd(void) { Dtd d; if(!(d = Malloc(sizeof(*d)))) return 0; d->name = 0; d->internal_part = 0; d->external_part = 0; d->entities = 0; d->parameter_entities = 0; d->predefined_entities = 0; #ifdef FOR_LT d->doctype = 0; #endif d->nelements = 0; d->neltalloc = 20; d->elements = Malloc(d->neltalloc * sizeof(ElementDefinition)); if(!d->elements) return 0; d->notations = 0; d->namespace_universe = 0; /* the global universe */ return d; } /* Free a DTD and everything in it */ void FreeDtd(Dtd dtd) { Entity ent, ent1; int i; NotationDefinition not, not1; if(!dtd) return; /* Free the name */ Free((Char *)dtd->name); /* cast is to get rid of const */ /* Free the entities */ FreeEntity(dtd->internal_part); FreeEntity(dtd->external_part); for(ent = dtd->entities; ent; ent = ent1) { ent1 = ent->next; /* get it before we free ent! */ FreeEntity(ent); } for(ent = dtd->parameter_entities; ent; ent = ent1) { ent1 = ent->next; FreeEntity(ent); } /* The predefined entities are shared, so we don't free them */ /* Free the elements */ for(i=0; inelements; i++) FreeElementDefinition(dtd->elements[i]); /* Frees the attributes too */ Free(dtd->elements); /* Free the notations */ for(not = dtd->notations; not; not = not1) { not1 = not->next; FreeNotationDefinition(not); } /* Free the dtd itself */ Free(dtd); } /* Entities */ /* * Make a new entity. The name and IDs are copied. */ Entity NewExternalEntity(const Char *name, const char8 *publicid, const char8 *systemid, NotationDefinition notation, Entity parent) { if(systemid && !(systemid = strdup8(systemid))) return 0; if(publicid && !(publicid = strdup8(publicid))) return 0; return NewExternalEntityN(name, name ? Strlen(name) : 0, publicid, systemid, notation, parent); } /* NB doesn't copy IDs */ Entity NewExternalEntityN(const Char *name, int namelen, const char8 *publicid, const char8 *systemid, NotationDefinition notation, Entity parent) { Entity e; if(!(e = Malloc(sizeof(*e)))) return 0; if(name && !(name = Strndup(name, namelen))) return 0; e->type = ET_external; e->name = name; e->base_url = 0; e->encoding = CE_unknown; e->next = 0; e->parent = parent; e->publicid = publicid; e->systemid = systemid; e->notation = notation; e->ml_decl = ML_unspecified; e->version_decl = 0; e->encoding_decl = CE_unknown; e->standalone_decl = SDD_unspecified; e->ddb_filename = 0; e->url = 0; e->is_externally_declared = 0; e->is_internal_subset = 0; return (Entity)e; } Entity NewInternalEntityN(const Char *name, int namelen, const Char *text, Entity parent, int line_offset, int line1_char_offset, int matches_parent_text) { Entity e; if(!(e = Malloc(sizeof(*e)))) return 0; if(name) if(!(name = Strndup(name, namelen))) return 0; e->type = ET_internal; e->name = name; e->base_url = 0; e->encoding = InternalCharacterEncoding; e->next = 0; e->parent = parent; e->text = text; e->line_offset = line_offset; e->line1_char_offset = line1_char_offset; e->matches_parent_text = matches_parent_text; e->url = 0; e->is_externally_declared = 0; e->is_internal_subset = 0; /* These should not really be accessed for an internal entity, but because the NSL layer uses internal entities to implement reading from strings, sometimes they are. */ e->publicid = 0; e->systemid = 0; e->notation = 0; e->ml_decl = ML_unspecified; e->version_decl = 0; e->encoding_decl = CE_unknown; e->standalone_decl = SDD_unspecified; e->ddb_filename = 0; return (Entity)e; } void FreeEntity(Entity e) { if(!e) return; CFree((void *)e->name); /* The casts are to get rid of the const */ CFree((void *)e->base_url); CFree((void *)e->url); switch(e->type) { case ET_internal: CFree((void *)e->text); break; case ET_external: CFree((void *)e->systemid); CFree((void *)e->publicid); CFree((void *)e->version_decl); CFree((void *)e->ddb_filename); break; } Free(e); } const char8 *EntityURL(Entity e) { /* Have we already determined the URL? */ if(e->url) return e->url; if(e->type == ET_internal) { if(e->parent) { const char8 *url = EntityURL(e->parent); if(url) e->url = strdup8(url); } } else e->url = url_merge(e->systemid, e->parent ? EntityBaseURL(e->parent) : 0, 0, 0, 0, 0); return e->url; } /* Returns the URL of the entity if it has one, otherwise the system ID. It will certainly have a URL if it was successfully opened by EntityOpen. Intended for error messages, so never returns NULL. */ const char8 *EntityDescription(Entity e) { if(e->url) return e->url; if(e->type == ET_external) return e->systemid; if(e->parent) return EntityDescription(e->parent); return ""; } void EntitySetBaseURL(Entity e, const char8 *url) { if(e->base_url) Free((void *)e->base_url); e->base_url = strdup8(url); } const char8 *EntityBaseURL(Entity e) { if(e->base_url) return e->base_url; if(e->type == ET_internal) { if(e->parent) return EntityBaseURL(e->parent); else return 0; } return EntityURL(e); } Entity DefineEntity(Dtd dtd, Entity e, int pe) { if(pe) { e->next = dtd->parameter_entities; dtd->parameter_entities = e; } else { e->next = dtd->entities; dtd->entities = e; } return e; } Entity FindEntityN(Dtd dtd, const Char *name, int namelen, int pe) { Entity e; if(!pe) for(e = dtd->predefined_entities; e; e = e->next) if(Strncmp(name, e->name, namelen) == 0 && e->name[namelen] == 0) return e; for(e = pe ? dtd->parameter_entities : dtd->entities; e; e=e->next) if(Strncmp(name, e->name, namelen) == 0 && e->name[namelen] == 0) return e; return 0; } Entity NextEntity(Dtd dtd, Entity previous) { return previous ? previous->next : dtd->entities; } Entity NextParameterEntity(Dtd dtd, Entity previous) { return previous ? previous->next : dtd->parameter_entities; } /* Elements */ /* * Define a new element. The name is copied, the content model is not, * but it is freed when the element definition is freed! */ ElementDefinition DefineElementN(Dtd dtd, const Char *name, int namelen, ContentType type, Char *content, ContentParticle particle, int declared) { ElementDefinition e; Char *t; #ifdef FOR_LT RHTEntry *entry; #endif if(!(e = Malloc(sizeof(*e)))) return 0; e->eltnum = dtd->nelements++; if(e->eltnum >= dtd->neltalloc) { dtd->neltalloc *= 2; dtd->elements = Realloc(dtd->elements, dtd->neltalloc * sizeof(ElementDefinition)); if(!dtd->elements) return 0; } dtd->elements[e->eltnum] = e; #ifdef FOR_LT entry = DeclareElement(dtd->doctype, name, namelen, 0, (ctVals)type); if (!entry) return 0; e->doctype = dtd->doctype; e->eltsum = (NSL_ElementSummary_I *)(dtd->doctype->permanentBase+entry->eval); *(short *)&(e->eltsum->omitEnd) = e->eltnum; name = (Char *)dtd->doctype->elements+entry->keyptr; #else if(!(name = Strndup(name, namelen))) return 0; #endif e->tentative = 0; e->name = name; e->namelen = namelen; e->type = type; e->content = content; e->particle = particle; e->declared = declared; e->has_attlist = 0; e->fsm = 0; e->nattributes = 0; e->nattralloc = 20; e->attributes = Malloc(e->nattralloc * sizeof(AttributeDefinition)); if(!e->attributes) return 0; e->id_attribute = 0; e->xml_space_attribute = 0; e->xml_lang_attribute = 0; e->notation_attribute = 0; e->cached_nsdef = 0; e->is_externally_declared = 0; if((t = Strchr(name, ':'))) { if(!(e->prefix = Strndup(name, t - name))) return 0; e->local = t+1; } else { e->local = name; e->prefix = 0; } return e; } ElementDefinition TentativelyDefineElementN(Dtd dtd, const Char *name, int namelen) { ElementDefinition e; if(!(e = DefineElementN(dtd, name, namelen, CT_any, 0, 0, 1))) return 0; e->tentative = 1; return e; } ElementDefinition RedefineElement(ElementDefinition e, ContentType type, Char *content, ContentParticle particle, int declared) { #ifdef FOR_LT e->eltsum->contentType = type; #endif e->tentative = 0; e->type = type; e->content = content; e->particle = particle; e->declared = declared; return e; } ElementDefinition FindElementN(Dtd dtd, const Char *name, int namelen) { ElementDefinition e; #ifdef FOR_LT /* Derived from FindElementAndName */ RHTEntry *entry; NSL_ElementSummary_I *eltsum; if(!dtd->doctype) return 0; entry = rsearch(name, namelen, dtd->doctype->elements); if(!entry) return 0; eltsum = (NSL_ElementSummary_I *)(dtd->doctype->permanentBase+entry->eval); if(!dtd->doctype->XMLMode) { /* NSL mode - we have to fake a structure */ e = &dtd->fake_elt; e->doctype = dtd->doctype; e->name = (Char *)dtd->doctype->elements+entry->keyptr; e->eltsum = eltsum; e->tentative = 0; return e; } return dtd->elements[*(short *)&(eltsum->omitEnd)]; #else int i; for(i=dtd->nelements-1; i>=0; i--) { e = dtd->elements[i]; if(namelen == e->namelen && *name == *e->name && memcmp(name, e->name, namelen*sizeof(Char)) == 0) return e; } return 0; #endif } NSElementDefinition NamespacifyElementDefinition(ElementDefinition element, Namespace ns) { if(element->cached_nsdef && element->cached_nsdef->namespace == ns) return element->cached_nsdef; element->cached_nsdef = FindNSElementDefinition(ns, element->local, 1); return element->cached_nsdef; } ElementDefinition NextElementDefinition(Dtd dtd, ElementDefinition previous) { int next = previous ? previous->eltnum+1 : 0; return next < dtd->nelements ? dtd->elements[next] : 0; } /* Free an element definition and its attribute definitions */ void FreeElementDefinition(ElementDefinition e) { int i; if(!e) return; /* Free the attributes */ for(i=0; inattributes; i++) FreeAttributeDefinition(e->attributes[i]); Free(e->attributes); #ifndef FOR_LT /* Free the element name (kept elsewhere in NSL) */ Free((void *)e->name); #endif Free((void *)e->prefix); /* Free the content model */ Free(e->content); FreeContentParticle(e->particle); FreeFSM(e->fsm); /* Free the ElementDefinition itself */ Free(e); } /* Attributes */ /* * Define a new attribute. The name is copied, the allowed values and * default are not, but they are freed when the attribute definition is freed! */ AttributeDefinition DefineAttributeN(ElementDefinition element, const Char *name, int namelen, AttributeType type, Char **allowed_values, DefaultType default_type, const Char *default_value, int declared) { #ifdef FOR_LT int nav = 0; Char **avp; NSL_Doctype_I *doctype = element->doctype; #endif AttributeDefinition a; static Char xml_space[] = {'x','m','l',':','s','p','a','c','e',0}; static Char xml_lang[] = {'x','m','l',':','l','a','n','g',0}; static Char xmlns[] = {'x','m','l','n','s',0}; Char *t; if(!(a= Malloc(sizeof(*a)))) return 0; a->attrnum = element->nattributes++; if(a->attrnum >= element->nattralloc) { element->nattralloc *= 2; element->attributes = Realloc(element->attributes, element->nattralloc * sizeof(AttributeDefinition)); if(!element->attributes) return 0; } element->attributes[a->attrnum] = a; #ifdef FOR_LT if(allowed_values) { for(avp = allowed_values; *avp; avp++) nav++; } if (!(name = DeclareAttr(doctype, name, namelen, (NSL_Attr_Declared_Value)type, allowed_values?allowed_values[0]:0, nav, (NSL_ADefType)default_type, default_value, &element->eltsum, element->name))) return 0; a->attrsum = FindAttrSpec(element->eltsum, doctype, name); #else if(!(name = Strndup(name, namelen))) return 0; #endif a->name = name; a->namelen = namelen; a->type = type; a->allowed_values = allowed_values; a->default_type = default_type; a->default_value = default_value; a->declared = declared; if(declared) element->has_attlist = 1; a->is_externally_declared = 0; if(a->type == AT_id && !element->id_attribute) element->id_attribute = a; else if(a->type == AT_notation && !element->notation_attribute) element->notation_attribute = a; if(Strcmp(name, xml_space) == 0) element->xml_space_attribute = a; else if(Strcmp(name, xml_lang) == 0) element->xml_lang_attribute = a; a->cached_nsdef = 0; if((t = Strchr(name, ':'))) { if(!(a->prefix = Strndup(name, t - name))) return 0; a->local = t+1; if(Strcmp(a->prefix, xmlns) == 0) a->ns_attr_prefix = a->local; else a->ns_attr_prefix = 0; } else { a->local = name; a->prefix = 0; if(Strcmp(name, xmlns) == 0) a->ns_attr_prefix = name+5; /* point to the null */ else a->ns_attr_prefix = 0; } return a; } AttributeDefinition FindAttributeN(ElementDefinition element, const Char *name, int namelen) { int i; #ifdef FOR_LT if(!(name = AttrUniqueName(element->doctype, name, namelen))) return 0; if(!element->doctype->XMLMode) /* XXX Hack for NSL documents. Return the attribute summary itself. Nothing in the RXP layer had better look at it! */ return (AttributeDefinition)FindAttrSpec(element->eltsum, element->doctype, name); if(!FindAttrSpecAndNumber(element->eltsum, element->doctype, name, &i)) return 0; if(i < 0) i = element->nattributes + i; return element->attributes[i]; #else for(i=element->nattributes-1; i>=0; i--) { AttributeDefinition a = element->attributes[i]; if(namelen == a->namelen && memcmp(name, a->name, namelen * sizeof(Char)) == 0) return a; } return 0; #endif } NSAttributeDefinition NamespacifyGlobalAttributeDefinition(AttributeDefinition attribute, Namespace ns) { if(attribute->cached_nsdef && !attribute->cached_nsdef->element && attribute->cached_nsdef->namespace == ns) return attribute->cached_nsdef; attribute->cached_nsdef = FindNSGlobalAttributeDefinition(ns, attribute->local, 1); return attribute->cached_nsdef; } NSAttributeDefinition NamespacifyElementAttributeDefinition(AttributeDefinition attribute, NSElementDefinition nselt) { if(attribute->cached_nsdef && attribute->cached_nsdef->element && attribute->cached_nsdef->element == nselt) return attribute->cached_nsdef; attribute->cached_nsdef = FindNSElementAttributeDefinition(nselt, attribute->local, 1); return attribute->cached_nsdef; } AttributeDefinition NextAttributeDefinition(ElementDefinition element, AttributeDefinition previous) { int next = previous ? previous->attrnum+1 : 0; return next < element->nattributes ? element->attributes[next] : 0; } /* Free an attribute definition */ void FreeAttributeDefinition(AttributeDefinition a) { if(!a) return; #ifndef FOR_LT /* These things are stored elsewhere in NSL */ /* Free the name */ Free((void *)a->name); /* Free the allowed values - we rely on them being allocated as in xmlparser.c: the Char * pointers point into one single block. */ if(a->allowed_values) Free(a->allowed_values[0]); /* Free the default value */ Free((void *)a->default_value); #endif /* NSL doesn't ever get its hands on this */ Free(a->allowed_values); Free((void *)a->prefix); /* Free the attribute definition itself */ Free(a); } /* Notations */ /* * Define a new notation. The name is copied, the system and public ids are * not, but they are freed when the notation definition is freed! */ NotationDefinition DefineNotationN(Dtd dtd, const Char *name, int namelen, const char8 *publicid, const char8 *systemid, Entity parent) { NotationDefinition n; if(!(n = Malloc(sizeof(*n))) || !(name = Strndup(name, namelen))) return 0; n->name = name; n->tentative = 0; n->systemid = systemid; n->publicid = publicid; n->url = 0; n->parent = parent; n->next = dtd->notations; dtd->notations = n; return n; } NotationDefinition TentativelyDefineNotationN(Dtd dtd, const Char *name, int namelen) { NotationDefinition n; if(!(n = DefineNotationN(dtd, name, namelen, 0, 0, 0))) return 0; n->tentative = 1; return n; } NotationDefinition RedefineNotation(NotationDefinition n, const char8 *publicid, const char8 *systemid, Entity parent) { n->tentative = 0; n->systemid = systemid; n->publicid = publicid; n->parent = parent; return n; } NotationDefinition FindNotationN(Dtd dtd, const Char *name, int namelen) { NotationDefinition n; for(n = dtd->notations; n; n = n->next) if(Strncmp(name, n->name, namelen) == 0 && n->name[namelen] == 0) return n; return 0; } NotationDefinition NextNotationDefinition(Dtd dtd, NotationDefinition previous) { return previous ? previous->next : dtd->notations; } const char8 *NotationURL(NotationDefinition n) { if(n->url) return n->url; n->url = url_merge(n->systemid, n->parent ? EntityBaseURL(n->parent) : 0, 0, 0, 0, 0); return n->url; } void FreeNotationDefinition(NotationDefinition n) { if(!n) return; /* Free the name */ Free((void *)n->name); /* Free the ids */ Free((void *)n->systemid); Free((void *)n->publicid); Free((void *)n->url); /* Free the notation definition itself */ Free(n); }