home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
xwphescr.zip
/
XWPH0208.ZIP
/
src
/
helpers
/
xmlparse.c
< prev
next >
Wrap
C/C++ Source or Header
|
2002-04-13
|
224KB
|
6,312 lines
/*
*@@sourcefile xmlparse.c:
* contains the API of the expat XML parser 1.95.2, as released on
* http://sourceforge.net/projects/expat/ on July 26, 2001.
*
* V1.95.1 was ported to and integrated with the xwphelpers
* for V0.9.9 (2001-02-10) [umoeller]. V1.95.2 was re-ported
* with V0.9.14 (2001-08-09) [umoeller].
*
* See xml.c for a general introduction to @XML support in the
* xwphelpers.
*
* Expat is a library, written in C, for parsing XML @documents. It's
* the underlying XML parser for the open source Mozilla project,
* perl's XML::Parser, and other open-source XML parsers.
*
* Expat was written by James Clark, who also wrote groff (an nroff
* look-alike), Jade (an implemention of ISO's DSSSL stylesheet
* language for SGML), XP (a Java XML parser package), XT (a Java
* XSL engine). He was also the technical lead on the XML Working
* Group at W3 that produced the XML specification.
*
* Most of this documentation is the original documentation
* that comes with expat as an HTML file. I (umoeller)
* have integrated the docs into the sources and added a
* couple of remarks while trying to implement parsers.
*
* See XML_ParserCreate for instructions how to parse XML.
*
* Note that expat is a non-validating XML processor. Validation
* is supported by the top layer of xwphelpers XML support. See
* xml.c.
*
*@@added V0.9.9 (2001-02-10) [umoeller]
*@@header "expat\expat.h"
*/
/*
* Copyright (C) 2001 Ulrich Möller.
* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd.
* and Clark Cooper.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*
*@@category: Helpers\XML\expat
* expat XML parser. See xmlparse.c.
*/
#include "setup.h"
#pragma info(norea, nogen)
// disable "statement unreachable" and "missing break statement"
// this code generates those options HEAVILY
/* #ifdef COMPILED_FROM_DSP
* # include "winconfig.h"
* # define XMLPARSEAPI(type) __declspec(dllexport) type __cdecl
* # include "expat.h"
* # undef XMLPARSEAPI
* #else
* #include <config.h> */
#ifdef __declspec
#define XMLPARSEAPI(type) __declspec(dllexport) type __cdecl
#endif
#include "expat\expat.h"
#ifdef __declspec
#undef XMLPARSEAPI
#endif
// #endif /* ndef COMPILED_FROM_DSP */
#include <stddef.h>
#include <string.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_WCHAR_T
#define XML_T(x) L ## x
#else
#define XML_T(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))
#include "expat\xmltok.h"
#include "expat\xmlrole.h"
typedef const XML_Char *KEY;
typedef struct
{
KEY name;
}
NAMED;
typedef struct
{
NAMED **v;
size_t size;
size_t used;
size_t usedLim;
XML_Memory_Handling_Suite *mem;
}
HASH_TABLE;
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_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;
int uriLen;
}
TAG_NAME;
typedef struct tag
{
struct tag *parent;
const char *rawName;
int rawNameLength;
TAG_NAME name;
char *buf;
char *bufEnd;
BINDING *bindings;
}
TAG;
typedef struct
{
const XML_Char *name;
const XML_Char *textPtr;
int textLen;
const XML_Char *systemId;
const XML_Char *base;
const XML_Char *publicId;
const XML_Char *notation;
char open;
char is_param;
}
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;
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;
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;
char maybeTokenized;
char xmlns;
}
ATTRIBUTE_ID;
typedef struct
{
const ATTRIBUTE_ID *id;
char isCdata;
const XML_Char *value;
}
DEFAULT_ATTRIBUTE;
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;
int complete;
int standalone;
#ifdef XML_DTD
HASH_TABLE paramEntities;
#endif /* XML_DTD */
PREFIX defaultPrefix;
/* === scaffolding for building content model === */
int 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;
}
OPEN_INTERNAL_ENTITY;
typedef XMLERROR 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;
#endif /* XML_DTD */
static Processor epilogProcessor;
static Processor errorProcessor;
static Processor externalEntityInitProcessor;
static Processor externalEntityInitProcessor2;
static Processor externalEntityInitProcessor3;
static Processor externalEntityContentProcessor;
static XMLERROR
handleUnknownEncoding(XML_Parser parser, const XML_Char * encodingName);
static XMLERROR
processXmlDecl(XML_Parser parser, int isGeneralTextEntity, const char *, const char *);
static XMLERROR
initializeEncoding(XML_Parser parser);
static XMLERROR
doProlog(XML_Parser parser, const ENCODING * enc, const char *s,
const char *end, int tok, const char *next, const char **nextPtr);
static XMLERROR
processInternalParamEntity(XML_Parser parser, ENTITY * entity);
static XMLERROR
doContent(XML_Parser parser, int startTagLevel, const ENCODING * enc,
const char *start, const char *end, const char **endPtr);
static XMLERROR
doCdataSection(XML_Parser parser, const ENCODING *, const char **startPtr, const char *end, const char **nextPtr);
#ifdef XML_DTD
static XMLERROR
doIgnoreSection(XML_Parser parser, const ENCODING *, const char **startPtr, const char *end, const char **nextPtr);
#endif /* XML_DTD */
static XMLERROR storeAtts(XML_Parser parser, const ENCODING *, const char *s,
TAG_NAME * tagNamePtr, BINDING ** bindingsPtr);
static
int addBinding(XML_Parser parser, PREFIX * prefix, const ATTRIBUTE_ID * attId, const XML_Char * uri, BINDING ** bindingsPtr);
static int
defineAttribute(ELEMENT_TYPE * type, ATTRIBUTE_ID *,
int isCdata, int isId, const XML_Char * dfltValue,
XML_Parser parser);
static XMLERROR
storeAttributeValue(XML_Parser parser, const ENCODING *, int isCdata, const char *, const char *,
STRING_POOL *);
static XMLERROR
appendAttributeValue(XML_Parser parser, const ENCODING *, int 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 XMLERROR
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 int setContext(XML_Parser parser, const XML_Char * context);
static void normalizePublicId(XML_Char * s);
static int dtdInit(DTD *, XML_Parser parser);
static void dtdDestroy(DTD *, XML_Parser parser);
static int dtdCopy(DTD * newDtd, const DTD * oldDtd, XML_Parser parser);
static int copyEntityTable(HASH_TABLE *, STRING_POOL *, const HASH_TABLE *,
XML_Parser parser);
#ifdef XML_DTD
static void dtdSwap(DTD *, DTD *);
#endif /* XML_DTD */
static NAMED *lookup(HASH_TABLE * table, KEY name, size_t createSize);
static void hashTableInit(HASH_TABLE *, XML_Memory_Handling_Suite * ms);
static void hashTableDestroy(HASH_TABLE *);
static void hashTableIterInit(HASH_TABLE_ITER *, const HASH_TABLE *);
static NAMED *hashTableIterNext(HASH_TABLE_ITER *);
static void poolInit(STRING_POOL *, XML_Memory_Handling_Suite * ms);
static void poolClear(STRING_POOL *);
static void poolDestroy(STRING_POOL *);
static XML_Char *poolAppend(STRING_POOL *pool,
const ENCODING *enc,
const char *ptr,
const char *end,
unsigned long *pulOfs); // V0.9.14 (2001-08-09) [umoeller]
static XML_Char *poolStoreString(STRING_POOL *pool,
const ENCODING *enc,
const char *ptr,
const char *end,
unsigned long *pulOfs); // V0.9.14 (2001-08-09) [umoeller]
static int poolGrow(STRING_POOL * pool);
static int nextScaffoldPart(XML_Parser parser);
static XMLCONTENT *build_model(XML_Parser parser);
static const XML_Char *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 *poolAppendString(STRING_POOL * pool, const XML_Char * s);
static ELEMENT_TYPE *getElementType(XML_Parser Paraser,
const ENCODING * enc,
const char *ptr,
const char *end);
#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))
typedef struct
{
/* The first member must be userData so that the XML_GetUserData macro works. */
void *m_userData;
void *m_handlerArg;
char *m_buffer;
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;
long 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;
void *m_externalEntityRefHandlerArg;
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;
int m_ns;
int m_ns_triplets;
void *m_unknownEncodingMem;
void *m_unknownEncodingData;
void *m_unknownEncodingHandlerData;
void (*m_unknownEncodingRelease) (void *);
PROLOG_STATE m_prologState;
Processor *m_processor;
XMLERROR m_errorCode;
const char *m_eventPtr;
const char *m_eventEndPtr;
const char *m_positionPtr;
OPEN_INTERNAL_ENTITY *m_openInternalEntities;
int 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;
char m_declAttributeIsCdata;
char 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;
POSITION m_position;
STRING_POOL m_tempPool;
STRING_POOL m_temp2Pool;
char *m_groupConnector;
unsigned m_groupSize;
int m_hadExternalDoctype;
XML_Char m_namespaceSeparator;
#ifdef XML_DTD
enum XML_ParamEntityParsing m_paramEntityParsing;
XML_Parser m_parentParser;
#endif
}
Parser;
#define MALLOC(s) (((Parser *)parser)->m_mem.malloc_fcn((s)))
#define REALLOC(p,s) (((Parser *)parser)->m_mem.realloc_fcn((p),(s)))
#define FREE(p) (((Parser *)parser)->m_mem.free_fcn((p)))
#define userData (((Parser *)parser)->m_userData)
#define handlerArg (((Parser *)parser)->m_handlerArg)
#define startElementHandler (((Parser *)parser)->m_startElementHandler)
#define endElementHandler (((Parser *)parser)->m_endElementHandler)
#define characterDataHandler (((Parser *)parser)->m_characterDataHandler)
#define processingInstructionHandler (((Parser *)parser)->m_processingInstructionHandler)
#define commentHandler (((Parser *)parser)->m_commentHandler)
#define startCdataSectionHandler (((Parser *)parser)->m_startCdataSectionHandler)
#define endCdataSectionHandler (((Parser *)parser)->m_endCdataSectionHandler)
#define defaultHandler (((Parser *)parser)->m_defaultHandler)
#define startDoctypeDeclHandler (((Parser *)parser)->m_startDoctypeDeclHandler)
#define endDoctypeDeclHandler (((Parser *)parser)->m_endDoctypeDeclHandler)
#define unparsedEntityDeclHandler (((Parser *)parser)->m_unparsedEntityDeclHandler)
#define notationDeclHandler (((Parser *)parser)->m_notationDeclHandler)
#define startNamespaceDeclHandler (((Parser *)parser)->m_startNamespaceDeclHandler)
#define endNamespaceDeclHandler (((Parser *)parser)->m_endNamespaceDeclHandler)
#define notStandaloneHandler (((Parser *)parser)->m_notStandaloneHandler)
#define externalEntityRefHandler (((Parser *)parser)->m_externalEntityRefHandler)
#define externalEntityRefHandlerArg (((Parser *)parser)->m_externalEntityRefHandlerArg)
#define internalEntityRefHandler (((Parser *)parser)->m_internalEntityRefHandler)
#define unknownEncodingHandler (((Parser *)parser)->m_unknownEncodingHandler)
#define elementDeclHandler (((Parser *)parser)->m_elementDeclHandler)
#define attlistDeclHandler (((Parser *)parser)->m_attlistDeclHandler)
#define entityDeclHandler (((Parser *)parser)->m_entityDeclHandler)
#define xmlDeclHandler (((Parser *)parser)->m_xmlDeclHandler)
#define encoding (((Parser *)parser)->m_encoding)
#define initEncoding (((Parser *)parser)->m_initEncoding)
#define internalEncoding (((Parser *)parser)->m_internalEncoding)
#define unknownEncodingMem (((Parser *)parser)->m_unknownEncodingMem)
#define unknownEncodingData (((Parser *)parser)->m_unknownEncodingData)
#define unknownEncodingHandlerData \
(((Parser *)parser)->m_unknownEncodingHandlerData)
#define unknownEncodingRelease (((Parser *)parser)->m_unknownEncodingRelease)
#define protocolEncodingName (((Parser *)parser)->m_protocolEncodingName)
#define ns (((Parser *)parser)->m_ns)
#define ns_triplets (((Parser *)parser)->m_ns_triplets)
#define prologState (((Parser *)parser)->m_prologState)
#define processor (((Parser *)parser)->m_processor)
#define errorCode (((Parser *)parser)->m_errorCode)
#define eventPtr (((Parser *)parser)->m_eventPtr)
#define eventEndPtr (((Parser *)parser)->m_eventEndPtr)
#define positionPtr (((Parser *)parser)->m_positionPtr)
#define position (((Parser *)parser)->m_position)
#define openInternalEntities (((Parser *)parser)->m_openInternalEntities)
#define defaultExpandInternalEntities (((Parser *)parser)->m_defaultExpandInternalEntities)
#define tagLevel (((Parser *)parser)->m_tagLevel)
#define buffer (((Parser *)parser)->m_buffer)
#define bufferPtr (((Parser *)parser)->m_bufferPtr)
#define bufferEnd (((Parser *)parser)->m_bufferEnd)
#define parseEndByteIndex (((Parser *)parser)->m_parseEndByteIndex)
#define parseEndPtr (((Parser *)parser)->m_parseEndPtr)
#define bufferLim (((Parser *)parser)->m_bufferLim)
#define dataBuf (((Parser *)parser)->m_dataBuf)
#define dataBufEnd (((Parser *)parser)->m_dataBufEnd)
#define dtd (((Parser *)parser)->m_dtd)
#define curBase (((Parser *)parser)->m_curBase)
#define declEntity (((Parser *)parser)->m_declEntity)
#define doctypeName (((Parser *)parser)->m_doctypeName)
#define doctypeSysid (((Parser *)parser)->m_doctypeSysid)
#define doctypePubid (((Parser *)parser)->m_doctypePubid)
#define declAttributeType (((Parser *)parser)->m_declAttributeType)
#define declNotationName (((Parser *)parser)->m_declNotationName)
#define declNotationPublicId (((Parser *)parser)->m_declNotationPublicId)
#define declElementType (((Parser *)parser)->m_declElementType)
#define declAttributeId (((Parser *)parser)->m_declAttributeId)
#define declAttributeIsCdata (((Parser *)parser)->m_declAttributeIsCdata)
#define declAttributeIsId (((Parser *)parser)->m_declAttributeIsId)
#define freeTagList (((Parser *)parser)->m_freeTagList)
#define freeBindingList (((Parser *)parser)->m_freeBindingList)
#define inheritedBindings (((Parser *)parser)->m_inheritedBindings)
#define tagStack (((Parser *)parser)->m_tagStack)
#define atts (((Parser *)parser)->m_atts)
#define attsSize (((Parser *)parser)->m_attsSize)
#define nSpecifiedAtts (((Parser *)parser)->m_nSpecifiedAtts)
#define idAttIndex (((Parser *)parser)->m_idAttIndex)
#define tempPool (((Parser *)parser)->m_tempPool)
#define temp2Pool (((Parser *)parser)->m_temp2Pool)
#define groupConnector (((Parser *)parser)->m_groupConnector)
#define groupSize (((Parser *)parser)->m_groupSize)
#define hadExternalDoctype (((Parser *)parser)->m_hadExternalDoctype)
#define namespaceSeparator (((Parser *)parser)->m_namespaceSeparator)
#ifdef XML_DTD
#define parentParser (((Parser *)parser)->m_parentParser)
#define paramEntityParsing (((Parser *)parser)->m_paramEntityParsing)
#endif /* XML_DTD */
#ifdef COMPILED_FROM_DSP
BOOL WINAPI DllMain(HINSTANCE h, DWORD r, LPVOID p)
{
return TRUE;
}
#endif /* def COMPILED_FROM_DSP */
#ifdef _MSC_VER
#ifdef _DEBUG
Parser *asParser(XML_Parser parser)
{
return parser;
}
#endif
#endif
/*
*@@ XML_ParserCreate:
* constructs a new parser. If encoding is non-null, it specifies
* a character encoding to use for the document (see below).
* This overrides the document encoding declaration.
*
* Expat is a stream-oriented parser. You register callback (or
* handler) functions with the parser and then start feeding it
* the document. As the parser recognizes parts of the document,
* it will call the appropriate handler for that part (if you've
* registered one). The document is fed to the parser in pieces,
* so you can start parsing before you have all the document.
* This also allows you to parse really huge documents that won't
* fit into memory.
*
* Expat can be intimidating due to the many kinds of handlers
* and options you can set. But you only need to learn four
* functions in order to do 90% of what you'll want to do with it:
*
* -- XML_ParserCreate: Create a new parser object.
*
* -- XML_SetElementHandler: Set handlers for start and end tags.
*
* -- XML_SetCharacterDataHandler: Set handler for text.
*
* -- XML_Parse: Pass a buffer full of document to the parser.
*
* So the first step in parsing an XML document with expat is
* to create a parser object. There are three functions in the
* expat API for creating a parser object. However, only two of
* these (XML_ParserCreate and XML_ParserCreateNS) can be used
* for constructing a parser for a top-level document. The object
* returned by these functions is an opaque pointer (i.e. expat.h
* declares it as void*) to data with further internal structure.
* In order to free the memory associated with this object you
* must call XML_ParserFree. Note that if you have provided
* any user data that gets stored in the parser, then your
* application is responsible for freeing it prior to calling
* XML_ParserFree.
*
* The objects returned by the parser creation functions are
* good for parsing only one XML document or external parsed
* entity. If your application needs to parse many XML documents,
* then it needs to create a parser object for each one. The
* best way to deal with this is to create a higher level object
* that contains all the default initialization you want for
* your parser objects.
*
* Walking through a document hierarchy with a stream oriented
* parser will require a good stack mechanism in order to keep
* track of current context. For instance, to answer the simple
* question, "What element does this text belong to?" requires
* a stack, since the parser may have descended into other
* elements that are children of the current one and has
* encountered this text on the way out.
*
* The things you're likely to want to keep on a stack are the
* currently opened element and its attributes. You push this
* information onto the stack in the start handler and you pop
* it off in the end handler.
*
* For some tasks, it is sufficient to just keep information on
* what the depth of the stack is (or would be if you had one).
* The outline program shown above presents one example. Another
* such task would be skipping over a complete element. When you
* see the start tag for the element you want to skip, you set a
* skip flag and record the depth at which the element started.
* When the end tag handler encounters the same depth, the
* skipped element has ended and the flag may be cleared. If you
* follow the convention that the root element starts at 1, then
* you can use the same variable for skip flag and skip depth.
*
* <B>Namespace Processing</B>
*
* When the parser is created using the XML_ParserCreateNS,
* function, expat performs namespace processing. See that
* function for details.
*
* <B>Character Encodings</B>
*
* While XML is based on Unicode, and every XML processor is
* required to recognized UTF-8 and UTF-16 (1 and 2 byte
* encodings of Unicode), other @encodings may be declared in
* XML documents or entities. For the main document, an XML
* declaration may contain an encoding declaration in its
* @text_declaration. See @encodings for additional
* information.
*
* With expat, you may also specify an encoding at the time
* of creating a parser. This is useful when the encoding
* information may come from a source outside the document
* itself (like a higher level protocol).
*
* See XML_SetUnknownEncodingHandler for encodings directly
* supported by expat and for how to handle other encodings.
*
* One pitfall that novice expat users are likely to fall into is
* that although expat may accept input in various encodings, the
* strings that it passes to the handlers are always encoded in
* UTF-8. Your application is responsible for any translation of
* these strings into other encodings.
*
* <B>Handling External Entity References</B>
*
* Expat does not read or parse @external_entities directly. Note that
* any external @DTD is a special case of an external entity. For how to
* handle external entities, see XML_SetExternalEntityRefHandler.
*
* <B>Parsing Parameter Entities</B>
*
* In order to parse @parameter_entities, before starting the parse,
* you must call XML_SetParamEntityParsing.
*/
XML_Parser XML_ParserCreate(const XML_Char * encodingName)
{
return XML_ParserCreate_MM(encodingName, NULL, NULL);
}
/*
*@@ XML_ParserCreateNS:
* constructs a new parser that has namespace processing
* in effect. Namespace expanded element names and attribute
* names are returned as a concatenation of the namespace URI,
* sep, and the local part of the name. This means that you
* should pick a character for sep that can't be part of a
* legal URI.
*
* Under namespace processing, expat consumes xmlns and xmlns:...
* attributes, which declare namespaces for the scope of the
* element in which they occur. This means that your start
* handler will not see these attributes. Your application can
* still be informed of these declarations by setting namespace
* declaration handlers with XML_SetNamespaceDeclHandler.
*
* Element type and attribute names that belong to a given
* namespace are passed to the appropriate handler in expanded
* form. By default this expanded form is a concatenation of the
* namespace URI, the separator character (which is the 2nd
* argument to XML_ParserCreateNS), and the local name (i.e.
* the part after the colon). Names with undeclared prefixes
* are passed through to the handlers unchanged, with the prefix
* and colon still attached. Unprefixed attribute names are never
* expanded, and unprefixed element names are only expanded when
* they are in the scope of a default namespace.
*
* However if XML_SetReturnNSTriplet has been called with a
* non-zero do_nst parameter, then the expanded form for names
* with an explicit prefix is a concatenation of: URI, separator,
* local name, separator, prefix.
*
* You can set handlers for the start of a namespace declaration
* and for the end of a scope of a declaration with the
* XML_SetNamespaceDeclHandler function. The
* StartNamespaceDeclHandler is called prior to the start
* tag handler and the EndNamespaceDeclHandler is called before
* the corresponding end tag that ends the namespace's scope.
* The namespace start handler gets passed the prefix and URI
* for the namespace. For a default namespace declaration
* (xmlns='...'), the prefix will be null. The URI will be null
* for the case where the default namespace is being unset. The
* namespace end handler just gets the prefix for the closing
* scope.
*
* These handlers are called for each declaration. So if, for
* instance, a start tag had three namespace declarations, then
* the StartNamespaceDeclHandler would be called three times
* before the start tag handler is called, once for each
* declaration.
*
* The namespace.c example demonstrates the use of these
* features. Like outline.c, it produces an outline, but in
* addition it annotates when a namespace scope starts and
* when it ends. This example also demonstrates use of
* application user data.
*/
XML_Parser XML_ParserCreateNS(const XML_Char * encodingName,
XML_Char nsSep)
{
XML_Char tmp[2];
*tmp = nsSep;
return XML_ParserCreate_MM(encodingName, NULL, tmp);
}
/*
*@@ XML_ParserCreate_MM:
* constructs a new parser using the suite of memory handling
* functions specified in ms. If ms is NULL, then use the
* standard set of memory management functions. If sep is
* non-NULL, then namespace processing is enabled in the
* created parser and the character pointed at by sep is
* used as the separator between the namespace URI and the
* local part of the name.
*/
XML_Parser XML_ParserCreate_MM(const XML_Char * encodingName,
const XML_Memory_Handling_Suite * memsuite,
const XML_Char * nameSep)
{
XML_Parser parser;
static
const XML_Char implicitContext[] =
{
XML_T('x'), XML_T('m'), XML_T('l'), XML_T('='),
XML_T('h'), XML_T('t'), XML_T('t'), XML_T('p'), XML_T(':'),
XML_T('/'), XML_T('/'), XML_T('w'), XML_T('w'), XML_T('w'),
XML_T('.'), XML_T('w'), XML_T('3'),
XML_T('.'), XML_T('o'), XML_T('r'), XML_T('g'),
XML_T('/'), XML_T('X'), XML_T('M'), XML_T('L'),
XML_T('/'), XML_T('1'), XML_T('9'), XML_T('9'), XML_T('8'),
XML_T('/'), XML_T('n'), XML_T('a'), XML_T('m'), XML_T('e'),
XML_T('s'), XML_T('p'), XML_T('a'), XML_T('c'), XML_T('e'),
XML_T('\0')
};
if (memsuite)
{
XML_Memory_Handling_Suite *mtemp;
parser = memsuite->malloc_fcn(sizeof(Parser));
mtemp = &(((Parser *) 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 = malloc(sizeof(Parser));
mtemp = &(((Parser *) parser)->m_mem);
mtemp->malloc_fcn = malloc;
mtemp->realloc_fcn = realloc;
mtemp->free_fcn = free;
}
if (!parser)
return parser;
processor = prologInitProcessor;
XmlPrologStateInit(&prologState);
userData = 0;
handlerArg = 0;
startElementHandler = 0;
endElementHandler = 0;
characterDataHandler = 0;
processingInstructionHandler = 0;
commentHandler = 0;
startCdataSectionHandler = 0;
endCdataSectionHandler = 0;
defaultHandler = 0;
startDoctypeDeclHandler = 0;
endDoctypeDeclHandler = 0;
unparsedEntityDeclHandler = 0;
notationDeclHandler = 0;
startNamespaceDeclHandler = 0;
endNamespaceDeclHandler = 0;
notStandaloneHandler = 0;
externalEntityRefHandler = 0;
externalEntityRefHandlerArg = parser;
unknownEncodingHandler = 0;
elementDeclHandler = 0;
attlistDeclHandler = 0;
entityDeclHandler = 0;
xmlDeclHandler = 0;
buffer = 0;
bufferPtr = 0;
bufferEnd = 0;
parseEndByteIndex = 0;
parseEndPtr = 0;
bufferLim = 0;
declElementType = 0;
declAttributeId = 0;
declEntity = 0;
doctypeName = 0;
doctypeSysid = 0;
doctypePubid = 0;
declAttributeType = 0;
declNotationName = 0;
declNotationPublicId = 0;
memset(&position, 0, sizeof(POSITION));
errorCode = ERROR_EXPAT_NONE;
eventPtr = 0;
eventEndPtr = 0;
positionPtr = 0;
openInternalEntities = 0;
tagLevel = 0;
tagStack = 0;
freeTagList = 0;
freeBindingList = 0;
inheritedBindings = 0;
attsSize = INIT_ATTS_SIZE;
atts = (ATTRIBUTE*)MALLOC(attsSize * sizeof(ATTRIBUTE));
nSpecifiedAtts = 0;
dataBuf = (XML_Char*)MALLOC(INIT_DATA_BUF_SIZE * sizeof(XML_Char));
groupSize = 0;
groupConnector = 0;
hadExternalDoctype = 0;
unknownEncodingMem = 0;
unknownEncodingRelease = 0;
unknownEncodingData = 0;
unknownEncodingHandlerData = 0;
namespaceSeparator = '!';
#ifdef XML_DTD
parentParser = 0;
paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
#endif
ns = 0;
ns_triplets = 0;
poolInit(&tempPool, &(((Parser *) parser)->m_mem));
poolInit(&temp2Pool, &(((Parser *) parser)->m_mem));
protocolEncodingName = encodingName ? poolCopyString(&tempPool, encodingName) : 0;
curBase = 0;
if (!dtdInit(&dtd, parser) || !atts || !dataBuf
|| (encodingName && !protocolEncodingName))
{
XML_ParserFree(parser);
return 0;
}
dataBufEnd = dataBuf + INIT_DATA_BUF_SIZE;
if (nameSep)
{
XmlInitEncodingNS(&initEncoding, &encoding, 0);
ns = 1;
internalEncoding = XmlGetInternalEncodingNS();
namespaceSeparator = *nameSep;
if (!setContext(parser, implicitContext))
{
XML_ParserFree(parser);
return 0;
}
}
else
{
XmlInitEncoding(&initEncoding, &encoding, 0);
internalEncoding = XmlGetInternalEncoding();
}
return parser;
} /* End XML_ParserCreate_MM */
/*
*@@ XML_SetEncoding:
* sets the encoding to be used by the parser. It is
* equivalent to passing a non-null encoding argument
* to the parser creation functions. It must not be
* called after XML_Parser or XML_ParseBuffer have
* been called on the given parser.
*/
int XML_SetEncoding(XML_Parser parser,
const XML_Char * encodingName)
{
if (!encodingName)
protocolEncodingName = 0;
else
{
protocolEncodingName = poolCopyString(&tempPool, encodingName);
if (!protocolEncodingName)
return 0;
}
return 1;
}
/*
*@@ XML_ExternalEntityParserCreate:
* constructs a new XML_Parser object for parsing an external
* general entity. Context is the context argument passed in a
* call to a ExternalEntityRefHandler. Other state information
* such as handlers, user data, namespace processing is
* inherited from the parser passed as the 1st argument. So you
* shouldn't need to call any of the behavior changing
* functions on this parser (unless you want it to act
* differently than the parent parser.)
*/
XML_Parser XML_ExternalEntityParserCreate(XML_Parser oldParser,
const XML_Char * context,
const XML_Char * encodingName)
{
XML_Parser parser = oldParser;
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_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;
int oldDefaultExpandInternalEntities = defaultExpandInternalEntities;
void *oldExternalEntityRefHandlerArg = externalEntityRefHandlerArg;
#ifdef XML_DTD
enum XML_ParamEntityParsing oldParamEntityParsing = paramEntityParsing;
#endif
int oldns_triplets = ns_triplets;
if (ns)
{
XML_Char tmp[2];
*tmp = namespaceSeparator;
parser = XML_ParserCreate_MM(encodingName, &((Parser *) parser)->m_mem,
tmp);
}
else
{
parser = XML_ParserCreate_MM(encodingName, &((Parser *) parser)->m_mem,
NULL);
}
if (!parser)
return 0;
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;
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;
#ifdef XML_DTD
paramEntityParsing = oldParamEntityParsing;
if (context)
{
#endif /* XML_DTD */
if (!dtdCopy(&dtd, oldDtd, parser) || !setContext(parser, context))
{
XML_ParserFree(parser);
return 0;
}
processor = externalEntityInitProcessor;
#ifdef XML_DTD
}
else
{
dtdSwap(&dtd, oldDtd);
parentParser = oldParser;
XmlPrologStateInitExternalEntity(&prologState);
dtd.complete = 1;
hadExternalDoctype = 1;
}
#endif /* XML_DTD */
return parser;
}
static void destroyBindings(BINDING * bindings,
XML_Parser parser)
{
for (;;)
{
BINDING *b = bindings;
if (!b)
break;
bindings = b->nextTagBinding;
FREE(b->uri);
FREE(b);
}
}
/*
*@@ XML_ParserFree:
* free memory used by the parser. Your application is
* responsible for freeing any memory associated
* with UserData.
*/
void XML_ParserFree(XML_Parser parser)
{
for (;;)
{
TAG *p;
if (tagStack == 0)
{
if (freeTagList == 0)
break;
tagStack = freeTagList;
freeTagList = 0;
}
p = tagStack;
tagStack = tagStack->parent;
FREE(p->buf);
destroyBindings(p->bindings, parser);
FREE(p);
}
destroyBindings(freeBindingList, parser);
destroyBindings(inheritedBindings, parser);
poolDestroy(&tempPool);
poolDestroy(&temp2Pool);
#ifdef XML_DTD
if (parentParser)
{
if (hadExternalDoctype)
dtd.complete = 0;
dtdSwap(&dtd, &((Parser *) parentParser)->m_dtd);
}
#endif /* XML_DTD */
dtdDestroy(&dtd, parser);
FREE((void *)atts);
if (groupConnector)
FREE(groupConnector);
if (buffer)
FREE(buffer);
FREE(dataBuf);
if (unknownEncodingMem)
FREE(unknownEncodingMem);
if (unknownEncodingRelease)
unknownEncodingRelease(unknownEncodingData);
FREE(parser);
}
/*
*@@ XML_UseParserAsHandlerArg:
* after this is called, handlers receive the parser in the
* userData argument (see XML_SetUserData). The userData
* information can still be obtained using the XML_GetUserData
* function.
*/
void XML_UseParserAsHandlerArg(XML_Parser parser)
{
handlerArg = parser;
}
/*
*@@ XML_SetReturnNSTriplet:
* this function only has an effect when using a parser
* created with XML_ParserCreateNS, i.e. when namespace
* processing is in effect. The do_nst sets whether or
* not prefixes are returned with names qualified with
* a namespace prefix. If this function is called with
* do_nst non-zero, then afterwards namespace qualified
* names (that is qualified with a prefix as opposed to
* belonging to a default namespace) are returned as a
* triplet with the three parts separated by the namespace
* separator specified when the parser was created. The
* order of returned parts is URI, local name, and prefix.
*
* If do_nst is zero, then namespaces are reported in
* the default manner, URI then local_name separated by
* the namespace separator.
*/
void XML_SetReturnNSTriplet(XML_Parser parser,
int do_nst)
{
ns_triplets = do_nst;
}
/*
*@@ XML_SetUserData:
* sets the user data pointer that gets passed to handlers.
*
* It overwrites any previous value for this pointer. Note that
* the application is responsible for freeing the memory
* associated with userData when it is finished with the parser.
* So if you call this when there's already a pointer there, and
* you haven't freed the memory associated with it, then you've
* probably just leaked memory.
*
* Also see XML_UseParserAsHandlerArg.
*/
void XML_SetUserData(XML_Parser parser,
void *p)
{
if (handlerArg == userData)
handlerArg = userData = p;
else
userData = p;
}
/*
*@@ XML_SetBase:
* set the base to be used for resolving relative URIs in
* system identifiers. The return value is 0 if there's no
* memory to store base, otherwise it's non-zero.
*/
int XML_SetBase(XML_Parser parser,
const XML_Char * p)
{
if (p)
{
p = poolCopyString(&dtd.pool, p);
if (!p)
return 0;
curBase = p;
}
else
curBase = 0;
return 1;
}
/*
*@@ XML_GetBase:
* returns the base for resolving relative URIs.
* See XML_SetBase.
*/
const XML_Char *XML_GetBase(XML_Parser parser)
{
return curBase;
}
/*
*@@ XML_GetSpecifiedAttributeCount:
* when attributes are reported to the start handler in the
* atts vector, attributes that were explicitly set in the
* element occur before any attributes that receive their
* value from default information in an ATTLIST declaration.
* This function returns the number of attributes that were
* explicitly set times two, thus giving the offset in the
* atts array passed to the start tag handler of the first
* attribute set due to defaults. It supplies information
* for the last call to a start handler. If called inside a
* start handler, then that means the current call.
*/
int XML_GetSpecifiedAttributeCount(XML_Parser parser)
{
return nSpecifiedAtts;
}
/*
*@@ XML_GetIdAttributeIndex:
* returns the index of the ID attribute passed in the atts
* array in the last call to XML_StartElementHandler, or -1
* if there is no ID attribute. If called inside a start
* handler, then that means the current call.
*/
int XML_GetIdAttributeIndex(XML_Parser parser)
{
return idAttIndex;
}
/*
*@@ XML_SetElementHandler:
* sets handlers for start and end tags with one call.
*
* See XML_SetStartElementHandler and XML_SetEndElementHandler
* for details.
*/
void XML_SetElementHandler(XML_Parser parser,
XML_StartElementHandler start,
XML_EndElementHandler end)
{
startElementHandler = start;
endElementHandler = end;
}
/*
*@@ XML_SetStartElementHandler:
* sets handler for start (and empty) tags.
*
* This handler must have the following prototype:
*
+ void EXPATENTRY StartElementHandler(void *pUserData,
+ const XML_Char *name,
+ const XML_Char **atts);
+
* "data" is the user data pointer set with XML_SetUserData.
*
* "name" is the element name.
*
* Attributes are passed to the start handler as a pointer
* to a vector of char pointers. Each attribute seen in a
* start (or empty) tag occupies 2 consecutive places in
* this vector: the attribute name followed by the attribute
* value. These pairs are terminated by a null pointer.
*
* Note that an empty tag generates a call to both start
* and end handlers (in that order).
*
* Although handlers are typically set prior to parsing and left
* alone, an application may choose to set or change the handler
* for a parsing event while the parse is in progress. For
* instance, your application may choose to ignore all text not
* descended from a para element. One way it could do this is to
* set the character handler when a para start tag is seen, and
* unset it for the corresponding end tag.
*
* A handler may be unset by providing a NULL pointer to the
* appropriate handler setter. None of the handler setting
* functions have a return value.
*
* Your handlers will be receiving strings in arrays of type
* XML_Char. This type is defined in expat.h as char* and
* contains bytes encoding UTF-8. Note that you'll receive them
* in this form independent of the original encoding of the
* document.
*/
void XML_SetStartElementHandler(XML_Parser parser,
XML_StartElementHandler start)
{
startElementHandler = start;
}
/*
*@@ XML_SetEndElementHandler:
* sets handler for end (and empty) tags. As noted above, an
* empty tag generates a call to both start and end handlers.
*
* Handler prototype:
+
+ void EXPATENTRY EndElementHandler(void *pUserData,
+ const XML_Char *name);
*/
void XML_SetEndElementHandler(XML_Parser parser,
XML_EndElementHandler end)
{
endElementHandler = end;
}
/*
*@@ XML_SetCharacterDataHandler:
* sets a character data (text, @content) handler.
*
* Handler prototype:
*
+ void EXPATENTRY CharacterDataHandler(void *pUserData,
+ const XML_Char *s,
+ int len);
+
* The string your handler receives is NOT zero terminated.
* You have to use the length argument to deal with the end
* of the string. A single block of contiguous text free of
* markup may still result in a sequence of calls to this
* handler. In other words, if you're searching for a pattern
* in the text, it may be split across calls to this handler.
*/
void XML_SetCharacterDataHandler(XML_Parser parser,
XML_CharacterDataHandler handler)
{
characterDataHandler = handler;
}
/*
*@@ XML_SetProcessingInstructionHandler:
* sets a handler for processing instructions.
*
* Handler prototype:
*
+ void EXPATENTRY ProcessingInstructionHandler(void *pUserData,
+ const XML_Char *target,
+ const XML_Char *data);
+
* The target is the first word in the processing instruction. The data
* is the rest of the characters in it after skipping all
* whitespace after the initial word.
*/
void XML_SetProcessingInstructionHandler(XML_Parser parser,
XML_ProcessingInstructionHandler handler)
{
processingInstructionHandler = handler;
}
/*
*@@ XML_SetCommentHandler:
* sets a handler for comments. The data is all text inside
* the comment delimiters.
*
* Handler prototype:
*
+ void EXPATENTRY CommentHandler(void *pUserData,
+ const XML_Char *data);
*
*/
void XML_SetCommentHandler(XML_Parser parser,
XML_CommentHandler handler)
{
commentHandler = handler;
}
/*
*@@ XML_SetCdataSectionHandler:
* combination of XML_SetStartCdataSectionHandler and
* XML_SetEndCdataSectionHandler in one call.
*/
void XML_SetCdataSectionHandler(XML_Parser parser,
XML_StartCdataSectionHandler start,
XML_EndCdataSectionHandler end)
{
startCdataSectionHandler = start;
endCdataSectionHandler = end;
}
/*
*@@ XML_SetCdataSectionHandler:
* sets a handler that gets called at the beginning of a CDATA
* section.
*
* Handler prototype:
*
+ void EXPATENTRY StartCdataSectionHandler(void *pUserData);
*
*/
void XML_SetStartCdataSectionHandler(XML_Parser parser,
XML_StartCdataSectionHandler start)
{
startCdataSectionHandler = start;
}
/*
*@@ XML_SetCdataSectionHandler:
* sets a handler that gets called at the end of a CDATA
* section.
*
* Handler prototype:
*
* void EXPATENTRY EndCdataSectionHandler(void *pUserData);
*/
void XML_SetEndCdataSectionHandler(XML_Parser parser,
XML_EndCdataSectionHandler end)
{
endCdataSectionHandler = end;
}
/*
*@@ XML_SetDefaultHandler:
* sets a handler for any characters in the document for
* which there is no applicable handler.
*
* This includes both data for which no handlers can be set
* (like some kinds of DTD declarations) and data which could
* be reported but for which there has no handler supplied.
*
* Handler prototype:
+
+ void EXPATENTRY DefaultHandler(void *pUserData,
+ const XML_Char *s,
+ int len);
*
* The characters are passed exactly as they were in the XML
* document except that they will be encoded in UTF-8. Line
* boundaries are not normalized.
*
* Note that a byte order mark character is not passed to the
* default handler.
*
* Note that a contiguous piece of data that is destined to
* be reported to the default handler may actually be reported
* over several calls to the handler.
*
* Setting the handler with this call has the side effect of
* turning off expansion of references to internally defined
* general entities. Instead these references are passed to
* the default handler. To avoid that, use XML_SetDefaultHandlerExpand.
*/
void XML_SetDefaultHandler(XML_Parser parser,
XML_DefaultHandler handler)
{
defaultHandler = handler;
defaultExpandInternalEntities = 0;
}
/*
*@@ XML_SetDefaultHandlerExpand:
* this sets a default handler, but doesn't affect expansion of
* internal entity references.
*
* See XML_SetDefaultHandler.
*/
void XML_SetDefaultHandlerExpand(XML_Parser parser,
XML_DefaultHandler handler)
{
defaultHandler = handler;
defaultExpandInternalEntities = 1;
}
/*
*@@ XML_SetDoctypeDeclHandler:
* combination of XML_SetStartDoctypeDeclHandler and
* XML_SetEndDoctypeDeclHandler.
*/
void XML_SetDoctypeDeclHandler(XML_Parser parser,
XML_StartDoctypeDeclHandler start,
XML_EndDoctypeDeclHandler end)
{
startDoctypeDeclHandler = start;
endDoctypeDeclHandler = end;
}
/*
*@@ XML_SetStartDoctypeDeclHandler:
* sets a handler that is called at the start of a DOCTYPE
* declaration, before any external or internal subset is
* parsed.
*
* Handler prototype:
*
+ void EXPATENTRY StartDoctypeDeclHandler(void *pUserData,
+ const XML_Char *pcszDoctypeName,
+ const XML_Char *pcszSysid,
+ const XML_Char *pcszPubid,
+ int fHasInternalSubset);
*
* Both pcszSysid and pcszPubid may be NULL. "fHasInternalSubset"
* will be non-zero if the DOCTYPE declaration has an internal subset.
*/
void XML_SetStartDoctypeDeclHandler(XML_Parser parser,
XML_StartDoctypeDeclHandler start)
{
startDoctypeDeclHandler = start;
}
/*
*@@ XML_SetEndDoctypeDeclHandler:
* sets a handler that is called at the end of a DOCTYPE
* declaration, after parsing any external subset.
*
* Handler prototype:
*
+ void EXPATENTRY EndDoctypeDeclHandler(void *pUserData);
*
*/
void XML_SetEndDoctypeDeclHandler(XML_Parser parser,
XML_EndDoctypeDeclHandler end)
{
endDoctypeDeclHandler = end;
}
/*
*@@ XML_SetUnparsedEntityDeclHandler:
* sets a handler that receives declarations of unparsed
* entities. These are entity declarations that have a
* notation (NDATA) field:
*
+ <!ENTITY logo SYSTEM "images/logo.gif" NDATA gif>
*
* This handler is obsolete and is provided for backwards
* compatibility. Use instead XML_SetEntityDeclHandler.
*/
void XML_SetUnparsedEntityDeclHandler(XML_Parser parser,
XML_UnparsedEntityDeclHandler handler)
{
unparsedEntityDeclHandler = handler;
}
/*
*@@ XML_SetNotationDeclHandler:
* sets a handler that receives notation declarations.
*
* Handler prototype:
+
+ void EXPATENTRY NotationDeclHandler(void *pUserData,
+ const XML_Char *pcszNotationName,
+ const XML_Char *pcszBase,
+ const XML_Char *pcszSystemId,
+ const XML_Char *pcszPublicId);
+
*/
void XML_SetNotationDeclHandler(XML_Parser parser,
XML_NotationDeclHandler handler)
{
notationDeclHandler = handler;
}
/*
*@@ XML_SetNamespaceDeclHandler:
* combination of XML_SetEndNamespaceDeclHandler and
* XML_SetEndNamespaceDeclHandler.
*/
void XML_SetNamespaceDeclHandler(XML_Parser parser,
XML_StartNamespaceDeclHandler start,
XML_EndNamespaceDeclHandler end)
{
startNamespaceDeclHandler = start;
endNamespaceDeclHandler = end;
}
/*
*@@ XML_SetStartNamespaceDeclHandler:
* sets a handler to be called when a namespace is declared.
* Namespace declarations occur inside start tags. But the
* namespace declaration start handler is called before the
* start tag handler for each namespace declared in that start
* tag.
*
* Handler prototype:
*
+ void EXPATENTRY StartNamespaceDeclHandler(void *pUserData,
+ const XML_Char *prefix,
+ const XML_Char *uri);
+
*/
void XML_SetStartNamespaceDeclHandler(XML_Parser parser,
XML_StartNamespaceDeclHandler start)
{
startNamespaceDeclHandler = start;
}
/*
*@@ XML_SetEndNamespaceDeclHandler:
* sets a handler to be called when leaving the scope of a
* namespace declaration. This will be called, for each
* namespace declaration, after the handler for the end tag
* of the element in which the namespace was declared.
*
* Handler prototype:
+
+ void EXPATENTRY EndNamespaceDeclHandler(void *pUserData,
+ const XML_Char *prefix);
*/
void XML_SetEndNamespaceDeclHandler(XML_Parser parser,
XML_EndNamespaceDeclHandler end)
{
endNamespaceDeclHandler = end;
}
/*
*@@ XML_SetNotStandaloneHandler:
* sets a handler that is called if the document is not
* "standalone". This happens when there is an external
* subset or a reference to a parameter entity, but does
* not have standalone set to "yes" in an XML declaration.
* If this handler returns 0, then the parser will throw an
* ERROR_EXPAT_NOT_STANDALONE error.
*
* Handler prototype:
*
+ int EXPATENTRY NotStandaloneHandler(void *pUserData);
*/
void XML_SetNotStandaloneHandler(XML_Parser parser,
XML_NotStandaloneHandler handler)
{
notStandaloneHandler = handler;
}
/*
*@@ XML_SetExternalEntityRefHandler:
* sets a handler for references to @external_entities.
*
* This handler is also called for processing an external DTD
* subset if parameter entity parsing is in effect.
* (See XML_SetParamEntityParsing.)
*
* Warning: If you have set no ExternalEntityRefHandler, then
* external entity references are silently ignored. Otherwise,
* they trigger a call to your handler with the information
* needed to read and parse the external entity.
*
* Handler prototype:
+
+ int EXPATENTRY ExternalEntityRefHandler(void *pUser,
+ XML_Parser parser,
+ const XML_Char *pcszContext,
+ const XML_Char *pcszBase,
+ const XML_Char *pcszSystemId,
+ const XML_Char *pcszPublicId);
+
* The pcszContext argument specifies the parsing context in the
* format expected by the context argument to
* XML_ExternalEntityParserCreate; pcszContext is valid only until
* the handler returns, so if the referenced entity is to be
* parsed later, it must be copied.
*
* The pcszBase parameter is the base to use for relative system
* identifiers. It is set by XML_SetBase and may be null.
*
* The pcszPublicId parameter is the public id given in the entity
* declaration and may be null.
*
* The pcszSystemId is the system identifier specified in the
* entity declaration and is never null.
*
* There are a couple of ways in which this handler differs
* from others. First, this handler returns an integer. A
* non-zero value should be returned for successful handling
* of the external entity reference. Returning a zero indicates
* failure, and causes the calling parser to return an
* ERROR_EXPAT_EXTERNAL_ENTITY_HANDLING error.
*
* Second, instead of having pUserData as its first argument,
* it receives the parser that encountered the entity reference.
* This, along with the context parameter, may be used as
* arguments to a call to XML_ExternalEntityParserCreate.
* Using the returned parser, the body of the external entity
* can be recursively parsed.
*
* Since this handler may be called recursively, it should not
* be saving information into global or static variables.
*
* Your handler isn't actually responsible for parsing the entity,
* but it is responsible for creating a subsidiary parser with
* XML_ExternalEntityParserCreate that will do the job. That returns
* an instance of XML_Parser that has handlers and other data
* structures initialized from the parent parser. You may then use
* XML_Parse or XML_ParseBuffer calls against that parser. Since
* external entities may refer to other external entities, your
* handler should be prepared to be called recursively.
*
*@@changed V0.9.14 (2001-08-09) [umoeller]: changed prototype to contain user data
*/
void XML_SetExternalEntityRefHandler(XML_Parser parser,
XML_ExternalEntityRefHandler handler)
{
externalEntityRefHandler = handler;
}
void XML_SetExternalEntityRefHandlerArg(XML_Parser parser, void *arg)
{
if (arg)
externalEntityRefHandlerArg = arg;
else
externalEntityRefHandlerArg = parser;
}
/*
*@@ XML_SetUnknownEncodingHandler:
* sets a handler to deal with @encodings other than the
* built-in set.
*
* There are four built-in encodings in expat:
*
* -- UTF-8: 8-bit encoding of Unicode.
*
* -- UTF-16: 16-bit encoding of Unicode.
*
* -- ISO-8859-1: that's "latin 1".
*
* -- US-ASCII
*
* Anything else discovered in an encoding declaration or in
* the protocol encoding specified in the parser constructor
* triggers a call to the UnknownEncodingHandler.
*
* Handler prototype:
*
+ int EXPATENTRY UnknownEncodingHandler(void *encodingHandlerData,
+ const XML_Char *name,
+ XML_Encoding *info);
+
* The encodingHandlerData argument is that which was passed as the
* second argument to XML_SetUnknownEncodingHandler.
*
* The name argument gives the name of the encoding as specified in
* the encoding declaration.
*
* If the callback can provide information about the encoding,
* it must fill in the XML_Encoding structure, and return 1.
* Otherwise it must return 0.
* If info does not describe a suitable encoding,
* then the parser will return an XML_UNKNOWN_ENCODING error.
*
* See _XML_Encoding for more details about that structure and
* what to do with it, and restrictions imposed by expat.
*
*/
void XML_SetUnknownEncodingHandler(XML_Parser parser,
XML_UnknownEncodingHandler handler,
void *data)
{
unknownEncodingHandler = handler;
unknownEncodingHandlerData = data;
}
/*
*@@ XML_SetElementDeclHandler:
* sets a handler for an @element_declaration in a @DTD. The
* handler gets called with the name of the element in
* the declaration and a pointer to a structure that contains
* the element model. It is the application's responsibility
* to free this data structure.
*
* This handler must have the following prototype:
*
+ void EXPATENTRY ElementDeclHandler(void *pUserData,
+ const XML_Char *name,
+ XMLCONTENT *model);
*
* See _XMLCONTENT for details.
*/
void XML_SetElementDeclHandler(XML_Parser parser,
XML_ElementDeclHandler eldecl)
{
elementDeclHandler = eldecl;
}
/*
*@@ XML_SetAttlistDeclHandler:
* sets a handler for an @attribute_declaration in the @DTD.
*
* This handler must have the following prototype:
*
+ void EXPATENTRY AttlistDeclHandler(void *pUserData,
+ const XML_Char *pcszElementName,
+ const XML_Char *pcszAttribName,
+ const XML_Char *pcszAttribType,
+ const XML_Char *pcszDefault,
+ int fIsRequired);
*
* This handler is called for each attribute. So a single attlist
* declaration with multiple attributes declared will generate
* multiple calls to this handler.
*
* -- pcszElementName is the name of the element for which the
* attribute is being declared.
*
* -- pcszAttribName has the attribute name being declared.
*
* -- pcszAttribType is the attribute type.
* It is the string representing the type in the declaration
* with whitespace removed.
*
* -- pcszDefault holds the default value. It will be
* NULL in the case of "#IMPLIED" or "#REQUIRED" attributes.
* You can distinguish these two cases by checking the
* fIsRequired parameter, which will be true in the case of
* "#REQUIRED" attributes. Attributes which are "#FIXED"
* will have also have a TRUE fIsRequired, but they will have
* the non-NULL fixed value in the pcszDefault parameter.
*/
void XML_SetAttlistDeclHandler(XML_Parser parser,
XML_AttlistDeclHandler attdecl)
{
attlistDeclHandler = attdecl;
}
/*
*@@ XML_SetEntityDeclHandler:
* sets a handler that will be called for all entity declarations.
*
* Handler prototype:
*
+ void EXPATENTRY EntityDeclHandler(void *pUserData,
+ const XML_Char *pcszEntityName,
+ int fIsParameterEntity,
+ const XML_Char *pcszValue,
+ int iValueLength,
+ const XML_Char *pcszBase,
+ const XML_Char *pcszSystemId,
+ const XML_Char *pcszPublicId,
+ const XML_Char *pcszNotationName);
+
* The fIsParameterEntity argument will be non-zero in the case
* of parameter entities and zero otherwise.
*
* For internal entities (<!ENTITY foo "bar">), pcszValue will be
* non-NULL and pcszSystemId, pcszPublicId, and pcszNotationName
* will all be NULL. The value string is not NULL terminated; the
* lengthis provided in the iValueLength parameter. Do not use
* iValueLength to test for internal entities, since it is legal
* to have zero-length values. Instead check for whether or not
* pcszValue is NULL.
*
* The pcszNotationName argument will have a non-NULL value only
* for unparsed entity declarations.
*/
void XML_SetEntityDeclHandler(XML_Parser parser,
XML_EntityDeclHandler handler)
{
entityDeclHandler = handler;
}
/*
*@@ XML_SetXmlDeclHandler:
* sets a handler that is called for XML declarations and also
* for text declarations discovered in external entities.
*
* Handler prototype:
*
+ void EXPATENTRY XmlDeclHandler(void *pUserData,
+ const XML_Char *pcszVersion,
+ const XML_Char *pcszEncoding,
+ int standalone);
*
* The way to distinguish is that the version parameter will
* be NULL for text declarations. The encoding parameter may
* be NULL for an XML declaration. The standalone argument will
* contain -1, 0, or 1 indicating respectively that there was no
* standalone parameter in the declaration, that it was given
* as no, or that it was given as yes.
*/
void XML_SetXmlDeclHandler(XML_Parser parser,
XML_XmlDeclHandler handler)
{
xmlDeclHandler = handler;
}
/*
*@@ XML_SetParamEntityParsing:
* this enables parsing of @parameter_entities, including the
* external parameter entity that is the external @DTD subset,
* according to code.
*
* If parsing of parameter entities is enabled, then references
* to external parameter entities (including the external DTD
* subset) will be passed to the handler set with
* XML_SetExternalEntityRefHandler. The context passed will be 0.
*
* Unlike external general entities, external parameter entities
* can only be parsed synchronously. If the external parameter
* entity is to be parsed, it must be parsed during the call to
* the external entity ref handler: the complete sequence of
* XML_ExternalEntityParserCreate, XML_Parse/XML_ParseBuffer and
* XML_ParserFree calls must be made during this call.
*
* After XML_ExternalEntityParserCreate has been called to create
* the parser for the external parameter entity (context must be 0
* for this call), it is illegal to make any calls on the old parser
* until XML_ParserFree has been called on the newly created parser.
* If the library has been compiled without support for parameter
* entity parsing (ie without XML_DTD being defined), then
* XML_SetParamEntityParsing will return 0 if parsing of parameter
* entities is requested; otherwise it will return non-zero.
*
* NOTE: The xwphelpers implementation #defines XML_DTD in
* include\expat\expat_setup.h, which is included in all expat
* files.
*
* The choices for code are:
*
* -- XML_PARAM_ENTITY_PARSING_NEVER:
* Don't parse parameter entities or the external subset.
* This is the only choice if XML_DTD is not defined.
*
* -- XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE:
* Parse parameter entities and the external subset unless
* standalone was set to "yes" in the XML declaration.
*
* -- XML_PARAM_ENTITY_PARSING_ALWAYS
* Always parse parameter entities and the external subset.
*
* In order to read an external DTD, you also have to set an
* external entity reference handler (XML_SetExternalEntityRefHandler).
*/
int XML_SetParamEntityParsing(XML_Parser parser,
enum XML_ParamEntityParsing parsing)
{
#ifdef XML_DTD
paramEntityParsing = parsing;
return 1;
#else
return parsing == XML_PARAM_ENTITY_PARSING_NEVER;
#endif
}
/*
*@@ XML_Parse:
* parses some more of the document.
*
* The string s is a buffer containing part (or perhaps all)
* of the document. The number of bytes of s that are part
* of the document is indicated by len. This means that s
* doesn't have to be null terminated. It also means that
* if len is larger than the number of bytes in the block
* of memory that s points at, then a memory fault is
* likely. The isFinal parameter informs the parser that
* this is the last piece of the document. Frequently, the
* last piece is empty (i.e. len is zero.)
*
* If a parse error occurred, it returns 0. Otherwise it
* returns a non-zero value.
*/
int XML_Parse(XML_Parser parser,
const char *s,
int len,
int isFinal)
{
if (len == 0)
{
if (!isFinal)
return 1;
positionPtr = bufferPtr;
errorCode = processor(parser, bufferPtr, parseEndPtr = bufferEnd, 0);
if (errorCode == ERROR_EXPAT_NONE)
return 1;
eventEndPtr = eventPtr;
processor = errorProcessor;
return 0;
}
#ifndef XML_CONTEXT_BYTES
else if (bufferPtr == bufferEnd)
{
const char *end;
int nLeftOver;
parseEndByteIndex += len;
positionPtr = s;
if (isFinal)
{
errorCode = processor(parser, s, parseEndPtr = s + len, 0);
if (errorCode == ERROR_EXPAT_NONE)
return 1;
eventEndPtr = eventPtr;
processor = errorProcessor;
return 0;
}
errorCode = processor(parser, s, parseEndPtr = s + len, &end);
if (errorCode != ERROR_EXPAT_NONE)
{
eventEndPtr = eventPtr;
processor = errorProcessor;
return 0;
}
XmlUpdatePosition(encoding, positionPtr, end, &position);
nLeftOver = s + len - end;
if (nLeftOver)
{
if (buffer == 0 || nLeftOver > bufferLim - buffer)
{
/* FIXME avoid integer overflow */
buffer = buffer == 0 ? MALLOC(len * 2) : REALLOC(buffer, len * 2);
/* FIXME storage leak if realloc fails */
if (!buffer)
{
errorCode = ERROR_EXPAT_NO_MEMORY;
eventPtr = eventEndPtr = 0;
processor = errorProcessor;
return 0;
}
bufferLim = buffer + len * 2;
}
memcpy(buffer, end, nLeftOver);
bufferPtr = buffer;
bufferEnd = buffer + nLeftOver;
}
return 1;
}
#endif /* not defined XML_CONTEXT_BYTES */
else
{
memcpy(XML_GetBuffer(parser, len), s, len);
return XML_ParseBuffer(parser, len, isFinal);
}
}
/*
*@@ XML_ParseBuffer:
* this is just like XML_Parse, except in this case expat
* provides the buffer. By obtaining the buffer from expat
* with the XML_GetBuffer function, the application can
* avoid double copying of the input.
*/
int XML_ParseBuffer(XML_Parser parser,
int len,
int isFinal)
{
const char *start = bufferPtr;
positionPtr = start;
bufferEnd += len;
parseEndByteIndex += len;
errorCode = processor(parser, start, parseEndPtr = bufferEnd,
isFinal ? (const char **)0 : &bufferPtr);
if (errorCode == ERROR_EXPAT_NONE)
{
if (!isFinal)
XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position);
return 1;
}
else
{
eventEndPtr = eventPtr;
processor = errorProcessor;
return 0;
}
}
/*
*@@ XML_GetBuffer:
* obtains a buffer of size len to read a piece of the
* document into. A NULL value is returned if expat can't
* allocate enough memory for this buffer. This has to be
* called prior to every call to XML_ParseBuffer.
*
* A typical use would look like this:
*
+ for (;;)
+ {
+ int bytes_read;
+ void *buff = XML_GetBuffer(p, BUFF_SIZE);
+ if (buff == NULL)
+ // handle error
+
+ bytes_read = read(docfd, buff, BUFF_SIZE);
+ if (bytes_read < 0)
+ // handle error
+
+ if (!XML_ParseBuffer(p, bytes_read, bytes_read == 0))
+ // handle parse error
+
+ if (bytes_read == 0)
+ break;
+ }
*
*/
void *XML_GetBuffer(XML_Parser parser,
int len)
{
if (len > bufferLim - bufferEnd)
{
/* FIXME avoid integer overflow */
int neededSize = len + (bufferEnd - bufferPtr);
#ifdef XML_CONTEXT_BYTES
int keep = 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 = (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 = bufferLim - bufferPtr;
if (bufferSize == 0)
bufferSize = INIT_BUFFER_SIZE;
do
{
bufferSize *= 2;
}
while (bufferSize < neededSize);
newBuf = (char*)MALLOC(bufferSize);
if (newBuf == 0)
{
errorCode = ERROR_EXPAT_NO_MEMORY;
return 0;
}
bufferLim = newBuf + bufferSize;
#ifdef XML_CONTEXT_BYTES
if (bufferPtr)
{
int keep = 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;
}
/*
*@@ XML_GetErrorCode:
* returns what type of error has occurred.
*
* To be called when the parse functions return 0 (i.e. a
* parse error has ocurred), although the position reporting
* functions are useful outside of errors. The position reported
* is the byte position (in the original document or entity
* encoding) of the first of the sequence of characters that
* generated the current event (or the error that caused the
* parse functions to return 0.)
*
* The position reporting functions are accurate only outside
* of the DTD. In other words, they usually return bogus
* information when called from within a DTD declaration handler.
*/
XMLERROR XML_GetErrorCode(XML_Parser parser)
{
return errorCode;
}
/*
*@@ XML_GetCurrentByteIndex:
* returns the byte offset of the position.
*
* To be called on parser errors. See XML_GetErrorCode.
*/
long XML_GetCurrentByteIndex(XML_Parser parser)
{
if (eventPtr)
return parseEndByteIndex - (parseEndPtr - eventPtr);
return -1;
}
/*
*@@ XML_GetCurrentByteCount:
* return the number of bytes in the current event. Returns
* 0 if the event is inside a reference to an internal entity.
*
* To be called on parser errors. See XML_GetErrorCode.
*/
int XML_GetCurrentByteCount(XML_Parser parser)
{
if (eventEndPtr && eventPtr)
return eventEndPtr - eventPtr;
return 0;
}
/*
*@@ XML_GetInputContext:
* returns the parser's input buffer, sets the integer pointed
* at by offset to the offset within this buffer of the current
* parse position, and set the integer pointed at by size to the
* size of the returned buffer.
*
* This should only be called from within a handler during an
* active parse and the returned buffer should only be referred
* to from within the handler that made the call. This input
* buffer contains the untranslated bytes of the input.
*
* Only a limited amount of context is kept, so if the event
* triggering a call spans over a very large amount of input,
* the actual parse position may be before the beginning of the buffer.
*/
const char *XML_GetInputContext(XML_Parser parser,
int *offset,
int *size)
{
#ifdef XML_CONTEXT_BYTES
if (eventPtr && buffer)
{
*offset = eventPtr - buffer;
*size = bufferEnd - buffer;
return buffer;
}
#endif /* defined XML_CONTEXT_BYTES */
return (char *)0;
}
/*
*@@ XML_GetCurrentLineNumber:
* returns the line number of the position.
*
* Can be called on parser errors. See XML_GetErrorCode.
*/
int XML_GetCurrentLineNumber(XML_Parser parser)
{
if (eventPtr)
{
XmlUpdatePosition(encoding, positionPtr, eventPtr, &position);
positionPtr = eventPtr;
}
return position.lineNumber + 1;
}
/*
*@@ XML_GetCurrentColumnNumber:
* returns the offset, from the beginning of the current
* line, of the position.
*
* Can be called on parser errors. See XML_GetErrorCode.
*/
int XML_GetCurrentColumnNumber(XML_Parser parser)
{
if (eventPtr)
{
XmlUpdatePosition(encoding, positionPtr, eventPtr, &position);
positionPtr = eventPtr;
}
return position.columnNumber;
}
/*
*@@ XML_DefaultCurrent:
* not in the expat docs.
*/
void 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 *XML_ErrorString(int code)
{
static const XML_LChar *message[] =
{
0,
XML_T("out of memory"),
XML_T("syntax error"),
XML_T("no element found"),
XML_T("not well-formed (invalid token)"),
XML_T("unclosed token"),
XML_T("unclosed token"),
XML_T("mismatched tag"),
XML_T("duplicate attribute"),
XML_T("junk after document element"),
XML_T("illegal parameter entity reference"),
XML_T("undefined entity"),
XML_T("recursive entity reference"),
XML_T("asynchronous entity"),
XML_T("reference to invalid character number"),
XML_T("reference to binary entity"),
XML_T("reference to external entity in attribute"),
XML_T("xml processing instruction not at start of external entity"),
XML_T("unknown encoding"),
XML_T("encoding specified in XML declaration is incorrect"),
XML_T("unclosed CDATA section"),
XML_T("error in processing external entity reference"),
XML_T("document is not standalone"),
XML_T("unexpected parser state - please send a bug report")
};
if (code > 0 && code < sizeof(message) / sizeof(message[0]))
return message[code];
return 0;
}
/* const XML_LChar *
* XML_ExpatVersion(void) {
* return VERSION;
* }
*
* XML_Expat_Version
* XML_ExpatVersionInfo(void) {
* XML_Expat_Version version;
*
* version.major = XML_MAJOR_VERSION;
* version.minor = XML_MINOR_VERSION;
* version.micro = XML_MICRO_VERSION;
*
* return version;
* } */
static XMLERROR contentProcessor(XML_Parser parser,
const char *start,
const char *end,
const char **endPtr)
{
return doContent(parser, 0, encoding, start, end, endPtr);
}
static XMLERROR externalEntityInitProcessor(XML_Parser parser,
const char *start,
const char *end,
const char **endPtr)
{
XMLERROR result = initializeEncoding(parser);
if (result != ERROR_EXPAT_NONE)
return result;
processor = externalEntityInitProcessor2;
return externalEntityInitProcessor2(parser, start, end, endPtr);
}
static XMLERROR externalEntityInitProcessor2(XML_Parser parser,
const char *start,
const char *end,
const char **endPtr)
{
const char *next;
int tok = XmlContentTok(encoding, start, end, &next);
switch (tok)
{
case XML_TOK_BOM:
start = next;
break;
case XML_TOK_PARTIAL:
if (endPtr)
{
*endPtr = start;
return ERROR_EXPAT_NONE;
}
eventPtr = start;
return ERROR_EXPAT_UNCLOSED_TOKEN;
case XML_TOK_PARTIAL_CHAR:
if (endPtr)
{
*endPtr = start;
return ERROR_EXPAT_NONE;
}
eventPtr = start;
return ERROR_EXPAT_PARTIAL_CHAR;
}
processor = externalEntityInitProcessor3;
return externalEntityInitProcessor3(parser, start, end, endPtr);
}
static XMLERROR externalEntityInitProcessor3(XML_Parser parser,
const char *start,
const char *end,
const char **endPtr)
{
const char *next;
int tok = XmlContentTok(encoding, start, end, &next);
switch (tok)
{
case XML_TOK_XML_DECL:
{
XMLERROR result = processXmlDecl(parser, 1, start, next);
if (result != ERROR_EXPAT_NONE)
return result;
start = next;
}
break;
case XML_TOK_PARTIAL:
if (endPtr)
{
*endPtr = start;
return ERROR_EXPAT_NONE;
}
eventPtr = start;
return ERROR_EXPAT_UNCLOSED_TOKEN;
case XML_TOK_PARTIAL_CHAR:
if (endPtr)
{
*endPtr = start;
return ERROR_EXPAT_NONE;
}
eventPtr = start;
return ERROR_EXPAT_PARTIAL_CHAR;
}
processor = externalEntityContentProcessor;
tagLevel = 1;
return doContent(parser, 1, encoding, start, end, endPtr);
}
static XMLERROR externalEntityContentProcessor(XML_Parser parser,
const char *start,
const char *end,
const char **endPtr)
{
return doContent(parser, 1, encoding, start, end, endPtr);
}
/*
*@@ doContent:
*
*@@changed V0.9.14 (2001-08-09) [umoeller]: fixed ERROR_EXPAT_UNDEFINED_ENTITY with callback-defined encodings
*/
static XMLERROR doContent(XML_Parser parser,
int startTagLevel,
const ENCODING * enc,
const char *s,
const char *end,
const char **nextPtr)
{
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 (nextPtr)
{
*nextPtr = s;
return ERROR_EXPAT_NONE;
}
*eventEndPP = end;
if (characterDataHandler)
{
XML_Char c = 0xA;
characterDataHandler(handlerArg, &c, 1);
}
else if (defaultHandler)
reportDefault(parser, enc, s, end);
if (startTagLevel == 0)
return ERROR_EXPAT_NO_ELEMENTS;
if (tagLevel != startTagLevel)
return ERROR_EXPAT_ASYNC_ENTITY;
return ERROR_EXPAT_NONE;
case XML_TOK_NONE:
if (nextPtr)
{
*nextPtr = s;
return ERROR_EXPAT_NONE;
}
if (startTagLevel > 0)
{
if (tagLevel != startTagLevel)
return ERROR_EXPAT_ASYNC_ENTITY;
return ERROR_EXPAT_NONE;
}
return ERROR_EXPAT_NO_ELEMENTS;
case XML_TOK_INVALID:
*eventPP = next;
return ERROR_EXPAT_INVALID_TOKEN;
case XML_TOK_PARTIAL:
if (nextPtr)
{
*nextPtr = s;
return ERROR_EXPAT_NONE;
}
return ERROR_EXPAT_UNCLOSED_TOKEN;
case XML_TOK_PARTIAL_CHAR:
if (nextPtr)
{
*nextPtr = s;
return ERROR_EXPAT_NONE;
}
return ERROR_EXPAT_PARTIAL_CHAR;
case XML_TOK_ENTITY_REF:
{
const XML_Char *name;
ENTITY *entity;
unsigned long ulOfs; // V0.9.14 (2001-08-09) [umoeller]
XML_Char ch = 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,
&ulOfs);
if (!name)
return ERROR_EXPAT_NO_MEMORY;
entity = (ENTITY*)lookup(&dtd.generalEntities,
name + ulOfs, // V0.9.14 (2001-08-09) [umoeller]
0);
poolDiscard(&dtd.pool);
if (!entity)
{
if (dtd.complete || dtd.standalone)
return ERROR_EXPAT_UNDEFINED_ENTITY;
if (defaultHandler)
reportDefault(parser, enc, s, next);
break;
}
if (entity->open)
return ERROR_EXPAT_RECURSIVE_ENTITY_REF;
if (entity->notation)
return ERROR_EXPAT_BINARY_ENTITY_REF;
if (entity)
{
if (entity->textPtr)
{
XMLERROR result;
OPEN_INTERNAL_ENTITY openEntity;
if (defaultHandler && !defaultExpandInternalEntities)
{
reportDefault(parser, enc, s, next);
break;
}
entity->open = 1;
openEntity.next = openInternalEntities;
openInternalEntities = &openEntity;
openEntity.entity = entity;
openEntity.internalEventPtr = 0;
openEntity.internalEventEndPtr = 0;
result = doContent(parser,
tagLevel,
internalEncoding,
(char *)entity->textPtr,
(char *)(entity->textPtr + entity->textLen),
0);
entity->open = 0;
openInternalEntities = openEntity.next;
if (result)
return result;
}
else if (externalEntityRefHandler)
{
const XML_Char *context;
entity->open = 1;
context = getContext(parser);
entity->open = 0;
if (!context)
return ERROR_EXPAT_NO_MEMORY;
if (!externalEntityRefHandler(handlerArg, // V0.9.14 (2001-08-09) [umoeller]
externalEntityRefHandlerArg,
context,
entity->base,
entity->systemId,
entity->publicId))
return ERROR_EXPAT_EXTERNAL_ENTITY_HANDLING;
poolDiscard(&tempPool);
}
else if (defaultHandler)
reportDefault(parser, enc, s, next);
}
break;
}
case XML_TOK_START_TAG_WITH_ATTS:
if (!startElementHandler)
{
XMLERROR result = storeAtts(parser, enc, s, 0, 0);
if (result)
return result;
}
/* fall through */
case XML_TOK_START_TAG_NO_ATTS:
{
TAG *tag;
if (freeTagList)
{
tag = freeTagList;
freeTagList = freeTagList->parent;
}
else
{
tag = (TAG*)MALLOC(sizeof(TAG));
if (!tag)
return ERROR_EXPAT_NO_MEMORY;
tag->buf = (char*)MALLOC(INIT_TAG_BUF_SIZE);
if (!tag->buf)
return ERROR_EXPAT_NO_MEMORY;
tag->bufEnd = tag->buf + INIT_TAG_BUF_SIZE;
}
tag->bindings = 0;
tag->parent = tagStack;
tagStack = tag;
tag->name.localPart = 0;
tag->rawName = s + enc->minBytesPerChar;
tag->rawNameLength = XmlNameLength(enc, tag->rawName);
if (nextPtr)
{
/* Need to guarantee that:
* tag->buf + ROUND_UP(tag->rawNameLength, sizeof(XML_Char)) <= tag->bufEnd - sizeof(XML_Char) */
if (tag->rawNameLength + (int)(sizeof(XML_Char) - 1) + (int)sizeof(XML_Char) > tag->bufEnd - tag->buf)
{
int bufSize = tag->rawNameLength * 4;
bufSize = ROUND_UP(bufSize, sizeof(XML_Char));
tag->buf = (char*)REALLOC(tag->buf, bufSize);
if (!tag->buf)
return ERROR_EXPAT_NO_MEMORY;
tag->bufEnd = tag->buf + bufSize;
}
memcpy(tag->buf, tag->rawName, tag->rawNameLength);
tag->rawName = tag->buf;
}
++tagLevel;
if (startElementHandler)
{
XMLERROR result;
XML_Char *toPtr;
for (;;)
{
const char *rawNameEnd = tag->rawName + tag->rawNameLength;
const char *fromPtr = tag->rawName;
int bufSize;
if (nextPtr)
toPtr = (XML_Char *) (tag->buf + ROUND_UP(tag->rawNameLength, sizeof(XML_Char)));
else
toPtr = (XML_Char *) tag->buf;
tag->name.str = toPtr;
XmlConvert(enc,
&fromPtr, rawNameEnd,
(ICHAR **) & toPtr, (ICHAR *) tag->bufEnd - 1);
if (fromPtr == rawNameEnd)
break;
bufSize = (tag->bufEnd - tag->buf) << 1;
tag->buf = (char*)REALLOC(tag->buf, bufSize);
if (!tag->buf)
return ERROR_EXPAT_NO_MEMORY;
tag->bufEnd = tag->buf + bufSize;
if (nextPtr)
tag->rawName = tag->buf;
}
*toPtr = XML_T('\0');
result = storeAtts(parser, enc, s, &(tag->name), &(tag->bindings));
if (result)
return result;
startElementHandler(handlerArg, tag->name.str, (const XML_Char **)atts);
poolClear(&tempPool);
}
else
{
tag->name.str = 0;
if (defaultHandler)
reportDefault(parser, enc, s, next);
}
break;
}
case XML_TOK_EMPTY_ELEMENT_WITH_ATTS:
if (!startElementHandler)
{
XMLERROR result = storeAtts(parser, enc, s, 0, 0);
if (result)
return result;
}
/* fall through */
case XML_TOK_EMPTY_ELEMENT_NO_ATTS:
if (startElementHandler || endElementHandler)
{
const char *rawName = s + enc->minBytesPerChar;
XMLERROR result;
BINDING *bindings = 0;
TAG_NAME name;
name.str = poolStoreString(&tempPool,
enc,
rawName,
rawName + XmlNameLength(enc, rawName),
NULL);
if (!name.str)
return ERROR_EXPAT_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);
if (endElementHandler)
{
if (startElementHandler)
*eventPP = *eventEndPP;
endElementHandler(handlerArg, name.str);
}
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;
}
}
else if (defaultHandler)
reportDefault(parser, enc, s, next);
if (tagLevel == 0)
return epilogProcessor(parser, next, end, nextPtr);
break;
case XML_TOK_END_TAG:
if (tagLevel == startTagLevel)
return ERROR_EXPAT_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 ERROR_EXPAT_TAG_MISMATCH;
}
--tagLevel;
if (endElementHandler && tag->name.str)
{
if (tag->name.localPart)
{
XML_Char *to = (XML_Char *) tag->name.str + tag->name.uriLen;
const XML_Char *from = tag->name.localPart;
while ((*to++ = *from++) != 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 ERROR_EXPAT_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 ERROR_EXPAT_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:
{
XMLERROR 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);
if (!next)
{
processor = cdataSectionProcessor;
return result;
}
}
break;
case XML_TOK_TRAILING_RSQB:
if (nextPtr)
{
*nextPtr = s;
return ERROR_EXPAT_NONE;
}
if (characterDataHandler)
{
if (MUST_CONVERT(enc, s))
{
ICHAR *dataPtr = (ICHAR *) dataBuf;
XmlConvert(enc, &s, end, &dataPtr, (ICHAR *) dataBufEnd);
characterDataHandler(handlerArg, dataBuf, dataPtr - (ICHAR *) dataBuf);
}
else
characterDataHandler(handlerArg,
(XML_Char *) s,
(XML_Char *) end - (XML_Char *) s);
}
else if (defaultHandler)
reportDefault(parser, enc, s, end);
if (startTagLevel == 0)
{
*eventPP = end;
return ERROR_EXPAT_NO_ELEMENTS;
}
if (tagLevel != startTagLevel)
{
*eventPP = end;
return ERROR_EXPAT_ASYNC_ENTITY;
}
return ERROR_EXPAT_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, dataPtr - (ICHAR *) dataBuf);
if (s == next)
break;
*eventPP = s;
}
}
else
characterDataHandler(handlerArg,
(XML_Char *) s,
(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 ERROR_EXPAT_NO_MEMORY;
break;
case XML_TOK_COMMENT:
if (!reportComment(parser, enc, s, next))
return ERROR_EXPAT_NO_MEMORY;
break;
default:
if (defaultHandler)
reportDefault(parser, enc, s, next);
break;
}
*eventPP = s = next;
}
/* not reached */
}
/* If tagNamePtr is non-null, build a real list of attributes,
* otherwise just check the attributes for well-formedness. */
static XMLERROR storeAtts(XML_Parser parser,
const ENCODING * enc,
const char *attStr,
TAG_NAME * tagNamePtr,
BINDING ** bindingsPtr)
{
ELEMENT_TYPE *elementType = 0;
int nDefaultAtts = 0;
const XML_Char **appAtts; /* the attribute list to pass to the application */
int attIndex = 0;
int i;
int n;
int nPrefixes = 0;
BINDING *binding;
const XML_Char *localPart;
/* lookup the element type name */
if (tagNamePtr)
{
elementType = (ELEMENT_TYPE *) lookup(&dtd.elementTypes, tagNamePtr->str, 0);
if (!elementType)
{
tagNamePtr->str = poolCopyString(&dtd.pool, tagNamePtr->str);
if (!tagNamePtr->str)
return ERROR_EXPAT_NO_MEMORY;
elementType = (ELEMENT_TYPE *) lookup(&dtd.elementTypes, tagNamePtr->str, sizeof(ELEMENT_TYPE));
if (!elementType)
return ERROR_EXPAT_NO_MEMORY;
if (ns && !setElementTypePrefix(parser, elementType))
return ERROR_EXPAT_NO_MEMORY;
}
nDefaultAtts = elementType->nDefaultAtts;
}
/* get the attributes from the tokenizer */
n = XmlGetAttributes(enc, attStr, attsSize, atts);
if (n + nDefaultAtts > attsSize)
{
int oldAttsSize = attsSize;
attsSize = n + nDefaultAtts + INIT_ATTS_SIZE;
atts = (ATTRIBUTE*)REALLOC((void *)atts, attsSize * sizeof(ATTRIBUTE));
if (!atts)
return ERROR_EXPAT_NO_MEMORY;
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 ERROR_EXPAT_NO_MEMORY;
/* detect duplicate attributes */
if ((attId->name)[-1])
{
if (enc == encoding)
eventPtr = atts[i].name;
return ERROR_EXPAT_DUPLICATE_ATTRIBUTE;
}
(attId->name)[-1] = 1;
appAtts[attIndex++] = attId->name;
if (!atts[i].normalized)
{
XMLERROR result;
int isCdata = 1;
/* 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;
if (tagNamePtr)
{
appAtts[attIndex] = poolStart(&tempPool);
poolFinish(&tempPool);
}
else
poolDiscard(&tempPool);
}
else if (tagNamePtr)
{
/* the value did not need normalizing */
appAtts[attIndex] = poolStoreString(&tempPool,
enc,
atts[i].valuePtr,
atts[i].valueEnd,
NULL);
if (appAtts[attIndex] == 0)
return ERROR_EXPAT_NO_MEMORY;
poolFinish(&tempPool);
}
/* handle prefixed attribute names */
if (attId->prefix && tagNamePtr)
{
if (attId->xmlns)
{
/* deal with namespace declarations here */
if (!addBinding(parser, attId->prefix, attId, appAtts[attIndex], bindingsPtr))
return ERROR_EXPAT_NO_MEMORY;
--attIndex;
}
else
{
/* deal with other prefixed names later */
attIndex++;
nPrefixes++;
(attId->name)[-1] = 2;
}
}
else
attIndex++;
}
if (tagNamePtr)
{
int j;
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 (j = 0; j < nDefaultAtts; j++)
{
const DEFAULT_ATTRIBUTE *da = elementType->defaultAtts + j;
if (!(da->id->name)[-1] && da->value)
{
if (da->id->prefix)
{
if (da->id->xmlns)
{
if (!addBinding(parser, da->id->prefix, da->id, da->value, bindingsPtr))
return ERROR_EXPAT_NO_MEMORY;
}
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;
}
i = 0;
if (nPrefixes)
{
/* expand prefixed attribute names */
for (; i < attIndex; i += 2)
{
if (appAtts[i][-1] == 2)
{
ATTRIBUTE_ID *id;
((XML_Char *) (appAtts[i]))[-1] = 0;
id = (ATTRIBUTE_ID *) lookup(&dtd.attributeIds, appAtts[i], 0);
if (id->prefix->binding)
{
int j;
const BINDING *b = id->prefix->binding;
const XML_Char *s = appAtts[i];
for (j = 0; j < b->uriLen; j++)
{
if (!poolAppendChar(&tempPool, b->uri[j]))
return ERROR_EXPAT_NO_MEMORY;
}
while (*s++ != ':')
;
do
{
if (!poolAppendChar(&tempPool, *s))
return ERROR_EXPAT_NO_MEMORY;
}
while (*s++);
if (ns_triplets)
{
tempPool.ptr[-1] = namespaceSeparator;
s = b->prefix->name;
do
{
if (!poolAppendChar(&tempPool, *s))
return ERROR_EXPAT_NO_MEMORY;
}
while (*s++);
}
appAtts[i] = poolStart(&tempPool);
poolFinish(&tempPool);
}
if (!--nPrefixes)
break;
}
else
((XML_Char *) (appAtts[i]))[-1] = 0;
}
}
/* clear the flags that say whether attributes were specified */
for (; i < attIndex; i += 2)
((XML_Char *) (appAtts[i]))[-1] = 0;
if (!tagNamePtr)
return ERROR_EXPAT_NONE;
for (binding = *bindingsPtr; binding; binding = binding->nextTagBinding)
binding->attId->name[-1] = 0;
/* expand the element type name */
if (elementType->prefix)
{
binding = elementType->prefix->binding;
if (!binding)
return ERROR_EXPAT_NONE;
localPart = tagNamePtr->str;
while (*localPart++ != XML_T(':'))
;
}
else if (dtd.defaultPrefix.binding)
{
binding = dtd.defaultPrefix.binding;
localPart = tagNamePtr->str;
}
else
return ERROR_EXPAT_NONE;
tagNamePtr->localPart = localPart;
tagNamePtr->uriLen = binding->uriLen;
for (i = 0; localPart[i++];)
;
n = i + binding->uriLen;
if (n > binding->uriAlloc)
{
TAG *p;
XML_Char *uri = (XML_Char*)MALLOC((n + EXPAND_SPARE) * sizeof(XML_Char));
if (!uri)
return ERROR_EXPAT_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;
}
memcpy(binding->uri + binding->uriLen, localPart, i * sizeof(XML_Char));
tagNamePtr->str = binding->uri;
return ERROR_EXPAT_NONE;
}
static int addBinding(XML_Parser parser,
PREFIX * prefix,
const ATTRIBUTE_ID * attId,
const XML_Char * uri,
BINDING ** bindingsPtr)
{
BINDING *b;
int len;
for (len = 0; uri[len]; len++)
;
if (namespaceSeparator)
len++;
if (freeBindingList)
{
b = freeBindingList;
if (len > b->uriAlloc)
{
b->uri = (XML_Char*)REALLOC(b->uri, sizeof(XML_Char) * (len + EXPAND_SPARE));
if (!b->uri)
return 0;
b->uriAlloc = len + EXPAND_SPARE;
}
freeBindingList = b->nextTagBinding;
}
else
{
b = (BINDING*)MALLOC(sizeof(BINDING));
if (!b)
return 0;
b->uri = (XML_Char*)MALLOC(sizeof(XML_Char) * (len + EXPAND_SPARE));
if (!b->uri)
{
FREE(b);
return 0;
}
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;
if (*uri == XML_T('\0') && prefix == &dtd.defaultPrefix)
prefix->binding = 0;
else
prefix->binding = b;
b->nextTagBinding = *bindingsPtr;
*bindingsPtr = b;
if (startNamespaceDeclHandler)
startNamespaceDeclHandler(handlerArg, prefix->name,
prefix->binding ? uri : 0);
return 1;
}
/* The idea here is to avoid using stack for each CDATA section when
* the whole file is parsed with one call. */
static XMLERROR cdataSectionProcessor(XML_Parser parser,
const char *start,
const char *end,
const char **endPtr)
{
XMLERROR result = doCdataSection(parser, encoding, &start, end, endPtr);
if (start)
{
processor = contentProcessor;
return contentProcessor(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 XMLERROR doCdataSection(XML_Parser parser,
const ENCODING * enc,
const char **startPtr,
const char *end,
const char **nextPtr)
{
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 = 0;
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;
return ERROR_EXPAT_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, dataPtr - (ICHAR *) dataBuf);
if (s == next)
break;
*eventPP = s;
}
}
else
characterDataHandler(handlerArg,
(XML_Char *) s,
(XML_Char *) next - (XML_Char *) s);
}
else if (defaultHandler)
reportDefault(parser, enc, s, next);
break;
case XML_TOK_INVALID:
*eventPP = next;
return ERROR_EXPAT_INVALID_TOKEN;
case XML_TOK_PARTIAL_CHAR:
if (nextPtr)
{
*nextPtr = s;
return ERROR_EXPAT_NONE;
}
return ERROR_EXPAT_PARTIAL_CHAR;
case XML_TOK_PARTIAL:
case XML_TOK_NONE:
if (nextPtr)
{
*nextPtr = s;
return ERROR_EXPAT_NONE;
}
return ERROR_EXPAT_UNCLOSED_CDATA_SECTION;
default:
*eventPP = next;
return ERROR_EXPAT_UNEXPECTED_STATE;
}
*eventPP = s = next;
}
/* 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 XMLERROR ignoreSectionProcessor(XML_Parser parser,
const char *start,
const char *end,
const char **endPtr)
{
XMLERROR result = doIgnoreSection(parser, encoding, &start, end, endPtr);
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 XMLERROR doIgnoreSection(XML_Parser parser,
const ENCODING * enc,
const char **startPtr,
const char *end,
const char **nextPtr)
{
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 = 0;
tok = XmlIgnoreSectionTok(enc, s, end, &next);
*eventEndPP = next;
switch (tok)
{
case XML_TOK_IGNORE_SECT:
if (defaultHandler)
reportDefault(parser, enc, s, next);
*startPtr = next;
return ERROR_EXPAT_NONE;
case XML_TOK_INVALID:
*eventPP = next;
return ERROR_EXPAT_INVALID_TOKEN;
case XML_TOK_PARTIAL_CHAR:
if (nextPtr)
{
*nextPtr = s;
return ERROR_EXPAT_NONE;
}
return ERROR_EXPAT_PARTIAL_CHAR;
case XML_TOK_PARTIAL:
case XML_TOK_NONE:
if (nextPtr)
{
*nextPtr = s;
return ERROR_EXPAT_NONE;
}
return ERROR_EXPAT_SYNTAX; /* ERROR_EXPAT_UNCLOSED_IGNORE_SECTION */
default:
*eventPP = next;
return ERROR_EXPAT_UNEXPECTED_STATE;
}
/* not reached */
}
#endif /* XML_DTD */
static XMLERROR initializeEncoding(XML_Parser parser)
{
const char *s;
#ifdef XML_UNICODE
char encodingBuf[128];
if (!protocolEncodingName)
s = 0;
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 ERROR_EXPAT_NONE;
return handleUnknownEncoding(parser, protocolEncodingName);
}
static XMLERROR processXmlDecl(XML_Parser parser,
int isGeneralTextEntity,
const char *s,
const char *next)
{
const char *encodingName = 0;
const char *storedEncName = 0;
const ENCODING *newEncoding = 0;
const char *version = 0;
const char *versionend;
const char *storedversion = 0;
int standalone = -1;
if (!(ns
? XmlParseXmlDeclNS
: XmlParseXmlDecl) (isGeneralTextEntity,
encoding,
s,
next,
&eventPtr,
&version,
&versionend,
&encodingName,
&newEncoding,
&standalone))
return ERROR_EXPAT_SYNTAX;
if (!isGeneralTextEntity && standalone == 1)
{
dtd.standalone = 1;
#ifdef XML_DTD
if (paramEntityParsing == XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE)
paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
#endif /* XML_DTD */
}
if (xmlDeclHandler)
{
if (encodingName)
{
storedEncName = poolStoreString(&temp2Pool,
encoding,
encodingName,
encodingName
+ XmlNameLength(encoding, encodingName),
NULL);
if (!storedEncName)
return ERROR_EXPAT_NO_MEMORY;
poolFinish(&temp2Pool);
}
if (version)
{
storedversion = poolStoreString(&temp2Pool,
encoding,
version,
versionend - encoding->minBytesPerChar,
NULL);
if (!storedversion)
return ERROR_EXPAT_NO_MEMORY;
}
xmlDeclHandler(handlerArg, storedversion, storedEncName, standalone);
}
else if (defaultHandler)
reportDefault(parser, encoding, s, next);
if (!protocolEncodingName)
{
if (newEncoding)
{
if (newEncoding->minBytesPerChar != encoding->minBytesPerChar)
{
eventPtr = encodingName;
return ERROR_EXPAT_INCORRECT_ENCODING;
}
encoding = newEncoding;
}
else if (encodingName)
{
XMLERROR result;
if (!storedEncName)
{
storedEncName = poolStoreString(&temp2Pool,
encoding,
encodingName,
encodingName
+ XmlNameLength(encoding, encodingName),
NULL);
if (!storedEncName)
return ERROR_EXPAT_NO_MEMORY;
}
result = handleUnknownEncoding(parser, storedEncName);
poolClear(&tempPool);
if (result == ERROR_EXPAT_UNKNOWN_ENCODING)
eventPtr = encodingName;
return result;
}
}
if (storedEncName || storedversion)
poolClear(&temp2Pool);
return ERROR_EXPAT_NONE;
}
static XMLERROR 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 = 0;
info.data = 0;
info.release = 0;
if (unknownEncodingHandler(unknownEncodingHandlerData, encodingName, &info))
{
ENCODING *enc;
unknownEncodingMem = MALLOC(XmlSizeOfUnknownEncoding());
if (!unknownEncodingMem)
{
if (info.release)
info.release(info.data);
return ERROR_EXPAT_NO_MEMORY;
}
enc = (ns
? XmlInitUnknownEncodingNS
: XmlInitUnknownEncoding) (unknownEncodingMem,
info.map,
info.convert,
info.data);
if (enc)
{
unknownEncodingData = info.data;
unknownEncodingRelease = (void(*)(void*))info.release;
encoding = enc;
return ERROR_EXPAT_NONE;
}
}
if (info.release)
info.release(info.data);
}
return ERROR_EXPAT_UNKNOWN_ENCODING;
}
static XMLERROR prologInitProcessor(XML_Parser parser,
const char *s,
const char *end,
const char **nextPtr)
{
XMLERROR result = initializeEncoding(parser);
if (result != ERROR_EXPAT_NONE)
return result;
processor = prologProcessor;
return prologProcessor(parser, s, end, nextPtr);
}
static XMLERROR prologProcessor(XML_Parser parser,
const char *s,
const char *end,
const char **nextPtr)
{
const char *next;
int tok = XmlPrologTok(encoding, s, end, &next);
return doProlog(parser, encoding, s, end, tok, next, nextPtr);
}
static XMLERROR doProlog(XML_Parser parser,
const ENCODING * enc,
const char *s,
const char *end,
int tok,
const char *next,
const char **nextPtr)
{
#ifdef XML_DTD
static const XML_Char externalSubsetName[] =
{'#', '\0'};
#endif /* XML_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;
*eventPP = s;
*eventEndPP = next;
if (tok <= 0)
{
if (nextPtr != 0 && tok != XML_TOK_INVALID)
{
*nextPtr = s;
return ERROR_EXPAT_NONE;
}
switch (tok)
{
case XML_TOK_INVALID:
*eventPP = next;
return ERROR_EXPAT_INVALID_TOKEN;
case XML_TOK_PARTIAL:
return ERROR_EXPAT_UNCLOSED_TOKEN;
case XML_TOK_PARTIAL_CHAR:
return ERROR_EXPAT_PARTIAL_CHAR;
case XML_TOK_NONE:
#ifdef XML_DTD
if (enc != encoding)
return ERROR_EXPAT_NONE;
if (parentParser)
{
if (XmlTokenRole(&prologState, XML_TOK_NONE, end, end, enc)
== XML_ROLE_ERROR)
return ERROR_EXPAT_SYNTAX;
hadExternalDoctype = 0;
return ERROR_EXPAT_NONE;
}
#endif /* XML_DTD */
return ERROR_EXPAT_NO_ELEMENTS;
default:
tok = -tok;
next = end;
break;
}
}
role = XmlTokenRole(&prologState, tok, s, next, enc);
switch (role)
{
case XML_ROLE_XML_DECL:
{
XMLERROR result = processXmlDecl(parser, 0, s, next);
if (result != ERROR_EXPAT_NONE)
return result;
enc = encoding;
}
break;
case XML_ROLE_DOCTYPE_NAME:
if (startDoctypeDeclHandler)
{
doctypeName = poolStoreString(&tempPool, enc, s, next, NULL);
if (!doctypeName)
return ERROR_EXPAT_NO_MEMORY;
poolFinish(&tempPool);
doctypeSysid = 0;
doctypePubid = 0;
}
break;
case XML_ROLE_DOCTYPE_INTERNAL_SUBSET:
if (startDoctypeDeclHandler)
{
startDoctypeDeclHandler(handlerArg, doctypeName, doctypeSysid,
doctypePubid, 1);
doctypeName = 0;
poolClear(&tempPool);
}
break;
#ifdef XML_DTD
case XML_ROLE_TEXT_DECL:
{
XMLERROR result = processXmlDecl(parser, 1, s, next);
if (result != ERROR_EXPAT_NONE)
return result;
enc = encoding;
}
break;
#endif /* XML_DTD */
case XML_ROLE_DOCTYPE_PUBLIC_ID:
if (startDoctypeDeclHandler)
{
doctypePubid = poolStoreString(&tempPool, enc, s + 1, next - 1, NULL);
if (!doctypePubid)
return ERROR_EXPAT_NO_MEMORY;
poolFinish(&tempPool);
}
#ifdef XML_DTD
declEntity = (ENTITY *) lookup(&dtd.paramEntities,
externalSubsetName,
sizeof(ENTITY));
if (!declEntity)
return ERROR_EXPAT_NO_MEMORY;
#endif /* XML_DTD */
/* fall through */
case XML_ROLE_ENTITY_PUBLIC_ID:
if (!XmlIsPublicId(enc, s, next, eventPP))
return ERROR_EXPAT_SYNTAX;
if (declEntity)
{
XML_Char *tem = poolStoreString(&dtd.pool,
enc,
s + enc->minBytesPerChar,
next - enc->minBytesPerChar,
NULL);
if (!tem)
return ERROR_EXPAT_NO_MEMORY;
normalizePublicId(tem);
declEntity->publicId = tem;
poolFinish(&dtd.pool);
}
break;
case XML_ROLE_DOCTYPE_CLOSE:
if (doctypeName)
{
startDoctypeDeclHandler(handlerArg, doctypeName,
doctypeSysid, doctypePubid, 0);
poolClear(&tempPool);
}
if (dtd.complete && hadExternalDoctype)
{
dtd.complete = 0;
#ifdef XML_DTD
if (paramEntityParsing && externalEntityRefHandler)
{
ENTITY *entity = (ENTITY *) lookup(&dtd.paramEntities,
externalSubsetName,
0);
if (!externalEntityRefHandler(handlerArg, // V0.9.14 (2001-08-09) [umoeller]
externalEntityRefHandlerArg,
0,
entity->base,
entity->systemId,
entity->publicId))
return ERROR_EXPAT_EXTERNAL_ENTITY_HANDLING;
}
#endif /* XML_DTD */
if (!dtd.complete
&& !dtd.standalone
&& notStandaloneHandler
&& !notStandaloneHandler(handlerArg))
return ERROR_EXPAT_NOT_STANDALONE;
}
if (endDoctypeDeclHandler)
endDoctypeDeclHandler(handlerArg);
break;
case XML_ROLE_INSTANCE_START:
processor = contentProcessor;
return contentProcessor(parser, s, end, nextPtr);
case XML_ROLE_ATTLIST_ELEMENT_NAME:
declElementType = getElementType(parser, enc, s, next);
if (!declElementType)
return ERROR_EXPAT_NO_MEMORY;
break;
case XML_ROLE_ATTRIBUTE_NAME:
declAttributeId = getAttributeId(parser, enc, s, next);
if (!declAttributeId)
return ERROR_EXPAT_NO_MEMORY;
declAttributeIsCdata = 0;
declAttributeType = 0;
declAttributeIsId = 0;
break;
case XML_ROLE_ATTRIBUTE_TYPE_CDATA:
declAttributeIsCdata = 1;
declAttributeType = "CDATA";
break;
case XML_ROLE_ATTRIBUTE_TYPE_ID:
declAttributeIsId = 1;
declAttributeType = "ID";
break;
case XML_ROLE_ATTRIBUTE_TYPE_IDREF:
declAttributeType = "IDREF";
break;
case XML_ROLE_ATTRIBUTE_TYPE_IDREFS:
declAttributeType = "IDREFS";
break;
case XML_ROLE_ATTRIBUTE_TYPE_ENTITY:
declAttributeType = "ENTITY";
break;
case XML_ROLE_ATTRIBUTE_TYPE_ENTITIES:
declAttributeType = "ENTITIES";
break;
case XML_ROLE_ATTRIBUTE_TYPE_NMTOKEN:
declAttributeType = "NMTOKEN";
break;
case XML_ROLE_ATTRIBUTE_TYPE_NMTOKENS:
declAttributeType = "NMTOKENS";
break;
case XML_ROLE_ATTRIBUTE_ENUM_VALUE:
case XML_ROLE_ATTRIBUTE_NOTATION_VALUE:
if (attlistDeclHandler)
{
char *prefix;
if (declAttributeType)
{
prefix = "|";
}
else
{
prefix = (role == XML_ROLE_ATTRIBUTE_NOTATION_VALUE
? "NOTATION("
: "(");
}
if (!poolAppendString(&tempPool, prefix))
return ERROR_EXPAT_NO_MEMORY;
if (!poolAppend(&tempPool, enc, s, next, NULL))
return ERROR_EXPAT_NO_MEMORY;
declAttributeType = tempPool.start;
}
break;
case XML_ROLE_IMPLIED_ATTRIBUTE_VALUE:
case XML_ROLE_REQUIRED_ATTRIBUTE_VALUE:
if (dtd.complete
&& !defineAttribute(declElementType, declAttributeId,
declAttributeIsCdata, declAttributeIsId, 0,
parser))
return ERROR_EXPAT_NO_MEMORY;
if (attlistDeclHandler && declAttributeType)
{
if (*declAttributeType == '('
|| (*declAttributeType == 'N' && declAttributeType[1] == 'O'))
{
/* Enumerated or Notation type */
if (!poolAppendChar(&tempPool, ')')
|| !poolAppendChar(&tempPool, '\0'))
return ERROR_EXPAT_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);
}
break;
case XML_ROLE_DEFAULT_ATTRIBUTE_VALUE:
case XML_ROLE_FIXED_ATTRIBUTE_VALUE:
{
const XML_Char *attVal;
XMLERROR result
= storeAttributeValue(parser, enc, declAttributeIsCdata,
s + enc->minBytesPerChar,
next - enc->minBytesPerChar,
&dtd.pool);
if (result)
return result;
attVal = poolStart(&dtd.pool);
poolFinish(&dtd.pool);
if (dtd.complete
/* ID attributes aren't allowed to have a default */
&& !defineAttribute(declElementType, declAttributeId, declAttributeIsCdata, 0, attVal, parser))
return ERROR_EXPAT_NO_MEMORY;
if (attlistDeclHandler && declAttributeType)
{
if (*declAttributeType == '('
|| (*declAttributeType == 'N' && declAttributeType[1] == 'O'))
{
/* Enumerated or Notation type */
if (!poolAppendChar(&tempPool, ')')
|| !poolAppendChar(&tempPool, '\0'))
return ERROR_EXPAT_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);
}
break;
}
case XML_ROLE_ENTITY_VALUE:
{
XMLERROR result = storeEntityValue(parser, enc,
s + enc->minBytesPerChar,
next - enc->minBytesPerChar);
if (declEntity)
{
declEntity->textPtr = poolStart(&dtd.pool);
declEntity->textLen = poolLength(&dtd.pool);
poolFinish(&dtd.pool);
if (entityDeclHandler)
{
*eventEndPP = s;
entityDeclHandler(handlerArg,
declEntity->name,
declEntity->is_param,
declEntity->textPtr,
declEntity->textLen,
curBase, 0, 0, 0);
}
}
else
poolDiscard(&dtd.pool);
if (result != ERROR_EXPAT_NONE)
return result;
}
break;
case XML_ROLE_DOCTYPE_SYSTEM_ID:
if (startDoctypeDeclHandler)
{
doctypeSysid = poolStoreString(&tempPool,
enc,
s + 1,
next - 1,
NULL);
if (!doctypeSysid)
return ERROR_EXPAT_NO_MEMORY;
poolFinish(&tempPool);
}
if (!dtd.standalone
#ifdef XML_DTD
&& !paramEntityParsing
#endif /* XML_DTD */
&& notStandaloneHandler
&& !notStandaloneHandler(handlerArg))
return ERROR_EXPAT_NOT_STANDALONE;
hadExternalDoctype = 1;
#ifndef XML_DTD
break;
#else /* XML_DTD */
if (!declEntity)
{
declEntity = (ENTITY *) lookup(&dtd.paramEntities,
externalSubsetName,
sizeof(ENTITY));
declEntity->publicId = 0;
if (!declEntity)
return ERROR_EXPAT_NO_MEMORY;
}
/* fall through */
#endif /* XML_DTD */
case XML_ROLE_ENTITY_SYSTEM_ID:
if (declEntity)
{
declEntity->systemId = poolStoreString(&dtd.pool,
enc,
s + enc->minBytesPerChar,
next - enc->minBytesPerChar,
NULL);
if (!declEntity->systemId)
return ERROR_EXPAT_NO_MEMORY;
declEntity->base = curBase;
poolFinish(&dtd.pool);
}
break;
case XML_ROLE_ENTITY_COMPLETE:
if (declEntity && entityDeclHandler)
{
*eventEndPP = s;
entityDeclHandler(handlerArg,
declEntity->name,
0, 0, 0,
declEntity->base,
declEntity->systemId,
declEntity->publicId,
0);
}
break;
case XML_ROLE_ENTITY_NOTATION_NAME:
if (declEntity)
{
declEntity->notation = poolStoreString(&dtd.pool,
enc,
s,
next,
NULL);
if (!declEntity->notation)
return ERROR_EXPAT_NO_MEMORY;
poolFinish(&dtd.pool);
if (unparsedEntityDeclHandler)
{
*eventEndPP = s;
unparsedEntityDeclHandler(handlerArg,
declEntity->name,
declEntity->base,
declEntity->systemId,
declEntity->publicId,
declEntity->notation);
}
else if (entityDeclHandler)
{
*eventEndPP = s;
entityDeclHandler(handlerArg,
declEntity->name,
0, 0, 0,
declEntity->base,
declEntity->systemId,
declEntity->publicId,
declEntity->notation);
}
}
break;
case XML_ROLE_GENERAL_ENTITY_NAME:
{
const XML_Char *name;
if (XmlPredefinedEntityName(enc, s, next))
{
declEntity = 0;
break;
}
name = poolStoreString(&dtd.pool,
enc,
s,
next,
NULL);
if (!name)
return ERROR_EXPAT_NO_MEMORY;
if (dtd.complete)
{
declEntity = (ENTITY *) lookup(&dtd.generalEntities, name, sizeof(ENTITY));
if (!declEntity)
return ERROR_EXPAT_NO_MEMORY;
if (declEntity->name != name)
{
poolDiscard(&dtd.pool);
declEntity = 0;
}
else
{
poolFinish(&dtd.pool);
declEntity->publicId = 0;
declEntity->is_param = 0;
}
}
else
{
poolDiscard(&dtd.pool);
declEntity = 0;
}
}
break;
case XML_ROLE_PARAM_ENTITY_NAME:
#ifdef XML_DTD
if (dtd.complete)
{
const XML_Char *name = poolStoreString(&dtd.pool, enc, s, next, NULL);
if (!name)
return ERROR_EXPAT_NO_MEMORY;
declEntity = (ENTITY *) lookup(&dtd.paramEntities,
name, sizeof(ENTITY));
if (!declEntity)
return ERROR_EXPAT_NO_MEMORY;
if (declEntity->name != name)
{
poolDiscard(&dtd.pool);
declEntity = 0;
}
else
{
poolFinish(&dtd.pool);
declEntity->publicId = 0;
declEntity->is_param = 1;
}
}
#else /* not XML_DTD */
declEntity = 0;
#endif /* not XML_DTD */
break;
case XML_ROLE_NOTATION_NAME:
declNotationPublicId = 0;
declNotationName = 0;
if (notationDeclHandler)
{
declNotationName = poolStoreString(&tempPool, enc, s, next, NULL);
if (!declNotationName)
return ERROR_EXPAT_NO_MEMORY;
poolFinish(&tempPool);
}
break;
case XML_ROLE_NOTATION_PUBLIC_ID:
if (!XmlIsPublicId(enc, s, next, eventPP))
return ERROR_EXPAT_SYNTAX;
if (declNotationName)
{
XML_Char *tem = poolStoreString(&tempPool,
enc,
s + enc->minBytesPerChar,
next - enc->minBytesPerChar,
NULL);
if (!tem)
return ERROR_EXPAT_NO_MEMORY;
normalizePublicId(tem);
declNotationPublicId = tem;
poolFinish(&tempPool);
}
break;
case XML_ROLE_NOTATION_SYSTEM_ID:
if (declNotationName && notationDeclHandler)
{
const XML_Char *systemId
= poolStoreString(&tempPool, enc,
s + enc->minBytesPerChar,
next - enc->minBytesPerChar,
NULL);
if (!systemId)
return ERROR_EXPAT_NO_MEMORY;
*eventEndPP = s;
notationDeclHandler(handlerArg,
declNotationName,
curBase,
systemId,
declNotationPublicId);
}
poolClear(&tempPool);
break;
case XML_ROLE_NOTATION_NO_SYSTEM_ID:
if (declNotationPublicId && notationDeclHandler)
{
*eventEndPP = s;
notationDeclHandler(handlerArg,
declNotationName,
curBase,
0,
declNotationPublicId);
}
poolClear(&tempPool);
break;
case XML_ROLE_ERROR:
switch (tok)
{
case XML_TOK_PARAM_ENTITY_REF:
return ERROR_EXPAT_PARAM_ENTITY_REF;
case XML_TOK_XML_DECL:
return ERROR_EXPAT_MISPLACED_XML_PI;
default:
return ERROR_EXPAT_SYNTAX;
}
#ifdef XML_DTD
case XML_ROLE_IGNORE_SECT:
{
XMLERROR result;
if (defaultHandler)
reportDefault(parser, enc, s, next);
result = doIgnoreSection(parser, enc, &next, end, nextPtr);
if (!next)
{
processor = ignoreSectionProcessor;
return result;
}
}
break;
#endif /* XML_DTD */
case XML_ROLE_GROUP_OPEN:
if (prologState.level >= groupSize)
{
if (groupSize)
{
groupConnector = (char*)REALLOC(groupConnector, groupSize *= 2);
if (dtd.scaffIndex)
dtd.scaffIndex = (int*)REALLOC(dtd.scaffIndex, groupSize * sizeof(int));
}
else
groupConnector = (char*)MALLOC(groupSize = 32);
if (!groupConnector)
return ERROR_EXPAT_NO_MEMORY;
}
groupConnector[prologState.level] = 0;
if (dtd.in_eldecl)
{
int myindex = nextScaffoldPart(parser);
if (myindex < 0)
return ERROR_EXPAT_NO_MEMORY;
dtd.scaffIndex[dtd.scaffLevel] = myindex;
dtd.scaffLevel++;
dtd.scaffold[myindex].type = XML_CTYPE_SEQ;
}
break;
case XML_ROLE_GROUP_SEQUENCE:
if (groupConnector[prologState.level] == '|')
return ERROR_EXPAT_SYNTAX;
groupConnector[prologState.level] = ',';
break;
case XML_ROLE_GROUP_CHOICE:
if (groupConnector[prologState.level] == ',')
return ERROR_EXPAT_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;
}
groupConnector[prologState.level] = '|';
break;
case XML_ROLE_PARAM_ENTITY_REF:
#ifdef XML_DTD
case XML_ROLE_INNER_PARAM_ENTITY_REF:
if (paramEntityParsing
&& (dtd.complete || role == XML_ROLE_INNER_PARAM_ENTITY_REF))
{
const XML_Char *name;
ENTITY *entity;
name = poolStoreString(&dtd.pool, enc,
s + enc->minBytesPerChar,
next - enc->minBytesPerChar,
NULL);
if (!name)
return ERROR_EXPAT_NO_MEMORY;
entity = (ENTITY *) lookup(&dtd.paramEntities, name, 0);
poolDiscard(&dtd.pool);
if (!entity)
{
/* FIXME what to do if !dtd.complete? */
return ERROR_EXPAT_UNDEFINED_ENTITY;
}
if (entity->open)
return ERROR_EXPAT_RECURSIVE_ENTITY_REF;
if (entity->textPtr)
{
XMLERROR result;
result = processInternalParamEntity(parser, entity);
if (result != ERROR_EXPAT_NONE)
return result;
break;
}
if (role == XML_ROLE_INNER_PARAM_ENTITY_REF)
return ERROR_EXPAT_PARAM_ENTITY_REF;
if (externalEntityRefHandler)
{
dtd.complete = 0;
entity->open = 1;
if (!externalEntityRefHandler(handlerArg, // V0.9.14 (2001-08-09) [umoeller]
externalEntityRefHandlerArg,
0,
entity->base,
entity->systemId,
entity->publicId))
{
entity->open = 0;
return ERROR_EXPAT_EXTERNAL_ENTITY_HANDLING;
}
entity->open = 0;
if (dtd.complete)
break;
}
}
#endif /* XML_DTD */
if (!dtd.standalone
&& notStandaloneHandler
&& !notStandaloneHandler(handlerArg))
return ERROR_EXPAT_NOT_STANDALONE;
dtd.complete = 0;
if (defaultHandler)
reportDefault(parser, enc, s, next);
break;
/* Element declaration stuff */
case XML_ROLE_ELEMENT_NAME:
if (elementDeclHandler)
{
declElementType = getElementType(parser, enc, s, next);
if (!declElementType)
return ERROR_EXPAT_NO_MEMORY;
dtd.scaffLevel = 0;
dtd.scaffCount = 0;
dtd.in_eldecl = 1;
}
break;
case XML_ROLE_CONTENT_ANY:
case XML_ROLE_CONTENT_EMPTY:
if (dtd.in_eldecl)
{
if (elementDeclHandler)
{
XMLCONTENT *content = (XMLCONTENT *) MALLOC(sizeof(XMLCONTENT));
if (!content)
return ERROR_EXPAT_NO_MEMORY;
content->quant = XML_CQUANT_NONE;
content->name = 0;
content->numchildren = 0;
content->children = 0;
content->type = ((role == XML_ROLE_CONTENT_ANY) ?
XML_CTYPE_ANY :
XML_CTYPE_EMPTY);
*eventEndPP = s;
elementDeclHandler(handlerArg, declElementType->name, content);
}
dtd.in_eldecl = 0;
}
break;
case XML_ROLE_CONTENT_PCDATA:
if (dtd.in_eldecl)
{
dtd.scaffold[dtd.scaffIndex[dtd.scaffLevel - 1]].type = XML_CTYPE_MIXED;
}
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 char *nxt = quant == XML_CQUANT_NONE ? next : next - 1;
int myindex = nextScaffoldPart(parser);
if (myindex < 0)
return ERROR_EXPAT_NO_MEMORY;
dtd.scaffold[myindex].type = XML_CTYPE_NAME;
dtd.scaffold[myindex].quant = quant;
el = getElementType(parser, enc, s, nxt);
if (!el)
return ERROR_EXPAT_NO_MEMORY;
dtd.scaffold[myindex].name = el->name;
dtd.contentStringLen += nxt - s + 1;
}
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)
{
dtd.scaffLevel--;
dtd.scaffold[dtd.scaffIndex[dtd.scaffLevel]].quant = quant;
if (dtd.scaffLevel == 0)
{
if (elementDeclHandler)
{
XMLCONTENT *model = build_model(parser);
if (!model)
return ERROR_EXPAT_NO_MEMORY;
*eventEndPP = s;
elementDeclHandler(handlerArg, declElementType->name, model);
}
dtd.in_eldecl = 0;
dtd.contentStringLen = 0;
}
}
break;
/* End element declaration stuff */
case XML_ROLE_NONE:
switch (tok)
{
case XML_TOK_PI:
if (!reportProcessingInstruction(parser, enc, s, next))
return ERROR_EXPAT_NO_MEMORY;
break;
case XML_TOK_COMMENT:
if (!reportComment(parser, enc, s, next))
return ERROR_EXPAT_NO_MEMORY;
break;
}
break;
}
if (defaultHandler)
{
switch (tok)
{
case XML_TOK_PI:
case XML_TOK_COMMENT:
case XML_TOK_BOM:
case XML_TOK_XML_DECL:
#ifdef XML_DTD
case XML_TOK_IGNORE_SECT:
#endif /* XML_DTD */
case XML_TOK_PARAM_ENTITY_REF:
break;
default:
#ifdef XML_DTD
if (role != XML_ROLE_IGNORE_SECT)
#endif /* XML_DTD */
reportDefault(parser, enc, s, next);
}
}
s = next;
tok = XmlPrologTok(enc, s, end, &next);
}
/* not reached */
}
static XMLERROR epilogProcessor(XML_Parser parser,
const char *s,
const char *end,
const char **nextPtr)
{
processor = epilogProcessor;
eventPtr = s;
for (;;)
{
const char *next;
int tok = XmlPrologTok(encoding, s, end, &next);
eventEndPtr = next;
switch (tok)
{
case -XML_TOK_PROLOG_S:
if (defaultHandler)
{
eventEndPtr = end;
reportDefault(parser, encoding, s, end);
}
/* fall through */
case XML_TOK_NONE:
if (nextPtr)
*nextPtr = end;
return ERROR_EXPAT_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 ERROR_EXPAT_NO_MEMORY;
break;
case XML_TOK_COMMENT:
if (!reportComment(parser, encoding, s, next))
return ERROR_EXPAT_NO_MEMORY;
break;
case XML_TOK_INVALID:
eventPtr = next;
return ERROR_EXPAT_INVALID_TOKEN;
case XML_TOK_PARTIAL:
if (nextPtr)
{
*nextPtr = s;
return ERROR_EXPAT_NONE;
}
return ERROR_EXPAT_UNCLOSED_TOKEN;
case XML_TOK_PARTIAL_CHAR:
if (nextPtr)
{
*nextPtr = s;
return ERROR_EXPAT_NONE;
}
return ERROR_EXPAT_PARTIAL_CHAR;
default:
return ERROR_EXPAT_JUNK_AFTER_DOC_ELEMENT;
}
eventPtr = s = next;
}
}
#ifdef XML_DTD
static XMLERROR processInternalParamEntity(XML_Parser parser,
ENTITY * entity)
{
const char *s, *end, *next;
int tok;
XMLERROR result;
OPEN_INTERNAL_ENTITY openEntity;
entity->open = 1;
openEntity.next = openInternalEntities;
openInternalEntities = &openEntity;
openEntity.entity = entity;
openEntity.internalEventPtr = 0;
openEntity.internalEventEndPtr = 0;
s = (char *)entity->textPtr;
end = (char *)(entity->textPtr + entity->textLen);
tok = XmlPrologTok(internalEncoding, s, end, &next);
result = doProlog(parser, internalEncoding, s, end, tok, next, 0);
entity->open = 0;
openInternalEntities = openEntity.next;
return result;
}
#endif /* XML_DTD */
static XMLERROR errorProcessor(XML_Parser parser,
const char *s,
const char *end,
const char **nextPtr)
{
return errorCode;
}
static XMLERROR storeAttributeValue(XML_Parser parser,
const ENCODING * enc,
int isCdata,
const char *ptr,
const char *end,
STRING_POOL * pool)
{
XMLERROR 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 ERROR_EXPAT_NO_MEMORY;
return ERROR_EXPAT_NONE;
}
/*
*@@ appendAttributeValue:
*
*@@changed V0.9.14 (2001-08-09) [umoeller]: fixed ERROR_EXPAT_UNDEFINED_ENTITY with callback-defined encodings
*/
static XMLERROR appendAttributeValue(XML_Parser parser,
const ENCODING * enc,
int isCdata,
const char *ptr,
const char *end,
STRING_POOL * pool)
{
for (;;)
{
const char *next;
int tok = XmlAttributeValueTok(enc, ptr, end, &next);
switch (tok)
{
case XML_TOK_NONE:
return ERROR_EXPAT_NONE;
case XML_TOK_INVALID:
if (enc == encoding)
eventPtr = next;
return ERROR_EXPAT_INVALID_TOKEN;
case XML_TOK_PARTIAL:
if (enc == encoding)
eventPtr = ptr;
return ERROR_EXPAT_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 ERROR_EXPAT_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 ERROR_EXPAT_BAD_CHAR_REF;
}
for (i = 0; i < n; i++)
{
if (!poolAppendChar(pool, buf[i]))
return ERROR_EXPAT_NO_MEMORY;
}
}
break;
case XML_TOK_DATA_CHARS:
if (!poolAppend(pool, enc, ptr, next, NULL))
return ERROR_EXPAT_NO_MEMORY;
break;
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 ERROR_EXPAT_NO_MEMORY;
break;
case XML_TOK_ENTITY_REF:
{
const XML_Char *name;
ENTITY *entity;
unsigned long ulOfs; // V0.9.14 (2001-08-09) [umoeller]
XML_Char ch = XmlPredefinedEntityName(enc,
ptr + enc->minBytesPerChar,
next - enc->minBytesPerChar);
if (ch)
{
if (!poolAppendChar(pool, ch))
return ERROR_EXPAT_NO_MEMORY;
break;
}
name = poolStoreString(&temp2Pool, enc,
ptr + enc->minBytesPerChar,
next - enc->minBytesPerChar,
&ulOfs); // V0.9.14 (2001-08-09) [umoeller]
if (!name)
return ERROR_EXPAT_NO_MEMORY;
entity = (ENTITY *) lookup(&dtd.generalEntities,
name + ulOfs, // V0.9.14 (2001-08-09) [umoeller]
0);
poolDiscard(&temp2Pool);
if (!entity)
{
if (dtd.complete)
{
if (enc == encoding)
eventPtr = ptr;
return ERROR_EXPAT_UNDEFINED_ENTITY;
}
}
else if (entity->open)
{
if (enc == encoding)
eventPtr = ptr;
return ERROR_EXPAT_RECURSIVE_ENTITY_REF;
}
else if (entity->notation)
{
if (enc == encoding)
eventPtr = ptr;
return ERROR_EXPAT_BINARY_ENTITY_REF;
}
else if (!entity->textPtr)
{
if (enc == encoding)
eventPtr = ptr;
return ERROR_EXPAT_ATTRIBUTE_EXTERNAL_ENTITY_REF;
}
else
{
XMLERROR result;
const XML_Char *textEnd = entity->textPtr + entity->textLen;
entity->open = 1;
result = appendAttributeValue(parser, internalEncoding, isCdata, (char *)entity->textPtr, (char *)textEnd, pool);
entity->open = 0;
if (result)
return result;
}
}
break;
default:
if (enc == encoding)
eventPtr = ptr;
return ERROR_EXPAT_UNEXPECTED_STATE;
}
ptr = next;
}
/* not reached */
}
static XMLERROR storeEntityValue(XML_Parser parser,
const ENCODING * enc,
const char *entityTextPtr,
const char *entityTextEnd)
{
STRING_POOL *pool = &(dtd.pool);
for (;;)
{
const char *next;
int tok = XmlEntityValueTok(enc, entityTextPtr, entityTextEnd, &next);
switch (tok)
{
case XML_TOK_PARAM_ENTITY_REF:
#ifdef XML_DTD
if (parentParser || enc != encoding)
{
XMLERROR result;
const XML_Char *name;
ENTITY *entity;
name = poolStoreString(&tempPool, enc,
entityTextPtr + enc->minBytesPerChar,
next - enc->minBytesPerChar,
NULL);
if (!name)
return ERROR_EXPAT_NO_MEMORY;
entity = (ENTITY *) lookup(&dtd.paramEntities, name, 0);
poolDiscard(&tempPool);
if (!entity)
{
if (enc == encoding)
eventPtr = entityTextPtr;
return ERROR_EXPAT_UNDEFINED_ENTITY;
}
if (entity->open)
{
if (enc == encoding)
eventPtr = entityTextPtr;
return ERROR_EXPAT_RECURSIVE_ENTITY_REF;
}
if (entity->systemId)
{
if (enc == encoding)
eventPtr = entityTextPtr;
return ERROR_EXPAT_PARAM_ENTITY_REF;
}
entity->open = 1;
result = storeEntityValue(parser,
internalEncoding,
(char *)entity->textPtr,
(char *)(entity->textPtr + entity->textLen));
entity->open = 0;
if (result)
return result;
break;
}
#endif /* XML_DTD */
eventPtr = entityTextPtr;
return ERROR_EXPAT_SYNTAX;
case XML_TOK_NONE:
return ERROR_EXPAT_NONE;
case XML_TOK_ENTITY_REF:
case XML_TOK_DATA_CHARS:
if (!poolAppend(pool, enc, entityTextPtr, next, NULL))
return ERROR_EXPAT_NO_MEMORY;
break;
case XML_TOK_TRAILING_CR:
next = entityTextPtr + enc->minBytesPerChar;
/* fall through */
case XML_TOK_DATA_NEWLINE:
if (pool->end == pool->ptr && !poolGrow(pool))
return ERROR_EXPAT_NO_MEMORY;
*(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;
return ERROR_EXPAT_BAD_CHAR_REF;
}
n = XmlEncode(n, (ICHAR *) buf);
if (!n)
{
if (enc == encoding)
eventPtr = entityTextPtr;
return ERROR_EXPAT_BAD_CHAR_REF;
}
for (i = 0; i < n; i++)
{
if (pool->end == pool->ptr && !poolGrow(pool))
return ERROR_EXPAT_NO_MEMORY;
*(pool->ptr)++ = buf[i];
}
}
break;
case XML_TOK_PARTIAL:
if (enc == encoding)
eventPtr = entityTextPtr;
return ERROR_EXPAT_INVALID_TOKEN;
case XML_TOK_INVALID:
if (enc == encoding)
eventPtr = next;
return ERROR_EXPAT_INVALID_TOKEN;
default:
if (enc == encoding)
eventPtr = entityTextPtr;
return ERROR_EXPAT_UNEXPECTED_STATE;
}
entityTextPtr = next;
}
/* not reached */
}
static void 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, NULL);
if (!target)
return 0;
poolFinish(&tempPool);
data = poolStoreString(&tempPool, enc,
XmlSkipS(enc, tem),
end - enc->minBytesPerChar * 2,
NULL);
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,
NULL);
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, dataPtr - (ICHAR *) dataBuf);
*eventPP = s;
}
while (s != end);
}
else
defaultHandler(handlerArg, (XML_Char *) s, (XML_Char *) end - (XML_Char *) s);
}
static int defineAttribute(ELEMENT_TYPE * type,
ATTRIBUTE_ID * attId,
int isCdata,
int 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));
}
else
{
type->allocDefaultAtts *= 2;
type->defaultAtts = (DEFAULT_ATTRIBUTE*)REALLOC(type->defaultAtts,
type->allocDefaultAtts * sizeof(DEFAULT_ATTRIBUTE));
}
if (!type->defaultAtts)
return 0;
}
att = type->defaultAtts + type->nDefaultAtts;
att->id = attId;
att->value = value;
att->isCdata = isCdata;
if (!isCdata)
attId->maybeTokenized = 1;
type->nDefaultAtts += 1;
return 1;
}
static int setElementTypePrefix(XML_Parser parser,
ELEMENT_TYPE * elementType)
{
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)
{
ATTRIBUTE_ID *id;
const XML_Char *name;
if (!poolAppendChar(&dtd.pool, XML_T('\0')))
return 0;
name = poolStoreString(&dtd.pool, enc, start, end, NULL);
if (!name)
return 0;
++name;
id = (ATTRIBUTE_ID *) lookup(&dtd.attributeIds, name, sizeof(ATTRIBUTE_ID));
if (!id)
return 0;
if (id->name != name)
poolDiscard(&dtd.pool);
else
{
poolFinish(&dtd.pool);
if (!ns)
;
else if (name[0] == 'x'
&& name[1] == 'm'
&& name[2] == 'l'
&& name[3] == 'n'
&& name[4] == 's'
&& (name[5] == XML_T('\0') || name[5] == XML_T(':')))
{
if (name[5] == '\0')
id->prefix = &dtd.defaultPrefix;
else
id->prefix = (PREFIX *) lookup(&dtd.prefixes, name + 6, sizeof(PREFIX));
id->xmlns = 1;
}
else
{
int i;
for (i = 0; name[i]; i++)
{
if (name[i] == XML_T(':'))
{
int j;
for (j = 0; j < i; j++)
{
if (!poolAppendChar(&dtd.pool, name[j]))
return 0;
}
if (!poolAppendChar(&dtd.pool, XML_T('\0')))
return 0;
id->prefix = (PREFIX *) lookup(&dtd.prefixes, poolStart(&dtd.pool), sizeof(PREFIX));
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)
{
HASH_TABLE_ITER iter;
int needSep = 0;
if (dtd.defaultPrefix.binding)
{
int i;
int len;
if (!poolAppendChar(&tempPool, XML_T('=')))
return 0;
len = dtd.defaultPrefix.binding->uriLen;
if (namespaceSeparator != XML_T('\0'))
len--;
for (i = 0; i < len; i++)
if (!poolAppendChar(&tempPool, dtd.defaultPrefix.binding->uri[i]))
return 0;
needSep = 1;
}
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 0;
for (s = prefix->name; *s; s++)
if (!poolAppendChar(&tempPool, *s))
return 0;
if (!poolAppendChar(&tempPool, XML_T('=')))
return 0;
len = prefix->binding->uriLen;
if (namespaceSeparator != XML_T('\0'))
len--;
for (i = 0; i < len; i++)
if (!poolAppendChar(&tempPool, prefix->binding->uri[i]))
return 0;
needSep = 1;
}
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 0;
for (s = e->name; *s; s++)
if (!poolAppendChar(&tempPool, *s))
return 0;
needSep = 1;
}
if (!poolAppendChar(&tempPool, XML_T('\0')))
return 0;
return tempPool.start;
}
static int setContext(XML_Parser parser,
const XML_Char * context)
{
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 0;
e = (ENTITY *) lookup(&dtd.generalEntities, poolStart(&tempPool), 0);
if (e)
e->open = 1;
if (*s != XML_T('\0'))
s++;
context = s;
poolDiscard(&tempPool);
}
else if (*s == '=')
{
PREFIX *prefix;
if (poolLength(&tempPool) == 0)
prefix = &dtd.defaultPrefix;
else
{
if (!poolAppendChar(&tempPool, XML_T('\0')))
return 0;
prefix = (PREFIX *) lookup(&dtd.prefixes, poolStart(&tempPool), sizeof(PREFIX));
if (!prefix)
return 0;
if (prefix->name == poolStart(&tempPool))
{
prefix->name = poolCopyString(&dtd.pool, prefix->name);
if (!prefix->name)
return 0;
}
poolDiscard(&tempPool);
}
for (context = s + 1; *context != CONTEXT_SEP && *context != XML_T('\0'); context++)
if (!poolAppendChar(&tempPool, *context))
return 0;
if (!poolAppendChar(&tempPool, XML_T('\0')))
return 0;
if (!addBinding(parser, prefix, 0, poolStart(&tempPool), &inheritedBindings))
return 0;
poolDiscard(&tempPool);
if (*context != XML_T('\0'))
++context;
s = context;
}
else
{
if (!poolAppendChar(&tempPool, *s))
return 0;
s++;
}
}
return 1;
}
static void 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 int dtdInit(DTD * p,
XML_Parser parser)
{
XML_Memory_Handling_Suite *ms = &((Parser *) parser)->m_mem;
poolInit(&(p->pool), ms);
hashTableInit(&(p->generalEntities), ms);
hashTableInit(&(p->elementTypes), ms);
hashTableInit(&(p->attributeIds), ms);
hashTableInit(&(p->prefixes), ms);
p->complete = 1;
p->standalone = 0;
#ifdef XML_DTD
hashTableInit(&(p->paramEntities), ms);
#endif /* XML_DTD */
p->defaultPrefix.name = 0;
p->defaultPrefix.binding = 0;
p->in_eldecl = 0;
p->scaffIndex = 0;
p->scaffLevel = 0;
p->scaffold = 0;
p->contentStringLen = 0;
p->scaffSize = 0;
p->scaffCount = 0;
return 1;
}
#ifdef XML_DTD
static void dtdSwap(DTD * p1, DTD * p2)
{
DTD tem;
memcpy(&tem, p1, sizeof(DTD));
memcpy(p1, p2, sizeof(DTD));
memcpy(p2, &tem, sizeof(DTD));
}
#endif /* XML_DTD */
static void dtdDestroy(DTD * p, XML_Parser parser)
{
HASH_TABLE_ITER iter;
hashTableIterInit(&iter, &(p->elementTypes));
for (;;)
{
ELEMENT_TYPE *e = (ELEMENT_TYPE *) hashTableIterNext(&iter);
if (!e)
break;
if (e->allocDefaultAtts != 0)
FREE(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));
if (p->scaffIndex)
FREE(p->scaffIndex);
if (p->scaffold)
FREE(p->scaffold);
}
/* 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, XML_Parser parser)
{
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 *) MALLOC(oldE->nDefaultAtts * sizeof(DEFAULT_ATTRIBUTE));
if (!newE->defaultAtts)
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 = 0;
}
}
/* Copy the entity tables. */
if (!copyEntityTable(&(newDtd->generalEntities),
&(newDtd->pool),
&(oldDtd->generalEntities), parser))
return 0;
#ifdef XML_DTD
if (!copyEntityTable(&(newDtd->paramEntities),
&(newDtd->pool),
&(oldDtd->paramEntities), parser))
return 0;
#endif /* XML_DTD */
newDtd->complete = oldDtd->complete;
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,
XML_Parser parser)
{
HASH_TABLE_ITER iter;
const XML_Char *cachedOldBase = 0;
const XML_Char *cachedNewBase = 0;
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;
}
}
}
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;
}
}
return 1;
}
#define INIT_SIZE 64
static int keyeq(KEY s1, KEY s2)
{
for (; *s1 == *s2; s1++, s2++)
if (*s1 == 0)
return 1;
return 0;
}
static unsigned long hash(KEY s)
{
unsigned long h = 0;
while (*s)
h = (h << 5) + h + (unsigned char)*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 0;
tsize = INIT_SIZE * sizeof(NAMED *);
table->v = (NAMED**)table->mem->malloc_fcn(tsize);
if (!table->v)
return 0;
memset(table->v, 0, tsize);
table->size = INIT_SIZE;
table->usedLim = INIT_SIZE / 2;
i = hash(name) & (table->size - 1);
}
else
{
unsigned long h = hash(name);
for (i = h & (table->size - 1);
table->v[i];
i == 0 ? i = table->size - 1 : --i)
{
if (keyeq(name, table->v[i]->name))
return table->v[i];
}
if (!createSize)
return 0;
if (table->used == table->usedLim)
{
/* check for overflow */
size_t newSize = table->size * 2;
size_t tsize = newSize * sizeof(NAMED *);
NAMED **newV = (NAMED**)table->mem->malloc_fcn(tsize);
if (!newV)
return 0;
memset(newV, 0, tsize);
for (i = 0; i < table->size; i++)
if (table->v[i])
{
size_t j;
for (j = hash(table->v[i]->name) & (newSize - 1);
newV[j];
j == 0 ? j = newSize - 1 : --j)
;
newV[j] = table->v[i];
}
table->mem->free_fcn(table->v);
table->v = newV;
table->size = newSize;
table->usedLim = newSize / 2;
for (i = h & (table->size - 1);
table->v[i];
i == 0 ? i = table->size - 1 : --i)
;
}
}
table->v[i] = (NAMED*)table->mem->malloc_fcn(createSize);
if (!table->v[i])
return 0;
memset(table->v[i], 0, createSize);
table->v[i]->name = name;
(table->used)++;
return table->v[i];
}
static void hashTableDestroy(HASH_TABLE * table)
{
size_t i;
for (i = 0; i < table->size; i++)
{
NAMED *p = table->v[i];
if (p)
table->mem->free_fcn(p);
}
if (table->v)
table->mem->free_fcn(table->v);
}
static void hashTableInit(HASH_TABLE * p, XML_Memory_Handling_Suite * ms)
{
p->size = 0;
p->usedLim = 0;
p->used = 0;
p->v = 0;
p->mem = ms;
}
static void hashTableIterInit(HASH_TABLE_ITER * iter, const HASH_TABLE * table)
{
iter->p = table->v;
iter->end = iter->p + table->size;
}
static NAMED *hashTableIterNext(HASH_TABLE_ITER * iter)
{
while (iter->p != iter->end)
{
NAMED *tem = *(iter->p)++;
if (tem)
return tem;
}
return 0;
}
static void poolInit(STRING_POOL * pool, XML_Memory_Handling_Suite * ms)
{
pool->blocks = 0;
pool->freeBlocks = 0;
pool->start = 0;
pool->ptr = 0;
pool->end = 0;
pool->mem = ms;
}
static void 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 = 0;
pool->start = 0;
pool->ptr = 0;
pool->end = 0;
}
static void poolDestroy(STRING_POOL * pool)
{
BLOCK *p = pool->blocks;
while (p)
{
BLOCK *tem = p->next;
pool->mem->free_fcn(p);
p = tem;
}
pool->blocks = 0;
p = pool->freeBlocks;
while (p)
{
BLOCK *tem = p->next;
pool->mem->free_fcn(p);
p = tem;
}
pool->freeBlocks = 0;
pool->ptr = 0;
pool->start = 0;
pool->end = 0;
}
/*
*@@ poolAppend:
* appends a new string to a pool.
* Returns pool->start if the pool is valid,
* or NULL if storing failed.
*
* V0.9.14: I added the pulOfs parameter which, after
* the string was stored, receives the offset from
* pool->start at which the string was stored in the
* pool. I am not quite sure how all this works, but
* if a user-defined encoding is in place (via
* XML_SetUnknownEncodingHandler), the first entry
* in the pool is always the encoding name from the
* xml header, and all entity references failed here
* because the lookup would always be done for
* the encoding name instead of the entity name
* (which then is the second entry in the pool).
* Whatever.
*
*@@changed V0.9.14 (2001-08-09) [umoeller]: added pulOfs param
*/
static XML_Char* poolAppend(STRING_POOL * pool,
const ENCODING * enc,
const char *ptr,
const char *end,
unsigned long *pulOfs) // out: offset of beginning of stored
// string from pool->start
// V0.9.14 (2001-08-09) [umoeller]
{
if (!pool->ptr && !poolGrow(pool))
return 0;
for (;;)
{
char *pOldStart = pool->ptr;
XmlConvert(enc,
&ptr, // fromP
end,
(ICHAR**)&(pool->ptr), // toP
(ICHAR *)pool->end);
// expands to:
// (((enc)->utf8Convert)(enc, fromP, fromLim, toP, toLim))
// -- for cp850, we end up in
// -- for Latin1, we end up in
if (pulOfs)
*pulOfs = pOldStart - pool->start; // V0.9.14 (2001-08-09) [umoeller]
if (ptr == end)
break;
if (!poolGrow(pool))
return 0;
}
return pool->start;
}
static const XML_Char* poolCopyString(STRING_POOL *pool,
const XML_Char *s)
{
do
{
if (!poolAppendChar(pool, *s))
return 0;
}
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 0;
for (; n > 0; --n, s++)
{
if (!poolAppendChar(pool, *s))
return 0;
}
s = pool->start;
poolFinish(pool);
return s;
}
static const XML_Char* poolAppendString(STRING_POOL *pool,
const XML_Char *s)
{
while (*s)
{
if (!poolAppendChar(pool, *s))
return 0;
s++;
}
return pool->start;
} /* End poolAppendString */
/*
*@@ poolStoreString:
*
*@@changed V0.9.14 (2001-08-09) [umoeller]: added pulOfs param
*/
static XML_Char* poolStoreString(STRING_POOL *pool,
const ENCODING *enc,
const char *ptr,
const char *end,
unsigned long *pulOfs) // V0.9.14 (2001-08-09) [umoeller]
{
if (!poolAppend(pool,
enc,
ptr,
end,
pulOfs)) // V0.9.14 (2001-08-09) [umoeller]
return 0;
if ( (pool->ptr == pool->end)
&& (!poolGrow(pool))
)
return 0;
*(pool->ptr)++ = 0;
return pool->start;
}
static int poolGrow(STRING_POOL *pool)
{
if (pool->freeBlocks)
{
if (pool->start == 0)
{
pool->blocks = pool->freeBlocks;
pool->freeBlocks = pool->freeBlocks->next;
pool->blocks->next = 0;
pool->start = pool->blocks->s;
pool->end = pool->start + pool->blocks->size;
pool->ptr = pool->start;
return 1;
}
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 1;
}
}
if (pool->blocks && pool->start == pool->blocks->s)
{
int blockSize = (pool->end - pool->start) * 2;
pool->blocks = (BLOCK*)pool->mem->realloc_fcn(pool->blocks, offsetof(BLOCK, s) + blockSize * sizeof(XML_Char));
if (!pool->blocks)
return 0;
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 = 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 0;
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 1;
}
static int nextScaffoldPart(XML_Parser parser)
{
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)
{
if (dtd.scaffold)
{
dtd.scaffSize *= 2;
dtd.scaffold = (CONTENT_SCAFFOLD *) REALLOC(dtd.scaffold,
dtd.scaffSize * sizeof(CONTENT_SCAFFOLD));
}
else
{
dtd.scaffSize = 32;
dtd.scaffold = (CONTENT_SCAFFOLD *) MALLOC(dtd.scaffSize * sizeof(CONTENT_SCAFFOLD));
}
if (!dtd.scaffold)
return -1;
}
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;
} /* End nextScaffoldPart */
static void build_node(XML_Parser parser,
int src_node,
XMLCONTENT * dest,
XMLCONTENT ** contpos,
char **strpos)
{
dest->type = dtd.scaffold[src_node].type;
dest->quant = dtd.scaffold[src_node].quant;
if (dest->type == XML_CTYPE_NAME)
{
const char *src;
dest->name = *strpos;
src = dtd.scaffold[src_node].name;
for (;;)
{
*(*strpos)++ = *src;
if (!*src)
break;
src++;
}
dest->numchildren = 0;
dest->children = 0;
}
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 = 0;
}
} /* End build_node */
static XMLCONTENT * build_model(XML_Parser parser)
{
XMLCONTENT *ret;
XMLCONTENT *cpos;
char *str;
int allocsize = dtd.scaffCount * sizeof(XMLCONTENT) + dtd.contentStringLen;
ret = (XMLCONTENT*)MALLOC(allocsize);
if (!ret)
return 0;
str = (char *)(&ret[dtd.scaffCount]);
cpos = &ret[1];
build_node(parser, 0, ret, &cpos, &str);
return ret;
} /* End build_model */
static ELEMENT_TYPE * getElementType(XML_Parser parser,
const ENCODING * enc,
const char *ptr,
const char *end)
{
const XML_Char *name = poolStoreString(&dtd.pool, enc, ptr, end, NULL);
ELEMENT_TYPE *ret;
if (!name)
return 0;
ret = (ELEMENT_TYPE *) lookup(&dtd.elementTypes, name, sizeof(ELEMENT_TYPE));
if (!ret)
return 0;
if (ret->name != name)
poolDiscard(&dtd.pool);
else
{
poolFinish(&dtd.pool);
if (!setElementTypePrefix(parser, ret))
return 0;
}
return ret;
} /* End getElementType */