| /* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd |
| See the file COPYING for copying permission. |
| */ |
| |
| #include <stddef.h> |
| #include <string.h> /* memset(), memcpy() */ |
| #include <assert.h> |
| |
| #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(__WATCOMC__) |
| #include "watcomconfig.h" |
| #elif defined(HAVE_EXPAT_CONFIG_H) |
| #include <expat_config.h> |
| #endif /* ndef COMPILED_FROM_DSP */ |
| |
| #include "ascii.h" |
| #include "expat.h" |
| |
| #ifdef XML_UNICODE |
| #define XML_ENCODE_MAX XML_UTF16_ENCODE_MAX |
| #define XmlConvert XmlUtf16Convert |
| #define XmlGetInternalEncoding XmlGetUtf16InternalEncoding |
| #define XmlGetInternalEncodingNS XmlGetUtf16InternalEncodingNS |
| #define XmlEncode XmlUtf16Encode |
| /* Using pointer subtraction to convert to integer type. */ |
| #define MUST_CONVERT(enc, s) (!(enc)->isUtf16 || (((char *)(s) - (char *)NULL) & 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[] = { |
| ASCII_x, ASCII_m, ASCII_l, ASCII_EQUALS, ASCII_h, ASCII_t, ASCII_t, ASCII_p, |
| ASCII_COLON, ASCII_SLASH, ASCII_SLASH, ASCII_w, ASCII_w, ASCII_w, |
| ASCII_PERIOD, ASCII_w, ASCII_3, ASCII_PERIOD, ASCII_o, ASCII_r, ASCII_g, |
| ASCII_SLASH, ASCII_X, ASCII_M, ASCII_L, ASCII_SLASH, ASCII_1, ASCII_9, |
| ASCII_9, ASCII_8, ASCII_SLASH, ASCII_n, ASCII_a, ASCII_m, ASCII_e, |
| ASCII_s, ASCII_p, ASCII_a, ASCII_c, ASCII_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 = ASCII_EXCL; |
| 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; |
| } |
| } |
| } |
| |
| 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 |
| #ifdef XML_LARGE_SIZE |
| {XML_FEATURE_LARGE_SIZE, XML_L("XML_LARGE_SIZE"), 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: |
| { |
| XML_CharacterDataHandler charDataHandler = characterDataHandler; |
| if (charDataHandler) { |
| if (MUST_CONVERT(enc, s)) { |
| for (;;) { |
| ICHAR *dataPtr = (ICHAR *)dataBuf; |
| XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd); |
| *eventEndPP = s; |
| charDataHandler(handlerArg, dataBuf, |
| (int)(dataPtr - (ICHAR *)dataBuf)); |
| if (s == next) |
| break; |
| *eventPP = s; |
| } |
| } |
| else |
| charDataHandler(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); |
| 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(ASCII_COLON)) |
| ; |
| 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(ASCII_COLON)) |
| ; |
| } |
| 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[] = { |
| ASCII_h, ASCII_t, ASCII_t, ASCII_p, ASCII_COLON, ASCII_SLASH, ASCII_SLASH, |
| ASCII_w, ASCII_w, ASCII_w, ASCII_PERIOD, ASCII_w, ASCII_3, ASCII_PERIOD, |
| ASCII_o, ASCII_r, ASCII_g, ASCII_SLASH, ASCII_X, ASCII_M, ASCII_L, |
| ASCII_SLASH, ASCII_1, ASCII_9, ASCII_9, ASCII_8, ASCII_SLASH, |
| ASCII_n, ASCII_a, ASCII_m, ASCII_e, ASCII_s, ASCII_p, ASCII_a, ASCII_c, |
| ASCII_e, '\0' |
| }; |
| static const int xmlLen = |
| (int)sizeof(xmlNamespace)/sizeof(XML_Char) - 1; |
| static const XML_Char xmlnsNamespace[] = { |
| ASCII_h, ASCII_t, ASCII_t, ASCII_p, ASCII_COLON, ASCII_SLASH, ASCII_SLASH, |
| ASCII_w, ASCII_w, ASCII_w, ASCII_PERIOD, ASCII_w, ASCII_3, ASCII_PERIOD, |
| ASCII_o, ASCII_r, ASCII_g, ASCII_SLASH, ASCII_2, ASCII_0, ASCII_0, |
| ASCII_0, ASCII_SLASH, ASCII_x, ASCII_m, ASCII_l, ASCII_n, ASCII_s, |
| ASCII_SLASH, '\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(ASCII_x) |
| && prefix->name[1] == XML_T(ASCII_m) |
| && prefix->name[2] == XML_T(ASCII_l)) { |
| |
| /* Not allowed to bind xmlns */ |
| if (prefix->name[3] == XML_T(ASCII_n) |
| && prefix->name[4] == XML_T(ASCII_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; |
| |