Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
11067a403b | ||
|
|
0505f1cd36 | ||
|
|
d504c1c894 | ||
|
|
59023a9533 | ||
|
|
d54b83991c | ||
|
|
0317338f10 | ||
|
|
5d0c27b76c | ||
|
|
1250e1d136 | ||
|
|
4b8e8545c5 |
+5
-2
@@ -4,7 +4,7 @@
|
||||
<TITLE>expat</TITLE>
|
||||
<BODY>
|
||||
<H1>expat - XML Parser Toolkit</H1>
|
||||
<H3>Version 19980504</H3>
|
||||
<H3>Version 19980514</H3>
|
||||
<P>
|
||||
Copyright (c) 1998 James Clark. Expat is subject to the <A
|
||||
HREF="MPL-1_0.html">Mozilla Public License Version 1.0</A>. You may
|
||||
@@ -33,7 +33,10 @@ file the corresponding <A
|
||||
href="http://www.jclark.com/xml/canonxml.html">canonical XML</A> will
|
||||
be written to <SAMP>dir/<VAR>f</VAR></SAMP>, where
|
||||
<SAMP><VAR>f</VAR></SAMP> is the filename (without any path) of the
|
||||
input file.</P>
|
||||
input file.
|
||||
A <CODE>-x</CODE> option will cause references to external general entities
|
||||
to be processed.
|
||||
</P>
|
||||
<P></P>
|
||||
<ADDRESS>
|
||||
<A HREF="mailto:jjc@jclark.com">James Clark</A>
|
||||
|
||||
+5
-5
@@ -3,13 +3,13 @@ $Revision: 1.17 $
|
||||
EndOptions
|
||||
$(projectdir)/MPL-1_0.html a 1.1
|
||||
$(projectdir)/Makefile a 1.5
|
||||
$(projectdir)/expat.html a 1.4
|
||||
$(projectdir)/expat.html a 1.6
|
||||
$(projectdir)/expat.mak a 1.12
|
||||
$(projectdir)/gennmtab/gennmtab.c a 1.2
|
||||
$(projectdir)/xmlparse/hashtable.c a 1.4
|
||||
$(projectdir)/xmlparse/hashtable.h a 1.3
|
||||
$(projectdir)/xmlparse/xmlparse.c a 1.25
|
||||
$(projectdir)/xmlparse/xmlparse.h a 1.4
|
||||
$(projectdir)/xmlparse/xmlparse.c a 1.28
|
||||
$(projectdir)/xmlparse/xmlparse.h a 1.6
|
||||
$(projectdir)/xmltok/asciitab.h a 1.4
|
||||
$(projectdir)/xmltok/dllmain.c a 1.2
|
||||
$(projectdir)/xmltok/iasciitab.h a 1.2
|
||||
@@ -18,7 +18,7 @@ $(projectdir)/xmltok/utf8tab.h a 1.4
|
||||
$(projectdir)/xmltok/xmldef.h a 1.3
|
||||
$(projectdir)/xmltok/xmlrole.c a 1.8
|
||||
$(projectdir)/xmltok/xmlrole.h a 1.4
|
||||
$(projectdir)/xmltok/xmltok.c a 1.23
|
||||
$(projectdir)/xmltok/xmltok.c a 1.24
|
||||
$(projectdir)/xmltok/xmltok.h a 1.16
|
||||
$(projectdir)/xmltok/xmltok_impl.c a 1.22
|
||||
$(projectdir)/xmltok/xmltok_impl.h a 1.5
|
||||
@@ -26,4 +26,4 @@ $(projectdir)/xmlwf/filemap.h a 1.2
|
||||
$(projectdir)/xmlwf/readfilemap.c a 1.3
|
||||
$(projectdir)/xmlwf/unixfilemap.c a 1.2
|
||||
$(projectdir)/xmlwf/win32filemap.c a 1.3
|
||||
$(projectdir)/xmlwf/xmlwf.c a 1.17
|
||||
$(projectdir)/xmlwf/xmlwf.c a 1.18
|
||||
|
||||
+411
-1
@@ -47,6 +47,7 @@ typedef struct {
|
||||
const char *textPtr;
|
||||
int textLen;
|
||||
const char *systemId;
|
||||
const char *base;
|
||||
const char *publicId;
|
||||
const char *notation;
|
||||
char open;
|
||||
@@ -94,6 +95,7 @@ typedef struct {
|
||||
STRING_POOL pool;
|
||||
int complete;
|
||||
int standalone;
|
||||
const char *base;
|
||||
} DTD;
|
||||
|
||||
typedef enum XML_Error Processor(XML_Parser parser,
|
||||
@@ -106,6 +108,8 @@ static Processor contentProcessor;
|
||||
static Processor cdataSectionProcessor;
|
||||
static Processor epilogProcessor;
|
||||
static Processor errorProcessor;
|
||||
static Processor externalEntityInitProcessor;
|
||||
static Processor externalEntityContentProcessor;
|
||||
|
||||
static enum XML_Error
|
||||
doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
|
||||
@@ -128,8 +132,12 @@ storeEntityValue(XML_Parser parser, const char *start, const char *end);
|
||||
static int
|
||||
reportProcessingInstruction(XML_Parser parser, const ENCODING *enc, const char *start, const char *end);
|
||||
|
||||
static const char *getOpenEntityNames(XML_Parser parser);
|
||||
static int setOpenEntityNames(XML_Parser parser, const char *openEntityNames);
|
||||
static void normalizePublicId(char *s);
|
||||
static int dtdInit(DTD *);
|
||||
static void dtdDestroy(DTD *);
|
||||
static int dtdCopy(DTD *newDtd, const DTD *oldDtd);
|
||||
static void poolInit(STRING_POOL *);
|
||||
static void poolClear(STRING_POOL *);
|
||||
static void poolDestroy(STRING_POOL *);
|
||||
@@ -138,6 +146,8 @@ static char *poolAppend(STRING_POOL *pool, const ENCODING *enc,
|
||||
static char *poolStoreString(STRING_POOL *pool, const ENCODING *enc,
|
||||
const char *ptr, const char *end);
|
||||
static int poolGrow(STRING_POOL *pool);
|
||||
static const char *poolCopyString(STRING_POOL *pool, const char *s);
|
||||
static const char *poolCopyStringN(STRING_POOL *pool, const char *s, int n);
|
||||
|
||||
#define poolStart(pool) ((pool)->start)
|
||||
#define poolEnd(pool) ((pool)->ptr)
|
||||
@@ -167,6 +177,7 @@ typedef struct {
|
||||
XML_EndElementHandler endElementHandler;
|
||||
XML_CharacterDataHandler characterDataHandler;
|
||||
XML_ProcessingInstructionHandler processingInstructionHandler;
|
||||
XML_ExternalEntityRefHandler externalEntityRefHandler;
|
||||
const ENCODING *encoding;
|
||||
INIT_ENCODING initEncoding;
|
||||
PROLOG_STATE prologState;
|
||||
@@ -197,6 +208,7 @@ typedef struct {
|
||||
#define endElementHandler (((Parser *)parser)->endElementHandler)
|
||||
#define characterDataHandler (((Parser *)parser)->characterDataHandler)
|
||||
#define processingInstructionHandler (((Parser *)parser)->processingInstructionHandler)
|
||||
#define externalEntityRefHandler (((Parser *)parser)->externalEntityRefHandler)
|
||||
#define encoding (((Parser *)parser)->encoding)
|
||||
#define initEncoding (((Parser *)parser)->initEncoding)
|
||||
#define prologState (((Parser *)parser)->prologState)
|
||||
@@ -240,6 +252,7 @@ XML_Parser XML_ParserCreate(const char *encodingName)
|
||||
endElementHandler = 0;
|
||||
characterDataHandler = 0;
|
||||
processingInstructionHandler = 0;
|
||||
externalEntityRefHandler = 0;
|
||||
buffer = 0;
|
||||
bufferPtr = 0;
|
||||
bufferEnd = 0;
|
||||
@@ -275,6 +288,40 @@ XML_Parser XML_ParserCreate(const char *encodingName)
|
||||
return parser;
|
||||
}
|
||||
|
||||
XML_Parser XML_ExternalEntityParserCreate(XML_Parser oldParser,
|
||||
const char *openEntityNames,
|
||||
const char *encodingName)
|
||||
{
|
||||
XML_Parser parser = oldParser;
|
||||
DTD *oldDtd = &dtd;
|
||||
XML_StartElementHandler oldStartElementHandler = startElementHandler;
|
||||
XML_EndElementHandler oldEndElementHandler = endElementHandler;
|
||||
XML_CharacterDataHandler oldCharacterDataHandler = characterDataHandler;
|
||||
XML_ProcessingInstructionHandler oldProcessingInstructionHandler = processingInstructionHandler;
|
||||
XML_ExternalEntityRefHandler oldExternalEntityRefHandler = externalEntityRefHandler;
|
||||
void *oldUserData = userData;
|
||||
|
||||
parser = XML_ParserCreate(encodingName);
|
||||
if (!parser)
|
||||
return 0;
|
||||
startElementHandler = oldStartElementHandler;
|
||||
endElementHandler = oldEndElementHandler;
|
||||
characterDataHandler = oldCharacterDataHandler;
|
||||
processingInstructionHandler = oldProcessingInstructionHandler;
|
||||
externalEntityRefHandler = oldExternalEntityRefHandler;
|
||||
userData = oldUserData;
|
||||
|
||||
if (!dtdCopy(&dtd, oldDtd) || !setOpenEntityNames(parser, openEntityNames)) {
|
||||
XML_ParserFree(parser);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (errorCode != XML_ERROR_UNKNOWN_ENCODING)
|
||||
processor = externalEntityInitProcessor;
|
||||
|
||||
return parser;
|
||||
}
|
||||
|
||||
void XML_ParserFree(XML_Parser parser)
|
||||
{
|
||||
for (;;) {
|
||||
@@ -305,6 +352,24 @@ void XML_SetUserData(XML_Parser parser, void *p)
|
||||
userData = p;
|
||||
}
|
||||
|
||||
void *XML_GetUserData(XML_Parser parser)
|
||||
{
|
||||
return userData;
|
||||
}
|
||||
|
||||
int XML_SetBase(XML_Parser parser, const char *p)
|
||||
{
|
||||
if (p) {
|
||||
p = poolCopyString(&dtd.pool, p);
|
||||
if (!p)
|
||||
return 0;
|
||||
dtd.base = p;
|
||||
}
|
||||
else
|
||||
dtd.base = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void XML_SetElementHandler(XML_Parser parser,
|
||||
XML_StartElementHandler start,
|
||||
XML_EndElementHandler end)
|
||||
@@ -325,6 +390,12 @@ void XML_SetProcessingInstructionHandler(XML_Parser parser,
|
||||
processingInstructionHandler = handler;
|
||||
}
|
||||
|
||||
void XML_SetExternalEntityRefHandler(XML_Parser parser,
|
||||
XML_ExternalEntityRefHandler handler)
|
||||
{
|
||||
externalEntityRefHandler = handler;
|
||||
}
|
||||
|
||||
int XML_Parse(XML_Parser parser, const char *s, int len, int isFinal)
|
||||
{
|
||||
bufferEndByteIndex += len;
|
||||
@@ -478,6 +549,7 @@ const char *XML_ErrorString(int code)
|
||||
"unknown encoding",
|
||||
"encoding specified in XML declaration is incorrect",
|
||||
"unclosed CDATA section",
|
||||
"error in processing external entity reference"
|
||||
};
|
||||
if (code > 0 && code < sizeof(message)/sizeof(message[0]))
|
||||
return message[code];
|
||||
@@ -493,6 +565,80 @@ enum XML_Error contentProcessor(XML_Parser parser,
|
||||
return doContent(parser, 0, encoding, start, end, endPtr);
|
||||
}
|
||||
|
||||
static
|
||||
enum XML_Error externalEntityInitProcessor(XML_Parser parser,
|
||||
const char *start,
|
||||
const char *end,
|
||||
const char **endPtr)
|
||||
{
|
||||
const char *next;
|
||||
int tok = XmlContentTok(encoding, start, end, &next);
|
||||
switch (tok) {
|
||||
case XML_TOK_BOM:
|
||||
start = next;
|
||||
tok = XmlContentTok(encoding, start, end, &next);
|
||||
if (tok != XML_TOK_XML_DECL)
|
||||
break;
|
||||
/* fall through */
|
||||
case XML_TOK_XML_DECL:
|
||||
{
|
||||
const char *encodingName = 0;
|
||||
const ENCODING *newEncoding = 0;
|
||||
const char *version;
|
||||
int standalone;
|
||||
if (!XmlParseXmlDecl(1,
|
||||
encoding,
|
||||
start,
|
||||
next,
|
||||
&errorPtr,
|
||||
&version,
|
||||
&encodingName,
|
||||
&newEncoding,
|
||||
&standalone))
|
||||
return XML_ERROR_SYNTAX;
|
||||
if (newEncoding) {
|
||||
if (newEncoding->minBytesPerChar != encoding->minBytesPerChar) {
|
||||
errorPtr = encodingName;
|
||||
return XML_ERROR_INCORRECT_ENCODING;
|
||||
}
|
||||
encoding = newEncoding;
|
||||
}
|
||||
else if (encodingName) {
|
||||
errorPtr = encodingName;
|
||||
return XML_ERROR_UNKNOWN_ENCODING;
|
||||
}
|
||||
start = next;
|
||||
break;
|
||||
}
|
||||
case XML_TOK_PARTIAL:
|
||||
if (endPtr) {
|
||||
*endPtr = start;
|
||||
return XML_ERROR_NONE;
|
||||
}
|
||||
errorPtr = start;
|
||||
return XML_ERROR_UNCLOSED_TOKEN;
|
||||
case XML_TOK_PARTIAL_CHAR:
|
||||
if (endPtr) {
|
||||
*endPtr = start;
|
||||
return XML_ERROR_NONE;
|
||||
}
|
||||
errorPtr = start;
|
||||
return XML_ERROR_PARTIAL_CHAR;
|
||||
}
|
||||
processor = externalEntityContentProcessor;
|
||||
tagLevel = 1;
|
||||
return doContent(parser, 1, encoding, start, end, endPtr);
|
||||
}
|
||||
|
||||
static
|
||||
enum XML_Error externalEntityContentProcessor(XML_Parser parser,
|
||||
const char *start,
|
||||
const char *end,
|
||||
const char **endPtr)
|
||||
{
|
||||
return doContent(parser, 1, encoding, start, end, endPtr);
|
||||
}
|
||||
|
||||
static enum XML_Error
|
||||
doContent(XML_Parser parser,
|
||||
int startTagLevel,
|
||||
@@ -507,6 +653,24 @@ doContent(XML_Parser parser,
|
||||
int tok = XmlContentTok(enc, s, end, &next);
|
||||
switch (tok) {
|
||||
case XML_TOK_TRAILING_CR:
|
||||
if (nextPtr) {
|
||||
*nextPtr = s;
|
||||
return XML_ERROR_NONE;
|
||||
}
|
||||
if (characterDataHandler) {
|
||||
char c = '\n';
|
||||
characterDataHandler(userData, &c, 1);
|
||||
}
|
||||
if (startTagLevel == 0) {
|
||||
errorPtr = s;
|
||||
return XML_ERROR_NO_ELEMENTS;
|
||||
|
||||
}
|
||||
if (tagLevel != startTagLevel) {
|
||||
errorPtr = s;
|
||||
return XML_ERROR_ASYNC_ENTITY;
|
||||
}
|
||||
return XML_ERROR_NONE;
|
||||
case XML_TOK_NONE:
|
||||
if (nextPtr) {
|
||||
*nextPtr = s;
|
||||
@@ -584,6 +748,18 @@ doContent(XML_Parser parser,
|
||||
return result;
|
||||
}
|
||||
}
|
||||
else if (externalEntityRefHandler) {
|
||||
const char *openEntityNames;
|
||||
entity->open = 1;
|
||||
openEntityNames = getOpenEntityNames(parser);
|
||||
entity->open = 0;
|
||||
if (!openEntityNames)
|
||||
return XML_ERROR_NO_MEMORY;
|
||||
if (!externalEntityRefHandler(parser, openEntityNames, dtd.base, entity->systemId, entity->publicId)) {
|
||||
errorPtr = s;
|
||||
return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1030,8 +1206,22 @@ prologProcessor(XML_Parser parser,
|
||||
case XML_ROLE_DOCTYPE_SYSTEM_ID:
|
||||
hadExternalDoctype = 1;
|
||||
break;
|
||||
case XML_ROLE_DOCTYPE_PUBLIC_ID:
|
||||
case XML_ROLE_ENTITY_PUBLIC_ID:
|
||||
if (!XmlIsPublicId(encoding, s, next, &errorPtr))
|
||||
return XML_ERROR_SYNTAX;
|
||||
if (declEntity) {
|
||||
char *tem = poolStoreString(&dtd.pool,
|
||||
encoding,
|
||||
s + encoding->minBytesPerChar,
|
||||
next - encoding->minBytesPerChar);
|
||||
if (!tem)
|
||||
return XML_ERROR_NO_MEMORY;
|
||||
normalizePublicId(tem);
|
||||
declEntity->publicId = tem;
|
||||
poolFinish(&dtd.pool);
|
||||
}
|
||||
break;
|
||||
case XML_ROLE_DOCTYPE_PUBLIC_ID:
|
||||
case XML_ROLE_NOTATION_PUBLIC_ID:
|
||||
if (!XmlIsPublicId(encoding, s, next, &errorPtr))
|
||||
return XML_ERROR_SYNTAX;
|
||||
@@ -1102,6 +1292,7 @@ prologProcessor(XML_Parser parser,
|
||||
next - encoding->minBytesPerChar);
|
||||
if (!declEntity->systemId)
|
||||
return XML_ERROR_NO_MEMORY;
|
||||
declEntity->base = dtd.base;
|
||||
poolFinish(&dtd.pool);
|
||||
}
|
||||
break;
|
||||
@@ -1537,6 +1728,80 @@ getAttributeId(XML_Parser parser, const ENCODING *enc, const char *start, const
|
||||
return id;
|
||||
}
|
||||
|
||||
static
|
||||
const char *getOpenEntityNames(XML_Parser parser)
|
||||
{
|
||||
HASH_TABLE_ITER iter;
|
||||
|
||||
hashTableIterInit(&iter, &(dtd.generalEntities));
|
||||
for (;;) {
|
||||
const char *s;
|
||||
ENTITY *e = (ENTITY *)hashTableIterNext(&iter);
|
||||
if (!e)
|
||||
break;
|
||||
if (!e->open)
|
||||
continue;
|
||||
if (poolLength(&tempPool) > 0 && !poolAppendByte(&tempPool, ' '))
|
||||
return 0;
|
||||
for (s = e->name; *s; s++)
|
||||
if (!poolAppendByte(&tempPool, *s))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!poolAppendByte(&tempPool, '\0'))
|
||||
return 0;
|
||||
return tempPool.start;
|
||||
}
|
||||
|
||||
static
|
||||
int setOpenEntityNames(XML_Parser parser, const char *openEntityNames)
|
||||
{
|
||||
const char *s = openEntityNames;
|
||||
while (*openEntityNames != '\0') {
|
||||
if (*s == ' ' || *s == '\0') {
|
||||
ENTITY *e;
|
||||
if (!poolAppendByte(&tempPool, '\0'))
|
||||
return 0;
|
||||
e = (ENTITY *)lookup(&dtd.generalEntities, poolStart(&tempPool), 0);
|
||||
if (e)
|
||||
e->open = 1;
|
||||
if (*s == ' ')
|
||||
s++;
|
||||
openEntityNames = s;
|
||||
poolDiscard(&tempPool);
|
||||
}
|
||||
else {
|
||||
if (!poolAppendByte(&tempPool, *s))
|
||||
return 0;
|
||||
s++;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
void normalizePublicId(char *publicId)
|
||||
{
|
||||
char *p = publicId;
|
||||
char *s;
|
||||
for (s = publicId; *s; s++) {
|
||||
switch (*s) {
|
||||
case ' ':
|
||||
case '\r':
|
||||
case '\n':
|
||||
if (p != publicId && p[-1] != ' ')
|
||||
*p++ = ' ';
|
||||
break;
|
||||
default:
|
||||
*p++ = *s;
|
||||
}
|
||||
}
|
||||
if (p != publicId && p[-1] == ' ')
|
||||
--p;
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
static int dtdInit(DTD *p)
|
||||
{
|
||||
static const char *names[] = { "lt", "amp", "gt", "quot", "apos" };
|
||||
@@ -1556,6 +1821,7 @@ static int dtdInit(DTD *p)
|
||||
hashTableInit(&(p->elementTypes));
|
||||
hashTableInit(&(p->attributeIds));
|
||||
p->complete = 1;
|
||||
p->base = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1575,6 +1841,126 @@ static void dtdDestroy(DTD *p)
|
||||
poolDestroy(&(p->pool));
|
||||
}
|
||||
|
||||
/* Do a deep copy of the DTD. Return 0 for out of memory; non-zero otherwise.
|
||||
The new DTD has already been initialized. */
|
||||
|
||||
static int dtdCopy(DTD *newDtd, const DTD *oldDtd)
|
||||
{
|
||||
HASH_TABLE_ITER iter;
|
||||
|
||||
if (oldDtd->base) {
|
||||
const char *tem = poolCopyString(&(newDtd->pool), oldDtd->base);
|
||||
if (!tem)
|
||||
return 0;
|
||||
newDtd->base = tem;
|
||||
}
|
||||
|
||||
hashTableIterInit(&iter, &(oldDtd->attributeIds));
|
||||
|
||||
/* Copy the attribute id table. */
|
||||
|
||||
for (;;) {
|
||||
ATTRIBUTE_ID *newA;
|
||||
const char *name;
|
||||
const ATTRIBUTE_ID *oldA = (ATTRIBUTE_ID *)hashTableIterNext(&iter);
|
||||
|
||||
if (!oldA)
|
||||
break;
|
||||
/* Remember to allocate the scratch byte before the name. */
|
||||
if (!poolAppendByte(&(newDtd->pool), 0))
|
||||
return 0;
|
||||
name = poolCopyString(&(newDtd->pool), oldA->name);
|
||||
if (!name)
|
||||
return 0;
|
||||
++name;
|
||||
newA = (ATTRIBUTE_ID *)lookup(&(newDtd->attributeIds), name, sizeof(ATTRIBUTE_ID));
|
||||
if (!newA)
|
||||
return 0;
|
||||
newA->maybeTokenized = oldA->maybeTokenized;
|
||||
}
|
||||
|
||||
/* Copy the element type table. */
|
||||
|
||||
hashTableIterInit(&iter, &(oldDtd->elementTypes));
|
||||
|
||||
for (;;) {
|
||||
int i;
|
||||
ELEMENT_TYPE *newE;
|
||||
const char *name;
|
||||
const ELEMENT_TYPE *oldE = (ELEMENT_TYPE *)hashTableIterNext(&iter);
|
||||
if (!oldE)
|
||||
break;
|
||||
name = poolCopyString(&(newDtd->pool), oldE->name);
|
||||
if (!name)
|
||||
return 0;
|
||||
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;
|
||||
newE->allocDefaultAtts = newE->nDefaultAtts = oldE->nDefaultAtts;
|
||||
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;
|
||||
newE->defaultAtts[i].value = poolCopyString(&(newDtd->pool), oldE->defaultAtts[i].value);
|
||||
if (!newE->defaultAtts[i].value)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy the entity table. */
|
||||
|
||||
hashTableIterInit(&iter, &(oldDtd->generalEntities));
|
||||
|
||||
for (;;) {
|
||||
ENTITY *newE;
|
||||
const char *name;
|
||||
const ENTITY *oldE = (ENTITY *)hashTableIterNext(&iter);
|
||||
if (!oldE)
|
||||
break;
|
||||
if (oldE->magic)
|
||||
continue;
|
||||
name = poolCopyString(&(newDtd->pool), oldE->name);
|
||||
if (!name)
|
||||
return 0;
|
||||
newE = (ENTITY *)lookup(&(newDtd->generalEntities), name, sizeof(ENTITY));
|
||||
if (!newE)
|
||||
return 0;
|
||||
if (oldE->systemId) {
|
||||
const char *tem = poolCopyString(&(newDtd->pool), oldE->systemId);
|
||||
if (!tem)
|
||||
return 0;
|
||||
newE->systemId = tem;
|
||||
if (oldE->base) {
|
||||
if (oldE->base == oldDtd->base)
|
||||
newE->base = newDtd->base;
|
||||
tem = poolCopyString(&(newDtd->pool), oldE->base);
|
||||
if (!tem)
|
||||
return 0;
|
||||
newE->base = tem;
|
||||
}
|
||||
}
|
||||
else {
|
||||
const char *tem = poolCopyStringN(&(newDtd->pool), oldE->textPtr, oldE->textLen);
|
||||
if (!tem)
|
||||
return 0;
|
||||
newE->textPtr = tem;
|
||||
newE->textLen = oldE->textLen;
|
||||
}
|
||||
if (oldE->notation) {
|
||||
const char *tem = poolCopyString(&(newDtd->pool), oldE->notation);
|
||||
if (!tem)
|
||||
return 0;
|
||||
newE->notation = tem;
|
||||
}
|
||||
}
|
||||
|
||||
newDtd->complete = oldDtd->complete;
|
||||
newDtd->standalone = oldDtd->standalone;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static
|
||||
void poolInit(STRING_POOL *pool)
|
||||
{
|
||||
@@ -1643,6 +2029,30 @@ char *poolAppend(STRING_POOL *pool, const ENCODING *enc,
|
||||
return pool->start;
|
||||
}
|
||||
|
||||
static const char *poolCopyString(STRING_POOL *pool, const char *s)
|
||||
{
|
||||
do {
|
||||
if (!poolAppendByte(pool, *s))
|
||||
return 0;
|
||||
} while (*s++);
|
||||
s = pool->start;
|
||||
poolFinish(pool);
|
||||
return s;
|
||||
}
|
||||
|
||||
static const char *poolCopyStringN(STRING_POOL *pool, const char *s, int n)
|
||||
{
|
||||
if (!pool->ptr && !poolGrow(pool))
|
||||
return 0;
|
||||
for (; n > 0; --n, s++) {
|
||||
if (!poolAppendByte(pool, *s))
|
||||
return 0;
|
||||
|
||||
}
|
||||
s = pool->start;
|
||||
poolFinish(pool);
|
||||
return s;
|
||||
}
|
||||
|
||||
static
|
||||
char *poolStoreString(STRING_POOL *pool, const ENCODING *enc,
|
||||
|
||||
@@ -31,8 +31,8 @@ extern "C" {
|
||||
|
||||
typedef void *XML_Parser;
|
||||
|
||||
/* Constructs a new parser; encoding should be the name of the charset from
|
||||
the Content-Type header if the Content-Type is text/xml, or null otherwise. */
|
||||
/* Constructs a new parser; encoding is the externally specified encoding,
|
||||
or null if there is no externally specified encoding. */
|
||||
|
||||
XML_Parser XMLPARSEAPI
|
||||
XML_ParserCreate(const char *encoding);
|
||||
@@ -58,6 +58,37 @@ typedef void (*XML_ProcessingInstructionHandler)(void *userData,
|
||||
const char *target,
|
||||
const char *data);
|
||||
|
||||
/* Reports a reference to an external parsed general entity.
|
||||
The referenced entity is not automatically parsed.
|
||||
The application can parse it immediately or later using
|
||||
XML_ExternalEntityParserCreate.
|
||||
The parser argument is the parser parsing the entity containing the reference;
|
||||
it can be passed as the parser argument to XML_ExternalEntityParserCreate.
|
||||
The systemId argument is the system identifier as specified in the entity declaration;
|
||||
it will not be null.
|
||||
The base argument is the system identifier that should be used as the base for
|
||||
resolving systemId if systemId was relative; this is set by XML_SetBase;
|
||||
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
|
||||
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.
|
||||
In this case the calling parser will return an XML_ERROR_EXTERNAL_ENTITY_HANDLING
|
||||
error.
|
||||
Note that unlike other handlers the first argument is the parser, not userData. */
|
||||
|
||||
typedef int (*XML_ExternalEntityRefHandler)(XML_Parser parser,
|
||||
const char *openEntityNames,
|
||||
const char *base,
|
||||
const char *systemId,
|
||||
const char *publicId);
|
||||
|
||||
void XMLPARSEAPI
|
||||
XML_SetElementHandler(XML_Parser parser,
|
||||
XML_StartElementHandler start,
|
||||
@@ -71,10 +102,27 @@ void XMLPARSEAPI
|
||||
XML_SetProcessingInstructionHandler(XML_Parser parser,
|
||||
XML_ProcessingInstructionHandler handler);
|
||||
|
||||
void XMLPARSEAPI
|
||||
XML_SetExternalEntityRefHandler(XML_Parser parser,
|
||||
XML_ExternalEntityRefHandler handler);
|
||||
|
||||
|
||||
/* This value is passed as the userData argument to callbacks. */
|
||||
void XMLPARSEAPI
|
||||
XML_SetUserData(XML_Parser parser, void *userData);
|
||||
|
||||
/* Returns the last value set by XML_SetUserData or null. */
|
||||
void XMLPARSEAPI *
|
||||
XML_GetUserData(XML_Parser parser);
|
||||
|
||||
/* Sets the base to be used for resolving relative URIs in system identifiers in
|
||||
declarations. Resolving relative identifiers is left to the application:
|
||||
this value will be passed through as the base argumentto the ExternalEntityRefHandler.
|
||||
The base argument will be copied. Returns zero if out of memory, non-zero otherwise. */
|
||||
|
||||
int XMLPARSEAPI
|
||||
XML_SetBase(XML_Parser parser, const char *base);
|
||||
|
||||
/* Parses some input. Returns 0 if a fatal error is detected.
|
||||
The last call to XML_Parse must have isFinal true;
|
||||
len may be zero for this call (or any other). */
|
||||
@@ -87,6 +135,21 @@ XML_GetBuffer(XML_Parser parser, int len);
|
||||
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,
|
||||
or null if there is no externally specified encoding.
|
||||
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.
|
||||
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 char *openEntityNames,
|
||||
const char *encoding);
|
||||
|
||||
/* If XML_Parser or XML_ParseEnd have returned 0, then XML_GetError*
|
||||
returns information about the error. */
|
||||
|
||||
@@ -111,7 +174,8 @@ enum XML_Error {
|
||||
XML_ERROR_MISPLACED_XML_PI,
|
||||
XML_ERROR_UNKNOWN_ENCODING,
|
||||
XML_ERROR_INCORRECT_ENCODING,
|
||||
XML_ERROR_UNCLOSED_CDATA_SECTION
|
||||
XML_ERROR_UNCLOSED_CDATA_SECTION,
|
||||
XML_ERROR_EXTERNAL_ENTITY_HANDLING
|
||||
};
|
||||
|
||||
int XMLPARSEAPI XML_GetErrorCode(XML_Parser parser);
|
||||
|
||||
@@ -240,6 +240,35 @@ static const struct normal_encoding latin1_encoding = {
|
||||
|
||||
#define latin1tab (latin1_encoding.type)
|
||||
|
||||
static
|
||||
int ascii_encode(const ENCODING *enc, int c, char *buf)
|
||||
{
|
||||
if (c < 0)
|
||||
return 0;
|
||||
if (c <= 0x7F) {
|
||||
buf[0] = (char)c;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
void ascii_toUtf8(const ENCODING *enc,
|
||||
const char **fromP, const char *fromLim,
|
||||
char **toP, const char *toLim)
|
||||
{
|
||||
while (*fromP != fromLim && *toP != toLim)
|
||||
*(*toP)++ = *(*fromP)++;
|
||||
}
|
||||
|
||||
static const struct normal_encoding ascii_encoding = {
|
||||
{ VTABLE1, ascii_encode, { ascii_toUtf8 }, 1 },
|
||||
{
|
||||
#include "asciitab.h"
|
||||
/* BT_NONXML == 0 */
|
||||
}
|
||||
};
|
||||
|
||||
#undef PREFIX
|
||||
|
||||
static int unicode_byte_type(char hi, char lo)
|
||||
@@ -514,6 +543,10 @@ int XmlInitEncoding(INIT_ENCODING *p, const ENCODING **encPtr, const char *name)
|
||||
*encPtr = &utf8_encoding.enc;
|
||||
return 1;
|
||||
}
|
||||
if (streqci(name, "US-ASCII")) {
|
||||
*encPtr = &ascii_encoding.enc;
|
||||
return 1;
|
||||
}
|
||||
if (!streqci(name, "UTF-16"))
|
||||
return 0;
|
||||
}
|
||||
@@ -653,6 +686,8 @@ const ENCODING *findEncoding(const ENCODING *enc, const char *ptr, const char *e
|
||||
return &utf8_encoding.enc;
|
||||
if (streqci(buf, "ISO-8859-1"))
|
||||
return &latin1_encoding.enc;
|
||||
if (streqci(buf, "US-ASCII"))
|
||||
return &ascii_encoding.enc;
|
||||
if (streqci(buf, "UTF-16")) {
|
||||
static const unsigned short n = 1;
|
||||
if (enc->minBytesPerChar == 2)
|
||||
|
||||
+85
-1
@@ -164,6 +164,60 @@ void processFile(const void *data, size_t size, const char *filename, void *args
|
||||
*retPtr = 1;
|
||||
}
|
||||
|
||||
static
|
||||
int isAsciiLetter(char c)
|
||||
{
|
||||
return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');
|
||||
}
|
||||
|
||||
static
|
||||
const char *resolveSystemId(const char *base, const char *systemId, char **toFree)
|
||||
{
|
||||
char *s;
|
||||
*toFree = 0;
|
||||
if (!base
|
||||
|| *systemId == '/'
|
||||
#ifdef WIN32
|
||||
|| *systemId == '\\'
|
||||
|| (isAsciiLetter(systemId[0]) && systemId[1] == ':')
|
||||
#endif
|
||||
)
|
||||
return systemId;
|
||||
*toFree = (char *)malloc(strlen(base) + strlen(systemId) + 2);
|
||||
if (!*toFree)
|
||||
return systemId;
|
||||
strcpy(*toFree, base);
|
||||
s = *toFree;
|
||||
if (strrchr(s, '/'))
|
||||
s = strrchr(s, '/') + 1;
|
||||
#ifdef WIN32
|
||||
if (strrchr(s, '\\'))
|
||||
s = strrchr(s, '\\') + 1;
|
||||
#endif
|
||||
strcpy(s, systemId);
|
||||
return *toFree;
|
||||
}
|
||||
|
||||
static
|
||||
int externalEntityRefFilemap(XML_Parser parser,
|
||||
const char *openEntityNames,
|
||||
const char *base,
|
||||
const char *systemId,
|
||||
const char *publicId)
|
||||
{
|
||||
int result;
|
||||
char *s;
|
||||
XML_Parser entParser = XML_ExternalEntityParserCreate(parser, openEntityNames, 0);
|
||||
PROCESS_ARGS args;
|
||||
args.retPtr = &result;
|
||||
args.parser = entParser;
|
||||
if (!filemap(resolveSystemId(base, systemId, &s), processFile, &args))
|
||||
result = 0;
|
||||
free(s);
|
||||
XML_ParserFree(entParser);
|
||||
return result;
|
||||
}
|
||||
|
||||
static
|
||||
int processStream(const char *filename, XML_Parser parser)
|
||||
{
|
||||
@@ -199,10 +253,25 @@ int processStream(const char *filename, XML_Parser parser)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static
|
||||
int externalEntityRefStream(XML_Parser parser,
|
||||
const char *openEntityNames,
|
||||
const char *base,
|
||||
const char *systemId,
|
||||
const char *publicId)
|
||||
{
|
||||
char *s;
|
||||
XML_Parser entParser = XML_ExternalEntityParserCreate(parser, openEntityNames, 0);
|
||||
int ret = processStream(resolveSystemId(base, systemId, &s), entParser);
|
||||
free(s);
|
||||
XML_ParserFree(entParser);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static
|
||||
void usage(const char *prog)
|
||||
{
|
||||
fprintf(stderr, "usage: %s [-r] [-d output-dir] [-e encoding] file ...\n", prog);
|
||||
fprintf(stderr, "usage: %s [-r] [-x] [-d output-dir] [-e encoding] file ...\n", prog);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -212,6 +281,7 @@ int main(int argc, char **argv)
|
||||
const char *outputDir = 0;
|
||||
const char *encoding = 0;
|
||||
int useFilemap = 1;
|
||||
int processExternalEntities = 0;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF);
|
||||
@@ -229,6 +299,10 @@ int main(int argc, char **argv)
|
||||
useFilemap = 0;
|
||||
j++;
|
||||
}
|
||||
if (argv[i][j] == 'x') {
|
||||
processExternalEntities = 1;
|
||||
j++;
|
||||
}
|
||||
if (argv[i][j] == 'd') {
|
||||
if (argv[i][j + 1] == '\0') {
|
||||
if (++i == argc)
|
||||
@@ -283,6 +357,16 @@ int main(int argc, char **argv)
|
||||
XML_SetCharacterDataHandler(parser, characterData);
|
||||
XML_SetProcessingInstructionHandler(parser, processingInstruction);
|
||||
}
|
||||
if (processExternalEntities) {
|
||||
if (!XML_SetBase(parser, argv[i])) {
|
||||
fprintf(stderr, "%s: out of memory", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
XML_SetExternalEntityRefHandler(parser,
|
||||
useFilemap
|
||||
? externalEntityRefFilemap
|
||||
: externalEntityRefStream);
|
||||
}
|
||||
if (useFilemap) {
|
||||
PROCESS_ARGS args;
|
||||
args.retPtr = &result;
|
||||
|
||||
Reference in New Issue
Block a user