/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd | |
See the file COPYING for copying permission. | |
*/ | |
#define XML_BUILDING_EXPAT 1 | |
#ifdef COMPILED_FROM_DSP | |
#include "winconfig.h" | |
#elif defined(MACOS_CLASSIC) | |
#include "macconfig.h" | |
#elif defined(__amigaos4__) | |
#include "amigaconfig.h" | |
#elif defined(HAVE_EXPAT_CONFIG_H) | |
#include <expat_config.h> | |
#endif /* ndef COMPILED_FROM_DSP */ | |
#include <stddef.h> | |
#include <string.h> /* memset(), memcpy() */ | |
#include <assert.h> | |
#if defined(UEFI_C_SOURCE) | |
#include <expat/expat.h> | |
#else | |
#include "expat.h" | |
#endif | |
#ifdef XML_UNICODE | |
#define XML_ENCODE_MAX XML_UTF16_ENCODE_MAX | |
#define XmlConvert XmlUtf16Convert | |
#define XmlGetInternalEncoding XmlGetUtf16InternalEncoding | |
#define XmlGetInternalEncodingNS XmlGetUtf16InternalEncodingNS | |
#define XmlEncode XmlUtf16Encode | |
#define MUST_CONVERT(enc, s) (!(enc)->isUtf16 || (((unsigned long)s) & 1)) | |
typedef unsigned short ICHAR; | |
#else | |
#define XML_ENCODE_MAX XML_UTF8_ENCODE_MAX | |
#define XmlConvert XmlUtf8Convert | |
#define XmlGetInternalEncoding XmlGetUtf8InternalEncoding | |
#define XmlGetInternalEncodingNS XmlGetUtf8InternalEncodingNS | |
#define XmlEncode XmlUtf8Encode | |
#define MUST_CONVERT(enc, s) (!(enc)->isUtf8) | |
typedef char ICHAR; | |
#endif | |
#ifndef XML_NS | |
#define XmlInitEncodingNS XmlInitEncoding | |
#define XmlInitUnknownEncodingNS XmlInitUnknownEncoding | |
#undef XmlGetInternalEncodingNS | |
#define XmlGetInternalEncodingNS XmlGetInternalEncoding | |
#define XmlParseXmlDeclNS XmlParseXmlDecl | |
#endif | |
#ifdef XML_UNICODE | |
#ifdef XML_UNICODE_WCHAR_T | |
#define XML_T(x) (const wchar_t)x | |
#define XML_L(x) L ## x | |
#else | |
#define XML_T(x) (const unsigned short)x | |
#define XML_L(x) x | |
#endif | |
#else | |
#define XML_T(x) x | |
#define XML_L(x) x | |
#endif | |
/* Round up n to be a multiple of sz, where sz is a power of 2. */ | |
#define ROUND_UP(n, sz) (((n) + ((sz) - 1)) & ~((sz) - 1)) | |
/* Handle the case where memmove() doesn't exist. */ | |
#ifndef HAVE_MEMMOVE | |
#ifdef HAVE_BCOPY | |
#define memmove(d,s,l) bcopy((s),(d),(l)) | |
#else | |
#error memmove does not exist on this platform, nor is a substitute available | |
#endif /* HAVE_BCOPY */ | |
#endif /* HAVE_MEMMOVE */ | |
#include "internal.h" | |
#include "xmltok.h" | |
#include "xmlrole.h" | |
typedef const XML_Char *KEY; | |
typedef struct { | |
KEY name; | |
} NAMED; | |
typedef struct { | |
NAMED **v; | |
unsigned char power; | |
size_t size; | |
size_t used; | |
const XML_Memory_Handling_Suite *mem; | |
} HASH_TABLE; | |
/* Basic character hash algorithm, taken from Python's string hash: | |
h = h * 1000003 ^ character, the constant being a prime number. | |
*/ | |
#ifdef XML_UNICODE | |
#define CHAR_HASH(h, c) \ | |
(((h) * 0xF4243) ^ (unsigned short)(c)) | |
#else | |
#define CHAR_HASH(h, c) \ | |
(((h) * 0xF4243) ^ (unsigned char)(c)) | |
#endif | |
/* For probing (after a collision) we need a step size relative prime | |
to the hash table size, which is a power of 2. We use double-hashing, | |
since we can calculate a second hash value cheaply by taking those bits | |
of the first hash value that were discarded (masked out) when the table | |
index was calculated: index = hash & mask, where mask = table->size - 1. | |
We limit the maximum step size to table->size / 4 (mask >> 2) and make | |
it odd, since odd numbers are always relative prime to a power of 2. | |
*/ | |
#define SECOND_HASH(hash, mask, power) \ | |
((((hash) & ~(mask)) >> ((power) - 1)) & ((mask) >> 2)) | |
#define PROBE_STEP(hash, mask, power) \ | |
((unsigned char)((SECOND_HASH(hash, mask, power)) | 1)) | |
typedef struct { | |
NAMED **p; | |
NAMED **end; | |
} HASH_TABLE_ITER; | |
#define INIT_TAG_BUF_SIZE 32 /* must be a multiple of sizeof(XML_Char) */ | |
#define INIT_DATA_BUF_SIZE 1024 | |
#define INIT_ATTS_SIZE 16 | |
#define INIT_ATTS_VERSION 0xFFFFFFFF | |
#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 { | |
const XML_Char *str; | |
const XML_Char *localPart; | |
const XML_Char *prefix; | |
int strLen; | |
int uriLen; | |
int prefixLen; | |
} TAG_NAME; | |
/* TAG represents an open element. | |
The name of the element is stored in both the document and API | |
encodings. The memory buffer 'buf' is a separately-allocated | |
memory area which stores the name. During the XML_Parse()/ | |
XMLParseBuffer() when the element is open, the memory for the 'raw' | |
version of the name (in the document encoding) is shared with the | |
document buffer. If the element is open across calls to | |
XML_Parse()/XML_ParseBuffer(), the buffer is re-allocated to | |
contain the 'raw' name as well. | |
A parser re-uses these structures, maintaining a list of allocated | |
TAG objects in a free list. | |
*/ | |
typedef struct tag { | |
struct tag *parent; /* parent of this element */ | |
const char *rawName; /* tagName in the original encoding */ | |
int rawNameLength; | |
TAG_NAME name; /* tagName in the API encoding */ | |
char *buf; /* buffer for name components */ | |
char *bufEnd; /* end of the buffer */ | |
BINDING *bindings; | |
} TAG; | |
typedef struct { | |
const XML_Char *name; | |
const XML_Char *textPtr; | |
int textLen; /* length in XML_Chars */ | |
int processed; /* # of processed bytes - when suspended */ | |
const XML_Char *systemId; | |
const XML_Char *base; | |
const XML_Char *publicId; | |
const XML_Char *notation; | |
XML_Bool open; | |
XML_Bool is_param; | |
XML_Bool is_internal; /* true if declared in internal subset outside PE */ | |
} ENTITY; | |
typedef struct { | |
enum XML_Content_Type type; | |
enum XML_Content_Quant quant; | |
const XML_Char * name; | |
int firstchild; | |
int lastchild; | |
int childcnt; | |
int nextsib; | |
} CONTENT_SCAFFOLD; | |
#define INIT_SCAFFOLD_ELEMENTS 32 | |
typedef struct block { | |
struct block *next; | |
int size; | |
XML_Char s[1]; | |
} BLOCK; | |
typedef struct { | |
BLOCK *blocks; | |
BLOCK *freeBlocks; | |
const XML_Char *end; | |
XML_Char *ptr; | |
XML_Char *start; | |
const XML_Memory_Handling_Suite *mem; | |
} STRING_POOL; | |
/* The XML_Char before the name is used to determine whether | |
an attribute has been specified. */ | |
typedef struct attribute_id { | |
XML_Char *name; | |
PREFIX *prefix; | |
XML_Bool maybeTokenized; | |
XML_Bool xmlns; | |
} ATTRIBUTE_ID; | |
typedef struct { | |
const ATTRIBUTE_ID *id; | |
XML_Bool isCdata; | |
const XML_Char *value; | |
} DEFAULT_ATTRIBUTE; | |
typedef struct { | |
unsigned long version; | |
unsigned long hash; | |
const XML_Char *uriName; | |
} NS_ATT; | |
typedef struct { | |
const XML_Char *name; | |
PREFIX *prefix; | |
const ATTRIBUTE_ID *idAtt; | |
int nDefaultAtts; | |
int allocDefaultAtts; | |
DEFAULT_ATTRIBUTE *defaultAtts; | |
} ELEMENT_TYPE; | |
typedef struct { | |
HASH_TABLE generalEntities; | |
HASH_TABLE elementTypes; | |
HASH_TABLE attributeIds; | |
HASH_TABLE prefixes; | |
STRING_POOL pool; | |
STRING_POOL entityValuePool; | |
/* false once a parameter entity reference has been skipped */ | |
XML_Bool keepProcessing; | |
/* true once an internal or external PE reference has been encountered; | |
this includes the reference to an external subset */ | |
XML_Bool hasParamEntityRefs; | |
XML_Bool standalone; | |
#ifdef XML_DTD | |
/* indicates if external PE has been read */ | |
XML_Bool paramEntityRead; | |
HASH_TABLE paramEntities; | |
#endif /* XML_DTD */ | |
PREFIX defaultPrefix; | |
/* === scaffolding for building content model === */ | |
XML_Bool in_eldecl; | |
CONTENT_SCAFFOLD *scaffold; | |
unsigned contentStringLen; | |
unsigned scaffSize; | |
unsigned scaffCount; | |
int scaffLevel; | |
int *scaffIndex; | |
} DTD; | |
typedef struct open_internal_entity { | |
const char *internalEventPtr; | |
const char *internalEventEndPtr; | |
struct open_internal_entity *next; | |
ENTITY *entity; | |
int startTagLevel; | |
XML_Bool betweenDecl; /* WFC: PE Between Declarations */ | |
} OPEN_INTERNAL_ENTITY; | |
typedef enum XML_Error PTRCALL Processor(XML_Parser parser, | |
const char *start, | |
const char *end, | |
const char **endPtr); | |
static Processor prologProcessor; | |
static Processor prologInitProcessor; | |
static Processor contentProcessor; | |
static Processor cdataSectionProcessor; | |
#ifdef XML_DTD | |
static Processor ignoreSectionProcessor; | |
static Processor externalParEntProcessor; | |
static Processor externalParEntInitProcessor; | |
static Processor entityValueProcessor; | |
static Processor entityValueInitProcessor; | |
#endif /* XML_DTD */ | |
static Processor epilogProcessor; | |
static Processor errorProcessor; | |
static Processor externalEntityInitProcessor; | |
static Processor externalEntityInitProcessor2; | |
static Processor externalEntityInitProcessor3; | |
static Processor externalEntityContentProcessor; | |
static Processor internalEntityProcessor; | |
static enum XML_Error | |
handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName); | |
static enum XML_Error | |
processXmlDecl(XML_Parser parser, int isGeneralTextEntity, | |
const char *s, const char *next); | |
static enum XML_Error | |
initializeEncoding(XML_Parser parser); | |
static enum XML_Error | |
doProlog(XML_Parser parser, const ENCODING *enc, const char *s, | |
const char *end, int tok, const char *next, const char **nextPtr, | |
XML_Bool haveMore); | |
static enum XML_Error | |
processInternalEntity(XML_Parser parser, ENTITY *entity, | |
XML_Bool betweenDecl); | |
static enum XML_Error | |
doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, | |
const char *start, const char *end, const char **endPtr, | |
XML_Bool haveMore); | |
static enum XML_Error | |
doCdataSection(XML_Parser parser, const ENCODING *, const char **startPtr, | |
const char *end, const char **nextPtr, XML_Bool haveMore); | |
#ifdef XML_DTD | |
static enum XML_Error | |
doIgnoreSection(XML_Parser parser, const ENCODING *, const char **startPtr, | |
const char *end, const char **nextPtr, XML_Bool haveMore); | |
#endif /* XML_DTD */ | |
static enum XML_Error | |
storeAtts(XML_Parser parser, const ENCODING *, const char *s, | |
TAG_NAME *tagNamePtr, BINDING **bindingsPtr); | |
static enum XML_Error | |
addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId, | |
const XML_Char *uri, BINDING **bindingsPtr); | |
static int | |
defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *, XML_Bool isCdata, | |
XML_Bool isId, const XML_Char *dfltValue, XML_Parser parser); | |
static enum XML_Error | |
storeAttributeValue(XML_Parser parser, const ENCODING *, XML_Bool isCdata, | |
const char *, const char *, STRING_POOL *); | |
static enum XML_Error | |
appendAttributeValue(XML_Parser parser, const ENCODING *, XML_Bool isCdata, | |
const char *, const char *, 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 ENCODING *enc, const char *start, | |
const char *end); | |
static int | |
reportProcessingInstruction(XML_Parser parser, const ENCODING *enc, | |
const char *start, const char *end); | |
static int | |
reportComment(XML_Parser parser, const ENCODING *enc, const char *start, | |
const char *end); | |
static void | |
reportDefault(XML_Parser parser, const ENCODING *enc, const char *start, | |
const char *end); | |
static const XML_Char * getContext(XML_Parser parser); | |
static XML_Bool | |
setContext(XML_Parser parser, const XML_Char *context); | |
static void FASTCALL normalizePublicId(XML_Char *s); | |
static DTD * dtdCreate(const XML_Memory_Handling_Suite *ms); | |
/* do not call if parentParser != NULL */ | |
static void dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms); | |
static void | |
dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms); | |
static int | |
dtdCopy(DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms); | |
static int | |
copyEntityTable(HASH_TABLE *, STRING_POOL *, const HASH_TABLE *); | |
static NAMED * | |
lookup(HASH_TABLE *table, KEY name, size_t createSize); | |
static void FASTCALL | |
hashTableInit(HASH_TABLE *, const XML_Memory_Handling_Suite *ms); | |
static void FASTCALL hashTableClear(HASH_TABLE *); | |
static void FASTCALL hashTableDestroy(HASH_TABLE *); | |
static void FASTCALL | |
hashTableIterInit(HASH_TABLE_ITER *, const HASH_TABLE *); | |
static NAMED * FASTCALL hashTableIterNext(HASH_TABLE_ITER *); | |
static void FASTCALL | |
poolInit(STRING_POOL *, const XML_Memory_Handling_Suite *ms); | |
static void FASTCALL poolClear(STRING_POOL *); | |
static void FASTCALL poolDestroy(STRING_POOL *); | |
static XML_Char * | |
poolAppend(STRING_POOL *pool, const ENCODING *enc, | |
const char *ptr, const char *end); | |
static XML_Char * | |
poolStoreString(STRING_POOL *pool, const ENCODING *enc, | |
const char *ptr, const char *end); | |
static XML_Bool FASTCALL poolGrow(STRING_POOL *pool); | |
static const XML_Char * FASTCALL | |
poolCopyString(STRING_POOL *pool, const XML_Char *s); | |
static const XML_Char * | |
poolCopyStringN(STRING_POOL *pool, const XML_Char *s, int n); | |
static const XML_Char * FASTCALL | |
poolAppendString(STRING_POOL *pool, const XML_Char *s); | |
static int FASTCALL nextScaffoldPart(XML_Parser parser); | |
static XML_Content * build_model(XML_Parser parser); | |
static ELEMENT_TYPE * | |
getElementType(XML_Parser parser, const ENCODING *enc, | |
const char *ptr, const char *end); | |
static XML_Parser | |
parserCreate(const XML_Char *encodingName, | |
const XML_Memory_Handling_Suite *memsuite, | |
const XML_Char *nameSep, | |
DTD *dtd); | |
static void | |
parserInit(XML_Parser parser, const XML_Char *encodingName); | |
#define poolStart(pool) ((pool)->start) | |
#define poolEnd(pool) ((pool)->ptr) | |
#define poolLength(pool) ((pool)->ptr - (pool)->start) | |
#define poolChop(pool) ((void)--(pool->ptr)) | |
#define poolLastChar(pool) (((pool)->ptr)[-1]) | |
#define poolDiscard(pool) ((pool)->ptr = (pool)->start) | |
#define poolFinish(pool) ((pool)->start = (pool)->ptr) | |
#define poolAppendChar(pool, c) \ | |
(((pool)->ptr == (pool)->end && !poolGrow(pool)) \ | |
? 0 \ | |
: ((*((pool)->ptr)++ = c), 1)) | |
struct XML_ParserStruct { | |
/* The first member must be userData so that the XML_GetUserData | |
macro works. */ | |
void *m_userData; | |
void *m_handlerArg; | |
char *m_buffer; | |
const XML_Memory_Handling_Suite m_mem; | |
/* first character to be parsed */ | |
const char *m_bufferPtr; | |
/* past last character to be parsed */ | |
char *m_bufferEnd; | |
/* allocated end of buffer */ | |
const char *m_bufferLim; | |
XML_Index m_parseEndByteIndex; | |
const char *m_parseEndPtr; | |
XML_Char *m_dataBuf; | |
XML_Char *m_dataBufEnd; | |
XML_StartElementHandler m_startElementHandler; | |
XML_EndElementHandler m_endElementHandler; | |
XML_CharacterDataHandler m_characterDataHandler; | |
XML_ProcessingInstructionHandler m_processingInstructionHandler; | |
XML_CommentHandler m_commentHandler; | |
XML_StartCdataSectionHandler m_startCdataSectionHandler; | |
XML_EndCdataSectionHandler m_endCdataSectionHandler; | |
XML_DefaultHandler m_defaultHandler; | |
XML_StartDoctypeDeclHandler m_startDoctypeDeclHandler; | |
XML_EndDoctypeDeclHandler m_endDoctypeDeclHandler; | |
XML_UnparsedEntityDeclHandler m_unparsedEntityDeclHandler; | |
XML_NotationDeclHandler m_notationDeclHandler; | |
XML_StartNamespaceDeclHandler m_startNamespaceDeclHandler; | |
XML_EndNamespaceDeclHandler m_endNamespaceDeclHandler; | |
XML_NotStandaloneHandler m_notStandaloneHandler; | |
XML_ExternalEntityRefHandler m_externalEntityRefHandler; | |
XML_Parser m_externalEntityRefHandlerArg; | |
XML_SkippedEntityHandler m_skippedEntityHandler; | |
XML_UnknownEncodingHandler m_unknownEncodingHandler; | |
XML_ElementDeclHandler m_elementDeclHandler; | |
XML_AttlistDeclHandler m_attlistDeclHandler; | |
XML_EntityDeclHandler m_entityDeclHandler; | |
XML_XmlDeclHandler m_xmlDeclHandler; | |
const ENCODING *m_encoding; | |
INIT_ENCODING m_initEncoding; | |
const ENCODING *m_internalEncoding; | |
const XML_Char *m_protocolEncodingName; | |
XML_Bool m_ns; | |
XML_Bool m_ns_triplets; | |
void *m_unknownEncodingMem; | |
void *m_unknownEncodingData; | |
void *m_unknownEncodingHandlerData; | |
void (XMLCALL *m_unknownEncodingRelease)(void *); | |
PROLOG_STATE m_prologState; | |
Processor *m_processor; | |
enum XML_Error m_errorCode; | |
const char *m_eventPtr; | |
const char *m_eventEndPtr; | |
const char *m_positionPtr; | |
OPEN_INTERNAL_ENTITY *m_openInternalEntities; | |
OPEN_INTERNAL_ENTITY *m_freeInternalEntities; | |
XML_Bool m_defaultExpandInternalEntities; | |
int m_tagLevel; | |
ENTITY *m_declEntity; | |
const XML_Char *m_doctypeName; | |
const XML_Char *m_doctypeSysid; | |
const XML_Char *m_doctypePubid; | |
const XML_Char *m_declAttributeType; | |
const XML_Char *m_declNotationName; | |
const XML_Char *m_declNotationPublicId; | |
ELEMENT_TYPE *m_declElementType; | |
ATTRIBUTE_ID *m_declAttributeId; | |
XML_Bool m_declAttributeIsCdata; | |
XML_Bool m_declAttributeIsId; | |
DTD *m_dtd; | |
const XML_Char *m_curBase; | |
TAG *m_tagStack; | |
TAG *m_freeTagList; | |
BINDING *m_inheritedBindings; | |
BINDING *m_freeBindingList; | |
int m_attsSize; | |
int m_nSpecifiedAtts; | |
int m_idAttIndex; | |
ATTRIBUTE *m_atts; | |
NS_ATT *m_nsAtts; | |
unsigned long m_nsAttsVersion; | |
unsigned char m_nsAttsPower; | |
POSITION m_position; | |
STRING_POOL m_tempPool; | |
STRING_POOL m_temp2Pool; | |
char *m_groupConnector; | |
unsigned int m_groupSize; | |
XML_Char m_namespaceSeparator; | |
XML_Parser m_parentParser; | |
XML_ParsingStatus m_parsingStatus; | |
#ifdef XML_DTD | |
XML_Bool m_isParamEntity; | |
XML_Bool m_useForeignDTD; | |
enum XML_ParamEntityParsing m_paramEntityParsing; | |
#endif | |
}; | |
#define MALLOC(s) (parser->m_mem.malloc_fcn((s))) | |
#define REALLOC(p,s) (parser->m_mem.realloc_fcn((p),(s))) | |
#define FREE(p) (parser->m_mem.free_fcn((p))) | |
#define userData (parser->m_userData) | |
#define handlerArg (parser->m_handlerArg) | |
#define startElementHandler (parser->m_startElementHandler) | |
#define endElementHandler (parser->m_endElementHandler) | |
#define characterDataHandler (parser->m_characterDataHandler) | |
#define processingInstructionHandler \ | |
(parser->m_processingInstructionHandler) | |
#define commentHandler (parser->m_commentHandler) | |
#define startCdataSectionHandler \ | |
(parser->m_startCdataSectionHandler) | |
#define endCdataSectionHandler (parser->m_endCdataSectionHandler) | |
#define defaultHandler (parser->m_defaultHandler) | |
#define startDoctypeDeclHandler (parser->m_startDoctypeDeclHandler) | |
#define endDoctypeDeclHandler (parser->m_endDoctypeDeclHandler) | |
#define unparsedEntityDeclHandler \ | |
(parser->m_unparsedEntityDeclHandler) | |
#define notationDeclHandler (parser->m_notationDeclHandler) | |
#define startNamespaceDeclHandler \ | |
(parser->m_startNamespaceDeclHandler) | |
#define endNamespaceDeclHandler (parser->m_endNamespaceDeclHandler) | |
#define notStandaloneHandler (parser->m_notStandaloneHandler) | |
#define externalEntityRefHandler \ | |
(parser->m_externalEntityRefHandler) | |
#define externalEntityRefHandlerArg \ | |
(parser->m_externalEntityRefHandlerArg) | |
#define internalEntityRefHandler \ | |
(parser->m_internalEntityRefHandler) | |
#define skippedEntityHandler (parser->m_skippedEntityHandler) | |
#define unknownEncodingHandler (parser->m_unknownEncodingHandler) | |
#define elementDeclHandler (parser->m_elementDeclHandler) | |
#define attlistDeclHandler (parser->m_attlistDeclHandler) | |
#define entityDeclHandler (parser->m_entityDeclHandler) | |
#define xmlDeclHandler (parser->m_xmlDeclHandler) | |
#define encoding (parser->m_encoding) | |
#define initEncoding (parser->m_initEncoding) | |
#define internalEncoding (parser->m_internalEncoding) | |
#define unknownEncodingMem (parser->m_unknownEncodingMem) | |
#define unknownEncodingData (parser->m_unknownEncodingData) | |
#define unknownEncodingHandlerData \ | |
(parser->m_unknownEncodingHandlerData) | |
#define unknownEncodingRelease (parser->m_unknownEncodingRelease) | |
#define protocolEncodingName (parser->m_protocolEncodingName) | |
#define ns (parser->m_ns) | |
#define ns_triplets (parser->m_ns_triplets) | |
#define prologState (parser->m_prologState) | |
#define processor (parser->m_processor) | |
#define errorCode (parser->m_errorCode) | |
#define eventPtr (parser->m_eventPtr) | |
#define eventEndPtr (parser->m_eventEndPtr) | |
#define positionPtr (parser->m_positionPtr) | |
#define position (parser->m_position) | |
#define openInternalEntities (parser->m_openInternalEntities) | |
#define freeInternalEntities (parser->m_freeInternalEntities) | |
#define defaultExpandInternalEntities \ | |
(parser->m_defaultExpandInternalEntities) | |
#define tagLevel (parser->m_tagLevel) | |
#define buffer (parser->m_buffer) | |
#define bufferPtr (parser->m_bufferPtr) | |
#define bufferEnd (parser->m_bufferEnd) | |
#define parseEndByteIndex (parser->m_parseEndByteIndex) | |
#define parseEndPtr (parser->m_parseEndPtr) | |
#define bufferLim (parser->m_bufferLim) | |
#define dataBuf (parser->m_dataBuf) | |
#define dataBufEnd (parser->m_dataBufEnd) | |
#define _dtd (parser->m_dtd) | |
#define curBase (parser->m_curBase) | |
#define declEntity (parser->m_declEntity) | |
#define doctypeName (parser->m_doctypeName) | |
#define doctypeSysid (parser->m_doctypeSysid) | |
#define doctypePubid (parser->m_doctypePubid) | |
#define declAttributeType (parser->m_declAttributeType) | |
#define declNotationName (parser->m_declNotationName) | |
#define declNotationPublicId (parser->m_declNotationPublicId) | |
#define declElementType (parser->m_declElementType) | |
#define declAttributeId (parser->m_declAttributeId) | |
#define declAttributeIsCdata (parser->m_declAttributeIsCdata) | |
#define declAttributeIsId (parser->m_declAttributeIsId) | |
#define freeTagList (parser->m_freeTagList) | |
#define freeBindingList (parser->m_freeBindingList) | |
#define inheritedBindings (parser->m_inheritedBindings) | |
#define tagStack (parser->m_tagStack) | |
#define atts (parser->m_atts) | |
#define attsSize (parser->m_attsSize) | |
#define nSpecifiedAtts (parser->m_nSpecifiedAtts) | |
#define idAttIndex (parser->m_idAttIndex) | |
#define nsAtts (parser->m_nsAtts) | |
#define nsAttsVersion (parser->m_nsAttsVersion) | |
#define nsAttsPower (parser->m_nsAttsPower) | |
#define tempPool (parser->m_tempPool) | |
#define temp2Pool (parser->m_temp2Pool) | |
#define groupConnector (parser->m_groupConnector) | |
#define groupSize (parser->m_groupSize) | |
#define namespaceSeparator (parser->m_namespaceSeparator) | |
#define parentParser (parser->m_parentParser) | |
#define ps_parsing (parser->m_parsingStatus.parsing) | |
#define ps_finalBuffer (parser->m_parsingStatus.finalBuffer) | |
#ifdef XML_DTD | |
#define isParamEntity (parser->m_isParamEntity) | |
#define useForeignDTD (parser->m_useForeignDTD) | |
#define paramEntityParsing (parser->m_paramEntityParsing) | |
#endif /* XML_DTD */ | |
XML_Parser XMLCALL | |
XML_ParserCreate(const XML_Char *encodingName) | |
{ | |
return XML_ParserCreate_MM(encodingName, NULL, NULL); | |
} | |
XML_Parser XMLCALL | |
XML_ParserCreateNS(const XML_Char *encodingName, XML_Char nsSep) | |
{ | |
XML_Char tmp[2]; | |
*tmp = nsSep; | |
return XML_ParserCreate_MM(encodingName, NULL, tmp); | |
} | |
static const XML_Char implicitContext[] = { | |
'x', 'm', 'l', '=', 'h', 't', 't', 'p', ':', '/', '/', | |
'w', 'w', 'w', '.', 'w', '3', '.', 'o', 'r', 'g', '/', | |
'X', 'M', 'L', '/', '1', '9', '9', '8', '/', | |
'n', 'a', 'm', 'e', 's', 'p', 'a', 'c', 'e', '\0' | |
}; | |
XML_Parser XMLCALL | |
XML_ParserCreate_MM(const XML_Char *encodingName, | |
const XML_Memory_Handling_Suite *memsuite, | |
const XML_Char *nameSep) | |
{ | |
XML_Parser parser = parserCreate(encodingName, memsuite, nameSep, NULL); | |
if (parser != NULL && ns) { | |
/* implicit context only set for root parser, since child | |
parsers (i.e. external entity parsers) will inherit it | |
*/ | |
if (!setContext(parser, implicitContext)) { | |
XML_ParserFree(parser); | |
return NULL; | |
} | |
} | |
return parser; | |
} | |
static XML_Parser | |
parserCreate(const XML_Char *encodingName, | |
const XML_Memory_Handling_Suite *memsuite, | |
const XML_Char *nameSep, | |
DTD *dtd) | |
{ | |
XML_Parser parser; | |
if (memsuite) { | |
XML_Memory_Handling_Suite *mtemp; | |
parser = (XML_Parser) | |
memsuite->malloc_fcn(sizeof(struct XML_ParserStruct)); | |
if (parser != NULL) { | |
mtemp = (XML_Memory_Handling_Suite *)&(parser->m_mem); | |
mtemp->malloc_fcn = memsuite->malloc_fcn; | |
mtemp->realloc_fcn = memsuite->realloc_fcn; | |
mtemp->free_fcn = memsuite->free_fcn; | |
} | |
} | |
else { | |
XML_Memory_Handling_Suite *mtemp; | |
parser = (XML_Parser)malloc(sizeof(struct XML_ParserStruct)); | |
if (parser != NULL) { | |
mtemp = (XML_Memory_Handling_Suite *)&(parser->m_mem); | |
mtemp->malloc_fcn = malloc; | |
mtemp->realloc_fcn = realloc; | |
mtemp->free_fcn = free; | |
} | |
} | |
if (!parser) | |
return parser; | |
buffer = NULL; | |
bufferLim = NULL; | |
attsSize = INIT_ATTS_SIZE; | |
atts = (ATTRIBUTE *)MALLOC(attsSize * sizeof(ATTRIBUTE)); | |
if (atts == NULL) { | |
FREE(parser); | |
return NULL; | |
} | |
dataBuf = (XML_Char *)MALLOC(INIT_DATA_BUF_SIZE * sizeof(XML_Char)); | |
if (dataBuf == NULL) { | |
FREE(atts); | |
FREE(parser); | |
return NULL; | |
} | |
dataBufEnd = dataBuf + INIT_DATA_BUF_SIZE; | |
if (dtd) | |
_dtd = dtd; | |
else { | |
_dtd = dtdCreate(&parser->m_mem); | |
if (_dtd == NULL) { | |
FREE(dataBuf); | |
FREE(atts); | |
FREE(parser); | |
return NULL; | |
} | |
} | |
freeBindingList = NULL; | |
freeTagList = NULL; | |
freeInternalEntities = NULL; | |
groupSize = 0; | |
groupConnector = NULL; | |
unknownEncodingHandler = NULL; | |
unknownEncodingHandlerData = NULL; | |
namespaceSeparator = '!'; | |
ns = XML_FALSE; | |
ns_triplets = XML_FALSE; | |
nsAtts = NULL; | |
nsAttsVersion = 0; | |
nsAttsPower = 0; | |
poolInit(&tempPool, &(parser->m_mem)); | |
poolInit(&temp2Pool, &(parser->m_mem)); | |
parserInit(parser, encodingName); | |
if (encodingName && !protocolEncodingName) { | |
XML_ParserFree(parser); | |
return NULL; | |
} | |
if (nameSep) { | |
ns = XML_TRUE; | |
internalEncoding = XmlGetInternalEncodingNS(); | |
namespaceSeparator = *nameSep; | |
} | |
else { | |
internalEncoding = XmlGetInternalEncoding(); | |
} | |
return parser; | |
} | |
static void | |
parserInit(XML_Parser parser, const XML_Char *encodingName) | |
{ | |
processor = prologInitProcessor; | |
XmlPrologStateInit(&prologState); | |
protocolEncodingName = (encodingName != NULL | |
? poolCopyString(&tempPool, encodingName) | |
: NULL); | |
curBase = NULL; | |
XmlInitEncoding(&initEncoding, &encoding, 0); | |
userData = NULL; | |
handlerArg = NULL; | |
startElementHandler = NULL; | |
endElementHandler = NULL; | |
characterDataHandler = NULL; | |
processingInstructionHandler = NULL; | |
commentHandler = NULL; | |
startCdataSectionHandler = NULL; | |
endCdataSectionHandler = NULL; | |
defaultHandler = NULL; | |
startDoctypeDeclHandler = NULL; | |
endDoctypeDeclHandler = NULL; | |
unparsedEntityDeclHandler = NULL; | |
notationDeclHandler = NULL; | |
startNamespaceDeclHandler = NULL; | |
endNamespaceDeclHandler = NULL; | |
notStandaloneHandler = NULL; | |
externalEntityRefHandler = NULL; | |
externalEntityRefHandlerArg = parser; | |
skippedEntityHandler = NULL; | |
elementDeclHandler = NULL; | |
attlistDeclHandler = NULL; | |
entityDeclHandler = NULL; | |
xmlDeclHandler = NULL; | |
bufferPtr = buffer; | |
bufferEnd = buffer; | |
parseEndByteIndex = 0; | |
parseEndPtr = NULL; | |
declElementType = NULL; | |
declAttributeId = NULL; | |
declEntity = NULL; | |
doctypeName = NULL; | |
doctypeSysid = NULL; | |
doctypePubid = NULL; | |
declAttributeType = NULL; | |
declNotationName = NULL; | |
declNotationPublicId = NULL; | |
declAttributeIsCdata = XML_FALSE; | |
declAttributeIsId = XML_FALSE; | |
memset(&position, 0, sizeof(POSITION)); | |
errorCode = XML_ERROR_NONE; | |
eventPtr = NULL; | |
eventEndPtr = NULL; | |
positionPtr = NULL; | |
openInternalEntities = NULL; | |
defaultExpandInternalEntities = XML_TRUE; | |
tagLevel = 0; | |
tagStack = NULL; | |
inheritedBindings = NULL; | |
nSpecifiedAtts = 0; | |
unknownEncodingMem = NULL; | |
unknownEncodingRelease = NULL; | |
unknownEncodingData = NULL; | |
parentParser = NULL; | |
ps_parsing = XML_INITIALIZED; | |
#ifdef XML_DTD | |
isParamEntity = XML_FALSE; | |
useForeignDTD = XML_FALSE; | |
paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER; | |
#endif | |
} | |
/* moves list of bindings to freeBindingList */ | |
static void FASTCALL | |
moveToFreeBindingList(XML_Parser parser, BINDING *bindings) | |
{ | |
while (bindings) { | |
BINDING *b = bindings; | |
bindings = bindings->nextTagBinding; | |
b->nextTagBinding = freeBindingList; | |
freeBindingList = b; | |
} | |
} | |
XML_Bool XMLCALL | |
XML_ParserReset(XML_Parser parser, const XML_Char *encodingName) | |
{ | |
TAG *tStk; | |
OPEN_INTERNAL_ENTITY *openEntityList; | |
if (parentParser) | |
return XML_FALSE; | |
/* move tagStack to freeTagList */ | |
tStk = tagStack; | |
while (tStk) { | |
TAG *tag = tStk; | |
tStk = tStk->parent; | |
tag->parent = freeTagList; | |
moveToFreeBindingList(parser, tag->bindings); | |
tag->bindings = NULL; | |
freeTagList = tag; | |
} | |
/* move openInternalEntities to freeInternalEntities */ | |
openEntityList = openInternalEntities; | |
while (openEntityList) { | |
OPEN_INTERNAL_ENTITY *openEntity = openEntityList; | |
openEntityList = openEntity->next; | |
openEntity->next = freeInternalEntities; | |
freeInternalEntities = openEntity; | |
} | |
moveToFreeBindingList(parser, inheritedBindings); | |
FREE(unknownEncodingMem); | |
if (unknownEncodingRelease) | |
unknownEncodingRelease(unknownEncodingData); | |
poolClear(&tempPool); | |
poolClear(&temp2Pool); | |
parserInit(parser, encodingName); | |
dtdReset(_dtd, &parser->m_mem); | |
return setContext(parser, implicitContext); | |
} | |
enum XML_Status XMLCALL | |
XML_SetEncoding(XML_Parser parser, const XML_Char *encodingName) | |
{ | |
/* Block after XML_Parse()/XML_ParseBuffer() has been called. | |
XXX There's no way for the caller to determine which of the | |
XXX possible error cases caused the XML_STATUS_ERROR return. | |
*/ | |
if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED) | |
return XML_STATUS_ERROR; | |
if (encodingName == NULL) | |
protocolEncodingName = NULL; | |
else { | |
protocolEncodingName = poolCopyString(&tempPool, encodingName); | |
if (!protocolEncodingName) | |
return XML_STATUS_ERROR; | |
} | |
return XML_STATUS_OK; | |
} | |
XML_Parser XMLCALL | |
XML_ExternalEntityParserCreate(XML_Parser oldParser, | |
const XML_Char *context, | |
const XML_Char *encodingName) | |
{ | |
XML_Parser parser = oldParser; | |
DTD *newDtd = NULL; | |
DTD *oldDtd = _dtd; | |
XML_StartElementHandler oldStartElementHandler = startElementHandler; | |
XML_EndElementHandler oldEndElementHandler = endElementHandler; | |
XML_CharacterDataHandler oldCharacterDataHandler = characterDataHandler; | |
XML_ProcessingInstructionHandler oldProcessingInstructionHandler | |
= processingInstructionHandler; | |
XML_CommentHandler oldCommentHandler = commentHandler; | |
XML_StartCdataSectionHandler oldStartCdataSectionHandler | |
= startCdataSectionHandler; | |
XML_EndCdataSectionHandler oldEndCdataSectionHandler | |
= endCdataSectionHandler; | |
XML_DefaultHandler oldDefaultHandler = defaultHandler; | |
XML_UnparsedEntityDeclHandler oldUnparsedEntityDeclHandler | |
= unparsedEntityDeclHandler; | |
XML_NotationDeclHandler oldNotationDeclHandler = notationDeclHandler; | |
XML_StartNamespaceDeclHandler oldStartNamespaceDeclHandler | |
= startNamespaceDeclHandler; | |
XML_EndNamespaceDeclHandler oldEndNamespaceDeclHandler | |
= endNamespaceDeclHandler; | |
XML_NotStandaloneHandler oldNotStandaloneHandler = notStandaloneHandler; | |
XML_ExternalEntityRefHandler oldExternalEntityRefHandler | |
= externalEntityRefHandler; | |
XML_SkippedEntityHandler oldSkippedEntityHandler = skippedEntityHandler; | |
XML_UnknownEncodingHandler oldUnknownEncodingHandler | |
= unknownEncodingHandler; | |
XML_ElementDeclHandler oldElementDeclHandler = elementDeclHandler; | |
XML_AttlistDeclHandler oldAttlistDeclHandler = attlistDeclHandler; | |
XML_EntityDeclHandler oldEntityDeclHandler = entityDeclHandler; | |
XML_XmlDeclHandler oldXmlDeclHandler = xmlDeclHandler; | |
ELEMENT_TYPE * oldDeclElementType = declElementType; | |
void *oldUserData = userData; | |
void *oldHandlerArg = handlerArg; | |
XML_Bool oldDefaultExpandInternalEntities = defaultExpandInternalEntities; | |
XML_Parser oldExternalEntityRefHandlerArg = externalEntityRefHandlerArg; | |
#ifdef XML_DTD | |
enum XML_ParamEntityParsing oldParamEntityParsing = paramEntityParsing; | |
int oldInEntityValue = prologState.inEntityValue; | |
#endif | |
XML_Bool oldns_triplets = ns_triplets; | |
#ifdef XML_DTD | |
if (!context) | |
newDtd = oldDtd; | |
#endif /* XML_DTD */ | |
/* Note that the magical uses of the pre-processor to make field | |
access look more like C++ require that `parser' be overwritten | |
here. This makes this function more painful to follow than it | |
would be otherwise. | |
*/ | |
if (ns) { | |
XML_Char tmp[2]; | |
*tmp = namespaceSeparator; | |
parser = parserCreate(encodingName, &parser->m_mem, tmp, newDtd); | |
} | |
else { | |
parser = parserCreate(encodingName, &parser->m_mem, NULL, newDtd); | |
} | |
if (!parser) | |
return NULL; | |
startElementHandler = oldStartElementHandler; | |
endElementHandler = oldEndElementHandler; | |
characterDataHandler = oldCharacterDataHandler; | |
processingInstructionHandler = oldProcessingInstructionHandler; | |
commentHandler = oldCommentHandler; | |
startCdataSectionHandler = oldStartCdataSectionHandler; | |
endCdataSectionHandler = oldEndCdataSectionHandler; | |
defaultHandler = oldDefaultHandler; | |
unparsedEntityDeclHandler = oldUnparsedEntityDeclHandler; | |
notationDeclHandler = oldNotationDeclHandler; | |
startNamespaceDeclHandler = oldStartNamespaceDeclHandler; | |
endNamespaceDeclHandler = oldEndNamespaceDeclHandler; | |
notStandaloneHandler = oldNotStandaloneHandler; | |
externalEntityRefHandler = oldExternalEntityRefHandler; | |
skippedEntityHandler = oldSkippedEntityHandler; | |
unknownEncodingHandler = oldUnknownEncodingHandler; | |
elementDeclHandler = oldElementDeclHandler; | |
attlistDeclHandler = oldAttlistDeclHandler; | |
entityDeclHandler = oldEntityDeclHandler; | |
xmlDeclHandler = oldXmlDeclHandler; | |
declElementType = oldDeclElementType; | |
userData = oldUserData; | |
if (oldUserData == oldHandlerArg) | |
handlerArg = userData; | |
else | |
handlerArg = parser; | |
if (oldExternalEntityRefHandlerArg != oldParser) | |
externalEntityRefHandlerArg = oldExternalEntityRefHandlerArg; | |
defaultExpandInternalEntities = oldDefaultExpandInternalEntities; | |
ns_triplets = oldns_triplets; | |
parentParser = oldParser; | |
#ifdef XML_DTD | |
paramEntityParsing = oldParamEntityParsing; | |
prologState.inEntityValue = oldInEntityValue; | |
if (context) { | |
#endif /* XML_DTD */ | |
if (!dtdCopy(_dtd, oldDtd, &parser->m_mem) | |
|| !setContext(parser, context)) { | |
XML_ParserFree(parser); | |
return NULL; | |
} | |
processor = externalEntityInitProcessor; | |
#ifdef XML_DTD | |
} | |
else { | |
/* The DTD instance referenced by _dtd is shared between the document's | |
root parser and external PE parsers, therefore one does not need to | |
call setContext. In addition, one also *must* not call setContext, | |
because this would overwrite existing prefix->binding pointers in | |
_dtd with ones that get destroyed with the external PE parser. | |
This would leave those prefixes with dangling pointers. | |
*/ | |
isParamEntity = XML_TRUE; | |
XmlPrologStateInitExternalEntity(&prologState); | |
processor = externalParEntInitProcessor; | |
} | |
#endif /* XML_DTD */ | |
return parser; | |
} | |
static void FASTCALL | |
destroyBindings(BINDING *bindings, XML_Parser parser) | |
{ | |
for (;;) { | |
BINDING *b = bindings; | |
if (!b) | |
break; | |
bindings = b->nextTagBinding; | |
FREE(b->uri); | |
FREE(b); | |
} | |
} | |
void XMLCALL | |
XML_ParserFree(XML_Parser parser) | |
{ | |
TAG *tagList; | |
OPEN_INTERNAL_ENTITY *entityList; | |
if (parser == NULL) | |
return; | |
/* free tagStack and freeTagList */ | |
tagList = tagStack; | |
for (;;) { | |
TAG *p; | |
if (tagList == NULL) { | |
if (freeTagList == NULL) | |
break; | |
tagList = freeTagList; | |
freeTagList = NULL; | |
} | |
p = tagList; | |
tagList = tagList->parent; | |
FREE(p->buf); | |
destroyBindings(p->bindings, parser); | |
FREE(p); | |
} | |
/* free openInternalEntities and freeInternalEntities */ | |
entityList = openInternalEntities; | |
for (;;) { | |
OPEN_INTERNAL_ENTITY *openEntity; | |
if (entityList == NULL) { | |
if (freeInternalEntities == NULL) | |
break; | |
entityList = freeInternalEntities; | |
freeInternalEntities = NULL; | |
} | |
openEntity = entityList; | |
entityList = entityList->next; | |
FREE(openEntity); | |
} | |
destroyBindings(freeBindingList, parser); | |
destroyBindings(inheritedBindings, parser); | |
poolDestroy(&tempPool); | |
poolDestroy(&temp2Pool); | |
#ifdef XML_DTD | |
/* external parameter entity parsers share the DTD structure | |
parser->m_dtd with the root parser, so we must not destroy it | |
*/ | |
if (!isParamEntity && _dtd) | |
#else | |
if (_dtd) | |
#endif /* XML_DTD */ | |
dtdDestroy(_dtd, (XML_Bool)!parentParser, &parser->m_mem); | |
FREE((void *)atts); | |
FREE(groupConnector); | |
FREE(buffer); | |
FREE(dataBuf); | |
FREE(nsAtts); | |
FREE(unknownEncodingMem); | |
if (unknownEncodingRelease) | |
unknownEncodingRelease(unknownEncodingData); | |
FREE(parser); | |
} | |
void XMLCALL | |
XML_UseParserAsHandlerArg(XML_Parser parser) | |
{ | |
handlerArg = parser; | |
} | |
enum XML_Error XMLCALL | |
XML_UseForeignDTD(XML_Parser parser, XML_Bool useDTD) | |
{ | |
#ifdef XML_DTD | |
/* block after XML_Parse()/XML_ParseBuffer() has been called */ | |
if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED) | |
return XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING; | |
useForeignDTD = useDTD; | |
return XML_ERROR_NONE; | |
#else | |
return XML_ERROR_FEATURE_REQUIRES_XML_DTD; | |
#endif | |
} | |
void XMLCALL | |
XML_SetReturnNSTriplet(XML_Parser parser, int do_nst) | |
{ | |
/* block after XML_Parse()/XML_ParseBuffer() has been called */ | |
if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED) | |
return; | |
ns_triplets = do_nst ? XML_TRUE : XML_FALSE; | |
} | |
void XMLCALL | |
XML_SetUserData(XML_Parser parser, void *p) | |
{ | |
if (handlerArg == userData) | |
handlerArg = userData = p; | |
else | |
userData = p; | |
} | |
enum XML_Status XMLCALL | |
XML_SetBase(XML_Parser parser, const XML_Char *p) | |
{ | |
if (p) { | |
p = poolCopyString(&_dtd->pool, p); | |
if (!p) | |
return XML_STATUS_ERROR; | |
curBase = p; | |
} | |
else | |
curBase = NULL; | |
return XML_STATUS_OK; | |
} | |
const XML_Char * XMLCALL | |
XML_GetBase(XML_Parser parser) | |
{ | |
return curBase; | |
} | |
int XMLCALL | |
XML_GetSpecifiedAttributeCount(XML_Parser parser) | |
{ | |
return nSpecifiedAtts; | |
} | |
int XMLCALL | |
XML_GetIdAttributeIndex(XML_Parser parser) | |
{ | |
return idAttIndex; | |
} | |
void XMLCALL | |
XML_SetElementHandler(XML_Parser parser, | |
XML_StartElementHandler start, | |
XML_EndElementHandler end) | |
{ | |
startElementHandler = start; | |
endElementHandler = end; | |
} | |
void XMLCALL | |
XML_SetStartElementHandler(XML_Parser parser, | |
XML_StartElementHandler start) { | |
startElementHandler = start; | |
} | |
void XMLCALL | |
XML_SetEndElementHandler(XML_Parser parser, | |
XML_EndElementHandler end) { | |
endElementHandler = end; | |
} | |
void XMLCALL | |
XML_SetCharacterDataHandler(XML_Parser parser, | |
XML_CharacterDataHandler handler) | |
{ | |
characterDataHandler = handler; | |
} | |
void XMLCALL | |
XML_SetProcessingInstructionHandler(XML_Parser parser, | |
XML_ProcessingInstructionHandler handler) | |
{ | |
processingInstructionHandler = handler; | |
} | |
void XMLCALL | |
XML_SetCommentHandler(XML_Parser parser, | |
XML_CommentHandler handler) | |
{ | |
commentHandler = handler; | |
} | |
void XMLCALL | |
XML_SetCdataSectionHandler(XML_Parser parser, | |
XML_StartCdataSectionHandler start, | |
XML_EndCdataSectionHandler end) | |
{ | |
startCdataSectionHandler = start; | |
endCdataSectionHandler = end; | |
} | |
void XMLCALL | |
XML_SetStartCdataSectionHandler(XML_Parser parser, | |
XML_StartCdataSectionHandler start) { | |
startCdataSectionHandler = start; | |
} | |
void XMLCALL | |
XML_SetEndCdataSectionHandler(XML_Parser parser, | |
XML_EndCdataSectionHandler end) { | |
endCdataSectionHandler = end; | |
} | |
void XMLCALL | |
XML_SetDefaultHandler(XML_Parser parser, | |
XML_DefaultHandler handler) | |
{ | |
defaultHandler = handler; | |
defaultExpandInternalEntities = XML_FALSE; | |
} | |
void XMLCALL | |
XML_SetDefaultHandlerExpand(XML_Parser parser, | |
XML_DefaultHandler handler) | |
{ | |
defaultHandler = handler; | |
defaultExpandInternalEntities = XML_TRUE; | |
} | |
void XMLCALL | |
XML_SetDoctypeDeclHandler(XML_Parser parser, | |
XML_StartDoctypeDeclHandler start, | |
XML_EndDoctypeDeclHandler end) | |
{ | |
startDoctypeDeclHandler = start; | |
endDoctypeDeclHandler = end; | |
} | |
void XMLCALL | |
XML_SetStartDoctypeDeclHandler(XML_Parser parser, | |
XML_StartDoctypeDeclHandler start) { | |
startDoctypeDeclHandler = start; | |
} | |
void XMLCALL | |
XML_SetEndDoctypeDeclHandler(XML_Parser parser, | |
XML_EndDoctypeDeclHandler end) { | |
endDoctypeDeclHandler = end; | |
} | |
void XMLCALL | |
XML_SetUnparsedEntityDeclHandler(XML_Parser parser, | |
XML_UnparsedEntityDeclHandler handler) | |
{ | |
unparsedEntityDeclHandler = handler; | |
} | |
void XMLCALL | |
XML_SetNotationDeclHandler(XML_Parser parser, | |
XML_NotationDeclHandler handler) | |
{ | |
notationDeclHandler = handler; | |
} | |
void XMLCALL | |
XML_SetNamespaceDeclHandler(XML_Parser parser, | |
XML_StartNamespaceDeclHandler start, | |
XML_EndNamespaceDeclHandler end) | |
{ | |
startNamespaceDeclHandler = start; | |
endNamespaceDeclHandler = end; | |
} | |
void XMLCALL | |
XML_SetStartNamespaceDeclHandler(XML_Parser parser, | |
XML_StartNamespaceDeclHandler start) { | |
startNamespaceDeclHandler = start; | |
} | |
void XMLCALL | |
XML_SetEndNamespaceDeclHandler(XML_Parser parser, | |
XML_EndNamespaceDeclHandler end) { | |
endNamespaceDeclHandler = end; | |
} | |
void XMLCALL | |
XML_SetNotStandaloneHandler(XML_Parser parser, | |
XML_NotStandaloneHandler handler) | |
{ | |
notStandaloneHandler = handler; | |
} | |
void XMLCALL | |
XML_SetExternalEntityRefHandler(XML_Parser parser, | |
XML_ExternalEntityRefHandler handler) | |
{ | |
externalEntityRefHandler = handler; | |
} | |
void XMLCALL | |
XML_SetExternalEntityRefHandlerArg(XML_Parser parser, void *arg) | |
{ | |
if (arg) | |
externalEntityRefHandlerArg = (XML_Parser)arg; | |
else | |
externalEntityRefHandlerArg = parser; | |
} | |
void XMLCALL | |
XML_SetSkippedEntityHandler(XML_Parser parser, | |
XML_SkippedEntityHandler handler) | |
{ | |
skippedEntityHandler = handler; | |
} | |
void XMLCALL | |
XML_SetUnknownEncodingHandler(XML_Parser parser, | |
XML_UnknownEncodingHandler handler, | |
void *data) | |
{ | |
unknownEncodingHandler = handler; | |
unknownEncodingHandlerData = data; | |
} | |
void XMLCALL | |
XML_SetElementDeclHandler(XML_Parser parser, | |
XML_ElementDeclHandler eldecl) | |
{ | |
elementDeclHandler = eldecl; | |
} | |
void XMLCALL | |
XML_SetAttlistDeclHandler(XML_Parser parser, | |
XML_AttlistDeclHandler attdecl) | |
{ | |
attlistDeclHandler = attdecl; | |
} | |
void XMLCALL | |
XML_SetEntityDeclHandler(XML_Parser parser, | |
XML_EntityDeclHandler handler) | |
{ | |
entityDeclHandler = handler; | |
} | |
void XMLCALL | |
XML_SetXmlDeclHandler(XML_Parser parser, | |
XML_XmlDeclHandler handler) { | |
xmlDeclHandler = handler; | |
} | |
int XMLCALL | |
XML_SetParamEntityParsing(XML_Parser parser, | |
enum XML_ParamEntityParsing peParsing) | |
{ | |
/* block after XML_Parse()/XML_ParseBuffer() has been called */ | |
if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED) | |
return 0; | |
#ifdef XML_DTD | |
paramEntityParsing = peParsing; | |
return 1; | |
#else | |
return peParsing == XML_PARAM_ENTITY_PARSING_NEVER; | |
#endif | |
} | |
enum XML_Status XMLCALL | |
XML_Parse(XML_Parser parser, const char *s, int len, int isFinal) | |
{ | |
switch (ps_parsing) { | |
case XML_SUSPENDED: | |
errorCode = XML_ERROR_SUSPENDED; | |
return XML_STATUS_ERROR; | |
case XML_FINISHED: | |
errorCode = XML_ERROR_FINISHED; | |
return XML_STATUS_ERROR; | |
default: | |
ps_parsing = XML_PARSING; | |
} | |
if (len == 0) { | |
ps_finalBuffer = (XML_Bool)isFinal; | |
if (!isFinal) | |
return XML_STATUS_OK; | |
positionPtr = bufferPtr; | |
parseEndPtr = bufferEnd; | |
/* If data are left over from last buffer, and we now know that these | |
data are the final chunk of input, then we have to check them again | |
to detect errors based on that fact. | |
*/ | |
errorCode = processor(parser, bufferPtr, parseEndPtr, &bufferPtr); | |
if (errorCode == XML_ERROR_NONE) { | |
switch (ps_parsing) { | |
case XML_SUSPENDED: | |
XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position); | |
positionPtr = bufferPtr; | |
return XML_STATUS_SUSPENDED; | |
case XML_INITIALIZED: | |
case XML_PARSING: | |
ps_parsing = XML_FINISHED; | |
/* fall through */ | |
default: | |
return XML_STATUS_OK; | |
} | |
} | |
eventEndPtr = eventPtr; | |
processor = errorProcessor; | |
return XML_STATUS_ERROR; | |
} | |
#ifndef XML_CONTEXT_BYTES | |
else if (bufferPtr == bufferEnd) { | |
const char *end; | |
int nLeftOver; | |
enum XML_Error result; | |
parseEndByteIndex += len; | |
positionPtr = s; | |
ps_finalBuffer = (XML_Bool)isFinal; | |
errorCode = processor(parser, s, parseEndPtr = s + len, &end); | |
if (errorCode != XML_ERROR_NONE) { | |
eventEndPtr = eventPtr; | |
processor = errorProcessor; | |
return XML_STATUS_ERROR; | |
} | |
else { | |
switch (ps_parsing) { | |
case XML_SUSPENDED: | |
result = XML_STATUS_SUSPENDED; | |
break; | |
case XML_INITIALIZED: | |
case XML_PARSING: | |
result = XML_STATUS_OK; | |
if (isFinal) { | |
ps_parsing = XML_FINISHED; | |
return result; | |
} | |
break; | |
default: | |
/* XML_FINISHED case required by compiler - but not tested - djv */ | |
return XML_STATUS_OK; | |
} | |
} | |
XmlUpdatePosition(encoding, positionPtr, end, &position); | |
nLeftOver = s + len - end; | |
if (nLeftOver) { | |
if (buffer == NULL || nLeftOver > bufferLim - buffer) { | |
/* FIXME avoid integer overflow */ | |
char *temp; | |
temp = (buffer == NULL | |
? (char *)MALLOC(len * 2) | |
: (char *)REALLOC(buffer, len * 2)); | |
if (temp == NULL) { | |
errorCode = XML_ERROR_NO_MEMORY; | |
return XML_STATUS_ERROR; | |
} | |
buffer = temp; | |
if (!buffer) { | |
errorCode = XML_ERROR_NO_MEMORY; | |
eventPtr = eventEndPtr = NULL; | |
processor = errorProcessor; | |
return XML_STATUS_ERROR; | |
} | |
bufferLim = buffer + len * 2; | |
} | |
memcpy(buffer, end, nLeftOver); | |
} | |
bufferPtr = buffer; | |
bufferEnd = buffer + nLeftOver; | |
positionPtr = bufferPtr; | |
parseEndPtr = bufferEnd; | |
eventPtr = bufferPtr; | |
eventEndPtr = bufferPtr; | |
return result; | |
} | |
#endif /* not defined XML_CONTEXT_BYTES */ | |
else { | |
void *buff = XML_GetBuffer(parser, len); | |
if (buff == NULL) | |
return XML_STATUS_ERROR; | |
else { | |
memcpy(buff, s, len); | |
return XML_ParseBuffer(parser, len, isFinal); | |
} | |
} | |
} | |
enum XML_Status XMLCALL | |
XML_ParseBuffer(XML_Parser parser, int len, int isFinal) | |
{ | |
const char *start; | |
enum XML_Status result = XML_STATUS_OK; | |
switch (ps_parsing) { | |
case XML_SUSPENDED: | |
errorCode = XML_ERROR_SUSPENDED; | |
return XML_STATUS_ERROR; | |
case XML_FINISHED: | |
errorCode = XML_ERROR_FINISHED; | |
return XML_STATUS_ERROR; | |
default: | |
ps_parsing = XML_PARSING; | |
} | |
start = bufferPtr; | |
positionPtr = start; | |
bufferEnd += len; | |
parseEndPtr = bufferEnd; | |
parseEndByteIndex += len; | |
ps_finalBuffer = (XML_Bool)isFinal; | |
errorCode = processor(parser, start, parseEndPtr, &bufferPtr); | |
if (errorCode != XML_ERROR_NONE) { | |
eventEndPtr = eventPtr; | |
processor = errorProcessor; | |
return XML_STATUS_ERROR; | |
} | |
else { | |
switch (ps_parsing) { | |
case XML_SUSPENDED: | |
result = XML_STATUS_SUSPENDED; | |
break; | |
case XML_INITIALIZED: | |
case XML_PARSING: | |
if (isFinal) { | |
ps_parsing = XML_FINISHED; | |
return result; | |
} | |
default: ; /* should not happen */ | |
} | |
} | |
XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position); | |
positionPtr = bufferPtr; | |
return result; | |
} | |
void * XMLCALL | |
XML_GetBuffer(XML_Parser parser, int len) | |
{ | |
switch (ps_parsing) { | |
case XML_SUSPENDED: | |
errorCode = XML_ERROR_SUSPENDED; | |
return NULL; | |
case XML_FINISHED: | |
errorCode = XML_ERROR_FINISHED; | |
return NULL; | |
default: ; | |
} | |
if (len > bufferLim - bufferEnd) { | |
/* FIXME avoid integer overflow */ | |
int neededSize = len + (int)(bufferEnd - bufferPtr); | |
#ifdef XML_CONTEXT_BYTES | |
int keep = (int)(bufferPtr - buffer); | |
if (keep > XML_CONTEXT_BYTES) | |
keep = XML_CONTEXT_BYTES; | |
neededSize += keep; | |
#endif /* defined XML_CONTEXT_BYTES */ | |
if (neededSize <= bufferLim - buffer) { | |
#ifdef XML_CONTEXT_BYTES | |
if (keep < bufferPtr - buffer) { | |
int offset = (int)(bufferPtr - buffer) - keep; | |
memmove(buffer, &buffer[offset], bufferEnd - bufferPtr + keep); | |
bufferEnd -= offset; | |
bufferPtr -= offset; | |
} | |
#else | |
memmove(buffer, bufferPtr, bufferEnd - bufferPtr); | |
bufferEnd = buffer + (bufferEnd - bufferPtr); | |
bufferPtr = buffer; | |
#endif /* not defined XML_CONTEXT_BYTES */ | |
} | |
else { | |
char *newBuf; | |
int bufferSize = (int)(bufferLim - bufferPtr); | |
if (bufferSize == 0) | |
bufferSize = INIT_BUFFER_SIZE; | |
do { | |
bufferSize *= 2; | |
} while (bufferSize < neededSize); | |
newBuf = (char *)MALLOC(bufferSize); | |
if (newBuf == 0) { | |
errorCode = XML_ERROR_NO_MEMORY; | |
return NULL; | |
} | |
bufferLim = newBuf + bufferSize; | |
#ifdef XML_CONTEXT_BYTES | |
if (bufferPtr) { | |
int keep = (int)(bufferPtr - buffer); | |
if (keep > XML_CONTEXT_BYTES) | |
keep = XML_CONTEXT_BYTES; | |
memcpy(newBuf, &bufferPtr[-keep], bufferEnd - bufferPtr + keep); | |
FREE(buffer); | |
buffer = newBuf; | |
bufferEnd = buffer + (bufferEnd - bufferPtr) + keep; | |
bufferPtr = buffer + keep; | |
} | |
else { | |
bufferEnd = newBuf + (bufferEnd - bufferPtr); | |
bufferPtr = buffer = newBuf; | |
} | |
#else | |
if (bufferPtr) { | |
memcpy(newBuf, bufferPtr, bufferEnd - bufferPtr); | |
FREE(buffer); | |
} | |
bufferEnd = newBuf + (bufferEnd - bufferPtr); | |
bufferPtr = buffer = newBuf; | |
#endif /* not defined XML_CONTEXT_BYTES */ | |
} | |
} | |
return bufferEnd; | |
} | |
enum XML_Status XMLCALL | |
XML_StopParser(XML_Parser parser, XML_Bool resumable) | |
{ | |
switch (ps_parsing) { | |
case XML_SUSPENDED: | |
if (resumable) { | |
errorCode = XML_ERROR_SUSPENDED; | |
return XML_STATUS_ERROR; | |
} | |
ps_parsing = XML_FINISHED; | |
break; | |
case XML_FINISHED: | |
errorCode = XML_ERROR_FINISHED; | |
return XML_STATUS_ERROR; | |
default: | |
if (resumable) { | |
#ifdef XML_DTD | |
if (isParamEntity) { | |
errorCode = XML_ERROR_SUSPEND_PE; | |
return XML_STATUS_ERROR; | |
} | |
#endif | |
ps_parsing = XML_SUSPENDED; | |
} | |
else | |
ps_parsing = XML_FINISHED; | |
} | |
return XML_STATUS_OK; | |
} | |
enum XML_Status XMLCALL | |
XML_ResumeParser(XML_Parser parser) | |
{ | |
enum XML_Status result = XML_STATUS_OK; | |
if (ps_parsing != XML_SUSPENDED) { | |
errorCode = XML_ERROR_NOT_SUSPENDED; | |
return XML_STATUS_ERROR; | |
} | |
ps_parsing = XML_PARSING; | |
errorCode = processor(parser, bufferPtr, parseEndPtr, &bufferPtr); | |
if (errorCode != XML_ERROR_NONE) { | |
eventEndPtr = eventPtr; | |
processor = errorProcessor; | |
return XML_STATUS_ERROR; | |
} | |
else { | |
switch (ps_parsing) { | |
case XML_SUSPENDED: | |
result = XML_STATUS_SUSPENDED; | |
break; | |
case XML_INITIALIZED: | |
case XML_PARSING: | |
if (ps_finalBuffer) { | |
ps_parsing = XML_FINISHED; | |
return result; | |
} | |
default: ; | |
} | |
} | |
XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position); | |
positionPtr = bufferPtr; | |
return result; | |
} | |
void XMLCALL | |
XML_GetParsingStatus(XML_Parser parser, XML_ParsingStatus *status) | |
{ | |
assert(status != NULL); | |
*status = parser->m_parsingStatus; | |
} | |
enum XML_Error XMLCALL | |
XML_GetErrorCode(XML_Parser parser) | |
{ | |
return errorCode; | |
} | |
XML_Index XMLCALL | |
XML_GetCurrentByteIndex(XML_Parser parser) | |
{ | |
if (eventPtr) | |
return parseEndByteIndex - (parseEndPtr - eventPtr); | |
return -1; | |
} | |
int XMLCALL | |
XML_GetCurrentByteCount(XML_Parser parser) | |
{ | |
if (eventEndPtr && eventPtr) | |
return (int)(eventEndPtr - eventPtr); | |
return 0; | |
} | |
const char * XMLCALL | |
XML_GetInputContext(XML_Parser parser, int *offset, int *size) | |
{ | |
#ifdef XML_CONTEXT_BYTES | |
if (eventPtr && buffer) { | |
*offset = (int)(eventPtr - buffer); | |
*size = (int)(bufferEnd - buffer); | |
return buffer; | |
} | |
#endif /* defined XML_CONTEXT_BYTES */ | |
return (char *) 0; | |
} | |
XML_Size XMLCALL | |
XML_GetCurrentLineNumber(XML_Parser parser) | |
{ | |
if (eventPtr && eventPtr >= positionPtr) { | |
XmlUpdatePosition(encoding, positionPtr, eventPtr, &position); | |
positionPtr = eventPtr; | |
} | |
return position.lineNumber + 1; | |
} | |
XML_Size XMLCALL | |
XML_GetCurrentColumnNumber(XML_Parser parser) | |
{ | |
if (eventPtr && eventPtr >= positionPtr) { | |
XmlUpdatePosition(encoding, positionPtr, eventPtr, &position); | |
positionPtr = eventPtr; | |
} | |
return position.columnNumber; | |
} | |
void XMLCALL | |
XML_FreeContentModel(XML_Parser parser, XML_Content *model) | |
{ | |
FREE(model); | |
} | |
void * XMLCALL | |
XML_MemMalloc(XML_Parser parser, size_t size) | |
{ | |
return MALLOC(size); | |
} | |
void * XMLCALL | |
XML_MemRealloc(XML_Parser parser, void *ptr, size_t size) | |
{ | |
return REALLOC(ptr, size); | |
} | |
void XMLCALL | |
XML_MemFree(XML_Parser parser, void *ptr) | |
{ | |
FREE(ptr); | |
} | |
void XMLCALL | |
XML_DefaultCurrent(XML_Parser parser) | |
{ | |
if (defaultHandler) { | |
if (openInternalEntities) | |
reportDefault(parser, | |
internalEncoding, | |
openInternalEntities->internalEventPtr, | |
openInternalEntities->internalEventEndPtr); | |
else | |
reportDefault(parser, encoding, eventPtr, eventEndPtr); | |
} | |
} | |
const XML_LChar * XMLCALL | |
XML_ErrorString(enum XML_Error code) | |
{ | |
static const XML_LChar* const message[] = { | |
0, | |
XML_L("out of memory"), | |
XML_L("syntax error"), | |
XML_L("no element found"), | |
XML_L("not well-formed (invalid token)"), | |
XML_L("unclosed token"), | |
XML_L("partial character"), | |
XML_L("mismatched tag"), | |
XML_L("duplicate attribute"), | |
XML_L("junk after document element"), | |
XML_L("illegal parameter entity reference"), | |
XML_L("undefined entity"), | |
XML_L("recursive entity reference"), | |
XML_L("asynchronous entity"), | |
XML_L("reference to invalid character number"), | |
XML_L("reference to binary entity"), | |
XML_L("reference to external entity in attribute"), | |
XML_L("XML or text declaration not at start of entity"), | |
XML_L("unknown encoding"), | |
XML_L("encoding specified in XML declaration is incorrect"), | |
XML_L("unclosed CDATA section"), | |
XML_L("error in processing external entity reference"), | |
XML_L("document is not standalone"), | |
XML_L("unexpected parser state - please send a bug report"), | |
XML_L("entity declared in parameter entity"), | |
XML_L("requested feature requires XML_DTD support in Expat"), | |
XML_L("cannot change setting once parsing has begun"), | |
XML_L("unbound prefix"), | |
XML_L("must not undeclare prefix"), | |
XML_L("incomplete markup in parameter entity"), | |
XML_L("XML declaration not well-formed"), | |
XML_L("text declaration not well-formed"), | |
XML_L("illegal character(s) in public id"), | |
XML_L("parser suspended"), | |
XML_L("parser not suspended"), | |
XML_L("parsing aborted"), | |
XML_L("parsing finished"), | |
XML_L("cannot suspend in external parameter entity"), | |
XML_L("reserved prefix (xml) must not be undeclared or bound to another namespace name"), | |
XML_L("reserved prefix (xmlns) must not be declared or undeclared"), | |
XML_L("prefix must not be bound to one of the reserved namespace names") | |
}; | |
if (code > 0 && code < sizeof(message)/sizeof(message[0])) | |
return message[code]; | |
return NULL; | |
} | |
const XML_LChar * XMLCALL | |
XML_ExpatVersion(void) { | |
/* V1 is used to string-ize the version number. However, it would | |
string-ize the actual version macro *names* unless we get them | |
substituted before being passed to V1. CPP is defined to expand | |
a macro, then rescan for more expansions. Thus, we use V2 to expand | |
the version macros, then CPP will expand the resulting V1() macro | |
with the correct numerals. */ | |
/* ### I'm assuming cpp is portable in this respect... */ | |
#define V1(a,b,c) XML_L(#a)XML_L(".")XML_L(#b)XML_L(".")XML_L(#c) | |
#define V2(a,b,c) XML_L("expat_")V1(a,b,c) | |
return V2(XML_MAJOR_VERSION, XML_MINOR_VERSION, XML_MICRO_VERSION); | |
#undef V1 | |
#undef V2 | |
} | |
XML_Expat_Version XMLCALL | |
XML_ExpatVersionInfo(void) | |
{ | |
XML_Expat_Version version; | |
version.major = XML_MAJOR_VERSION; | |
version.minor = XML_MINOR_VERSION; | |
version.micro = XML_MICRO_VERSION; | |
return version; | |
} | |
const XML_Feature * XMLCALL | |
XML_GetFeatureList(void) | |
{ | |
static const XML_Feature features[] = { | |
{XML_FEATURE_SIZEOF_XML_CHAR, XML_L("sizeof(XML_Char)"), | |
sizeof(XML_Char)}, | |
{XML_FEATURE_SIZEOF_XML_LCHAR, XML_L("sizeof(XML_LChar)"), | |
sizeof(XML_LChar)}, | |
#ifdef XML_UNICODE | |
{XML_FEATURE_UNICODE, XML_L("XML_UNICODE"), 0}, | |
#endif | |
#ifdef XML_UNICODE_WCHAR_T | |
{XML_FEATURE_UNICODE_WCHAR_T, XML_L("XML_UNICODE_WCHAR_T"), 0}, | |
#endif | |
#ifdef XML_DTD | |
{XML_FEATURE_DTD, XML_L("XML_DTD"), 0}, | |
#endif | |
#ifdef XML_CONTEXT_BYTES | |
{XML_FEATURE_CONTEXT_BYTES, XML_L("XML_CONTEXT_BYTES"), | |
XML_CONTEXT_BYTES}, | |
#endif | |
#ifdef XML_MIN_SIZE | |
{XML_FEATURE_MIN_SIZE, XML_L("XML_MIN_SIZE"), 0}, | |
#endif | |
#ifdef XML_NS | |
{XML_FEATURE_NS, XML_L("XML_NS"), 0}, | |
#endif | |
{XML_FEATURE_END, NULL, 0} | |
}; | |
return features; | |
} | |
/* Initially tag->rawName always points into the parse buffer; | |
for those TAG instances opened while the current parse buffer was | |
processed, and not yet closed, we need to store tag->rawName in a more | |
permanent location, since the parse buffer is about to be discarded. | |
*/ | |
static XML_Bool | |
storeRawNames(XML_Parser parser) | |
{ | |
TAG *tag = tagStack; | |
while (tag) { | |
int bufSize; | |
int nameLen = sizeof(XML_Char) * (tag->name.strLen + 1); | |
char *rawNameBuf = tag->buf + nameLen; | |
/* Stop if already stored. Since tagStack is a stack, we can stop | |
at the first entry that has already been copied; everything | |
below it in the stack is already been accounted for in a | |
previous call to this function. | |
*/ | |
if (tag->rawName == rawNameBuf) | |
break; | |
/* For re-use purposes we need to ensure that the | |
size of tag->buf is a multiple of sizeof(XML_Char). | |
*/ | |
bufSize = nameLen + ROUND_UP(tag->rawNameLength, sizeof(XML_Char)); | |
if (bufSize > tag->bufEnd - tag->buf) { | |
char *temp = (char *)REALLOC(tag->buf, bufSize); | |
if (temp == NULL) | |
return XML_FALSE; | |
/* if tag->name.str points to tag->buf (only when namespace | |
processing is off) then we have to update it | |
*/ | |
if (tag->name.str == (XML_Char *)tag->buf) | |
tag->name.str = (XML_Char *)temp; | |
/* if tag->name.localPart is set (when namespace processing is on) | |
then update it as well, since it will always point into tag->buf | |
*/ | |
if (tag->name.localPart) | |
tag->name.localPart = (XML_Char *)temp + (tag->name.localPart - | |
(XML_Char *)tag->buf); | |
tag->buf = temp; | |
tag->bufEnd = temp + bufSize; | |
rawNameBuf = temp + nameLen; | |
} | |
memcpy(rawNameBuf, tag->rawName, tag->rawNameLength); | |
tag->rawName = rawNameBuf; | |
tag = tag->parent; | |
} | |
return XML_TRUE; | |
} | |
static enum XML_Error PTRCALL | |
contentProcessor(XML_Parser parser, | |
const char *start, | |
const char *end, | |
const char **endPtr) | |
{ | |
enum XML_Error result = doContent(parser, 0, encoding, start, end, | |
endPtr, (XML_Bool)!ps_finalBuffer); | |
if (result == XML_ERROR_NONE) { | |
if (!storeRawNames(parser)) | |
return XML_ERROR_NO_MEMORY; | |
} | |
return result; | |
} | |
static enum XML_Error PTRCALL | |
externalEntityInitProcessor(XML_Parser parser, | |
const char *start, | |
const char *end, | |
const char **endPtr) | |
{ | |
enum XML_Error result = initializeEncoding(parser); | |
if (result != XML_ERROR_NONE) | |
return result; | |
processor = externalEntityInitProcessor2; | |
return externalEntityInitProcessor2(parser, start, end, endPtr); | |
} | |
static enum XML_Error PTRCALL | |
externalEntityInitProcessor2(XML_Parser parser, | |
const char *start, | |
const char *end, | |
const char **endPtr) | |
{ | |
const char *next = start; /* XmlContentTok doesn't always set the last arg */ | |
int tok = XmlContentTok(encoding, start, end, &next); | |
switch (tok) { | |
case XML_TOK_BOM: | |
/* If we are at the end of the buffer, this would cause the next stage, | |
i.e. externalEntityInitProcessor3, to pass control directly to | |
doContent (by detecting XML_TOK_NONE) without processing any xml text | |
declaration - causing the error XML_ERROR_MISPLACED_XML_PI in doContent. | |
*/ | |
if (next == end && !ps_finalBuffer) { | |
*endPtr = next; | |
return XML_ERROR_NONE; | |
} | |
start = next; | |
break; | |
case XML_TOK_PARTIAL: | |
if (!ps_finalBuffer) { | |
*endPtr = start; | |
return XML_ERROR_NONE; | |
} | |
eventPtr = start; | |
return XML_ERROR_UNCLOSED_TOKEN; | |
case XML_TOK_PARTIAL_CHAR: | |
if (!ps_finalBuffer) { | |
*endPtr = start; | |
return XML_ERROR_NONE; | |
} | |
eventPtr = start; | |
return XML_ERROR_PARTIAL_CHAR; | |
} | |
processor = externalEntityInitProcessor3; | |
return externalEntityInitProcessor3(parser, start, end, endPtr); | |
} | |
static enum XML_Error PTRCALL | |
externalEntityInitProcessor3(XML_Parser parser, | |
const char *start, | |
const char *end, | |
const char **endPtr) | |
{ | |
int tok; | |
const char *next = start; /* XmlContentTok doesn't always set the last arg */ | |
eventPtr = start; | |
tok = XmlContentTok(encoding, start, end, &next); | |
eventEndPtr = next; | |
switch (tok) { | |
case XML_TOK_XML_DECL: | |
{ | |
enum XML_Error result; | |
result = processXmlDecl(parser, 1, start, next); | |
if (result != XML_ERROR_NONE) | |
return result; | |
switch (ps_parsing) { | |
case XML_SUSPENDED: | |
*endPtr = next; | |
return XML_ERROR_NONE; | |
case XML_FINISHED: | |
return XML_ERROR_ABORTED; | |
default: | |
start = next; | |
} | |
} | |
break; | |
case XML_TOK_PARTIAL: | |
if (!ps_finalBuffer) { | |
*endPtr = start; | |
return XML_ERROR_NONE; | |
} | |
return XML_ERROR_UNCLOSED_TOKEN; | |
case XML_TOK_PARTIAL_CHAR: | |
if (!ps_finalBuffer) { | |
*endPtr = start; | |
return XML_ERROR_NONE; | |
} | |
return XML_ERROR_PARTIAL_CHAR; | |
} | |
processor = externalEntityContentProcessor; | |
tagLevel = 1; | |
return externalEntityContentProcessor(parser, start, end, endPtr); | |
} | |
static enum XML_Error PTRCALL | |
externalEntityContentProcessor(XML_Parser parser, | |
const char *start, | |
const char *end, | |
const char **endPtr) | |
{ | |
enum XML_Error result = doContent(parser, 1, encoding, start, end, | |
endPtr, (XML_Bool)!ps_finalBuffer); | |
if (result == XML_ERROR_NONE) { | |
if (!storeRawNames(parser)) | |
return XML_ERROR_NO_MEMORY; | |
} | |
return result; | |
} | |
static enum XML_Error | |
doContent(XML_Parser parser, | |
int startTagLevel, | |
const ENCODING *enc, | |
const char *s, | |
const char *end, | |
const char **nextPtr, | |
XML_Bool haveMore) | |
{ | |
/* save one level of indirection */ | |
DTD * const dtd = _dtd; | |
const char **eventPP; | |
const char **eventEndPP; | |
if (enc == encoding) { | |
eventPP = &eventPtr; | |
eventEndPP = &eventEndPtr; | |
} | |
else { | |
eventPP = &(openInternalEntities->internalEventPtr); | |
eventEndPP = &(openInternalEntities->internalEventEndPtr); | |
} | |
*eventPP = s; | |
for (;;) { | |
const char *next = s; /* XmlContentTok doesn't always set the last arg */ | |
int tok = XmlContentTok(enc, s, end, &next); | |
*eventEndPP = next; | |
switch (tok) { | |
case XML_TOK_TRAILING_CR: | |
if (haveMore) { | |
*nextPtr = s; | |
return XML_ERROR_NONE; | |
} | |
*eventEndPP = end; | |
if (characterDataHandler) { | |
XML_Char c = 0xA; | |
characterDataHandler(handlerArg, &c, 1); | |
} | |
else if (defaultHandler) | |
reportDefault(parser, enc, s, end); | |
/* We are at the end of the final buffer, should we check for | |
XML_SUSPENDED, XML_FINISHED? | |
*/ | |
if (startTagLevel == 0) | |
return XML_ERROR_NO_ELEMENTS; | |
if (tagLevel != startTagLevel) | |
return XML_ERROR_ASYNC_ENTITY; | |
*nextPtr = end; | |
return XML_ERROR_NONE; | |
case XML_TOK_NONE: | |
if (haveMore) { | |
*nextPtr = s; | |
return XML_ERROR_NONE; | |
} | |
if (startTagLevel > 0) { | |
if (tagLevel != startTagLevel) | |
return XML_ERROR_ASYNC_ENTITY; | |
*nextPtr = s; | |
return XML_ERROR_NONE; | |
} | |
return XML_ERROR_NO_ELEMENTS; | |
case XML_TOK_INVALID: | |
*eventPP = next; | |
return XML_ERROR_INVALID_TOKEN; | |
case XML_TOK_PARTIAL: | |
if (haveMore) { | |
*nextPtr = s; | |
return XML_ERROR_NONE; | |
} | |
return XML_ERROR_UNCLOSED_TOKEN; | |
case XML_TOK_PARTIAL_CHAR: | |
if (haveMore) { | |
*nextPtr = s; | |
return XML_ERROR_NONE; | |
} | |
return XML_ERROR_PARTIAL_CHAR; | |
case XML_TOK_ENTITY_REF: | |
{ | |
const XML_Char *name; | |
ENTITY *entity; | |
XML_Char ch = (XML_Char) XmlPredefinedEntityName(enc, | |
s + enc->minBytesPerChar, | |
next - enc->minBytesPerChar); | |
if (ch) { | |
if (characterDataHandler) | |
characterDataHandler(handlerArg, &ch, 1); | |
else if (defaultHandler) | |
reportDefault(parser, enc, s, next); | |
break; | |
} | |
name = poolStoreString(&dtd->pool, enc, | |
s + enc->minBytesPerChar, | |
next - enc->minBytesPerChar); | |
if (!name) | |
return XML_ERROR_NO_MEMORY; | |
entity = (ENTITY *)lookup(&dtd->generalEntities, name, 0); | |
poolDiscard(&dtd->pool); | |
/* First, determine if a check for an existing declaration is needed; | |
if yes, check that the entity exists, and that it is internal, | |
otherwise call the skipped entity or default handler. | |
*/ | |
if (!dtd->hasParamEntityRefs || dtd->standalone) { | |
if (!entity) | |
return XML_ERROR_UNDEFINED_ENTITY; | |
else if (!entity->is_internal) | |
return XML_ERROR_ENTITY_DECLARED_IN_PE; | |
} | |
else if (!entity) { | |
if (skippedEntityHandler) | |
skippedEntityHandler(handlerArg, name, 0); | |
else if (defaultHandler) | |
reportDefault(parser, enc, s, next); | |
break; | |
} | |
if (entity->open) | |
return XML_ERROR_RECURSIVE_ENTITY_REF; | |
if (entity->notation) | |
return XML_ERROR_BINARY_ENTITY_REF; | |
if (entity->textPtr) { | |
enum XML_Error result; | |
if (!defaultExpandInternalEntities) { | |
if (skippedEntityHandler) | |
skippedEntityHandler(handlerArg, entity->name, 0); | |
else if (defaultHandler) | |
reportDefault(parser, enc, s, next); | |
break; | |
} | |
result = processInternalEntity(parser, entity, XML_FALSE); | |
if (result != XML_ERROR_NONE) | |
return result; | |
} | |
else if (externalEntityRefHandler) { | |
const XML_Char *context; | |
entity->open = XML_TRUE; | |
context = getContext(parser); | |
entity->open = XML_FALSE; | |
if (!context) | |
return XML_ERROR_NO_MEMORY; | |
if (!externalEntityRefHandler(externalEntityRefHandlerArg, | |
context, | |
entity->base, | |
entity->systemId, | |
entity->publicId)) | |
return XML_ERROR_EXTERNAL_ENTITY_HANDLING; | |
poolDiscard(&tempPool); | |
} | |
else if (defaultHandler) | |
reportDefault(parser, enc, s, next); | |
break; | |
} | |
case XML_TOK_START_TAG_NO_ATTS: | |
/* fall through */ | |
case XML_TOK_START_TAG_WITH_ATTS: | |
{ | |
TAG *tag; | |
enum XML_Error result; | |
XML_Char *toPtr; | |
if (freeTagList) { | |
tag = freeTagList; | |
freeTagList = freeTagList->parent; | |
} | |
else { | |
tag = (TAG *)MALLOC(sizeof(TAG)); | |
if (!tag) | |
return XML_ERROR_NO_MEMORY; | |
tag->buf = (char *)MALLOC(INIT_TAG_BUF_SIZE); | |
if (!tag->buf) { | |
FREE(tag); | |
return XML_ERROR_NO_MEMORY; | |
} | |
tag->bufEnd = tag->buf + INIT_TAG_BUF_SIZE; | |
} | |
tag->bindings = NULL; | |
tag->parent = tagStack; | |
tagStack = tag; | |
tag->name.localPart = NULL; | |
tag->name.prefix = NULL; | |
tag->rawName = s + enc->minBytesPerChar; | |
tag->rawNameLength = XmlNameLength(enc, tag->rawName); | |
++tagLevel; | |
{ | |
const char *rawNameEnd = tag->rawName + tag->rawNameLength; | |
const char *fromPtr = tag->rawName; | |
toPtr = (XML_Char *)tag->buf; | |
for (;;) { | |
int bufSize; | |
int convLen; | |
XmlConvert(enc, | |
&fromPtr, rawNameEnd, | |
(ICHAR **)&toPtr, (ICHAR *)tag->bufEnd - 1); | |
convLen = (int)(toPtr - (XML_Char *)tag->buf); | |
if (fromPtr == rawNameEnd) { | |
tag->name.strLen = convLen; | |
break; | |
} | |
bufSize = (int)(tag->bufEnd - tag->buf) << 1; | |
{ | |
char *temp = (char *)REALLOC(tag->buf, bufSize); | |
if (temp == NULL) | |
return XML_ERROR_NO_MEMORY; | |
tag->buf = temp; | |
tag->bufEnd = temp + bufSize; | |
toPtr = (XML_Char *)temp + convLen; | |
} | |
} | |
} | |
tag->name.str = (XML_Char *)tag->buf; | |
*toPtr = XML_T('\0'); | |
result = storeAtts(parser, enc, s, &(tag->name), &(tag->bindings)); | |
if (result) | |
return result; | |
if (startElementHandler) | |
startElementHandler(handlerArg, tag->name.str, | |
(const XML_Char **)atts); | |
else if (defaultHandler) | |
reportDefault(parser, enc, s, next); | |
poolClear(&tempPool); | |
break; | |
} | |
case XML_TOK_EMPTY_ELEMENT_NO_ATTS: | |
/* fall through */ | |
case XML_TOK_EMPTY_ELEMENT_WITH_ATTS: | |
{ | |
const char *rawName = s + enc->minBytesPerChar; | |
enum XML_Error result; | |
BINDING *bindings = NULL; | |
XML_Bool noElmHandlers = XML_TRUE; | |
TAG_NAME name; | |
name.str = poolStoreString(&tempPool, enc, rawName, | |
rawName + XmlNameLength(enc, rawName)); | |
if (!name.str) | |
return XML_ERROR_NO_MEMORY; | |
poolFinish(&tempPool); | |
result = storeAtts(parser, enc, s, &name, &bindings); | |
if (result) | |
return result; | |
poolFinish(&tempPool); | |
if (startElementHandler) { | |
startElementHandler(handlerArg, name.str, (const XML_Char **)atts); | |
noElmHandlers = XML_FALSE; | |
} | |
if (endElementHandler) { | |
if (startElementHandler) | |
*eventPP = *eventEndPP; | |
endElementHandler(handlerArg, name.str); | |
noElmHandlers = XML_FALSE; | |
} | |
if (noElmHandlers && defaultHandler) | |
reportDefault(parser, enc, s, next); | |
poolClear(&tempPool); | |
while (bindings) { | |
BINDING *b = bindings; | |
if (endNamespaceDeclHandler) | |
endNamespaceDeclHandler(handlerArg, b->prefix->name); | |
bindings = bindings->nextTagBinding; | |
b->nextTagBinding = freeBindingList; | |
freeBindingList = b; | |
b->prefix->binding = b->prevPrefixBinding; | |
} | |
} | |
if (tagLevel == 0) | |
return epilogProcessor(parser, next, end, nextPtr); | |
break; | |
case XML_TOK_END_TAG: | |
if (tagLevel == startTagLevel) | |
return XML_ERROR_ASYNC_ENTITY; | |
else { | |
int len; | |
const char *rawName; | |
TAG *tag = tagStack; | |
tagStack = tag->parent; | |
tag->parent = freeTagList; | |
freeTagList = tag; | |
rawName = s + enc->minBytesPerChar*2; | |
len = XmlNameLength(enc, rawName); | |
if (len != tag->rawNameLength | |
|| memcmp(tag->rawName, rawName, len) != 0) { | |
*eventPP = rawName; | |
return XML_ERROR_TAG_MISMATCH; | |
} | |
--tagLevel; | |
if (endElementHandler) { | |
const XML_Char *localPart; | |
const XML_Char *prefix; | |
XML_Char *uri; | |
localPart = tag->name.localPart; | |
if (ns && localPart) { | |
/* localPart and prefix may have been overwritten in | |
tag->name.str, since this points to the binding->uri | |
buffer which gets re-used; so we have to add them again | |
*/ | |
uri = (XML_Char *)tag->name.str + tag->name.uriLen; | |
/* don't need to check for space - already done in storeAtts() */ | |
while (*localPart) *uri++ = *localPart++; | |
prefix = (XML_Char *)tag->name.prefix; | |
if (ns_triplets && prefix) { | |
*uri++ = namespaceSeparator; | |
while (*prefix) *uri++ = *prefix++; | |
} | |
*uri = XML_T('\0'); | |
} | |
endElementHandler(handlerArg, tag->name.str); | |
} | |
else if (defaultHandler) | |
reportDefault(parser, enc, s, next); | |
while (tag->bindings) { | |
BINDING *b = tag->bindings; | |
if (endNamespaceDeclHandler) | |
endNamespaceDeclHandler(handlerArg, b->prefix->name); | |
tag->bindings = tag->bindings->nextTagBinding; | |
b->nextTagBinding = freeBindingList; | |
freeBindingList = b; | |
b->prefix->binding = b->prevPrefixBinding; | |
} | |
if (tagLevel == 0) | |
return epilogProcessor(parser, next, end, nextPtr); | |
} | |
break; | |
case XML_TOK_CHAR_REF: | |
{ | |
int n = XmlCharRefNumber(enc, s); | |
if (n < 0) | |
return XML_ERROR_BAD_CHAR_REF; | |
if (characterDataHandler) { | |
XML_Char buf[XML_ENCODE_MAX]; | |
characterDataHandler(handlerArg, buf, XmlEncode(n, (ICHAR *)buf)); | |
} | |
else if (defaultHandler) | |
reportDefault(parser, enc, s, next); | |
} | |
break; | |
case XML_TOK_XML_DECL: | |
return XML_ERROR_MISPLACED_XML_PI; | |
case XML_TOK_DATA_NEWLINE: | |
if (characterDataHandler) { | |
XML_Char c = 0xA; | |
characterDataHandler(handlerArg, &c, 1); | |
} | |
else if (defaultHandler) | |
reportDefault(parser, enc, s, next); | |
break; | |
case XML_TOK_CDATA_SECT_OPEN: | |
{ | |
enum XML_Error result; | |
if (startCdataSectionHandler) | |
startCdataSectionHandler(handlerArg); | |
#if 0 | |
/* Suppose you doing a transformation on a document that involves | |
changing only the character data. You set up a defaultHandler | |
and a characterDataHandler. The defaultHandler simply copies | |
characters through. The characterDataHandler does the | |
transformation and writes the characters out escaping them as | |
necessary. This case will fail to work if we leave out the | |
following two lines (because & and < inside CDATA sections will | |
be incorrectly escaped). | |
However, now we have a start/endCdataSectionHandler, so it seems | |
easier to let the user deal with this. | |
*/ | |
else if (characterDataHandler) | |
characterDataHandler(handlerArg, dataBuf, 0); | |
#endif | |
else if (defaultHandler) | |
reportDefault(parser, enc, s, next); | |
result = doCdataSection(parser, enc, &next, end, nextPtr, haveMore); | |
if (result != XML_ERROR_NONE) | |
return result; | |
else if (!next) { | |
processor = cdataSectionProcessor; | |
return result; | |
} | |
} | |
break; | |
case XML_TOK_TRAILING_RSQB: | |
if (haveMore) { | |
*nextPtr = s; | |
return XML_ERROR_NONE; | |
} | |
if (characterDataHandler) { | |
if (MUST_CONVERT(enc, s)) { | |
ICHAR *dataPtr = (ICHAR *)dataBuf; | |
XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)dataBufEnd); | |
characterDataHandler(handlerArg, dataBuf, | |
(int)(dataPtr - (ICHAR *)dataBuf)); | |
} | |
else | |
characterDataHandler(handlerArg, | |
(XML_Char *)s, | |
(int)((XML_Char *)end - (XML_Char *)s)); | |
} | |
else if (defaultHandler) | |
reportDefault(parser, enc, s, end); | |
/* We are at the end of the final buffer, should we check for | |
XML_SUSPENDED, XML_FINISHED? | |
*/ | |
if (startTagLevel == 0) { | |
*eventPP = end; | |
return XML_ERROR_NO_ELEMENTS; | |
} | |
if (tagLevel != startTagLevel) { | |
*eventPP = end; | |
return XML_ERROR_ASYNC_ENTITY; | |
} | |
*nextPtr = end; | |
return XML_ERROR_NONE; | |
case XML_TOK_DATA_CHARS: | |
if (characterDataHandler) { | |
if (MUST_CONVERT(enc, s)) { | |
for (;;) { | |
ICHAR *dataPtr = (ICHAR *)dataBuf; | |
XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd); | |
*eventEndPP = s; | |
characterDataHandler(handlerArg, dataBuf, | |
(int)(dataPtr - (ICHAR *)dataBuf)); | |
if (s == next) | |
break; | |
*eventPP = s; | |
} | |
} | |
else | |
characterDataHandler(handlerArg, | |
(XML_Char *)s, | |
(int)((XML_Char *)next - (XML_Char *)s)); | |
} | |
else if (defaultHandler) | |
reportDefault(parser, enc, s, next); | |
break; | |
case XML_TOK_PI: | |
if (!reportProcessingInstruction(parser, enc, s, next)) | |
return XML_ERROR_NO_MEMORY; | |
break; | |
case XML_TOK_COMMENT: | |
if (!reportComment(parser, enc, s, next)) | |
return XML_ERROR_NO_MEMORY; | |
break; | |
default: | |
if (defaultHandler) | |
reportDefault(parser, enc, s, next); | |
break; | |
} | |
*eventPP = s = next; | |
switch (ps_parsing) { | |
case XML_SUSPENDED: | |
*nextPtr = next; | |
return XML_ERROR_NONE; | |
case XML_FINISHED: | |
return XML_ERROR_ABORTED; | |
default: ; | |
} | |
} | |
/* not reached */ | |
} | |
/* Precondition: all arguments must be non-NULL; | |
Purpose: | |
- normalize attributes | |
- check attributes for well-formedness | |
- generate namespace aware attribute names (URI, prefix) | |
- build list of attributes for startElementHandler | |
- default attributes | |
- process namespace declarations (check and report them) | |
- generate namespace aware element name (URI, prefix) | |
*/ | |
static enum XML_Error | |
storeAtts(XML_Parser parser, const ENCODING *enc, | |
const char *attStr, TAG_NAME *tagNamePtr, | |
BINDING **bindingsPtr) | |
{ | |
DTD * const dtd = _dtd; /* save one level of indirection */ | |
ELEMENT_TYPE *elementType; | |
int nDefaultAtts; | |
const XML_Char **appAtts; /* the attribute list for the application */ | |
int attIndex = 0; | |
int prefixLen; | |
int i; | |
int n; | |
XML_Char *uri; | |
int nPrefixes = 0; | |
BINDING *binding; | |
const XML_Char *localPart; | |
/* lookup the element type name */ | |
elementType = (ELEMENT_TYPE *)lookup(&dtd->elementTypes, tagNamePtr->str,0); | |
if (!elementType) { | |
const XML_Char *name = poolCopyString(&dtd->pool, tagNamePtr->str); | |
if (!name) | |
return XML_ERROR_NO_MEMORY; | |
elementType = (ELEMENT_TYPE *)lookup(&dtd->elementTypes, name, | |
sizeof(ELEMENT_TYPE)); | |
if (!elementType) | |
return XML_ERROR_NO_MEMORY; | |
if (ns && !setElementTypePrefix(parser, elementType)) | |
return XML_ERROR_NO_MEMORY; | |
} | |
nDefaultAtts = elementType->nDefaultAtts; | |
/* get the attributes from the tokenizer */ | |
n = XmlGetAttributes(enc, attStr, attsSize, atts); | |
if (n + nDefaultAtts > attsSize) { | |
int oldAttsSize = attsSize; | |
ATTRIBUTE *temp; | |
attsSize = n + nDefaultAtts + INIT_ATTS_SIZE; | |
temp = (ATTRIBUTE *)REALLOC((void *)atts, attsSize * sizeof(ATTRIBUTE)); | |
if (temp == NULL) | |
return XML_ERROR_NO_MEMORY; | |
atts = temp; | |
if (n > oldAttsSize) | |
XmlGetAttributes(enc, attStr, n, atts); | |
} | |
appAtts = (const XML_Char **)atts; | |
for (i = 0; i < n; i++) { | |
/* add the name and value to the attribute list */ | |
ATTRIBUTE_ID *attId = getAttributeId(parser, enc, atts[i].name, | |
atts[i].name | |
+ XmlNameLength(enc, atts[i].name)); | |
if (!attId) | |
return XML_ERROR_NO_MEMORY; | |
/* Detect duplicate attributes by their QNames. This does not work when | |
namespace processing is turned on and different prefixes for the same | |
namespace are used. For this case we have a check further down. | |
*/ | |
if ((attId->name)[-1]) { | |
if (enc == encoding) | |
eventPtr = atts[i].name; | |
return XML_ERROR_DUPLICATE_ATTRIBUTE; | |
} | |
(attId->name)[-1] = 1; | |
appAtts[attIndex++] = attId->name; | |
if (!atts[i].normalized) { | |
enum XML_Error result; | |
XML_Bool isCdata = XML_TRUE; | |
/* figure out whether declared as other than CDATA */ | |
if (attId->maybeTokenized) { | |
int j; | |
for (j = 0; j < nDefaultAtts; j++) { | |
if (attId == elementType->defaultAtts[j].id) { | |
isCdata = elementType->defaultAtts[j].isCdata; | |
break; | |
} | |
} | |
} | |
/* normalize the attribute value */ | |
result = storeAttributeValue(parser, enc, isCdata, | |
atts[i].valuePtr, atts[i].valueEnd, | |
&tempPool); | |
if (result) | |
return result; | |
appAtts[attIndex] = poolStart(&tempPool); | |
poolFinish(&tempPool); | |
} | |
else { | |
/* the value did not need normalizing */ | |
appAtts[attIndex] = poolStoreString(&tempPool, enc, atts[i].valuePtr, | |
atts[i].valueEnd); | |
if (appAtts[attIndex] == 0) | |
return XML_ERROR_NO_MEMORY; | |
poolFinish(&tempPool); | |
} | |
/* handle prefixed attribute names */ | |
if (attId->prefix) { | |
if (attId->xmlns) { | |
/* deal with namespace declarations here */ | |
enum XML_Error result = addBinding(parser, attId->prefix, attId, | |
appAtts[attIndex], bindingsPtr); | |
if (result) | |
return result; | |
--attIndex; | |
} | |
else { | |
/* deal with other prefixed names later */ | |
attIndex++; | |
nPrefixes++; | |
(attId->name)[-1] = 2; | |
} | |
} | |
else | |
attIndex++; | |
} | |
/* set-up for XML_GetSpecifiedAttributeCount and XML_GetIdAttributeIndex */ | |
nSpecifiedAtts = attIndex; | |
if (elementType->idAtt && (elementType->idAtt->name)[-1]) { | |
for (i = 0; i < attIndex; i += 2) | |
if (appAtts[i] == elementType->idAtt->name) { | |
idAttIndex = i; | |
break; | |
} | |
} | |
else | |
idAttIndex = -1; | |
/* do attribute defaulting */ | |
for (i = 0; i < nDefaultAtts; i++) { | |
const DEFAULT_ATTRIBUTE *da = elementType->defaultAtts + i; | |
if (!(da->id->name)[-1] && da->value) { | |
if (da->id->prefix) { | |
if (da->id->xmlns) { | |
enum XML_Error result = addBinding(parser, da->id->prefix, da->id, | |
da->value, bindingsPtr); | |
if (result) | |
return result; | |
} | |
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[attIndex] = 0; | |
/* expand prefixed attribute names, check for duplicates, | |
and clear flags that say whether attributes were specified */ | |
i = 0; | |
if (nPrefixes) { | |
int j; /* hash table index */ | |
unsigned long version = nsAttsVersion; | |
int nsAttsSize = (int)1 << nsAttsPower; | |
/* size of hash table must be at least 2 * (# of prefixed attributes) */ | |
if ((nPrefixes << 1) >> nsAttsPower) { /* true for nsAttsPower = 0 */ | |
NS_ATT *temp; | |
/* hash table size must also be a power of 2 and >= 8 */ | |
while (nPrefixes >> nsAttsPower++); | |
if (nsAttsPower < 3) | |
nsAttsPower = 3; | |
nsAttsSize = (int)1 << nsAttsPower; | |
temp = (NS_ATT *)REALLOC(nsAtts, nsAttsSize * sizeof(NS_ATT)); | |
if (!temp) | |
return XML_ERROR_NO_MEMORY; | |
nsAtts = temp; | |
version = 0; /* force re-initialization of nsAtts hash table */ | |
} | |
/* using a version flag saves us from initializing nsAtts every time */ | |
if (!version) { /* initialize version flags when version wraps around */ | |
version = INIT_ATTS_VERSION; | |
for (j = nsAttsSize; j != 0; ) | |
nsAtts[--j].version = version; | |
} | |
nsAttsVersion = --version; | |
/* expand prefixed names and check for duplicates */ | |
for (; i < attIndex; i += 2) { | |
const XML_Char *s = appAtts[i]; | |
if (s[-1] == 2) { /* prefixed */ | |
ATTRIBUTE_ID *id; | |
const BINDING *b; | |
unsigned long uriHash = 0; | |
((XML_Char *)s)[-1] = 0; /* clear flag */ | |
id = (ATTRIBUTE_ID *)lookup(&dtd->attributeIds, s, 0); | |
if (!id) | |
return XML_ERROR_NO_MEMORY; | |
b = id->prefix->binding; | |
if (!b) | |
return XML_ERROR_UNBOUND_PREFIX; | |
/* as we expand the name we also calculate its hash value */ | |
for (j = 0; j < b->uriLen; j++) { | |
const XML_Char c = b->uri[j]; | |
if (!poolAppendChar(&tempPool, c)) | |
return XML_ERROR_NO_MEMORY; | |
uriHash = CHAR_HASH(uriHash, c); | |
} | |
while (*s++ != XML_T(':')) | |
; | |
do { /* copies null terminator */ | |
const XML_Char c = *s; | |
if (!poolAppendChar(&tempPool, *s)) | |
return XML_ERROR_NO_MEMORY; | |
uriHash = CHAR_HASH(uriHash, c); | |
} while (*s++); | |
{ /* Check hash table for duplicate of expanded name (uriName). | |
Derived from code in lookup(HASH_TABLE *table, ...). | |
*/ | |
unsigned char step = 0; | |
unsigned long mask = nsAttsSize - 1; | |
j = uriHash & mask; /* index into hash table */ | |
while (nsAtts[j].version == version) { | |
/* for speed we compare stored hash values first */ | |
if (uriHash == nsAtts[j].hash) { | |
const XML_Char *s1 = poolStart(&tempPool); | |
const XML_Char *s2 = nsAtts[j].uriName; | |
/* s1 is null terminated, but not s2 */ | |
for (; *s1 == *s2 && *s1 != 0; s1++, s2++); | |
if (*s1 == 0) | |
return XML_ERROR_DUPLICATE_ATTRIBUTE; | |
} | |
if (!step) | |
step = PROBE_STEP(uriHash, mask, nsAttsPower); | |
j < step ? (j += nsAttsSize - step) : (j -= step); | |
} | |
} | |
if (ns_triplets) { /* append namespace separator and prefix */ | |
tempPool.ptr[-1] = namespaceSeparator; | |
s = b->prefix->name; | |
do { | |
if (!poolAppendChar(&tempPool, *s)) | |
return XML_ERROR_NO_MEMORY; | |
} while (*s++); | |
} | |
/* store expanded name in attribute list */ | |
s = poolStart(&tempPool); | |
poolFinish(&tempPool); | |
appAtts[i] = s; | |
/* fill empty slot with new version, uriName and hash value */ | |
nsAtts[j].version = version; | |
nsAtts[j].hash = uriHash; | |
nsAtts[j].uriName = s; | |
if (!--nPrefixes) { | |
i += 2; | |
break; | |
} | |
} | |
else /* not prefixed */ | |
((XML_Char *)s)[-1] = 0; /* clear flag */ | |
} | |
} | |
/* clear flags for the remaining attributes */ | |
for (; i < attIndex; i += 2) | |
((XML_Char *)(appAtts[i]))[-1] = 0; | |
for (binding = *bindingsPtr; binding; binding = binding->nextTagBinding) | |
binding->attId->name[-1] = 0; | |
if (!ns) | |
return XML_ERROR_NONE; | |
/* expand the element type name */ | |
if (elementType->prefix) { | |
binding = elementType->prefix->binding; | |
if (!binding) | |
return XML_ERROR_UNBOUND_PREFIX; | |
localPart = tagNamePtr->str; | |
while (*localPart++ != XML_T(':')) | |
; | |
} | |
else if (dtd->defaultPrefix.binding) { | |
binding = dtd->defaultPrefix.binding; | |
localPart = tagNamePtr->str; | |
} | |
else | |
return XML_ERROR_NONE; | |
prefixLen = 0; | |
if (ns_triplets && binding->prefix->name) { | |
for (; binding->prefix->name[prefixLen++];) | |
; /* prefixLen includes null terminator */ | |
} | |
tagNamePtr->localPart = localPart; | |
tagNamePtr->uriLen = binding->uriLen; | |
tagNamePtr->prefix = binding->prefix->name; | |
tagNamePtr->prefixLen = prefixLen; | |
for (i = 0; localPart[i++];) | |
; /* i includes null terminator */ | |
n = i + binding->uriLen + prefixLen; | |
if (n > binding->uriAlloc) { | |
TAG *p; | |
uri = (XML_Char *)MALLOC((n + EXPAND_SPARE) * sizeof(XML_Char)); | |
if (!uri) | |
return XML_ERROR_NO_MEMORY; | |
binding->uriAlloc = n + EXPAND_SPARE; | |
memcpy(uri, binding->uri, binding->uriLen * sizeof(XML_Char)); | |
for (p = tagStack; p; p = p->parent) | |
if (p->name.str == binding->uri) | |
p->name.str = uri; | |
FREE(binding->uri); | |
binding->uri = uri; | |
} | |
/* if namespaceSeparator != '\0' then uri includes it already */ | |
uri = binding->uri + binding->uriLen; | |
memcpy(uri, localPart, i * sizeof(XML_Char)); | |
/* we always have a namespace separator between localPart and prefix */ | |
if (prefixLen) { | |
uri += i - 1; | |
*uri = namespaceSeparator; /* replace null terminator */ | |
memcpy(uri + 1, binding->prefix->name, prefixLen * sizeof(XML_Char)); | |
} | |
tagNamePtr->str = binding->uri; | |
return XML_ERROR_NONE; | |
} | |
/* addBinding() overwrites the value of prefix->binding without checking. | |
Therefore one must keep track of the old value outside of addBinding(). | |
*/ | |
static enum XML_Error | |
addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId, | |
const XML_Char *uri, BINDING **bindingsPtr) | |
{ | |
static const XML_Char xmlNamespace[] = { | |
'h', 't', 't', 'p', ':', '/', '/', | |
'w', 'w', 'w', '.', 'w', '3', '.', 'o', 'r', 'g', '/', | |
'X', 'M', 'L', '/', '1', '9', '9', '8', '/', | |
'n', 'a', 'm', 'e', 's', 'p', 'a', 'c', 'e', '\0' | |
}; | |
static const int xmlLen = | |
(int)sizeof(xmlNamespace)/sizeof(XML_Char) - 1; | |
static const XML_Char xmlnsNamespace[] = { | |
'h', 't', 't', 'p', ':', '/', '/', | |
'w', 'w', 'w', '.', 'w', '3', '.', 'o', 'r', 'g', '/', | |
'2', '0', '0', '0', '/', 'x', 'm', 'l', 'n', 's', '/', '\0' | |
}; | |
static const int xmlnsLen = | |
(int)sizeof(xmlnsNamespace)/sizeof(XML_Char) - 1; | |
XML_Bool mustBeXML = XML_FALSE; | |
XML_Bool isXML = XML_TRUE; | |
XML_Bool isXMLNS = XML_TRUE; | |
BINDING *b; | |
int len; | |
/* empty URI is only valid for default namespace per XML NS 1.0 (not 1.1) */ | |
if (*uri == XML_T('\0') && prefix->name) | |
return XML_ERROR_UNDECLARING_PREFIX; | |
if (prefix->name | |
&& prefix->name[0] == XML_T('x') | |
&& prefix->name[1] == XML_T('m') | |
&& prefix->name[2] == XML_T('l')) { | |
/* Not allowed to bind xmlns */ | |
if (prefix->name[3] == XML_T('n') | |
&& prefix->name[4] == XML_T('s') | |
&& prefix->name[5] == XML_T('\0')) | |
return XML_ERROR_RESERVED_PREFIX_XMLNS; | |
if (prefix->name[3] == XML_T('\0')) | |
mustBeXML = XML_TRUE; | |
} | |
for (len = 0; uri[len]; len++) { | |
if (isXML && (len > xmlLen || uri[len] != xmlNamespace[len])) | |
isXML = XML_FALSE; | |
if (!mustBeXML && isXMLNS | |
&& (len > xmlnsLen || uri[len] != xmlnsNamespace[len])) | |
isXMLNS = XML_FALSE; | |
} | |
isXML = isXML && len == xmlLen; | |
isXMLNS = isXMLNS && len == xmlnsLen; | |
if (mustBeXML != isXML) | |
return mustBeXML ? XML_ERROR_RESERVED_PREFIX_XML | |
: XML_ERROR_RESERVED_NAMESPACE_URI; | |
if (isXMLNS) | |
return XML_ERROR_RESERVED_NAMESPACE_URI; | |
if (namespaceSeparator) | |
len++; | |
if (freeBindingList) { | |
b = freeBindingList; | |
if (len > b->uriAlloc) { | |
XML_Char *temp = (XML_Char *)REALLOC(b->uri, | |
sizeof(XML_Char) * (len + EXPAND_SPARE)); | |
if (temp == NULL) | |
return XML_ERROR_NO_MEMORY; | |
b->uri = temp; | |
b->uriAlloc = len + EXPAND_SPARE; | |
} | |
freeBindingList = b->nextTagBinding; | |
} | |
else { | |
b = (BINDING *)MALLOC(sizeof(BINDING)); | |
if (!b) | |
return XML_ERROR_NO_MEMORY; | |
b->uri = (XML_Char *)MALLOC(sizeof(XML_Char) * (len + EXPAND_SPARE)); | |
if (!b->uri) { | |
FREE(b); | |
return XML_ERROR_NO_MEMORY; | |
} | |
b->uriAlloc = len + EXPAND_SPARE; | |
} | |
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 = prefix->binding; | |
/* NULL binding when default namespace undeclared */ | |
if (*uri == XML_T('\0') && prefix == &_dtd->defaultPrefix) | |
prefix->binding = NULL; | |
else | |
prefix->binding = b; | |
b->nextTagBinding = *bindingsPtr; | |
*bindingsPtr = b; | |
/* if attId == NULL then we are not starting a namespace scope */ | |
if (attId && startNamespaceDeclHandler) | |
startNamespaceDeclHandler(handlerArg, prefix->name, | |
prefix->binding ? uri : 0); | |
return XML_ERROR_NONE; | |
} | |
/* The idea here is to avoid using stack for each CDATA section when | |
the whole file is parsed with one call. | |
*/ | |
static enum XML_Error PTRCALL | |
cdataSectionProcessor(XML_Parser parser, | |
const char *start, | |
const char *end, | |
const char **endPtr) | |
{ | |
enum XML_Error result = doCdataSection(parser, encoding, &start, end, | |
endPtr, (XML_Bool)!ps_finalBuffer); | |
if (result != XML_ERROR_NONE) | |
return result; | |
if (start) { | |
if (parentParser) { /* we are parsing an external entity */ | |
processor = externalEntityContentProcessor; | |
return externalEntityContentProcessor(parser, start, end, endPtr); | |
} | |
else { | |
processor = contentProcessor; | |
return contentProcessor(parser, start, end, endPtr); | |
} | |
} | |
return result; | |
} | |
/* startPtr gets set to non-null if the section is closed, and to null if | |
the section is not yet closed. | |
*/ | |
static enum XML_Error | |
doCdataSection(XML_Parser parser, | |
const ENCODING *enc, | |
const char **startPtr, | |
const char *end, | |
const char **nextPtr, | |
XML_Bool haveMore) | |
{ | |
const char *s = *startPtr; | |
const char **eventPP; | |
const char **eventEndPP; | |
if (enc == encoding) { | |
eventPP = &eventPtr; | |
*eventPP = s; | |
eventEndPP = &eventEndPtr; | |
} | |
else { | |
eventPP = &(openInternalEntities->internalEventPtr); | |
eventEndPP = &(openInternalEntities->internalEventEndPtr); | |
} | |
*eventPP = s; | |
*startPtr = NULL; | |
for (;;) { | |
const char *next; | |
int tok = XmlCdataSectionTok(enc, s, end, &next); | |
*eventEndPP = next; | |
switch (tok) { | |
case XML_TOK_CDATA_SECT_CLOSE: | |
if (endCdataSectionHandler) | |
endCdataSectionHandler(handlerArg); | |
#if 0 | |
/* see comment under XML_TOK_CDATA_SECT_OPEN */ | |
else if (characterDataHandler) | |
characterDataHandler(handlerArg, dataBuf, 0); | |
#endif | |
else if (defaultHandler) | |
reportDefault(parser, enc, s, next); | |
*startPtr = next; | |
*nextPtr = next; | |
if (ps_parsing == XML_FINISHED) | |
return XML_ERROR_ABORTED; | |
else | |
return XML_ERROR_NONE; | |
case XML_TOK_DATA_NEWLINE: | |
if (characterDataHandler) { | |
XML_Char c = 0xA; | |
characterDataHandler(handlerArg, &c, 1); | |
} | |
else if (defaultHandler) | |
reportDefault(parser, enc, s, next); | |
break; | |
case XML_TOK_DATA_CHARS: | |
if (characterDataHandler) { | |
if (MUST_CONVERT(enc, s)) { | |
for (;;) { | |
ICHAR *dataPtr = (ICHAR *)dataBuf; | |
XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd); | |
*eventEndPP = next; | |
characterDataHandler(handlerArg, dataBuf, | |
(int)(dataPtr - (ICHAR *)dataBuf)); | |
if (s == next) | |
break; | |
*eventPP = s; | |
} | |
} | |
else | |
characterDataHandler(handlerArg, | |
(XML_Char *)s, | |
(int)((XML_Char *)next - (XML_Char *)s)); | |
} | |
else if (defaultHandler) | |
reportDefault(parser, enc, s, next); | |
break; | |
case XML_TOK_INVALID: | |
*eventPP = next; | |
return XML_ERROR_INVALID_TOKEN; | |
case XML_TOK_PARTIAL_CHAR: | |
if (haveMore) { | |
*nextPtr = s; | |
return XML_ERROR_NONE; | |
} | |
return XML_ERROR_PARTIAL_CHAR; | |
case XML_TOK_PARTIAL: | |
case XML_TOK_NONE: | |
if (haveMore) { | |
*nextPtr = s; | |
return XML_ERROR_NONE; | |
} | |
return XML_ERROR_UNCLOSED_CDATA_SECTION; | |
default: | |
*eventPP = next; | |
return XML_ERROR_UNEXPECTED_STATE; | |
} | |
*eventPP = s = next; | |
switch (ps_parsing) { | |
case XML_SUSPENDED: | |
*nextPtr = next; | |
return XML_ERROR_NONE; | |
case XML_FINISHED: | |
return XML_ERROR_ABORTED; | |
default: ; | |
} | |
} | |
/* not reached */ | |
} | |
#ifdef XML_DTD | |
/* The idea here is to avoid using stack for each IGNORE section when | |
the whole file is parsed with one call. | |
*/ | |
static enum XML_Error PTRCALL | |
ignoreSectionProcessor(XML_Parser parser, | |
const char *start, | |
const char *end, | |
const char **endPtr) | |
{ | |
enum XML_Error result = doIgnoreSection(parser, encoding, &start, end, | |
endPtr, (XML_Bool)!ps_finalBuffer); | |
if (result != XML_ERROR_NONE) | |
return result; | |
if (start) { | |
processor = prologProcessor; | |
return prologProcessor(parser, start, end, endPtr); | |
} | |
return result; | |
} | |
/* startPtr gets set to non-null is the section is closed, and to null | |
if the section is not yet closed. | |
*/ | |
static enum XML_Error | |
doIgnoreSection(XML_Parser parser, | |
const ENCODING *enc, | |
const char **startPtr, | |
const char *end, | |
const char **nextPtr, | |
XML_Bool haveMore) | |
{ | |
const char *next; | |
int tok; | |
const char *s = *startPtr; | |
const char **eventPP; | |
const char **eventEndPP; | |
if (enc == encoding) { | |
eventPP = &eventPtr; | |
*eventPP = s; | |
eventEndPP = &eventEndPtr; | |
} | |
else { | |
eventPP = &(openInternalEntities->internalEventPtr); | |
eventEndPP = &(openInternalEntities->internalEventEndPtr); | |
} | |
*eventPP = s; | |
*startPtr = NULL; | |
tok = XmlIgnoreSectionTok(enc, s, end, &next); | |
*eventEndPP = next; | |
switch (tok) { | |
case XML_TOK_IGNORE_SECT: | |
if (defaultHandler) | |
reportDefault(parser, enc, s, next); | |
*startPtr = next; | |
*nextPtr = next; | |
if (ps_parsing == XML_FINISHED) | |
return XML_ERROR_ABORTED; | |
else | |
return XML_ERROR_NONE; | |
case XML_TOK_INVALID: | |
*eventPP = next; | |
return XML_ERROR_INVALID_TOKEN; | |
case XML_TOK_PARTIAL_CHAR: | |
if (haveMore) { | |
*nextPtr = s; | |
return XML_ERROR_NONE; | |
} | |
return XML_ERROR_PARTIAL_CHAR; | |
case XML_TOK_PARTIAL: | |
case XML_TOK_NONE: | |
if (haveMore) { | |
*nextPtr = s; | |
return XML_ERROR_NONE; | |
} | |
return XML_ERROR_SYNTAX; /* XML_ERROR_UNCLOSED_IGNORE_SECTION */ | |
default: | |
*eventPP = next; | |
return XML_ERROR_UNEXPECTED_STATE; | |
} | |
/* not reached */ | |
} | |
#endif /* XML_DTD */ | |
static enum XML_Error | |
initializeEncoding(XML_Parser parser) | |
{ | |
const char *s; | |
#ifdef XML_UNICODE | |
char encodingBuf[128]; | |
if (!protocolEncodingName) | |
s = NULL; | |
else { | |
int i; | |
for (i = 0; protocolEncodingName[i]; i++) { | |
if (i == sizeof(encodingBuf) - 1 | |
|| (protocolEncodingName[i] & ~0x7f) != 0) { | |
encodingBuf[0] = '\0'; | |
break; | |
} | |
encodingBuf[i] = (char)protocolEncodingName[i]; | |
} | |
encodingBuf[i] = '\0'; | |
s = encodingBuf; | |
} | |
#else | |
s = protocolEncodingName; | |
#endif | |
if ((ns ? XmlInitEncodingNS : XmlInitEncoding)(&initEncoding, &encoding, s)) | |
return XML_ERROR_NONE; | |
return handleUnknownEncoding(parser, protocolEncodingName); | |
} | |
static enum XML_Error | |
processXmlDecl(XML_Parser parser, int isGeneralTextEntity, | |
const char *s, const char *next) | |
{ | |
const char *encodingName = NULL; | |
const XML_Char *storedEncName = NULL; | |
const ENCODING *newEncoding = NULL; | |
const char *version = NULL; | |
const char *versionend; | |
const XML_Char *storedversion = NULL; | |
int standalone = -1; | |
if (!(ns | |
? XmlParseXmlDeclNS | |
: XmlParseXmlDecl)(isGeneralTextEntity, | |
encoding, | |
s, | |
next, | |
&eventPtr, | |
&version, | |
&versionend, | |
&encodingName, | |
&newEncoding, | |
&standalone)) { | |
if (isGeneralTextEntity) | |
return XML_ERROR_TEXT_DECL; | |
else | |
return XML_ERROR_XML_DECL; | |
} | |
if (!isGeneralTextEntity && standalone == 1) { | |
_dtd->standalone = XML_TRUE; | |
#ifdef XML_DTD | |
if (paramEntityParsing == XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE) | |
paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER; | |
#endif /* XML_DTD */ | |
} | |
if (xmlDeclHandler) { | |
if (encodingName != NULL) { | |
storedEncName = poolStoreString(&temp2Pool, | |
encoding, | |
encodingName, | |
encodingName | |
+ XmlNameLength(encoding, encodingName)); | |
if (!storedEncName) | |
return XML_ERROR_NO_MEMORY; | |
poolFinish(&temp2Pool); | |
} | |
if (version) { | |
storedversion = poolStoreString(&temp2Pool, | |
encoding, | |
version, | |
versionend - encoding->minBytesPerChar); | |
if (!storedversion) | |
return XML_ERROR_NO_MEMORY; | |
} | |
xmlDeclHandler(handlerArg, storedversion, storedEncName, standalone); | |
} | |
else if (defaultHandler) | |
reportDefault(parser, encoding, s, next); | |
if (protocolEncodingName == NULL) { | |
if (newEncoding) { | |
if (newEncoding->minBytesPerChar != encoding->minBytesPerChar) { | |
eventPtr = encodingName; | |
return XML_ERROR_INCORRECT_ENCODING; | |
} | |
encoding = newEncoding; | |
} | |
else if (encodingName) { | |
enum XML_Error result; | |
if (!storedEncName) { | |
storedEncName = poolStoreString( | |
&temp2Pool, encoding, encodingName, | |
encodingName + XmlNameLength(encoding, encodingName)); | |
if (!storedEncName) | |
return XML_ERROR_NO_MEMORY; | |
} | |
result = handleUnknownEncoding(parser, storedEncName); | |
poolClear(&temp2Pool); | |
if (result == XML_ERROR_UNKNOWN_ENCODING) | |
eventPtr = encodingName; | |
return result; | |
} | |
} | |
if (storedEncName || storedversion) | |
poolClear(&temp2Pool); | |
return XML_ERROR_NONE; | |
} | |
static enum XML_Error | |
handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName) | |
{ | |
if (unknownEncodingHandler) { | |
XML_Encoding info; | |
int i; | |
for (i = 0; i < 256; i++) | |
info.map[i] = -1; | |
info.convert = NULL; | |
info.data = NULL; | |
info.release = NULL; | |
if (unknownEncodingHandler(unknownEncodingHandlerData, encodingName, | |
&info)) { | |
ENCODING *enc; | |
unknownEncodingMem = MALLOC(XmlSizeOfUnknownEncoding()); | |
if (!unknownEncodingMem) { | |
if (info.release) | |
info.release(info.data); | |
return XML_ERROR_NO_MEMORY; | |
} | |
enc = (ns | |
? XmlInitUnknownEncodingNS | |
: XmlInitUnknownEncoding)(unknownEncodingMem, | |
info.map, | |
info.convert, | |
info.data); | |
if (enc) { | |
unknownEncodingData = info.data; | |
unknownEncodingRelease = info.release; | |
encoding = enc; | |
return XML_ERROR_NONE; | |
} | |
} | |
if (info.release != NULL) | |
info.release(info.data); | |
} | |
return XML_ERROR_UNKNOWN_ENCODING; | |
} | |
static enum XML_Error PTRCALL | |
prologInitProcessor(XML_Parser parser, | |
const char *s, | |
const char *end, | |
const char **nextPtr) | |
{ | |
enum XML_Error result = initializeEncoding(parser); | |
if (result != XML_ERROR_NONE) | |
return result; | |
processor = prologProcessor; | |
return prologProcessor(parser, s, end, nextPtr); | |
} | |
#ifdef XML_DTD | |
static enum XML_Error PTRCALL | |
externalParEntInitProcessor(XML_Parser parser, | |
const char *s, | |
const char *end, | |
const char **nextPtr) | |
{ | |
enum XML_Error result = initializeEncoding(parser); | |
if (result != XML_ERROR_NONE) | |
return result; | |
/* we know now that XML_Parse(Buffer) has been called, | |
so we consider the external parameter entity read */ | |
_dtd->paramEntityRead = XML_TRUE; | |
if (prologState.inEntityValue) { | |
processor = entityValueInitProcessor; | |
return entityValueInitProcessor(parser, s, end, nextPtr); | |
} | |
else { | |
processor = externalParEntProcessor; | |
return externalParEntProcessor(parser, s, end, nextPtr); | |
} | |
} | |
static enum XML_Error PTRCALL | |
entityValueInitProcessor(XML_Parser parser, | |
const char *s, | |
const char *end, | |
const char **nextPtr) | |
{ | |
int tok; | |
const char *start = s; | |
const char *next = start; | |
eventPtr = start; | |
for (;;) { | |
tok = XmlPrologTok(encoding, start, end, &next); | |
eventEndPtr = next; | |
if (tok <= 0) { | |
if (!ps_finalBuffer && tok != XML_TOK_INVALID) { | |
*nextPtr = s; | |
return XML_ERROR_NONE; | |
} | |
switch (tok) { | |
case XML_TOK_INVALID: | |
return XML_ERROR_INVALID_TOKEN; | |
case XML_TOK_PARTIAL: | |
return XML_ERROR_UNCLOSED_TOKEN; | |
case XML_TOK_PARTIAL_CHAR: | |
return XML_ERROR_PARTIAL_CHAR; | |
case XML_TOK_NONE: /* start == end */ | |
default: | |
break; | |
} | |
/* found end of entity value - can store it now */ | |
return storeEntityValue(parser, encoding, s, end); | |
} | |
else if (tok == XML_TOK_XML_DECL) { | |
enum XML_Error result; | |
result = processXmlDecl(parser, 0, start, next); | |
if (result != XML_ERROR_NONE) | |
return result; | |
switch (ps_parsing) { | |
case XML_SUSPENDED: | |
*nextPtr = next; | |
return XML_ERROR_NONE; | |
case XML_FINISHED: | |
return XML_ERROR_ABORTED; | |
default: | |
*nextPtr = next; | |
} | |
/* stop scanning for text declaration - we found one */ | |
processor = entityValueProcessor; | |
return entityValueProcessor(parser, next, end, nextPtr); | |
} | |
/* If we are at the end of the buffer, this would cause XmlPrologTok to | |
return XML_TOK_NONE on the next call, which would then cause the | |
function to exit with *nextPtr set to s - that is what we want for other | |
tokens, but not for the BOM - we would rather like to skip it; | |
then, when this routine is entered the next time, XmlPrologTok will | |
return XML_TOK_INVALID, since the BOM is still in the buffer | |
*/ | |
else if (tok == XML_TOK_BOM && next == end && !ps_finalBuffer) { | |
*nextPtr = next; | |
return XML_ERROR_NONE; | |
} | |
start = next; | |
eventPtr = start; | |
} | |
} | |
static enum XML_Error PTRCALL | |
externalParEntProcessor(XML_Parser parser, | |
const char *s, | |
const char *end, | |
const char **nextPtr) | |
{ | |
const char *next = s; | |
int tok; | |
tok = XmlPrologTok(encoding, s, end, &next); | |
if (tok <= 0) { | |
if (!ps_finalBuffer && tok != XML_TOK_INVALID) { | |
*nextPtr = s; | |
return XML_ERROR_NONE; | |
} | |
switch (tok) { | |
case XML_TOK_INVALID: | |
return XML_ERROR_INVALID_TOKEN; | |
case XML_TOK_PARTIAL: | |
return XML_ERROR_UNCLOSED_TOKEN; | |
case XML_TOK_PARTIAL_CHAR: | |
return XML_ERROR_PARTIAL_CHAR; | |
case XML_TOK_NONE: /* start == end */ | |
default: | |
break; | |
} | |
} | |
/* This would cause the next stage, i.e. doProlog to be passed XML_TOK_BOM. | |
However, when parsing an external subset, doProlog will not accept a BOM | |
as valid, and report a syntax error, so we have to skip the BOM | |
*/ | |
else if (tok == XML_TOK_BOM) { | |
s = next; | |
tok = XmlPrologTok(encoding, s, end, &next); | |
} | |
processor = prologProcessor; | |
return doProlog(parser, encoding, s, end, tok, next, | |
nextPtr, (XML_Bool)!ps_finalBuffer); | |
} | |
static enum XML_Error PTRCALL | |
entityValueProcessor(XML_Parser parser, | |
const char *s, | |
const char *end, | |
const char **nextPtr) | |
{ | |
const char *start = s; | |
const char *next = s; | |
const ENCODING *enc = encoding; | |
int tok; | |
for (;;) { | |
tok = XmlPrologTok(enc, start, end, &next); | |
if (tok <= 0) { | |
if (!ps_finalBuffer && tok != XML_TOK_INVALID) { | |
*nextPtr = s; | |
return XML_ERROR_NONE; | |
} | |
switch (tok) { | |
case XML_TOK_INVALID: | |
return XML_ERROR_INVALID_TOKEN; | |
case XML_TOK_PARTIAL: | |
return XML_ERROR_UNCLOSED_TOKEN; | |
case XML_TOK_PARTIAL_CHAR: | |
return XML_ERROR_PARTIAL_CHAR; | |
case XML_TOK_NONE: /* start == end */ | |
default: | |
break; | |
} | |
/* found end of entity value - can store it now */ | |
return storeEntityValue(parser, enc, s, end); | |
} | |
start = next; | |
} | |
} | |
#endif /* XML_DTD */ | |
static enum XML_Error PTRCALL | |
prologProcessor(XML_Parser parser, | |
const char *s, | |
const char *end, | |
const char **nextPtr) | |
{ | |
const char *next = s; | |
int tok = XmlPrologTok(encoding, s, end, &next); | |
return doProlog(parser, encoding, s, end, tok, next, | |
nextPtr, (XML_Bool)!ps_finalBuffer); | |
} | |
static enum XML_Error | |
doProlog(XML_Parser parser, | |
const ENCODING *enc, | |
const char *s, | |
const char *end, | |
int tok, | |
const char *next, | |
const char **nextPtr, | |
XML_Bool haveMore) | |
{ | |
#ifdef XML_DTD | |
static const XML_Char externalSubsetName[] = { '#' , '\0' }; | |
#endif /* XML_DTD */ | |
static const XML_Char atypeCDATA[] = { 'C', 'D', 'A', 'T', 'A', '\0' }; | |
static const XML_Char atypeID[] = { 'I', 'D', '\0' }; | |
static const XML_Char atypeIDREF[] = { 'I', 'D', 'R', 'E', 'F', '\0' }; | |
static const XML_Char atypeIDREFS[] = { 'I', 'D', 'R', 'E', 'F', 'S', '\0' }; | |
static const XML_Char atypeENTITY[] = { 'E', 'N', 'T', 'I', 'T', 'Y', '\0' }; | |
static const XML_Char atypeENTITIES[] = | |
{ 'E', 'N', 'T', 'I', 'T', 'I', 'E', 'S', '\0' }; | |
static const XML_Char atypeNMTOKEN[] = { | |
'N', 'M', 'T', 'O', 'K', 'E', 'N', '\0' }; | |
static const XML_Char atypeNMTOKENS[] = { | |
'N', 'M', 'T', 'O', 'K', 'E', 'N', 'S', '\0' }; | |
static const XML_Char notationPrefix[] = { | |
'N', 'O', 'T', 'A', 'T', 'I', 'O', 'N', '(', '\0' }; | |
static const XML_Char enumValueSep[] = { '|', '\0' }; | |
static const XML_Char enumValueStart[] = { '(', '\0' }; | |
/* save one level of indirection */ | |
DTD * const dtd = _dtd; | |
const char **eventPP; | |
const char **eventEndPP; | |
enum XML_Content_Quant quant; | |
if (enc == encoding) { | |
eventPP = &eventPtr; | |
eventEndPP = &eventEndPtr; | |
} | |
else { | |
eventPP = &(openInternalEntities->internalEventPtr); | |
eventEndPP = &(openInternalEntities->internalEventEndPtr); | |
} | |
for (;;) { | |
int role; | |
XML_Bool handleDefault = XML_TRUE; | |
*eventPP = s; | |
*eventEndPP = next; | |
if (tok <= 0) { | |
if (haveMore && tok != XML_TOK_INVALID) { | |
*nextPtr = s; | |
return XML_ERROR_NONE; | |
} | |
switch (tok) { | |
case XML_TOK_INVALID: | |
*eventPP = next; | |
return XML_ERROR_INVALID_TOKEN; | |
case XML_TOK_PARTIAL: | |
return XML_ERROR_UNCLOSED_TOKEN; | |
case XML_TOK_PARTIAL_CHAR: | |
return XML_ERROR_PARTIAL_CHAR; | |
case -XML_TOK_PROLOG_S: | |
tok = -tok; | |
break; | |
case XML_TOK_NONE: | |
#ifdef XML_DTD | |
/* for internal PE NOT referenced between declarations */ | |
if (enc != encoding && !openInternalEntities->betweenDecl) { | |
*nextPtr = s; | |
return XML_ERROR_NONE; | |
} | |
/* WFC: PE Between Declarations - must check that PE contains | |
complete markup, not only for external PEs, but also for | |
internal PEs if the reference occurs between declarations. | |
*/ | |
if (isParamEntity || enc != encoding) { | |
if (XmlTokenRole(&prologState, XML_TOK_NONE, end, end, enc) | |
== XML_ROLE_ERROR) | |
return XML_ERROR_INCOMPLETE_PE; | |
*nextPtr = s; | |
return XML_ERROR_NONE; | |
} | |
#endif /* XML_DTD */ | |
return XML_ERROR_NO_ELEMENTS; | |
default: | |
tok = -tok; | |
next = end; | |
break; | |
} | |
} | |
role = XmlTokenRole(&prologState, tok, s, next, enc); | |
switch (role) { | |
case XML_ROLE_XML_DECL: | |
{ | |
enum XML_Error result = processXmlDecl(parser, 0, s, next); | |
if (result != XML_ERROR_NONE) | |
return result; | |
enc = encoding; | |
handleDefault = XML_FALSE; | |
} | |
break; | |
case XML_ROLE_DOCTYPE_NAME: | |
if (startDoctypeDeclHandler) { | |
doctypeName = poolStoreString(&tempPool, enc, s, next); | |
if (!doctypeName) | |
return XML_ERROR_NO_MEMORY; | |
poolFinish(&tempPool); | |
doctypePubid = NULL; | |
handleDefault = XML_FALSE; | |
} | |
doctypeSysid = NULL; /* always initialize to NULL */ | |
break; | |
case XML_ROLE_DOCTYPE_INTERNAL_SUBSET: | |
if (startDoctypeDeclHandler) { | |
startDoctypeDeclHandler(handlerArg, doctypeName, doctypeSysid, | |
doctypePubid, 1); | |
doctypeName = NULL; | |
poolClear(&tempPool); | |
handleDefault = XML_FALSE; | |
} | |
break; | |
#ifdef XML_DTD | |
case XML_ROLE_TEXT_DECL: | |
{ | |
enum XML_Error result = processXmlDecl(parser, 1, s, next); | |
if (result != XML_ERROR_NONE) | |
return result; | |
enc = encoding; | |
handleDefault = XML_FALSE; | |
} | |
break; | |
#endif /* XML_DTD */ | |
case XML_ROLE_DOCTYPE_PUBLIC_ID: | |
#ifdef XML_DTD | |
useForeignDTD = XML_FALSE; | |
declEntity = (ENTITY *)lookup(&dtd->paramEntities, | |
externalSubsetName, | |
sizeof(ENTITY)); | |
if (!declEntity) | |
return XML_ERROR_NO_MEMORY; | |
#endif /* XML_DTD */ | |
dtd->hasParamEntityRefs = XML_TRUE; | |
if (startDoctypeDeclHandler) { | |
if (!XmlIsPublicId(enc, s, next, eventPP)) | |
return XML_ERROR_PUBLICID; | |
doctypePubid = poolStoreString(&tempPool, enc, | |
s + enc->minBytesPerChar, | |
next - enc->minBytesPerChar); | |
if (!doctypePubid) | |
return XML_ERROR_NO_MEMORY; | |
normalizePublicId((XML_Char *)doctypePubid); | |
poolFinish(&tempPool); | |
handleDefault = XML_FALSE; | |
goto alreadyChecked; | |
} | |
/* fall through */ | |
case XML_ROLE_ENTITY_PUBLIC_ID: | |
if (!XmlIsPublicId(enc, s, next, eventPP)) | |
return XML_ERROR_PUBLICID; | |
alreadyChecked: | |
if (dtd->keepProcessing && declEntity) { | |
XML_Char *tem = poolStoreString(&dtd->pool, | |
enc, | |
s + enc->minBytesPerChar, | |
next - enc->minBytesPerChar); | |
if (!tem) | |
return XML_ERROR_NO_MEMORY; | |
normalizePublicId(tem); | |
declEntity->publicId = tem; | |
poolFinish(&dtd->pool); | |
if (entityDeclHandler) | |
handleDefault = XML_FALSE; | |
} | |
break; | |
case XML_ROLE_DOCTYPE_CLOSE: | |
if (doctypeName) { | |
startDoctypeDeclHandler(handlerArg, doctypeName, | |
doctypeSysid, doctypePubid, 0); | |
poolClear(&tempPool); | |
handleDefault = XML_FALSE; | |
} | |
/* doctypeSysid will be non-NULL in the case of a previous | |
XML_ROLE_DOCTYPE_SYSTEM_ID, even if startDoctypeDeclHandler | |
was not set, indicating an external subset | |
*/ | |
#ifdef XML_DTD | |
if (doctypeSysid || useForeignDTD) { | |
XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs; | |
dtd->hasParamEntityRefs = XML_TRUE; | |
if (paramEntityParsing && externalEntityRefHandler) { | |
ENTITY *entity = (ENTITY *)lookup(&dtd->paramEntities, | |
externalSubsetName, | |
sizeof(ENTITY)); | |
if (!entity) | |
return XML_ERROR_NO_MEMORY; | |
if (useForeignDTD) | |
entity->base = curBase; | |
dtd->paramEntityRead = XML_FALSE; | |
if (!externalEntityRefHandler(externalEntityRefHandlerArg, | |
0, | |
entity->base, | |
entity->systemId, | |
entity->publicId)) | |
return XML_ERROR_EXTERNAL_ENTITY_HANDLING; | |
if (dtd->paramEntityRead) { | |
if (!dtd->standalone && | |
notStandaloneHandler && | |
!notStandaloneHandler(handlerArg)) | |
return XML_ERROR_NOT_STANDALONE; | |
} | |
/* if we didn't read the foreign DTD then this means that there | |
is no external subset and we must reset dtd->hasParamEntityRefs | |
*/ | |
else if (!doctypeSysid) | |
dtd->hasParamEntityRefs = hadParamEntityRefs; | |
/* end of DTD - no need to update dtd->keepProcessing */ | |
} | |
useForeignDTD = XML_FALSE; | |
} | |
#endif /* XML_DTD */ | |
if (endDoctypeDeclHandler) { | |
endDoctypeDeclHandler(handlerArg); | |
handleDefault = XML_FALSE; | |
} | |
break; | |
case XML_ROLE_INSTANCE_START: | |
#ifdef XML_DTD | |
/* if there is no DOCTYPE declaration then now is the | |
last chance to read the foreign DTD | |
*/ | |
if (useForeignDTD) { | |
XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs; | |
dtd->hasParamEntityRefs = XML_TRUE; | |
if (paramEntityParsing && externalEntityRefHandler) { | |
ENTITY *entity = (ENTITY *)lookup(&dtd->paramEntities, | |
externalSubsetName, | |
sizeof(ENTITY)); | |
if (!entity) | |
return XML_ERROR_NO_MEMORY; | |
entity->base = curBase; | |
dtd->paramEntityRead = XML_FALSE; | |
if (!externalEntityRefHandler(externalEntityRefHandlerArg, | |
0, | |
entity->base, | |
entity->systemId, | |
entity->publicId)) | |
return XML_ERROR_EXTERNAL_ENTITY_HANDLING; | |
if (dtd->paramEntityRead) { | |
if (!dtd->standalone && | |
notStandaloneHandler && | |
!notStandaloneHandler(handlerArg)) | |
return XML_ERROR_NOT_STANDALONE; | |
} | |
/* if we didn't read the foreign DTD then this means that there | |
is no external subset and we must reset dtd->hasParamEntityRefs | |
*/ | |
else | |
dtd->hasParamEntityRefs = hadParamEntityRefs; | |
/* end of DTD - no need to update dtd->keepProcessing */ | |
} | |
} | |
#endif /* XML_DTD */ | |
processor = contentProcessor; | |
return contentProcessor(parser, s, end, nextPtr); | |
case XML_ROLE_ATTLIST_ELEMENT_NAME: | |
declElementType = getElementType(parser, enc, s, next); | |
if (!declElementType) | |
return XML_ERROR_NO_MEMORY; | |
goto checkAttListDeclHandler; | |
case XML_ROLE_ATTRIBUTE_NAME: | |
declAttributeId = getAttributeId(parser, enc, s, next); | |
if (!declAttributeId) | |
return XML_ERROR_NO_MEMORY; | |
declAttributeIsCdata = XML_FALSE; | |
declAttributeType = NULL; | |
declAttributeIsId = XML_FALSE; | |
goto checkAttListDeclHandler; | |
case XML_ROLE_ATTRIBUTE_TYPE_CDATA: | |
declAttributeIsCdata = XML_TRUE; | |
declAttributeType = atypeCDATA; | |
goto checkAttListDeclHandler; | |
case XML_ROLE_ATTRIBUTE_TYPE_ID: | |
declAttributeIsId = XML_TRUE; | |
declAttributeType = atypeID; | |
goto checkAttListDeclHandler; | |
case XML_ROLE_ATTRIBUTE_TYPE_IDREF: | |
declAttributeType = atypeIDREF; | |
goto checkAttListDeclHandler; | |
case XML_ROLE_ATTRIBUTE_TYPE_IDREFS: | |
declAttributeType = atypeIDREFS; | |
goto checkAttListDeclHandler; | |
case XML_ROLE_ATTRIBUTE_TYPE_ENTITY: | |
declAttributeType = atypeENTITY; | |
goto checkAttListDeclHandler; | |
case XML_ROLE_ATTRIBUTE_TYPE_ENTITIES: | |
declAttributeType = atypeENTITIES; | |
goto checkAttListDeclHandler; | |
case XML_ROLE_ATTRIBUTE_TYPE_NMTOKEN: | |
declAttributeType = atypeNMTOKEN; | |
goto checkAttListDeclHandler; | |
case XML_ROLE_ATTRIBUTE_TYPE_NMTOKENS: | |
declAttributeType = atypeNMTOKENS; | |
checkAttListDeclHandler: | |
if (dtd->keepProcessing && attlistDeclHandler) | |
handleDefault = XML_FALSE; | |
break; | |
case XML_ROLE_ATTRIBUTE_ENUM_VALUE: | |
case XML_ROLE_ATTRIBUTE_NOTATION_VALUE: | |
if (dtd->keepProcessing && attlistDeclHandler) { | |
const XML_Char *prefix; | |
if (declAttributeType) { | |
prefix = enumValueSep; | |
} | |
else { | |
prefix = (role == XML_ROLE_ATTRIBUTE_NOTATION_VALUE | |
? notationPrefix | |
: enumValueStart); | |
} | |
if (!poolAppendString(&tempPool, prefix)) | |
return XML_ERROR_NO_MEMORY; | |
if (!poolAppend(&tempPool, enc, s, next)) | |
return XML_ERROR_NO_MEMORY; | |
declAttributeType = tempPool.start; | |
handleDefault = XML_FALSE; | |
} | |
break; | |
case XML_ROLE_IMPLIED_ATTRIBUTE_VALUE: | |
case XML_ROLE_REQUIRED_ATTRIBUTE_VALUE: | |
if (dtd->keepProcessing) { | |
if (!defineAttribute(declElementType, declAttributeId, | |
declAttributeIsCdata, declAttributeIsId, | |
0, parser)) | |
return XML_ERROR_NO_MEMORY; | |
if (attlistDeclHandler && declAttributeType) { | |
if (*declAttributeType == XML_T('(') | |
|| (*declAttributeType == XML_T('N') | |
&& declAttributeType[1] == XML_T('O'))) { | |
/* Enumerated or Notation type */ | |
if (!poolAppendChar(&tempPool, XML_T(')')) | |
|| !poolAppendChar(&tempPool, XML_T('\0'))) | |
return XML_ERROR_NO_MEMORY; | |
declAttributeType = tempPool.start; | |
poolFinish(&tempPool); | |
} | |
*eventEndPP = s; | |
attlistDeclHandler(handlerArg, declElementType->name, | |
declAttributeId->name, declAttributeType, | |
0, role == XML_ROLE_REQUIRED_ATTRIBUTE_VALUE); | |
poolClear(&tempPool); | |
handleDefault = XML_FALSE; | |
} | |
} | |
break; | |
case XML_ROLE_DEFAULT_ATTRIBUTE_VALUE: | |
case XML_ROLE_FIXED_ATTRIBUTE_VALUE: | |
if (dtd->keepProcessing) { | |
const XML_Char *attVal; | |
enum XML_Error result = | |
storeAttributeValue(parser, enc, declAttributeIsCdata, | |
s + enc->minBytesPerChar, | |
next - enc->minBytesPerChar, | |
&dtd->pool); | |
if (result) | |
return result; | |
attVal = poolStart(&dtd->pool); | |
poolFinish(&dtd->pool); | |
/* ID attributes aren't allowed to have a default */ | |
if (!defineAttribute(declElementType, declAttributeId, | |
declAttributeIsCdata, XML_FALSE, attVal, parser)) | |
return XML_ERROR_NO_MEMORY; | |
if (attlistDeclHandler && declAttributeType) { | |
if (*declAttributeType == XML_T('(') | |
|| (*declAttributeType == XML_T('N') | |
&& declAttributeType[1] == XML_T('O'))) { | |
/* Enumerated or Notation type */ | |
if (!poolAppendChar(&tempPool, XML_T(')')) | |
|| !poolAppendChar(&tempPool, XML_T('\0'))) | |
return XML_ERROR_NO_MEMORY; | |
declAttributeType = tempPool.start; | |
poolFinish(&tempPool); | |
} | |
*eventEndPP = s; | |
attlistDeclHandler(handlerArg, declElementType->name, | |
declAttributeId->name, declAttributeType, | |
attVal, | |
role == XML_ROLE_FIXED_ATTRIBUTE_VALUE); | |
poolClear(&tempPool); | |
handleDefault = XML_FALSE; | |
} | |
} | |
break; | |
case XML_ROLE_ENTITY_VALUE: | |
if (dtd->keepProcessing) { | |
enum XML_Error result = storeEntityValue(parser, enc, | |
s + enc->minBytesPerChar, | |
next - enc->minBytesPerChar); | |
if (declEntity) { | |
declEntity->textPtr = poolStart(&dtd->entityValuePool); | |
declEntity->textLen = (int)(poolLength(&dtd->entityValuePool)); | |
poolFinish(&dtd->entityValuePool); | |
if (entityDeclHandler) { | |
*eventEndPP = s; | |
entityDeclHandler(handlerArg, | |
declEntity->name, | |
declEntity->is_param, | |
declEntity->textPtr, | |
declEntity->textLen, | |
curBase, 0, 0, 0); | |
handleDefault = XML_FALSE; | |
} | |
} | |
else | |
poolDiscard(&dtd->entityValuePool); | |
if (result != XML_ERROR_NONE) | |
return result; | |
} | |
break; | |
case XML_ROLE_DOCTYPE_SYSTEM_ID: | |
#ifdef XML_DTD | |
useForeignDTD = XML_FALSE; | |
#endif /* XML_DTD */ | |
dtd->hasParamEntityRefs = XML_TRUE; | |
if (startDoctypeDeclHandler) { | |
doctypeSysid = poolStoreString(&tempPool, enc, | |
s + enc->minBytesPerChar, | |
next - enc->minBytesPerChar); | |
if (doctypeSysid == NULL) | |
return XML_ERROR_NO_MEMORY; | |
poolFinish(&tempPool); | |
handleDefault = XML_FALSE; | |
} | |
#ifdef XML_DTD | |
else | |
/* use externalSubsetName to make doctypeSysid non-NULL | |
for the case where no startDoctypeDeclHandler is set */ | |
doctypeSysid = externalSubsetName; | |
#endif /* XML_DTD */ | |
if (!dtd->standalone | |
#ifdef XML_DTD | |
&& !paramEntityParsing | |
#endif /* XML_DTD */ | |
&& notStandaloneHandler | |
&& !notStandaloneHandler(handlerArg)) | |
return XML_ERROR_NOT_STANDALONE; | |
#ifndef XML_DTD | |
break; | |
#else /* XML_DTD */ | |
if (!declEntity) { | |
declEntity = (ENTITY *)lookup(&dtd->paramEntities, | |
externalSubsetName, | |
sizeof(ENTITY)); | |
if (!declEntity) | |
return XML_ERROR_NO_MEMORY; | |
declEntity->publicId = NULL; | |
} | |
/* fall through */ | |
#endif /* XML_DTD */ | |
case XML_ROLE_ENTITY_SYSTEM_ID: | |
if (dtd->keepProcessing && declEntity) { | |
declEntity->systemId = poolStoreString(&dtd->pool, enc, | |
s + enc->minBytesPerChar, | |
next - enc->minBytesPerChar); | |
if (!declEntity->systemId) | |
return XML_ERROR_NO_MEMORY; | |
declEntity->base = curBase; | |
poolFinish(&dtd->pool); | |
if (entityDeclHandler) | |
handleDefault = XML_FALSE; | |
} | |
break; | |
case XML_ROLE_ENTITY_COMPLETE: | |
if (dtd->keepProcessing && declEntity && entityDeclHandler) { | |
*eventEndPP = s; | |
entityDeclHandler(handlerArg, | |
declEntity->name, | |
declEntity->is_param, | |
0,0, | |
declEntity->base, | |
declEntity->systemId, | |
declEntity->publicId, | |
0); | |
handleDefault = XML_FALSE; | |
} | |
break; | |
case XML_ROLE_ENTITY_NOTATION_NAME: | |
if (dtd->keepProcessing && declEntity) { | |
declEntity->notation = poolStoreString(&dtd->pool, enc, s, next); | |
if (!declEntity->notation) | |
return XML_ERROR_NO_MEMORY; | |
poolFinish(&dtd->pool); | |
if (unparsedEntityDeclHandler) { | |
*eventEndPP = s; | |
unparsedEntityDeclHandler(handlerArg, | |
declEntity->name, | |
declEntity->base, | |
declEntity->systemId, | |
declEntity->publicId, | |
declEntity->notation); | |
handleDefault = XML_FALSE; | |
} | |
else if (entityDeclHandler) { | |
*eventEndPP = s; | |
entityDeclHandler(handlerArg, | |
declEntity->name, | |
0,0,0, | |
declEntity->base, | |
declEntity->systemId, | |
declEntity->publicId, | |
declEntity->notation); | |
handleDefault = XML_FALSE; | |
} | |
} | |
break; | |
case XML_ROLE_GENERAL_ENTITY_NAME: | |
{ | |
if (XmlPredefinedEntityName(enc, s, next)) { | |
declEntity = NULL; | |
break; | |
} | |
if (dtd->keepProcessing) { | |
const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next); | |
if (!name) | |
return XML_ERROR_NO_MEMORY; | |
declEntity = (ENTITY *)lookup(&dtd->generalEntities, name, | |
sizeof(ENTITY)); | |
if (!declEntity) | |
return XML_ERROR_NO_MEMORY; | |
if (declEntity->name != name) { | |
poolDiscard(&dtd->pool); | |
declEntity = NULL; | |
} | |
else { | |
poolFinish(&dtd->pool); | |
declEntity->publicId = NULL; | |
declEntity->is_param = XML_FALSE; | |
/* if we have a parent parser or are reading an internal parameter | |
entity, then the entity declaration is not considered "internal" | |
*/ | |
declEntity->is_internal = !(parentParser || openInternalEntities); | |
if (entityDeclHandler) | |
handleDefault = XML_FALSE; | |
} | |
} | |
else { | |
poolDiscard(&dtd->pool); | |
declEntity = NULL; | |
} | |
} | |
break; | |
case XML_ROLE_PARAM_ENTITY_NAME: | |
#ifdef XML_DTD | |
if (dtd->keepProcessing) { | |
const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next); | |
if (!name) | |
return XML_ERROR_NO_MEMORY; | |
declEntity = (ENTITY *)lookup(&dtd->paramEntities, | |
name, sizeof(ENTITY)); | |
if (!declEntity) | |
return XML_ERROR_NO_MEMORY; | |
if (declEntity->name != name) { | |
poolDiscard(&dtd->pool); | |
declEntity = NULL; | |
} | |
else { | |
poolFinish(&dtd->pool); | |
declEntity->publicId = NULL; | |
declEntity->is_param = XML_TRUE; | |
/* if we have a parent parser or are reading an internal parameter | |
entity, then the entity declaration is not considered "internal" | |
*/ | |
declEntity->is_internal = !(parentParser || openInternalEntities); | |
if (entityDeclHandler) | |
handleDefault = XML_FALSE; | |
} | |
} | |
else { | |
poolDiscard(&dtd->pool); | |
declEntity = NULL; | |
} | |
#else /* not XML_DTD */ | |
declEntity = NULL; | |
#endif /* XML_DTD */ | |
break; | |
case XML_ROLE_NOTATION_NAME: | |
declNotationPublicId = NULL; | |
declNotationName = NULL; | |
if (notationDeclHandler) { | |
declNotationName = poolStoreString(&tempPool, enc, s, next); | |
if (!declNotationName) | |
return XML_ERROR_NO_MEMORY; | |
poolFinish(&tempPool); | |
handleDefault = XML_FALSE; | |
} | |
break; | |
case XML_ROLE_NOTATION_PUBLIC_ID: | |
if (!XmlIsPublicId(enc, s, next, eventPP)) | |
return XML_ERROR_PUBLICID; | |
if (declNotationName) { /* means notationDeclHandler != NULL */ | |
XML_Char *tem = poolStoreString(&tempPool, | |
enc, | |
s + enc->minBytesPerChar, | |
next - enc->minBytesPerChar); | |
if (!tem) | |
return XML_ERROR_NO_MEMORY; | |
normalizePublicId(tem); | |
declNotationPublicId = tem; | |
poolFinish(&tempPool); | |
handleDefault = XML_FALSE; | |
} | |
break; | |
case XML_ROLE_NOTATION_SYSTEM_ID: | |
if (declNotationName && notationDeclHandler) { | |
const XML_Char *systemId | |
= poolStoreString(&tempPool, enc, | |
s + enc->minBytesPerChar, | |
next - enc->minBytesPerChar); | |
if (!systemId) | |
return XML_ERROR_NO_MEMORY; | |
*eventEndPP = s; | |
notationDeclHandler(handlerArg, | |
declNotationName, | |
curBase, | |
systemId, | |
declNotationPublicId); | |
handleDefault = XML_FALSE; | |
} | |
poolClear(&tempPool); | |
break; | |
case XML_ROLE_NOTATION_NO_SYSTEM_ID: | |
if (declNotationPublicId && notationDeclHandler) { | |
*eventEndPP = s; | |
notationDeclHandler(handlerArg, | |
declNotationName, | |
curBase, | |
0, | |
declNotationPublicId); | |
handleDefault = XML_FALSE; | |
} | |
poolClear(&tempPool); | |
break; | |
case XML_ROLE_ERROR: | |
switch (tok) { | |
case XML_TOK_PARAM_ENTITY_REF: | |
/* PE references in internal subset are | |
not allowed within declarations. */ | |
return XML_ERROR_PARAM_ENTITY_REF; | |
case XML_TOK_XML_DECL: | |
return XML_ERROR_MISPLACED_XML_PI; | |
default: | |
return XML_ERROR_SYNTAX; | |
} | |
#ifdef XML_DTD | |
case XML_ROLE_IGNORE_SECT: | |
{ | |
enum XML_Error result; | |
if (defaultHandler) | |
reportDefault(parser, enc, s, next); | |
handleDefault = XML_FALSE; | |
result = doIgnoreSection(parser, enc, &next, end, nextPtr, haveMore); | |
if (result != XML_ERROR_NONE) | |
return result; | |
else if (!next) { | |
processor = ignoreSectionProcessor; | |
return result; | |
} | |
} | |
break; | |
#endif /* XML_DTD */ | |
case XML_ROLE_GROUP_OPEN: | |
if (prologState.level >= groupSize) { | |
if (groupSize) { | |
char *temp = (char *)REALLOC(groupConnector, groupSize *= 2); | |
if (temp == NULL) | |
return XML_ERROR_NO_MEMORY; | |
groupConnector = temp; | |
if (dtd->scaffIndex) { | |
int *temp = (int *)REALLOC(dtd->scaffIndex, | |
groupSize * sizeof(int)); | |
if (temp == NULL) | |
return XML_ERROR_NO_MEMORY; | |
dtd->scaffIndex = temp; | |
} | |
} | |
else { | |
groupConnector = (char *)MALLOC(groupSize = 32); | |
if (!groupConnector) | |
return XML_ERROR_NO_MEMORY; | |
} | |
} | |
groupConnector[prologState.level] = 0; | |
if (dtd->in_eldecl) { | |
int myindex = nextScaffoldPart(parser); | |
if (myindex < 0) | |
return XML_ERROR_NO_MEMORY; | |
dtd->scaffIndex[dtd->scaffLevel] = myindex; | |
dtd->scaffLevel++; | |
dtd->scaffold[myindex].type = XML_CTYPE_SEQ; | |
if (elementDeclHandler) | |
handleDefault = XML_FALSE; | |
} | |
break; | |
case XML_ROLE_GROUP_SEQUENCE: | |
if (groupConnector[prologState.level] == '|') | |
return XML_ERROR_SYNTAX; | |
groupConnector[prologState.level] = ','; | |
if (dtd->in_eldecl && elementDeclHandler) | |
handleDefault = XML_FALSE; | |
break; | |
case XML_ROLE_GROUP_CHOICE: | |
if (groupConnector[prologState.level] == ',') | |
return XML_ERROR_SYNTAX; | |
if (dtd->in_eldecl | |
&& !groupConnector[prologState.level] | |
&& (dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]].type | |
!= XML_CTYPE_MIXED) | |
) { | |
dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]].type | |
= XML_CTYPE_CHOICE; | |
if (elementDeclHandler) | |
handleDefault = XML_FALSE; | |
} | |
groupConnector[prologState.level] = '|'; | |
break; | |
case XML_ROLE_PARAM_ENTITY_REF: | |
#ifdef XML_DTD | |
case XML_ROLE_INNER_PARAM_ENTITY_REF: | |
dtd->hasParamEntityRefs = XML_TRUE; | |
if (!paramEntityParsing) | |
dtd->keepProcessing = dtd->standalone; | |
else { | |
const XML_Char *name; | |
ENTITY *entity; | |
name = poolStoreString(&dtd->pool, enc, | |
s + enc->minBytesPerChar, | |
next - enc->minBytesPerChar); | |
if (!name) | |
return XML_ERROR_NO_MEMORY; | |
entity = (ENTITY *)lookup(&dtd->paramEntities, name, 0); | |
poolDiscard(&dtd->pool); | |
/* first, determine if a check for an existing declaration is needed; | |
if yes, check that the entity exists, and that it is internal, | |
otherwise call the skipped entity handler | |
*/ | |
if (prologState.documentEntity && | |
(dtd->standalone | |
? !openInternalEntities | |
: !dtd->hasParamEntityRefs)) { | |
if (!entity) | |
return XML_ERROR_UNDEFINED_ENTITY; | |
else if (!entity->is_internal) | |
return XML_ERROR_ENTITY_DECLARED_IN_PE; | |
} | |
else if (!entity) { | |
dtd->keepProcessing = dtd->standalone; | |
/* cannot report skipped entities in declarations */ | |
if ((role == XML_ROLE_PARAM_ENTITY_REF) && skippedEntityHandler) { | |
skippedEntityHandler(handlerArg, name, 1); | |
handleDefault = XML_FALSE; | |
} | |
break; | |
} | |
if (entity->open) | |
return XML_ERROR_RECURSIVE_ENTITY_REF; | |
if (entity->textPtr) { | |
enum XML_Error result; | |
XML_Bool betweenDecl = | |
(role == XML_ROLE_PARAM_ENTITY_REF ? XML_TRUE : XML_FALSE); | |
result = processInternalEntity(parser, entity, betweenDecl); | |
if (result != XML_ERROR_NONE) | |
return result; | |
handleDefault = XML_FALSE; | |
break; | |
} | |
if (externalEntityRefHandler) { | |
dtd->paramEntityRead = XML_FALSE; | |
entity->open = XML_TRUE; | |
if (!externalEntityRefHandler(externalEntityRefHandlerArg, | |
0, | |
entity->base, | |
entity->systemId, | |
entity->publicId)) { | |
entity->open = XML_FALSE; | |
return XML_ERROR_EXTERNAL_ENTITY_HANDLING; | |
} | |
entity->open = XML_FALSE; | |
handleDefault = XML_FALSE; | |
if (!dtd->paramEntityRead) { | |
dtd->keepProcessing = dtd->standalone; | |
break; | |
} | |
} | |
else { | |
dtd->keepProcessing = dtd->standalone; | |
break; | |
} | |
} | |
#endif /* XML_DTD */ | |
if (!dtd->standalone && | |
notStandaloneHandler && | |
!notStandaloneHandler(handlerArg)) | |
return XML_ERROR_NOT_STANDALONE; | |
break; | |
/* Element declaration stuff */ | |
case XML_ROLE_ELEMENT_NAME: | |
if (elementDeclHandler) { | |
declElementType = getElementType(parser, enc, s, next); | |
if (!declElementType) | |
return XML_ERROR_NO_MEMORY; | |
dtd->scaffLevel = 0; | |
dtd->scaffCount = 0; | |
dtd->in_eldecl = XML_TRUE; | |
handleDefault = XML_FALSE; | |
} | |
break; | |
case XML_ROLE_CONTENT_ANY: | |
case XML_ROLE_CONTENT_EMPTY: | |
if (dtd->in_eldecl) { | |
if (elementDeclHandler) { | |
XML_Content * content = (XML_Content *) MALLOC(sizeof(XML_Content)); | |
if (!content) | |
return XML_ERROR_NO_MEMORY; | |
content->quant = XML_CQUANT_NONE; | |
content->name = NULL; | |
content->numchildren = 0; | |
content->children = NULL; | |
content->type = ((role == XML_ROLE_CONTENT_ANY) ? | |
XML_CTYPE_ANY : | |
XML_CTYPE_EMPTY); | |
*eventEndPP = s; | |
elementDeclHandler(handlerArg, declElementType->name, content); | |
handleDefault = XML_FALSE; | |
} | |
dtd->in_eldecl = XML_FALSE; | |
} | |
break; | |
case XML_ROLE_CONTENT_PCDATA: | |
if (dtd->in_eldecl) { | |
dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]].type | |
= XML_CTYPE_MIXED; | |
if (elementDeclHandler) | |
handleDefault = XML_FALSE; | |
} | |
break; | |
case XML_ROLE_CONTENT_ELEMENT: | |
quant = XML_CQUANT_NONE; | |
goto elementContent; | |
case XML_ROLE_CONTENT_ELEMENT_OPT: | |
quant = XML_CQUANT_OPT; | |
goto elementContent; | |
case XML_ROLE_CONTENT_ELEMENT_REP: | |
quant = XML_CQUANT_REP; | |
goto elementContent; | |
case XML_ROLE_CONTENT_ELEMENT_PLUS: | |
quant = XML_CQUANT_PLUS; | |
elementContent: | |
if (dtd->in_eldecl) { | |
ELEMENT_TYPE *el; | |
const XML_Char *name; | |
int nameLen; | |
const char *nxt = (quant == XML_CQUANT_NONE | |
? next | |
: next - enc->minBytesPerChar); | |
int myindex = nextScaffoldPart(parser); | |
if (myindex < 0) | |
return XML_ERROR_NO_MEMORY; | |
dtd->scaffold[myindex].type = XML_CTYPE_NAME; | |
dtd->scaffold[myindex].quant = quant; | |
el = getElementType(parser, enc, s, nxt); | |
if (!el) | |
return XML_ERROR_NO_MEMORY; | |
name = el->name; | |
dtd->scaffold[myindex].name = name; | |
nameLen = 0; | |
for (; name[nameLen++]; ); | |
dtd->contentStringLen += nameLen; | |
if (elementDeclHandler) | |
handleDefault = XML_FALSE; | |
} | |
break; | |
case XML_ROLE_GROUP_CLOSE: | |
quant = XML_CQUANT_NONE; | |
goto closeGroup; | |
case XML_ROLE_GROUP_CLOSE_OPT: | |
quant = XML_CQUANT_OPT; | |
goto closeGroup; | |
case XML_ROLE_GROUP_CLOSE_REP: | |
quant = XML_CQUANT_REP; | |
goto closeGroup; | |
case XML_ROLE_GROUP_CLOSE_PLUS: | |
quant = XML_CQUANT_PLUS; | |
closeGroup: | |
if (dtd->in_eldecl) { | |
if (elementDeclHandler) | |
handleDefault = XML_FALSE; | |
dtd->scaffLevel--; | |
dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel]].quant = quant; | |
if (dtd->scaffLevel == 0) { | |
if (!handleDefault) { | |
XML_Content *model = build_model(parser); | |
if (!model) | |
return XML_ERROR_NO_MEMORY; | |
*eventEndPP = s; | |
elementDeclHandler(handlerArg, declElementType->name, model); | |
} | |
dtd->in_eldecl = XML_FALSE; | |
dtd->contentStringLen = 0; | |
} | |
} | |
break; | |
/* End element declaration stuff */ | |
case XML_ROLE_PI: | |
if (!reportProcessingInstruction(parser, enc, s, next)) | |
return XML_ERROR_NO_MEMORY; | |
handleDefault = XML_FALSE; | |
break; | |
case XML_ROLE_COMMENT: | |
if (!reportComment(parser, enc, s, next)) | |
return XML_ERROR_NO_MEMORY; | |
handleDefault = XML_FALSE; | |
break; | |
case XML_ROLE_NONE: | |
switch (tok) { | |
case XML_TOK_BOM: | |
handleDefault = XML_FALSE; | |
break; | |
} | |
break; | |
case XML_ROLE_DOCTYPE_NONE: | |
if (startDoctypeDeclHandler) | |
handleDefault = XML_FALSE; | |
break; | |
case XML_ROLE_ENTITY_NONE: | |
if (dtd->keepProcessing && entityDeclHandler) | |
handleDefault = XML_FALSE; | |
break; | |
case XML_ROLE_NOTATION_NONE: | |
if (notationDeclHandler) | |
handleDefault = XML_FALSE; | |
break; | |
case XML_ROLE_ATTLIST_NONE: | |
if (dtd->keepProcessing && attlistDeclHandler) | |
handleDefault = XML_FALSE; | |
break; | |
case XML_ROLE_ELEMENT_NONE: | |
if (elementDeclHandler) | |
handleDefault = XML_FALSE; | |
break; | |
} /* end of big switch */ | |
if (handleDefault && defaultHandler) | |
reportDefault(parser, enc, s, next); | |
switch (ps_parsing) { | |
case XML_SUSPENDED: | |
*nextPtr = next; | |
return XML_ERROR_NONE; | |
case XML_FINISHED: | |
return XML_ERROR_ABORTED; | |
default: | |
s = next; | |
tok = XmlPrologTok(enc, s, end, &next); | |
} | |
} | |
/* not reached */ | |
} | |
static enum XML_Error PTRCALL | |
epilogProcessor(XML_Parser parser, | |
const char *s, | |
const char *end, | |
const char **nextPtr) | |
{ | |
processor = epilogProcessor; | |
eventPtr = s; | |
for (;;) { | |
const char *next = NULL; | |
int tok = XmlPrologTok(encoding, s, end, &next); | |
eventEndPtr = next; | |
switch (tok) { | |
/* report partial linebreak - it might be the last token */ | |
case -XML_TOK_PROLOG_S: | |
if (defaultHandler) { | |
reportDefault(parser, encoding, s, next); | |
if (ps_parsing == XML_FINISHED) | |
return XML_ERROR_ABORTED; | |
} | |
*nextPtr = next; | |
return XML_ERROR_NONE; | |
case XML_TOK_NONE: | |
*nextPtr = s; | |
return XML_ERROR_NONE; | |
case XML_TOK_PROLOG_S: | |
if (defaultHandler) | |
reportDefault(parser, encoding, s, next); | |
break; | |
case XML_TOK_PI: | |
if (!reportProcessingInstruction(parser, encoding, s, next)) | |
return XML_ERROR_NO_MEMORY; | |
break; | |
case XML_TOK_COMMENT: | |
if (!reportComment(parser, encoding, s, next)) | |
return XML_ERROR_NO_MEMORY; | |
break; | |
case XML_TOK_INVALID: | |
eventPtr = next; | |
return XML_ERROR_INVALID_TOKEN; | |
case XML_TOK_PARTIAL: | |
if (!ps_finalBuffer) { | |
*nextPtr = s; | |
return XML_ERROR_NONE; | |
} | |
return XML_ERROR_UNCLOSED_TOKEN; | |
case XML_TOK_PARTIAL_CHAR: | |
if (!ps_finalBuffer) { | |
*nextPtr = s; | |
return XML_ERROR_NONE; | |
} | |
return XML_ERROR_PARTIAL_CHAR; | |
default: | |
return XML_ERROR_JUNK_AFTER_DOC_ELEMENT; | |
} | |
eventPtr = s = next; | |
switch (ps_parsing) { | |
case XML_SUSPENDED: | |
*nextPtr = next; | |
return XML_ERROR_NONE; | |
case XML_FINISHED: | |
return XML_ERROR_ABORTED; | |
default: ; | |
} | |
} | |
} | |
static enum XML_Error | |
processInternalEntity(XML_Parser parser, ENTITY *entity, | |
XML_Bool betweenDecl) | |
{ | |
const char *textStart, *textEnd; | |
const char *next; | |
enum XML_Error result; | |
OPEN_INTERNAL_ENTITY *openEntity; | |
if (freeInternalEntities) { | |
openEntity = freeInternalEntities; | |
freeInternalEntities = openEntity->next; | |
} | |
else { | |
openEntity = (OPEN_INTERNAL_ENTITY *)MALLOC(sizeof(OPEN_INTERNAL_ENTITY)); | |
if (!openEntity) | |
return XML_ERROR_NO_MEMORY; | |
} | |
entity->open = XML_TRUE; | |
entity->processed = 0; | |
openEntity->next = openInternalEntities; | |
openInternalEntities = openEntity; | |
openEntity->entity = entity; | |
openEntity->startTagLevel = tagLevel; | |
openEntity->betweenDecl = betweenDecl; | |
openEntity->internalEventPtr = NULL; | |
openEntity->internalEventEndPtr = NULL; | |
textStart = (char *)entity->textPtr; | |
textEnd = (char *)(entity->textPtr + entity->textLen); | |
#ifdef XML_DTD | |
if (entity->is_param) { | |
int tok = XmlPrologTok(internalEncoding, textStart, textEnd, &next); | |
result = doProlog(parser, internalEncoding, textStart, textEnd, tok, | |
next, &next, XML_FALSE); | |
} | |
else | |
#endif /* XML_DTD */ | |
result = doContent(parser, tagLevel, internalEncoding, textStart, | |
textEnd, &next, XML_FALSE); | |
if (result == XML_ERROR_NONE) { | |
if (textEnd != next && ps_parsing == XML_SUSPENDED) { | |
entity->processed = (int)(next - textStart); | |
processor = internalEntityProcessor; | |
} | |
else { | |
entity->open = XML_FALSE; | |
openInternalEntities = openEntity->next; | |
/* put openEntity back in list of free instances */ | |
openEntity->next = freeInternalEntities; | |
freeInternalEntities = openEntity; | |
} | |
} | |
return result; | |
} | |
static enum XML_Error PTRCALL | |
internalEntityProcessor(XML_Parser parser, | |
const char *s, | |
const char *end, | |
const char **nextPtr) | |
{ | |
ENTITY *entity; | |
const char *textStart, *textEnd; | |
const char *next; | |
enum XML_Error result; | |
OPEN_INTERNAL_ENTITY *openEntity = openInternalEntities; | |
if (!openEntity) | |
return XML_ERROR_UNEXPECTED_STATE; | |
entity = openEntity->entity; | |
textStart = ((char *)entity->textPtr) + entity->processed; | |
textEnd = (char *)(entity->textPtr + entity->textLen); | |
#ifdef XML_DTD | |
if (entity->is_param) { | |
int tok = XmlPrologTok(internalEncoding, textStart, textEnd, &next); | |
result = doProlog(parser, internalEncoding, textStart, textEnd, tok, | |
next, &next, XML_FALSE); | |
} | |
else | |
#endif /* XML_DTD */ | |
result = doContent(parser, openEntity->startTagLevel, internalEncoding, | |
textStart, textEnd, &next, XML_FALSE); | |
if (result != XML_ERROR_NONE) | |
return result; | |
else if (textEnd != next && ps_parsing == XML_SUSPENDED) { | |
entity->processed = (int)(next - (char *)entity->textPtr); | |
return result; | |
} | |
else { | |
entity->open = XML_FALSE; | |
openInternalEntities = openEntity->next; | |
/* put openEntity back in list of free instances */ | |
openEntity->next = freeInternalEntities; | |
freeInternalEntities = openEntity; | |
} | |
#ifdef XML_DTD | |
if (entity->is_param) { | |
int tok; | |
processor = prologProcessor; | |
tok = XmlPrologTok(encoding, s, end, &next); | |
return doProlog(parser, encoding, s, end, tok, next, nextPtr, | |
(XML_Bool)!ps_finalBuffer); | |
} | |
else | |
#endif /* XML_DTD */ | |
{ | |
processor = contentProcessor; | |
/* see externalEntityContentProcessor vs contentProcessor */ | |
return doContent(parser, parentParser ? 1 : 0, encoding, s, end, | |
nextPtr, (XML_Bool)!ps_finalBuffer); | |
} | |
} | |
static enum XML_Error PTRCALL | |
errorProcessor(XML_Parser parser, | |
const char *s, | |
const char *end, | |
const char **nextPtr) | |
{ | |
return errorCode; | |
} | |
static enum XML_Error | |
storeAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata, | |
const char *ptr, const char *end, | |
STRING_POOL *pool) | |
{ | |
enum XML_Error result = appendAttributeValue(parser, enc, isCdata, ptr, | |
end, pool); | |
if (result) | |
return result; | |
if (!isCdata && poolLength(pool) && poolLastChar(pool) == 0x20) | |
poolChop(pool); | |
if (!poolAppendChar(pool, XML_T('\0'))) | |
return XML_ERROR_NO_MEMORY; | |
return XML_ERROR_NONE; | |
} | |
static enum XML_Error | |
appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata, | |
const char *ptr, const char *end, | |
STRING_POOL *pool) | |
{ | |
DTD * const dtd = _dtd; /* save one level of indirection */ | |
for (;;) { | |
const char *next; | |
int tok = XmlAttributeValueTok(enc, ptr, end, &next); | |
switch (tok) { | |
case XML_TOK_NONE: | |
return XML_ERROR_NONE; | |
case XML_TOK_INVALID: | |
if (enc == encoding) | |
eventPtr = next; | |
return XML_ERROR_INVALID_TOKEN; | |
case XML_TOK_PARTIAL: | |
if (enc == encoding) | |
eventPtr = ptr; | |
return XML_ERROR_INVALID_TOKEN; | |
case XML_TOK_CHAR_REF: | |
{ | |
XML_Char buf[XML_ENCODE_MAX]; | |
int i; | |
int n = XmlCharRefNumber(enc, ptr); | |
if (n < 0) { | |
if (enc == encoding) | |
eventPtr = ptr; | |
return XML_ERROR_BAD_CHAR_REF; | |
} | |
if (!isCdata | |
&& n == 0x20 /* space */ | |
&& (poolLength(pool) == 0 || poolLastChar(pool) == 0x20)) | |
break; | |
n = XmlEncode(n, (ICHAR *)buf); | |
if (!n) { | |
if (enc == encoding) | |
eventPtr = ptr; | |
return XML_ERROR_BAD_CHAR_REF; | |
} | |
for (i = 0; i < n; i++) { | |
if (!poolAppendChar(pool, buf[i])) | |
return XML_ERROR_NO_MEMORY; | |
} | |
} | |
break; | |
case XML_TOK_DATA_CHARS: | |
if (!poolAppend(pool, enc, ptr, next)) | |
return XML_ERROR_NO_MEMORY; | |
break; | |
case XML_TOK_TRAILING_CR: | |
next = ptr + enc->minBytesPerChar; | |
/* fall through */ | |
case XML_TOK_ATTRIBUTE_VALUE_S: | |
case XML_TOK_DATA_NEWLINE: | |
if (!isCdata && (poolLength(pool) == 0 || poolLastChar(pool) == 0x20)) | |
break; | |
if (!poolAppendChar(pool, 0x20)) | |
return XML_ERROR_NO_MEMORY; | |
break; | |
case XML_TOK_ENTITY_REF: | |
{ | |
const XML_Char *name; | |
ENTITY *entity; | |
char checkEntityDecl; | |
XML_Char ch = (XML_Char) XmlPredefinedEntityName(enc, | |
ptr + enc->minBytesPerChar, | |
next - enc->minBytesPerChar); | |
if (ch) { | |
if (!poolAppendChar(pool, ch)) | |
return XML_ERROR_NO_MEMORY; | |
break; | |
} | |
name = poolStoreString(&temp2Pool, enc, | |
ptr + enc->minBytesPerChar, | |
next - enc->minBytesPerChar); | |
if (!name) | |
return XML_ERROR_NO_MEMORY; | |
entity = (ENTITY *)lookup(&dtd->generalEntities, name, 0); | |
poolDiscard(&temp2Pool); | |
/* First, determine if a check for an existing declaration is needed; | |
if yes, check that the entity exists, and that it is internal. | |
*/ | |
if (pool == &dtd->pool) /* are we called from prolog? */ | |
checkEntityDecl = | |
#ifdef XML_DTD | |
prologState.documentEntity && | |
#endif /* XML_DTD */ | |
(dtd->standalone | |
? !openInternalEntities | |
: !dtd->hasParamEntityRefs); | |
else /* if (pool == &tempPool): we are called from content */ | |
checkEntityDecl = !dtd->hasParamEntityRefs || dtd->standalone; | |
if (checkEntityDecl) { | |
if (!entity) | |
return XML_ERROR_UNDEFINED_ENTITY; | |
else if (!entity->is_internal) | |
return XML_ERROR_ENTITY_DECLARED_IN_PE; | |
} | |
else if (!entity) { | |
/* Cannot report skipped entity here - see comments on | |
skippedEntityHandler. | |
if (skippedEntityHandler) | |
skippedEntityHandler(handlerArg, name, 0); | |
*/ | |
/* Cannot call the default handler because this would be | |
out of sync with the call to the startElementHandler. | |
if ((pool == &tempPool) && defaultHandler) | |
reportDefault(parser, enc, ptr, next); | |
*/ | |
break; | |
} | |
if (entity->open) { | |
if (enc == encoding) | |
eventPtr = ptr; | |
return XML_ERROR_RECURSIVE_ENTITY_REF; | |
} | |
if (entity->notation) { | |
if (enc == encoding) | |
eventPtr = ptr; | |
return XML_ERROR_BINARY_ENTITY_REF; | |
} | |
if (!entity->textPtr) { | |
if (enc == encoding) | |
eventPtr = ptr; | |
return XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF; | |
} | |
else { | |
enum XML_Error result; | |
const XML_Char *textEnd = entity->textPtr + entity->textLen; | |
entity->open = XML_TRUE; | |
result = appendAttributeValue(parser, internalEncoding, isCdata, | |
(char *)entity->textPtr, | |
(char *)textEnd, pool); | |
entity->open = XML_FALSE; | |
if (result) | |
return result; | |
} | |
} | |
break; | |
default: | |
if (enc == encoding) | |
eventPtr = ptr; | |
return XML_ERROR_UNEXPECTED_STATE; | |
} | |
ptr = next; | |
} | |
/* not reached */ | |
} | |
static enum XML_Error | |
storeEntityValue(XML_Parser parser, | |
const ENCODING *enc, | |
const char *entityTextPtr, | |
const char *entityTextEnd) | |
{ | |
DTD * const dtd = _dtd; /* save one level of indirection */ | |
STRING_POOL *pool = &(dtd->entityValuePool); | |
enum XML_Error result = XML_ERROR_NONE; | |
#ifdef XML_DTD | |
int oldInEntityValue = prologState.inEntityValue; | |
prologState.inEntityValue = 1; | |
#endif /* XML_DTD */ | |
/* never return Null for the value argument in EntityDeclHandler, | |
since this would indicate an external entity; therefore we | |
have to make sure that entityValuePool.start is not null */ | |
if (!pool->blocks) { | |
if (!poolGrow(pool)) | |
return XML_ERROR_NO_MEMORY; | |
} | |
for (;;) { | |
const char *next; | |
int tok = XmlEntityValueTok(enc, entityTextPtr, entityTextEnd, &next); | |
switch (tok) { | |
case XML_TOK_PARAM_ENTITY_REF: | |
#ifdef XML_DTD | |
if (isParamEntity || enc != encoding) { | |
const XML_Char *name; | |
ENTITY *entity; | |
name = poolStoreString(&tempPool, enc, | |
entityTextPtr + enc->minBytesPerChar, | |
next - enc->minBytesPerChar); | |
if (!name) { | |
result = XML_ERROR_NO_MEMORY; | |
goto endEntityValue; | |
} | |
entity = (ENTITY *)lookup(&dtd->paramEntities, name, 0); | |
poolDiscard(&tempPool); | |
if (!entity) { | |
/* not a well-formedness error - see XML 1.0: WFC Entity Declared */ | |
/* cannot report skipped entity here - see comments on | |
skippedEntityHandler | |
if (skippedEntityHandler) | |
skippedEntityHandler(handlerArg, name, 0); | |
*/ | |
dtd->keepProcessing = dtd->standalone; | |
goto endEntityValue; | |
} | |
if (entity->open) { | |
if (enc == encoding) | |
eventPtr = entityTextPtr; | |
result = XML_ERROR_RECURSIVE_ENTITY_REF; | |
goto endEntityValue; | |
} | |
if (entity->systemId) { | |
if (externalEntityRefHandler) { | |
dtd->paramEntityRead = XML_FALSE; | |
entity->open = XML_TRUE; | |
if (!externalEntityRefHandler(externalEntityRefHandlerArg, | |
0, | |
entity->base, | |
entity->systemId, | |
entity->publicId)) { | |
entity->open = XML_FALSE; | |
result = XML_ERROR_EXTERNAL_ENTITY_HANDLING; | |
goto endEntityValue; | |
} | |
entity->open = XML_FALSE; | |
if (!dtd->paramEntityRead) | |
dtd->keepProcessing = dtd->standalone; | |
} | |
else | |
dtd->keepProcessing = dtd->standalone; | |
} | |
else { | |
entity->open = XML_TRUE; | |
result = storeEntityValue(parser, | |
internalEncoding, | |
(char *)entity->textPtr, | |
(char *)(entity->textPtr | |
+ entity->textLen)); | |
entity->open = XML_FALSE; | |
if (result) | |
goto endEntityValue; | |
} | |
break; | |
} | |
#endif /* XML_DTD */ | |
/* In the internal subset, PE references are not legal | |
within markup declarations, e.g entity values in this case. */ | |
eventPtr = entityTextPtr; | |
result = XML_ERROR_PARAM_ENTITY_REF; | |
goto endEntityValue; | |
case XML_TOK_NONE: | |
result = XML_ERROR_NONE; | |
goto endEntityValue; | |
case XML_TOK_ENTITY_REF: | |
case XML_TOK_DATA_CHARS: | |
if (!poolAppend(pool, enc, entityTextPtr, next)) { | |
result = XML_ERROR_NO_MEMORY; | |
goto endEntityValue; | |
} | |
break; | |
case XML_TOK_TRAILING_CR: | |
next = entityTextPtr + enc->minBytesPerChar; | |
/* fall through */ | |
case XML_TOK_DATA_NEWLINE: | |
if (pool->end == pool->ptr && !poolGrow(pool)) { | |
result = XML_ERROR_NO_MEMORY; | |
goto endEntityValue; | |
} | |
*(pool->ptr)++ = 0xA; | |
break; | |
case XML_TOK_CHAR_REF: | |
{ | |
XML_Char buf[XML_ENCODE_MAX]; | |
int i; | |
int n = XmlCharRefNumber(enc, entityTextPtr); | |
if (n < 0) { | |
if (enc == encoding) | |
eventPtr = entityTextPtr; | |
result = XML_ERROR_BAD_CHAR_REF; | |
goto endEntityValue; | |
} | |
n = XmlEncode(n, (ICHAR *)buf); | |
if (!n) { | |
if (enc == encoding) | |
eventPtr = entityTextPtr; | |
result = XML_ERROR_BAD_CHAR_REF; | |
goto endEntityValue; | |
} | |
for (i = 0; i < n; i++) { | |
if (pool->end == pool->ptr && !poolGrow(pool)) { | |
result = XML_ERROR_NO_MEMORY; | |
goto endEntityValue; | |
} | |
*(pool->ptr)++ = buf[i]; | |
} | |
} | |
break; | |
case XML_TOK_PARTIAL: | |
if (enc == encoding) | |
eventPtr = entityTextPtr; | |
result = XML_ERROR_INVALID_TOKEN; | |
goto endEntityValue; | |
case XML_TOK_INVALID: | |
if (enc == encoding) | |
eventPtr = next; | |
result = XML_ERROR_INVALID_TOKEN; | |
goto endEntityValue; | |
default: | |
if (enc == encoding) | |
eventPtr = entityTextPtr; | |
result = XML_ERROR_UNEXPECTED_STATE; | |
goto endEntityValue; | |
} | |
entityTextPtr = next; | |
} | |
endEntityValue: | |
#ifdef XML_DTD | |
prologState.inEntityValue = oldInEntityValue; | |
#endif /* XML_DTD */ | |
return result; | |
} | |
static void FASTCALL | |
normalizeLines(XML_Char *s) | |
{ | |
XML_Char *p; | |
for (;; s++) { | |
if (*s == XML_T('\0')) | |
return; | |
if (*s == 0xD) | |
break; | |
} | |
p = s; | |
do { | |
if (*s == 0xD) { | |
*p++ = 0xA; | |
if (*++s == 0xA) | |
s++; | |
} | |
else | |
*p++ = *s++; | |
} while (*s); | |
*p = XML_T('\0'); | |
} | |
static int | |
reportProcessingInstruction(XML_Parser parser, const ENCODING *enc, | |
const char *start, const char *end) | |
{ | |
const XML_Char *target; | |
XML_Char *data; | |
const char *tem; | |
if (!processingInstructionHandler) { | |
if (defaultHandler) | |
reportDefault(parser, enc, start, end); | |
return 1; | |
} | |
start += enc->minBytesPerChar * 2; | |
tem = start + XmlNameLength(enc, start); | |
target = poolStoreString(&tempPool, enc, start, tem); | |
if (!target) | |
return 0; | |
poolFinish(&tempPool); | |
data = poolStoreString(&tempPool, enc, | |
XmlSkipS(enc, tem), | |
end - enc->minBytesPerChar*2); | |
if (!data) | |
return 0; | |
normalizeLines(data); | |
processingInstructionHandler(handlerArg, target, data); | |
poolClear(&tempPool); | |
return 1; | |
} | |
static int | |
reportComment(XML_Parser parser, const ENCODING *enc, | |
const char *start, const char *end) | |
{ | |
XML_Char *data; | |
if (!commentHandler) { | |
if (defaultHandler) | |
reportDefault(parser, enc, start, end); | |
return 1; | |
} | |
data = poolStoreString(&tempPool, | |
enc, | |
start + enc->minBytesPerChar * 4, | |
end - enc->minBytesPerChar * 3); | |
if (!data) | |
return 0; | |
normalizeLines(data); | |
commentHandler(handlerArg, data); | |
poolClear(&tempPool); | |
return 1; | |
} | |
static void | |
reportDefault(XML_Parser parser, const ENCODING *enc, | |
const char *s, const char *end) | |
{ | |
if (MUST_CONVERT(enc, s)) { | |
const char **eventPP; | |
const char **eventEndPP; | |
if (enc == encoding) { | |
eventPP = &eventPtr; | |
eventEndPP = &eventEndPtr; | |
} | |
else { | |
eventPP = &(openInternalEntities->internalEventPtr); | |
eventEndPP = &(openInternalEntities->internalEventEndPtr); | |
} | |
do { | |
ICHAR *dataPtr = (ICHAR *)dataBuf; | |
XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)dataBufEnd); | |
*eventEndPP = s; | |
defaultHandler(handlerArg, dataBuf, (int)(dataPtr - (ICHAR *)dataBuf)); | |
*eventPP = s; | |
} while (s != end); | |
} | |
else | |
defaultHandler(handlerArg, (XML_Char *)s, (int)((XML_Char *)end - (XML_Char *)s)); | |
} | |
static int | |
defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, XML_Bool isCdata, | |
XML_Bool isId, const XML_Char *value, XML_Parser parser) | |
{ | |
DEFAULT_ATTRIBUTE *att; | |
if (value || isId) { | |
/* The handling of default attributes gets messed up if we have | |
a default which duplicates a non-default. */ | |
int i; | |
for (i = 0; i < type->nDefaultAtts; i++) | |
if (attId == type->defaultAtts[i].id) | |
return 1; | |
if (isId && !type->idAtt && !attId->xmlns) | |
type->idAtt = attId; | |
} | |
if (type->nDefaultAtts == type->allocDefaultAtts) { | |
if (type->allocDefaultAtts == 0) { | |
type->allocDefaultAtts = 8; | |
type->defaultAtts = (DEFAULT_ATTRIBUTE *)MALLOC(type->allocDefaultAtts | |
* sizeof(DEFAULT_ATTRIBUTE)); | |
if (!type->defaultAtts) | |
return 0; | |
} | |
else { | |
DEFAULT_ATTRIBUTE *temp; | |
int count = type->allocDefaultAtts * 2; | |
temp = (DEFAULT_ATTRIBUTE *) | |
REALLOC(type->defaultAtts, (count * sizeof(DEFAULT_ATTRIBUTE))); | |
if (temp == NULL) | |
return 0; | |
type->allocDefaultAtts = count; | |
type->defaultAtts = temp; | |
} | |
} | |
att = type->defaultAtts + type->nDefaultAtts; | |
att->id = attId; | |
att->value = value; | |
att->isCdata = isCdata; | |
if (!isCdata) | |
attId->maybeTokenized = XML_TRUE; | |
type->nDefaultAtts += 1; | |
return 1; | |
} | |
static int | |
setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *elementType) | |
{ | |
DTD * const dtd = _dtd; /* save one level of indirection */ | |
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) | |
{ | |
DTD * const dtd = _dtd; /* save one level of indirection */ | |
ATTRIBUTE_ID *id; | |
const XML_Char *name; | |
if (!poolAppendChar(&dtd->pool, XML_T('\0'))) | |
return NULL; | |
name = poolStoreString(&dtd->pool, enc, start, end); | |
if (!name) | |
return NULL; | |
/* skip quotation mark - its storage will be re-used (like in name[-1]) */ | |
++name; | |
id = (ATTRIBUTE_ID *)lookup(&dtd->attributeIds, name, sizeof(ATTRIBUTE_ID)); | |
if (!id) | |
return NULL; | |
if (id->name != name) | |
poolDiscard(&dtd->pool); | |
else { | |
poolFinish(&dtd->pool); | |
if (!ns) | |
; | |
else if (name[0] == XML_T('x') | |
&& name[1] == XML_T('m') | |
&& name[2] == XML_T('l') | |
&& name[3] == XML_T('n') | |
&& name[4] == XML_T('s') | |
&& (name[5] == XML_T('\0') || name[5] == XML_T(':'))) { | |
if (name[5] == XML_T('\0')) | |
id->prefix = &dtd->defaultPrefix; | |
else | |
id->prefix = (PREFIX *)lookup(&dtd->prefixes, name + 6, sizeof(PREFIX)); | |
id->xmlns = XML_TRUE; | |
} | |
else { | |
int i; | |
for (i = 0; name[i]; i++) { | |
/* attributes without prefix are *not* in the default namespace */ | |
if (name[i] == XML_T(':')) { | |
int j; | |
for (j = 0; j < i; j++) { | |
if (!poolAppendChar(&dtd->pool, name[j])) | |
return NULL; | |
} | |
if (!poolAppendChar(&dtd->pool, XML_T('\0'))) | |
return NULL; | |
id->prefix = (PREFIX *)lookup(&dtd->prefixes, poolStart(&dtd->pool), | |
sizeof(PREFIX)); | |
if (!id->prefix) | |
return NULL; | |
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 * | |
getContext(XML_Parser parser) | |
{ | |
DTD * const dtd = _dtd; /* save one level of indirection */ | |
HASH_TABLE_ITER iter; | |
XML_Bool needSep = XML_FALSE; | |
if (dtd->defaultPrefix.binding) { | |
int i; | |
int len; | |
if (!poolAppendChar(&tempPool, XML_T('='))) | |
return NULL; | |
len = dtd->defaultPrefix.binding->uriLen; | |
if (namespaceSeparator) | |
len--; | |
for (i = 0; i < len; i++) | |
if (!poolAppendChar(&tempPool, dtd->defaultPrefix.binding->uri[i])) | |
return NULL; | |
needSep = XML_TRUE; | |
} | |
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 NULL; | |
for (s = prefix->name; *s; s++) | |
if (!poolAppendChar(&tempPool, *s)) | |
return NULL; | |
if (!poolAppendChar(&tempPool, XML_T('='))) | |
return NULL; | |
len = prefix->binding->uriLen; | |
if (namespaceSeparator) | |
len--; | |
for (i = 0; i < len; i++) | |
if (!poolAppendChar(&tempPool, prefix->binding->uri[i])) | |
return NULL; | |
needSep = XML_TRUE; | |
} | |
hashTableIterInit(&iter, &(dtd->generalEntities)); | |
for (;;) { | |
const XML_Char *s; | |
ENTITY *e = (ENTITY *)hashTableIterNext(&iter); | |
if (!e) | |
break; | |
if (!e->open) | |
continue; | |
if (needSep && !poolAppendChar(&tempPool, CONTEXT_SEP)) | |
return NULL; | |
for (s = e->name; *s; s++) | |
if (!poolAppendChar(&tempPool, *s)) | |
return 0; | |
needSep = XML_TRUE; | |
} | |
if (!poolAppendChar(&tempPool, XML_T('\0'))) | |
return NULL; | |
return tempPool.start; | |
} | |
static XML_Bool | |
setContext(XML_Parser parser, const XML_Char *context) | |
{ | |
DTD * const dtd = _dtd; /* save one level of indirection */ | |
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 XML_FALSE; | |
e = (ENTITY *)lookup(&dtd->generalEntities, poolStart(&tempPool), 0); | |
if (e) | |
e->open = XML_TRUE; | |
if (*s != XML_T('\0')) | |
s++; | |
context = s; | |
poolDiscard(&tempPool); | |
} | |
else if (*s == XML_T('=')) { | |
PREFIX *prefix; | |
if (poolLength(&tempPool) == 0) | |
prefix = &dtd->defaultPrefix; | |
else { | |
if (!poolAppendChar(&tempPool, XML_T('\0'))) | |
return XML_FALSE; | |
prefix = (PREFIX *)lookup(&dtd->prefixes, poolStart(&tempPool), | |
sizeof(PREFIX)); | |
if (!prefix) | |
return XML_FALSE; | |
if (prefix->name == poolStart(&tempPool)) { | |
prefix->name = poolCopyString(&dtd->pool, prefix->name); | |
if (!prefix->name) | |
return XML_FALSE; | |
} | |
poolDiscard(&tempPool); | |
} | |
for (context = s + 1; | |
*context != CONTEXT_SEP && *context != XML_T('\0'); | |
context++) | |
if (!poolAppendChar(&tempPool, *context)) | |
return XML_FALSE; | |
if (!poolAppendChar(&tempPool, XML_T('\0'))) | |
return XML_FALSE; | |
if (addBinding(parser, prefix, NULL, poolStart(&tempPool), | |
&inheritedBindings) != XML_ERROR_NONE) | |
return XML_FALSE; | |
poolDiscard(&tempPool); | |
if (*context != XML_T('\0')) | |
++context; | |
s = context; | |
} | |
else { | |
if (!poolAppendChar(&tempPool, *s)) | |
return XML_FALSE; | |
s++; | |
} | |
} | |
return XML_TRUE; | |
} | |
static void FASTCALL | |
normalizePublicId(XML_Char *publicId) | |
{ | |
XML_Char *p = publicId; | |
XML_Char *s; | |
for (s = publicId; *s; s++) { | |
switch (*s) { | |
case 0x20: | |
case 0xD: | |
case 0xA: | |
if (p != publicId && p[-1] != 0x20) | |
*p++ = 0x20; | |
break; | |
default: | |
*p++ = *s; | |
} | |
} | |
if (p != publicId && p[-1] == 0x20) | |
--p; | |
*p = XML_T('\0'); | |
} | |
static DTD * | |
dtdCreate(const XML_Memory_Handling_Suite *ms) | |
{ | |
DTD *p = (DTD *)ms->malloc_fcn(sizeof(DTD)); | |
if (p == NULL) | |
return p; | |
poolInit(&(p->pool), ms); | |
poolInit(&(p->entityValuePool), ms); | |
hashTableInit(&(p->generalEntities), ms); | |
hashTableInit(&(p->elementTypes), ms); | |
hashTableInit(&(p->attributeIds), ms); | |
hashTableInit(&(p->prefixes), ms); | |
#ifdef XML_DTD | |
p->paramEntityRead = XML_FALSE; | |
hashTableInit(&(p->paramEntities), ms); | |
#endif /* XML_DTD */ | |
p->defaultPrefix.name = NULL; | |
p->defaultPrefix.binding = NULL; | |
p->in_eldecl = XML_FALSE; | |
p->scaffIndex = NULL; | |
p->scaffold = NULL; | |
p->scaffLevel = 0; | |
p->scaffSize = 0; | |
p->scaffCount = 0; | |
p->contentStringLen = 0; | |
p->keepProcessing = XML_TRUE; | |
p->hasParamEntityRefs = XML_FALSE; | |
p->standalone = XML_FALSE; | |
return p; | |
} | |
static void | |
dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms) | |
{ | |
HASH_TABLE_ITER iter; | |
hashTableIterInit(&iter, &(p->elementTypes)); | |
for (;;) { | |
ELEMENT_TYPE *e = (ELEMENT_TYPE *)hashTableIterNext(&iter); | |
if (!e) | |
break; | |
if (e->allocDefaultAtts != 0) | |
ms->free_fcn(e->defaultAtts); | |
} | |
hashTableClear(&(p->generalEntities)); | |
#ifdef XML_DTD | |
p->paramEntityRead = XML_FALSE; | |
hashTableClear(&(p->paramEntities)); | |
#endif /* XML_DTD */ | |
hashTableClear(&(p->elementTypes)); | |
hashTableClear(&(p->attributeIds)); | |
hashTableClear(&(p->prefixes)); | |
poolClear(&(p->pool)); | |
poolClear(&(p->entityValuePool)); | |
p->defaultPrefix.name = NULL; | |
p->defaultPrefix.binding = NULL; | |
p->in_eldecl = XML_FALSE; | |
ms->free_fcn(p->scaffIndex); | |
p->scaffIndex = NULL; | |
ms->free_fcn(p->scaffold); | |
p->scaffold = NULL; | |
p->scaffLevel = 0; | |
p->scaffSize = 0; | |
p->scaffCount = 0; | |
p->contentStringLen = 0; | |
p->keepProcessing = XML_TRUE; | |
p->hasParamEntityRefs = XML_FALSE; | |
p->standalone = XML_FALSE; | |
} | |
static void | |
dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms) | |
{ | |
HASH_TABLE_ITER iter; | |
hashTableIterInit(&iter, &(p->elementTypes)); | |
for (;;) { | |
ELEMENT_TYPE *e = (ELEMENT_TYPE *)hashTableIterNext(&iter); | |
if (!e) | |
break; | |
if (e->allocDefaultAtts != 0) | |
ms->free_fcn(e->defaultAtts); | |
} | |
hashTableDestroy(&(p->generalEntities)); | |
#ifdef XML_DTD | |
hashTableDestroy(&(p->paramEntities)); | |
#endif /* XML_DTD */ | |
hashTableDestroy(&(p->elementTypes)); | |
hashTableDestroy(&(p->attributeIds)); | |
hashTableDestroy(&(p->prefixes)); | |
poolDestroy(&(p->pool)); | |
poolDestroy(&(p->entityValuePool)); | |
if (isDocEntity) { | |
ms->free_fcn(p->scaffIndex); | |
ms->free_fcn(p->scaffold); | |
} | |
ms->free_fcn(p); | |
} | |
/* 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, const XML_Memory_Handling_Suite *ms) | |
{ | |
HASH_TABLE_ITER iter; | |
/* 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. */ | |
for (;;) { | |
ATTRIBUTE_ID *newA; | |
const XML_Char *name; | |
const ATTRIBUTE_ID *oldA = (ATTRIBUTE_ID *)hashTableIterNext(&iter); | |
if (!oldA) | |
break; | |
/* Remember to allocate the scratch byte before the name. */ | |
if (!poolAppendChar(&(newDtd->pool), XML_T('\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; | |
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. */ | |
hashTableIterInit(&iter, &(oldDtd->elementTypes)); | |
for (;;) { | |
int i; | |
ELEMENT_TYPE *newE; | |
const XML_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; | |
if (oldE->nDefaultAtts) { | |
newE->defaultAtts = (DEFAULT_ATTRIBUTE *) | |
ms->malloc_fcn(oldE->nDefaultAtts * sizeof(DEFAULT_ATTRIBUTE)); | |
if (!newE->defaultAtts) { | |
ms->free_fcn(newE); | |
return 0; | |
} | |
} | |
if (oldE->idAtt) | |
newE->idAtt = (ATTRIBUTE_ID *) | |
lookup(&(newDtd->attributeIds), oldE->idAtt->name, 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; | |
if (oldE->defaultAtts[i].value) { | |
newE->defaultAtts[i].value | |
= poolCopyString(&(newDtd->pool), oldE->defaultAtts[i].value); | |
if (!newE->defaultAtts[i].value) | |
return 0; | |
} | |
else | |
newE->defaultAtts[i].value = NULL; | |
} | |
} | |
/* Copy the entity tables. */ | |
if (!copyEntityTable(&(newDtd->generalEntities), | |
&(newDtd->pool), | |
&(oldDtd->generalEntities))) | |
return 0; | |
#ifdef XML_DTD | |
if (!copyEntityTable(&(newDtd->paramEntities), | |
&(newDtd->pool), | |
&(oldDtd->paramEntities))) | |
return 0; | |
newDtd->paramEntityRead = oldDtd->paramEntityRead; | |
#endif /* XML_DTD */ | |
newDtd->keepProcessing = oldDtd->keepProcessing; | |
newDtd->hasParamEntityRefs = oldDtd->hasParamEntityRefs; | |
newDtd->standalone = oldDtd->standalone; | |
/* Don't want deep copying for scaffolding */ | |
newDtd->in_eldecl = oldDtd->in_eldecl; | |
newDtd->scaffold = oldDtd->scaffold; | |
newDtd->contentStringLen = oldDtd->contentStringLen; | |
newDtd->scaffSize = oldDtd->scaffSize; | |
newDtd->scaffLevel = oldDtd->scaffLevel; | |
newDtd->scaffIndex = oldDtd->scaffIndex; | |
return 1; | |
} /* End dtdCopy */ | |
static int | |
copyEntityTable(HASH_TABLE *newTable, | |
STRING_POOL *newPool, | |
const HASH_TABLE *oldTable) | |
{ | |
HASH_TABLE_ITER iter; | |
const XML_Char *cachedOldBase = NULL; | |
const XML_Char *cachedNewBase = NULL; | |
hashTableIterInit(&iter, oldTable); | |
for (;;) { | |
ENTITY *newE; | |
const XML_Char *name; | |
const ENTITY *oldE = (ENTITY *)hashTableIterNext(&iter); | |
if (!oldE) | |
break; | |
name = poolCopyString(newPool, oldE->name); | |
if (!name) | |
return 0; | |
newE = (ENTITY *)lookup(newTable, name, sizeof(ENTITY)); | |
if (!newE) | |
return 0; | |
if (oldE->systemId) { | |
const XML_Char *tem = poolCopyString(newPool, oldE->systemId); | |
if (!tem) | |
return 0; | |
newE->systemId = tem; | |
if (oldE->base) { | |
if (oldE->base == cachedOldBase) | |
newE->base = cachedNewBase; | |
else { | |
cachedOldBase = oldE->base; | |
tem = poolCopyString(newPool, cachedOldBase); | |
if (!tem) | |
return 0; | |
cachedNewBase = newE->base = tem; | |
} | |
} | |
if (oldE->publicId) { | |
tem = poolCopyString(newPool, oldE->publicId); | |
if (!tem) | |
return 0; | |
newE->publicId = tem; | |
} | |
} | |
else { | |
const XML_Char *tem = poolCopyStringN(newPool, oldE->textPtr, | |
oldE->textLen); | |
if (!tem) | |
return 0; | |
newE->textPtr = tem; | |
newE->textLen = oldE->textLen; | |
} | |
if (oldE->notation) { | |
const XML_Char *tem = poolCopyString(newPool, oldE->notation); | |
if (!tem) | |
return 0; | |
newE->notation = tem; | |
} | |
newE->is_param = oldE->is_param; | |
newE->is_internal = oldE->is_internal; | |
} | |
return 1; | |
} | |
#define INIT_POWER 6 | |
static XML_Bool FASTCALL | |
keyeq(KEY s1, KEY s2) | |
{ | |
for (; *s1 == *s2; s1++, s2++) | |
if (*s1 == 0) | |
return XML_TRUE; | |
return XML_FALSE; | |
} | |
static unsigned long FASTCALL | |
hash(KEY s) | |
{ | |
unsigned long h = 0; | |
while (*s) | |
h = CHAR_HASH(h, *s++); | |
return h; | |
} | |
static NAMED * | |
lookup(HASH_TABLE *table, KEY name, size_t createSize) | |
{ | |
size_t i; | |
if (table->size == 0) { | |
size_t tsize; | |
if (!createSize) | |
return NULL; | |
table->power = INIT_POWER; | |
/* table->size is a power of 2 */ | |
table->size = (size_t)1 << INIT_POWER; | |
tsize = table->size * sizeof(NAMED *); | |
table->v = (NAMED **)table->mem->malloc_fcn(tsize); | |
if (!table->v) { | |
table->size = 0; | |
return NULL; | |
} | |
memset(table->v, 0, tsize); | |
i = hash(name) & ((unsigned long)table->size - 1); | |
} | |
else { | |
unsigned long h = hash(name); | |
unsigned long mask = (unsigned long)table->size - 1; | |
unsigned char step = 0; | |
i = h & mask; | |
while (table->v[i]) { | |
if (keyeq(name, table->v[i]->name)) | |
return table->v[i]; | |
if (!step) | |
step = PROBE_STEP(h, mask, table->power); | |
i < step ? (i += table->size - step) : (i -= step); | |
} | |
if (!createSize) | |
return NULL; | |
/* check for overflow (table is half full) */ | |
if (table->used >> (table->power - 1)) { | |
unsigned char newPower = table->power + 1; | |
size_t newSize = (size_t)1 << newPower; | |
unsigned long newMask = (unsigned long)newSize - 1; | |
size_t tsize = newSize * sizeof(NAMED *); | |
NAMED **newV = (NAMED **)table->mem->malloc_fcn(tsize); | |
if (!newV) | |
return NULL; | |
memset(newV, 0, tsize); | |
for (i = 0; i < table->size; i++) | |
if (table->v[i]) { | |
unsigned long newHash = hash(table->v[i]->name); | |
size_t j = newHash & newMask; | |
step = 0; | |
while (newV[j]) { | |
if (!step) | |
step = PROBE_STEP(newHash, newMask, newPower); | |
j < step ? (j += newSize - step) : (j -= step); | |
} | |
newV[j] = table->v[i]; | |
} | |
table->mem->free_fcn(table->v); | |
table->v = newV; | |
table->power = newPower; | |
table->size = newSize; | |
i = h & newMask; | |
step = 0; | |
while (table->v[i]) { | |
if (!step) | |
step = PROBE_STEP(h, newMask, newPower); | |
i < step ? (i += newSize - step) : (i -= step); | |
} | |
} | |
} | |
table->v[i] = (NAMED *)table->mem->malloc_fcn(createSize); | |
if (!table->v[i]) | |
return NULL; | |
memset(table->v[i], 0, createSize); | |
table->v[i]->name = name; | |
(table->used)++; | |
return table->v[i]; | |
} | |
static void FASTCALL | |
hashTableClear(HASH_TABLE *table) | |
{ | |
size_t i; | |
for (i = 0; i < table->size; i++) { | |
table->mem->free_fcn(table->v[i]); | |
table->v[i] = NULL; | |
} | |
table->used = 0; | |
} | |
static void FASTCALL | |
hashTableDestroy(HASH_TABLE *table) | |
{ | |
size_t i; | |
for (i = 0; i < table->size; i++) | |
table->mem->free_fcn(table->v[i]); | |
table->mem->free_fcn(table->v); | |
} | |
static void FASTCALL | |
hashTableInit(HASH_TABLE *p, const XML_Memory_Handling_Suite *ms) | |
{ | |
p->power = 0; | |
p->size = 0; | |
p->used = 0; | |
p->v = NULL; | |
p->mem = ms; | |
} | |
static void FASTCALL | |
hashTableIterInit(HASH_TABLE_ITER *iter, const HASH_TABLE *table) | |
{ | |
iter->p = table->v; | |
iter->end = iter->p + table->size; | |
} | |
static NAMED * FASTCALL | |
hashTableIterNext(HASH_TABLE_ITER *iter) | |
{ | |
while (iter->p != iter->end) { | |
NAMED *tem = *(iter->p)++; | |
if (tem) | |
return tem; | |
} | |
return NULL; | |
} | |
static void FASTCALL | |
poolInit(STRING_POOL *pool, const XML_Memory_Handling_Suite *ms) | |
{ | |
pool->blocks = NULL; | |
pool->freeBlocks = NULL; | |
pool->start = NULL; | |
pool->ptr = NULL; | |
pool->end = NULL; | |
pool->mem = ms; | |
} | |
static void FASTCALL | |
poolClear(STRING_POOL *pool) | |
{ | |
if (!pool->freeBlocks) | |
pool->freeBlocks = pool->blocks; | |
else { | |
BLOCK *p = pool->blocks; | |
while (p) { | |
BLOCK *tem = p->next; | |
p->next = pool->freeBlocks; | |
pool->freeBlocks = p; | |
p = tem; | |
} | |
} | |
pool->blocks = NULL; | |
pool->start = NULL; | |
pool->ptr = NULL; | |
pool->end = NULL; | |
} | |
static void FASTCALL | |
poolDestroy(STRING_POOL *pool) | |
{ | |
BLOCK *p = pool->blocks; | |
while (p) { | |
BLOCK *tem = p->next; | |
pool->mem->free_fcn(p); | |
p = tem; | |
} | |
p = pool->freeBlocks; | |
while (p) { | |
BLOCK *tem = p->next; | |
pool->mem->free_fcn(p); | |
p = tem; | |
} | |
} | |
static XML_Char * | |
poolAppend(STRING_POOL *pool, const ENCODING *enc, | |
const char *ptr, const char *end) | |
{ | |
if (!pool->ptr && !poolGrow(pool)) | |
return NULL; | |
for (;;) { | |
XmlConvert(enc, &ptr, end, (ICHAR **)&(pool->ptr), (ICHAR *)pool->end); | |
if (ptr == end) | |
break; | |
if (!poolGrow(pool)) | |
return NULL; | |
} | |
return pool->start; | |
} | |
static const XML_Char * FASTCALL | |
poolCopyString(STRING_POOL *pool, const XML_Char *s) | |
{ | |
do { | |
if (!poolAppendChar(pool, *s)) | |
return NULL; | |
} while (*s++); | |
s = pool->start; | |
poolFinish(pool); | |
return s; | |
} | |
static const XML_Char * | |
poolCopyStringN(STRING_POOL *pool, const XML_Char *s, int n) | |
{ | |
if (!pool->ptr && !poolGrow(pool)) | |
return NULL; | |
for (; n > 0; --n, s++) { | |
if (!poolAppendChar(pool, *s)) | |
return NULL; | |
} | |
s = pool->start; | |
poolFinish(pool); | |
return s; | |
} | |
static const XML_Char * FASTCALL | |
poolAppendString(STRING_POOL *pool, const XML_Char *s) | |
{ | |
while (*s) { | |
if (!poolAppendChar(pool, *s)) | |
return NULL; | |
s++; | |
} | |
return pool->start; | |
} | |
static XML_Char * | |
poolStoreString(STRING_POOL *pool, const ENCODING *enc, | |
const char *ptr, const char *end) | |
{ | |
if (!poolAppend(pool, enc, ptr, end)) | |
return NULL; | |
if (pool->ptr == pool->end && !poolGrow(pool)) | |
return NULL; | |
*(pool->ptr)++ = 0; | |
return pool->start; | |
} | |
static XML_Bool FASTCALL | |
poolGrow(STRING_POOL *pool) | |
{ | |
if (pool->freeBlocks) { | |
if (pool->start == 0) { | |
pool->blocks = pool->freeBlocks; | |
pool->freeBlocks = pool->freeBlocks->next; | |
pool->blocks->next = NULL; | |
pool->start = pool->blocks->s; | |
pool->end = pool->start + pool->blocks->size; | |
pool->ptr = pool->start; | |
return XML_TRUE; | |
} | |
if (pool->end - pool->start < pool->freeBlocks->size) { | |
BLOCK *tem = pool->freeBlocks->next; | |
pool->freeBlocks->next = pool->blocks; | |
pool->blocks = pool->freeBlocks; | |
pool->freeBlocks = tem; | |
memcpy(pool->blocks->s, pool->start, | |
(pool->end - pool->start) * sizeof(XML_Char)); | |
pool->ptr = pool->blocks->s + (pool->ptr - pool->start); | |
pool->start = pool->blocks->s; | |
pool->end = pool->start + pool->blocks->size; | |
return XML_TRUE; | |
} | |
} | |
if (pool->blocks && pool->start == pool->blocks->s) { | |
int blockSize = (int)(pool->end - pool->start)*2; | |
pool->blocks = (BLOCK *) | |
pool->mem->realloc_fcn(pool->blocks, | |
(offsetof(BLOCK, s) | |
+ blockSize * sizeof(XML_Char))); | |
if (pool->blocks == NULL) | |
return XML_FALSE; | |
pool->blocks->size = blockSize; | |
pool->ptr = pool->blocks->s + (pool->ptr - pool->start); | |
pool->start = pool->blocks->s; | |
pool->end = pool->start + blockSize; | |
} | |
else { | |
BLOCK *tem; | |
int blockSize = (int)(pool->end - pool->start); | |
if (blockSize < INIT_BLOCK_SIZE) | |
blockSize = INIT_BLOCK_SIZE; | |
else | |
blockSize *= 2; | |
tem = (BLOCK *)pool->mem->malloc_fcn(offsetof(BLOCK, s) | |
+ blockSize * sizeof(XML_Char)); | |
if (!tem) | |
return XML_FALSE; | |
tem->size = blockSize; | |
tem->next = pool->blocks; | |
pool->blocks = tem; | |
if (pool->ptr != pool->start) | |
memcpy(tem->s, pool->start, | |
(pool->ptr - pool->start) * sizeof(XML_Char)); | |
pool->ptr = tem->s + (pool->ptr - pool->start); | |
pool->start = tem->s; | |
pool->end = tem->s + blockSize; | |
} | |
return XML_TRUE; | |
} | |
static int FASTCALL | |
nextScaffoldPart(XML_Parser parser) | |
{ | |
DTD * const dtd = _dtd; /* save one level of indirection */ | |
CONTENT_SCAFFOLD * me; | |
int next; | |
if (!dtd->scaffIndex) { | |
dtd->scaffIndex = (int *)MALLOC(groupSize * sizeof(int)); | |
if (!dtd->scaffIndex) | |
return -1; | |
dtd->scaffIndex[0] = 0; | |
} | |
if (dtd->scaffCount >= dtd->scaffSize) { | |
CONTENT_SCAFFOLD *temp; | |
if (dtd->scaffold) { | |
temp = (CONTENT_SCAFFOLD *) | |
REALLOC(dtd->scaffold, dtd->scaffSize * 2 * sizeof(CONTENT_SCAFFOLD)); | |
if (temp == NULL) | |
return -1; | |
dtd->scaffSize *= 2; | |
} | |
else { | |
temp = (CONTENT_SCAFFOLD *)MALLOC(INIT_SCAFFOLD_ELEMENTS | |
* sizeof(CONTENT_SCAFFOLD)); | |
if (temp == NULL) | |
return -1; | |
dtd->scaffSize = INIT_SCAFFOLD_ELEMENTS; | |
} | |
dtd->scaffold = temp; | |
} | |
next = dtd->scaffCount++; | |
me = &dtd->scaffold[next]; | |
if (dtd->scaffLevel) { | |
CONTENT_SCAFFOLD *parent = &dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel-1]]; | |
if (parent->lastchild) { | |
dtd->scaffold[parent->lastchild].nextsib = next; | |
} | |
if (!parent->childcnt) | |
parent->firstchild = next; | |
parent->lastchild = next; | |
parent->childcnt++; | |
} | |
me->firstchild = me->lastchild = me->childcnt = me->nextsib = 0; | |
return next; | |
} | |
static void | |
build_node(XML_Parser parser, | |
int src_node, | |
XML_Content *dest, | |
XML_Content **contpos, | |
XML_Char **strpos) | |
{ | |
DTD * const dtd = _dtd; /* save one level of indirection */ | |
dest->type = dtd->scaffold[src_node].type; | |
dest->quant = dtd->scaffold[src_node].quant; | |
if (dest->type == XML_CTYPE_NAME) { | |
const XML_Char *src; | |
dest->name = *strpos; | |
src = dtd->scaffold[src_node].name; | |
for (;;) { | |
*(*strpos)++ = *src; | |
if (!*src) | |
break; | |
src++; | |
} | |
dest->numchildren = 0; | |
dest->children = NULL; | |
} | |
else { | |
unsigned int i; | |
int cn; | |
dest->numchildren = dtd->scaffold[src_node].childcnt; | |
dest->children = *contpos; | |
*contpos += dest->numchildren; | |
for (i = 0, cn = dtd->scaffold[src_node].firstchild; | |
i < dest->numchildren; | |
i++, cn = dtd->scaffold[cn].nextsib) { | |
build_node(parser, cn, &(dest->children[i]), contpos, strpos); | |
} | |
dest->name = NULL; | |
} | |
} | |
static XML_Content * | |
build_model (XML_Parser parser) | |
{ | |
DTD * const dtd = _dtd; /* save one level of indirection */ | |
XML_Content *ret; | |
XML_Content *cpos; | |
XML_Char * str; | |
int allocsize = (dtd->scaffCount * sizeof(XML_Content) | |
+ (dtd->contentStringLen * sizeof(XML_Char))); | |
ret = (XML_Content *)MALLOC(allocsize); | |
if (!ret) | |
return NULL; | |
str = (XML_Char *) (&ret[dtd->scaffCount]); | |
cpos = &ret[1]; | |
build_node(parser, 0, ret, &cpos, &str); | |
return ret; | |
} | |
static ELEMENT_TYPE * | |
getElementType(XML_Parser parser, | |
const ENCODING *enc, | |
const char *ptr, | |
const char *end) | |
{ | |
DTD * const dtd = _dtd; /* save one level of indirection */ | |
const XML_Char *name = poolStoreString(&dtd->pool, enc, ptr, end); | |
ELEMENT_TYPE *ret; | |
if (!name) | |
return NULL; | |
ret = (ELEMENT_TYPE *) lookup(&dtd->elementTypes, name, sizeof(ELEMENT_TYPE)); | |
if (!ret) | |
return NULL; | |
if (ret->name != name) | |
poolDiscard(&dtd->pool); | |
else { | |
poolFinish(&dtd->pool); | |
if (!setElementTypePrefix(parser, ret)) | |
return NULL; | |
} | |
return ret; | |
} |