]> granicus.if.org Git - libexpat/commitdiff
Namespace support
authorJames Clark <jjc@jclark.com>
Wed, 26 Aug 1998 09:10:50 +0000 (09:10 +0000)
committerJames Clark <jjc@jclark.com>
Wed, 26 Aug 1998 09:10:50 +0000 (09:10 +0000)
expat/xmlparse/xmlparse.c
expat/xmlparse/xmlparse.h
expat/xmlwf/xmlwf.c

index 8d2643d47258ee31f3cdc4a37b49f026e9568ded..46a2332a5ec9cab9a3b26e61275c2b932f924cb1 100755 (executable)
@@ -49,6 +49,7 @@ typedef char ICHAR;
 #define XmlInitUnknownEncodingNS XmlInitUnknownEncoding
 #undef XmlGetInternalEncodingNS
 #define XmlGetInternalEncodingNS XmlGetInternalEncoding
+#define XmlParseXmlDeclNS XmlParseXmlDecl
 
 #endif
 
@@ -73,6 +74,23 @@ typedef char ICHAR;
 #define INIT_BLOCK_SIZE 1024
 #define INIT_BUFFER_SIZE 1024
 
+#define EXPAND_SPARE 24
+
+typedef struct binding {
+  struct prefix *prefix;
+  struct binding *nextTagBinding;
+  struct binding *prevPrefixBinding;
+  const struct attribute_id *attId;
+  XML_Char *uri;
+  int uriLen;
+  int uriAlloc;
+} BINDING;
+
+typedef struct prefix {
+  const XML_Char *name;
+  BINDING *binding;
+} PREFIX;
+
 typedef struct tag {
   struct tag *parent;
   const char *rawName;
@@ -80,6 +98,7 @@ typedef struct tag {
   const XML_Char *name;
   char *buf;
   char *bufEnd;
+  BINDING *bindings;
 } TAG;
 
 typedef struct {
@@ -109,9 +128,11 @@ typedef struct {
 
 /* The XML_Char before the name is used to determine whether
 an attribute has been specified. */
-typedef struct {
+typedef struct attribute_id {
   XML_Char *name;
+  PREFIX *prefix;
   char maybeTokenized;
+  char xmlns;
 } ATTRIBUTE_ID;
 
 typedef struct {
@@ -122,6 +143,7 @@ typedef struct {
 
 typedef struct {
   const XML_Char *name;
+  PREFIX *prefix;
   int nDefaultAtts;
   int allocDefaultAtts;
   DEFAULT_ATTRIBUTE *defaultAtts;
@@ -131,10 +153,12 @@ typedef struct {
   HASH_TABLE generalEntities;
   HASH_TABLE elementTypes;
   HASH_TABLE attributeIds;
+  HASH_TABLE prefixes;
   STRING_POOL pool;
   int complete;
   int standalone;
   const XML_Char *base;
+  PREFIX defaultPrefix;
 } DTD;
 
 typedef enum XML_Error Processor(XML_Parser parser,
@@ -164,7 +188,10 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
          const char *start, const char *end, const char **endPtr);
 static enum XML_Error
 doCdataSection(XML_Parser parser, const ENCODING *, const char **startPtr, const char *end, const char **nextPtr);
-static enum XML_Error storeAtts(XML_Parser parser, const ENCODING *, const XML_Char *tagName, const char *s);
+static enum XML_Error storeAtts(XML_Parser parser, const ENCODING *, const char *s,
+                               const XML_Char **tagNamePtr, BINDING **bindingsPtr);
+static
+int addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId, const XML_Char *uri, BINDING **bindingsPtr);
 static int
 defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *, int isCdata, const XML_Char *dfltValue);
 static enum XML_Error
@@ -175,6 +202,7 @@ appendAttributeValue(XML_Parser parser, const ENCODING *, int isCdata, const cha
                    STRING_POOL *);
 static ATTRIBUTE_ID *
 getAttributeId(XML_Parser parser, const ENCODING *enc, const char *start, const char *end);
+static int setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *);
 static enum XML_Error
 storeEntityValue(XML_Parser parser, const char *start, const char *end);
 static int
@@ -182,8 +210,8 @@ reportProcessingInstruction(XML_Parser parser, const ENCODING *enc, const char *
 static void
 reportDefault(XML_Parser parser, const ENCODING *enc, const char *start, const char *end);
 
-static const XML_Char *getOpenEntityNames(XML_Parser parser);
-static int setOpenEntityNames(XML_Parser parser, const XML_Char *openEntityNames);
+static const XML_Char *getContext(XML_Parser parser);
+static int setContext(XML_Parser parser, const XML_Char *context);
 static void normalizePublicId(XML_Char *s);
 static int dtdInit(DTD *);
 static void dtdDestroy(DTD *);
@@ -238,9 +266,7 @@ typedef struct {
   const ENCODING *encoding;
   INIT_ENCODING initEncoding;
   const XML_Char *protocolEncodingName;
-#ifdef XMLNS
   int ns;
-#endif
   void *unknownEncodingMem;
   void *unknownEncodingData;
   void *unknownEncodingHandlerData;
@@ -261,6 +287,8 @@ typedef struct {
   DTD dtd;
   TAG *tagStack;
   TAG *freeTagList;
+  BINDING *inheritedBindings;
+  BINDING *freeBindingList;
   int attsSize;
   ATTRIBUTE *atts;
   POSITION position;
@@ -269,6 +297,7 @@ typedef struct {
   char *groupConnector;
   unsigned groupSize;
   int hadExternalDoctype;
+  XML_Char namespaceSeparator;
 } Parser;
 
 #define userData (((Parser *)parser)->userData)
@@ -290,11 +319,7 @@ typedef struct {
   (((Parser *)parser)->unknownEncodingHandlerData)
 #define unknownEncodingRelease (((Parser *)parser)->unknownEncodingRelease)
 #define protocolEncodingName (((Parser *)parser)->protocolEncodingName)
-#ifdef XMLNS
 #define ns (((Parser *)parser)->ns)
-#else
-#define ns (0)
-#endif
 #define prologState (((Parser *)parser)->prologState)
 #define processor (((Parser *)parser)->processor)
 #define errorCode (((Parser *)parser)->errorCode)
@@ -319,6 +344,8 @@ typedef struct {
 #define declAttributeId (((Parser *)parser)->declAttributeId)
 #define declAttributeIsCdata (((Parser *)parser)->declAttributeIsCdata)
 #define freeTagList (((Parser *)parser)->freeTagList)
+#define freeBindingList (((Parser *)parser)->freeBindingList)
+#define inheritedBindings (((Parser *)parser)->inheritedBindings)
 #define tagStack (((Parser *)parser)->tagStack)
 #define atts (((Parser *)parser)->atts)
 #define attsSize (((Parser *)parser)->attsSize)
@@ -327,6 +354,7 @@ typedef struct {
 #define groupConnector (((Parser *)parser)->groupConnector)
 #define groupSize (((Parser *)parser)->groupSize)
 #define hadExternalDoctype (((Parser *)parser)->hadExternalDoctype)
+#define namespaceSeparator (((Parser *)parser)->namespaceSeparator)
 
 XML_Parser XML_ParserCreate(const XML_Char *encodingName)
 {
@@ -365,6 +393,8 @@ XML_Parser XML_ParserCreate(const XML_Char *encodingName)
   tagLevel = 0;
   tagStack = 0;
   freeTagList = 0;
+  freeBindingList = 0;
+  inheritedBindings = 0;
   attsSize = INIT_ATTS_SIZE;
   atts = malloc(attsSize * sizeof(ATTRIBUTE));
   dataBuf = malloc(INIT_DATA_BUF_SIZE * sizeof(XML_Char));
@@ -375,9 +405,8 @@ XML_Parser XML_ParserCreate(const XML_Char *encodingName)
   unknownEncodingRelease = 0;
   unknownEncodingData = 0;
   unknownEncodingHandlerData = 0;
-#ifdef XMLNS
+  namespaceSeparator = '!';
   ns = 0;
-#endif
   poolInit(&tempPool);
   poolInit(&temp2Pool);
   protocolEncodingName = encodingName ? poolCopyString(&tempPool, encodingName) : 0;
@@ -391,22 +420,19 @@ XML_Parser XML_ParserCreate(const XML_Char *encodingName)
   return parser;
 }
 
-#ifdef XMLNS
-
-XML_Parser XML_ParserCreateNS(const XML_Char *encodingName)
+XML_Parser XML_ParserCreateNS(const XML_Char *encodingName, XML_Char nsSep)
 {
   XML_Parser parser = XML_ParserCreate(encodingName);
   if (parser) {
     XmlInitEncodingNS(&initEncoding, &encoding, 0);
     ns = 1;
+    namespaceSeparator = nsSep;
   }
   return parser;
 }
 
-#endif
-
 XML_Parser XML_ExternalEntityParserCreate(XML_Parser oldParser,
-                                         const XML_Char *openEntityNames,
+                                         const XML_Char *context,
                                          const XML_Char *encodingName)
 {
   XML_Parser parser = oldParser;
@@ -421,7 +447,9 @@ XML_Parser XML_ExternalEntityParserCreate(XML_Parser oldParser,
   void *oldUserData = userData;
   void *oldHandlerArg = handlerArg;
  
-  parser = (ns ? XML_ParserCreateNS : XML_ParserCreate)(encodingName);
+  parser = (ns
+            ? XML_ParserCreateNS(encodingName, namespaceSeparator)
+           : XML_ParserCreate(encodingName));
   if (!parser)
     return 0;
   startElementHandler = oldStartElementHandler;
@@ -436,7 +464,7 @@ XML_Parser XML_ExternalEntityParserCreate(XML_Parser oldParser,
     handlerArg = userData;
   else
     handlerArg = parser;
-  if (!dtdCopy(&dtd, oldDtd) || !setOpenEntityNames(parser, openEntityNames)) {
+  if (!dtdCopy(&dtd, oldDtd) || !setContext(parser, context)) {
     XML_ParserFree(parser);
     return 0;
   }
@@ -444,6 +472,19 @@ XML_Parser XML_ExternalEntityParserCreate(XML_Parser oldParser,
   return parser;
 }
 
+static
+void destroyBindings(BINDING *bindings)
+{
+  for (;;) {
+    BINDING *b = bindings;
+    if (!b)
+      break;
+    bindings = b->nextTagBinding;
+    free(b->uri);
+    free(b);
+  }
+}
+
 void XML_ParserFree(XML_Parser parser)
 {
   for (;;) {
@@ -457,8 +498,11 @@ void XML_ParserFree(XML_Parser parser)
     p = tagStack;
     tagStack = tagStack->parent;
     free(p->buf);
+    destroyBindings(p->bindings);
     free(p);
   }
+  destroyBindings(freeBindingList);
+  destroyBindings(inheritedBindings);
   poolDestroy(&tempPool);
   poolDestroy(&temp2Pool);
   dtdDestroy(&dtd);
@@ -949,13 +993,13 @@ doContent(XML_Parser parser,
              return result;
          }
          else if (externalEntityRefHandler) {
-           const XML_Char *openEntityNames;
+           const XML_Char *context;
            entity->open = 1;
-           openEntityNames = getOpenEntityNames(parser);
+           context = getContext(parser);
            entity->open = 0;
-           if (!openEntityNames)
+           if (!context)
              return XML_ERROR_NO_MEMORY;
-           if (!externalEntityRefHandler(parser, openEntityNames, dtd.base, entity->systemId, entity->publicId))
+           if (!externalEntityRefHandler(parser, context, dtd.base, entity->systemId, entity->publicId))
              return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
          }
          else if (defaultHandler)
@@ -965,7 +1009,7 @@ doContent(XML_Parser parser,
       }
     case XML_TOK_START_TAG_WITH_ATTS:
       if (!startElementHandler) {
-       enum XML_Error result = storeAtts(parser, enc, 0, s);
+       enum XML_Error result = storeAtts(parser, enc, s, 0, 0);
        if (result)
          return result;
       }
@@ -986,6 +1030,7 @@ doContent(XML_Parser parser,
            return XML_ERROR_NO_MEMORY;
          tag->bufEnd = tag->buf + INIT_TAG_BUF_SIZE;
        }
+       tag->bindings = 0;
        tag->parent = tagStack;
        tagStack = tag;
        tag->rawName = s + enc->minBytesPerChar;
@@ -1029,7 +1074,7 @@ doContent(XML_Parser parser,
              tag->rawName = tag->buf;
          }
          *toPtr = XML_T('\0');
-         result = storeAtts(parser, enc, tag->name, s);
+         result = storeAtts(parser, enc, s, &(tag->name), &(tag->bindings));
          if (result)
            return result;
          startElementHandler(handlerArg, tag->name, (const XML_Char **)atts);
@@ -1044,7 +1089,7 @@ doContent(XML_Parser parser,
       }
     case XML_TOK_EMPTY_ELEMENT_WITH_ATTS:
       if (!startElementHandler) {
-       enum XML_Error result = storeAtts(parser, enc, 0, s);
+       enum XML_Error result = storeAtts(parser, enc, s, 0, 0);
        if (result)
          return result;
       }
@@ -1052,24 +1097,33 @@ doContent(XML_Parser parser,
     case XML_TOK_EMPTY_ELEMENT_NO_ATTS:
       if (startElementHandler || endElementHandler) {
        const char *rawName = s + enc->minBytesPerChar;
+       enum XML_Error result;
+       BINDING *bindings = 0;
        const XML_Char *name = poolStoreString(&tempPool, enc, rawName,
                                               rawName
                                               + XmlNameLength(enc, rawName));
        if (!name)
          return XML_ERROR_NO_MEMORY;
        poolFinish(&tempPool);
-       if (startElementHandler) {
-         enum XML_Error result = storeAtts(parser, enc, name, s);
-         if (result)
-           return result;
+       result = storeAtts(parser, enc, s, &name, &bindings);
+       if (result)
+         return result;
+       poolFinish(&tempPool);
+       if (startElementHandler)
          startElementHandler(handlerArg, name, (const XML_Char **)atts);
-       }
        if (endElementHandler) {
          if (startElementHandler)
            *eventEndPP = *eventPP;
          endElementHandler(handlerArg, name);
        }
        poolClear(&tempPool);
+       while (bindings) {
+         BINDING *b = bindings;
+         bindings = bindings->nextTagBinding;
+         b->nextTagBinding = freeBindingList;
+         freeBindingList = b;
+         b->prefix->binding = b->prevPrefixBinding;
+       }
       }
       else if (defaultHandler)
        reportDefault(parser, enc, s, next);
@@ -1094,20 +1148,17 @@ doContent(XML_Parser parser,
          return XML_ERROR_TAG_MISMATCH;
        }
        --tagLevel;
-       if (endElementHandler) {
-         if (tag->name)
-           endElementHandler(handlerArg, tag->name);
-         else {
-           const XML_Char *name = poolStoreString(&tempPool, enc, rawName,
-                                                  rawName + len);
-           if (!name)
-             return XML_ERROR_NO_MEMORY;
-           endElementHandler(handlerArg, name);
-           poolClear(&tempPool);
-         }
-       }
+       if (endElementHandler && tag->name)
+         endElementHandler(handlerArg, tag->name);
        else if (defaultHandler)
          reportDefault(parser, enc, s, next);
+       while (tag->bindings) {
+         BINDING *b = tag->bindings;
+         tag->bindings = tag->bindings->nextTagBinding;
+         b->nextTagBinding = freeBindingList;
+         freeBindingList = b;
+         b->prefix->binding = b->prevPrefixBinding;
+       }
        if (tagLevel == 0)
          return epilogProcessor(parser, next, end, nextPtr);
       }
@@ -1211,24 +1262,37 @@ doContent(XML_Parser parser,
   /* not reached */
 }
 
-/* If tagName is non-null, build a real list of attributes,
+/* If tagNamePtr is non-null, build a real list of attributes,
 otherwise just check the attributes for well-formedness. */
 
 static enum XML_Error storeAtts(XML_Parser parser, const ENCODING *enc,
-                               const XML_Char *tagName, const char *s)
+                               const char *s, const XML_Char **tagNamePtr,
+                               BINDING **bindingsPtr)
 {
   ELEMENT_TYPE *elementType = 0;
   int nDefaultAtts = 0;
   const XML_Char **appAtts;
+  int attIndex = 0;
   int i;
   int n;
-
-  if (tagName) {
-    elementType = (ELEMENT_TYPE *)lookup(&dtd.elementTypes, tagName, 0);
-    if (elementType)
-      nDefaultAtts = elementType->nDefaultAtts;
+  int nPrefixes = 0;
+  BINDING *binding;
+  const XML_Char *localPart;
+
+  if (tagNamePtr) {
+    elementType = (ELEMENT_TYPE *)lookup(&dtd.elementTypes, *tagNamePtr, 0);
+    if (!elementType) {
+      *tagNamePtr = poolCopyString(&dtd.pool, *tagNamePtr);
+      if (!*tagNamePtr)
+       return XML_ERROR_NO_MEMORY;
+      elementType = (ELEMENT_TYPE *)lookup(&dtd.elementTypes, *tagNamePtr, sizeof(ELEMENT_TYPE));
+      if (!elementType)
+        return XML_ERROR_NO_MEMORY;
+      if (ns && !setElementTypePrefix(parser, elementType))
+        return XML_ERROR_NO_MEMORY;
+    }
+    nDefaultAtts = elementType->nDefaultAtts;
   }
-  
   n = XmlGetAttributes(enc, s, attsSize, atts);
   if (n + nDefaultAtts > attsSize) {
     int oldAttsSize = attsSize;
@@ -1242,8 +1306,8 @@ static enum XML_Error storeAtts(XML_Parser parser, const ENCODING *enc,
   appAtts = (const XML_Char **)atts;
   for (i = 0; i < n; i++) {
     ATTRIBUTE_ID *attId = getAttributeId(parser, enc, atts[i].name,
-                                         atts[i].name
-                                         + XmlNameLength(enc, atts[i].name));
+                                        atts[i].name
+                                        + XmlNameLength(enc, atts[i].name));
     if (!attId)
       return XML_ERROR_NO_MEMORY;
     if ((attId->name)[-1]) {
@@ -1252,7 +1316,7 @@ static enum XML_Error storeAtts(XML_Parser parser, const ENCODING *enc,
       return XML_ERROR_DUPLICATE_ATTRIBUTE;
     }
     (attId->name)[-1] = 1;
-    appAtts[i << 1] = attId->name;
+    appAtts[attIndex++] = attId->name;
     if (!atts[i].normalized) {
       enum XML_Error result;
       int isCdata = 1;
@@ -1272,38 +1336,167 @@ static enum XML_Error storeAtts(XML_Parser parser, const ENCODING *enc,
                                   &tempPool);
       if (result)
        return result;
-      if (tagName) {
-       appAtts[(i << 1) + 1] = poolStart(&tempPool);
+      if (tagNamePtr) {
+       appAtts[attIndex] = poolStart(&tempPool);
        poolFinish(&tempPool);
       }
       else
        poolDiscard(&tempPool);
     }
-    else if (tagName) {
-      appAtts[(i << 1) + 1] = poolStoreString(&tempPool, enc, atts[i].valuePtr, atts[i].valueEnd);
-      if (appAtts[(i << 1) + 1] == 0)
+    else if (tagNamePtr) {
+      appAtts[attIndex] = poolStoreString(&tempPool, enc, atts[i].valuePtr, atts[i].valueEnd);
+      if (appAtts[attIndex] == 0)
        return XML_ERROR_NO_MEMORY;
       poolFinish(&tempPool);
     }
+    if (attId->prefix && tagNamePtr) {
+      if (attId->xmlns) {
+        if (!addBinding(parser, attId->prefix, attId, appAtts[attIndex], bindingsPtr))
+          return XML_ERROR_NO_MEMORY;
+        --attIndex;
+      }
+      else {
+        attIndex++;
+        nPrefixes++;
+        (attId->name)[-1] = 2;
+      }
+    }
+    else
+      attIndex++;
   }
-  if (tagName) {
+  if (tagNamePtr) {
     int j;
     for (j = 0; j < nDefaultAtts; j++) {
       const DEFAULT_ATTRIBUTE *da = elementType->defaultAtts + j;
       if (!(da->id->name)[-1] && da->value) {
-       (da->id->name)[-1] = 1;
-       appAtts[i << 1] = da->id->name;
-       appAtts[(i << 1) + 1] = da->value;
-       i++;
+        if (da->id->prefix) {
+          if (da->id->xmlns) {
+           if (!addBinding(parser, da->id->prefix, da->id, da->value, bindingsPtr))
+             return XML_ERROR_NO_MEMORY;
+         }
+          else {
+           (da->id->name)[-1] = 2;
+           nPrefixes++;
+           appAtts[attIndex++] = da->id->name;
+           appAtts[attIndex++] = da->value;
+         }
+       }
+       else {
+         (da->id->name)[-1] = 1;
+         appAtts[attIndex++] = da->id->name;
+         appAtts[attIndex++] = da->value;
+       }
       }
     }
-    appAtts[i << 1] = 0;
+    appAtts[attIndex] = 0;
+  }
+  i = 0;
+  if (nPrefixes) {
+    for (; i < attIndex; i += 2) {
+      if (appAtts[i][-1] == 2) {
+        ATTRIBUTE_ID *id;
+        ((XML_Char *)(appAtts[i]))[-1] = 0;
+       id = (ATTRIBUTE_ID *)lookup(&dtd.attributeIds, appAtts[i], 0);
+       if (id->prefix->binding) {
+         int j;
+         const BINDING *b = id->prefix->binding;
+         const XML_Char *s = appAtts[i];
+         for (j = 0; j < b->uriLen; j++) {
+           if (!poolAppendChar(&tempPool, b->uri[j]))
+             return XML_ERROR_NO_MEMORY;
+         }
+         while (*s++ != ':')
+           ;
+         do {
+           if (!poolAppendChar(&tempPool, *s))
+             return XML_ERROR_NO_MEMORY;
+         } while (*s++);
+         appAtts[i] = poolStart(&tempPool);
+         poolFinish(&tempPool);
+       }
+       if (!--nPrefixes)
+         break;
+      }
+      else
+       ((XML_Char *)(appAtts[i]))[-1] = 0;
+    }
   }
-  while (i-- > 0)
-    ((XML_Char *)appAtts[i << 1])[-1] = 0;
+  for (; i < attIndex; i += 2)
+    ((XML_Char *)(appAtts[i]))[-1] = 0;
+  if (!tagNamePtr)
+    return XML_ERROR_NONE;
+  for (binding = *bindingsPtr; binding; binding = binding->nextTagBinding)
+    binding->attId->name[-1] = 0;
+  if (elementType->prefix) {
+    binding = elementType->prefix->binding;
+    if (!binding)
+      return XML_ERROR_NONE;
+    localPart = *tagNamePtr;
+    while (*localPart++ != XML_T(':'))
+      ;
+  }
+  else if (dtd.defaultPrefix.binding) {
+    binding = dtd.defaultPrefix.binding;
+    localPart = *tagNamePtr;
+  }
+  else
+    return XML_ERROR_NONE;
+  i = binding->uriLen;
+  do {
+    if (i == binding->uriAlloc) {
+      binding->uri = realloc(binding->uri, binding->uriAlloc *= 2);
+      if (!binding->uri)
+       return XML_ERROR_NO_MEMORY;
+    }
+    binding->uri[i++] = *localPart;
+  } while (*localPart++);
+  *tagNamePtr = binding->uri;
   return XML_ERROR_NONE;
 }
 
+static
+int addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId, const XML_Char *uri, BINDING **bindingsPtr)
+{
+  BINDING *b;
+  int len;
+  for (len = 0; uri[len]; len++)
+    ;
+  if (namespaceSeparator)
+    len++;
+  if (freeBindingList) {
+    b = freeBindingList;
+    if (len > b->uriAlloc) {
+      b->uri = realloc(b->uri, len + EXPAND_SPARE);
+      if (!b->uri)
+       return 0;
+      b->uriAlloc = len + EXPAND_SPARE;
+    }
+    freeBindingList = b->nextTagBinding;
+  }
+  else {
+    b = malloc(sizeof(BINDING));
+    if (!b)
+      return 0;
+    b->uri = malloc(sizeof(XML_Char) * len + EXPAND_SPARE);
+    if (!b->uri) {
+      free(b);
+      return 0;
+    }
+    b->uriAlloc = len;
+  }
+  b->uriLen = len;
+  memcpy(b->uri, uri, len * sizeof(XML_Char));
+  if (namespaceSeparator)
+    b->uri[len - 1] = namespaceSeparator;
+  b->prefix = prefix;
+  b->attId = attId;
+  b->prevPrefixBinding = b->prefix->binding;
+  b->prefix->binding = *uri == XML_T('\0') ? 0 : b;
+  b->nextTagBinding = *bindingsPtr;
+  *bindingsPtr = b;
+  return 1;
+}
+
 /* The idea here is to avoid using stack for each CDATA section when
 the whole file is parsed with one call. */
 
@@ -1613,8 +1806,11 @@ prologProcessor(XML_Parser parser,
          return XML_ERROR_NO_MEMORY;
        if (declElementType->name != name)
          poolDiscard(&dtd.pool);
-       else
+       else {
          poolFinish(&dtd.pool);
+         if (!setElementTypePrefix(parser, declElementType))
+            return XML_ERROR_NO_MEMORY;
+       }
        break;
       }
     case XML_ROLE_ATTRIBUTE_NAME:
@@ -2210,6 +2406,33 @@ defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, int isCdata, const XML_
   return 1;
 }
 
+static int setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *elementType)
+{
+  const XML_Char *name;
+  for (name = elementType->name; *name; name++) {
+    if (*name == XML_T(':')) {
+      PREFIX *prefix;
+      const XML_Char *s;
+      for (s = elementType->name; s != name; s++) {
+       if (!poolAppendChar(&dtd.pool, *s))
+         return 0;
+      }
+      if (!poolAppendChar(&dtd.pool, XML_T('\0')))
+       return 0;
+      prefix = (PREFIX *)lookup(&dtd.prefixes, poolStart(&dtd.pool), sizeof(PREFIX));
+      if (!prefix)
+       return 0;
+      if (prefix->name == poolStart(&dtd.pool))
+       poolFinish(&dtd.pool);
+      else
+       poolDiscard(&dtd.pool);
+      elementType->prefix = prefix;
+
+    }
+  }
+  return 1;
+}
+
 static ATTRIBUTE_ID *
 getAttributeId(XML_Parser parser, const ENCODING *enc, const char *start, const char *end)
 {
@@ -2226,15 +2449,94 @@ getAttributeId(XML_Parser parser, const ENCODING *enc, const char *start, const
     return 0;
   if (id->name != name)
     poolDiscard(&dtd.pool);
-  else
+  else {
     poolFinish(&dtd.pool);
+    if (!ns)
+      ;
+    else if (name[0] == 'x'
+       && name[1] == 'm'
+       && name[2] == 'l'
+       && name[3] == 'n'
+       && name[4] == 's'
+       && (name[5] == XML_T('\0') || name[5] == XML_T(':'))) {
+      if (name[5] == '\0')
+       id->prefix = &dtd.defaultPrefix;
+      else
+       id->prefix = (PREFIX *)lookup(&dtd.prefixes, name + 6, sizeof(PREFIX));
+      id->xmlns = 1;
+    }
+    else {
+      int i;
+      for (i = 0; name[i]; i++) {
+       if (name[i] == XML_T(':')) {
+         int j;
+         for (j = 0; j < i; j++) {
+           if (!poolAppendChar(&dtd.pool, name[j]))
+             return 0;
+         }
+         if (!poolAppendChar(&dtd.pool, XML_T('\0')))
+           return 0;
+         id->prefix = (PREFIX *)lookup(&dtd.prefixes, poolStart(&dtd.pool), sizeof(PREFIX));
+         if (id->prefix->name == poolStart(&dtd.pool))
+           poolFinish(&dtd.pool);
+         else
+           poolDiscard(&dtd.pool);
+         break;
+       }
+      }
+    }
+  }
   return id;
 }
 
+#define CONTEXT_SEP XML_T('\f')
+
 static
-const XML_Char *getOpenEntityNames(XML_Parser parser)
+const XML_Char *getContext(XML_Parser parser)
 {
   HASH_TABLE_ITER iter;
+  int needSep = 0;
+
+  if (dtd.defaultPrefix.binding) {
+    int i;
+    int len;
+    if (!poolAppendChar(&tempPool, XML_T('=')))
+      return 0;
+    len = dtd.defaultPrefix.binding->uriLen;
+    if (namespaceSeparator != XML_T('\0'))
+      len--;
+    for (i = 0; i < len; i++)
+      if (!poolAppendChar(&tempPool, dtd.defaultPrefix.binding->uri[i]))
+       return 0;
+    needSep = 1;
+  }
+
+  hashTableIterInit(&iter, &(dtd.prefixes));
+  for (;;) {
+    int i;
+    int len;
+    const XML_Char *s;
+    PREFIX *prefix = (PREFIX *)hashTableIterNext(&iter);
+    if (!prefix)
+      break;
+    if (!prefix->binding)
+      continue;
+    if (needSep && !poolAppendChar(&tempPool, CONTEXT_SEP))
+      return 0;
+    for (s = prefix->name; *s; s++)
+      if (!poolAppendChar(&tempPool, *s))
+        return 0;
+    if (!poolAppendChar(&tempPool, XML_T('=')))
+      return 0;
+    len = prefix->binding->uriLen;
+    if (namespaceSeparator != XML_T('\0'))
+      len--;
+    for (i = 0; i < len; i++)
+      if (!poolAppendChar(&tempPool, prefix->binding->uri[i]))
+        return 0;
+    needSep = 1;
+  }
+
 
   hashTableIterInit(&iter, &(dtd.generalEntities));
   for (;;) {
@@ -2244,11 +2546,12 @@ const XML_Char *getOpenEntityNames(XML_Parser parser)
       break;
     if (!e->open)
       continue;
-    if (poolLength(&tempPool) > 0 && !poolAppendChar(&tempPool, XML_T(' ')))
+    if (needSep && !poolAppendChar(&tempPool, CONTEXT_SEP))
       return 0;
     for (s = e->name; *s; s++)
       if (!poolAppendChar(&tempPool, *s))
         return 0;
+    needSep = 1;
   }
 
   if (!poolAppendChar(&tempPool, XML_T('\0')))
@@ -2257,21 +2560,49 @@ const XML_Char *getOpenEntityNames(XML_Parser parser)
 }
 
 static
-int setOpenEntityNames(XML_Parser parser, const XML_Char *openEntityNames)
+int setContext(XML_Parser parser, const XML_Char *context)
 {
-  const XML_Char *s = openEntityNames;
-  while (*openEntityNames != XML_T('\0')) {
-    if (*s == XML_T(' ') || *s == XML_T('\0')) {
+  const XML_Char *s = context;
+
+  while (*context != XML_T('\0')) {
+    if (*s == CONTEXT_SEP || *s == XML_T('\0')) {
       ENTITY *e;
       if (!poolAppendChar(&tempPool, XML_T('\0')))
        return 0;
       e = (ENTITY *)lookup(&dtd.generalEntities, poolStart(&tempPool), 0);
       if (e)
        e->open = 1;
-      if (*s == XML_T(' '))
+      if (*s != XML_T('\0'))
        s++;
-      openEntityNames = s;
+      context = s;
+      poolDiscard(&tempPool);
+    }
+    else if (*s == '=') {
+      PREFIX *prefix;
+      if (poolLength(&tempPool) == 0)
+       prefix = &dtd.defaultPrefix;
+      else {
+       if (!poolAppendChar(&tempPool, XML_T('\0')))
+         return 0;
+       prefix = (PREFIX *)lookup(&dtd.prefixes, poolStart(&tempPool), sizeof(PREFIX));
+       if (!prefix)
+         return 0;
+        if (prefix->name == poolStart(&tempPool))
+          poolFinish(&tempPool);
+        else
+         poolDiscard(&tempPool);
+      }
+      for (context = s + 1; *context != CONTEXT_SEP && *context != XML_T('\0'); context++)
+        if (!poolAppendChar(&tempPool, *context))
+          return 0;
+      if (!poolAppendChar(&tempPool, XML_T('\0')))
+       return 0;
+      if (!addBinding(parser, prefix, 0, poolStart(&tempPool), &inheritedBindings))
+       return 0;
       poolDiscard(&tempPool);
+      if (*context != XML_T('\0'))
+       ++context;
+      s = context;
     }
     else {
       if (!poolAppendChar(&tempPool, *s))
@@ -2311,8 +2642,11 @@ static int dtdInit(DTD *p)
   hashTableInit(&(p->generalEntities));
   hashTableInit(&(p->elementTypes));
   hashTableInit(&(p->attributeIds));
+  hashTableInit(&(p->prefixes));
   p->complete = 1;
   p->base = 0;
+  p->defaultPrefix.name = 0;
+  p->defaultPrefix.binding = 0;
   return 1;
 }
 
@@ -2330,6 +2664,7 @@ static void dtdDestroy(DTD *p)
   hashTableDestroy(&(p->generalEntities));
   hashTableDestroy(&(p->elementTypes));
   hashTableDestroy(&(p->attributeIds));
+  hashTableDestroy(&(p->prefixes));
   poolDestroy(&(p->pool));
 }
 
@@ -2347,6 +2682,21 @@ static int dtdCopy(DTD *newDtd, const DTD *oldDtd)
     newDtd->base = tem;
   }
 
+  /* Copy the prefix table. */
+
+  hashTableIterInit(&iter, &(oldDtd->prefixes));
+  for (;;) {
+    const XML_Char *name;
+    const PREFIX *oldP = (PREFIX *)hashTableIterNext(&iter);
+    if (!oldP)
+      break;
+    name = poolCopyString(&(newDtd->pool), oldP->name);
+    if (!name)
+      return 0;
+    if (!lookup(&(newDtd->prefixes), name, sizeof(PREFIX)))
+      return 0;
+  }
+
   hashTableIterInit(&iter, &(oldDtd->attributeIds));
 
   /* Copy the attribute id table. */
@@ -2369,6 +2719,13 @@ static int dtdCopy(DTD *newDtd, const DTD *oldDtd)
     if (!newA)
       return 0;
     newA->maybeTokenized = oldA->maybeTokenized;
+    if (oldA->prefix) {
+      newA->xmlns = oldA->xmlns;
+      if (oldA->prefix == &oldDtd->defaultPrefix)
+       newA->prefix = &newDtd->defaultPrefix;
+      else
+       newA->prefix = (PREFIX *)lookup(&(newDtd->prefixes), oldA->prefix->name, 0);
+    }
   }
 
   /* Copy the element type table. */
@@ -2388,10 +2745,14 @@ static int dtdCopy(DTD *newDtd, const DTD *oldDtd)
     newE = (ELEMENT_TYPE *)lookup(&(newDtd->elementTypes), name, sizeof(ELEMENT_TYPE));
     if (!newE)
       return 0;
-    newE->defaultAtts = (DEFAULT_ATTRIBUTE *)malloc(oldE->nDefaultAtts * sizeof(DEFAULT_ATTRIBUTE));
-    if (!newE->defaultAtts)
-      return 0;
+    if (oldE->nDefaultAtts) {
+      newE->defaultAtts = (DEFAULT_ATTRIBUTE *)malloc(oldE->nDefaultAtts * sizeof(DEFAULT_ATTRIBUTE));
+      if (!newE->defaultAtts)
+       return 0;
+    }
     newE->allocDefaultAtts = newE->nDefaultAtts = oldE->nDefaultAtts;
+    if (oldE->prefix)
+      newE->prefix = (PREFIX *)lookup(&(newDtd->prefixes), oldE->prefix->name, 0);
     for (i = 0; i < newE->nDefaultAtts; i++) {
       newE->defaultAtts[i].id = (ATTRIBUTE_ID *)lookup(&(newDtd->attributeIds), oldE->defaultAtts[i].id->name, 0);
       newE->defaultAtts[i].isCdata = oldE->defaultAtts[i].isCdata;
index 6ffcc74440cd1c455408d6d1bf98f187a3412077..3ae1b714825960a61ba2114b4939be3e799cf4ee 100755 (executable)
@@ -70,8 +70,18 @@ protocol or null if there is none specified. */
 XML_Parser XMLPARSEAPI
 XML_ParserCreate(const XML_Char *encoding);
 
+/* Constructs a new parser and namespace processor.  Element type names
+and attribute names that belong to a namespace will be expanded;
+unprefixed attribute names are never expanded; unprefixed element type
+names are expanded only if there is a default namespace. The expanded
+name is the concatenation of the namespace URI, the namespace separator character,
+and the local part of the name.  If the namespace separator is '\0' then
+the namespace URI and the local part will be concatenated without any
+separator.  When a namespace is not declared, the name and prefix will be
+passed through without expansion. */
+
 XML_Parser XMLPARSEAPI
-XML_ParserCreateNS(const XML_Char *encoding);
+XML_ParserCreateNS(const XML_Char *encoding, XML_Char namespaceSeparator);
 
 
 /* atts is array of name/value pairs, terminated by 0;
@@ -148,10 +158,9 @@ it may be null.
 The publicId argument is the public identifier as specified in the entity declaration,
 or null if none was specified; the whitespace in the public identifier
 will have been normalized as required by the XML spec.
-The openEntityNames argument is a space-separated list of the names of the entities
-that are open for the parse of this entity (including the name of the referenced
-entity); this can be passed as the openEntityNames argument to
-XML_ExternalEntityParserCreate; openEntityNames is valid only until the handler
+The context argument specifies the parsing context in the format
+expected by the context argument to
+XML_ExternalEntityParserCreate; context is valid only until the handler
 returns, so if the referenced entity is to be parsed later, it must be copied.
 The handler should return 0 if processing should not continue because of
 a fatal error in the handling of the external entity.
@@ -160,7 +169,7 @@ error.
 Note that unlike other handlers the first argument is the parser, not userData. */
 
 typedef int (*XML_ExternalEntityRefHandler)(XML_Parser parser,
-                                           const XML_Char *openEntityNames,
+                                           const XML_Char *context,
                                            const XML_Char *base,
                                            const XML_Char *systemId,
                                            const XML_Char *publicId);
@@ -310,10 +319,13 @@ int XMLPARSEAPI
 XML_ParseBuffer(XML_Parser parser, int len, int isFinal);
 
 /* Creates an XML_Parser object that can parse an external general entity;
-openEntityNames is a space-separated list of the names of the entities that are open
-for the parse of this entity (including the name of this one);
-encoding is the externally specified encoding,
+context is a '\0'-terminated string specifying the parse context;
+encoding is a '\0'-terminated string giving the name of the externally specified encoding,
 or null if there is no externally specified encoding.
+The context string consists of a sequence of tokens separated by formfeeds (\f);
+a token consisting of a name specifies that the general entity of the name
+is open; a token of the form prefix=uri specifies the namespace for a particular
+prefix; a token of the form =uri specifies the default namespace.
 This can be called at any point after the first call to an ExternalEntityRefHandler
 so longer as the parser has not yet been freed.
 The new parser is completely independent and may safely be used in a separate thread.
@@ -321,7 +333,7 @@ The handlers and userData are initialized from the parser argument.
 Returns 0 if out of memory.  Otherwise returns a new XML_Parser object. */
 XML_Parser XMLPARSEAPI
 XML_ExternalEntityParserCreate(XML_Parser parser,
-                              const XML_Char *openEntityNames,
+                              const XML_Char *context,
                               const XML_Char *encoding);
 
 enum XML_Error {
index b43af715088f45ab3553d520da8599125589fd4d..7968c4cd5533899c7ee080920aaef51e86a8ca9d 100755 (executable)
@@ -91,6 +91,8 @@ Contributor(s):
 #define tremove remove
 #endif /* not XML_UNICODE */
 
+#define NSSEP T('\001')
+
 static void characterData(void *userData, const XML_Char *s, int len)
 {
   FILE *fp = userData;
@@ -163,6 +165,73 @@ static void endElement(void *userData, const XML_Char *name)
   puttc(T('>'), fp);
 }
 
+static void startElementNS(void *userData, const XML_Char *name, const XML_Char **atts)
+{
+  int nAtts;
+  int nsi;
+  const XML_Char **p;
+  FILE *fp = userData;
+  const XML_Char *sep;
+  puttc(T('<'), fp);
+
+  sep = tcsrchr(name, NSSEP);
+  if (sep) {
+    fputts(T("ns0:"), fp);
+    fputts(sep + 1, fp);
+    fputts(T(" xmlns:ns0=\""), fp);
+    characterData(userData, name, sep - name);
+    puttc(T('"'), fp);
+    nsi = 1;
+  }
+  else {
+    fputts(name, fp);
+    nsi = 0;
+  }
+
+  p = atts;
+  while (*p)
+    ++p;
+  nAtts = (p - atts) >> 1;
+  if (nAtts > 1)
+    qsort((void *)atts, nAtts, sizeof(XML_Char *) * 2, attcmp);
+  while (*atts) {
+    name = *atts++;
+    sep = tcsrchr(name, NSSEP);
+    if (sep) {
+      ftprintf(fp, T(" xmlns:ns%d=\""), nsi);
+      characterData(userData, name, sep - name);
+      puttc(T('"'), fp);
+      name = sep + 1;
+      ftprintf(fp, T(" ns%d:"), nsi++);
+    }
+    else
+      puttc(T(' '), fp);
+    fputts(name, fp);
+    puttc(T('='), fp);
+    puttc(T('"'), fp);
+    characterData(userData, *atts, tcslen(*atts));
+    puttc(T('"'), fp);
+    atts++;
+  }
+  puttc(T('>'), fp);
+}
+
+static void endElementNS(void *userData, const XML_Char *name)
+{
+  FILE *fp = userData;
+  const XML_Char *sep;
+  puttc(T('<'), fp);
+  puttc(T('/'), fp);
+  sep = tcsrchr(name, NSSEP);
+  if (sep) {
+    fputts(T("ns0:"), fp);
+    fputts(sep + 1, fp);
+  }
+  else
+    fputts(name, fp);
+  puttc(T('>'), fp);
+}
+
 static void processingInstruction(void *userData, const XML_Char *target, const XML_Char *data)
 {
   FILE *fp = userData;
@@ -374,7 +443,7 @@ const XML_Char *resolveSystemId(const XML_Char *base, const XML_Char *systemId,
 
 static
 int externalEntityRefFilemap(XML_Parser parser,
-                            const XML_Char *openEntityNames,
+                            const XML_Char *context,
                             const XML_Char *base,
                             const XML_Char *systemId,
                             const XML_Char *publicId)
@@ -382,7 +451,7 @@ int externalEntityRefFilemap(XML_Parser parser,
   int result;
   XML_Char *s;
   const XML_Char *filename;
-  XML_Parser entParser = XML_ExternalEntityParserCreate(parser, openEntityNames, 0);
+  XML_Parser entParser = XML_ExternalEntityParserCreate(parser, context, 0);
   PROCESS_ARGS args;
   args.retPtr = &result;
   args.parser = entParser;
@@ -432,7 +501,7 @@ int processStream(const XML_Char *filename, XML_Parser parser)
 
 static
 int externalEntityRefStream(XML_Parser parser,
-                           const XML_Char *openEntityNames,
+                           const XML_Char *context,
                            const XML_Char *base,
                            const XML_Char *systemId,
                            const XML_Char *publicId)
@@ -440,7 +509,7 @@ int externalEntityRefStream(XML_Parser parser,
   XML_Char *s;
   const XML_Char *filename;
   int ret;
-  XML_Parser entParser = XML_ExternalEntityParserCreate(parser, openEntityNames, 0);
+  XML_Parser entParser = XML_ExternalEntityParserCreate(parser, context, 0);
   filename = resolveSystemId(base, systemId, &s);
   XML_SetBase(entParser, filename);
   ret = processStream(filename, entParser);
@@ -496,7 +565,7 @@ int unknownEncoding(void *userData,
 static
 void usage(const XML_Char *prog)
 {
-  ftprintf(stderr, T("usage: %s [-r] [-w] [-x] [-d output-dir] [-e encoding] file ...\n"), prog);
+  ftprintf(stderr, T("usage: %s [-n] [-r] [-w] [-x] [-d output-dir] [-e encoding] file ...\n"), prog);
   exit(1);
 }
 
@@ -509,9 +578,7 @@ int tmain(int argc, XML_Char **argv)
   int processExternalEntities = 0;
   int windowsCodePages = 0;
   int outputType = 0;
-#ifdef XMLNS
-  int enforceNamespaceSyntax = 0;
-#endif
+  int useNamespaces = 0;
 
 #ifdef _MSC_VER
   _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF);
@@ -529,12 +596,11 @@ int tmain(int argc, XML_Char **argv)
       useFilemap = 0;
       j++;
     }
-#ifdef XMLNS
     if (argv[i][j] == T('n')) {
-      enforceNamespaceSyntax = 1;
+      useNamespaces = 1;
+      outputType = 0;
       j++;
     }
-#endif
     if (argv[i][j] == T('x')) {
       processExternalEntities = 1;
       j++;
@@ -545,10 +611,12 @@ int tmain(int argc, XML_Char **argv)
     }
     if (argv[i][j] == T('m')) {
       outputType = 'm';
+      useNamespaces = 0;
       j++;
     }
     if (argv[i][j] == T('c')) {
       outputType = 'c';
+      useNamespaces = 0;
       j++;
     }
     if (argv[i][j] == T('d')) {
@@ -582,13 +650,11 @@ int tmain(int argc, XML_Char **argv)
     FILE *fp = 0;
     XML_Char *outName = 0;
     int result;
-#ifdef XMLNS
-    XML_Parser parser = (enforceNamespaceSyntax
-                         ? XML_ParserCreateNS
-                        : XML_ParserCreate)(encoding);
-#else
-    XML_Parser parser = XML_ParserCreate(encoding);
-#endif
+    XML_Parser parser;
+    if (useNamespaces)
+      parser = XML_ParserCreateNS(encoding, NSSEP);
+    else
+      parser = XML_ParserCreate(encoding);
     if (outputDir) {
       const XML_Char *file = argv[i];
       if (tcsrchr(file, T('/')))
@@ -606,6 +672,7 @@ int tmain(int argc, XML_Char **argv)
        tperror(outName);
        exit(1);
       }
+      setvbuf(fp, NULL, _IOFBF, 16384);
 #ifdef XML_UNICODE
       puttc(0xFEFF, fp);
 #endif
@@ -628,7 +695,10 @@ int tmain(int argc, XML_Char **argv)
        XML_SetProcessingInstructionHandler(parser, defaultProcessingInstruction);
        break;
       default:
-       XML_SetElementHandler(parser, startElement, endElement);
+       if (useNamespaces)
+         XML_SetElementHandler(parser, startElementNS, endElementNS);
+       else
+         XML_SetElementHandler(parser, startElement, endElement);
        XML_SetCharacterDataHandler(parser, characterData);
        XML_SetProcessingInstructionHandler(parser, processingInstruction);
        break;