From 7b75da706bf852114d792cf3b0f3c73ae0ca0fb8 Mon Sep 17 00:00:00 2001 From: Peter Breitenlohner Date: Tue, 10 Nov 2009 14:02:38 +0000 Subject: directories not used for build moved to extra/ git-svn-id: svn://tug.org/texlive/trunk@15980 c570f23f-e606-0410-a88d-b1316a301751 --- Build/source/extra/expat/xmlwf/wfcheck.c | 953 +++++++++++++++++++++++++++++++ 1 file changed, 953 insertions(+) create mode 100644 Build/source/extra/expat/xmlwf/wfcheck.c (limited to 'Build/source/extra/expat/xmlwf/wfcheck.c') diff --git a/Build/source/extra/expat/xmlwf/wfcheck.c b/Build/source/extra/expat/xmlwf/wfcheck.c new file mode 100644 index 00000000000..c18abd290bd --- /dev/null +++ b/Build/source/extra/expat/xmlwf/wfcheck.c @@ -0,0 +1,953 @@ +#include +#include + +#include "wfcheck.h" +#include "hashtable.h" + +#include "xmltok.h" +#include "xmlrole.h" + +typedef struct { + const char *name; + const char *textPtr; + size_t textLen; + const char *docTextPtr; + const char *systemId; + const char *publicId; + const char *notation; + char open; + char wfInContent; + char wfInAttribute; + char magic; +} ENTITY; + +#define INIT_BLOCK_SIZE 1024 + +typedef struct block { + struct block *next; + char s[1]; +} BLOCK; + +typedef struct { + BLOCK *blocks; + const char *end; + char *ptr; + char *start; +} STRING_POOL; + +typedef struct { + HASH_TABLE generalEntities; + HASH_TABLE paramEntities; + STRING_POOL pool; + int containsRef; + int standalone; + char *groupConnector; + size_t groupSize; +} DTD; + +typedef struct { + DTD dtd; + size_t stackSize; + const char **startName; + int attsSize; + ATTRIBUTE *atts; +} CONTEXT; + +static void poolInit(STRING_POOL *); +static void poolDestroy(STRING_POOL *); +static const char *poolAppend(STRING_POOL *pool, const ENCODING *enc, + const char *ptr, const char *end); +static const char *poolStoreString(STRING_POOL *pool, const ENCODING *enc, + const char *ptr, const char *end); +static int poolGrow(STRING_POOL *); +static int dtdInit(DTD *); +static void dtdDestroy(DTD *); +static int contextInit(CONTEXT *); +static void contextDestroy(CONTEXT *); + +#define poolStart(pool) ((pool)->start) +#define poolDiscard(pool) ((pool)->ptr = (pool)->start) +#define poolFinish(pool) ((pool)->start = (pool)->ptr) + +static enum WfCheckResult +checkProlog(DTD *, const char *s, const char *end, const char **, const ENCODING **enc); +static enum WfCheckResult +checkContent(size_t level, CONTEXT *context, const ENCODING *enc, + const char *s, const char *end, const char **badPtr); +static enum WfCheckResult +checkGeneralTextEntity(CONTEXT *context, + const char *s, const char *end, + const char **nextPtr, + const ENCODING **enc); +static enum WfCheckResult +checkAttributeValue(DTD *, const ENCODING *, const char *, const char *, const char **); +static enum WfCheckResult +checkAttributeUniqueness(CONTEXT *context, const ENCODING *enc, int nAtts, + const char **badPtr); +static enum WfCheckResult +checkParsedEntities(CONTEXT *context, const char **badPtr); + +static +enum WfCheckResult storeEntity(DTD *dtd, + const ENCODING *enc, + int isParam, + const char *entityNamePtr, + const char *entityNameEnd, + const char *entityTextPtr, + const char *entityTextEnd, + const char **badPtr); + + +enum WfCheckResult +wfCheck(enum EntityType entityType, const char *s, size_t n, + const char **badPtr, unsigned long *badLine, unsigned long *badCol) +{ + CONTEXT context; + const ENCODING *enc; + const char *start = s; + const char *end = s + n; + const char *next = 0; + enum WfCheckResult result; + + if (!contextInit(&context)) { + contextDestroy(&context); + return noMemory; + } + if (entityType == documentEntity) { + result = checkProlog(&context.dtd, s, end, &next, &enc); + s = next; + if (!result) { + result = checkParsedEntities(&context, &next); + s = next; + if (!result) { + result = checkContent(0, &context, enc, s, end, &next); + s = next; + } + } + } + else { + result = checkGeneralTextEntity(&context, s, end, &next, &enc); + s = next; + } + if (result && s) { + POSITION pos; + memset(&pos, 0, sizeof(POSITION)); + XmlUpdatePosition(enc, start, s, &pos); + *badPtr = s; + *badLine = pos.lineNumber; + *badCol = pos.columnNumber; + } + contextDestroy(&context); + return result; +} + +static +int contextInit(CONTEXT *p) +{ + p->stackSize = 1024; + p->startName = malloc(p->stackSize * sizeof(char *)); + p->attsSize = 1024; + p->atts = malloc(p->attsSize * sizeof(ATTRIBUTE)); + return dtdInit(&(p->dtd)) && p->atts && p->startName; +} + +static +void contextDestroy(CONTEXT *p) +{ + dtdDestroy(&(p->dtd)); + free((void *)p->startName); + free((void *)p->atts); +} + +static enum WfCheckResult +checkContent(size_t level, CONTEXT *context, const ENCODING *enc, + const char *s, const char *end, const char **badPtr) +{ + size_t startLevel = level; + const char *next; + int tok = XmlContentTok(enc, s, end, &next); + for (;;) { + switch (tok) { + case XML_TOK_TRAILING_CR: + case XML_TOK_NONE: + if (startLevel > 0) { + if (level != startLevel) { + *badPtr = s; + return asyncEntity; + } + return wellFormed; + } + *badPtr = s; + return noElements; + case XML_TOK_INVALID: + *badPtr = next; + return invalidToken; + case XML_TOK_PARTIAL: + *badPtr = s; + return unclosedToken; + case XML_TOK_PARTIAL_CHAR: + *badPtr = s; + return partialChar; + case XML_TOK_EMPTY_ELEMENT_NO_ATTS: + break; + case XML_TOK_ENTITY_REF: + { + const char *name = poolStoreString(&context->dtd.pool, enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + ENTITY *entity = (ENTITY *)lookup(&context->dtd.generalEntities, name, 0); + poolDiscard(&context->dtd.pool); + if (!entity) { + if (!context->dtd.containsRef || context->dtd.standalone) { + *badPtr = s; + return undefinedEntity; + } + break; + } + if (entity->wfInContent) + break; + if (entity->open) { + *badPtr = s; + return recursiveEntityRef; + } + if (entity->notation) { + *badPtr = s; + return binaryEntityRef; + } + if (entity) { + if (entity->textPtr) { + enum WfCheckResult result; + const ENCODING *internalEnc = XmlGetInternalEncoding(XML_UTF8_ENCODING); + entity->open = 1; + result = checkContent(level, context, internalEnc, + entity->textPtr, entity->textPtr + entity->textLen, + badPtr); + entity->open = 0; + if (result && *badPtr) { + *badPtr = s; + return result; + } + entity->wfInContent = 1; + } + } + break; + } + case XML_TOK_START_TAG_NO_ATTS: + if (level == context->stackSize) { + context->startName + = realloc((void *)context->startName, (context->stackSize *= 2) * sizeof(char *)); + if (!context->startName) + return noMemory; + } + context->startName[level++] = s + enc->minBytesPerChar; + break; + case XML_TOK_START_TAG_WITH_ATTS: + if (level == context->stackSize) { + context->startName = realloc((void *)context->startName, (context->stackSize *= 2) * sizeof(char *)); + if (!context->startName) + return noMemory; + } + context->startName[level++] = s + enc->minBytesPerChar; + /* fall through */ + case XML_TOK_EMPTY_ELEMENT_WITH_ATTS: + { + int i; + int n = XmlGetAttributes(enc, s, context->attsSize, context->atts); + if (n > context->attsSize) { + context->attsSize = 2*n; + context->atts = realloc((void *)context->atts, context->attsSize * sizeof(ATTRIBUTE)); + if (!context->atts) + return noMemory; + XmlGetAttributes(enc, s, n, context->atts); + } + for (i = 0; i < n; i++) { + if (!context->atts[i].normalized) { + enum WfCheckResult result + = checkAttributeValue(&context->dtd, enc, + context->atts[i].valuePtr, + context->atts[i].valueEnd, + badPtr); + if (result) + return result; + } + } + if (i > 1) { + enum WfCheckResult result = checkAttributeUniqueness(context, enc, n, badPtr); + if (result) + return result; + } + } + break; + case XML_TOK_END_TAG: + if (level == startLevel) { + *badPtr = s; + return asyncEntity; + } + --level; + if (!XmlSameName(enc, context->startName[level], s + enc->minBytesPerChar * 2)) { + *badPtr = s; + return tagMismatch; + } + break; + case XML_TOK_CHAR_REF: + if (XmlCharRefNumber(enc, s) < 0) { + *badPtr = s; + return badCharRef; + } + break; + case XML_TOK_XML_DECL: + *badPtr = s; + return misplacedXmlPi; + } + s = next; + if (level == 0) { + do { + tok = XmlPrologTok(enc, s, end, &next); + switch (tok) { + case XML_TOK_TRAILING_CR: + case XML_TOK_NONE: + return wellFormed; + case XML_TOK_PROLOG_S: + case XML_TOK_COMMENT: + case XML_TOK_PI: + s = next; + break; + default: + if (tok > 0) { + *badPtr = s; + return junkAfterDocElement; + } + break; + } + } while (tok > 0); + } + else + tok = XmlContentTok(enc, s, end, &next); + } + /* not reached */ +} + +static +int attcmp(const void *p1, const void *p2) +{ + const ATTRIBUTE *a1 = p1; + const ATTRIBUTE *a2 = p2; + size_t n1 = a1->valuePtr - a1->name; + size_t n2 = a2->valuePtr - a2->name; + + if (n1 == n2) { + int n = memcmp(a1->name, a2->name, n1); + if (n) + return n; + /* Sort identical attribute names by position, so that we always + report the first duplicate attribute. */ + if (a1->name < a2->name) + return -1; + else if (a1->name > a2->name) + return 1; + else + return 0; + } + else if (n1 < n2) + return -1; + else + return 1; +} + +/* Note that this trashes the attribute values. */ + +static enum WfCheckResult +checkAttributeUniqueness(CONTEXT *context, const ENCODING *enc, int nAtts, + const char **badPtr) +{ +#define QSORT_MIN_ATTS 10 + if (nAtts < QSORT_MIN_ATTS) { + int i; + for (i = 1; i < nAtts; i++) { + int j; + for (j = 0; j < i; j++) { + if (XmlSameName(enc, context->atts[i].name, context->atts[j].name)) { + *badPtr = context->atts[i].name; + return duplicateAttribute; + } + } + } + } + else { + int i; + const char *dup = 0; + /* Store the end of the name in valuePtr */ + for (i = 0; i < nAtts; i++) { + ATTRIBUTE *a = context->atts + i; + a->valuePtr = a->name + XmlNameLength(enc, a->name); + } + qsort(context->atts, nAtts, sizeof(ATTRIBUTE), attcmp); + for (i = 1; i < nAtts; i++) { + ATTRIBUTE *a = context->atts + i; + if (XmlSameName(enc, a->name, a[-1].name)) { + if (!dup || a->name < dup) + dup = a->name; + } + } + if (dup) { + *badPtr = dup; + return duplicateAttribute; + } + } + return wellFormed; +} + +static enum WfCheckResult +checkProlog(DTD *dtd, const char *s, const char *end, + const char **nextPtr, const ENCODING **enc) +{ + const char *entityNamePtr, *entityNameEnd; + int entityIsParam; + PROLOG_STATE state; + ENTITY *entity; + INIT_ENCODING initEnc; + XmlInitEncoding(&initEnc, enc); + XmlPrologStateInit(&state); + for (;;) { + const char *next; + int tok = XmlPrologTok(*enc, s, end, &next); + switch (XmlTokenRole(&state, tok, s, next, *enc)) { + case XML_ROLE_XML_DECL: + { + const char *encodingName = 0; + const ENCODING *encoding = 0; + const char *version; + int standalone = -1; + if (!XmlParseXmlDecl(0, + *enc, + s, + next, + nextPtr, + &version, + &encodingName, + &encoding, + &standalone)) + return syntaxError; + if (encoding) { + if (encoding->minBytesPerChar != (*enc)->minBytesPerChar) { + *nextPtr = encodingName; + return incorrectEncoding; + } + *enc = encoding; + } + else if (encodingName) { + *nextPtr = encodingName; + return unknownEncoding; + } + if (standalone == 1) + dtd->standalone = 1; + break; + } + case XML_ROLE_DOCTYPE_SYSTEM_ID: + dtd->containsRef = 1; + break; + case XML_ROLE_DOCTYPE_PUBLIC_ID: + case XML_ROLE_ENTITY_PUBLIC_ID: + case XML_ROLE_NOTATION_PUBLIC_ID: + if (!XmlIsPublicId(*enc, s, next, nextPtr)) + return syntaxError; + break; + case XML_ROLE_INSTANCE_START: + *nextPtr = s; + return wellFormed; + case XML_ROLE_DEFAULT_ATTRIBUTE_VALUE: + case XML_ROLE_FIXED_ATTRIBUTE_VALUE: + { + const char *tem = 0; + enum WfCheckResult result + = checkAttributeValue(dtd, *enc, s + (*enc)->minBytesPerChar, + next - (*enc)->minBytesPerChar, + &tem); + if (result) { + if (tem) + *nextPtr = tem; + return result; + } + break; + } + case XML_ROLE_ENTITY_VALUE: + { + enum WfCheckResult result + = storeEntity(dtd, + *enc, + entityIsParam, + entityNamePtr, + entityNameEnd, + s, + next, + nextPtr); + if (result != wellFormed) + return result; + } + break; + case XML_ROLE_ENTITY_SYSTEM_ID: + { + const char *name = poolStoreString(&dtd->pool, *enc, entityNamePtr, entityNameEnd); + entity = (ENTITY *)lookup(entityIsParam ? &dtd->paramEntities : &dtd->generalEntities, + name, sizeof(ENTITY)); + if (entity->name != name) { + poolDiscard(&dtd->pool); + entity = 0; + } + else { + poolFinish(&dtd->pool); + entity->systemId = poolStoreString(&dtd->pool, *enc, + s + (*enc)->minBytesPerChar, + next - (*enc)->minBytesPerChar); + poolFinish(&dtd->pool); + } + } + break; + case XML_ROLE_PARAM_ENTITY_REF: + { + const char *name = poolStoreString(&dtd->pool, *enc, + s + (*enc)->minBytesPerChar, + next - (*enc)->minBytesPerChar); + ENTITY *entity = (ENTITY *)lookup(&dtd->paramEntities, name, 0); + poolDiscard(&dtd->pool); + if (!entity) { + if (!dtd->containsRef || dtd->standalone) { + *nextPtr = s; + return undefinedEntity; + } + } + } + break; + case XML_ROLE_ENTITY_NOTATION_NAME: + if (entity) { + entity->notation = poolStoreString(&dtd->pool, *enc, s, next); + poolFinish(&dtd->pool); + } + break; + case XML_ROLE_GENERAL_ENTITY_NAME: + entityNamePtr = s; + entityNameEnd = next; + entityIsParam = 0; + break; + case XML_ROLE_PARAM_ENTITY_NAME: + entityNamePtr = s; + entityNameEnd = next; + entityIsParam = 1; + break; + case XML_ROLE_ERROR: + *nextPtr = s; + switch (tok) { + case XML_TOK_PARAM_ENTITY_REF: + return paramEntityRef; + case XML_TOK_INVALID: + *nextPtr = next; + return invalidToken; + case XML_TOK_NONE: + return noElements; + case XML_TOK_PARTIAL: + return unclosedToken; + case XML_TOK_PARTIAL_CHAR: + return partialChar; + case XML_TOK_TRAILING_CR: + *nextPtr = s + (*enc)->minBytesPerChar; + return noElements; + case XML_TOK_XML_DECL: + return misplacedXmlPi; + default: + return syntaxError; + } + case XML_ROLE_GROUP_OPEN: + if (state.level >= dtd->groupSize) { + if (dtd->groupSize) + dtd->groupConnector = realloc(dtd->groupConnector, dtd->groupSize *= 2); + else + dtd->groupConnector = malloc(dtd->groupSize = 32); + if (!dtd->groupConnector) + return noMemory; + } + dtd->groupConnector[state.level] = 0; + break; + case XML_ROLE_GROUP_SEQUENCE: + if (dtd->groupConnector[state.level] == '|') { + *nextPtr = s; + return syntaxError; + } + dtd->groupConnector[state.level] = ','; + break; + case XML_ROLE_GROUP_CHOICE: + if (dtd->groupConnector[state.level] == ',') { + *nextPtr = s; + return syntaxError; + } + dtd->groupConnector[state.level] = '|'; + break; + case XML_ROLE_NONE: + if (tok == XML_TOK_PARAM_ENTITY_REF) + dtd->containsRef = 1; + break; + } + s = next; + } + /* not reached */ +} + +static enum WfCheckResult +checkParsedEntities(CONTEXT *context, const char **badPtr) +{ + HASH_TABLE_ITER iter; + hashTableIterInit(&iter, &context->dtd.generalEntities); + for (;;) { + ENTITY *entity = (ENTITY *)hashTableIterNext(&iter); + if (!entity) + break; + if (entity->textPtr && !entity->wfInContent && !entity->magic) { + enum WfCheckResult result; + const ENCODING *internalEnc = XmlGetInternalEncoding(XML_UTF8_ENCODING); + entity->open = 1; + result = checkContent(1, context, internalEnc, + entity->textPtr, entity->textPtr + entity->textLen, + badPtr); + entity->open = 0; + if (result && *badPtr) { + *badPtr = entity->docTextPtr; + return result; + } + entity->wfInContent = 1; + } + } + return wellFormed; +} + +static enum WfCheckResult +checkGeneralTextEntity(CONTEXT *context, + const char *s, const char *end, + const char **nextPtr, + const ENCODING **enc) +{ + INIT_ENCODING initEnc; + const char *next; + int tok; + + XmlInitEncoding(&initEnc, enc); + tok = XmlContentTok(*enc, s, end, &next); + + if (tok == XML_TOK_BOM) { + s = next; + tok = XmlContentTok(*enc, s, end, &next); + } + if (tok == XML_TOK_XML_DECL) { + const char *encodingName = 0; + const ENCODING *encoding = 0; + const char *version; + if (!XmlParseXmlDecl(1, + *enc, + s, + next, + nextPtr, + &version, + &encodingName, + &encoding, + 0)) + return syntaxError; + if (encoding) { + if (encoding->minBytesPerChar != (*enc)->minBytesPerChar) { + *nextPtr = encodingName; + return incorrectEncoding; + } + *enc = encoding; + } + else if (encodingName) { + *nextPtr = encodingName; + return unknownEncoding; + } + s = next; + } + context->dtd.containsRef = 1; + return checkContent(1, context, *enc, s, end, nextPtr); +} + +static enum WfCheckResult +checkAttributeValue(DTD *dtd, const ENCODING *enc, + const char *ptr, const char *end, const char **badPtr) +{ + for (;;) { + const char *next; + int tok = XmlAttributeValueTok(enc, ptr, end, &next); + switch (tok) { + case XML_TOK_TRAILING_CR: + case XML_TOK_NONE: + return wellFormed; + case XML_TOK_INVALID: + *badPtr = next; + return invalidToken; + case XML_TOK_PARTIAL: + *badPtr = ptr; + return invalidToken; + case XML_TOK_CHAR_REF: + if (XmlCharRefNumber(enc, ptr) < 0) { + *badPtr = ptr; + return badCharRef; + } + break; + case XML_TOK_DATA_CHARS: + case XML_TOK_DATA_NEWLINE: + break; + case XML_TOK_ENTITY_REF: + { + const char *name = poolStoreString(&dtd->pool, enc, + ptr + enc->minBytesPerChar, + next - enc->minBytesPerChar); + ENTITY *entity = (ENTITY *)lookup(&dtd->generalEntities, name, 0); + poolDiscard(&dtd->pool); + if (!entity) { + if (!dtd->containsRef) { + *badPtr = ptr; + return undefinedEntity; + } + break; + } + if (entity->wfInAttribute) + break; + if (entity->open) { + *badPtr = ptr; + return recursiveEntityRef; + } + if (entity->notation) { + *badPtr = ptr; + return binaryEntityRef; + } + if (entity) { + if (entity->textPtr) { + enum WfCheckResult result; + const ENCODING *internalEnc = XmlGetInternalEncoding(XML_UTF8_ENCODING); + const char *textEnd = entity->textPtr + entity->textLen; + entity->open = 1; + result = checkAttributeValue(dtd, internalEnc, entity->textPtr, textEnd, badPtr); + entity->open = 0; + if (result && *badPtr) { + *badPtr = ptr; + return result; + } + entity->wfInAttribute = 1; + } + else { + *badPtr = ptr; + return attributeExternalEntityRef; + } + } + break; + } + break; + default: + abort(); + } + ptr = next; + } + /* not reached */ +} + +static +void poolInit(STRING_POOL *pool) +{ + pool->blocks = 0; + pool->start = 0; + pool->ptr = 0; + pool->end = 0; +} + +static +void poolDestroy(STRING_POOL *pool) +{ + BLOCK *p = pool->blocks; + while (p) { + BLOCK *tem = p->next; + free(p); + p = tem; + } + pool->blocks = 0; + pool->ptr = 0; + pool->start = 0; + pool->end = 0; +} + +static +const char *poolAppend(STRING_POOL *pool, const ENCODING *enc, + const char *ptr, const char *end) +{ + for (;;) { + XmlConvert(enc, XML_UTF8_ENCODING, &ptr, end, &(pool->ptr), pool->end); + if (ptr == end) + break; + if (!poolGrow(pool)) + return 0; + } + return pool->start; +} + +static +const char *poolStoreString(STRING_POOL *pool, const ENCODING *enc, + const char *ptr, const char *end) +{ + if (!poolAppend(pool, enc, ptr, end)) + return 0; + if (pool->ptr == pool->end && !poolGrow(pool)) + return 0; + *(pool->ptr)++ = 0; + return pool->start; +} + +static +int poolGrow(STRING_POOL *pool) +{ + if (pool->blocks && pool->start == pool->blocks->s) { + size_t blockSize = (pool->end - pool->start)*2; + pool->blocks = realloc(pool->blocks, offsetof(BLOCK, s) + blockSize); + if (!pool->blocks) + return 0; + pool->ptr = pool->blocks->s + (pool->ptr - pool->start); + pool->start = pool->blocks->s; + pool->end = pool->start + blockSize; + } + else { + BLOCK *tem; + size_t blockSize = pool->end - pool->start; + if (blockSize < INIT_BLOCK_SIZE) + blockSize = INIT_BLOCK_SIZE; + else + blockSize *= 2; + tem = malloc(offsetof(BLOCK, s) + blockSize); + if (!tem) + return 0; + tem->next = pool->blocks; + pool->blocks = tem; + memcpy(tem->s, pool->start, pool->ptr - pool->start); + pool->ptr = tem->s + (pool->ptr - pool->start); + pool->start = tem->s; + pool->end = tem->s + blockSize; + } + return 1; +} + +static int dtdInit(DTD *dtd) +{ + static const char *names[] = { "lt", "amp", "gt", "quot", "apos" }; + static const char chars[] = { '<', '&', '>', '"', '\'' }; + int i; + + poolInit(&(dtd->pool)); + hashTableInit(&(dtd->generalEntities)); + for (i = 0; i < 5; i++) { + ENTITY *entity = (ENTITY *)lookup(&(dtd->generalEntities), names[i], sizeof(ENTITY)); + if (!entity) + return 0; + entity->textPtr = chars + i; + entity->textLen = 1; + entity->magic = 1; + entity->wfInContent = 1; + entity->wfInAttribute = 1; + } + hashTableInit(&(dtd->paramEntities)); + dtd->containsRef = 0; + dtd->groupSize = 0; + dtd->groupConnector = 0; + return 1; +} + +static void dtdDestroy(DTD *dtd) +{ + poolDestroy(&(dtd->pool)); + hashTableDestroy(&(dtd->generalEntities)); + hashTableDestroy(&(dtd->paramEntities)); + free(dtd->groupConnector); +} + +static +enum WfCheckResult storeEntity(DTD *dtd, + const ENCODING *enc, + int isParam, + const char *entityNamePtr, + const char *entityNameEnd, + const char *entityTextPtr, + const char *entityTextEnd, + const char **badPtr) +{ + ENTITY *entity; + const ENCODING *utf8 = XmlGetInternalEncoding(XML_UTF8_ENCODING); + STRING_POOL *pool = &(dtd->pool); + if (!poolStoreString(pool, enc, entityNamePtr, entityNameEnd)) + return noMemory; + entity = (ENTITY *)lookup(isParam ? &(dtd->paramEntities) : &(dtd->generalEntities), + pool->start, + sizeof(ENTITY)); + if (entity->name != pool->start) { + poolDiscard(pool); + entityNamePtr = 0; + } + else + poolFinish(pool); + entityTextPtr += enc->minBytesPerChar; + entityTextEnd -= enc->minBytesPerChar; + entity->docTextPtr = entityTextPtr; + for (;;) { + const char *next; + int tok = XmlEntityValueTok(enc, entityTextPtr, entityTextEnd, &next); + switch (tok) { + case XML_TOK_PARAM_ENTITY_REF: + *badPtr = entityTextPtr; + return syntaxError; + case XML_TOK_NONE: + if (entityNamePtr) { + entity->textPtr = pool->start; + entity->textLen = pool->ptr - pool->start; + poolFinish(pool); + } + else + poolDiscard(pool); + return wellFormed; + case XML_TOK_ENTITY_REF: + case XML_TOK_DATA_CHARS: + if (!poolAppend(pool, enc, entityTextPtr, next)) + return noMemory; + break; + case XML_TOK_TRAILING_CR: + next = entityTextPtr + enc->minBytesPerChar; + /* fall through */ + case XML_TOK_DATA_NEWLINE: + if (pool->end == pool->ptr && !poolGrow(pool)) + return noMemory; + *(pool->ptr)++ = '\n'; + break; + case XML_TOK_CHAR_REF: + { + char buf[XML_MAX_BYTES_PER_CHAR]; + int i; + int n = XmlCharRefNumber(enc, entityTextPtr); + if (n < 0) { + *badPtr = entityTextPtr; + return badCharRef; + } + n = XmlEncode(utf8, n, buf); + if (!n) { + *badPtr = entityTextPtr; + return badCharRef; + } + for (i = 0; i < n; i++) { + if (pool->end == pool->ptr && !poolGrow(pool)) + return noMemory; + *(pool->ptr)++ = buf[i]; + } + } + break; + case XML_TOK_PARTIAL: + *badPtr = entityTextPtr; + return invalidToken; + case XML_TOK_INVALID: + *badPtr = next; + return invalidToken; + default: + abort(); + } + entityTextPtr = next; + } + /* not reached */ +} -- cgit v1.2.3