Namespace support

This commit is contained in:
James Clark 1998-08-26 09:10:50 +00:00
parent 9f52171901
commit 2b1702456d
3 changed files with 552 additions and 109 deletions

View file

@ -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;
int nPrefixes = 0;
BINDING *binding;
const XML_Char *localPart;
if (tagName) {
elementType = (ELEMENT_TYPE *)lookup(&dtd.elementTypes, tagName, 0);
if (elementType)
nDefaultAtts = elementType->nDefaultAtts;
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;
}
while (i-- > 0)
((XML_Char *)appAtts[i << 1])[-1] = 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;
}
}
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,22 +2560,50 @@ 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))
return 0;
@ -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;

View file

@ -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 {

View file

@ -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;