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