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