9687041b14
git-svn-id: http://mc-server.googlecode.com/svn/trunk@1375 0a769ca7-a7f5-676a-18bf-c427514a06d6
6295 lines
190 KiB
C
6295 lines
190 KiB
C
/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
|
|
See the file COPYING for copying permission.
|
|
*/
|
|
|
|
#include <stddef.h>
|
|
#include <string.h> /* memset(), memcpy() */
|
|
#include <assert.h>
|
|
|
|
#define XML_BUILDING_EXPAT 1
|
|
|
|
// 2013_04_09 _X: Quick and dirty "fix" for expat compilation under Linux:
|
|
#define HAVE_MEMMOVE
|
|
|
|
#ifdef COMPILED_FROM_DSP
|
|
#include "winconfig.h"
|
|
#elif defined(MACOS_CLASSIC)
|
|
#include "macconfig.h"
|
|
#elif defined(__amigaos4__)
|
|
#include "amigaconfig.h"
|
|
#elif defined(__WATCOMC__)
|
|
#include "watcomconfig.h"
|
|
#elif defined(HAVE_EXPAT_CONFIG_H)
|
|
#include <expat_config.h>
|
|
#endif /* ndef COMPILED_FROM_DSP */
|
|
|
|
#include "ascii.h"
|
|
#include "expat.h"
|
|
|
|
#ifdef XML_UNICODE
|
|
#define XML_ENCODE_MAX XML_UTF16_ENCODE_MAX
|
|
#define XmlConvert XmlUtf16Convert
|
|
#define XmlGetInternalEncoding XmlGetUtf16InternalEncoding
|
|
#define XmlGetInternalEncodingNS XmlGetUtf16InternalEncodingNS
|
|
#define XmlEncode XmlUtf16Encode
|
|
/* Using pointer subtraction to convert to integer type. */
|
|
#define MUST_CONVERT(enc, s) (!(enc)->isUtf16 || (((char *)(s) - (char *)NULL) & 1))
|
|
typedef unsigned short ICHAR;
|
|
#else
|
|
#define XML_ENCODE_MAX XML_UTF8_ENCODE_MAX
|
|
#define XmlConvert XmlUtf8Convert
|
|
#define XmlGetInternalEncoding XmlGetUtf8InternalEncoding
|
|
#define XmlGetInternalEncodingNS XmlGetUtf8InternalEncodingNS
|
|
#define XmlEncode XmlUtf8Encode
|
|
#define MUST_CONVERT(enc, s) (!(enc)->isUtf8)
|
|
typedef char ICHAR;
|
|
#endif
|
|
|
|
|
|
#ifndef XML_NS
|
|
|
|
#define XmlInitEncodingNS XmlInitEncoding
|
|
#define XmlInitUnknownEncodingNS XmlInitUnknownEncoding
|
|
#undef XmlGetInternalEncodingNS
|
|
#define XmlGetInternalEncodingNS XmlGetInternalEncoding
|
|
#define XmlParseXmlDeclNS XmlParseXmlDecl
|
|
|
|
#endif
|
|
|
|
#ifdef XML_UNICODE
|
|
|
|
#ifdef XML_UNICODE_WCHAR_T
|
|
#define XML_T(x) (const wchar_t)x
|
|
#define XML_L(x) L ## x
|
|
#else
|
|
#define XML_T(x) (const unsigned short)x
|
|
#define XML_L(x) x
|
|
#endif
|
|
|
|
#else
|
|
|
|
#define XML_T(x) x
|
|
#define XML_L(x) x
|
|
|
|
#endif
|
|
|
|
/* Round up n to be a multiple of sz, where sz is a power of 2. */
|
|
#define ROUND_UP(n, sz) (((n) + ((sz) - 1)) & ~((sz) - 1))
|
|
|
|
/* Handle the case where memmove() doesn't exist. */
|
|
#ifndef HAVE_MEMMOVE
|
|
#ifdef HAVE_BCOPY
|
|
#define memmove(d,s,l) bcopy((s),(d),(l))
|
|
#else
|
|
#error memmove does not exist on this platform, nor is a substitute available
|
|
#endif /* HAVE_BCOPY */
|
|
#endif /* HAVE_MEMMOVE */
|
|
|
|
#include "internal.h"
|
|
#include "xmltok.h"
|
|
#include "xmlrole.h"
|
|
|
|
typedef const XML_Char *KEY;
|
|
|
|
typedef struct {
|
|
KEY name;
|
|
} NAMED;
|
|
|
|
typedef struct {
|
|
NAMED **v;
|
|
unsigned char power;
|
|
size_t size;
|
|
size_t used;
|
|
const XML_Memory_Handling_Suite *mem;
|
|
} HASH_TABLE;
|
|
|
|
/* Basic character hash algorithm, taken from Python's string hash:
|
|
h = h * 1000003 ^ character, the constant being a prime number.
|
|
|
|
*/
|
|
#ifdef XML_UNICODE
|
|
#define CHAR_HASH(h, c) \
|
|
(((h) * 0xF4243) ^ (unsigned short)(c))
|
|
#else
|
|
#define CHAR_HASH(h, c) \
|
|
(((h) * 0xF4243) ^ (unsigned char)(c))
|
|
#endif
|
|
|
|
/* For probing (after a collision) we need a step size relative prime
|
|
to the hash table size, which is a power of 2. We use double-hashing,
|
|
since we can calculate a second hash value cheaply by taking those bits
|
|
of the first hash value that were discarded (masked out) when the table
|
|
index was calculated: index = hash & mask, where mask = table->size - 1.
|
|
We limit the maximum step size to table->size / 4 (mask >> 2) and make
|
|
it odd, since odd numbers are always relative prime to a power of 2.
|
|
*/
|
|
#define SECOND_HASH(hash, mask, power) \
|
|
((((hash) & ~(mask)) >> ((power) - 1)) & ((mask) >> 2))
|
|
#define PROBE_STEP(hash, mask, power) \
|
|
((unsigned char)((SECOND_HASH(hash, mask, power)) | 1))
|
|
|
|
typedef struct {
|
|
NAMED **p;
|
|
NAMED **end;
|
|
} HASH_TABLE_ITER;
|
|
|
|
#define INIT_TAG_BUF_SIZE 32 /* must be a multiple of sizeof(XML_Char) */
|
|
#define INIT_DATA_BUF_SIZE 1024
|
|
#define INIT_ATTS_SIZE 16
|
|
#define INIT_ATTS_VERSION 0xFFFFFFFF
|
|
#define INIT_BLOCK_SIZE 1024
|
|
#define INIT_BUFFER_SIZE 1024
|
|
|
|
#define EXPAND_SPARE 24
|
|
|
|
typedef struct binding {
|
|
struct prefix *prefix;
|
|
struct binding *nextTagBinding;
|
|
struct binding *prevPrefixBinding;
|
|
const struct attribute_id *attId;
|
|
XML_Char *uri;
|
|
int uriLen;
|
|
int uriAlloc;
|
|
} BINDING;
|
|
|
|
typedef struct prefix {
|
|
const XML_Char *name;
|
|
BINDING *binding;
|
|
} PREFIX;
|
|
|
|
typedef struct {
|
|
const XML_Char *str;
|
|
const XML_Char *localPart;
|
|
const XML_Char *prefix;
|
|
int strLen;
|
|
int uriLen;
|
|
int prefixLen;
|
|
} TAG_NAME;
|
|
|
|
/* TAG represents an open element.
|
|
The name of the element is stored in both the document and API
|
|
encodings. The memory buffer 'buf' is a separately-allocated
|
|
memory area which stores the name. During the XML_Parse()/
|
|
XMLParseBuffer() when the element is open, the memory for the 'raw'
|
|
version of the name (in the document encoding) is shared with the
|
|
document buffer. If the element is open across calls to
|
|
XML_Parse()/XML_ParseBuffer(), the buffer is re-allocated to
|
|
contain the 'raw' name as well.
|
|
|
|
A parser re-uses these structures, maintaining a list of allocated
|
|
TAG objects in a free list.
|
|
*/
|
|
typedef struct tag {
|
|
struct tag *parent; /* parent of this element */
|
|
const char *rawName; /* tagName in the original encoding */
|
|
int rawNameLength;
|
|
TAG_NAME name; /* tagName in the API encoding */
|
|
char *buf; /* buffer for name components */
|
|
char *bufEnd; /* end of the buffer */
|
|
BINDING *bindings;
|
|
} TAG;
|
|
|
|
typedef struct {
|
|
const XML_Char *name;
|
|
const XML_Char *textPtr;
|
|
int textLen; /* length in XML_Chars */
|
|
int processed; /* # of processed bytes - when suspended */
|
|
const XML_Char *systemId;
|
|
const XML_Char *base;
|
|
const XML_Char *publicId;
|
|
const XML_Char *notation;
|
|
XML_Bool open;
|
|
XML_Bool is_param;
|
|
XML_Bool is_internal; /* true if declared in internal subset outside PE */
|
|
} ENTITY;
|
|
|
|
typedef struct {
|
|
enum XML_Content_Type type;
|
|
enum XML_Content_Quant quant;
|
|
const XML_Char * name;
|
|
int firstchild;
|
|
int lastchild;
|
|
int childcnt;
|
|
int nextsib;
|
|
} CONTENT_SCAFFOLD;
|
|
|
|
#define INIT_SCAFFOLD_ELEMENTS 32
|
|
|
|
typedef struct block {
|
|
struct block *next;
|
|
int size;
|
|
XML_Char s[1];
|
|
} BLOCK;
|
|
|
|
typedef struct {
|
|
BLOCK *blocks;
|
|
BLOCK *freeBlocks;
|
|
const XML_Char *end;
|
|
XML_Char *ptr;
|
|
XML_Char *start;
|
|
const XML_Memory_Handling_Suite *mem;
|
|
} STRING_POOL;
|
|
|
|
/* The XML_Char before the name is used to determine whether
|
|
an attribute has been specified. */
|
|
typedef struct attribute_id {
|
|
XML_Char *name;
|
|
PREFIX *prefix;
|
|
XML_Bool maybeTokenized;
|
|
XML_Bool xmlns;
|
|
} ATTRIBUTE_ID;
|
|
|
|
typedef struct {
|
|
const ATTRIBUTE_ID *id;
|
|
XML_Bool isCdata;
|
|
const XML_Char *value;
|
|
} DEFAULT_ATTRIBUTE;
|
|
|
|
typedef struct {
|
|
unsigned long version;
|
|
unsigned long hash;
|
|
const XML_Char *uriName;
|
|
} NS_ATT;
|
|
|
|
typedef struct {
|
|
const XML_Char *name;
|
|
PREFIX *prefix;
|
|
const ATTRIBUTE_ID *idAtt;
|
|
int nDefaultAtts;
|
|
int allocDefaultAtts;
|
|
DEFAULT_ATTRIBUTE *defaultAtts;
|
|
} ELEMENT_TYPE;
|
|
|
|
typedef struct {
|
|
HASH_TABLE generalEntities;
|
|
HASH_TABLE elementTypes;
|
|
HASH_TABLE attributeIds;
|
|
HASH_TABLE prefixes;
|
|
STRING_POOL pool;
|
|
STRING_POOL entityValuePool;
|
|
/* false once a parameter entity reference has been skipped */
|
|
XML_Bool keepProcessing;
|
|
/* true once an internal or external PE reference has been encountered;
|
|
this includes the reference to an external subset */
|
|
XML_Bool hasParamEntityRefs;
|
|
XML_Bool standalone;
|
|
#ifdef XML_DTD
|
|
/* indicates if external PE has been read */
|
|
XML_Bool paramEntityRead;
|
|
HASH_TABLE paramEntities;
|
|
#endif /* XML_DTD */
|
|
PREFIX defaultPrefix;
|
|
/* === scaffolding for building content model === */
|
|
XML_Bool in_eldecl;
|
|
CONTENT_SCAFFOLD *scaffold;
|
|
unsigned contentStringLen;
|
|
unsigned scaffSize;
|
|
unsigned scaffCount;
|
|
int scaffLevel;
|
|
int *scaffIndex;
|
|
} DTD;
|
|
|
|
typedef struct open_internal_entity {
|
|
const char *internalEventPtr;
|
|
const char *internalEventEndPtr;
|
|
struct open_internal_entity *next;
|
|
ENTITY *entity;
|
|
int startTagLevel;
|
|
XML_Bool betweenDecl; /* WFC: PE Between Declarations */
|
|
} OPEN_INTERNAL_ENTITY;
|
|
|
|
typedef enum XML_Error PTRCALL Processor(XML_Parser parser,
|
|
const char *start,
|
|
const char *end,
|
|
const char **endPtr);
|
|
|
|
static Processor prologProcessor;
|
|
static Processor prologInitProcessor;
|
|
static Processor contentProcessor;
|
|
static Processor cdataSectionProcessor;
|
|
#ifdef XML_DTD
|
|
static Processor ignoreSectionProcessor;
|
|
static Processor externalParEntProcessor;
|
|
static Processor externalParEntInitProcessor;
|
|
static Processor entityValueProcessor;
|
|
static Processor entityValueInitProcessor;
|
|
#endif /* XML_DTD */
|
|
static Processor epilogProcessor;
|
|
static Processor errorProcessor;
|
|
static Processor externalEntityInitProcessor;
|
|
static Processor externalEntityInitProcessor2;
|
|
static Processor externalEntityInitProcessor3;
|
|
static Processor externalEntityContentProcessor;
|
|
static Processor internalEntityProcessor;
|
|
|
|
static enum XML_Error
|
|
handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName);
|
|
static enum XML_Error
|
|
processXmlDecl(XML_Parser parser, int isGeneralTextEntity,
|
|
const char *s, const char *next);
|
|
static enum XML_Error
|
|
initializeEncoding(XML_Parser parser);
|
|
static enum XML_Error
|
|
doProlog(XML_Parser parser, const ENCODING *enc, const char *s,
|
|
const char *end, int tok, const char *next, const char **nextPtr,
|
|
XML_Bool haveMore);
|
|
static enum XML_Error
|
|
processInternalEntity(XML_Parser parser, ENTITY *entity,
|
|
XML_Bool betweenDecl);
|
|
static enum XML_Error
|
|
doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
|
|
const char *start, const char *end, const char **endPtr,
|
|
XML_Bool haveMore);
|
|
static enum XML_Error
|
|
doCdataSection(XML_Parser parser, const ENCODING *, const char **startPtr,
|
|
const char *end, const char **nextPtr, XML_Bool haveMore);
|
|
#ifdef XML_DTD
|
|
static enum XML_Error
|
|
doIgnoreSection(XML_Parser parser, const ENCODING *, const char **startPtr,
|
|
const char *end, const char **nextPtr, XML_Bool haveMore);
|
|
#endif /* XML_DTD */
|
|
|
|
static enum XML_Error
|
|
storeAtts(XML_Parser parser, const ENCODING *, const char *s,
|
|
TAG_NAME *tagNamePtr, BINDING **bindingsPtr);
|
|
static enum XML_Error
|
|
addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
|
|
const XML_Char *uri, BINDING **bindingsPtr);
|
|
static int
|
|
defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *, XML_Bool isCdata,
|
|
XML_Bool isId, const XML_Char *dfltValue, XML_Parser parser);
|
|
static enum XML_Error
|
|
storeAttributeValue(XML_Parser parser, const ENCODING *, XML_Bool isCdata,
|
|
const char *, const char *, STRING_POOL *);
|
|
static enum XML_Error
|
|
appendAttributeValue(XML_Parser parser, const ENCODING *, XML_Bool isCdata,
|
|
const char *, const char *, STRING_POOL *);
|
|
static ATTRIBUTE_ID *
|
|
getAttributeId(XML_Parser parser, const ENCODING *enc, const char *start,
|
|
const char *end);
|
|
static int
|
|
setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *);
|
|
static enum XML_Error
|
|
storeEntityValue(XML_Parser parser, const ENCODING *enc, const char *start,
|
|
const char *end);
|
|
static int
|
|
reportProcessingInstruction(XML_Parser parser, const ENCODING *enc,
|
|
const char *start, const char *end);
|
|
static int
|
|
reportComment(XML_Parser parser, const ENCODING *enc, const char *start,
|
|
const char *end);
|
|
static void
|
|
reportDefault(XML_Parser parser, const ENCODING *enc, const char *start,
|
|
const char *end);
|
|
|
|
static const XML_Char * getContext(XML_Parser parser);
|
|
static XML_Bool
|
|
setContext(XML_Parser parser, const XML_Char *context);
|
|
|
|
static void FASTCALL normalizePublicId(XML_Char *s);
|
|
|
|
static DTD * dtdCreate(const XML_Memory_Handling_Suite *ms);
|
|
/* do not call if parentParser != NULL */
|
|
static void dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms);
|
|
static void
|
|
dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms);
|
|
static int
|
|
dtdCopy(DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms);
|
|
static int
|
|
copyEntityTable(HASH_TABLE *, STRING_POOL *, const HASH_TABLE *);
|
|
|
|
static NAMED *
|
|
lookup(HASH_TABLE *table, KEY name, size_t createSize);
|
|
static void FASTCALL
|
|
hashTableInit(HASH_TABLE *, const XML_Memory_Handling_Suite *ms);
|
|
static void FASTCALL hashTableClear(HASH_TABLE *);
|
|
static void FASTCALL hashTableDestroy(HASH_TABLE *);
|
|
static void FASTCALL
|
|
hashTableIterInit(HASH_TABLE_ITER *, const HASH_TABLE *);
|
|
static NAMED * FASTCALL hashTableIterNext(HASH_TABLE_ITER *);
|
|
|
|
static void FASTCALL
|
|
poolInit(STRING_POOL *, const XML_Memory_Handling_Suite *ms);
|
|
static void FASTCALL poolClear(STRING_POOL *);
|
|
static void FASTCALL poolDestroy(STRING_POOL *);
|
|
static XML_Char *
|
|
poolAppend(STRING_POOL *pool, const ENCODING *enc,
|
|
const char *ptr, const char *end);
|
|
static XML_Char *
|
|
poolStoreString(STRING_POOL *pool, const ENCODING *enc,
|
|
const char *ptr, const char *end);
|
|
static XML_Bool FASTCALL poolGrow(STRING_POOL *pool);
|
|
static const XML_Char * FASTCALL
|
|
poolCopyString(STRING_POOL *pool, const XML_Char *s);
|
|
static const XML_Char *
|
|
poolCopyStringN(STRING_POOL *pool, const XML_Char *s, int n);
|
|
static const XML_Char * FASTCALL
|
|
poolAppendString(STRING_POOL *pool, const XML_Char *s);
|
|
|
|
static int FASTCALL nextScaffoldPart(XML_Parser parser);
|
|
static XML_Content * build_model(XML_Parser parser);
|
|
static ELEMENT_TYPE *
|
|
getElementType(XML_Parser parser, const ENCODING *enc,
|
|
const char *ptr, const char *end);
|
|
|
|
static XML_Parser
|
|
parserCreate(const XML_Char *encodingName,
|
|
const XML_Memory_Handling_Suite *memsuite,
|
|
const XML_Char *nameSep,
|
|
DTD *dtd);
|
|
static void
|
|
parserInit(XML_Parser parser, const XML_Char *encodingName);
|
|
|
|
#define poolStart(pool) ((pool)->start)
|
|
#define poolEnd(pool) ((pool)->ptr)
|
|
#define poolLength(pool) ((pool)->ptr - (pool)->start)
|
|
#define poolChop(pool) ((void)--(pool->ptr))
|
|
#define poolLastChar(pool) (((pool)->ptr)[-1])
|
|
#define poolDiscard(pool) ((pool)->ptr = (pool)->start)
|
|
#define poolFinish(pool) ((pool)->start = (pool)->ptr)
|
|
#define poolAppendChar(pool, c) \
|
|
(((pool)->ptr == (pool)->end && !poolGrow(pool)) \
|
|
? 0 \
|
|
: ((*((pool)->ptr)++ = c), 1))
|
|
|
|
struct XML_ParserStruct {
|
|
/* The first member must be userData so that the XML_GetUserData
|
|
macro works. */
|
|
void *m_userData;
|
|
void *m_handlerArg;
|
|
char *m_buffer;
|
|
const XML_Memory_Handling_Suite m_mem;
|
|
/* first character to be parsed */
|
|
const char *m_bufferPtr;
|
|
/* past last character to be parsed */
|
|
char *m_bufferEnd;
|
|
/* allocated end of buffer */
|
|
const char *m_bufferLim;
|
|
XML_Index m_parseEndByteIndex;
|
|
const char *m_parseEndPtr;
|
|
XML_Char *m_dataBuf;
|
|
XML_Char *m_dataBufEnd;
|
|
XML_StartElementHandler m_startElementHandler;
|
|
XML_EndElementHandler m_endElementHandler;
|
|
XML_CharacterDataHandler m_characterDataHandler;
|
|
XML_ProcessingInstructionHandler m_processingInstructionHandler;
|
|
XML_CommentHandler m_commentHandler;
|
|
XML_StartCdataSectionHandler m_startCdataSectionHandler;
|
|
XML_EndCdataSectionHandler m_endCdataSectionHandler;
|
|
XML_DefaultHandler m_defaultHandler;
|
|
XML_StartDoctypeDeclHandler m_startDoctypeDeclHandler;
|
|
XML_EndDoctypeDeclHandler m_endDoctypeDeclHandler;
|
|
XML_UnparsedEntityDeclHandler m_unparsedEntityDeclHandler;
|
|
XML_NotationDeclHandler m_notationDeclHandler;
|
|
XML_StartNamespaceDeclHandler m_startNamespaceDeclHandler;
|
|
XML_EndNamespaceDeclHandler m_endNamespaceDeclHandler;
|
|
XML_NotStandaloneHandler m_notStandaloneHandler;
|
|
XML_ExternalEntityRefHandler m_externalEntityRefHandler;
|
|
XML_Parser m_externalEntityRefHandlerArg;
|
|
XML_SkippedEntityHandler m_skippedEntityHandler;
|
|
XML_UnknownEncodingHandler m_unknownEncodingHandler;
|
|
XML_ElementDeclHandler m_elementDeclHandler;
|
|
XML_AttlistDeclHandler m_attlistDeclHandler;
|
|
XML_EntityDeclHandler m_entityDeclHandler;
|
|
XML_XmlDeclHandler m_xmlDeclHandler;
|
|
const ENCODING *m_encoding;
|
|
INIT_ENCODING m_initEncoding;
|
|
const ENCODING *m_internalEncoding;
|
|
const XML_Char *m_protocolEncodingName;
|
|
XML_Bool m_ns;
|
|
XML_Bool m_ns_triplets;
|
|
void *m_unknownEncodingMem;
|
|
void *m_unknownEncodingData;
|
|
void *m_unknownEncodingHandlerData;
|
|
void (XMLCALL *m_unknownEncodingRelease)(void *);
|
|
PROLOG_STATE m_prologState;
|
|
Processor *m_processor;
|
|
enum XML_Error m_errorCode;
|
|
const char *m_eventPtr;
|
|
const char *m_eventEndPtr;
|
|
const char *m_positionPtr;
|
|
OPEN_INTERNAL_ENTITY *m_openInternalEntities;
|
|
OPEN_INTERNAL_ENTITY *m_freeInternalEntities;
|
|
XML_Bool m_defaultExpandInternalEntities;
|
|
int m_tagLevel;
|
|
ENTITY *m_declEntity;
|
|
const XML_Char *m_doctypeName;
|
|
const XML_Char *m_doctypeSysid;
|
|
const XML_Char *m_doctypePubid;
|
|
const XML_Char *m_declAttributeType;
|
|
const XML_Char *m_declNotationName;
|
|
const XML_Char *m_declNotationPublicId;
|
|
ELEMENT_TYPE *m_declElementType;
|
|
ATTRIBUTE_ID *m_declAttributeId;
|
|
XML_Bool m_declAttributeIsCdata;
|
|
XML_Bool m_declAttributeIsId;
|
|
DTD *m_dtd;
|
|
const XML_Char *m_curBase;
|
|
TAG *m_tagStack;
|
|
TAG *m_freeTagList;
|
|
BINDING *m_inheritedBindings;
|
|
BINDING *m_freeBindingList;
|
|
int m_attsSize;
|
|
int m_nSpecifiedAtts;
|
|
int m_idAttIndex;
|
|
ATTRIBUTE *m_atts;
|
|
NS_ATT *m_nsAtts;
|
|
unsigned long m_nsAttsVersion;
|
|
unsigned char m_nsAttsPower;
|
|
POSITION m_position;
|
|
STRING_POOL m_tempPool;
|
|
STRING_POOL m_temp2Pool;
|
|
char *m_groupConnector;
|
|
unsigned int m_groupSize;
|
|
XML_Char m_namespaceSeparator;
|
|
XML_Parser m_parentParser;
|
|
XML_ParsingStatus m_parsingStatus;
|
|
#ifdef XML_DTD
|
|
XML_Bool m_isParamEntity;
|
|
XML_Bool m_useForeignDTD;
|
|
enum XML_ParamEntityParsing m_paramEntityParsing;
|
|
#endif
|
|
};
|
|
|
|
#define MALLOC(s) (parser->m_mem.malloc_fcn((s)))
|
|
#define REALLOC(p,s) (parser->m_mem.realloc_fcn((p),(s)))
|
|
#define FREE(p) (parser->m_mem.free_fcn((p)))
|
|
|
|
#define userData (parser->m_userData)
|
|
#define handlerArg (parser->m_handlerArg)
|
|
#define startElementHandler (parser->m_startElementHandler)
|
|
#define endElementHandler (parser->m_endElementHandler)
|
|
#define characterDataHandler (parser->m_characterDataHandler)
|
|
#define processingInstructionHandler \
|
|
(parser->m_processingInstructionHandler)
|
|
#define commentHandler (parser->m_commentHandler)
|
|
#define startCdataSectionHandler \
|
|
(parser->m_startCdataSectionHandler)
|
|
#define endCdataSectionHandler (parser->m_endCdataSectionHandler)
|
|
#define defaultHandler (parser->m_defaultHandler)
|
|
#define startDoctypeDeclHandler (parser->m_startDoctypeDeclHandler)
|
|
#define endDoctypeDeclHandler (parser->m_endDoctypeDeclHandler)
|
|
#define unparsedEntityDeclHandler \
|
|
(parser->m_unparsedEntityDeclHandler)
|
|
#define notationDeclHandler (parser->m_notationDeclHandler)
|
|
#define startNamespaceDeclHandler \
|
|
(parser->m_startNamespaceDeclHandler)
|
|
#define endNamespaceDeclHandler (parser->m_endNamespaceDeclHandler)
|
|
#define notStandaloneHandler (parser->m_notStandaloneHandler)
|
|
#define externalEntityRefHandler \
|
|
(parser->m_externalEntityRefHandler)
|
|
#define externalEntityRefHandlerArg \
|
|
(parser->m_externalEntityRefHandlerArg)
|
|
#define internalEntityRefHandler \
|
|
(parser->m_internalEntityRefHandler)
|
|
#define skippedEntityHandler (parser->m_skippedEntityHandler)
|
|
#define unknownEncodingHandler (parser->m_unknownEncodingHandler)
|
|
#define elementDeclHandler (parser->m_elementDeclHandler)
|
|
#define attlistDeclHandler (parser->m_attlistDeclHandler)
|
|
#define entityDeclHandler (parser->m_entityDeclHandler)
|
|
#define xmlDeclHandler (parser->m_xmlDeclHandler)
|
|
#define encoding (parser->m_encoding)
|
|
#define initEncoding (parser->m_initEncoding)
|
|
#define internalEncoding (parser->m_internalEncoding)
|
|
#define unknownEncodingMem (parser->m_unknownEncodingMem)
|
|
#define unknownEncodingData (parser->m_unknownEncodingData)
|
|
#define unknownEncodingHandlerData \
|
|
(parser->m_unknownEncodingHandlerData)
|
|
#define unknownEncodingRelease (parser->m_unknownEncodingRelease)
|
|
#define protocolEncodingName (parser->m_protocolEncodingName)
|
|
#define ns (parser->m_ns)
|
|
#define ns_triplets (parser->m_ns_triplets)
|
|
#define prologState (parser->m_prologState)
|
|
#define processor (parser->m_processor)
|
|
#define errorCode (parser->m_errorCode)
|
|
#define eventPtr (parser->m_eventPtr)
|
|
#define eventEndPtr (parser->m_eventEndPtr)
|
|
#define positionPtr (parser->m_positionPtr)
|
|
#define position (parser->m_position)
|
|
#define openInternalEntities (parser->m_openInternalEntities)
|
|
#define freeInternalEntities (parser->m_freeInternalEntities)
|
|
#define defaultExpandInternalEntities \
|
|
(parser->m_defaultExpandInternalEntities)
|
|
#define tagLevel (parser->m_tagLevel)
|
|
#define buffer (parser->m_buffer)
|
|
#define bufferPtr (parser->m_bufferPtr)
|
|
#define bufferEnd (parser->m_bufferEnd)
|
|
#define parseEndByteIndex (parser->m_parseEndByteIndex)
|
|
#define parseEndPtr (parser->m_parseEndPtr)
|
|
#define bufferLim (parser->m_bufferLim)
|
|
#define dataBuf (parser->m_dataBuf)
|
|
#define dataBufEnd (parser->m_dataBufEnd)
|
|
#define _dtd (parser->m_dtd)
|
|
#define curBase (parser->m_curBase)
|
|
#define declEntity (parser->m_declEntity)
|
|
#define doctypeName (parser->m_doctypeName)
|
|
#define doctypeSysid (parser->m_doctypeSysid)
|
|
#define doctypePubid (parser->m_doctypePubid)
|
|
#define declAttributeType (parser->m_declAttributeType)
|
|
#define declNotationName (parser->m_declNotationName)
|
|
#define declNotationPublicId (parser->m_declNotationPublicId)
|
|
#define declElementType (parser->m_declElementType)
|
|
#define declAttributeId (parser->m_declAttributeId)
|
|
#define declAttributeIsCdata (parser->m_declAttributeIsCdata)
|
|
#define declAttributeIsId (parser->m_declAttributeIsId)
|
|
#define freeTagList (parser->m_freeTagList)
|
|
#define freeBindingList (parser->m_freeBindingList)
|
|
#define inheritedBindings (parser->m_inheritedBindings)
|
|
#define tagStack (parser->m_tagStack)
|
|
#define atts (parser->m_atts)
|
|
#define attsSize (parser->m_attsSize)
|
|
#define nSpecifiedAtts (parser->m_nSpecifiedAtts)
|
|
#define idAttIndex (parser->m_idAttIndex)
|
|
#define nsAtts (parser->m_nsAtts)
|
|
#define nsAttsVersion (parser->m_nsAttsVersion)
|
|
#define nsAttsPower (parser->m_nsAttsPower)
|
|
#define tempPool (parser->m_tempPool)
|
|
#define temp2Pool (parser->m_temp2Pool)
|
|
#define groupConnector (parser->m_groupConnector)
|
|
#define groupSize (parser->m_groupSize)
|
|
#define namespaceSeparator (parser->m_namespaceSeparator)
|
|
#define parentParser (parser->m_parentParser)
|
|
#define ps_parsing (parser->m_parsingStatus.parsing)
|
|
#define ps_finalBuffer (parser->m_parsingStatus.finalBuffer)
|
|
#ifdef XML_DTD
|
|
#define isParamEntity (parser->m_isParamEntity)
|
|
#define useForeignDTD (parser->m_useForeignDTD)
|
|
#define paramEntityParsing (parser->m_paramEntityParsing)
|
|
#endif /* XML_DTD */
|
|
|
|
XML_Parser XMLCALL
|
|
XML_ParserCreate(const XML_Char *encodingName)
|
|
{
|
|
return XML_ParserCreate_MM(encodingName, NULL, NULL);
|
|
}
|
|
|
|
XML_Parser XMLCALL
|
|
XML_ParserCreateNS(const XML_Char *encodingName, XML_Char nsSep)
|
|
{
|
|
XML_Char tmp[2];
|
|
*tmp = nsSep;
|
|
return XML_ParserCreate_MM(encodingName, NULL, tmp);
|
|
}
|
|
|
|
static const XML_Char implicitContext[] = {
|
|
ASCII_x, ASCII_m, ASCII_l, ASCII_EQUALS, ASCII_h, ASCII_t, ASCII_t, ASCII_p,
|
|
ASCII_COLON, ASCII_SLASH, ASCII_SLASH, ASCII_w, ASCII_w, ASCII_w,
|
|
ASCII_PERIOD, ASCII_w, ASCII_3, ASCII_PERIOD, ASCII_o, ASCII_r, ASCII_g,
|
|
ASCII_SLASH, ASCII_X, ASCII_M, ASCII_L, ASCII_SLASH, ASCII_1, ASCII_9,
|
|
ASCII_9, ASCII_8, ASCII_SLASH, ASCII_n, ASCII_a, ASCII_m, ASCII_e,
|
|
ASCII_s, ASCII_p, ASCII_a, ASCII_c, ASCII_e, '\0'
|
|
};
|
|
|
|
XML_Parser XMLCALL
|
|
XML_ParserCreate_MM(const XML_Char *encodingName,
|
|
const XML_Memory_Handling_Suite *memsuite,
|
|
const XML_Char *nameSep)
|
|
{
|
|
XML_Parser parser = parserCreate(encodingName, memsuite, nameSep, NULL);
|
|
if (parser != NULL && ns) {
|
|
/* implicit context only set for root parser, since child
|
|
parsers (i.e. external entity parsers) will inherit it
|
|
*/
|
|
if (!setContext(parser, implicitContext)) {
|
|
XML_ParserFree(parser);
|
|
return NULL;
|
|
}
|
|
}
|
|
return parser;
|
|
}
|
|
|
|
static XML_Parser
|
|
parserCreate(const XML_Char *encodingName,
|
|
const XML_Memory_Handling_Suite *memsuite,
|
|
const XML_Char *nameSep,
|
|
DTD *dtd)
|
|
{
|
|
XML_Parser parser;
|
|
|
|
if (memsuite) {
|
|
XML_Memory_Handling_Suite *mtemp;
|
|
parser = (XML_Parser)
|
|
memsuite->malloc_fcn(sizeof(struct XML_ParserStruct));
|
|
if (parser != NULL) {
|
|
mtemp = (XML_Memory_Handling_Suite *)&(parser->m_mem);
|
|
mtemp->malloc_fcn = memsuite->malloc_fcn;
|
|
mtemp->realloc_fcn = memsuite->realloc_fcn;
|
|
mtemp->free_fcn = memsuite->free_fcn;
|
|
}
|
|
}
|
|
else {
|
|
XML_Memory_Handling_Suite *mtemp;
|
|
parser = (XML_Parser)malloc(sizeof(struct XML_ParserStruct));
|
|
if (parser != NULL) {
|
|
mtemp = (XML_Memory_Handling_Suite *)&(parser->m_mem);
|
|
mtemp->malloc_fcn = malloc;
|
|
mtemp->realloc_fcn = realloc;
|
|
mtemp->free_fcn = free;
|
|
}
|
|
}
|
|
|
|
if (!parser)
|
|
return parser;
|
|
|
|
buffer = NULL;
|
|
bufferLim = NULL;
|
|
|
|
attsSize = INIT_ATTS_SIZE;
|
|
atts = (ATTRIBUTE *)MALLOC(attsSize * sizeof(ATTRIBUTE));
|
|
if (atts == NULL) {
|
|
FREE(parser);
|
|
return NULL;
|
|
}
|
|
dataBuf = (XML_Char *)MALLOC(INIT_DATA_BUF_SIZE * sizeof(XML_Char));
|
|
if (dataBuf == NULL) {
|
|
FREE(atts);
|
|
FREE(parser);
|
|
return NULL;
|
|
}
|
|
dataBufEnd = dataBuf + INIT_DATA_BUF_SIZE;
|
|
|
|
if (dtd)
|
|
_dtd = dtd;
|
|
else {
|
|
_dtd = dtdCreate(&parser->m_mem);
|
|
if (_dtd == NULL) {
|
|
FREE(dataBuf);
|
|
FREE(atts);
|
|
FREE(parser);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
freeBindingList = NULL;
|
|
freeTagList = NULL;
|
|
freeInternalEntities = NULL;
|
|
|
|
groupSize = 0;
|
|
groupConnector = NULL;
|
|
|
|
unknownEncodingHandler = NULL;
|
|
unknownEncodingHandlerData = NULL;
|
|
|
|
namespaceSeparator = ASCII_EXCL;
|
|
ns = XML_FALSE;
|
|
ns_triplets = XML_FALSE;
|
|
|
|
nsAtts = NULL;
|
|
nsAttsVersion = 0;
|
|
nsAttsPower = 0;
|
|
|
|
poolInit(&tempPool, &(parser->m_mem));
|
|
poolInit(&temp2Pool, &(parser->m_mem));
|
|
parserInit(parser, encodingName);
|
|
|
|
if (encodingName && !protocolEncodingName) {
|
|
XML_ParserFree(parser);
|
|
return NULL;
|
|
}
|
|
|
|
if (nameSep) {
|
|
ns = XML_TRUE;
|
|
internalEncoding = XmlGetInternalEncodingNS();
|
|
namespaceSeparator = *nameSep;
|
|
}
|
|
else {
|
|
internalEncoding = XmlGetInternalEncoding();
|
|
}
|
|
|
|
return parser;
|
|
}
|
|
|
|
static void
|
|
parserInit(XML_Parser parser, const XML_Char *encodingName)
|
|
{
|
|
processor = prologInitProcessor;
|
|
XmlPrologStateInit(&prologState);
|
|
protocolEncodingName = (encodingName != NULL
|
|
? poolCopyString(&tempPool, encodingName)
|
|
: NULL);
|
|
curBase = NULL;
|
|
XmlInitEncoding(&initEncoding, &encoding, 0);
|
|
userData = NULL;
|
|
handlerArg = NULL;
|
|
startElementHandler = NULL;
|
|
endElementHandler = NULL;
|
|
characterDataHandler = NULL;
|
|
processingInstructionHandler = NULL;
|
|
commentHandler = NULL;
|
|
startCdataSectionHandler = NULL;
|
|
endCdataSectionHandler = NULL;
|
|
defaultHandler = NULL;
|
|
startDoctypeDeclHandler = NULL;
|
|
endDoctypeDeclHandler = NULL;
|
|
unparsedEntityDeclHandler = NULL;
|
|
notationDeclHandler = NULL;
|
|
startNamespaceDeclHandler = NULL;
|
|
endNamespaceDeclHandler = NULL;
|
|
notStandaloneHandler = NULL;
|
|
externalEntityRefHandler = NULL;
|
|
externalEntityRefHandlerArg = parser;
|
|
skippedEntityHandler = NULL;
|
|
elementDeclHandler = NULL;
|
|
attlistDeclHandler = NULL;
|
|
entityDeclHandler = NULL;
|
|
xmlDeclHandler = NULL;
|
|
bufferPtr = buffer;
|
|
bufferEnd = buffer;
|
|
parseEndByteIndex = 0;
|
|
parseEndPtr = NULL;
|
|
declElementType = NULL;
|
|
declAttributeId = NULL;
|
|
declEntity = NULL;
|
|
doctypeName = NULL;
|
|
doctypeSysid = NULL;
|
|
doctypePubid = NULL;
|
|
declAttributeType = NULL;
|
|
declNotationName = NULL;
|
|
declNotationPublicId = NULL;
|
|
declAttributeIsCdata = XML_FALSE;
|
|
declAttributeIsId = XML_FALSE;
|
|
memset(&position, 0, sizeof(POSITION));
|
|
errorCode = XML_ERROR_NONE;
|
|
eventPtr = NULL;
|
|
eventEndPtr = NULL;
|
|
positionPtr = NULL;
|
|
openInternalEntities = NULL;
|
|
defaultExpandInternalEntities = XML_TRUE;
|
|
tagLevel = 0;
|
|
tagStack = NULL;
|
|
inheritedBindings = NULL;
|
|
nSpecifiedAtts = 0;
|
|
unknownEncodingMem = NULL;
|
|
unknownEncodingRelease = NULL;
|
|
unknownEncodingData = NULL;
|
|
parentParser = NULL;
|
|
ps_parsing = XML_INITIALIZED;
|
|
#ifdef XML_DTD
|
|
isParamEntity = XML_FALSE;
|
|
useForeignDTD = XML_FALSE;
|
|
paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
|
|
#endif
|
|
}
|
|
|
|
/* moves list of bindings to freeBindingList */
|
|
static void FASTCALL
|
|
moveToFreeBindingList(XML_Parser parser, BINDING *bindings)
|
|
{
|
|
while (bindings) {
|
|
BINDING *b = bindings;
|
|
bindings = bindings->nextTagBinding;
|
|
b->nextTagBinding = freeBindingList;
|
|
freeBindingList = b;
|
|
}
|
|
}
|
|
|
|
XML_Bool XMLCALL
|
|
XML_ParserReset(XML_Parser parser, const XML_Char *encodingName)
|
|
{
|
|
TAG *tStk;
|
|
OPEN_INTERNAL_ENTITY *openEntityList;
|
|
if (parentParser)
|
|
return XML_FALSE;
|
|
/* move tagStack to freeTagList */
|
|
tStk = tagStack;
|
|
while (tStk) {
|
|
TAG *tag = tStk;
|
|
tStk = tStk->parent;
|
|
tag->parent = freeTagList;
|
|
moveToFreeBindingList(parser, tag->bindings);
|
|
tag->bindings = NULL;
|
|
freeTagList = tag;
|
|
}
|
|
/* move openInternalEntities to freeInternalEntities */
|
|
openEntityList = openInternalEntities;
|
|
while (openEntityList) {
|
|
OPEN_INTERNAL_ENTITY *openEntity = openEntityList;
|
|
openEntityList = openEntity->next;
|
|
openEntity->next = freeInternalEntities;
|
|
freeInternalEntities = openEntity;
|
|
}
|
|
moveToFreeBindingList(parser, inheritedBindings);
|
|
FREE(unknownEncodingMem);
|
|
if (unknownEncodingRelease)
|
|
unknownEncodingRelease(unknownEncodingData);
|
|
poolClear(&tempPool);
|
|
poolClear(&temp2Pool);
|
|
parserInit(parser, encodingName);
|
|
dtdReset(_dtd, &parser->m_mem);
|
|
return setContext(parser, implicitContext);
|
|
}
|
|
|
|
enum XML_Status XMLCALL
|
|
XML_SetEncoding(XML_Parser parser, const XML_Char *encodingName)
|
|
{
|
|
/* Block after XML_Parse()/XML_ParseBuffer() has been called.
|
|
XXX There's no way for the caller to determine which of the
|
|
XXX possible error cases caused the XML_STATUS_ERROR return.
|
|
*/
|
|
if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
|
|
return XML_STATUS_ERROR;
|
|
if (encodingName == NULL)
|
|
protocolEncodingName = NULL;
|
|
else {
|
|
protocolEncodingName = poolCopyString(&tempPool, encodingName);
|
|
if (!protocolEncodingName)
|
|
return XML_STATUS_ERROR;
|
|
}
|
|
return XML_STATUS_OK;
|
|
}
|
|
|
|
XML_Parser XMLCALL
|
|
XML_ExternalEntityParserCreate(XML_Parser oldParser,
|
|
const XML_Char *context,
|
|
const XML_Char *encodingName)
|
|
{
|
|
XML_Parser parser = oldParser;
|
|
DTD *newDtd = NULL;
|
|
DTD *oldDtd = _dtd;
|
|
XML_StartElementHandler oldStartElementHandler = startElementHandler;
|
|
XML_EndElementHandler oldEndElementHandler = endElementHandler;
|
|
XML_CharacterDataHandler oldCharacterDataHandler = characterDataHandler;
|
|
XML_ProcessingInstructionHandler oldProcessingInstructionHandler
|
|
= processingInstructionHandler;
|
|
XML_CommentHandler oldCommentHandler = commentHandler;
|
|
XML_StartCdataSectionHandler oldStartCdataSectionHandler
|
|
= startCdataSectionHandler;
|
|
XML_EndCdataSectionHandler oldEndCdataSectionHandler
|
|
= endCdataSectionHandler;
|
|
XML_DefaultHandler oldDefaultHandler = defaultHandler;
|
|
XML_UnparsedEntityDeclHandler oldUnparsedEntityDeclHandler
|
|
= unparsedEntityDeclHandler;
|
|
XML_NotationDeclHandler oldNotationDeclHandler = notationDeclHandler;
|
|
XML_StartNamespaceDeclHandler oldStartNamespaceDeclHandler
|
|
= startNamespaceDeclHandler;
|
|
XML_EndNamespaceDeclHandler oldEndNamespaceDeclHandler
|
|
= endNamespaceDeclHandler;
|
|
XML_NotStandaloneHandler oldNotStandaloneHandler = notStandaloneHandler;
|
|
XML_ExternalEntityRefHandler oldExternalEntityRefHandler
|
|
= externalEntityRefHandler;
|
|
XML_SkippedEntityHandler oldSkippedEntityHandler = skippedEntityHandler;
|
|
XML_UnknownEncodingHandler oldUnknownEncodingHandler
|
|
= unknownEncodingHandler;
|
|
XML_ElementDeclHandler oldElementDeclHandler = elementDeclHandler;
|
|
XML_AttlistDeclHandler oldAttlistDeclHandler = attlistDeclHandler;
|
|
XML_EntityDeclHandler oldEntityDeclHandler = entityDeclHandler;
|
|
XML_XmlDeclHandler oldXmlDeclHandler = xmlDeclHandler;
|
|
ELEMENT_TYPE * oldDeclElementType = declElementType;
|
|
|
|
void *oldUserData = userData;
|
|
void *oldHandlerArg = handlerArg;
|
|
XML_Bool oldDefaultExpandInternalEntities = defaultExpandInternalEntities;
|
|
XML_Parser oldExternalEntityRefHandlerArg = externalEntityRefHandlerArg;
|
|
#ifdef XML_DTD
|
|
enum XML_ParamEntityParsing oldParamEntityParsing = paramEntityParsing;
|
|
int oldInEntityValue = prologState.inEntityValue;
|
|
#endif
|
|
XML_Bool oldns_triplets = ns_triplets;
|
|
|
|
#ifdef XML_DTD
|
|
if (!context)
|
|
newDtd = oldDtd;
|
|
#endif /* XML_DTD */
|
|
|
|
/* Note that the magical uses of the pre-processor to make field
|
|
access look more like C++ require that `parser' be overwritten
|
|
here. This makes this function more painful to follow than it
|
|
would be otherwise.
|
|
*/
|
|
if (ns) {
|
|
XML_Char tmp[2];
|
|
*tmp = namespaceSeparator;
|
|
parser = parserCreate(encodingName, &parser->m_mem, tmp, newDtd);
|
|
}
|
|
else {
|
|
parser = parserCreate(encodingName, &parser->m_mem, NULL, newDtd);
|
|
}
|
|
|
|
if (!parser)
|
|
return NULL;
|
|
|
|
startElementHandler = oldStartElementHandler;
|
|
endElementHandler = oldEndElementHandler;
|
|
characterDataHandler = oldCharacterDataHandler;
|
|
processingInstructionHandler = oldProcessingInstructionHandler;
|
|
commentHandler = oldCommentHandler;
|
|
startCdataSectionHandler = oldStartCdataSectionHandler;
|
|
endCdataSectionHandler = oldEndCdataSectionHandler;
|
|
defaultHandler = oldDefaultHandler;
|
|
unparsedEntityDeclHandler = oldUnparsedEntityDeclHandler;
|
|
notationDeclHandler = oldNotationDeclHandler;
|
|
startNamespaceDeclHandler = oldStartNamespaceDeclHandler;
|
|
endNamespaceDeclHandler = oldEndNamespaceDeclHandler;
|
|
notStandaloneHandler = oldNotStandaloneHandler;
|
|
externalEntityRefHandler = oldExternalEntityRefHandler;
|
|
skippedEntityHandler = oldSkippedEntityHandler;
|
|
unknownEncodingHandler = oldUnknownEncodingHandler;
|
|
elementDeclHandler = oldElementDeclHandler;
|
|
attlistDeclHandler = oldAttlistDeclHandler;
|
|
entityDeclHandler = oldEntityDeclHandler;
|
|
xmlDeclHandler = oldXmlDeclHandler;
|
|
declElementType = oldDeclElementType;
|
|
userData = oldUserData;
|
|
if (oldUserData == oldHandlerArg)
|
|
handlerArg = userData;
|
|
else
|
|
handlerArg = parser;
|
|
if (oldExternalEntityRefHandlerArg != oldParser)
|
|
externalEntityRefHandlerArg = oldExternalEntityRefHandlerArg;
|
|
defaultExpandInternalEntities = oldDefaultExpandInternalEntities;
|
|
ns_triplets = oldns_triplets;
|
|
parentParser = oldParser;
|
|
#ifdef XML_DTD
|
|
paramEntityParsing = oldParamEntityParsing;
|
|
prologState.inEntityValue = oldInEntityValue;
|
|
if (context) {
|
|
#endif /* XML_DTD */
|
|
if (!dtdCopy(_dtd, oldDtd, &parser->m_mem)
|
|
|| !setContext(parser, context)) {
|
|
XML_ParserFree(parser);
|
|
return NULL;
|
|
}
|
|
processor = externalEntityInitProcessor;
|
|
#ifdef XML_DTD
|
|
}
|
|
else {
|
|
/* The DTD instance referenced by _dtd is shared between the document's
|
|
root parser and external PE parsers, therefore one does not need to
|
|
call setContext. In addition, one also *must* not call setContext,
|
|
because this would overwrite existing prefix->binding pointers in
|
|
_dtd with ones that get destroyed with the external PE parser.
|
|
This would leave those prefixes with dangling pointers.
|
|
*/
|
|
isParamEntity = XML_TRUE;
|
|
XmlPrologStateInitExternalEntity(&prologState);
|
|
processor = externalParEntInitProcessor;
|
|
}
|
|
#endif /* XML_DTD */
|
|
return parser;
|
|
}
|
|
|
|
static void FASTCALL
|
|
destroyBindings(BINDING *bindings, XML_Parser parser)
|
|
{
|
|
for (;;) {
|
|
BINDING *b = bindings;
|
|
if (!b)
|
|
break;
|
|
bindings = b->nextTagBinding;
|
|
FREE(b->uri);
|
|
FREE(b);
|
|
}
|
|
}
|
|
|
|
void XMLCALL
|
|
XML_ParserFree(XML_Parser parser)
|
|
{
|
|
TAG *tagList;
|
|
OPEN_INTERNAL_ENTITY *entityList;
|
|
if (parser == NULL)
|
|
return;
|
|
/* free tagStack and freeTagList */
|
|
tagList = tagStack;
|
|
for (;;) {
|
|
TAG *p;
|
|
if (tagList == NULL) {
|
|
if (freeTagList == NULL)
|
|
break;
|
|
tagList = freeTagList;
|
|
freeTagList = NULL;
|
|
}
|
|
p = tagList;
|
|
tagList = tagList->parent;
|
|
FREE(p->buf);
|
|
destroyBindings(p->bindings, parser);
|
|
FREE(p);
|
|
}
|
|
/* free openInternalEntities and freeInternalEntities */
|
|
entityList = openInternalEntities;
|
|
for (;;) {
|
|
OPEN_INTERNAL_ENTITY *openEntity;
|
|
if (entityList == NULL) {
|
|
if (freeInternalEntities == NULL)
|
|
break;
|
|
entityList = freeInternalEntities;
|
|
freeInternalEntities = NULL;
|
|
}
|
|
openEntity = entityList;
|
|
entityList = entityList->next;
|
|
FREE(openEntity);
|
|
}
|
|
|
|
destroyBindings(freeBindingList, parser);
|
|
destroyBindings(inheritedBindings, parser);
|
|
poolDestroy(&tempPool);
|
|
poolDestroy(&temp2Pool);
|
|
#ifdef XML_DTD
|
|
/* external parameter entity parsers share the DTD structure
|
|
parser->m_dtd with the root parser, so we must not destroy it
|
|
*/
|
|
if (!isParamEntity && _dtd)
|
|
#else
|
|
if (_dtd)
|
|
#endif /* XML_DTD */
|
|
dtdDestroy(_dtd, (XML_Bool)!parentParser, &parser->m_mem);
|
|
FREE((void *)atts);
|
|
FREE(groupConnector);
|
|
FREE(buffer);
|
|
FREE(dataBuf);
|
|
FREE(nsAtts);
|
|
FREE(unknownEncodingMem);
|
|
if (unknownEncodingRelease)
|
|
unknownEncodingRelease(unknownEncodingData);
|
|
FREE(parser);
|
|
}
|
|
|
|
void XMLCALL
|
|
XML_UseParserAsHandlerArg(XML_Parser parser)
|
|
{
|
|
handlerArg = parser;
|
|
}
|
|
|
|
enum XML_Error XMLCALL
|
|
XML_UseForeignDTD(XML_Parser parser, XML_Bool useDTD)
|
|
{
|
|
#ifdef XML_DTD
|
|
/* block after XML_Parse()/XML_ParseBuffer() has been called */
|
|
if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
|
|
return XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING;
|
|
useForeignDTD = useDTD;
|
|
return XML_ERROR_NONE;
|
|
#else
|
|
return XML_ERROR_FEATURE_REQUIRES_XML_DTD;
|
|
#endif
|
|
}
|
|
|
|
void XMLCALL
|
|
XML_SetReturnNSTriplet(XML_Parser parser, int do_nst)
|
|
{
|
|
/* block after XML_Parse()/XML_ParseBuffer() has been called */
|
|
if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
|
|
return;
|
|
ns_triplets = do_nst ? XML_TRUE : XML_FALSE;
|
|
}
|
|
|
|
void XMLCALL
|
|
XML_SetUserData(XML_Parser parser, void *p)
|
|
{
|
|
if (handlerArg == userData)
|
|
handlerArg = userData = p;
|
|
else
|
|
userData = p;
|
|
}
|
|
|
|
enum XML_Status XMLCALL
|
|
XML_SetBase(XML_Parser parser, const XML_Char *p)
|
|
{
|
|
if (p) {
|
|
p = poolCopyString(&_dtd->pool, p);
|
|
if (!p)
|
|
return XML_STATUS_ERROR;
|
|
curBase = p;
|
|
}
|
|
else
|
|
curBase = NULL;
|
|
return XML_STATUS_OK;
|
|
}
|
|
|
|
const XML_Char * XMLCALL
|
|
XML_GetBase(XML_Parser parser)
|
|
{
|
|
return curBase;
|
|
}
|
|
|
|
int XMLCALL
|
|
XML_GetSpecifiedAttributeCount(XML_Parser parser)
|
|
{
|
|
return nSpecifiedAtts;
|
|
}
|
|
|
|
int XMLCALL
|
|
XML_GetIdAttributeIndex(XML_Parser parser)
|
|
{
|
|
return idAttIndex;
|
|
}
|
|
|
|
void XMLCALL
|
|
XML_SetElementHandler(XML_Parser parser,
|
|
XML_StartElementHandler start,
|
|
XML_EndElementHandler end)
|
|
{
|
|
startElementHandler = start;
|
|
endElementHandler = end;
|
|
}
|
|
|
|
void XMLCALL
|
|
XML_SetStartElementHandler(XML_Parser parser,
|
|
XML_StartElementHandler start) {
|
|
startElementHandler = start;
|
|
}
|
|
|
|
void XMLCALL
|
|
XML_SetEndElementHandler(XML_Parser parser,
|
|
XML_EndElementHandler end) {
|
|
endElementHandler = end;
|
|
}
|
|
|
|
void XMLCALL
|
|
XML_SetCharacterDataHandler(XML_Parser parser,
|
|
XML_CharacterDataHandler handler)
|
|
{
|
|
characterDataHandler = handler;
|
|
}
|
|
|
|
void XMLCALL
|
|
XML_SetProcessingInstructionHandler(XML_Parser parser,
|
|
XML_ProcessingInstructionHandler handler)
|
|
{
|
|
processingInstructionHandler = handler;
|
|
}
|
|
|
|
void XMLCALL
|
|
XML_SetCommentHandler(XML_Parser parser,
|
|
XML_CommentHandler handler)
|
|
{
|
|
commentHandler = handler;
|
|
}
|
|
|
|
void XMLCALL
|
|
XML_SetCdataSectionHandler(XML_Parser parser,
|
|
XML_StartCdataSectionHandler start,
|
|
XML_EndCdataSectionHandler end)
|
|
{
|
|
startCdataSectionHandler = start;
|
|
endCdataSectionHandler = end;
|
|
}
|
|
|
|
void XMLCALL
|
|
XML_SetStartCdataSectionHandler(XML_Parser parser,
|
|
XML_StartCdataSectionHandler start) {
|
|
startCdataSectionHandler = start;
|
|
}
|
|
|
|
void XMLCALL
|
|
XML_SetEndCdataSectionHandler(XML_Parser parser,
|
|
XML_EndCdataSectionHandler end) {
|
|
endCdataSectionHandler = end;
|
|
}
|
|
|
|
void XMLCALL
|
|
XML_SetDefaultHandler(XML_Parser parser,
|
|
XML_DefaultHandler handler)
|
|
{
|
|
defaultHandler = handler;
|
|
defaultExpandInternalEntities = XML_FALSE;
|
|
}
|
|
|
|
void XMLCALL
|
|
XML_SetDefaultHandlerExpand(XML_Parser parser,
|
|
XML_DefaultHandler handler)
|
|
{
|
|
defaultHandler = handler;
|
|
defaultExpandInternalEntities = XML_TRUE;
|
|
}
|
|
|
|
void XMLCALL
|
|
XML_SetDoctypeDeclHandler(XML_Parser parser,
|
|
XML_StartDoctypeDeclHandler start,
|
|
XML_EndDoctypeDeclHandler end)
|
|
{
|
|
startDoctypeDeclHandler = start;
|
|
endDoctypeDeclHandler = end;
|
|
}
|
|
|
|
void XMLCALL
|
|
XML_SetStartDoctypeDeclHandler(XML_Parser parser,
|
|
XML_StartDoctypeDeclHandler start) {
|
|
startDoctypeDeclHandler = start;
|
|
}
|
|
|
|
void XMLCALL
|
|
XML_SetEndDoctypeDeclHandler(XML_Parser parser,
|
|
XML_EndDoctypeDeclHandler end) {
|
|
endDoctypeDeclHandler = end;
|
|
}
|
|
|
|
void XMLCALL
|
|
XML_SetUnparsedEntityDeclHandler(XML_Parser parser,
|
|
XML_UnparsedEntityDeclHandler handler)
|
|
{
|
|
unparsedEntityDeclHandler = handler;
|
|
}
|
|
|
|
void XMLCALL
|
|
XML_SetNotationDeclHandler(XML_Parser parser,
|
|
XML_NotationDeclHandler handler)
|
|
{
|
|
notationDeclHandler = handler;
|
|
}
|
|
|
|
void XMLCALL
|
|
XML_SetNamespaceDeclHandler(XML_Parser parser,
|
|
XML_StartNamespaceDeclHandler start,
|
|
XML_EndNamespaceDeclHandler end)
|
|
{
|
|
startNamespaceDeclHandler = start;
|
|
endNamespaceDeclHandler = end;
|
|
}
|
|
|
|
void XMLCALL
|
|
XML_SetStartNamespaceDeclHandler(XML_Parser parser,
|
|
XML_StartNamespaceDeclHandler start) {
|
|
startNamespaceDeclHandler = start;
|
|
}
|
|
|
|
void XMLCALL
|
|
XML_SetEndNamespaceDeclHandler(XML_Parser parser,
|
|
XML_EndNamespaceDeclHandler end) {
|
|
endNamespaceDeclHandler = end;
|
|
}
|
|
|
|
void XMLCALL
|
|
XML_SetNotStandaloneHandler(XML_Parser parser,
|
|
XML_NotStandaloneHandler handler)
|
|
{
|
|
notStandaloneHandler = handler;
|
|
}
|
|
|
|
void XMLCALL
|
|
XML_SetExternalEntityRefHandler(XML_Parser parser,
|
|
XML_ExternalEntityRefHandler handler)
|
|
{
|
|
externalEntityRefHandler = handler;
|
|
}
|
|
|
|
void XMLCALL
|
|
XML_SetExternalEntityRefHandlerArg(XML_Parser parser, void *arg)
|
|
{
|
|
if (arg)
|
|
externalEntityRefHandlerArg = (XML_Parser)arg;
|
|
else
|
|
externalEntityRefHandlerArg = parser;
|
|
}
|
|
|
|
void XMLCALL
|
|
XML_SetSkippedEntityHandler(XML_Parser parser,
|
|
XML_SkippedEntityHandler handler)
|
|
{
|
|
skippedEntityHandler = handler;
|
|
}
|
|
|
|
void XMLCALL
|
|
XML_SetUnknownEncodingHandler(XML_Parser parser,
|
|
XML_UnknownEncodingHandler handler,
|
|
void *data)
|
|
{
|
|
unknownEncodingHandler = handler;
|
|
unknownEncodingHandlerData = data;
|
|
}
|
|
|
|
void XMLCALL
|
|
XML_SetElementDeclHandler(XML_Parser parser,
|
|
XML_ElementDeclHandler eldecl)
|
|
{
|
|
elementDeclHandler = eldecl;
|
|
}
|
|
|
|
void XMLCALL
|
|
XML_SetAttlistDeclHandler(XML_Parser parser,
|
|
XML_AttlistDeclHandler attdecl)
|
|
{
|
|
attlistDeclHandler = attdecl;
|
|
}
|
|
|
|
void XMLCALL
|
|
XML_SetEntityDeclHandler(XML_Parser parser,
|
|
XML_EntityDeclHandler handler)
|
|
{
|
|
entityDeclHandler = handler;
|
|
}
|
|
|
|
void XMLCALL
|
|
XML_SetXmlDeclHandler(XML_Parser parser,
|
|
XML_XmlDeclHandler handler) {
|
|
xmlDeclHandler = handler;
|
|
}
|
|
|
|
int XMLCALL
|
|
XML_SetParamEntityParsing(XML_Parser parser,
|
|
enum XML_ParamEntityParsing peParsing)
|
|
{
|
|
/* block after XML_Parse()/XML_ParseBuffer() has been called */
|
|
if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
|
|
return 0;
|
|
#ifdef XML_DTD
|
|
paramEntityParsing = peParsing;
|
|
return 1;
|
|
#else
|
|
return peParsing == XML_PARAM_ENTITY_PARSING_NEVER;
|
|
#endif
|
|
}
|
|
|
|
enum XML_Status XMLCALL
|
|
XML_Parse(XML_Parser parser, const char *s, int len, int isFinal)
|
|
{
|
|
switch (ps_parsing) {
|
|
case XML_SUSPENDED:
|
|
errorCode = XML_ERROR_SUSPENDED;
|
|
return XML_STATUS_ERROR;
|
|
case XML_FINISHED:
|
|
errorCode = XML_ERROR_FINISHED;
|
|
return XML_STATUS_ERROR;
|
|
default:
|
|
ps_parsing = XML_PARSING;
|
|
}
|
|
|
|
if (len == 0) {
|
|
ps_finalBuffer = (XML_Bool)isFinal;
|
|
if (!isFinal)
|
|
return XML_STATUS_OK;
|
|
positionPtr = bufferPtr;
|
|
parseEndPtr = bufferEnd;
|
|
|
|
/* If data are left over from last buffer, and we now know that these
|
|
data are the final chunk of input, then we have to check them again
|
|
to detect errors based on that fact.
|
|
*/
|
|
errorCode = processor(parser, bufferPtr, parseEndPtr, &bufferPtr);
|
|
|
|
if (errorCode == XML_ERROR_NONE) {
|
|
switch (ps_parsing) {
|
|
case XML_SUSPENDED:
|
|
XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position);
|
|
positionPtr = bufferPtr;
|
|
return XML_STATUS_SUSPENDED;
|
|
case XML_INITIALIZED:
|
|
case XML_PARSING:
|
|
ps_parsing = XML_FINISHED;
|
|
/* fall through */
|
|
default:
|
|
return XML_STATUS_OK;
|
|
}
|
|
}
|
|
eventEndPtr = eventPtr;
|
|
processor = errorProcessor;
|
|
return XML_STATUS_ERROR;
|
|
}
|
|
#ifndef XML_CONTEXT_BYTES
|
|
else if (bufferPtr == bufferEnd) {
|
|
const char *end;
|
|
int nLeftOver;
|
|
enum XML_Error result;
|
|
parseEndByteIndex += len;
|
|
positionPtr = s;
|
|
ps_finalBuffer = (XML_Bool)isFinal;
|
|
|
|
errorCode = processor(parser, s, parseEndPtr = s + len, &end);
|
|
|
|
if (errorCode != XML_ERROR_NONE) {
|
|
eventEndPtr = eventPtr;
|
|
processor = errorProcessor;
|
|
return XML_STATUS_ERROR;
|
|
}
|
|
else {
|
|
switch (ps_parsing) {
|
|
case XML_SUSPENDED:
|
|
result = XML_STATUS_SUSPENDED;
|
|
break;
|
|
case XML_INITIALIZED:
|
|
case XML_PARSING:
|
|
result = XML_STATUS_OK;
|
|
if (isFinal) {
|
|
ps_parsing = XML_FINISHED;
|
|
return result;
|
|
}
|
|
}
|
|
}
|
|
|
|
XmlUpdatePosition(encoding, positionPtr, end, &position);
|
|
nLeftOver = s + len - end;
|
|
if (nLeftOver) {
|
|
if (buffer == NULL || nLeftOver > bufferLim - buffer) {
|
|
/* FIXME avoid integer overflow */
|
|
char *temp;
|
|
temp = (buffer == NULL
|
|
? (char *)MALLOC(len * 2)
|
|
: (char *)REALLOC(buffer, len * 2));
|
|
if (temp == NULL) {
|
|
errorCode = XML_ERROR_NO_MEMORY;
|
|
return XML_STATUS_ERROR;
|
|
}
|
|
buffer = temp;
|
|
if (!buffer) {
|
|
errorCode = XML_ERROR_NO_MEMORY;
|
|
eventPtr = eventEndPtr = NULL;
|
|
processor = errorProcessor;
|
|
return XML_STATUS_ERROR;
|
|
}
|
|
bufferLim = buffer + len * 2;
|
|
}
|
|
memcpy(buffer, end, nLeftOver);
|
|
}
|
|
bufferPtr = buffer;
|
|
bufferEnd = buffer + nLeftOver;
|
|
positionPtr = bufferPtr;
|
|
parseEndPtr = bufferEnd;
|
|
eventPtr = bufferPtr;
|
|
eventEndPtr = bufferPtr;
|
|
return result;
|
|
}
|
|
#endif /* not defined XML_CONTEXT_BYTES */
|
|
else {
|
|
void *buff = XML_GetBuffer(parser, len);
|
|
if (buff == NULL)
|
|
return XML_STATUS_ERROR;
|
|
else {
|
|
memcpy(buff, s, len);
|
|
return XML_ParseBuffer(parser, len, isFinal);
|
|
}
|
|
}
|
|
}
|
|
|
|
enum XML_Status XMLCALL
|
|
XML_ParseBuffer(XML_Parser parser, int len, int isFinal)
|
|
{
|
|
const char *start;
|
|
enum XML_Status result = XML_STATUS_OK;
|
|
|
|
switch (ps_parsing) {
|
|
case XML_SUSPENDED:
|
|
errorCode = XML_ERROR_SUSPENDED;
|
|
return XML_STATUS_ERROR;
|
|
case XML_FINISHED:
|
|
errorCode = XML_ERROR_FINISHED;
|
|
return XML_STATUS_ERROR;
|
|
default:
|
|
ps_parsing = XML_PARSING;
|
|
}
|
|
|
|
start = bufferPtr;
|
|
positionPtr = start;
|
|
bufferEnd += len;
|
|
parseEndPtr = bufferEnd;
|
|
parseEndByteIndex += len;
|
|
ps_finalBuffer = (XML_Bool)isFinal;
|
|
|
|
errorCode = processor(parser, start, parseEndPtr, &bufferPtr);
|
|
|
|
if (errorCode != XML_ERROR_NONE) {
|
|
eventEndPtr = eventPtr;
|
|
processor = errorProcessor;
|
|
return XML_STATUS_ERROR;
|
|
}
|
|
else {
|
|
switch (ps_parsing) {
|
|
case XML_SUSPENDED:
|
|
result = XML_STATUS_SUSPENDED;
|
|
break;
|
|
case XML_INITIALIZED:
|
|
case XML_PARSING:
|
|
if (isFinal) {
|
|
ps_parsing = XML_FINISHED;
|
|
return result;
|
|
}
|
|
default: ; /* should not happen */
|
|
}
|
|
}
|
|
|
|
XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position);
|
|
positionPtr = bufferPtr;
|
|
return result;
|
|
}
|
|
|
|
void * XMLCALL
|
|
XML_GetBuffer(XML_Parser parser, int len)
|
|
{
|
|
switch (ps_parsing) {
|
|
case XML_SUSPENDED:
|
|
errorCode = XML_ERROR_SUSPENDED;
|
|
return NULL;
|
|
case XML_FINISHED:
|
|
errorCode = XML_ERROR_FINISHED;
|
|
return NULL;
|
|
default: ;
|
|
}
|
|
|
|
if (len > bufferLim - bufferEnd) {
|
|
/* FIXME avoid integer overflow */
|
|
int neededSize = len + (int)(bufferEnd - bufferPtr);
|
|
#ifdef XML_CONTEXT_BYTES
|
|
int keep = (int)(bufferPtr - buffer);
|
|
|
|
if (keep > XML_CONTEXT_BYTES)
|
|
keep = XML_CONTEXT_BYTES;
|
|
neededSize += keep;
|
|
#endif /* defined XML_CONTEXT_BYTES */
|
|
if (neededSize <= bufferLim - buffer) {
|
|
#ifdef XML_CONTEXT_BYTES
|
|
if (keep < bufferPtr - buffer) {
|
|
int offset = (int)(bufferPtr - buffer) - keep;
|
|
memmove(buffer, &buffer[offset], bufferEnd - bufferPtr + keep);
|
|
bufferEnd -= offset;
|
|
bufferPtr -= offset;
|
|
}
|
|
#else
|
|
memmove(buffer, bufferPtr, bufferEnd - bufferPtr);
|
|
bufferEnd = buffer + (bufferEnd - bufferPtr);
|
|
bufferPtr = buffer;
|
|
#endif /* not defined XML_CONTEXT_BYTES */
|
|
}
|
|
else {
|
|
char *newBuf;
|
|
int bufferSize = (int)(bufferLim - bufferPtr);
|
|
if (bufferSize == 0)
|
|
bufferSize = INIT_BUFFER_SIZE;
|
|
do {
|
|
bufferSize *= 2;
|
|
} while (bufferSize < neededSize);
|
|
newBuf = (char *)MALLOC(bufferSize);
|
|
if (newBuf == 0) {
|
|
errorCode = XML_ERROR_NO_MEMORY;
|
|
return NULL;
|
|
}
|
|
bufferLim = newBuf + bufferSize;
|
|
#ifdef XML_CONTEXT_BYTES
|
|
if (bufferPtr) {
|
|
int keep = (int)(bufferPtr - buffer);
|
|
if (keep > XML_CONTEXT_BYTES)
|
|
keep = XML_CONTEXT_BYTES;
|
|
memcpy(newBuf, &bufferPtr[-keep], bufferEnd - bufferPtr + keep);
|
|
FREE(buffer);
|
|
buffer = newBuf;
|
|
bufferEnd = buffer + (bufferEnd - bufferPtr) + keep;
|
|
bufferPtr = buffer + keep;
|
|
}
|
|
else {
|
|
bufferEnd = newBuf + (bufferEnd - bufferPtr);
|
|
bufferPtr = buffer = newBuf;
|
|
}
|
|
#else
|
|
if (bufferPtr) {
|
|
memcpy(newBuf, bufferPtr, bufferEnd - bufferPtr);
|
|
FREE(buffer);
|
|
}
|
|
bufferEnd = newBuf + (bufferEnd - bufferPtr);
|
|
bufferPtr = buffer = newBuf;
|
|
#endif /* not defined XML_CONTEXT_BYTES */
|
|
}
|
|
}
|
|
return bufferEnd;
|
|
}
|
|
|
|
enum XML_Status XMLCALL
|
|
XML_StopParser(XML_Parser parser, XML_Bool resumable)
|
|
{
|
|
switch (ps_parsing) {
|
|
case XML_SUSPENDED:
|
|
if (resumable) {
|
|
errorCode = XML_ERROR_SUSPENDED;
|
|
return XML_STATUS_ERROR;
|
|
}
|
|
ps_parsing = XML_FINISHED;
|
|
break;
|
|
case XML_FINISHED:
|
|
errorCode = XML_ERROR_FINISHED;
|
|
return XML_STATUS_ERROR;
|
|
default:
|
|
if (resumable) {
|
|
#ifdef XML_DTD
|
|
if (isParamEntity) {
|
|
errorCode = XML_ERROR_SUSPEND_PE;
|
|
return XML_STATUS_ERROR;
|
|
}
|
|
#endif
|
|
ps_parsing = XML_SUSPENDED;
|
|
}
|
|
else
|
|
ps_parsing = XML_FINISHED;
|
|
}
|
|
return XML_STATUS_OK;
|
|
}
|
|
|
|
enum XML_Status XMLCALL
|
|
XML_ResumeParser(XML_Parser parser)
|
|
{
|
|
enum XML_Status result = XML_STATUS_OK;
|
|
|
|
if (ps_parsing != XML_SUSPENDED) {
|
|
errorCode = XML_ERROR_NOT_SUSPENDED;
|
|
return XML_STATUS_ERROR;
|
|
}
|
|
ps_parsing = XML_PARSING;
|
|
|
|
errorCode = processor(parser, bufferPtr, parseEndPtr, &bufferPtr);
|
|
|
|
if (errorCode != XML_ERROR_NONE) {
|
|
eventEndPtr = eventPtr;
|
|
processor = errorProcessor;
|
|
return XML_STATUS_ERROR;
|
|
}
|
|
else {
|
|
switch (ps_parsing) {
|
|
case XML_SUSPENDED:
|
|
result = XML_STATUS_SUSPENDED;
|
|
break;
|
|
case XML_INITIALIZED:
|
|
case XML_PARSING:
|
|
if (ps_finalBuffer) {
|
|
ps_parsing = XML_FINISHED;
|
|
return result;
|
|
}
|
|
default: ;
|
|
}
|
|
}
|
|
|
|
XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position);
|
|
positionPtr = bufferPtr;
|
|
return result;
|
|
}
|
|
|
|
void XMLCALL
|
|
XML_GetParsingStatus(XML_Parser parser, XML_ParsingStatus *status)
|
|
{
|
|
assert(status != NULL);
|
|
*status = parser->m_parsingStatus;
|
|
}
|
|
|
|
enum XML_Error XMLCALL
|
|
XML_GetErrorCode(XML_Parser parser)
|
|
{
|
|
return errorCode;
|
|
}
|
|
|
|
XML_Index XMLCALL
|
|
XML_GetCurrentByteIndex(XML_Parser parser)
|
|
{
|
|
if (eventPtr)
|
|
return parseEndByteIndex - (parseEndPtr - eventPtr);
|
|
return -1;
|
|
}
|
|
|
|
int XMLCALL
|
|
XML_GetCurrentByteCount(XML_Parser parser)
|
|
{
|
|
if (eventEndPtr && eventPtr)
|
|
return (int)(eventEndPtr - eventPtr);
|
|
return 0;
|
|
}
|
|
|
|
const char * XMLCALL
|
|
XML_GetInputContext(XML_Parser parser, int *offset, int *size)
|
|
{
|
|
#ifdef XML_CONTEXT_BYTES
|
|
if (eventPtr && buffer) {
|
|
*offset = (int)(eventPtr - buffer);
|
|
*size = (int)(bufferEnd - buffer);
|
|
return buffer;
|
|
}
|
|
#endif /* defined XML_CONTEXT_BYTES */
|
|
return (char *) 0;
|
|
}
|
|
|
|
XML_Size XMLCALL
|
|
XML_GetCurrentLineNumber(XML_Parser parser)
|
|
{
|
|
if (eventPtr && eventPtr >= positionPtr) {
|
|
XmlUpdatePosition(encoding, positionPtr, eventPtr, &position);
|
|
positionPtr = eventPtr;
|
|
}
|
|
return position.lineNumber + 1;
|
|
}
|
|
|
|
XML_Size XMLCALL
|
|
XML_GetCurrentColumnNumber(XML_Parser parser)
|
|
{
|
|
if (eventPtr && eventPtr >= positionPtr) {
|
|
XmlUpdatePosition(encoding, positionPtr, eventPtr, &position);
|
|
positionPtr = eventPtr;
|
|
}
|
|
return position.columnNumber;
|
|
}
|
|
|
|
void XMLCALL
|
|
XML_FreeContentModel(XML_Parser parser, XML_Content *model)
|
|
{
|
|
FREE(model);
|
|
}
|
|
|
|
void * XMLCALL
|
|
XML_MemMalloc(XML_Parser parser, size_t size)
|
|
{
|
|
return MALLOC(size);
|
|
}
|
|
|
|
void * XMLCALL
|
|
XML_MemRealloc(XML_Parser parser, void *ptr, size_t size)
|
|
{
|
|
return REALLOC(ptr, size);
|
|
}
|
|
|
|
void XMLCALL
|
|
XML_MemFree(XML_Parser parser, void *ptr)
|
|
{
|
|
FREE(ptr);
|
|
}
|
|
|
|
void XMLCALL
|
|
XML_DefaultCurrent(XML_Parser parser)
|
|
{
|
|
if (defaultHandler) {
|
|
if (openInternalEntities)
|
|
reportDefault(parser,
|
|
internalEncoding,
|
|
openInternalEntities->internalEventPtr,
|
|
openInternalEntities->internalEventEndPtr);
|
|
else
|
|
reportDefault(parser, encoding, eventPtr, eventEndPtr);
|
|
}
|
|
}
|
|
|
|
const XML_LChar * XMLCALL
|
|
XML_ErrorString(enum XML_Error code)
|
|
{
|
|
static const XML_LChar* const message[] = {
|
|
0,
|
|
XML_L("out of memory"),
|
|
XML_L("syntax error"),
|
|
XML_L("no element found"),
|
|
XML_L("not well-formed (invalid token)"),
|
|
XML_L("unclosed token"),
|
|
XML_L("partial character"),
|
|
XML_L("mismatched tag"),
|
|
XML_L("duplicate attribute"),
|
|
XML_L("junk after document element"),
|
|
XML_L("illegal parameter entity reference"),
|
|
XML_L("undefined entity"),
|
|
XML_L("recursive entity reference"),
|
|
XML_L("asynchronous entity"),
|
|
XML_L("reference to invalid character number"),
|
|
XML_L("reference to binary entity"),
|
|
XML_L("reference to external entity in attribute"),
|
|
XML_L("XML or text declaration not at start of entity"),
|
|
XML_L("unknown encoding"),
|
|
XML_L("encoding specified in XML declaration is incorrect"),
|
|
XML_L("unclosed CDATA section"),
|
|
XML_L("error in processing external entity reference"),
|
|
XML_L("document is not standalone"),
|
|
XML_L("unexpected parser state - please send a bug report"),
|
|
XML_L("entity declared in parameter entity"),
|
|
XML_L("requested feature requires XML_DTD support in Expat"),
|
|
XML_L("cannot change setting once parsing has begun"),
|
|
XML_L("unbound prefix"),
|
|
XML_L("must not undeclare prefix"),
|
|
XML_L("incomplete markup in parameter entity"),
|
|
XML_L("XML declaration not well-formed"),
|
|
XML_L("text declaration not well-formed"),
|
|
XML_L("illegal character(s) in public id"),
|
|
XML_L("parser suspended"),
|
|
XML_L("parser not suspended"),
|
|
XML_L("parsing aborted"),
|
|
XML_L("parsing finished"),
|
|
XML_L("cannot suspend in external parameter entity"),
|
|
XML_L("reserved prefix (xml) must not be undeclared or bound to another namespace name"),
|
|
XML_L("reserved prefix (xmlns) must not be declared or undeclared"),
|
|
XML_L("prefix must not be bound to one of the reserved namespace names")
|
|
};
|
|
if (code > 0 && code < sizeof(message)/sizeof(message[0]))
|
|
return message[code];
|
|
return NULL;
|
|
}
|
|
|
|
const XML_LChar * XMLCALL
|
|
XML_ExpatVersion(void) {
|
|
|
|
/* V1 is used to string-ize the version number. However, it would
|
|
string-ize the actual version macro *names* unless we get them
|
|
substituted before being passed to V1. CPP is defined to expand
|
|
a macro, then rescan for more expansions. Thus, we use V2 to expand
|
|
the version macros, then CPP will expand the resulting V1() macro
|
|
with the correct numerals. */
|
|
/* ### I'm assuming cpp is portable in this respect... */
|
|
|
|
#define V1(a,b,c) XML_L(#a)XML_L(".")XML_L(#b)XML_L(".")XML_L(#c)
|
|
#define V2(a,b,c) XML_L("expat_")V1(a,b,c)
|
|
|
|
return V2(XML_MAJOR_VERSION, XML_MINOR_VERSION, XML_MICRO_VERSION);
|
|
|
|
#undef V1
|
|
#undef V2
|
|
}
|
|
|
|
XML_Expat_Version XMLCALL
|
|
XML_ExpatVersionInfo(void)
|
|
{
|
|
XML_Expat_Version version;
|
|
|
|
version.major = XML_MAJOR_VERSION;
|
|
version.minor = XML_MINOR_VERSION;
|
|
version.micro = XML_MICRO_VERSION;
|
|
|
|
return version;
|
|
}
|
|
|
|
const XML_Feature * XMLCALL
|
|
XML_GetFeatureList(void)
|
|
{
|
|
static const XML_Feature features[] = {
|
|
{XML_FEATURE_SIZEOF_XML_CHAR, XML_L("sizeof(XML_Char)"),
|
|
sizeof(XML_Char)},
|
|
{XML_FEATURE_SIZEOF_XML_LCHAR, XML_L("sizeof(XML_LChar)"),
|
|
sizeof(XML_LChar)},
|
|
#ifdef XML_UNICODE
|
|
{XML_FEATURE_UNICODE, XML_L("XML_UNICODE"), 0},
|
|
#endif
|
|
#ifdef XML_UNICODE_WCHAR_T
|
|
{XML_FEATURE_UNICODE_WCHAR_T, XML_L("XML_UNICODE_WCHAR_T"), 0},
|
|
#endif
|
|
#ifdef XML_DTD
|
|
{XML_FEATURE_DTD, XML_L("XML_DTD"), 0},
|
|
#endif
|
|
#ifdef XML_CONTEXT_BYTES
|
|
{XML_FEATURE_CONTEXT_BYTES, XML_L("XML_CONTEXT_BYTES"),
|
|
XML_CONTEXT_BYTES},
|
|
#endif
|
|
#ifdef XML_MIN_SIZE
|
|
{XML_FEATURE_MIN_SIZE, XML_L("XML_MIN_SIZE"), 0},
|
|
#endif
|
|
#ifdef XML_NS
|
|
{XML_FEATURE_NS, XML_L("XML_NS"), 0},
|
|
#endif
|
|
#ifdef XML_LARGE_SIZE
|
|
{XML_FEATURE_LARGE_SIZE, XML_L("XML_LARGE_SIZE"), 0},
|
|
#endif
|
|
{XML_FEATURE_END, NULL, 0}
|
|
};
|
|
|
|
return features;
|
|
}
|
|
|
|
/* Initially tag->rawName always points into the parse buffer;
|
|
for those TAG instances opened while the current parse buffer was
|
|
processed, and not yet closed, we need to store tag->rawName in a more
|
|
permanent location, since the parse buffer is about to be discarded.
|
|
*/
|
|
static XML_Bool
|
|
storeRawNames(XML_Parser parser)
|
|
{
|
|
TAG *tag = tagStack;
|
|
while (tag) {
|
|
int bufSize;
|
|
int nameLen = sizeof(XML_Char) * (tag->name.strLen + 1);
|
|
char *rawNameBuf = tag->buf + nameLen;
|
|
/* Stop if already stored. Since tagStack is a stack, we can stop
|
|
at the first entry that has already been copied; everything
|
|
below it in the stack is already been accounted for in a
|
|
previous call to this function.
|
|
*/
|
|
if (tag->rawName == rawNameBuf)
|
|
break;
|
|
/* For re-use purposes we need to ensure that the
|
|
size of tag->buf is a multiple of sizeof(XML_Char).
|
|
*/
|
|
bufSize = nameLen + ROUND_UP(tag->rawNameLength, sizeof(XML_Char));
|
|
if (bufSize > tag->bufEnd - tag->buf) {
|
|
char *temp = (char *)REALLOC(tag->buf, bufSize);
|
|
if (temp == NULL)
|
|
return XML_FALSE;
|
|
/* if tag->name.str points to tag->buf (only when namespace
|
|
processing is off) then we have to update it
|
|
*/
|
|
if (tag->name.str == (XML_Char *)tag->buf)
|
|
tag->name.str = (XML_Char *)temp;
|
|
/* if tag->name.localPart is set (when namespace processing is on)
|
|
then update it as well, since it will always point into tag->buf
|
|
*/
|
|
if (tag->name.localPart)
|
|
tag->name.localPart = (XML_Char *)temp + (tag->name.localPart -
|
|
(XML_Char *)tag->buf);
|
|
tag->buf = temp;
|
|
tag->bufEnd = temp + bufSize;
|
|
rawNameBuf = temp + nameLen;
|
|
}
|
|
memcpy(rawNameBuf, tag->rawName, tag->rawNameLength);
|
|
tag->rawName = rawNameBuf;
|
|
tag = tag->parent;
|
|
}
|
|
return XML_TRUE;
|
|
}
|
|
|
|
static enum XML_Error PTRCALL
|
|
contentProcessor(XML_Parser parser,
|
|
const char *start,
|
|
const char *end,
|
|
const char **endPtr)
|
|
{
|
|
enum XML_Error result = doContent(parser, 0, encoding, start, end,
|
|
endPtr, (XML_Bool)!ps_finalBuffer);
|
|
if (result == XML_ERROR_NONE) {
|
|
if (!storeRawNames(parser))
|
|
return XML_ERROR_NO_MEMORY;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static enum XML_Error PTRCALL
|
|
externalEntityInitProcessor(XML_Parser parser,
|
|
const char *start,
|
|
const char *end,
|
|
const char **endPtr)
|
|
{
|
|
enum XML_Error result = initializeEncoding(parser);
|
|
if (result != XML_ERROR_NONE)
|
|
return result;
|
|
processor = externalEntityInitProcessor2;
|
|
return externalEntityInitProcessor2(parser, start, end, endPtr);
|
|
}
|
|
|
|
static enum XML_Error PTRCALL
|
|
externalEntityInitProcessor2(XML_Parser parser,
|
|
const char *start,
|
|
const char *end,
|
|
const char **endPtr)
|
|
{
|
|
const char *next = start; /* XmlContentTok doesn't always set the last arg */
|
|
int tok = XmlContentTok(encoding, start, end, &next);
|
|
switch (tok) {
|
|
case XML_TOK_BOM:
|
|
/* If we are at the end of the buffer, this would cause the next stage,
|
|
i.e. externalEntityInitProcessor3, to pass control directly to
|
|
doContent (by detecting XML_TOK_NONE) without processing any xml text
|
|
declaration - causing the error XML_ERROR_MISPLACED_XML_PI in doContent.
|
|
*/
|
|
if (next == end && !ps_finalBuffer) {
|
|
*endPtr = next;
|
|
return XML_ERROR_NONE;
|
|
}
|
|
start = next;
|
|
break;
|
|
case XML_TOK_PARTIAL:
|
|
if (!ps_finalBuffer) {
|
|
*endPtr = start;
|
|
return XML_ERROR_NONE;
|
|
}
|
|
eventPtr = start;
|
|
return XML_ERROR_UNCLOSED_TOKEN;
|
|
case XML_TOK_PARTIAL_CHAR:
|
|
if (!ps_finalBuffer) {
|
|
*endPtr = start;
|
|
return XML_ERROR_NONE;
|
|
}
|
|
eventPtr = start;
|
|
return XML_ERROR_PARTIAL_CHAR;
|
|
}
|
|
processor = externalEntityInitProcessor3;
|
|
return externalEntityInitProcessor3(parser, start, end, endPtr);
|
|
}
|
|
|
|
static enum XML_Error PTRCALL
|
|
externalEntityInitProcessor3(XML_Parser parser,
|
|
const char *start,
|
|
const char *end,
|
|
const char **endPtr)
|
|
{
|
|
int tok;
|
|
const char *next = start; /* XmlContentTok doesn't always set the last arg */
|
|
eventPtr = start;
|
|
tok = XmlContentTok(encoding, start, end, &next);
|
|
eventEndPtr = next;
|
|
|
|
switch (tok) {
|
|
case XML_TOK_XML_DECL:
|
|
{
|
|
enum XML_Error result;
|
|
result = processXmlDecl(parser, 1, start, next);
|
|
if (result != XML_ERROR_NONE)
|
|
return result;
|
|
switch (ps_parsing) {
|
|
case XML_SUSPENDED:
|
|
*endPtr = next;
|
|
return XML_ERROR_NONE;
|
|
case XML_FINISHED:
|
|
return XML_ERROR_ABORTED;
|
|
default:
|
|
start = next;
|
|
}
|
|
}
|
|
break;
|
|
case XML_TOK_PARTIAL:
|
|
if (!ps_finalBuffer) {
|
|
*endPtr = start;
|
|
return XML_ERROR_NONE;
|
|
}
|
|
return XML_ERROR_UNCLOSED_TOKEN;
|
|
case XML_TOK_PARTIAL_CHAR:
|
|
if (!ps_finalBuffer) {
|
|
*endPtr = start;
|
|
return XML_ERROR_NONE;
|
|
}
|
|
return XML_ERROR_PARTIAL_CHAR;
|
|
}
|
|
processor = externalEntityContentProcessor;
|
|
tagLevel = 1;
|
|
return externalEntityContentProcessor(parser, start, end, endPtr);
|
|
}
|
|
|
|
static enum XML_Error PTRCALL
|
|
externalEntityContentProcessor(XML_Parser parser,
|
|
const char *start,
|
|
const char *end,
|
|
const char **endPtr)
|
|
{
|
|
enum XML_Error result = doContent(parser, 1, encoding, start, end,
|
|
endPtr, (XML_Bool)!ps_finalBuffer);
|
|
if (result == XML_ERROR_NONE) {
|
|
if (!storeRawNames(parser))
|
|
return XML_ERROR_NO_MEMORY;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static enum XML_Error
|
|
doContent(XML_Parser parser,
|
|
int startTagLevel,
|
|
const ENCODING *enc,
|
|
const char *s,
|
|
const char *end,
|
|
const char **nextPtr,
|
|
XML_Bool haveMore)
|
|
{
|
|
/* save one level of indirection */
|
|
DTD * const dtd = _dtd;
|
|
|
|
const char **eventPP;
|
|
const char **eventEndPP;
|
|
if (enc == encoding) {
|
|
eventPP = &eventPtr;
|
|
eventEndPP = &eventEndPtr;
|
|
}
|
|
else {
|
|
eventPP = &(openInternalEntities->internalEventPtr);
|
|
eventEndPP = &(openInternalEntities->internalEventEndPtr);
|
|
}
|
|
*eventPP = s;
|
|
|
|
for (;;) {
|
|
const char *next = s; /* XmlContentTok doesn't always set the last arg */
|
|
int tok = XmlContentTok(enc, s, end, &next);
|
|
*eventEndPP = next;
|
|
switch (tok) {
|
|
case XML_TOK_TRAILING_CR:
|
|
if (haveMore) {
|
|
*nextPtr = s;
|
|
return XML_ERROR_NONE;
|
|
}
|
|
*eventEndPP = end;
|
|
if (characterDataHandler) {
|
|
XML_Char c = 0xA;
|
|
characterDataHandler(handlerArg, &c, 1);
|
|
}
|
|
else if (defaultHandler)
|
|
reportDefault(parser, enc, s, end);
|
|
/* We are at the end of the final buffer, should we check for
|
|
XML_SUSPENDED, XML_FINISHED?
|
|
*/
|
|
if (startTagLevel == 0)
|
|
return XML_ERROR_NO_ELEMENTS;
|
|
if (tagLevel != startTagLevel)
|
|
return XML_ERROR_ASYNC_ENTITY;
|
|
*nextPtr = end;
|
|
return XML_ERROR_NONE;
|
|
case XML_TOK_NONE:
|
|
if (haveMore) {
|
|
*nextPtr = s;
|
|
return XML_ERROR_NONE;
|
|
}
|
|
if (startTagLevel > 0) {
|
|
if (tagLevel != startTagLevel)
|
|
return XML_ERROR_ASYNC_ENTITY;
|
|
*nextPtr = s;
|
|
return XML_ERROR_NONE;
|
|
}
|
|
return XML_ERROR_NO_ELEMENTS;
|
|
case XML_TOK_INVALID:
|
|
*eventPP = next;
|
|
return XML_ERROR_INVALID_TOKEN;
|
|
case XML_TOK_PARTIAL:
|
|
if (haveMore) {
|
|
*nextPtr = s;
|
|
return XML_ERROR_NONE;
|
|
}
|
|
return XML_ERROR_UNCLOSED_TOKEN;
|
|
case XML_TOK_PARTIAL_CHAR:
|
|
if (haveMore) {
|
|
*nextPtr = s;
|
|
return XML_ERROR_NONE;
|
|
}
|
|
return XML_ERROR_PARTIAL_CHAR;
|
|
case XML_TOK_ENTITY_REF:
|
|
{
|
|
const XML_Char *name;
|
|
ENTITY *entity;
|
|
XML_Char ch = (XML_Char) XmlPredefinedEntityName(enc,
|
|
s + enc->minBytesPerChar,
|
|
next - enc->minBytesPerChar);
|
|
if (ch) {
|
|
if (characterDataHandler)
|
|
characterDataHandler(handlerArg, &ch, 1);
|
|
else if (defaultHandler)
|
|
reportDefault(parser, enc, s, next);
|
|
break;
|
|
}
|
|
name = poolStoreString(&dtd->pool, enc,
|
|
s + enc->minBytesPerChar,
|
|
next - enc->minBytesPerChar);
|
|
if (!name)
|
|
return XML_ERROR_NO_MEMORY;
|
|
entity = (ENTITY *)lookup(&dtd->generalEntities, name, 0);
|
|
poolDiscard(&dtd->pool);
|
|
/* First, determine if a check for an existing declaration is needed;
|
|
if yes, check that the entity exists, and that it is internal,
|
|
otherwise call the skipped entity or default handler.
|
|
*/
|
|
if (!dtd->hasParamEntityRefs || dtd->standalone) {
|
|
if (!entity)
|
|
return XML_ERROR_UNDEFINED_ENTITY;
|
|
else if (!entity->is_internal)
|
|
return XML_ERROR_ENTITY_DECLARED_IN_PE;
|
|
}
|
|
else if (!entity) {
|
|
if (skippedEntityHandler)
|
|
skippedEntityHandler(handlerArg, name, 0);
|
|
else if (defaultHandler)
|
|
reportDefault(parser, enc, s, next);
|
|
break;
|
|
}
|
|
if (entity->open)
|
|
return XML_ERROR_RECURSIVE_ENTITY_REF;
|
|
if (entity->notation)
|
|
return XML_ERROR_BINARY_ENTITY_REF;
|
|
if (entity->textPtr) {
|
|
enum XML_Error result;
|
|
if (!defaultExpandInternalEntities) {
|
|
if (skippedEntityHandler)
|
|
skippedEntityHandler(handlerArg, entity->name, 0);
|
|
else if (defaultHandler)
|
|
reportDefault(parser, enc, s, next);
|
|
break;
|
|
}
|
|
result = processInternalEntity(parser, entity, XML_FALSE);
|
|
if (result != XML_ERROR_NONE)
|
|
return result;
|
|
}
|
|
else if (externalEntityRefHandler) {
|
|
const XML_Char *context;
|
|
entity->open = XML_TRUE;
|
|
context = getContext(parser);
|
|
entity->open = XML_FALSE;
|
|
if (!context)
|
|
return XML_ERROR_NO_MEMORY;
|
|
if (!externalEntityRefHandler(externalEntityRefHandlerArg,
|
|
context,
|
|
entity->base,
|
|
entity->systemId,
|
|
entity->publicId))
|
|
return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
|
|
poolDiscard(&tempPool);
|
|
}
|
|
else if (defaultHandler)
|
|
reportDefault(parser, enc, s, next);
|
|
break;
|
|
}
|
|
case XML_TOK_START_TAG_NO_ATTS:
|
|
/* fall through */
|
|
case XML_TOK_START_TAG_WITH_ATTS:
|
|
{
|
|
TAG *tag;
|
|
enum XML_Error result;
|
|
XML_Char *toPtr;
|
|
if (freeTagList) {
|
|
tag = freeTagList;
|
|
freeTagList = freeTagList->parent;
|
|
}
|
|
else {
|
|
tag = (TAG *)MALLOC(sizeof(TAG));
|
|
if (!tag)
|
|
return XML_ERROR_NO_MEMORY;
|
|
tag->buf = (char *)MALLOC(INIT_TAG_BUF_SIZE);
|
|
if (!tag->buf) {
|
|
FREE(tag);
|
|
return XML_ERROR_NO_MEMORY;
|
|
}
|
|
tag->bufEnd = tag->buf + INIT_TAG_BUF_SIZE;
|
|
}
|
|
tag->bindings = NULL;
|
|
tag->parent = tagStack;
|
|
tagStack = tag;
|
|
tag->name.localPart = NULL;
|
|
tag->name.prefix = NULL;
|
|
tag->rawName = s + enc->minBytesPerChar;
|
|
tag->rawNameLength = XmlNameLength(enc, tag->rawName);
|
|
++tagLevel;
|
|
{
|
|
const char *rawNameEnd = tag->rawName + tag->rawNameLength;
|
|
const char *fromPtr = tag->rawName;
|
|
toPtr = (XML_Char *)tag->buf;
|
|
for (;;) {
|
|
int bufSize;
|
|
int convLen;
|
|
XmlConvert(enc,
|
|
&fromPtr, rawNameEnd,
|
|
(ICHAR **)&toPtr, (ICHAR *)tag->bufEnd - 1);
|
|
convLen = (int)(toPtr - (XML_Char *)tag->buf);
|
|
if (fromPtr == rawNameEnd) {
|
|
tag->name.strLen = convLen;
|
|
break;
|
|
}
|
|
bufSize = (int)(tag->bufEnd - tag->buf) << 1;
|
|
{
|
|
char *temp = (char *)REALLOC(tag->buf, bufSize);
|
|
if (temp == NULL)
|
|
return XML_ERROR_NO_MEMORY;
|
|
tag->buf = temp;
|
|
tag->bufEnd = temp + bufSize;
|
|
toPtr = (XML_Char *)temp + convLen;
|
|
}
|
|
}
|
|
}
|
|
tag->name.str = (XML_Char *)tag->buf;
|
|
*toPtr = XML_T('\0');
|
|
result = storeAtts(parser, enc, s, &(tag->name), &(tag->bindings));
|
|
if (result)
|
|
return result;
|
|
if (startElementHandler)
|
|
startElementHandler(handlerArg, tag->name.str,
|
|
(const XML_Char **)atts);
|
|
else if (defaultHandler)
|
|
reportDefault(parser, enc, s, next);
|
|
poolClear(&tempPool);
|
|
break;
|
|
}
|
|
case XML_TOK_EMPTY_ELEMENT_NO_ATTS:
|
|
/* fall through */
|
|
case XML_TOK_EMPTY_ELEMENT_WITH_ATTS:
|
|
{
|
|
const char *rawName = s + enc->minBytesPerChar;
|
|
enum XML_Error result;
|
|
BINDING *bindings = NULL;
|
|
XML_Bool noElmHandlers = XML_TRUE;
|
|
TAG_NAME name;
|
|
name.str = poolStoreString(&tempPool, enc, rawName,
|
|
rawName + XmlNameLength(enc, rawName));
|
|
if (!name.str)
|
|
return XML_ERROR_NO_MEMORY;
|
|
poolFinish(&tempPool);
|
|
result = storeAtts(parser, enc, s, &name, &bindings);
|
|
if (result)
|
|
return result;
|
|
poolFinish(&tempPool);
|
|
if (startElementHandler) {
|
|
startElementHandler(handlerArg, name.str, (const XML_Char **)atts);
|
|
noElmHandlers = XML_FALSE;
|
|
}
|
|
if (endElementHandler) {
|
|
if (startElementHandler)
|
|
*eventPP = *eventEndPP;
|
|
endElementHandler(handlerArg, name.str);
|
|
noElmHandlers = XML_FALSE;
|
|
}
|
|
if (noElmHandlers && defaultHandler)
|
|
reportDefault(parser, enc, s, next);
|
|
poolClear(&tempPool);
|
|
while (bindings) {
|
|
BINDING *b = bindings;
|
|
if (endNamespaceDeclHandler)
|
|
endNamespaceDeclHandler(handlerArg, b->prefix->name);
|
|
bindings = bindings->nextTagBinding;
|
|
b->nextTagBinding = freeBindingList;
|
|
freeBindingList = b;
|
|
b->prefix->binding = b->prevPrefixBinding;
|
|
}
|
|
}
|
|
if (tagLevel == 0)
|
|
return epilogProcessor(parser, next, end, nextPtr);
|
|
break;
|
|
case XML_TOK_END_TAG:
|
|
if (tagLevel == startTagLevel)
|
|
return XML_ERROR_ASYNC_ENTITY;
|
|
else {
|
|
int len;
|
|
const char *rawName;
|
|
TAG *tag = tagStack;
|
|
tagStack = tag->parent;
|
|
tag->parent = freeTagList;
|
|
freeTagList = tag;
|
|
rawName = s + enc->minBytesPerChar*2;
|
|
len = XmlNameLength(enc, rawName);
|
|
if (len != tag->rawNameLength
|
|
|| memcmp(tag->rawName, rawName, len) != 0) {
|
|
*eventPP = rawName;
|
|
return XML_ERROR_TAG_MISMATCH;
|
|
}
|
|
--tagLevel;
|
|
if (endElementHandler) {
|
|
const XML_Char *localPart;
|
|
const XML_Char *prefix;
|
|
XML_Char *uri;
|
|
localPart = tag->name.localPart;
|
|
if (ns && localPart) {
|
|
/* localPart and prefix may have been overwritten in
|
|
tag->name.str, since this points to the binding->uri
|
|
buffer which gets re-used; so we have to add them again
|
|
*/
|
|
uri = (XML_Char *)tag->name.str + tag->name.uriLen;
|
|
/* don't need to check for space - already done in storeAtts() */
|
|
while (*localPart) *uri++ = *localPart++;
|
|
prefix = (XML_Char *)tag->name.prefix;
|
|
if (ns_triplets && prefix) {
|
|
*uri++ = namespaceSeparator;
|
|
while (*prefix) *uri++ = *prefix++;
|
|
}
|
|
*uri = XML_T('\0');
|
|
}
|
|
endElementHandler(handlerArg, tag->name.str);
|
|
}
|
|
else if (defaultHandler)
|
|
reportDefault(parser, enc, s, next);
|
|
while (tag->bindings) {
|
|
BINDING *b = tag->bindings;
|
|
if (endNamespaceDeclHandler)
|
|
endNamespaceDeclHandler(handlerArg, b->prefix->name);
|
|
tag->bindings = tag->bindings->nextTagBinding;
|
|
b->nextTagBinding = freeBindingList;
|
|
freeBindingList = b;
|
|
b->prefix->binding = b->prevPrefixBinding;
|
|
}
|
|
if (tagLevel == 0)
|
|
return epilogProcessor(parser, next, end, nextPtr);
|
|
}
|
|
break;
|
|
case XML_TOK_CHAR_REF:
|
|
{
|
|
int n = XmlCharRefNumber(enc, s);
|
|
if (n < 0)
|
|
return XML_ERROR_BAD_CHAR_REF;
|
|
if (characterDataHandler) {
|
|
XML_Char buf[XML_ENCODE_MAX];
|
|
characterDataHandler(handlerArg, buf, XmlEncode(n, (ICHAR *)buf));
|
|
}
|
|
else if (defaultHandler)
|
|
reportDefault(parser, enc, s, next);
|
|
}
|
|
break;
|
|
case XML_TOK_XML_DECL:
|
|
return XML_ERROR_MISPLACED_XML_PI;
|
|
case XML_TOK_DATA_NEWLINE:
|
|
if (characterDataHandler) {
|
|
XML_Char c = 0xA;
|
|
characterDataHandler(handlerArg, &c, 1);
|
|
}
|
|
else if (defaultHandler)
|
|
reportDefault(parser, enc, s, next);
|
|
break;
|
|
case XML_TOK_CDATA_SECT_OPEN:
|
|
{
|
|
enum XML_Error result;
|
|
if (startCdataSectionHandler)
|
|
startCdataSectionHandler(handlerArg);
|
|
#if 0
|
|
/* Suppose you doing a transformation on a document that involves
|
|
changing only the character data. You set up a defaultHandler
|
|
and a characterDataHandler. The defaultHandler simply copies
|
|
characters through. The characterDataHandler does the
|
|
transformation and writes the characters out escaping them as
|
|
necessary. This case will fail to work if we leave out the
|
|
following two lines (because & and < inside CDATA sections will
|
|
be incorrectly escaped).
|
|
|
|
However, now we have a start/endCdataSectionHandler, so it seems
|
|
easier to let the user deal with this.
|
|
*/
|
|
else if (characterDataHandler)
|
|
characterDataHandler(handlerArg, dataBuf, 0);
|
|
#endif
|
|
else if (defaultHandler)
|
|
reportDefault(parser, enc, s, next);
|
|
result = doCdataSection(parser, enc, &next, end, nextPtr, haveMore);
|
|
if (result != XML_ERROR_NONE)
|
|
return result;
|
|
else if (!next) {
|
|
processor = cdataSectionProcessor;
|
|
return result;
|
|
}
|
|
}
|
|
break;
|
|
case XML_TOK_TRAILING_RSQB:
|
|
if (haveMore) {
|
|
*nextPtr = s;
|
|
return XML_ERROR_NONE;
|
|
}
|
|
if (characterDataHandler) {
|
|
if (MUST_CONVERT(enc, s)) {
|
|
ICHAR *dataPtr = (ICHAR *)dataBuf;
|
|
XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)dataBufEnd);
|
|
characterDataHandler(handlerArg, dataBuf,
|
|
(int)(dataPtr - (ICHAR *)dataBuf));
|
|
}
|
|
else
|
|
characterDataHandler(handlerArg,
|
|
(XML_Char *)s,
|
|
(int)((XML_Char *)end - (XML_Char *)s));
|
|
}
|
|
else if (defaultHandler)
|
|
reportDefault(parser, enc, s, end);
|
|
/* We are at the end of the final buffer, should we check for
|
|
XML_SUSPENDED, XML_FINISHED?
|
|
*/
|
|
if (startTagLevel == 0) {
|
|
*eventPP = end;
|
|
return XML_ERROR_NO_ELEMENTS;
|
|
}
|
|
if (tagLevel != startTagLevel) {
|
|
*eventPP = end;
|
|
return XML_ERROR_ASYNC_ENTITY;
|
|
}
|
|
*nextPtr = end;
|
|
return XML_ERROR_NONE;
|
|
case XML_TOK_DATA_CHARS:
|
|
{
|
|
XML_CharacterDataHandler charDataHandler = characterDataHandler;
|
|
if (charDataHandler) {
|
|
if (MUST_CONVERT(enc, s)) {
|
|
for (;;) {
|
|
ICHAR *dataPtr = (ICHAR *)dataBuf;
|
|
XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd);
|
|
*eventEndPP = s;
|
|
charDataHandler(handlerArg, dataBuf,
|
|
(int)(dataPtr - (ICHAR *)dataBuf));
|
|
if (s == next)
|
|
break;
|
|
*eventPP = s;
|
|
}
|
|
}
|
|
else
|
|
charDataHandler(handlerArg,
|
|
(XML_Char *)s,
|
|
(int)((XML_Char *)next - (XML_Char *)s));
|
|
}
|
|
else if (defaultHandler)
|
|
reportDefault(parser, enc, s, next);
|
|
}
|
|
break;
|
|
case XML_TOK_PI:
|
|
if (!reportProcessingInstruction(parser, enc, s, next))
|
|
return XML_ERROR_NO_MEMORY;
|
|
break;
|
|
case XML_TOK_COMMENT:
|
|
if (!reportComment(parser, enc, s, next))
|
|
return XML_ERROR_NO_MEMORY;
|
|
break;
|
|
default:
|
|
if (defaultHandler)
|
|
reportDefault(parser, enc, s, next);
|
|
break;
|
|
}
|
|
*eventPP = s = next;
|
|
switch (ps_parsing) {
|
|
case XML_SUSPENDED:
|
|
*nextPtr = next;
|
|
return XML_ERROR_NONE;
|
|
case XML_FINISHED:
|
|
return XML_ERROR_ABORTED;
|
|
default: ;
|
|
}
|
|
}
|
|
/* not reached */
|
|
}
|
|
|
|
/* Precondition: all arguments must be non-NULL;
|
|
Purpose:
|
|
- normalize attributes
|
|
- check attributes for well-formedness
|
|
- generate namespace aware attribute names (URI, prefix)
|
|
- build list of attributes for startElementHandler
|
|
- default attributes
|
|
- process namespace declarations (check and report them)
|
|
- generate namespace aware element name (URI, prefix)
|
|
*/
|
|
static enum XML_Error
|
|
storeAtts(XML_Parser parser, const ENCODING *enc,
|
|
const char *attStr, TAG_NAME *tagNamePtr,
|
|
BINDING **bindingsPtr)
|
|
{
|
|
DTD * const dtd = _dtd; /* save one level of indirection */
|
|
ELEMENT_TYPE *elementType;
|
|
int nDefaultAtts;
|
|
const XML_Char **appAtts; /* the attribute list for the application */
|
|
int attIndex = 0;
|
|
int prefixLen;
|
|
int i;
|
|
int n;
|
|
XML_Char *uri;
|
|
int nPrefixes = 0;
|
|
BINDING *binding;
|
|
const XML_Char *localPart;
|
|
|
|
/* lookup the element type name */
|
|
elementType = (ELEMENT_TYPE *)lookup(&dtd->elementTypes, tagNamePtr->str,0);
|
|
if (!elementType) {
|
|
const XML_Char *name = poolCopyString(&dtd->pool, tagNamePtr->str);
|
|
if (!name)
|
|
return XML_ERROR_NO_MEMORY;
|
|
elementType = (ELEMENT_TYPE *)lookup(&dtd->elementTypes, name,
|
|
sizeof(ELEMENT_TYPE));
|
|
if (!elementType)
|
|
return XML_ERROR_NO_MEMORY;
|
|
if (ns && !setElementTypePrefix(parser, elementType))
|
|
return XML_ERROR_NO_MEMORY;
|
|
}
|
|
nDefaultAtts = elementType->nDefaultAtts;
|
|
|
|
/* get the attributes from the tokenizer */
|
|
n = XmlGetAttributes(enc, attStr, attsSize, atts);
|
|
if (n + nDefaultAtts > attsSize) {
|
|
int oldAttsSize = attsSize;
|
|
ATTRIBUTE *temp;
|
|
attsSize = n + nDefaultAtts + INIT_ATTS_SIZE;
|
|
temp = (ATTRIBUTE *)REALLOC((void *)atts, attsSize * sizeof(ATTRIBUTE));
|
|
if (temp == NULL)
|
|
return XML_ERROR_NO_MEMORY;
|
|
atts = temp;
|
|
if (n > oldAttsSize)
|
|
XmlGetAttributes(enc, attStr, n, atts);
|
|
}
|
|
|
|
appAtts = (const XML_Char **)atts;
|
|
for (i = 0; i < n; i++) {
|
|
/* add the name and value to the attribute list */
|
|
ATTRIBUTE_ID *attId = getAttributeId(parser, enc, atts[i].name,
|
|
atts[i].name
|
|
+ XmlNameLength(enc, atts[i].name));
|
|
if (!attId)
|
|
return XML_ERROR_NO_MEMORY;
|
|
/* Detect duplicate attributes by their QNames. This does not work when
|
|
namespace processing is turned on and different prefixes for the same
|
|
namespace are used. For this case we have a check further down.
|
|
*/
|
|
if ((attId->name)[-1]) {
|
|
if (enc == encoding)
|
|
eventPtr = atts[i].name;
|
|
return XML_ERROR_DUPLICATE_ATTRIBUTE;
|
|
}
|
|
(attId->name)[-1] = 1;
|
|
appAtts[attIndex++] = attId->name;
|
|
if (!atts[i].normalized) {
|
|
enum XML_Error result;
|
|
XML_Bool isCdata = XML_TRUE;
|
|
|
|
/* figure out whether declared as other than CDATA */
|
|
if (attId->maybeTokenized) {
|
|
int j;
|
|
for (j = 0; j < nDefaultAtts; j++) {
|
|
if (attId == elementType->defaultAtts[j].id) {
|
|
isCdata = elementType->defaultAtts[j].isCdata;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* normalize the attribute value */
|
|
result = storeAttributeValue(parser, enc, isCdata,
|
|
atts[i].valuePtr, atts[i].valueEnd,
|
|
&tempPool);
|
|
if (result)
|
|
return result;
|
|
appAtts[attIndex] = poolStart(&tempPool);
|
|
poolFinish(&tempPool);
|
|
}
|
|
else {
|
|
/* the value did not need normalizing */
|
|
appAtts[attIndex] = poolStoreString(&tempPool, enc, atts[i].valuePtr,
|
|
atts[i].valueEnd);
|
|
if (appAtts[attIndex] == 0)
|
|
return XML_ERROR_NO_MEMORY;
|
|
poolFinish(&tempPool);
|
|
}
|
|
/* handle prefixed attribute names */
|
|
if (attId->prefix) {
|
|
if (attId->xmlns) {
|
|
/* deal with namespace declarations here */
|
|
enum XML_Error result = addBinding(parser, attId->prefix, attId,
|
|
appAtts[attIndex], bindingsPtr);
|
|
if (result)
|
|
return result;
|
|
--attIndex;
|
|
}
|
|
else {
|
|
/* deal with other prefixed names later */
|
|
attIndex++;
|
|
nPrefixes++;
|
|
(attId->name)[-1] = 2;
|
|
}
|
|
}
|
|
else
|
|
attIndex++;
|
|
}
|
|
|
|
/* set-up for XML_GetSpecifiedAttributeCount and XML_GetIdAttributeIndex */
|
|
nSpecifiedAtts = attIndex;
|
|
if (elementType->idAtt && (elementType->idAtt->name)[-1]) {
|
|
for (i = 0; i < attIndex; i += 2)
|
|
if (appAtts[i] == elementType->idAtt->name) {
|
|
idAttIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
idAttIndex = -1;
|
|
|
|
/* do attribute defaulting */
|
|
for (i = 0; i < nDefaultAtts; i++) {
|
|
const DEFAULT_ATTRIBUTE *da = elementType->defaultAtts + i;
|
|
if (!(da->id->name)[-1] && da->value) {
|
|
if (da->id->prefix) {
|
|
if (da->id->xmlns) {
|
|
enum XML_Error result = addBinding(parser, da->id->prefix, da->id,
|
|
da->value, bindingsPtr);
|
|
if (result)
|
|
return result;
|
|
}
|
|
else {
|
|
(da->id->name)[-1] = 2;
|
|
nPrefixes++;
|
|
appAtts[attIndex++] = da->id->name;
|
|
appAtts[attIndex++] = da->value;
|
|
}
|
|
}
|
|
else {
|
|
(da->id->name)[-1] = 1;
|
|
appAtts[attIndex++] = da->id->name;
|
|
appAtts[attIndex++] = da->value;
|
|
}
|
|
}
|
|
}
|
|
appAtts[attIndex] = 0;
|
|
|
|
/* expand prefixed attribute names, check for duplicates,
|
|
and clear flags that say whether attributes were specified */
|
|
i = 0;
|
|
if (nPrefixes) {
|
|
int j; /* hash table index */
|
|
unsigned long version = nsAttsVersion;
|
|
int nsAttsSize = (int)1 << nsAttsPower;
|
|
/* size of hash table must be at least 2 * (# of prefixed attributes) */
|
|
if ((nPrefixes << 1) >> nsAttsPower) { /* true for nsAttsPower = 0 */
|
|
NS_ATT *temp;
|
|
/* hash table size must also be a power of 2 and >= 8 */
|
|
while (nPrefixes >> nsAttsPower++);
|
|
if (nsAttsPower < 3)
|
|
nsAttsPower = 3;
|
|
nsAttsSize = (int)1 << nsAttsPower;
|
|
temp = (NS_ATT *)REALLOC(nsAtts, nsAttsSize * sizeof(NS_ATT));
|
|
if (!temp)
|
|
return XML_ERROR_NO_MEMORY;
|
|
nsAtts = temp;
|
|
version = 0; /* force re-initialization of nsAtts hash table */
|
|
}
|
|
/* using a version flag saves us from initializing nsAtts every time */
|
|
if (!version) { /* initialize version flags when version wraps around */
|
|
version = INIT_ATTS_VERSION;
|
|
for (j = nsAttsSize; j != 0; )
|
|
nsAtts[--j].version = version;
|
|
}
|
|
nsAttsVersion = --version;
|
|
|
|
/* expand prefixed names and check for duplicates */
|
|
for (; i < attIndex; i += 2) {
|
|
const XML_Char *s = appAtts[i];
|
|
if (s[-1] == 2) { /* prefixed */
|
|
ATTRIBUTE_ID *id;
|
|
const BINDING *b;
|
|
unsigned long uriHash = 0;
|
|
((XML_Char *)s)[-1] = 0; /* clear flag */
|
|
id = (ATTRIBUTE_ID *)lookup(&dtd->attributeIds, s, 0);
|
|
b = id->prefix->binding;
|
|
if (!b)
|
|
return XML_ERROR_UNBOUND_PREFIX;
|
|
|
|
/* as we expand the name we also calculate its hash value */
|
|
for (j = 0; j < b->uriLen; j++) {
|
|
const XML_Char c = b->uri[j];
|
|
if (!poolAppendChar(&tempPool, c))
|
|
return XML_ERROR_NO_MEMORY;
|
|
uriHash = CHAR_HASH(uriHash, c);
|
|
}
|
|
while (*s++ != XML_T(ASCII_COLON))
|
|
;
|
|
do { /* copies null terminator */
|
|
const XML_Char c = *s;
|
|
if (!poolAppendChar(&tempPool, *s))
|
|
return XML_ERROR_NO_MEMORY;
|
|
uriHash = CHAR_HASH(uriHash, c);
|
|
} while (*s++);
|
|
|
|
{ /* Check hash table for duplicate of expanded name (uriName).
|
|
Derived from code in lookup(HASH_TABLE *table, ...).
|
|
*/
|
|
unsigned char step = 0;
|
|
unsigned long mask = nsAttsSize - 1;
|
|
j = uriHash & mask; /* index into hash table */
|
|
while (nsAtts[j].version == version) {
|
|
/* for speed we compare stored hash values first */
|
|
if (uriHash == nsAtts[j].hash) {
|
|
const XML_Char *s1 = poolStart(&tempPool);
|
|
const XML_Char *s2 = nsAtts[j].uriName;
|
|
/* s1 is null terminated, but not s2 */
|
|
for (; *s1 == *s2 && *s1 != 0; s1++, s2++);
|
|
if (*s1 == 0)
|
|
return XML_ERROR_DUPLICATE_ATTRIBUTE;
|
|
}
|
|
if (!step)
|
|
step = PROBE_STEP(uriHash, mask, nsAttsPower);
|
|
j < step ? (j += nsAttsSize - step) : (j - |