diff -r 000000000000 -r e35f40988205 xml/libxml2libs/src/libxml2/libxml2_parser.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xml/libxml2libs/src/libxml2/libxml2_parser.c Thu Dec 17 09:29:21 2009 +0200 @@ -0,0 +1,13593 @@ +/* + * libxml2_parser.c : an XML 1.0 parser, namespaces and validity support are mostly + * implemented on top of the SAX interfaces + * + * References: + * The XML specification: + * http://www.w3.org/TR/REC-xml + * Original 1.0 version: + * http://www.w3.org/TR/1998/REC-xml-19980210 + * XML second edition workingdraft + * http://www.w3.org/TR/2000/WD-xml-2e-20000814 + * + * Okay this is a big file, the parser core is around 7000 lines, then it + * is followed by the progressive parser top routines, then the various + * high level APIs to call the parser and a few miscellaneous functions. + * A number of helper functions and deprecated ones have been moved to + * parserInternals.c to reduce this file size. + * As much as possible the functions are associated with their relative + * production in the XML specification. A few productions defining the + * different ranges of character are actually implanted either in + * parserInternals.h or parserInternals.c + * The DOM tree build is realized from the default SAX callbacks in + * the module SAX.c. + * The routines doing the validation checks are in valid.c and called either + * from the SAX callbacks or as standalone functions using a preparsed + * document. + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + * Portion Copyright © 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. + */ + +#pragma warning(disable: 4127 4132) + +#define IN_LIBXML +#include "xmlenglibxml.h" + +#if (defined(WIN32) || defined(__SYMBIAN32__)) && !defined (__CYGWIN__) +#define XML_DIR_SEP '\\' +#else +#define XML_DIR_SEP '/' +#endif + +#include +#include +#include + +#include +#include +#include "libxml2_errencoding.h" +#include "libxml2_xmlerror2.h" +#include + +#ifdef LIBXML_CATALOG_ENABLED +#include "libxml2_catalog.h" +#endif + +#ifdef HAVE_CTYPE_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_ZLIB_H +#include +#endif + +#define SAX2 1 + +#define XML_PARSER_BIG_BUFFER_SIZE 300 +#define XML_PARSER_BUFFER_SIZE 100 + + +/* DEPR void xmlParserHandleReference(xmlParserCtxtPtr ctxt); */ +xmlEntityPtr xmlParseStringPEReference(xmlParserCtxtPtr ctxt, + const xmlChar **str); + +static xmlParserErrors +xmlParseExternalEntityPrivate(xmlDocPtr doc, xmlParserCtxtPtr oldctxt, + xmlSAXHandlerPtr sax, + void *user_data, int depth, const xmlChar *URL, + const xmlChar *ID, xmlNodePtr *list); + +#ifdef LIBXML_LEGACY_ENABLED +static void +xmlAddEntityReference(xmlEntityPtr ent, xmlNodePtr firstNode, + xmlNodePtr lastNode); +#endif /* LIBXML_LEGACY_ENABLED */ + +static xmlParserErrors +xmlParseBalancedChunkMemoryInternal(xmlParserCtxtPtr oldctxt, + const xmlChar *string, void *user_data, xmlNodePtr *lst); + +/************************************************************************ + * * + * Some factorized error routines * + * * + ************************************************************************/ + +/** + * xmlErrAttributeDup: + * @param ctxt an XML parser context + * @param prefix the attribute prefix + * @param localname the attribute localname + * + * Handle a redefinition of attribute error + */ +static void +xmlErrAttributeDup(xmlParserCtxtPtr ctxt, const xmlChar * prefix, + const xmlChar * localname) +{ + if ((ctxt != NULL) && (ctxt->disableSAX != 0) && + (ctxt->instate == XML_PARSER_EOF)) + return; + ctxt->errNo = XML_ERR_ATTRIBUTE_REDEFINED; + if (prefix == NULL) + __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER, + ctxt->errNo, XML_ERR_FATAL, NULL, 0, + (const char *) localname, NULL, NULL, 0, 0, + EMBED_ERRTXT("Attribute %s redefined\n"), localname); + else + __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER, + ctxt->errNo, XML_ERR_FATAL, NULL, 0, + (const char *) prefix, (const char *) localname, + NULL, 0, 0, EMBED_ERRTXT("Attribute %s:%s redefined\n"), prefix, + localname); + ctxt->wellFormed = 0; + if (ctxt->recovery == 0) + ctxt->disableSAX = 1; +} + +/** + * xmlFatalErr: + * @param ctxt an XML parser context + * @param error the error number + * @param extra extra information string + * + * Handle a fatal parser error, i.e. violating Well-Formedness constraints + */ +static void +xmlFatalErr(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *info) +{ + const char *errmsg; + + if ((ctxt != NULL) && (ctxt->disableSAX != 0) && (ctxt->instate == XML_PARSER_EOF)) + return; + +#ifdef XMLENGINE_EXCLUDE_EMBED_MSG + errmsg = "Error message is not availabe\n"; +#else + switch (error) { // DONE: Disable this SWITCH if EMBED_ERRTXT returns NULL + case XML_ERR_INVALID_HEX_CHARREF: + errmsg = EMBED_ERRTXT("CharRef: invalid hexadecimal value\n"); + break; + case XML_ERR_INVALID_DEC_CHARREF: + errmsg = EMBED_ERRTXT("CharRef: invalid decimal value\n"); + break; + case XML_ERR_INVALID_CHARREF: + errmsg = EMBED_ERRTXT("CharRef: invalid value\n"); + break; + case XML_ERR_INTERNAL_ERROR: + errmsg = EMBED_ERRTXT("internal error"); + break; + case XML_ERR_PEREF_AT_EOF: + errmsg = EMBED_ERRTXT("PEReference at end of document\n"); + break; + case XML_ERR_PEREF_IN_PROLOG: + errmsg = EMBED_ERRTXT("PEReference in prolog\n"); + break; + case XML_ERR_PEREF_IN_EPILOG: + errmsg = EMBED_ERRTXT("PEReference in epilog\n"); + break; + case XML_ERR_PEREF_NO_NAME: + errmsg = EMBED_ERRTXT("PEReference: no name\n"); + break; + case XML_ERR_PEREF_SEMICOL_MISSING: + errmsg = EMBED_ERRTXT("PEReference: expecting ';'\n"); + break; + case XML_ERR_ENTITY_LOOP: + errmsg = EMBED_ERRTXT("Detected an entity reference loop\n"); + break; + case XML_ERR_ENTITY_NOT_STARTED: + errmsg = EMBED_ERRTXT("EntityValue: \" or ' expected\n"); + break; + case XML_ERR_ENTITY_PE_INTERNAL: + errmsg = EMBED_ERRTXT("PEReferences forbidden in internal subset\n"); + break; + case XML_ERR_ENTITY_NOT_FINISHED: + errmsg = EMBED_ERRTXT("EntityValue: \" or ' expected\n"); + break; + case XML_ERR_ATTRIBUTE_NOT_STARTED: + errmsg = EMBED_ERRTXT("AttValue: \" or ' expected\n"); + break; + case XML_ERR_LT_IN_ATTRIBUTE: + errmsg = EMBED_ERRTXT("Unescaped '<' not allowed in attributes values\n"); + break; + case XML_ERR_LITERAL_NOT_STARTED: + errmsg = EMBED_ERRTXT("SystemLiteral \" or ' expected\n"); + break; + case XML_ERR_LITERAL_NOT_FINISHED: + errmsg = EMBED_ERRTXT("UnfinishedSystem or Public ID \" or ' expected\n"); + break; + case XML_ERR_MISPLACED_CDATA_END: + errmsg = EMBED_ERRTXT("Sequence ']]>' not allowed in content\n"); + break; + case XML_ERR_URI_REQUIRED: + errmsg = EMBED_ERRTXT("SYSTEM or PUBLIC, the URI is missing\n"); + break; + case XML_ERR_PUBID_REQUIRED: + errmsg = EMBED_ERRTXT("PUBLIC, the Public Identifier is missing\n"); + break; + case XML_ERR_HYPHEN_IN_COMMENT: + errmsg = EMBED_ERRTXT("Comment must not contain '--' (double-hyphen)\n"); + break; + case XML_ERR_PI_NOT_STARTED: + errmsg = EMBED_ERRTXT("xmlParsePI : no target name\n"); + break; + case XML_ERR_RESERVED_XML_NAME: + errmsg = EMBED_ERRTXT("Invalid PI name\n"); + break; + case XML_ERR_NOTATION_NOT_STARTED: + errmsg = EMBED_ERRTXT("NOTATION: Name expected here\n"); + break; + case XML_ERR_NOTATION_NOT_FINISHED: + errmsg = EMBED_ERRTXT("'>' required to close NOTATION declaration\n"); + break; + case XML_ERR_VALUE_REQUIRED: + errmsg = EMBED_ERRTXT("Entity value required\n"); + break; + case XML_ERR_URI_FRAGMENT: + errmsg = EMBED_ERRTXT("Fragment not allowed"); + break; + case XML_ERR_ATTLIST_NOT_STARTED: + errmsg = EMBED_ERRTXT("'(' required to start ATTLIST enumeration\n"); + break; + case XML_ERR_NMTOKEN_REQUIRED: + errmsg = EMBED_ERRTXT("NmToken expected in ATTLIST enumeration\n"); + break; + case XML_ERR_ATTLIST_NOT_FINISHED: + errmsg = EMBED_ERRTXT("')' required to finish ATTLIST enumeration\n"); + break; + case XML_ERR_MIXED_NOT_STARTED: + errmsg = EMBED_ERRTXT("MixedContentDecl : '|' or ')*' expected\n"); + break; + case XML_ERR_PCDATA_REQUIRED: + errmsg = EMBED_ERRTXT("MixedContentDecl : '#PCDATA' expected\n"); + break; + case XML_ERR_ELEMCONTENT_NOT_STARTED: + errmsg = EMBED_ERRTXT("ContentDecl : Name or '(' expected\n"); + break; + case XML_ERR_ELEMCONTENT_NOT_FINISHED: + errmsg = EMBED_ERRTXT("ContentDecl : ',' '|' or ')' expected\n"); + break; + case XML_ERR_PEREF_IN_INT_SUBSET: + errmsg = + EMBED_ERRTXT("PEReference: forbidden within markup decl in internal subset\n"); + break; + case XML_ERR_GT_REQUIRED: + errmsg =EMBED_ERRTXT("expected '>'\n"); + break; + case XML_ERR_CONDSEC_INVALID: + errmsg = EMBED_ERRTXT("XML conditional section '[' expected\n"); + break; + case XML_ERR_EXT_SUBSET_NOT_FINISHED: + errmsg = EMBED_ERRTXT("Content error in the external subset\n"); + break; + case XML_ERR_CONDSEC_INVALID_KEYWORD: + errmsg = + EMBED_ERRTXT("conditional section INCLUDE or IGNORE keyword expected\n"); + break; + case XML_ERR_CONDSEC_NOT_FINISHED: + errmsg = EMBED_ERRTXT("XML conditional section not closed\n"); + break; + case XML_ERR_XMLDECL_NOT_STARTED: + errmsg = EMBED_ERRTXT("Text declaration '' expected\n"); + break; + case XML_ERR_EXT_ENTITY_STANDALONE: + errmsg = EMBED_ERRTXT("external parsed entities cannot be standalone\n"); + break; + case XML_ERR_ENTITYREF_SEMICOL_MISSING: + errmsg = EMBED_ERRTXT("EntityRef: expecting ';'\n"); + break; + case XML_ERR_DOCTYPE_NOT_FINISHED: + errmsg = EMBED_ERRTXT("DOCTYPE improperly terminated\n"); + break; + case XML_ERR_LTSLASH_REQUIRED: + errmsg = EMBED_ERRTXT("EndTag: 'errNo = error; + __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER, error, + XML_ERR_FATAL, NULL, 0, info, NULL, NULL, 0, 0, errmsg, + info); + ctxt->wellFormed = 0; + if (ctxt->recovery == 0) + ctxt->disableSAX = 1; +} + +/** + * xmlFatalErrMsg: + * @param ctxt an XML parser context + * @param error the error number + * @param msg the error message + * + * Handle a fatal parser error, i.e. violating Well-Formedness constraints + */ +static void +xmlFatalErrMsg(xmlParserCtxtPtr ctxt, xmlParserErrors error, + const char *msg) +{ + if ((ctxt != NULL) && (ctxt->disableSAX != 0) && + (ctxt->instate == XML_PARSER_EOF)) + return; + ctxt->errNo = error; + __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER, error, + XML_ERR_FATAL, NULL, 0, NULL, NULL, NULL, 0, 0, msg); + ctxt->wellFormed = 0; + if (ctxt->recovery == 0) + ctxt->disableSAX = 1; +} + +/** + * xmlWarningMsg: + * @param ctxt an XML parser context + * @param error the error number + * @param msg the error message + * @param str1 extra data + * @param str2 extra data + * + * Handle a warning. + */ +static void +xmlWarningMsg(xmlParserCtxtPtr ctxt, xmlParserErrors error, + const char *msg, const xmlChar *str1, const xmlChar *str2) +{ + xmlStructuredErrorFunc schannel = NULL; + + if ((ctxt != NULL) && (ctxt->disableSAX != 0) && + (ctxt->instate == XML_PARSER_EOF)) + return; + ctxt->errNo = error; + if ((ctxt->sax != NULL) && (ctxt->sax->initialized == XML_SAX2_MAGIC)) + schannel = ctxt->sax->serror; + __xmlRaiseError(schannel, + (ctxt->sax) ? ctxt->sax->warning : NULL, + ctxt->userData, + ctxt, NULL, XML_FROM_PARSER, error, + XML_ERR_WARNING, NULL, 0, + (const char *) str1, (const char *) str2, NULL, 0, 0, + msg, (const char *) str1, (const char *) str2); +} + +/** + * xmlValidityError: + * @param ctxt an XML parser context + * @param error the error number + * @param msg the error message + * @param str1 extra data + * + * Handle a validity error. + */ +static void +xmlValidityError(xmlParserCtxtPtr ctxt, xmlParserErrors error, + const char *msg, const xmlChar *str1) +{ + xmlStructuredErrorFunc schannel = NULL; + + if ((ctxt != NULL) && (ctxt->disableSAX != 0) && + (ctxt->instate == XML_PARSER_EOF)) + return; + ctxt->errNo = error; + if ((ctxt->sax != NULL) && (ctxt->sax->initialized == XML_SAX2_MAGIC)) + schannel = ctxt->sax->serror; + __xmlRaiseError(schannel, + ctxt->vctxt.error, ctxt->vctxt.userData, + ctxt, NULL, XML_FROM_DTD, error, + XML_ERR_ERROR, NULL, 0, (const char *) str1, + NULL, NULL, 0, 0, + msg, (const char *) str1); + ctxt->valid = 0; +} + +/** + * xmlFatalErrMsgInt: + * @param ctxt an XML parser context + * @param error the error number + * @param msg the error message + * @param val an integer value + * + * Handle a fatal parser error, i.e. violating Well-Formedness constraints + */ +static void +xmlFatalErrMsgInt(xmlParserCtxtPtr ctxt, xmlParserErrors error, + const char *msg, int val) +{ + if ((ctxt != NULL) && (ctxt->disableSAX != 0) && + (ctxt->instate == XML_PARSER_EOF)) + return; + ctxt->errNo = error; + __xmlRaiseError(NULL, NULL, NULL, + ctxt, NULL, XML_FROM_PARSER, error, XML_ERR_FATAL, + NULL, 0, NULL, NULL, NULL, val, 0, msg, val); + ctxt->wellFormed = 0; + if (ctxt->recovery == 0) + ctxt->disableSAX = 1; +} + +/** + * xmlFatalErrMsgStrIntStr: + * @param ctxt an XML parser context + * @param error the error number + * @param msg the error message + * @param str1 an string info + * @param val an integer value + * @param str2 an string info + * + * Handle a fatal parser error, i.e. violating Well-Formedness constraints + */ +static void +xmlFatalErrMsgStrIntStr(xmlParserCtxtPtr ctxt, xmlParserErrors error, + const char *msg, const xmlChar *str1, int val, + const xmlChar *str2) +{ + if ((ctxt != NULL) && (ctxt->disableSAX != 0) && + (ctxt->instate == XML_PARSER_EOF)) + return; + ctxt->errNo = error; + __xmlRaiseError(NULL, NULL, NULL, + ctxt, NULL, XML_FROM_PARSER, error, XML_ERR_FATAL, + NULL, 0, (const char *) str1, (const char *) str2, + NULL, val, 0, msg, str1, val, str2); + ctxt->wellFormed = 0; + if (ctxt->recovery == 0) + ctxt->disableSAX = 1; +} + +/** + * xmlFatalErrMsgStr: + * @param ctxt an XML parser context + * @param error the error number + * @param msg the error message + * @param val a string value + * + * Handle a fatal parser error, i.e. violating Well-Formedness constraints + */ +static void +xmlFatalErrMsgStr(xmlParserCtxtPtr ctxt, xmlParserErrors error, + const char *msg, const xmlChar * val) +{ + if ((ctxt != NULL) && (ctxt->disableSAX != 0) && + (ctxt->instate == XML_PARSER_EOF)) + return; + ctxt->errNo = error; + __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, + XML_FROM_PARSER, error, XML_ERR_FATAL, + NULL, 0, (const char *) val, NULL, NULL, 0, 0, msg, + val); + ctxt->wellFormed = 0; + if (ctxt->recovery == 0) + ctxt->disableSAX = 1; +} + +/** + * xmlErrMsgStr: + * @param ctxt an XML parser context + * @param error the error number + * @param msg the error message + * @param val a string value + * + * Handle a non fatal parser error + */ +static void +xmlErrMsgStr(xmlParserCtxtPtr ctxt, xmlParserErrors error, + const char *msg, const xmlChar * val) +{ + if ((ctxt != NULL) && (ctxt->disableSAX != 0) && + (ctxt->instate == XML_PARSER_EOF)) + return; + ctxt->errNo = error; + __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, + XML_FROM_PARSER, error, XML_ERR_ERROR, + NULL, 0, (const char *) val, NULL, NULL, 0, 0, msg, + val); +} + +/** + * xmlNsErr: + * @param ctxt an XML parser context + * @param error the error number + * @param msg the message + * @param info1 extra information string + * @param info2 extra information string + * + * Handle a fatal parser error, i.e. violating Well-Formedness constraints + */ +static void +xmlNsErr(xmlParserCtxtPtr ctxt, xmlParserErrors error, + const char *msg, + const xmlChar * info1, const xmlChar * info2, + const xmlChar * info3) +{ + if ((ctxt != NULL) && (ctxt->disableSAX != 0) && + (ctxt->instate == XML_PARSER_EOF)) + return; + ctxt->errNo = error; + __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_NAMESPACE, error, + XML_ERR_ERROR, NULL, 0, (const char *) info1, + (const char *) info2, (const char *) info3, 0, 0, msg, + info1, info2, info3); + ctxt->nsWellFormed = 0; +} + +// XMLENGINE: New code +/** + * xmlParserOOMErr: + * @param ctxt an XML parser context + * + * Handle a OOM error during parsing XML; + * parser is set into state that prevents further processing + */ +static void +xmlParserOOMErr(xmlParserCtxtPtr ctxt) +{ + // Note: this function is mere a simpler (smaller) form to use + // it should not change + xmlErrMemory(ctxt, NULL); +} +// + +/** + * xmlCheckCdataPush: + * @param cur pointer to the bock of characters + * @param len length of the block in bytes + * + * Check that the block of characters is okay as SCdata content [20] + * + * Returns the number of bytes to pass if okay, a negative index where an + * UTF-8 error occured otherwise + */ +static int +xmlCheckCdataPush(const xmlChar *utf, int len) { + int ix; + unsigned char c; + int codepoint; + + if ((utf == NULL) || (len <= 0)) + return(0); + + for (ix = 0; ix < len;) { /* string is 0-terminated */ + c = utf[ix]; + if ((c & 0x80) == 0x00) { /* 1-byte code, starts with 10 */ + if (c >= 0x20) + ix++; + else if ((c == 0xA) || (c == 0xD) || (c == 0x9)) + ix++; + else + return(-ix); + } else if ((c & 0xe0) == 0xc0) {/* 2-byte code, starts with 110 */ + if (ix + 2 > len) return(ix); + if ((utf[ix+1] & 0xc0 ) != 0x80) + return(-ix); + codepoint = (utf[ix] & 0x1f) << 6; + codepoint |= utf[ix+1] & 0x3f; + if (!xmlIsCharQ(codepoint)) + return(-ix); + ix += 2; + } else if ((c & 0xf0) == 0xe0) {/* 3-byte code, starts with 1110 */ + if (ix + 3 > len) return(ix); + if (((utf[ix+1] & 0xc0) != 0x80) || + ((utf[ix+2] & 0xc0) != 0x80)) + return(-ix); + codepoint = (utf[ix] & 0xf) << 12; + codepoint |= (utf[ix+1] & 0x3f) << 6; + codepoint |= utf[ix+2] & 0x3f; + if (!xmlIsCharQ(codepoint)) + return(-ix); + ix += 3; + } else if ((c & 0xf8) == 0xf0) {/* 4-byte code, starts with 11110 */ + if (ix + 4 > len) return(ix); + if (((utf[ix+1] & 0xc0) != 0x80) || + ((utf[ix+2] & 0xc0) != 0x80) || + ((utf[ix+3] & 0xc0) != 0x80)) + return(-ix); + codepoint = (utf[ix] & 0x7) << 18; + codepoint |= (utf[ix+1] & 0x3f) << 12; + codepoint |= (utf[ix+2] & 0x3f) << 6; + codepoint |= utf[ix+3] & 0x3f; + if (!xmlIsCharQ(codepoint)) + return(-ix); + ix += 4; + } else /* unknown encoding */ + return(-ix); + } + return(ix); +} + +/************************************************************************ + * * + * SAX2 defaulted attributes handling * + * * + ************************************************************************/ + +/** + * xmlDetectSAX2: + * @param ctxt an XML parser context + * + * Do the SAX2 detection and specific intialization + * + * OOM: possible --> OOM flag is set + */ +static void +xmlDetectSAX2(xmlParserCtxtPtr ctxt) +{ + if (!ctxt) + return; +#ifdef LIBXML_SAX1_ENABLED + if ((ctxt->sax) && (ctxt->sax->initialized == XML_SAX2_MAGIC) && + ((ctxt->sax->startElementNs != NULL) || + (ctxt->sax->endElementNs != NULL))) + { + ctxt->sax2 = 1; + } +#else + ctxt->sax2 = 1; +#endif /* LIBXML_SAX1_ENABLED */ + // Each of these can end with OOM condition + ctxt->str_xml = xmlDictLookup(ctxt->dict, BAD_CAST "xml", 3); + ctxt->str_xmlns = xmlDictLookup(ctxt->dict, BAD_CAST "xmlns", 5); + ctxt->str_xml_ns = xmlDictLookup(ctxt->dict, XML_XML_NAMESPACE, 36); + if(ctxt->sax && ctxt->sax->startElementNs == xmlSAX2StartElementNs) + { + ctxt->stackLowThreshold = MIN_STACK_THRESHOLD; + } + else + { + ctxt->stackLowThreshold = MAX_STACK_THRESHOLD; + } +} + +typedef struct _xmlDefAttrs xmlDefAttrs; +typedef xmlDefAttrs *xmlDefAttrsPtr; +struct _xmlDefAttrs { + int nbAttrs; /* number of defaulted attributes on that element */ + int maxAttrs; /* the size of the array */ + const xmlChar *values[4]; /* array of localname/prefix/values */ +}; + +/** + * xmlAddDefAttrs: + * @param ctxt an XML parser context + * @param fullname the element fullname + * @param fullattr the attribute fullname + * @param value the attribute value + * + * Add a defaulted attribute for an element + */ +static void +xmlAddDefAttrs(xmlParserCtxtPtr ctxt, + const xmlChar *fullname, + const xmlChar *fullattr, + const xmlChar *value) +{ + xmlDefAttrsPtr defaults; + int len; + const xmlChar* name; + const xmlChar* prefix; + LOAD_GS_SAFE_CTXT(ctxt) + + if (ctxt->attsDefault == NULL) { + ctxt->attsDefault = xmlHashCreate(10); + if (ctxt->attsDefault == NULL) + goto mem_error; + } + + /* + * split the element name into prefix:localname , the string found + * are within the DTD and then not associated to namespace names. + */ + name = xmlSplitQName3(fullname, &len); + if (name == NULL) { + name = xmlDictLookup(ctxt->dict, fullname, -1); + prefix = NULL; + } else { + name = xmlDictLookup(ctxt->dict, name, -1); + prefix = xmlDictLookup(ctxt->dict, fullname, len); + } + + /* + * make sure there is some storage + */ + defaults = (xmlDefAttrsPtr)xmlHashLookup2(ctxt->attsDefault, name, prefix); + if (defaults == NULL) + { + defaults = (xmlDefAttrsPtr) xmlMalloc(sizeof(xmlDefAttrs) + + 12 * sizeof(const xmlChar *)); + if (defaults == NULL) + goto mem_error; + defaults->maxAttrs = 4; + defaults->nbAttrs = 0; + if ( xmlHashUpdateEntry2(ctxt->attsDefault, name, prefix, defaults, NULL) == -1 ) + { + xmlFree( defaults ); + return ; + } + if ( OOM_FLAG ) + return ; + } + else if (defaults->nbAttrs >= defaults->maxAttrs) + { + // DONE: Fix xmlRealloc + // NOTE: nothing to fix since 'defaults' is stored in hash table + defaults = (xmlDefAttrsPtr) xmlRealloc(defaults, sizeof(xmlDefAttrs) + + (2 * defaults->maxAttrs * 4) * sizeof(const xmlChar*)); + if (defaults == NULL) + goto mem_error; + defaults->maxAttrs *= 2; + if ( xmlHashUpdateEntry2(ctxt->attsDefault, name, prefix, defaults, NULL) == -1 ) + { + xmlFree( defaults ); + return ; + } + if ( OOM_FLAG ) + return ; + } + + /* + * split the element name into prefix:localname , the string found + * are within the DTD and then not associated to namespace names. + */ + name = xmlSplitQName3(fullattr, &len); + if (name == NULL) { + name = xmlDictLookup(ctxt->dict, fullattr, -1); + prefix = NULL; + } else { + name = xmlDictLookup(ctxt->dict, name, -1); + prefix = xmlDictLookup(ctxt->dict, fullattr, len); + } + + defaults->values[4 * defaults->nbAttrs] = name; + defaults->values[4 * defaults->nbAttrs + 1] = prefix; + /* intern the string and precompute the end */ + len = xmlStrlen(value); + value = xmlDictLookup(ctxt->dict, value, len); + defaults->values[4 * defaults->nbAttrs + 2] = value; + defaults->values[4 * defaults->nbAttrs + 3] = value + len; + defaults->nbAttrs++; + + return; + +mem_error: + xmlErrMemory(ctxt, NULL); + return; +} + +/** + * xmlAddSpecialAttr: + * @param ctxt an XML parser context + * @param fullname the element fullname + * @param fullattr the attribute fullname + * @param type the attribute type + * + * Register that this attribute is not CDATA + */ +static void +xmlAddSpecialAttr(xmlParserCtxtPtr ctxt, + const xmlChar *fullname, + const xmlChar *fullattr, + int type) +{ + if (ctxt->attsSpecial == NULL) { + ctxt->attsSpecial = xmlHashCreate(10); + if (ctxt->attsSpecial == NULL) + goto mem_error; + } + + xmlHashAddEntry2(ctxt->attsSpecial, fullname, fullattr, + (void *) (long) type); + return; + +mem_error: + xmlParserOOMErr(ctxt); + return; +} + +/** + * xmlCheckLanguageID: + * @param lang pointer to the string value + * + * Checks that the value conforms to the LanguageID production: + * + * NOTE: this is somewhat deprecated, those productions were removed from + * the XML Second edition. + * + * [33] LanguageID ::= Langcode ('-' Subcode)* + * [34] Langcode ::= ISO639Code | IanaCode | UserCode + * [35] ISO639Code ::= ([a-z] | [A-Z]) ([a-z] | [A-Z]) + * [36] IanaCode ::= ('i' | 'I') '-' ([a-z] | [A-Z])+ + * [37] UserCode ::= ('x' | 'X') '-' ([a-z] | [A-Z])+ + * [38] Subcode ::= ([a-z] | [A-Z])+ + * + * Returns 1 if correct 0 otherwise + **/ +XMLPUBFUNEXPORT int +xmlCheckLanguageID(const xmlChar * lang) +{ + const xmlChar *cur = lang; + + if (cur == NULL) + return (0); + if (((cur[0] == 'i') && (cur[1] == '-')) || + ((cur[0] == 'I') && (cur[1] == '-'))) { + /* + * IANA code + */ + cur += 2; + while (((cur[0] >= 'A') && (cur[0] <= 'Z')) || /* non input consuming */ + ((cur[0] >= 'a') && (cur[0] <= 'z'))) + cur++; + } else if (((cur[0] == 'x') && (cur[1] == '-')) || + ((cur[0] == 'X') && (cur[1] == '-'))) { + /* + * User code + */ + cur += 2; + while (((cur[0] >= 'A') && (cur[0] <= 'Z')) || /* non input consuming */ + ((cur[0] >= 'a') && (cur[0] <= 'z'))) + cur++; + } else if (((cur[0] >= 'A') && (cur[0] <= 'Z')) || + ((cur[0] >= 'a') && (cur[0] <= 'z'))) { + /* + * ISO639 + */ + cur++; + if (((cur[0] >= 'A') && (cur[0] <= 'Z')) || + ((cur[0] >= 'a') && (cur[0] <= 'z'))) + cur++; + else + return (0); + } else + return (0); + while (cur[0] != 0) { /* non input consuming */ + if (cur[0] != '-') + return (0); + cur++; + if (((cur[0] >= 'A') && (cur[0] <= 'Z')) || + ((cur[0] >= 'a') && (cur[0] <= 'z'))) + cur++; + else + return (0); + while (((cur[0] >= 'A') && (cur[0] <= 'Z')) || /* non input consuming */ + ((cur[0] >= 'a') && (cur[0] <= 'z'))) + cur++; + } + return (1); +} + +/************************************************************************ + * * + * Parser stacks related functions and macros * + * * + ************************************************************************/ + +xmlEntityPtr xmlParseStringEntityRef(xmlParserCtxtPtr ctxt, + const xmlChar** str); + +#ifdef SAX2 +/** + * nsPush: + * @param ctxt an XML parser context + * @param prefix the namespace prefix or NULL + * @param URL the namespace name + * + * Pushes a new parser namespace on top of the ns stack + * + * Returns -1 in case of error, -2 if the namespace should be discarded + * and the index in the stack otherwise. + */ +static int +nsPush(xmlParserCtxtPtr ctxt, const xmlChar *prefix, const xmlChar *URL) +{ + if (ctxt->options & XML_PARSE_NSCLEAN) + { + int i; + for (i = 0; i < ctxt->nsNr; i += 2) + { + if (ctxt->nsTab[i] == prefix) + { + /* in scope */ + if (ctxt->nsTab[i + 1] == URL) + return(-2); + /* out of scope keep it */ + break; + } + } + } + if ((ctxt->nsMax == 0) || (ctxt->nsTab == NULL)) { + ctxt->nsMax = 10; + ctxt->nsNr = 0; + + ctxt->nsTab = (const xmlChar **) + xmlMalloc(ctxt->nsMax * sizeof(xmlChar *)); + if (ctxt->nsTab == NULL) { + xmlParserOOMErr(ctxt); + ctxt->nsMax = 0; + return (-1); + } + } else if (ctxt->nsNr >= ctxt->nsMax) { + const xmlChar** largerTab; + + ctxt->nsMax *= 2; + // DONE: Fix memory leak here (when realloc returns NULL) + largerTab = (const xmlChar **) + xmlRealloc((char *) ctxt->nsTab, + ctxt->nsMax * sizeof(ctxt->nsTab[0])); + if (!largerTab) { + xmlParserOOMErr(ctxt); + ctxt->nsMax /= 2; + return (-1); + } + ctxt->nsTab = largerTab; + } + ctxt->nsTab[ctxt->nsNr++] = prefix; + ctxt->nsTab[ctxt->nsNr++] = URL; +// XE: BEGIN NEW CODE + /* + * SAX: prefix mapping ! + */ + if ((ctxt->sax != NULL) && + (ctxt->sax->startPrefixMapping != NULL) && + (!ctxt->disableSAX)) + { + ctxt->sax->startPrefixMapping(ctxt->userData, prefix, URL); + } +// XE: END NEW CODE + return (ctxt->nsNr); +} +/** + * nsPop: + * @param ctxt an XML parser context + * @param nr the number to pop + * + * Pops the top nr parser prefix/namespace from the ns stack + * + * Returns the number of namespaces removed + */ +static int +nsPop(xmlParserCtxtPtr ctxt, int nr) +{ + int i; + + if (ctxt->nsTab == NULL) return(0); + if (ctxt->nsNr < nr) { + xmlGenericError(xmlGenericErrorContext, EMBED_ERRTXT("Pbm popping %d NS\n"), nr); + nr = ctxt->nsNr; + } + if (ctxt->nsNr <= 0) + return (0); + +// XE: REPLACED CODE + //for (i = 0;i < nr;i++) { + // nr is even number, because pairs of (URL,prefix) are removed from ctxt->nsTab[] array + // by this moment ctxt->nsNr points to the next free cell after ...{prefix}{URL}{..}... + // ctxt->nsTab[ctxt->nsNr]-------^ +// XE: REPLACED WITH + for (i = nr/2; i > 0; i--) { + ctxt->nsNr--; + ctxt->nsTab[ctxt->nsNr] = NULL; // clean up URL + ctxt->nsNr--; +// XE: BEGIN NEW CODE + + /* + * SAX: end of prefix mapping ! + */ + if ((ctxt->sax != NULL) && + (ctxt->sax->endPrefixMapping != NULL) && + (!ctxt->disableSAX)) + { + ctxt->sax->endPrefixMapping(ctxt->userData, ctxt->nsTab[ctxt->nsNr]); + } +// XE: END NEW CODE + ctxt->nsTab[ctxt->nsNr] = NULL; // clean up prefix name + + + } + return(nr); +} +#endif + +static int +xmlCtxtGrowAttrs(xmlParserCtxtPtr ctxt, int nr) { + const xmlChar **atts; + int *attallocs; + int maxatts; + + if (ctxt->atts == NULL) { + maxatts = 55; /* allow for 10 attrs by default */ + atts = (const xmlChar **) + xmlMalloc(maxatts * sizeof(xmlChar *)); + if (atts == NULL) goto mem_error; + ctxt->atts = atts; + attallocs = (int *) xmlMalloc((maxatts / 5) * sizeof(int)); + if (attallocs == NULL) goto mem_error; + ctxt->attallocs = attallocs; + ctxt->maxatts = maxatts; + } else if (nr + 5 > ctxt->maxatts) { + maxatts = (nr + 5) * 2; + atts = (const xmlChar **) xmlRealloc((void *) ctxt->atts, + maxatts * sizeof(const xmlChar *)); + if (atts == NULL) goto mem_error; + ctxt->atts = atts; + attallocs = (int *) xmlRealloc((void *) ctxt->attallocs, + (maxatts / 5) * sizeof(int)); + if (attallocs == NULL) goto mem_error; + ctxt->attallocs = attallocs; + ctxt->maxatts = maxatts; + } + return(ctxt->maxatts); +mem_error: + xmlParserOOMErr(ctxt); + return(-1); +} + +/** + * inputPush: + * @param ctxt an XML parser context + * @param value the parser input + * + * Pushes a new parser input on top of the input stack + * + * Returns -1 in case of error, the index in the stack otherwise + * + * OOM: possible --> returns -1 and OOM flag is set + */ +XMLPUBFUNEXPORT int +inputPush(xmlParserCtxtPtr ctxt, xmlParserInputPtr value) +{ + if (ctxt->inputNr >= ctxt->inputMax) + { + // DONE: Fix xmlRealloc + void* tmp; + ctxt->inputMax *= 2; + tmp = xmlRealloc(ctxt->inputTab, + ctxt->inputMax * sizeof(ctxt->inputTab[0])); + if (!tmp) { + ctxt->inputMax /= 2; + xmlParserOOMErr(ctxt); + return (-1); + } + ctxt->inputTab = (xmlParserInputPtr*) tmp; + } + ctxt->inputTab[ctxt->inputNr] = value; + ctxt->input = value; + return (ctxt->inputNr++); +} + +/** + * inputPop: + * @param ctxt an XML parser context + * + * Pops the top parser input from the input stack + * + * Returns the input just removed + */ +XMLPUBFUNEXPORT xmlParserInputPtr +inputPop(xmlParserCtxtPtr ctxt) +{ + xmlParserInputPtr ret; + + if (ctxt->inputNr <= 0) + return (0); + ctxt->inputNr--; + if (ctxt->inputNr > 0) + ctxt->input = ctxt->inputTab[ctxt->inputNr - 1]; + else + ctxt->input = NULL; + ret = ctxt->inputTab[ctxt->inputNr]; + ctxt->inputTab[ctxt->inputNr] = 0; + return (ret); +} +/** + * nodePush: + * @param ctxt an XML parser context + * @param value the element node + * + * Pushes a new element node on top of the node stack + * + * Returns 0 in case of error, the index in the stack otherwise + */ +XMLPUBFUNEXPORT int +nodePush(xmlParserCtxtPtr ctxt, xmlNodePtr value) +{ + LOAD_GS_SAFE_CTXT(ctxt) + if (ctxt->nodeNr >= ctxt->nodeMax) + { + // DONE: Fix xmlRealloc + void* tmp; + ctxt->nodeMax *= 2; + tmp = xmlRealloc(ctxt->nodeTab, + ctxt->nodeMax * sizeof(ctxt->nodeTab[0])); + if (!tmp) { + ctxt->nodeMax /= 2; + xmlParserOOMErr(ctxt); + return (0); + } + ctxt->nodeTab = (xmlNodePtr*) tmp; + } + + if (((unsigned int) ctxt->nodeNr) > xmlParserMaxDepth) + { + xmlFatalErrMsgInt(ctxt, XML_ERR_INTERNAL_ERROR, + EMBED_ERRTXT("Excessive depth in document: change xmlParserMaxDepth = %d\n"), + xmlParserMaxDepth); + ctxt->instate = XML_PARSER_EOF; + return(0); + } + + ctxt->nodeTab[ctxt->nodeNr] = value; + ctxt->node = value; + return (ctxt->nodeNr++); +} + +/** + * nodePop: + * @param ctxt an XML parser context + * + * Pops the top element node from the node stack + * + * Returns the node just removed + */ +XMLPUBFUNEXPORT xmlNodePtr +nodePop(xmlParserCtxtPtr ctxt) +{ + xmlNodePtr ret; + + if (ctxt->nodeNr <= 0) + return (0); + ctxt->nodeNr--; + if (ctxt->nodeNr > 0) + ctxt->node = ctxt->nodeTab[ctxt->nodeNr - 1]; + else + ctxt->node = NULL; + ret = ctxt->nodeTab[ctxt->nodeNr]; + ctxt->nodeTab[ctxt->nodeNr] = 0; + return (ret); +} +/** + * nameNsPush: + * @param ctxt an XML parser context + * @param value the element name + * @param prefix the element prefix + * @param URI the element namespace name + * + * Pushes a new element name/prefix/URL on top of the name stack + * + * Returns -1 in case of error, the index in the stack otherwise + */ +static int +nameNsPush(xmlParserCtxtPtr ctxt, const xmlChar * value, + const xmlChar *prefix, const xmlChar *URI, int nsNr) +{ + if (ctxt->nameNr >= ctxt->nameMax) { + const xmlChar * *tmp; + void **tmp2; + ctxt->nameMax *= 2; + tmp = (const xmlChar * *) xmlRealloc((xmlChar * *)ctxt->nameTab, + ctxt->nameMax * + sizeof(ctxt->nameTab[0])); + if (tmp == NULL) { + ctxt->nameMax /= 2; + goto mem_error; + } + ctxt->nameTab = tmp; + tmp2 = (void **) xmlRealloc((void * *)ctxt->pushTab, + ctxt->nameMax * 3 * + sizeof(ctxt->pushTab[0])); + if (tmp2 == NULL) { + ctxt->nameMax /= 2; + goto mem_error; + } + ctxt->pushTab = tmp2; + } + ctxt->nameTab[ctxt->nameNr] = value; + ctxt->name = value; + ctxt->pushTab[ctxt->nameNr * 3] = (void *) prefix; + ctxt->pushTab[ctxt->nameNr * 3 + 1] = (void *) URI; + ctxt->pushTab[ctxt->nameNr * 3 + 2] = (void *) (long) nsNr; + return (ctxt->nameNr++); +mem_error: + xmlParserOOMErr(ctxt); + return (-1); +} +/** + * nameNsPop: + * @param ctxt an XML parser context + * + * Pops the top element/prefix/URI name from the name stack + * + * Returns the name just removed + */ +static const xmlChar * +nameNsPop(xmlParserCtxtPtr ctxt) +{ + const xmlChar *ret; + + if (ctxt->nameNr <= 0) + return (0); + ctxt->nameNr--; + if (ctxt->nameNr > 0) + ctxt->name = ctxt->nameTab[ctxt->nameNr - 1]; + else + ctxt->name = NULL; + ret = ctxt->nameTab[ctxt->nameNr]; + ctxt->nameTab[ctxt->nameNr] = NULL; + return (ret); +} + +/** + * namePush: + * @param ctxt an XML parser context + * @param value the element name + * + * Pushes a new element name on top of the name stack + * + * Returns -1 in case of error, the index in the stack otherwise + */ +XMLPUBFUNEXPORT extern int +namePush(xmlParserCtxtPtr ctxt, const xmlChar * value) +{ + if (ctxt->nameNr >= ctxt->nameMax) { + const xmlChar** tmp; + ctxt->nameMax *= 2; + tmp = (const xmlChar**) xmlRealloc((xmlChar**)ctxt->nameTab, + ctxt->nameMax * + sizeof(ctxt->nameTab[0])); + if (!tmp) { + ctxt->nameMax /= 2; + xmlParserOOMErr(ctxt); + return (-1); + } + ctxt->nameTab = tmp; + } + ctxt->nameTab[ctxt->nameNr] = value; + ctxt->name = value; + return (ctxt->nameNr++); +} + +/** + * namePop: + * @param ctxt an XML parser context + * + * Pops the top element name from the name stack + * + * Returns the name just removed + */ +XMLPUBFUNEXPORT extern const xmlChar* +namePop(xmlParserCtxtPtr ctxt) +{ + const xmlChar *ret; + + if (ctxt->nameNr <= 0) + return (0); + ctxt->nameNr--; + if (ctxt->nameNr > 0) + ctxt->name = ctxt->nameTab[ctxt->nameNr - 1]; + else + ctxt->name = NULL; + ret = ctxt->nameTab[ctxt->nameNr]; + ctxt->nameTab[ctxt->nameNr] = 0; + return (ret); +} + +static int spacePush(xmlParserCtxtPtr ctxt, int val) +{ + if (ctxt->spaceNr >= ctxt->spaceMax) { + // DONE: Fix xmlRealloc + void* tmp; + ctxt->spaceMax *= 2; + tmp = xmlRealloc(ctxt->spaceTab, + ctxt->spaceMax * sizeof(ctxt->spaceTab[0])); + if (!tmp) { + ctxt->spaceMax /= 2; + xmlParserOOMErr(ctxt); + return(0); + } + ctxt->spaceTab = (int*) tmp; + } + ctxt->spaceTab[ctxt->spaceNr] = val; + ctxt->space = &ctxt->spaceTab[ctxt->spaceNr]; + return(ctxt->spaceNr++); +} + +static int spacePop(xmlParserCtxtPtr ctxt) +{ + int ret; + if (ctxt->spaceNr <= 0) return(0); + ctxt->spaceNr--; + if (ctxt->spaceNr > 0) + ctxt->space = &ctxt->spaceTab[ctxt->spaceNr - 1]; + else + ctxt->space = NULL; + ret = ctxt->spaceTab[ctxt->spaceNr]; + ctxt->spaceTab[ctxt->spaceNr] = -1; + return(ret); +} + +/* + * Macros for accessing the content. Those should be used only by the parser, + * and not exported. + * + * Dirty macros, i.e. one often need to make assumption on the context to + * use them + * + * CUR_PTR return the current pointer to the xmlChar to be parsed. + * To be used with extreme caution since operations consuming + * characters may move the input buffer to a different location ! + * CUR returns the current xmlChar value, i.e. a 8 bit value if compiled + * This should be used internally by the parser + * only to compare to ASCII values otherwise it would break when + * running with UTF-8 encoding. + * RAW same as CUR but in the input buffer, bypass any token + * extraction that may have been done + * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only + * to compare on ASCII based substring. + * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined + * strings without newlines within the parser. + * NEXT1(l) Skip 1 xmlChar, and must also be used only to skip 1 non-newline ASCII + * defined char within the parser. + * Clean macros, not dependent of an ASCII context, expect UTF-8 encoding + * + * NEXT Skip to the next character, this does the proper decoding + * in UTF-8 mode. It also pop-up unfinishedEntities on the fly. + * NEXTL(l) Skip the current unicode character of l xmlChars long. + * CUR_CHAR(l) returns the current unicode character (int), set l + * to the number of xmlChars used for the encoding [0-5]. + * CUR_SCHAR same but operate on a string instead of the context + * COPY_BUF copy the current unicode char to the target buffer, increment + * the index + * GROW, SHRINK handling of input buffers + */ + +#define RAW (*ctxt->input->cur) +#define CUR (*ctxt->input->cur) +#define NXT(val) ctxt->input->cur[(val)] +#define CUR_PTR ctxt->input->cur + +#define CMP4( s, c1, c2, c3, c4 ) \ + ( ((unsigned char *) s)[ 0 ] == c1 && ((unsigned char *) s)[ 1 ] == c2 && \ + ((unsigned char *) s)[ 2 ] == c3 && ((unsigned char *) s)[ 3 ] == c4 ) +#define CMP5( s, c1, c2, c3, c4, c5 ) \ + ( CMP4( s, c1, c2, c3, c4 ) && ((unsigned char *) s)[ 4 ] == c5 ) +#define CMP6( s, c1, c2, c3, c4, c5, c6 ) \ + ( CMP5( s, c1, c2, c3, c4, c5 ) && ((unsigned char *) s)[ 5 ] == c6 ) +#define CMP7( s, c1, c2, c3, c4, c5, c6, c7 ) \ + ( CMP6( s, c1, c2, c3, c4, c5, c6 ) && ((unsigned char *) s)[ 6 ] == c7 ) +#define CMP8( s, c1, c2, c3, c4, c5, c6, c7, c8 ) \ + ( CMP7( s, c1, c2, c3, c4, c5, c6, c7 ) && ((unsigned char *) s)[ 7 ] == c8 ) +#define CMP9( s, c1, c2, c3, c4, c5, c6, c7, c8, c9 ) \ + ( CMP8( s, c1, c2, c3, c4, c5, c6, c7, c8 ) && \ + ((unsigned char *) s)[ 8 ] == c9 ) +#define CMP10( s, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10 ) \ + ( CMP9( s, c1, c2, c3, c4, c5, c6, c7, c8, c9 ) && \ + ((unsigned char *) s)[ 9 ] == c10 ) + +#define SKIP(val) do { \ + ctxt->nbChars += (val),ctxt->input->cur += (val),ctxt->input->col+=(val); \ + if (*ctxt->input->cur == '%') xmlParserHandlePEReference(ctxt); \ + if ((*ctxt->input->cur == 0) && \ + (xmlParserInputGrow(ctxt->input, INPUT_CHUNK) <= 0)) \ + xmlPopInput(ctxt); \ + } while (0) + +#define SKIPL(val) do { \ + int skipl; \ + for(skipl=0; skiplinput->cur) == '\n') { \ + ctxt->input->line++; ctxt->input->col = 1; \ + } else ctxt->input->col++; \ + ctxt->nbChars++; \ + ctxt->input->cur++; \ + } \ + if (*ctxt->input->cur == '%') xmlParserHandlePEReference(ctxt); \ + if ((*ctxt->input->cur == 0) && \ + (xmlParserInputGrow(ctxt->input, INPUT_CHUNK) <= 0)) \ + xmlPopInput(ctxt); \ + } while (0) + +#define SHRINK if ((ctxt->progressive == 0) && \ + (ctxt->input->cur - ctxt->input->base > 2 * INPUT_CHUNK) && \ + (ctxt->input->end - ctxt->input->cur < 2 * INPUT_CHUNK)) \ + xmlSHRINK (ctxt); + +static void xmlSHRINK (xmlParserCtxtPtr ctxt) { + xmlParserInputShrink(ctxt->input); + if ((*ctxt->input->cur == 0) && + (xmlParserInputGrow(ctxt->input, INPUT_CHUNK) <= 0)) + xmlPopInput(ctxt); + } + +/** +OOM: possible --> OOM flag is set +*/ +#define GROW if ((ctxt->progressive == 0) && \ + (ctxt->input->end - ctxt->input->cur < INPUT_CHUNK)) \ + xmlGROW (ctxt); + +/** +OOM: possible --> OOM flag is set +*/ +static void xmlGROW (xmlParserCtxtPtr ctxt) { + xmlParserInputGrow(ctxt->input, INPUT_CHUNK); + if ((*ctxt->input->cur == 0) && + (xmlParserInputGrow(ctxt->input, INPUT_CHUNK) <= 0)) + { + xmlPopInput(ctxt); + } +} + +#define SKIP_BLANKS xmlSkipBlankChars(ctxt) + +/* + * OOM: possible --> check OOM flag + */ +#define NEXT xmlNextChar(ctxt) + +#define NEXT1 { \ + ctxt->input->col++; \ + ctxt->input->cur++; \ + ctxt->nbChars++; \ + if (*ctxt->input->cur == 0) \ + xmlParserInputGrow(ctxt->input, INPUT_CHUNK); \ + } + +// OOM: not reviewed yet + + +#define NEXTL(l) do { \ + if (*(ctxt->input->cur) == '\n') { \ + ctxt->input->line++; ctxt->input->col = 1; \ + }else{ \ + ctxt->input->col++; \ + } \ + ctxt->input->cur += l; \ + if (*ctxt->input->cur == '%') \ + xmlParserHandlePEReference(ctxt); \ + } while (0) + +// OOM: possible --> sets flag when returns 0 +#define CUR_CHAR(l) xmlCurrentChar(ctxt, &l) +#define CUR_SCHAR(s, l) xmlStringCurrentChar(ctxt, s, &l) + +#define COPY_BUF(l,b,i,v) \ + if (l == 1) b[i++] = (xmlChar) v; \ + else i += xmlCopyCharMultiByte(&b[i],v) + +/** + * xmlSkipBlankChars: + * @param ctxt the XML parser context + * + * skip all blanks character found at that point in the input streams. + * It pops up finished entities in the process if allowable at that point. + * + * Returns the number of space chars skipped + * + * OOM: possible --> + */ +XMLPUBFUNEXPORT int +xmlSkipBlankChars(xmlParserCtxtPtr ctxt) { + int res = 0; + /* + * It's Okay to use CUR/NEXT here since all the blanks are on + * the ASCII range. + */ + if ((ctxt->inputNr == 1) && (ctxt->instate != XML_PARSER_DTD)) { + const xmlChar *cur; + /* + * if we are in the document content, go really fast + */ + cur = ctxt->input->cur; + while (IS_BLANK_CH(*cur)) { + if (*cur == '\n') { + ctxt->input->line++; ctxt->input->col = 1; + } + cur++; + res++; + if (*cur == 0) { + ctxt->input->cur = cur; + xmlParserInputGrow(ctxt->input, INPUT_CHUNK); + cur = ctxt->input->cur; + } + } + ctxt->input->cur = cur; + } else { + int cur; + do { + cur = CUR; + while (IS_BLANK(cur)) { /* CHECKED tstblanks.xml */ + NEXT; + cur = CUR; + res++; + } + while ((cur == 0) && (ctxt->inputNr > 1) && + (ctxt->instate != XML_PARSER_COMMENT)) { + xmlPopInput(ctxt); + cur = CUR; + } + /* + * Need to handle support of entities branching here + */ + if (*ctxt->input->cur == '%') xmlParserHandlePEReference(ctxt); + } while (IS_BLANK(cur)); /* CHECKED tstblanks.xml */ + } + return(res); +} + +/************************************************************************ + * * + * Commodity functions to handle entities * + * * + ************************************************************************/ + +/** + * xmlPopInput: + * @param ctxt an XML parser context + * + * xmlPopInput: the current input pointed by ctxt->input came to an end + * pop it and return the next char. + * + * Returns the current xmlChar in the parser context + * + * OOM: possible --> check OOM flag!!! + */ +XMLPUBFUNEXPORT xmlChar +xmlPopInput(xmlParserCtxtPtr ctxt) { + + LOAD_GS_SAFE_CTXT(ctxt) + if (ctxt->inputNr == 1) + return(0); /* End of main Input */ + if (xmlParserDebugEntities) + xmlGenericError(xmlGenericErrorContext, EMBED_ERRTXT("Popping input %d\n"), ctxt->inputNr); + xmlFreeInputStream(inputPop(ctxt)); + if ((*ctxt->input->cur == 0) && + (xmlParserInputGrow(ctxt->input, INPUT_CHUNK) <= 0)) + { + if(OOM_FLAG) + return 0; + return(xmlPopInput(ctxt)); + } + return(CUR); +} + +/** + * xmlPushInput: + * @param ctxt an XML parser context + * @param input an XML parser input fragment (entity, XML fragment ...). + * + * xmlPushInput: switch to a new input stream which is stacked on top + * of the previous one(s). + */ +XMLPUBFUNEXPORT void +xmlPushInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr input) { + LOAD_GS_SAFE_CTXT(ctxt) + if (input == NULL) return; + + if (xmlParserDebugEntities) { + if ((ctxt->input != NULL) && (ctxt->input->filename)) + xmlGenericError(xmlGenericErrorContext, + EMBED_ERRTXT("%s(%d): "), ctxt->input->filename, + ctxt->input->line); + xmlGenericError(xmlGenericErrorContext, + EMBED_ERRTXT("Pushing input %d : %.30s\n"), ctxt->inputNr+1, input->cur); + } + inputPush(ctxt, input); + GROW; +} + +/** + * xmlParseCharRef: + * @param ctxt an XML parser context + * + * parse Reference declarations + * + * [66] CharRef ::= '&#' [0-9]+ ';' | + * '&#x' [0-9a-fA-F]+ ';' + * + * [ WFC: Legal Character ] + * Characters referred to using character references must match the + * production for Char. + * + * Returns the value parsed (as an int), 0 in case of error + */ +XMLPUBFUNEXPORT int +xmlParseCharRef(xmlParserCtxtPtr ctxt) { + unsigned int val = 0; + int count = 0; + + /* + * Using RAW/CUR/NEXT is okay since we are working on ASCII range here + */ + if ((RAW == '&') && (NXT(1) == '#') && + (NXT(2) == 'x')) { + SKIP(3); + GROW; + while (RAW != ';') { /* loop blocked by count */ + if (count++ > 20) { + count = 0; + GROW; + } + if ((RAW >= '0') && (RAW <= '9')) + val = val * 16 + (CUR - '0'); + else if ((RAW >= 'a') && (RAW <= 'f') && (count < 20)) + val = val * 16 + (CUR - 'a') + 10; + else if ((RAW >= 'A') && (RAW <= 'F') && (count < 20)) + val = val * 16 + (CUR - 'A') + 10; + else { + xmlFatalErr(ctxt, XML_ERR_INVALID_HEX_CHARREF, NULL); + val = 0; + break; + } + NEXT; + count++; + } + if (RAW == ';') { + /* on purpose to avoid reentrancy problems with NEXT and SKIP */ + ctxt->input->col++; + ctxt->nbChars ++; + ctxt->input->cur++; + } + } else if ((RAW == '&') && (NXT(1) == '#')) { + SKIP(2); + GROW; + while (RAW != ';') { /* loop blocked by count */ + if (count++ > 20) { + count = 0; + GROW; + } + if ((RAW >= '0') && (RAW <= '9')) + val = val * 10 + (CUR - '0'); + else { + xmlFatalErr(ctxt, XML_ERR_INVALID_DEC_CHARREF, NULL); + val = 0; + break; + } + NEXT; + count++; + } + if (RAW == ';') { + /* on purpose to avoid reentrancy problems with NEXT and SKIP */ + ctxt->input->col++; + ctxt->nbChars ++; + ctxt->input->cur++; + } + } else { + xmlFatalErr(ctxt, XML_ERR_INVALID_CHARREF, NULL); + } + + /* + * [ WFC: Legal Character ] + * Characters referred to using character references must match the + * production for Char. + */ + if (IS_CHAR(val)) { + return(val); + } else { + xmlFatalErrMsgInt(ctxt, XML_ERR_INVALID_CHAR, + EMBED_ERRTXT("xmlParseCharRef: invalid xmlChar value %d\n"), + val); + } + return(0); +} + +/** + * xmlParseStringCharRef: + * @param ctxt an XML parser context + * @param str a pointer to an index in the string + * + * parse Reference declarations, variant parsing from a string rather + * than an an input flow. + * + * [66] CharRef ::= '&#' [0-9]+ ';' | + * '&#x' [0-9a-fA-F]+ ';' + * + * [ WFC: Legal Character ] + * Characters referred to using character references must match the + * production for Char. + * + * Returns the value parsed (as an int), 0 in case of error, str will be + * updated to the current value of the index + */ +static int +xmlParseStringCharRef(xmlParserCtxtPtr ctxt, const xmlChar **str) { + const xmlChar *ptr; + xmlChar cur; + int val = 0; + + if ((str == NULL) || (*str == NULL)) return(0); + ptr = *str; + cur = *ptr; + if ((cur == '&') && (ptr[1] == '#') && (ptr[2] == 'x')) { + ptr += 3; + cur = *ptr; + while (cur != ';') { /* Non input consuming loop */ + if ((cur >= '0') && (cur <= '9')) + val = val * 16 + (cur - '0'); + else if ((cur >= 'a') && (cur <= 'f')) + val = val * 16 + (cur - 'a') + 10; + else if ((cur >= 'A') && (cur <= 'F')) + val = val * 16 + (cur - 'A') + 10; + else { + xmlFatalErr(ctxt, XML_ERR_INVALID_HEX_CHARREF, NULL); + val = 0; + break; + } + ptr++; + cur = *ptr; + } + if (cur == ';') + ptr++; + } else if ((cur == '&') && (ptr[1] == '#')){ + ptr += 2; + cur = *ptr; + while (cur != ';') { /* Non input consuming loops */ + if ((cur >= '0') && (cur <= '9')) + val = val * 10 + (cur - '0'); + else { + xmlFatalErr(ctxt, XML_ERR_INVALID_DEC_CHARREF, NULL); + val = 0; + break; + } + ptr++; + cur = *ptr; + } + if (cur == ';') + ptr++; + } else { + xmlFatalErr(ctxt, XML_ERR_INVALID_CHARREF, NULL); + return(0); + } + *str = ptr; + + /* + * [ WFC: Legal Character ] + * Characters referred to using character references must match the + * production for Char. + */ + if (IS_CHAR(val)) { + return(val); + } else { + xmlFatalErrMsgInt(ctxt, XML_ERR_INVALID_CHAR, + EMBED_ERRTXT("xmlParseStringCharRef: invalid xmlChar value %d\n"), + val); + } + return(0); +} + +/** + * xmlNewBlanksWrapperInputStream: + * @param ctxt an XML parser context + * @param entity an Entity pointer + * + * Create a new input stream for wrapping + * blanks around a PEReference + * + * Returns the new input stream or NULL + */ + +static void deallocblankswrapper (xmlChar *str) {xmlFree(str);} + +static xmlParserInputPtr +xmlNewBlanksWrapperInputStream(xmlParserCtxtPtr ctxt, xmlEntityPtr entity) { + xmlParserInputPtr input; + xmlChar *buffer; + size_t length; + LOAD_GS_SAFE_CTXT(ctxt) + if (entity == NULL) { + xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR, + EMBED_ERRTXT("xmlNewBlanksWrapperInputStream entity\n")); + return(NULL); + } + if (xmlParserDebugEntities) + xmlGenericError(xmlGenericErrorContext, + EMBED_ERRTXT("new blanks wrapper for entity: %s\n"), entity->name); + input = xmlNewInputStream(ctxt); + if (input == NULL) { + return(NULL); + } + length = xmlStrlen(entity->name) + 5; + buffer = (xmlChar*)xmlMallocAtomic(length); + if (buffer == NULL) { + xmlParserOOMErr(ctxt); + return(NULL); + } + buffer [0] = ' '; + buffer [1] = '%'; + buffer [length-3] = ';'; + buffer [length-2] = ' '; + buffer [length-1] = 0; + memcpy(buffer + 2, entity->name, length - 5); + input->free = deallocblankswrapper; + input->base = buffer; + input->cur = buffer; + input->length = length; + input->end = &buffer[length]; + return(input); +} + +/** + * xmlParserHandlePEReference: + * @param ctxt the parser context + * + * [69] PEReference ::= '%' Name ';' + * + * [ WFC: No Recursion ] + * A parsed entity must not contain a recursive + * reference to itself, either directly or indirectly. + * + * [ WFC: Entity Declared ] + * In a document without any DTD, a document with only an internal DTD + * subset which contains no parameter entity references, or a document + * with "standalone='yes'", ... ... The declaration of a parameter + * entity must precede any reference to it... + * + * [ VC: Entity Declared ] + * In a document with an external subset or external parameter entities + * with "standalone='no'", ... ... The declaration of a parameter entity + * must precede any reference to it... + * + * [ WFC: In DTD ] + * Parameter-entity references may only appear in the DTD. + * NOTE: misleading but this is handled. + * + * A PEReference may have been detected in the current input stream + * the handling is done accordingly to + * http://www.w3.org/TR/REC-xml#entproc + * i.e. + * - Included in literal in entity values + * - Included as Parameter Entity reference within DTDs + * + * OOM: possible ------ review NOT FINISHED YET + */ +XMLPUBFUNEXPORT void +xmlParserHandlePEReference(xmlParserCtxtPtr ctxt) { + const xmlChar *name; + xmlEntityPtr entity = NULL; + xmlParserInputPtr input; + LOAD_GS_SAFE_CTXT(ctxt) + + if (RAW != '%') return; + + + switch(ctxt->instate) { + case XML_PARSER_CDATA_SECTION: + return; + case XML_PARSER_COMMENT: + return; + case XML_PARSER_START_TAG: + return; + case XML_PARSER_END_TAG: + return; + case XML_PARSER_EOF: + xmlFatalErr(ctxt, XML_ERR_PEREF_AT_EOF, NULL); + return; + case XML_PARSER_PROLOG: + case XML_PARSER_START: + case XML_PARSER_MISC: + xmlFatalErr(ctxt, XML_ERR_PEREF_IN_PROLOG, NULL); + return; + case XML_PARSER_ENTITY_DECL: + case XML_PARSER_CONTENT: + case XML_PARSER_ATTRIBUTE_VALUE: + case XML_PARSER_PI: + case XML_PARSER_SYSTEM_LITERAL: + case XML_PARSER_PUBLIC_LITERAL: + /* we just ignore it there */ + return; + case XML_PARSER_EPILOG: + xmlFatalErr(ctxt, XML_ERR_PEREF_IN_EPILOG, NULL); + return; + case XML_PARSER_ENTITY_VALUE: + /* + * NOTE: in the case of entity values, we don't do the + * substitution here since we need the literal + * entity value to be able to save the internal + * subset of the document. + * This will be handled by xmlStringDecodeEntities + */ + return; + case XML_PARSER_DTD: + /* + * [WFC: Well-Formedness Constraint: PEs in Internal Subset] + * In the internal DTD subset, parameter-entity references + * can occur only where markup declarations can occur, not + * within markup declarations. + * In that case this is handled in xmlParseMarkupDecl + */ + if ((ctxt->external == 0) && (ctxt->inputNr == 1)) + return; + if (IS_BLANK_CH(NXT(1)) || NXT(1) == 0) + return; + break; + case XML_PARSER_IGNORE: + return; + } + + NEXT; + name = xmlParseName(ctxt); // may set OOM flag + if(OOM_FLAG) + return; + + if (xmlParserDebugEntities) + xmlGenericError(xmlGenericErrorContext, EMBED_ERRTXT("PEReference: %s\n"), name); + if (name == NULL) { + xmlFatalErr(ctxt, XML_ERR_PEREF_NO_NAME, NULL); + return; + } + // XMLENGINE: OK: IF condition branches were exchanged and ELSE bacame main flow + if (RAW != ';') + { + xmlFatalErr(ctxt, XML_ERR_PEREF_SEMICOL_MISSING, NULL); + return; + } + + NEXT; + if(OOM_FLAG) + return; + + if ((ctxt->sax != NULL) && (ctxt->sax->getParameterEntity != NULL)) + entity = ctxt->sax->getParameterEntity(ctxt->userData, name); + if (entity == NULL) + { + /* + * [ WFC: Entity Declared ] + * In a document without any DTD, a document with only an + * internal DTD subset which contains no parameter entity + * references, or a document with "standalone='yes'", ... + * ... The declaration of a parameter entity must precede + * any reference to it... + */ + if ((ctxt->standalone == 1) || + ((ctxt->hasExternalSubset == 0) && + (ctxt->hasPErefs == 0))) + { + xmlFatalErrMsgStr(ctxt, XML_ERR_UNDECLARED_ENTITY, + EMBED_ERRTXT("PEReference: %%%s; not found\n"), name); + } else { + /* + * [ VC: Entity Declared ] + * In a document with an external subset or external + * parameter entities with "standalone='no'", ... + * ... The declaration of a parameter entity must precede + * any reference to it... + */ + if ((ctxt->validate) && (ctxt->vctxt.error != NULL)) { + xmlValidityError(ctxt, XML_WAR_UNDECLARED_ENTITY, + EMBED_ERRTXT("PEReference: %%%s; not found\n"), name); + }else{ + xmlWarningMsg(ctxt, XML_WAR_UNDECLARED_ENTITY, + EMBED_ERRTXT("PEReference: %%%s; not found\n"), name, NULL); + } + ctxt->valid = 0; + } + } // if (entity == NULL) + else if (ctxt->input->free != deallocblankswrapper) + { + input = xmlNewBlanksWrapperInputStream(ctxt, entity); + xmlPushInput(ctxt, input); + } + else if ((entity->etype == XML_INTERNAL_PARAMETER_ENTITY) || + (entity->etype == XML_EXTERNAL_PARAMETER_ENTITY)) + { + xmlChar start[4]; + xmlCharEncoding enc; + + /* + * handle the extra spaces added before and after + * c.f. http://www.w3.org/TR/REC-xml#as-PE + * this is done independently. + */ + input = xmlNewEntityInputStream(ctxt, entity); + xmlPushInput(ctxt, input); + + /* + * Get the 4 first bytes and decode the charset + * if enc != XML_CHAR_ENCODING_NONE + * plug some encoding conversion routines. + * Note that, since we may have some non-UTF8 + * encoding (like UTF16, ), the 'length' + * is not known, but we can calculate based upon + * the amount of data in the buffer. + */ + GROW + if ((ctxt->input->end - ctxt->input->cur)>=4) { + start[0] = RAW; + start[1] = NXT(1); + start[2] = NXT(2); + start[3] = NXT(3); + enc = xmlDetectCharEncoding(start, 4); + if (enc != XML_CHAR_ENCODING_NONE) { + xmlSwitchEncoding(ctxt, enc); + } + } + + if ((entity->etype == XML_EXTERNAL_PARAMETER_ENTITY) && + (CMP5(CUR_PTR, '<', '?', 'x', 'm', 'l' )) && + (IS_BLANK_CH(NXT(5)))) + { + xmlParseTextDecl(ctxt); + } + } else { + xmlFatalErrMsgStr(ctxt, XML_ERR_ENTITY_IS_PARAMETER, + EMBED_ERRTXT("PEReference: %s is not a parameter entity\n"), + name); + } +} + +/* + * Macro used to grow the current buffer. + */ + + + /** + * SYMBIAN : DEFECT FIX : DEF129002 (libxml2 buffer overflow vulnerability) + * Increase the buffer size by sufficient amount before doubling it. + * So that, this will help in dealing with the long-entity names. + * The original defect can be located in debian bug tracking database + * with defect number 498768. + */ + +#define GROW_BUFFER(buffer) { \ + xmlChar *tmp; \ + buffer##_size += XML_PARSER_BUFFER_SIZE ; \ + buffer##_size *= 2; \ + tmp = (xmlChar *) \ + xmlRealloc(buffer, buffer##_size * sizeof(xmlChar)); \ + if (tmp == NULL) goto mem_error; \ + buffer = tmp; \ +} + + +/** + * xmlStringLenDecodeEntities: + * @param ctxt the parser context + * @param str the input string + * @param len the string length + * @param what combination of XML_SUBSTITUTE_REF and XML_SUBSTITUTE_PEREF + * @param end an end marker xmlChar, 0 if none + * @param end2 an end marker xmlChar, 0 if none + * @param end3 an end marker xmlChar, 0 if none + * + * Takes a entity string content and process to do the adequate substitutions. + * + * [67] Reference ::= EntityRef | CharRef + * + * [69] PEReference ::= '%' Name ';' + * + * Returns A newly allocated string with the substitution done. The caller + * must deallocate it ! + */ +XMLPUBFUNEXPORT xmlChar * +xmlStringLenDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, int len, + int what, xmlChar end, xmlChar end2, xmlChar end3) { + xmlChar *buffer = NULL; + int buffer_size = 0; + + xmlChar *current = NULL; + const xmlChar *last; + xmlEntityPtr ent; + int c,l; + int nbchars = 0; + LOAD_GS_SAFE_CTXT(ctxt) + + if ((str == NULL) || (len < 0)) + return(NULL); + last = str + len; + + if (ctxt->depth > 40) { + xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL); + return(NULL); + } + + /* + * allocate a translation buffer. + */ + buffer_size = XML_PARSER_BIG_BUFFER_SIZE; + buffer = (xmlChar *) xmlMallocAtomic(buffer_size * sizeof(xmlChar)); + if (buffer == NULL) goto mem_error; + + /* + * OK loop until we reach one of the ending char or a size limit. + * we are operating on already parsed values. + */ + if (str < last) + c = CUR_SCHAR(str, l); + else + c = 0; + while ((c != 0) && (c != end) && /* non input consuming loop */ + (c != end2) && (c != end3)) { + + if (c == 0) break; + if ((c == '&') && (str[1] == '#')) { + int val = xmlParseStringCharRef(ctxt, &str); + if (val != 0) { + COPY_BUF(0,buffer,nbchars,val); + } + } else if ((c == '&') && (what & XML_SUBSTITUTE_REF)) { + if (xmlParserDebugEntities) + xmlGenericError(xmlGenericErrorContext, + EMBED_ERRTXT("String decoding Entity Reference: %.30s\n"), + str); + ent = xmlParseStringEntityRef(ctxt, &str); + if ((ent != NULL) && + (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) { + if (ent->content != NULL) { + COPY_BUF(0,buffer,nbchars,ent->content[0]); + } else { + xmlFatalErrMsg(ctxt, XML_ERR_INTERNAL_ERROR, + EMBED_ERRTXT("predefined entity has no content\n")); + } + } else if ((ent != NULL) && (ent->content != NULL)) { + xmlChar *rep; + + ctxt->depth++; + rep = xmlStringDecodeEntities(ctxt, ent->content, what, + 0, 0, 0); + ctxt->depth--; + if (rep != NULL) { + current = rep; + while (*current != 0) { /* non input consuming loop */ + buffer[nbchars++] = *current++; + if (nbchars > + buffer_size - XML_PARSER_BUFFER_SIZE) { + GROW_BUFFER(buffer); + } + } + xmlFree(rep); + } + } else if (ent != NULL) { + int i = xmlStrlen(ent->name); + const xmlChar *cur = ent->name; + + buffer[nbchars++] = '&'; + if (nbchars > buffer_size - i - XML_PARSER_BUFFER_SIZE) { + GROW_BUFFER(buffer); + } + for (;i > 0;i--) + buffer[nbchars++] = *cur++; + buffer[nbchars++] = ';'; + } + } else if (c == '%' && (what & XML_SUBSTITUTE_PEREF)) { + if (xmlParserDebugEntities) + xmlGenericError(xmlGenericErrorContext, + EMBED_ERRTXT("String decoding PE Reference: %.30s\n"), str); + ent = xmlParseStringPEReference(ctxt, &str); + if (ent != NULL) { + xmlChar *rep; + + ctxt->depth++; + rep = xmlStringDecodeEntities(ctxt, ent->content, what, + 0, 0, 0); + ctxt->depth--; + if (rep != NULL) { + current = rep; + while (*current != 0) { /* non input consuming loop */ + buffer[nbchars++] = *current++; + if (nbchars > + buffer_size - XML_PARSER_BUFFER_SIZE) { + GROW_BUFFER(buffer); + } + } + xmlFree(rep); + } + } + } else { + COPY_BUF(l,buffer,nbchars,c); + str += l; + if (nbchars > buffer_size - XML_PARSER_BUFFER_SIZE) { + GROW_BUFFER(buffer); + } + } + if (str < last) + c = CUR_SCHAR(str, l); + else + c = 0; + } + buffer[nbchars++] = 0; + return(buffer); + +mem_error: + xmlParserOOMErr(ctxt); + return(NULL); +} + +/** + * xmlStringDecodeEntities: + * @param ctxt the parser context + * @param str the input string + * @param what combination of XML_SUBSTITUTE_REF and XML_SUBSTITUTE_PEREF + * @param end an end marker xmlChar, 0 if none + * @param end2 an end marker xmlChar, 0 if none + * @param end3 an end marker xmlChar, 0 if none + * + * Takes a entity string content and process to do the adequate substitutions. + * + * [67] Reference ::= EntityRef | CharRef + * + * [69] PEReference ::= '%' Name ';' + * + * Returns A newly allocated string with the substitution done. The caller + * must deallocate it ! + */ +XMLPUBFUNEXPORT xmlChar * +xmlStringDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, int what, + xmlChar end, xmlChar end2, xmlChar end3) { + return(xmlStringLenDecodeEntities(ctxt, str, xmlStrlen(str), what, + end, end2, end3)); +} + +/************************************************************************ + * * + * Commodity functions, cleanup needed ? * + * * + ************************************************************************/ + +/** + * areBlanks: + * @param ctxt an XML parser context + * @param str a xmlChar * + * @param len the size of str + * @param blank_chars we know the chars are blanks + * + * Is this a sequence of blank chars that one can ignore ? + * + * Returns 1 if ignorable 0 otherwise. + */ + +static int areBlanks(xmlParserCtxtPtr ctxt, const xmlChar *str, int len, + int blank_chars) { + int i, ret; + xmlNodePtr lastChild; + + /* + * Don't spend time trying to differentiate them, the same callback is + * used ! + */ + if (ctxt->sax->ignorableWhitespace == ctxt->sax->characters) + return(0); + + /* + * Check for xml:space value. + */ + if (*(ctxt->space) == 1) + return(0); + + /* + * Check that the string is made of blanks + */ + if (blank_chars == 0) { + for (i = 0;i < len;i++) + if (!(IS_BLANK_CH(str[i]))) + return(0); + } + + /* + * Look if the element is mixed content in the DTD if available + */ + if (!ctxt->node) + return(0); + if (ctxt->myDoc) { + ret = xmlIsMixedElement(ctxt->myDoc, ctxt->node->name); + + if (ret == 0) return(1); // replace with + if (ret == 1) return(0); // return 1-ret; OR return !(ret&1) + } + + /* + * Otherwise, heuristic :-\ + */ + if (RAW != '<') + return(0); + if ((ctxt->node->children == NULL) && + (RAW == '<') && (NXT(1) == '/')) + return(0); + + + lastChild = xmlGetLastChild(ctxt->node); + if (lastChild == NULL) { + if ((ctxt->node->type != XML_ELEMENT_NODE) && + (ctxt->node->content != NULL)) return(0); + } else { + if (xmlNodeIsText(lastChild)) + return(0); + else + if ((ctxt->node->children != NULL) && + (xmlNodeIsText(ctxt->node->children))) + return(0); + } + return(1); +} + +/************************************************************************ + * * + * Extra stuff for namespace support * + * Relates to http://www.w3.org/TR/WD-xml-names * + * * + ************************************************************************/ + +/** + * xmlSplitQName: + * @param ctxt an XML parser context + * @param name an XML parser context + * @param prefix a xmlChar ** + * + * parse an UTF8 encoded XML qualified name string + * + * [NS 5] QName ::= (Prefix ':')? LocalPart + * + * [NS 6] Prefix ::= NCName + * + * [NS 7] LocalPart ::= NCName + * + * Returns the local part, and prefix is updated + * to get the Prefix if any. + * + * OOM: possible --> returns NULL (*prefix is NULL too); + * always check OOM flag to distinguish OOM and "bad QName" + */ +// DONE: Make sure that in OOM (prefix is set to NULL and freed if needed) +XMLPUBFUNEXPORT xmlChar* +xmlSplitQName(xmlParserCtxtPtr ctxt, const xmlChar* name, xmlChar** prefix) +{ + xmlChar buf[XML_MAX_NAMELEN + 5]; + xmlChar* buffer = NULL; // We use it instead of 'buf' for too long names + int len = 0; + int max = XML_MAX_NAMELEN; + xmlChar* ret = NULL; + const xmlChar* cur = name; + int c; + + *prefix = NULL; + + if (cur == NULL) + return(NULL); + +#ifndef XML_XML_NAMESPACE + /* xml: prefix is not really a namespace */ + if ((cur[0] == 'x') && (cur[1] == 'm') && + (cur[2] == 'l') && (cur[3] == ':')) + { + return(xmlStrdup(name)); + } +#endif + + /* nasty but well=formed */ + if (cur[0] == ':') + return(xmlStrdup(name)); + + c = *cur++; + while ((c != 0) && (c != ':') && (len < max)) { /* tested bigname.xml */ + buf[len++] = c; + c = *cur++; + } + if (len >= max) + { + /* + * Okay someone managed to make a huge name, so he's ready to pay + * for the processing speed. + */ + max = len * 2; + + buffer = (xmlChar*) xmlMallocAtomic(max * sizeof(xmlChar)); + if (!buffer) + goto OOM_exit; + + // NOTE: Now 'buffer' must be returned or freed (in OOM).. + memcpy(buffer, buf, len); + while ((c != 0) && (c != ':')) + { /* tested bigname.xml */ + if (len + 10 > max) + { + void* tmp; // DONE: Fix xmlRealloc + max *= 2; + tmp = xmlRealloc(buffer, max * sizeof(xmlChar)); + if (!tmp) { +OOM_free_buffer: + if(buffer) // Note: must check if jump here from other parts of function + xmlFree(buffer); +OOM_exit: + xmlParserOOMErr(ctxt); + return(NULL); + } + buffer = (xmlChar*) tmp; + } + buffer[len++] = c; + c = *cur++; + } + buffer[len] = 0; + } + + /* nasty but well=formed + if ((c == ':') && (*cur == 0)) { + return(xmlStrdup(name)); + } */ + + if (buffer == NULL) + ret = xmlStrndup(buf, len); + else { + ret = buffer; // NOTE: 'buffer' is to be returned so far + buffer = NULL; + max = XML_MAX_NAMELEN; + } + + + if (c == ':') + { + c = *cur; + *prefix = ret; // NOTE: in 'prefix' we return 'buffer' or a copy from 'buf' + if (c == 0) { + return(xmlStrndup(BAD_CAST "", 0)); + } + len = 0; + + /* + * Check that the first character is proper to start + * a new name + */ + if (!(((c >= 0x61) && (c <= 0x7A)) || + ((c >= 0x41) && (c <= 0x5A)) || + (c == '_') || (c == ':'))) + { + int l; + int first = CUR_SCHAR(cur, l); + + if (!IS_LETTER(first) && (first != '_')) { + xmlFatalErrMsgStr(ctxt, XML_NS_ERR_QNAME, + EMBED_ERRTXT("Name %s is not XML Namespace compliant\n"), + name); + } + } + cur++; + + while ((c != 0) && (len < max)) + { /* tested bigname2.xml */ + buf[len++] = c; + c = *cur++; + } + if (len >= max) { + /* + * Okay someone managed to make a huge name, so he's ready to pay + * for the processing speed. + */ + max = len * 2; + + buffer = (xmlChar*) xmlMallocAtomic(max * sizeof(xmlChar)); + if (!buffer) + goto OOM_free_prefix_buffer; // NOTE: it's ok to free NULL buffer here + + memcpy(buffer, buf, len); + while (c != 0) + { /* tested bigname2.xml */ + if (len + 10 > max) + { + void* tmp; // DONE: Fix xmlRealloc + max *= 2; + tmp = xmlRealloc(buffer, max * sizeof(xmlChar)); + if (!tmp) { +OOM_free_prefix_buffer: + xmlFree(*prefix); + *prefix = NULL; + goto OOM_free_buffer; + } + buffer = (xmlChar*) tmp; + } + buffer[len++] = c; + c = *cur++; + } + buffer[len] = 0; + } + + if (!buffer){ + ret = xmlStrndup(buf, len); // DONE: Check OOM, free prefix if needed + if(!ret) + goto OOM_free_prefix_buffer; + } else { + ret = buffer; + } + } // end if (c == ':') + + return(ret); +} + +/************************************************************************ + * * + * The parser itself * + * Relates to http://www.w3.org/TR/REC-xml * + * * + ************************************************************************/ + +static const xmlChar * xmlParseNameComplex(xmlParserCtxtPtr ctxt); +static xmlChar * xmlParseAttValueInternal(xmlParserCtxtPtr ctxt, + int *len, int *alloc, int normalize); + +/** + * xmlParseName: + * @param ctxt an XML parser context + * + * parse an XML name. + * + * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | + * CombiningChar | Extender + * + * [5] Name ::= (Letter | '_' | ':') (NameChar)* + * + * [6] Names ::= Name (S Name)* + * + * Returns the Name parsed or NULL + * + * OOM: possible --- Review is not finished (for xmlParseNameComplex) + *--> OOM flag is set when NULL is returned + */ + +XMLPUBFUNEXPORT const xmlChar* +xmlParseName(xmlParserCtxtPtr ctxt) { + const xmlChar *in; + const xmlChar *ret; + int count = 0; + LOAD_GS_SAFE_CTXT(ctxt) + + GROW; + if(OOM_FLAG) + return NULL; + /* + * Accelerator for simple ASCII names + */ + in = ctxt->input->cur; + if (((*in >= 0x61) && (*in <= 0x7A)) || + ((*in >= 0x41) && (*in <= 0x5A)) || + (*in == '_') || (*in == ':')) + { + in++; + while (((*in >= 0x61) && (*in <= 0x7A)) || + ((*in >= 0x41) && (*in <= 0x5A)) || + ((*in >= 0x30) && (*in <= 0x39)) || + (*in == '_') || (*in == '-') || + (*in == ':') || (*in == '.')) + in++; + + if ((*in > 0) && (*in < 0x80)) { + count = in - ctxt->input->cur; + ret = xmlDictLookup(ctxt->dict, ctxt->input->cur, count); + if(OOM_FLAG) + return NULL; + ctxt->input->cur = in; + ctxt->nbChars += count; + ctxt->input->col += count; + if (ret == NULL) + xmlParserOOMErr(ctxt); + return(ret); + } + } + return(xmlParseNameComplex(ctxt)); +} + +/** + * xmlParseNameAndCompare: + * @param ctxt an XML parser context + * + * parse an XML name and compares for match + * (specialized for endtag parsing) + * + * Returns NULL for an illegal name, (xmlChar*) 1 for success + * and the name for mismatch + */ + +static const xmlChar * +xmlParseNameAndCompare(xmlParserCtxtPtr ctxt, xmlChar const *other) { + register const xmlChar *cmp = other; + register const xmlChar *in; + const xmlChar *ret; + + GROW; + + in = ctxt->input->cur; + while (*in != 0 && *in == *cmp) { + ++in; + ++cmp; + } + if (*cmp == 0 && (*in == '>' || IS_BLANK_CH (*in))) { + /* success */ + ctxt->input->cur = in; + return (const xmlChar*) 1; + } + /* failure (or end of input buffer), check with full function */ + ret = xmlParseName (ctxt); + /* strings coming from the dictionnary direct compare possible */ + if (ret == other) { + return (const xmlChar*) 1; + } + return ret; +} + +/** + +OOM: +*/ +static const xmlChar* +xmlParseNameComplex(xmlParserCtxtPtr ctxt) { + int len = 0, clen; // DONE: renamed 'l' --> 'clen' + int c; + int count = 0; + + /* + * Handler for more complex cases + */ + GROW; + c = CUR_CHAR(clen); + + if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */ + (!IS_LETTER(c) && (c != '_') && (c != ':'))) + { + return(NULL); + } + + while ( + (c != ' ') && (c != '>') && (c != '/') /* test bigname.xml */ + && + ( IS_LETTER(c) || IS_DIGIT(c) || + (c == '.') || (c == '-') || + (c == '_') || (c == ':') || + IS_COMBINING(c)|| IS_EXTENDER(c) + ) + ) + { + if (count++ > 100) { + count = 0; + GROW; + } + len += clen; + NEXTL(clen); + c = CUR_CHAR(clen); // may set OOM flag + } + return(xmlDictLookup(ctxt->dict, ctxt->input->cur - len, len)); +} + +/** + * xmlParseStringName: + * @param ctxt an XML parser context + * @param str a pointer to the string pointer (IN/OUT) + * + * parse an XML name. + * + * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | + * CombiningChar | Extender + * + * [5] Name ::= (Letter | '_' | ':') (NameChar)* + * + * [6] Names ::= Name (S Name)* + * + * Returns the Name parsed or NULL. The str pointer + * is updated to the current location in the string. + */ +static xmlChar* +xmlParseStringName(xmlParserCtxtPtr ctxt, const xmlChar** str) +{ + xmlChar buf[XML_MAX_NAMELEN + 5]; + const xmlChar* cur = *str; + int len = 0, l; + int c; + + c = CUR_SCHAR(cur, l); + if (!IS_LETTER(c) && + (c != '_') && + (c != ':')) + { + return(NULL); + } + + while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigentname.xml */ + (c == '.') || (c == '-') || + (c == '_') || (c == ':') || + (IS_COMBINING(c)) || + (IS_EXTENDER(c))) + { + COPY_BUF(l,buf,len,c); + cur += l; + c = CUR_SCHAR(cur, l); + if (len >= XML_MAX_NAMELEN) + { /* test bigentname.xml */ + /* + * Okay someone managed to make a huge name, so he's ready to pay + * for the processing speed. + */ + xmlChar* buffer; + int max = len * 2; + + buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar)); + if (!buffer) + goto OOM_exit; + + memcpy(buffer, buf, len); + while ((IS_LETTER(c)) || (IS_DIGIT(c)) || + /* test bigentname.xml */ + (c == '.') || (c == '-') || + (c == '_') || (c == ':') || + (IS_COMBINING(c)) || + (IS_EXTENDER(c))) + { + if (len + 10 > max) + { // DONE: Fix xmlRealloc + void* tmp; + max *= 2; + tmp = xmlRealloc(buffer, max * sizeof(xmlChar)); + if (!tmp) { + xmlFree(buffer); +OOM_exit: + xmlParserOOMErr(ctxt); + return(NULL); + } + buffer = (xmlChar*) tmp; + } + COPY_BUF(l,buffer,len,c); + cur += l; + c = CUR_SCHAR(cur, l); + } + buffer[len] = 0; + *str = cur; + return(buffer); + } + } + *str = cur; + return(xmlStrndup(buf, len)); +} + +/** + * xmlParseNmtoken: + * @param ctxt an XML parser context + * + * parse an XML Nmtoken. + * + * [7] Nmtoken ::= (NameChar)+ + * + * [8] Nmtokens ::= Nmtoken (S Nmtoken)* + * + * Returns the Nmtoken parsed or NULL + * + * OOM: possible --> for too long names; check OOM flag + */ +XMLPUBFUNEXPORT xmlChar* +xmlParseNmtoken(xmlParserCtxtPtr ctxt) +{ + xmlChar buf[XML_MAX_NAMELEN + 5]; + int len = 0, l; + int c; + int count = 0; + + GROW; + c = CUR_CHAR(l); + + while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigtoken.xml */ + (c == '.') || (c == '-') || + (c == '_') || (c == ':') || + (IS_COMBINING(c)) || + (IS_EXTENDER(c))) + { + if (count++ > 100) { + count = 0; + GROW; + } + COPY_BUF(l,buf,len,c); + NEXTL(l); + c = CUR_CHAR(l); + + if (len >= XML_MAX_NAMELEN) + { + /* + * Okay someone managed to make a huge token, so he's ready to pay + * for the processing speed. + */ + xmlChar *buffer; + int max = len * 2; + + buffer = (xmlChar*) xmlMallocAtomic(max * sizeof(xmlChar)); + if (!buffer) + goto OOM_exit; + + memcpy(buffer, buf, len); + while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigtoken.xml */ + (c == '.') || (c == '-') || + (c == '_') || (c == ':') || + (IS_COMBINING(c)) || + (IS_EXTENDER(c))) + { + if (count++ > 100) { + count = 0; + GROW; + } + if (len + 10 > max) { + // DONE: Fix xmlRealloc + void* tmp; + max *= 2; + tmp = xmlRealloc(buffer, max * sizeof(xmlChar)); + if (!tmp) { + xmlFree(buffer); +OOM_exit: + xmlParserOOMErr(ctxt); + return(NULL); + } + buffer = (xmlChar*) tmp; + } + COPY_BUF(l,buffer,len,c); + NEXTL(l); + c = CUR_CHAR(l); + } + buffer[len] = 0; + return(buffer); + } // if (len >= XML_MAX_NAMELEN) + } // while + if (len == 0) + return(NULL); + return(xmlStrndup(buf, len)); +} + +/** + * xmlParseEntityValue: + * @param ctxt an XML parser context + * @param orig if non-NULL store a copy of the original entity value + * + * parse a value for ENTITY declarations + * + * [9] EntityValue ::= '"' ([^%&"] | PEReference | Reference)* '"' | + * "'" ([^%&'] | PEReference | Reference)* "'" + * + * Returns the EntityValue parsed with reference substituted or NULL + */ + +XMLPUBFUNEXPORT xmlChar * +xmlParseEntityValue(xmlParserCtxtPtr ctxt, xmlChar **orig) { + xmlChar *buf = NULL; + int len = 0; + int size = XML_PARSER_BUFFER_SIZE; + int c, l; + xmlChar stop; + xmlChar *ret = NULL; + const xmlChar *cur = NULL; + xmlParserInputPtr input; + + if (RAW == '"') stop = '"'; + else if (RAW == '\'') stop = '\''; + else { + xmlFatalErr(ctxt, XML_ERR_ENTITY_NOT_STARTED, NULL); + return(NULL); + } + buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar)); + if (buf == NULL) { + xmlParserOOMErr(ctxt); + return(NULL); + } + + /* + * The content of the entity definition is copied in a buffer. + */ + + ctxt->instate = XML_PARSER_ENTITY_VALUE; + input = ctxt->input; + GROW; + NEXT; + c = CUR_CHAR(l); + /* + * NOTE: 4.4.5 Included in Literal + * When a parameter entity reference appears in a literal entity + * value, ... a single or double quote character in the replacement + * text is always treated as a normal data character and will not + * terminate the literal. + * In practice it means we stop the loop only when back at parsing + * the initial entity and the quote is found + */ + while ((IS_CHAR(c)) && ((c != stop) || /* checked */ + (ctxt->input != input))) + { + if (len + 5 >= size) { + // DONE: Fix xmlRealloc + void* tmp; + size *= 2; + tmp = xmlRealloc(buf, size * sizeof(xmlChar)); + if (!tmp) { + xmlFree(buf); + xmlParserOOMErr(ctxt); + return(NULL); + } + buf = (xmlChar*) tmp; + } + COPY_BUF(l,buf,len,c); + NEXTL(l); + /* + * Pop-up of finished entities. + */ + while ((RAW == 0) && (ctxt->inputNr > 1)) /* non input consuming */ + xmlPopInput(ctxt); + + GROW; + c = CUR_CHAR(l); + if (c == 0) { + GROW; + c = CUR_CHAR(l); + } + } + buf[len] = 0; + + /* + * Raise problem w.r.t. '&' and '%' being used in non-entities + * reference constructs. Note Charref will be handled in + * xmlStringDecodeEntities() + */ + cur = buf; + while (*cur != 0) { /* non input consuming */ + if ((*cur == '%') || ((*cur == '&') && (cur[1] != '#'))) { + xmlChar *name; + xmlChar tmp = *cur; + + cur++; + name = xmlParseStringName(ctxt, &cur); + if ((name == NULL) || (*cur != ';')) { + xmlFatalErrMsgInt(ctxt, XML_ERR_ENTITY_CHAR_ERROR, + EMBED_ERRTXT("EntityValue: '%c' forbidden except for entities references\n"), + tmp); + } + if ((tmp == '%') && (ctxt->inSubset == 1) && + (ctxt->inputNr == 1)) { + xmlFatalErr(ctxt, XML_ERR_ENTITY_PE_INTERNAL, NULL); + } + if (name != NULL) + xmlFree(name); + if (*cur == 0) + break; + } + cur++; + } + + /* + * Then PEReference entities are substituted. + */ + if (c != stop) { + xmlFatalErr(ctxt, XML_ERR_ENTITY_NOT_FINISHED, NULL); + xmlFree(buf); + } else { + NEXT; + /* + * NOTE: 4.4.7 Bypassed + * When a general entity reference appears in the EntityValue in + * an entity declaration, it is bypassed and left as is. + * so XML_SUBSTITUTE_REF is not set here. + */ + ret = xmlStringDecodeEntities(ctxt, buf, XML_SUBSTITUTE_PEREF, + 0, 0, 0); + if (orig != NULL) + *orig = buf; + else + xmlFree(buf); + } + + return(ret); +} + +/** + * xmlParseAttValueComplex: + * @param ctxt an XML parser context + * @param len the resulting attribute len + * @param normalize wether to apply the inner normalization + * + * parse a value for an attribute, this is the fallback function + * of xmlParseAttValue() when the attribute parsing requires handling + * of non-ASCII characters, or normalization compaction. + * + * Returns the AttValue parsed or NULL. The value has to be freed by the caller. + */ +static xmlChar * +xmlParseAttValueComplex(xmlParserCtxtPtr ctxt, int *attlen, int normalize) { + xmlChar limit = 0; + xmlChar *buf = NULL; + int len = 0; + int buf_size = 0; + int c, l, in_space = 0; + xmlChar *current = NULL; + xmlEntityPtr ent; + + if (NXT(0) == '"') { + ctxt->instate = XML_PARSER_ATTRIBUTE_VALUE; + limit = '"'; + NEXT; + } else if (NXT(0) == '\'') { + limit = '\''; + ctxt->instate = XML_PARSER_ATTRIBUTE_VALUE; + NEXT; + } else { + xmlFatalErr(ctxt, XML_ERR_ATTRIBUTE_NOT_STARTED, NULL); + return(NULL); + } + + /* + * allocate a translation buffer. + */ + buf_size = XML_PARSER_BUFFER_SIZE; + buf = (xmlChar *) xmlMallocAtomic(buf_size * sizeof(xmlChar)); + if (buf == NULL) goto mem_error; + + /* + * OK loop until we reach one of the ending char or a size limit. + */ + c = CUR_CHAR(l); + while ((NXT(0) != limit) && /* checked */ + (c != '<')) { + if (c == 0) break; + if (c == '&') { + in_space = 0; + if (NXT(1) == '#') { + int val = xmlParseCharRef(ctxt); + + if (val == '&') { + if (ctxt->replaceEntities) { + if (len > buf_size - 10) { + GROW_BUFFER(buf); + } + buf[len++] = '&'; + } else { + /* + * The reparsing will be done in xmlStringGetNodeList() + * called by the attribute() function in SAX.c + */ + if (len > buf_size - 10) { + GROW_BUFFER(buf); + } + buf[len++] = '&'; + buf[len++] = '#'; + buf[len++] = '3'; + buf[len++] = '8'; + buf[len++] = ';'; + } + } else { + if (len > buf_size - 10) { + GROW_BUFFER(buf); + } + len += xmlCopyChar(0, &buf[len], val); + } + } else { + ent = xmlParseEntityRef(ctxt); + // XML ENGINE: TEST CODE: for disabling "Unknown entity reference" error + //if(!ent)return; + + if ((ent != NULL) && + (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) { + if (len > buf_size - 10) { + GROW_BUFFER(buf); + } + if ((ctxt->replaceEntities == 0) && + (ent->content[0] == '&')) + { + buf[len++] = '&'; + buf[len++] = '#'; + buf[len++] = '3'; + buf[len++] = '8'; + buf[len++] = ';'; + } else { + buf[len++] = ent->content[0]; + } + } else if ((ent != NULL) && + (ctxt->replaceEntities != 0)) { + xmlChar *rep; + + if (ent->etype != XML_INTERNAL_PREDEFINED_ENTITY) { + rep = xmlStringDecodeEntities(ctxt, ent->content, + XML_SUBSTITUTE_REF, + 0, 0, 0); + if (rep != NULL) { + current = rep; + while (*current != 0) { /* non input consuming */ + buf[len++] = *current++; + if (len > buf_size - 10) { + GROW_BUFFER(buf); + } + } + xmlFree(rep); + } + } else { + if (len > buf_size - 10) { + GROW_BUFFER(buf); + } + if (ent->content != NULL) + buf[len++] = ent->content[0]; + } + } else if (ent != NULL) { + int i = xmlStrlen(ent->name); + const xmlChar *cur = ent->name; + + /* + * This may look absurd but is needed to detect + * entities problems + */ + if ((ent->etype != XML_INTERNAL_PREDEFINED_ENTITY) && + (ent->content != NULL)) { + xmlChar *rep; + rep = xmlStringDecodeEntities(ctxt, ent->content, + XML_SUBSTITUTE_REF, 0, 0, 0); + if (rep != NULL) + xmlFree(rep); + } + + /* + * Just output the reference + */ + buf[len++] = '&'; + /** + * SYMBIAN : DEFECT FIX : DEF129002 (libxml2 buffer overflow vulnerability) + * Make sure that the buffer is grown until it becomes + * large enough to avoid buffer overflow in case of long-entity + * names.The original defect can be located in debian bug tracking database + * with defect number 498768. + */ + while (len > buf_size - i - 10) { + GROW_BUFFER(buf); + } + for (;i > 0;i--) + buf[len++] = *cur++; + buf[len++] = ';'; + } + } + } else { + if ((c == 0x20) || (c == 0xD) || (c == 0xA) || (c == 0x9)) { + if ((len != 0) || (!normalize)) { + if ((!normalize) || (!in_space)) { + COPY_BUF(l,buf,len,0x20); + if (len > buf_size - 10) { + GROW_BUFFER(buf); + } + } + in_space = 1; + } + } else { + in_space = 0; + COPY_BUF(l,buf,len,c); + if (len > buf_size - 10) { + GROW_BUFFER(buf); + } + } + NEXTL(l); + } + GROW; + c = CUR_CHAR(l); + } + if ((in_space) && (normalize)) { + while (buf[len - 1] == 0x20) len--; + } + buf[len] = 0; + if (RAW == '<') { + xmlFatalErr(ctxt, XML_ERR_LT_IN_ATTRIBUTE, NULL); + } else if (RAW != limit) { + xmlFatalErrMsg(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED, + EMBED_ERRTXT("AttValue: ' expected\n")); + } else + NEXT; + if (attlen != NULL) *attlen = len; + return(buf); + +mem_error: + xmlParserOOMErr(ctxt); + return(NULL); +} + +/** + * xmlParseAttValue: + * @param ctxt an XML parser context + * + * parse a value for an attribute + * Note: the parser won't do substitution of entities here, this + * will be handled later in xmlStringGetNodeList + * + * [10] AttValue ::= '"' ([^<&"] | Reference)* '"' | + * "'" ([^<&'] | Reference)* "'" + * + * 3.3.3 Attribute-Value Normalization: + * Before the value of an attribute is passed to the application or + * checked for validity, the XML processor must normalize it as follows: + * - a character reference is processed by appending the referenced + * character to the attribute value + * - an entity reference is processed by recursively processing the + * replacement text of the entity + * - a whitespace character (#x20, #xD, #xA, #x9) is processed by + * appending #x20 to the normalized value, except that only a single + * #x20 is appended for a "#xD#xA" sequence that is part of an external + * parsed entity or the literal entity value of an internal parsed entity + * - other characters are processed by appending them to the normalized value + * If the declared value is not CDATA, then the XML processor must further + * process the normalized attribute value by discarding any leading and + * trailing space (#x20) characters, and by replacing sequences of space + * (#x20) characters by a single space (#x20) character. + * All attributes for which no declaration has been read should be treated + * by a non-validating parser as if declared CDATA. + * + * Returns the AttValue parsed or NULL. The value has to be freed by the caller. + */ + + +XMLPUBFUNEXPORT xmlChar * +xmlParseAttValue(xmlParserCtxtPtr ctxt) { + return(xmlParseAttValueInternal(ctxt, NULL, NULL, 0)); +} + +/** + * xmlParseSystemLiteral: + * @param ctxt an XML parser context + * + * parse an XML Literal + * + * [11] SystemLiteral ::= ('"' [^"]* '"') | ("'" [^']* "'") + * + * Returns the SystemLiteral parsed or NULL + */ + +XMLPUBFUNEXPORT xmlChar * +xmlParseSystemLiteral(xmlParserCtxtPtr ctxt) { + xmlChar *buf = NULL; + int len = 0; + int size = XML_PARSER_BUFFER_SIZE; + int cur, l; + xmlChar stop; + int state = ctxt->instate; + int count = 0; + + SHRINK; + if (RAW == '"') { + NEXT; + stop = '"'; + } else if (RAW == '\'') { + NEXT; + stop = '\''; + } else { + xmlFatalErr(ctxt, XML_ERR_LITERAL_NOT_STARTED, NULL); + return(NULL); + } + + buf = (xmlChar*) xmlMallocAtomic(size * sizeof(xmlChar)); + if (!buf){ + xmlParserOOMErr(ctxt); + return NULL; + } + ctxt->instate = XML_PARSER_SYSTEM_LITERAL; + cur = CUR_CHAR(l); + while ((IS_CHAR(cur)) && (cur != stop)) + { /* checked */ + if (len + 5 >= size) { + // DONE: Fix xmlRealloc + xmlChar* tmp; + size *= 2; + tmp = (xmlChar*) xmlRealloc(buf, size * sizeof(xmlChar)); + if (!tmp) { + xmlFree(buf); + xmlParserOOMErr(ctxt); + ctxt->instate = (xmlParserInputState) state; + return(NULL); + } + buf = tmp; + } + count++; + if (count > 50) { + GROW; + count = 0; + } + COPY_BUF(l,buf,len,cur); + NEXTL(l); + cur = CUR_CHAR(l); + if (cur == 0) { + GROW; + SHRINK; + cur = CUR_CHAR(l); + } + } + buf[len] = 0; + ctxt->instate = (xmlParserInputState) state; + if (!IS_CHAR(cur)) { + xmlFatalErr(ctxt, XML_ERR_LITERAL_NOT_FINISHED, NULL); + } else { + NEXT; + } + return(buf); +} + +/** + * xmlParsePubidLiteral: + * @param ctxt an XML parser context + * + * parse an XML public literal + * + * [12] PubidLiteral ::= '"' PubidChar* '"' | "'" (PubidChar - "'")* "'" + * + * Returns the PubidLiteral parsed or NULL. + */ +XMLPUBFUNEXPORT xmlChar * +xmlParsePubidLiteral(xmlParserCtxtPtr ctxt) +{ + xmlChar* buf = NULL; + int len = 0; + int size = XML_PARSER_BUFFER_SIZE; + xmlChar cur; + xmlChar stop; + int count = 0; + xmlParserInputState oldstate = ctxt->instate; + + SHRINK; + if (RAW == '"') { + NEXT; + stop = '"'; + } else if (RAW == '\'') { + NEXT; + stop = '\''; + } else { + xmlFatalErr(ctxt, XML_ERR_LITERAL_NOT_STARTED, NULL); + return(NULL); + } + buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar)); + if (!buf) + goto OOM_exit; + + ctxt->instate = XML_PARSER_PUBLIC_LITERAL; + cur = CUR; + while ((IS_PUBIDCHAR_CH(cur)) && (cur != stop)) + { /* checked */ + if (len + 1 >= size) + { + // DONE: Fix xmlRealloc + xmlChar* tmp; + size *= 2; + tmp = (xmlChar*) xmlRealloc(buf, size * sizeof(xmlChar)); + if (!tmp) { + xmlFree(buf); +OOM_exit: + xmlParserOOMErr(ctxt); + return(NULL); + } + buf = tmp; + } + buf[len++] = cur; + count++; + if (count > 50) { + GROW; + count = 0; + } + NEXT; + cur = CUR; + if (cur == 0) { + GROW; + SHRINK; + cur = CUR; + } + } // while PUBID CHARs + + buf[len] = 0; + if (cur != stop) { + xmlFatalErr(ctxt, XML_ERR_LITERAL_NOT_FINISHED, NULL); + } else { + NEXT; + } + ctxt->instate = oldstate; + return(buf); +} + +void xmlParseCharDataComplex(xmlParserCtxtPtr ctxt, int cdata); +/** + * xmlParseCharData: + * @param ctxt an XML parser context + * @param cdata int indicating whether we are within a CDATA section + * + * parse a CharData section. + * if we are within a CDATA section ']]>' marks an end of section. + * + * The right angle bracket (>) may be represented using the string ">", + * and must, for compatibility, be escaped using ">" or a character + * reference when it appears in the string "]]>" in content, when that + * string is not marking the end of a CDATA section. + * + * [14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*) + */ + +XMLPUBFUNEXPORT void +xmlParseCharData(xmlParserCtxtPtr ctxt, int cdata) { + const xmlChar *in; + int nbchar = 0; + int line = ctxt->input->line; + int col = ctxt->input->col; + + SHRINK; + GROW; + /* + * Accelerated common case where input don't need to be + * modified before passing it to the handler. + */ + if (cdata) + goto parse_complex; + //-------------------------------------------------------------------- + in = ctxt->input->cur; + + do + { +get_more_space: + while (*in == 0x20) + in++; + + if (*in == 0xA) { + ctxt->input->line++; + in++; + while (*in == 0xA) { + ctxt->input->line++; + in++; + } + goto get_more_space; + } + + if (*in == '<') { + nbchar = in - ctxt->input->cur; + if (nbchar > 0) { + const xmlChar* tmp = ctxt->input->cur; + ctxt->input->cur = in; + + if (ctxt->sax->ignorableWhitespace != ctxt->sax->characters) { + if (areBlanks(ctxt, tmp, nbchar, 1)){ + ctxt->sax->ignorableWhitespace(ctxt->userData, tmp, nbchar); + } else + if (ctxt->sax->characters) + ctxt->sax->characters(ctxt->userData, tmp, nbchar); + } else + if (ctxt->sax->characters) { + ctxt->sax->characters(ctxt->userData, tmp, nbchar); + } + } + return; + } +get_more: + while (((*in > ']') && (*in <= 0x7F)) || + ((*in > '&') && (*in < '<')) || + ((*in > '<') && (*in < ']')) || + ((*in >= 0x20) && (*in < '&')) || + (*in == 0x09)) + { + in++; + } + + if (*in == 0xA) { + ctxt->input->line++; + in++; + while (*in == 0xA) { + ctxt->input->line++; + in++; + } + goto get_more; + } + if (*in == ']') { + if ((in[1] == ']') && (in[2] == '>')) { + xmlFatalErr(ctxt, XML_ERR_MISPLACED_CDATA_END, NULL); + ctxt->input->cur = in; + return; + } + in++; + goto get_more; + } + nbchar = in - ctxt->input->cur; + if (nbchar > 0) { + if (ctxt->sax->ignorableWhitespace != ctxt->sax->characters + && + IS_BLANK_CH(*ctxt->input->cur)) + { + const xmlChar *tmp = ctxt->input->cur; + ctxt->input->cur = in; + + if (areBlanks(ctxt, tmp, nbchar, 0)) + { + ctxt->sax->ignorableWhitespace(ctxt->userData, tmp, nbchar); + } + else if (ctxt->sax->characters) + { + ctxt->sax->characters(ctxt->userData, tmp, nbchar); + } + } else { + if (ctxt->sax->characters) + { + ctxt->sax->characters(ctxt->userData, ctxt->input->cur, nbchar); + } + } + line = ctxt->input->line; // moved from both IF branches above + col = ctxt->input->col; // + } + ctxt->input->cur = in; + if (*in == 0xD) { + in++; + if (*in == 0xA) { + ctxt->input->cur = in; + in++; + ctxt->input->line++; + continue; /* do-while loop */ + } + in--; + } + + if (*in == '<' || *in == '&') { + return; + } + SHRINK; + GROW; + in = ctxt->input->cur; + // end of DO-WHILE loop + } while ((*in >= 0x20 && *in <= 0x7F) || (*in == 0x09)); + + //nbchar = 0; // NOT needed + +//--------------------------------------------------------------------------------------- +parse_complex: + ctxt->input->line = line; + ctxt->input->col = col; + xmlParseCharDataComplex(ctxt, cdata); +} + +/** + * xmlParseCharDataComplex: + * @param ctxt an XML parser context + * @param cdata int indicating whether we are within a CDATA section + * + * parse a CharData section.this is the fallback function + * of xmlParseCharData() when the parsing requires handling + * of non-ASCII characters. + */ +void +xmlParseCharDataComplex(xmlParserCtxtPtr ctxt, int cdata) { + xmlChar buf[XML_PARSER_BIG_BUFFER_SIZE + 5]; + int nbchar = 0; + int cur, l; + int count = 0; + + SHRINK; + GROW; + cur = CUR_CHAR(l); + while ((cur != '<') && /* checked */ + (cur != '&') && + (IS_CHAR(cur))) /* test also done in xmlCurrentChar() */ { + if ((cur == ']') && (NXT(1) == ']') && + (NXT(2) == '>')) { + if (cdata) break; + else { + xmlFatalErr(ctxt, XML_ERR_MISPLACED_CDATA_END, NULL); + } + } + COPY_BUF(l,buf,nbchar,cur); + if (nbchar >= XML_PARSER_BIG_BUFFER_SIZE) { + buf[nbchar] = 0; + + /* + * OK the segment is to be consumed as chars. + */ + if ((ctxt->sax != NULL) && (!ctxt->disableSAX)) { + if (areBlanks(ctxt, buf, nbchar, 0)) { + if (ctxt->sax->ignorableWhitespace != NULL) + ctxt->sax->ignorableWhitespace(ctxt->userData, + buf, nbchar); + } else { + if (ctxt->sax->characters != NULL) + ctxt->sax->characters(ctxt->userData, buf, nbchar); + } + } + nbchar = 0; + } + count++; + if (count > 50) { + GROW; + count = 0; + } + NEXTL(l); + cur = CUR_CHAR(l); + } + if (nbchar != 0) { + buf[nbchar] = 0; + /* + * OK the segment is to be consumed as chars. + */ + if ((ctxt->sax != NULL) && (!ctxt->disableSAX)) { + if (areBlanks(ctxt, buf, nbchar, 0)) { + if (ctxt->sax->ignorableWhitespace != NULL) + ctxt->sax->ignorableWhitespace(ctxt->userData, buf, nbchar); + } else { + if (ctxt->sax->characters != NULL) + ctxt->sax->characters(ctxt->userData, buf, nbchar); + } + } + } +} + +/** + * xmlParseExternalID: + * @param ctxt an XML parser context + * @param publicID a xmlChar** receiving PubidLiteral + * @param strict indicate whether we should restrict parsing to only + * production [75], see NOTE below + * + * Parse an External ID or a Public ID + * + * NOTE: Productions [75] and [83] interact badly since [75] can generate + * 'PUBLIC' S PubidLiteral S SystemLiteral + * + * [75] ExternalID ::= 'SYSTEM' S SystemLiteral + * | 'PUBLIC' S PubidLiteral S SystemLiteral + * + * [83] PublicID ::= 'PUBLIC' S PubidLiteral + * + * Returns the function returns SystemLiteral and in the second + * case publicID receives PubidLiteral, is strict is off + * it is possible to return NULL and have publicID set. + */ + +XMLPUBFUNEXPORT xmlChar * +xmlParseExternalID(xmlParserCtxtPtr ctxt, xmlChar **publicID, int strict) { + xmlChar *URI = NULL; + + SHRINK; + + *publicID = NULL; + if (CMP6(CUR_PTR, 'S', 'Y', 'S', 'T', 'E', 'M')) { + SKIP(6); + if (!IS_BLANK_CH(CUR)) { + xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, + EMBED_ERRTXT("Space required after 'SYSTEM'\n")); + } + SKIP_BLANKS; + URI = xmlParseSystemLiteral(ctxt); + if (URI == NULL) { + xmlFatalErr(ctxt, XML_ERR_URI_REQUIRED, NULL); + } + } else if (CMP6(CUR_PTR, 'P', 'U', 'B', 'L', 'I', 'C')) { + SKIP(6); + if (!IS_BLANK_CH(CUR)) { + xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, + EMBED_ERRTXT("Space required after 'PUBLIC'\n")); + } + SKIP_BLANKS; + *publicID = xmlParsePubidLiteral(ctxt); + if (*publicID == NULL) { + xmlFatalErr(ctxt, XML_ERR_PUBID_REQUIRED, NULL); + } + if (strict) { + /* + * We don't handle [83] so "S SystemLiteral" is required. + */ + if (!IS_BLANK_CH(CUR)) { + xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, + EMBED_ERRTXT("Space required after the Public Identifier\n")); + } + } else { + /* + * We handle [83] so we return immediately, if + * "S SystemLiteral" is not detected. From a purely parsing + * point of view that's a nice mess. + */ + const xmlChar *ptr; + GROW; + + ptr = CUR_PTR; + if (!IS_BLANK_CH(*ptr)) return(NULL); + + while (IS_BLANK_CH(*ptr)) ptr++; + if ((*ptr != '\'') && (*ptr != '"')) return(NULL); + } + SKIP_BLANKS; + URI = xmlParseSystemLiteral(ctxt); + if (URI == NULL) { + xmlFatalErr(ctxt, XML_ERR_URI_REQUIRED, NULL); + } + } + return(URI); +} + +/** + * xmlParseComment: + * @param ctxt an XML parser context + * + * Skip an XML (SGML) comment + * The spec says that "For compatibility, the string "--" (double-hyphen) + * must not occur within comments. " + * + * [15] Comment ::= '' + */ +XMLPUBFUNEXPORT void +xmlParseComment(xmlParserCtxtPtr ctxt) { + xmlChar *buf = NULL; + int len; + int size = XML_PARSER_BUFFER_SIZE; + int q, ql; + int r, rl; + int cur, l; + xmlParserInputState state; + xmlParserInputPtr input = ctxt->input; + int count = 0; + + /* + * Check that there is a comment right here. + */ + if ((RAW != '<') || (NXT(1) != '!') || + (NXT(2) != '-') || (NXT(3) != '-')) return; + + state = ctxt->instate; + ctxt->instate = XML_PARSER_COMMENT; + SHRINK; + SKIP(4); + buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar)); + if (buf == NULL) + goto OOM_exit; + + q = CUR_CHAR(ql); + if (q == 0) + goto not_terminated; + NEXTL(ql); + r = CUR_CHAR(rl); + if (r == 0) + goto not_terminated; + NEXTL(rl); + cur = CUR_CHAR(l); + if (cur == 0) + goto not_terminated; + len = 0; + while (IS_CHAR(cur) && /* checked */ + ((cur != '>') || + (r != '-') || (q != '-'))) { + if ((r == '-') && (q == '-')) { + xmlFatalErr(ctxt, XML_ERR_HYPHEN_IN_COMMENT, NULL); + } + if (len + 5 >= size) { + // DONE: Fix xmlRealloc + xmlChar* tmp; + size *= 2; + tmp = (xmlChar*) xmlRealloc(buf, size * sizeof(xmlChar)); + if (!tmp) { + xmlFree(buf); +OOM_exit: + xmlParserOOMErr(ctxt); + ctxt->instate = state; + return; + } + buf = tmp; + } + COPY_BUF(ql,buf,len,q); + q = r; + ql = rl; + r = cur; + rl = l; + + count++; + if (count > 50) { + GROW; + count = 0; + } + NEXTL(l); + cur = CUR_CHAR(l); + if (cur == 0) { + SHRINK; + GROW; + cur = CUR_CHAR(l); + } + } + buf[len] = 0; + if (!IS_CHAR(cur)) { + xmlFatalErrMsgStr(ctxt, XML_ERR_COMMENT_NOT_FINISHED, + EMBED_ERRTXT("Comment not terminated \n check OOM flag / NULL is returned too + */ + +static const xmlChar * +xmlParseStartTag2(xmlParserCtxtPtr ctxt, const xmlChar **pref, + const xmlChar **URI, int *tlen) +{ + const xmlChar *localname; + const xmlChar *prefix; + const xmlChar *attname; + const xmlChar *aprefix; + const xmlChar *nsname; + xmlChar *attvalue; // = NULL : unneeded initialization -- done by xmlParseAttribute2 + const xmlChar **atts = ctxt->atts; + int maxatts = ctxt->maxatts; + int nratts, nbatts, nbdef; + int i, j, nbNs, attval; + const xmlChar *base; + unsigned long cur; + LOAD_GS_SAFE_CTXT(ctxt) + + if (RAW != '<') + return(NULL); + NEXT1; + + /* + * NOTE: it is crucial with the SAX2 API to never call SHRINK beyond that + * point since the attribute values may be stored as pointers to + * the buffer and calling SHRINK would destroy them ! + * The Shrinking is only possible once the full set of attribute + * callbacks have been done. + */ +reparse: + SHRINK; + base = ctxt->input->base; + cur = ctxt->input->cur - ctxt->input->base; + nbatts = 0; + nratts = 0; + nbdef = 0; + nbNs = 0; + attval = 0; + + localname = xmlParseQName(ctxt, &prefix); + if (localname == NULL) { + xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED, EMBED_ERRTXT("StartTag: invalid element name\n")); + return(NULL); + } + + *tlen = ctxt->input->cur - ctxt->input->base - cur; + + /* + * Now parse the attributes, it ends up with the ending + * + * (S Attribute)* S? + */ + + SKIP_BLANKS; + GROW; + + if (ctxt->input->base != base) + goto base_changed; + + while ((RAW != '>') && + ((RAW != '/') || (NXT(1) != '>')) && + (IS_BYTE_CHAR(RAW))) + { + // Parse one attribute + + const xmlChar *q = CUR_PTR; + unsigned int cons = ctxt->input->consumed; + int len = -1, alloc = 0; + + attname = xmlParseAttribute2(ctxt, prefix, localname, &aprefix, &attvalue, &len, &alloc); + if ((attname != NULL) && (attvalue != NULL)) + { + // if 'len' has not changed, then there was memory allocation + // (because of complex, expanded attribute value) + if (len < 0) + len = xmlStrlen(attvalue); + + if ((attname == ctxt->str_xmlns) && (aprefix == NULL)) + { + // we have [ xmlns="uri" ] - a default namespace definition + const xmlChar *URL = xmlDictLookup(ctxt->dict, attvalue, len); + xmlURIPtr uri; + + if(!URL) + goto OOM; + + if (*URL != 0) { + uri = xmlParseURI((const char *) URL); + if (uri == NULL) { + if(OOM_FLAG)goto OOM; + xmlWarningMsg(ctxt, XML_WAR_NS_URI, + EMBED_ERRTXT("xmlns: %s not a valid URI\n"), URL, NULL); + } else { + if (uri->scheme == NULL) { + xmlWarningMsg(ctxt, XML_WAR_NS_URI_RELATIVE, + EMBED_ERRTXT("xmlns: URI %s is not absolute\n"), URL, NULL); + } + xmlFreeURI(uri); + } + } + /* + * check that it's not a defined namespace + */ + for (j = 1;j <= nbNs;j++) + if (ctxt->nsTab[ctxt->nsNr - 2 * j] == NULL) + break; + + if (j <= nbNs){ + xmlErrAttributeDup(ctxt, NULL, attname); + }else{ + // SAX2 startPrefixMapping callback is invoked in nsPush + if (nsPush(ctxt, NULL, URL) > 0) + nbNs++; + } + if (alloc != 0) + xmlFree(attvalue); + + SKIP_BLANKS; + continue; + } + + if (aprefix == ctxt->str_xmlns) + { + // we have [ xmlns:prefix="uri" ] - a prefix mapping definition + const xmlChar *URL = xmlDictLookup(ctxt->dict, attvalue, len); + xmlURIPtr uri; + + if (attname == ctxt->str_xml) { + if (URL != ctxt->str_xml_ns) { + xmlNsErr(ctxt, XML_NS_ERR_XML_NAMESPACE, + EMBED_ERRTXT("xml namespace prefix mapped to wrong URI\n"), + NULL, NULL, NULL); + } + /* + * Do not keep a namespace definition node + */ + if (alloc != 0) xmlFree(attvalue); + SKIP_BLANKS; + continue; + } // attname == ctxt->str_xml + + uri = xmlParseURI((const char *) URL); + if (uri == NULL) { + xmlWarningMsg(ctxt, XML_WAR_NS_URI, + EMBED_ERRTXT("xmlns:%s: '%s' is not a valid URI\n"), attname, URL); + } else { + if ((ctxt->pedantic) && (uri->scheme == NULL)) { + xmlWarningMsg(ctxt, XML_WAR_NS_URI_RELATIVE, + EMBED_ERRTXT("xmlns:%s: URI %s is not absolute\n"), attname, URL); + } + xmlFreeURI(uri); + } // uri == NULL + + /* + * check that it's not a defined namespace + */ + for (j = 1;j <= nbNs;j++) + if (ctxt->nsTab[ctxt->nsNr - 2 * j] == attname) + break; + if (j <= nbNs){ + xmlErrAttributeDup(ctxt, aprefix, attname); + }else{ + // SAX2 startPrefixMapping callback is invoked in nsPush + if (nsPush(ctxt, attname, URL) > 0) + nbNs++; + } + if (alloc != 0) + xmlFree(attvalue); + + SKIP_BLANKS; + if (ctxt->input->base != base) { + if (alloc != 0) + xmlFree(attvalue); + goto base_changed; + } + continue; + } // if (aprefix == ctxt->str_xmlns) + + + // If we are here, then we have parsed usual [ attribute="value" ] pair + + /* + * Add the pair to atts + */ + if ((atts == NULL) || (nbatts + 5 > maxatts)) { + if (xmlCtxtGrowAttrs(ctxt, nbatts + 5) < 0) { + if (attvalue[len] == 0) + xmlFree(attvalue); + goto failed; + } + maxatts = ctxt->maxatts; + atts = ctxt->atts; + } + + ctxt->attallocs[nratts++] = alloc; + atts[nbatts++] = attname; + atts[nbatts++] = aprefix; + atts[nbatts++] = NULL; /* the URI will be fetched later */ + atts[nbatts++] = attvalue; + attvalue += len; + atts[nbatts++] = attvalue; // the pointer after the end of attribute is stored instead of length + /* + * tag if some deallocation is needed + */ + if (alloc != 0) + attval = 1; + + + } // if ((attname != NULL) && (attvalue != NULL)) + else { + if ((attvalue != NULL) && (attvalue[len] == 0)) + xmlFree(attvalue); + } + +failed: + + GROW; + + if (ctxt->input->base != base) + goto base_changed; + + if ((RAW == '>') || (((RAW == '/') && (NXT(1) == '>')))) + { + break; // while + } + + if (!IS_BLANK_CH(RAW)) { + xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, EMBED_ERRTXT("attributes construct error\n")); + } + + SKIP_BLANKS; + + if (( cons == ctxt->input->consumed ) && + ( q == CUR_PTR ) && + ( attname == NULL ) && + (attvalue == NULL )) + { + xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR, EMBED_ERRTXT("xmlParseStartTag: problem parsing attributes\n")); + break; // while + } + + GROW; + + if (ctxt->input->base != base) + goto base_changed; + + } // end of while (...) //Parse one attribute + + + /* + * The attributes defaulting + */ + if (ctxt->attsDefault != NULL) + { + xmlDefAttrsPtr defaults; + defaults = (xmlDefAttrsPtr)xmlHashLookup2(ctxt->attsDefault, localname, prefix); + if (defaults != NULL) + { + for (i = 0;i < defaults->nbAttrs;i++) + { + attname = defaults->values[4 * i]; + aprefix = defaults->values[4 * i + 1]; + + /* + * special work for namespaces defaulted defs + */ + + if ((attname == ctxt->str_xmlns) && (aprefix == NULL)) { + /* + * check that it's not a defined namespace + */ + for (j = 1;j <= nbNs;j++) + if (ctxt->nsTab[ctxt->nsNr - 2 * j] == NULL) + break; + if (j <= nbNs) + continue; // for (i = 0;i < defaults->nbAttrs;i++) + + nsname = xmlGetNamespace(ctxt, NULL); + + // DONE: make defaulted namespace mappings added to attributes for XmlInterface support + if (nsname != defaults->values[4 * i + 2]) { + // SAX2 startPrefixMapping callback is invoked in nsPush + if (nsPush(ctxt, NULL, defaults->values[4 * i + 2]) > 0) + nbNs++; + } + + } // (attname == ctxt->str_xmlns) && (aprefix == NULL) + else + if (aprefix == ctxt->str_xmlns) { + /* + * check that it's not a defined namespace + */ + for (j = 1;j <= nbNs;j++) + if (ctxt->nsTab[ctxt->nsNr - 2 * j] == attname) + break; + if (j <= nbNs) + continue; // for (i = 0;i < defaults->nbAttrs;i++) + + // DONE: make prefix-to-namespace mappings added to attributes for complete SAX2 + nsname = xmlGetNamespace(ctxt, attname); + if (nsname != defaults->values[2]) { + // SAX2 startPrefixMapping callback is invoked in nsPush + if (nsPush(ctxt, attname, defaults->values[4 * i + 2]) > 0) + nbNs++; + } + + } //(aprefix == ctxt->str_xmlns) + else { + /* + * check that it's not a defined attribute + */ + for (j = 0;j < nbatts;j+=5) { + if ((attname == atts[j]) && (aprefix == atts[j+1])) + break; + } + + if (j < nbatts) + continue; // for (i = 0;i < defaults->nbAttrs;i++) + + if ((atts == NULL) || (nbatts + 5 > maxatts)) { + if (xmlCtxtGrowAttrs(ctxt, nbatts + 5) < 0) + { // OOM + if(attvalue) + { + xmlFree(attvalue); + } + return(NULL); + } + maxatts = ctxt->maxatts; + atts = ctxt->atts; + } + + atts[nbatts++] = attname; + atts[nbatts++] = aprefix; + atts[nbatts++] = aprefix ? xmlGetNamespace(ctxt, aprefix) + : aprefix /* it's NULL here */; + atts[nbatts++] = defaults->values[4 * i + 2]; + atts[nbatts++] = defaults->values[4 * i + 3]; + nbdef++; + } + } // for (i = 0;i < defaults->nbAttrs;i++) + } // if (defaults != NULL) + } // if (ctxt->attsDefault != NULL) + + /* + * The attributes checkings + */ + for (i = 0; i < nbatts;i += 5) + { + if (atts[i + 1] != NULL) { + nsname = xmlGetNamespace(ctxt, atts[i + 1]); + if (nsname == NULL) { + xmlNsErr(ctxt, XML_NS_ERR_UNDEFINED_NAMESPACE, + "Namespace prefix %s for %s on %s is not defined\n", + atts[i + 1], atts[i], localname); + } + atts[i + 2] = nsname; + } else + nsname = NULL; + + /* + * [ WFC: Unique Att Spec ] + * No attribute name may appear more than once in the same + * start-tag or empty-element tag. + * As extended by the Namespace in XML REC. + */ + for (j = 0; j < i;j += 5) + { + if (atts[i] == atts[j]) + { + if (atts[i+1] == atts[j+1]) + { + xmlErrAttributeDup(ctxt, atts[i+1], atts[i]); + break; + } + if ((nsname != NULL) && (atts[j + 2] == nsname)) + { + xmlNsErr(ctxt, XML_NS_ERR_ATTRIBUTE_REDEFINED, + EMBED_ERRTXT("Namespaced Attribute %s in '%s' redefined\n"), + atts[i], nsname, NULL); + break; + } + } + } // for (i = 0; j < i; j += 5) + } // for (i = 0; i < nbatts; i += 5) + + // check element's namespace: if there is, then should be defined already + nsname = xmlGetNamespace(ctxt, prefix); + if ((prefix != NULL) && (nsname == NULL)) + { + xmlNsErr(ctxt, XML_NS_ERR_UNDEFINED_NAMESPACE, + EMBED_ERRTXT("Namespace prefix %s on %s is not defined\n"), + prefix, localname, NULL); + } + + *pref = prefix; + *URI = nsname; + + /* + * SAX: Start of Element ! + */ + if ((ctxt->sax != NULL) && + (ctxt->sax->startElementNs != NULL) && + (!ctxt->disableSAX)) + { + + if (nbNs > 0) + { + ctxt->sax->startElementNs(ctxt->userData, + localname, prefix, + nsname, nbNs, &ctxt->nsTab[ctxt->nsNr - 2 * nbNs], + nbatts / 5, nbdef, atts); + } + else + { + ctxt->sax->startElementNs(ctxt->userData, + localname, prefix, + nsname, 0, NULL, + nbatts / 5, nbdef, atts); + } + } + + /* + * Free up attribute allocated strings if needed + */ + if (attval != 0) { + for (i = 3,j = 0; j < nratts;i += 5,j++) + if ((ctxt->attallocs[j] != 0) && (atts[i] != NULL)) + xmlFree((xmlChar *) atts[i]); + } + // check OOM after calling callback + if(OOM_FLAG) + { + goto OOM; + } +// XE: BEGIN NEW CODE - save number of newly defined (and pushed to stack) namespaces + ctxt->lastNsNr = nbNs; +// XE: END NEW CODE + + return(localname); + +base_changed: + /* + * the attribute strings are valid iif the base didn't changed + */ + if (attval != 0) { + for (i = 3,j = 0; j < nratts;i += 5,j++) + if ((ctxt->attallocs[j] != 0) && (atts[i] != NULL)) + xmlFree((xmlChar *) atts[i]); + } + ctxt->input->cur = ctxt->input->base + cur; + + if (ctxt->wellFormed == 1) { + goto reparse; + } + return(NULL); +//--------------------------------- +OOM: + xmlParserOOMErr(ctxt); + return NULL; +} + +/** + * xmlParseEndTag2: + * @param ctxt an XML parser context + * @param line line of the start tag + * @param nsNr number of namespaces on the start tag + * + * parse an end of tag + * + * [42] ETag ::= '' + * + * With namespace + * + * [NS 9] ETag ::= '' + */ + +static void +xmlParseEndTag2(xmlParserCtxtPtr ctxt, const xmlChar *prefix, + const xmlChar *URI, int line, int nsNr, int tlen) { + const xmlChar *name; + + GROW; + if ((RAW != '<') || (NXT(1) != '/')) { + xmlFatalErr(ctxt, XML_ERR_LTSLASH_REQUIRED, NULL); + return; + } + SKIP(2); + + if ((tlen > 0) && (strncmp((char*) ctxt->input->cur, (char*) ctxt->name, tlen) == 0)) { + if (ctxt->input->cur[tlen] == '>') { + ctxt->input->cur += tlen + 1; + goto done; + } + ctxt->input->cur += tlen; + name = (xmlChar*)1; + } else { + if (prefix == NULL) + name = xmlParseNameAndCompare(ctxt, ctxt->name); + else + name = xmlParseQNameAndCompare(ctxt, ctxt->name, prefix); + } + + /* + * We should definitely be at the ending "S? '>'" part + */ + GROW; + SKIP_BLANKS; + if ((!IS_BYTE_CHAR(RAW)) || (RAW != '>')) { + xmlFatalErr(ctxt, XML_ERR_GT_REQUIRED, NULL); + } else + NEXT1; + + /* + * [ WFC: Element Type Match ] + * The Name in an element's end-tag must match the element type in the + * start-tag. + * + */ + if (name != (xmlChar*)1) { + if (name == NULL) name = BAD_CAST "unparseable"; + xmlFatalErrMsgStrIntStr(ctxt, XML_ERR_TAG_NAME_MISMATCH, + EMBED_ERRTXT("Opening and ending tag mismatch: %s line %d and %s\n"), + ctxt->name, line, name); + } + + /* + * SAX: End of Tag + */ +done: + if ((ctxt->sax != NULL) && + (ctxt->sax->endElementNs != NULL) && + (!ctxt->disableSAX)) + { + ctxt->sax->endElementNs(ctxt->userData, ctxt->name, prefix, URI); + } + + spacePop(ctxt); + if (nsNr != 0){ + // SAX2 endPrefixMapping callback is invoked in nsPop for every popped prefix + nsPop(ctxt, nsNr); + } + return; +} + +/** + * xmlParseCDSect: + * @param ctxt an XML parser context + * + * Parse escaped pure raw content. + * + * [18] CDSect ::= CDStart CData CDEnd + * + * [19] CDStart ::= '' Char*)) + * + * [21] CDEnd ::= ']]>' + */ +XMLPUBFUNEXPORT void +xmlParseCDSect(xmlParserCtxtPtr ctxt) { + xmlChar *buf = NULL; + int len = 0; + int size = XML_PARSER_BUFFER_SIZE; + int r, rl; + int s, sl; + int cur, l; + int count = 0; + + /* Check 2.6.0 was NXT(0) not RAW */ + if (CMP9(CUR_PTR, '<', '!', '[', 'C', 'D', 'A', 'T', 'A', '[')) { + SKIP(9); + } else + return; + + ctxt->instate = XML_PARSER_CDATA_SECTION; + r = CUR_CHAR(rl); + if (!IS_CHAR(r)) { + xmlFatalErr(ctxt, XML_ERR_CDATA_NOT_FINISHED, NULL); + ctxt->instate = XML_PARSER_CONTENT; + return; + } + NEXTL(rl); + s = CUR_CHAR(sl); + if (!IS_CHAR(s)) { + xmlFatalErr(ctxt, XML_ERR_CDATA_NOT_FINISHED, NULL); + ctxt->instate = XML_PARSER_CONTENT; + return; + } + NEXTL(sl); + cur = CUR_CHAR(l); + buf = (xmlChar*) xmlMallocAtomic(size * sizeof(xmlChar)); + if (!buf) + goto OOM_exit; + + while (IS_CHAR(cur) && + ((r != ']') || (s != ']') || (cur != '>'))) { + if (len + 5 >= size) { + // DONE: Fix xmlRealloc + xmlChar* tmp; + size *= 2; + tmp = (xmlChar*) xmlRealloc(buf, size * sizeof(xmlChar)); + if (!tmp) { + xmlFree(buf); +OOM_exit: + xmlParserOOMErr(ctxt); + return; + } + buf = tmp; + } + COPY_BUF(rl,buf,len,r); + r = s; + rl = sl; + s = cur; + sl = l; + count++; + if (count > 50) { + GROW; + count = 0; + } + NEXTL(l); + cur = CUR_CHAR(l); + } + buf[len] = 0; + ctxt->instate = XML_PARSER_CONTENT; + if (cur != '>') { + xmlFatalErrMsgStr(ctxt, XML_ERR_CDATA_NOT_FINISHED, + EMBED_ERRTXT("CData section not finished\n%.50s\n"), buf); + xmlFree(buf); + return; + } + NEXTL(l); + + /* + * OK the buffer is to be consumed as cdata. + */ + if ((ctxt->sax != NULL) && (!ctxt->disableSAX)) { + if (ctxt->sax->cdataBlock != NULL) + ctxt->sax->cdataBlock(ctxt->userData, buf, len); + else if (ctxt->sax->characters != NULL) + ctxt->sax->characters(ctxt->userData, buf, len); + } + xmlFree(buf); +} + +/** + * xmlParseContent: + * @param ctxt an XML parser context + * + * Parse a content: + * + * [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)* + */ + +XMLPUBFUNEXPORT void +xmlParseContent(xmlParserCtxtPtr ctxt) { + LOAD_GS_SAFE_CTXT(ctxt) + GROW; + while ((RAW != 0) && + ((RAW != '<') || (NXT(1) != '/'))) { + const xmlChar *test = CUR_PTR; + unsigned int cons = ctxt->input->consumed; + const xmlChar *cur = ctxt->input->cur; + + /* + * First case : a Processing Instruction. + */ + if ((*cur == '<') && (cur[1] == '?')) { + xmlParsePI(ctxt); + } + + /* + * Second case : a CDSection + */ + /* 2.6.0 test was *cur not RAW */ + else if (CMP9(CUR_PTR, '<', '!', '[', 'C', 'D', 'A', 'T', 'A', '[')) { + xmlParseCDSect(ctxt); + } + + /* + * Third case : a comment + */ + else if ((*cur == '<') && (NXT(1) == '!') && + (NXT(2) == '-') && (NXT(3) == '-')) { + xmlParseComment(ctxt); + ctxt->instate = XML_PARSER_CONTENT; + } + + /* + * Fourth case : a sub-element. + */ + else if (*cur == '<') + { + if( (((unsigned int)&cur) - ((unsigned int) xeStackLimit)) < ctxt->stackLowThreshold ) + { + SET_OOM_FLAG; + xmlFatalErr(ctxt, XML_ERR_STACK_LOW, NULL); + return; + } + + xmlParseElement(ctxt); + if(OOM_FLAG) + { + return; + } + } + + /* + * Fifth case : a reference. If if has not been resolved, + * parsing returns it's Name, create the node + */ + + else if (*cur == '&') { + xmlParseReference(ctxt); + } + + /* + * Last case, text. Note that References are handled directly. + */ + else { + xmlParseCharData(ctxt, 0); + } + + GROW; + /* + * Pop-up of finished entities. + */ + while ((RAW == 0) && (ctxt->inputNr > 1)) + xmlPopInput(ctxt); + SHRINK; + + if ((cons == ctxt->input->consumed) && (test == CUR_PTR)) { + xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR, + EMBED_ERRTXT("detected an error in element content\n")); + ctxt->instate = XML_PARSER_EOF; + break; + } + } +} + +/** + * xmlParseElement: + * @param ctxt an XML parser context + * + * parse an XML element, this is highly recursive + * + * [39] element ::= EmptyElemTag | STag content ETag + * + * [ WFC: Element Type Match ] + * The Name in an element's end-tag must match the element type in the + * start-tag. + * + */ + +XMLPUBFUNEXPORT void +xmlParseElement(xmlParserCtxtPtr ctxt) +{ + const xmlChar *name; + const xmlChar *prefix; + const xmlChar *URI; +#ifdef XMLENGINE_ENABLE_PARSER_RECORD_INFO + xmlParserNodeInfo node_info; + xmlNodePtr ret; +#endif + int line, tlen; + int nsNr = ctxt->nsNr; + LOAD_GS_SAFE_CTXT(ctxt) + +#ifdef XMLENGINE_ENABLE_PARSER_RECORD_INFO + /* Capture start position */ + + if (ctxt->record_info) { + node_info.begin_pos = ctxt->input->consumed + + (CUR_PTR - ctxt->input->base); + node_info.begin_line = ctxt->input->line; + } +#endif + + if (ctxt->spaceNr == 0) + spacePush(ctxt, -1); + else + spacePush(ctxt, *ctxt->space); + + line = ctxt->input->line; +#ifdef LIBXML_SAX1_ENABLED + if (ctxt->sax2) +#endif /* LIBXML_SAX1_ENABLED */ + name = xmlParseStartTag2(ctxt, &prefix, &URI, &tlen); +#ifdef LIBXML_SAX1_ENABLED + else + name = xmlParseStartTag(ctxt); +#endif /* LIBXML_SAX1_ENABLED */ + if (name == NULL) { + spacePop(ctxt); + return; + } + namePush(ctxt, name); +#ifdef XMLENGINE_ENABLE_PARSER_RECORD_INFO + ret = ctxt->node; +#endif + +#ifdef LIBXML_VALID_ENABLED + /* + * [ VC: Root Element Type ] + * The Name in the document type declaration must match the element + * type of the root element. + */ + if (ctxt->validate && ctxt->wellFormed && ctxt->myDoc && + ctxt->node && (ctxt->node == ctxt->myDoc->children)) + ctxt->valid &= xmlValidateRoot(&ctxt->vctxt, ctxt->myDoc); +#endif /* LIBXML_VALID_ENABLED */ + + /* + * Check for an Empty Element. + */ + if ((RAW == '/') && (NXT(1) == '>')) { + SKIP(2); + if (ctxt->sax2) { + if ((ctxt->sax != NULL) && (ctxt->sax->endElementNs != NULL) && + (!ctxt->disableSAX)) + ctxt->sax->endElementNs(ctxt->userData, name, prefix, URI); +#ifdef LIBXML_SAX1_ENABLED + } else { + if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL) && + (!ctxt->disableSAX)) + ctxt->sax->endElement(ctxt->userData, name); +#endif /* LIBXML_SAX1_ENABLED */ + } + namePop(ctxt); + spacePop(ctxt); + if (nsNr != ctxt->nsNr) + nsPop(ctxt, ctxt->nsNr - nsNr); +#ifdef XMLENGINE_ENABLE_PARSER_RECORD_INFO + if ( ret != NULL && ctxt->record_info ) { + node_info.end_pos = ctxt->input->consumed + + (CUR_PTR - ctxt->input->base); + node_info.end_line = ctxt->input->line; + node_info.node = ret; + xmlParserAddNodeInfo(ctxt, &node_info); + } +#endif + return; + } + if (RAW == '>') { + NEXT1; + } else { + xmlFatalErrMsgStrIntStr(ctxt, XML_ERR_GT_REQUIRED, + EMBED_ERRTXT("Couldn't find end of Start Tag %s line %d\n"), + name, line, NULL); + + /* + * end of parsing of this node. + */ + nodePop(ctxt); + namePop(ctxt); + spacePop(ctxt); + if (nsNr != ctxt->nsNr) + nsPop(ctxt, ctxt->nsNr - nsNr); + +#ifdef XMLENGINE_ENABLE_PARSER_RECORD_INFO + /* + * Capture end position and add node + */ + if ( ret != NULL && ctxt->record_info ) { + node_info.end_pos = ctxt->input->consumed + (CUR_PTR - ctxt->input->base); + node_info.end_line = ctxt->input->line; + node_info.node = ret; + xmlParserAddNodeInfo(ctxt, &node_info); + } +#endif + return; + } + + /* + * Parse the content of the element: + */ + xmlParseContent(ctxt); + if(OOM_FLAG) + { + return; + } + if (!IS_BYTE_CHAR(RAW)) { + xmlFatalErrMsgStrIntStr(ctxt, XML_ERR_TAG_NOT_FINISHED, + EMBED_ERRTXT("Premature end of data in tag %s line %d\n"), + name, line, NULL); + + /* + * end of parsing of this node. + */ + nodePop(ctxt); + namePop(ctxt); + spacePop(ctxt); + if (nsNr != ctxt->nsNr) + nsPop(ctxt, ctxt->nsNr - nsNr); + return; + } + + /* + * parse the end of tag: 'sax2) { + xmlParseEndTag2(ctxt, prefix, URI, line, ctxt->nsNr - nsNr, tlen); + namePop(ctxt); + } +#ifdef LIBXML_SAX1_ENABLED + else + xmlParseEndTag1(ctxt, line); +#endif /* LIBXML_SAX1_ENABLED */ + +#ifdef XMLENGINE_ENABLE_PARSER_RECORD_INFO + /* + * Capture end position and add node + */ + if ( ret != NULL && ctxt->record_info ) { + node_info.end_pos = ctxt->input->consumed + + (CUR_PTR - ctxt->input->base); + node_info.end_line = ctxt->input->line; + node_info.node = ret; + xmlParserAddNodeInfo(ctxt, &node_info); + } +#endif +} + +/** + * xmlParseVersionNum: + * @param ctxt an XML parser context + * + * parse the XML version value. + * + * [26] VersionNum ::= ([a-zA-Z0-9_.:] | '-')+ + * + * Returns the string giving the XML version number, or NULL + * + * OOM: possible --> sets OOM flag when NULL is returned + */ +XMLPUBFUNEXPORT xmlChar* +xmlParseVersionNum(xmlParserCtxtPtr ctxt) +{ + xmlChar* buf; + int len = 0; + int size = 10; + xmlChar cur; + + buf = (xmlChar*) xmlMallocAtomic(size * sizeof(xmlChar)); + if (!buf) + goto OOM_exit; + + cur = CUR; + while (((cur >= 'a') && (cur <= 'z')) || + ((cur >= 'A') && (cur <= 'Z')) || + ((cur >= '0') && (cur <= '9')) || + (cur == '_') || (cur == '.') || + (cur == ':') || (cur == '-')) + { + if (len + 1 >= size) + { + // DONE: Fix xmlRealloc + xmlChar* tmp; + size *= 2; + tmp = (xmlChar*) xmlRealloc(buf, size * sizeof(xmlChar)); + if (!tmp) { + xmlFree(buf); +OOM_exit: + xmlParserOOMErr(ctxt); + return(NULL); + } + buf = tmp; + } + buf[len++] = cur; + NEXT; + cur=CUR; + } + buf[len] = 0; + return(buf); +} + +/** + * xmlParseVersionInfo: + * @param ctxt an XML parser context + * + * parse the XML version. + * + * [24] VersionInfo ::= S 'version' Eq (' VersionNum ' | " VersionNum ") + * [25] Eq ::= S? '=' S? + * + * Returns the version string, e.g. "1.0" + * + * OOM: + */ +XMLPUBFUNEXPORT xmlChar* +xmlParseVersionInfo(xmlParserCtxtPtr ctxt) { + xmlChar* version; + xmlChar ch; + int errCode; + LOAD_GS_SAFE_CTXT(ctxt) + + + + + if (CMP7(CUR_PTR, 'v', 'e', 'r', 's', 'i', 'o', 'n')) + { + SKIP(7); + SKIP_BLANKS; +//XMLENGINE: BEGIN REPLACE CODE +//XMLENGINE: NEW CODE + if(OOM_FLAG) goto OOM; + if (RAW != '=') { + errCode = XML_ERR_EQUAL_REQUIRED; + goto ERR; + } + NEXT; + if(OOM_FLAG) + goto OOM; + SKIP_BLANKS; + if(OOM_FLAG) + goto OOM; + + ch = RAW; + if (ch == '"' || ch=='\'') + { // DONE: OPTIMIZE: Combine two cases when RAW='\"' or '\'' + NEXT; + if(OOM_FLAG) + goto OOM; + version = xmlParseVersionNum(ctxt); + if (RAW == ch) { + NEXT; + if(OOM_FLAG) + goto OOM; // checks xmlParseVersionNum too + return version; + } else { + errCode = XML_ERR_STRING_NOT_CLOSED; + goto ERR; + } + } else { + errCode = XML_ERR_STRING_NOT_STARTED; + goto ERR; + } +//XMLENGINE: END REPLACE CODE + } +OOM: + return NULL; +ERR: + xmlFatalErr(ctxt, (xmlParserErrors)errCode, NULL); + goto OOM; +} + +/** + * xmlParseEncName: + * @param ctxt an XML parser context + * + * parse the XML encoding name + * + * [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')* + * + * Returns the encoding name value or NULL + */ +XMLPUBFUNEXPORT xmlChar * +xmlParseEncName(xmlParserCtxtPtr ctxt) { + xmlChar *buf = NULL; + int len = 0; + int size = 10; + xmlChar cur; + + cur = CUR; + if (((cur >= 'a') && (cur <= 'z')) || + ((cur >= 'A') && (cur <= 'Z'))) { + buf = (xmlChar*) xmlMallocAtomic(size * sizeof(xmlChar)); + if (!buf) + goto OOM_exit; + + buf[len++] = cur; + NEXT; + cur = CUR; + while (((cur >= 'a') && (cur <= 'z')) || + ((cur >= 'A') && (cur <= 'Z')) || + ((cur >= '0') && (cur <= '9')) || + (cur == '.') || (cur == '_') || + (cur == '-')) { + if (len + 1 >= size) { + // DONE: Fix xmlRealloc + xmlChar* tmp; + size *= 2; + tmp = (xmlChar*) xmlRealloc(buf, size * sizeof(xmlChar)); + if (!tmp) { + xmlFree(buf); +OOM_exit: + xmlParserOOMErr(ctxt); + return(NULL); + } + buf = tmp; + } + buf[len++] = cur; + NEXT; + cur = CUR; + if (cur == 0) { + SHRINK; + GROW; + cur = CUR; + } + } + buf[len] = 0; + } else { + xmlFatalErr(ctxt, XML_ERR_ENCODING_NAME, NULL); + } + return(buf); +} + +/** + * xmlParseEncodingDecl: + * @param ctxt an XML parser context + * + * parse the XML encoding declaration + * + * [80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' | "'" EncName "'") + * + * this setups the conversion filters. + * + * Returns the encoding value or NULL + */ + +XMLPUBFUNEXPORT const xmlChar * +xmlParseEncodingDecl(xmlParserCtxtPtr ctxt) { + xmlChar *encoding = NULL; + + SKIP_BLANKS; + if (CMP8(CUR_PTR, 'e', 'n', 'c', 'o', 'd', 'i', 'n', 'g')) { + SKIP(8); + SKIP_BLANKS; + if (RAW != '=') { + xmlFatalErr(ctxt, XML_ERR_EQUAL_REQUIRED, NULL); + return(NULL); + } + NEXT; + SKIP_BLANKS; + if (RAW == '"') { + NEXT; + encoding = xmlParseEncName(ctxt); + if (RAW != '"') { + xmlFatalErr(ctxt, XML_ERR_STRING_NOT_CLOSED, NULL); + } else + NEXT; + } else if (RAW == '\''){ + NEXT; + encoding = xmlParseEncName(ctxt); + if (RAW != '\'') { + xmlFatalErr(ctxt, XML_ERR_STRING_NOT_CLOSED, NULL); + } else + NEXT; + } else { + xmlFatalErr(ctxt, XML_ERR_STRING_NOT_STARTED, NULL); + } + /* + * UTF-16 encoding stwich has already taken place at this stage, + * more over the little-endian/big-endian selection is already done + */ + if ((encoding != NULL) && + ((!xmlStrcasecmp(encoding, BAD_CAST "UTF-16")) || + (!xmlStrcasecmp(encoding, BAD_CAST "UTF16")))) { + if (ctxt->encoding != NULL) + xmlFree((xmlChar *) ctxt->encoding); + ctxt->encoding = encoding; + } + /* + * UTF-8 encoding is handled natively + */ + else if ((encoding != NULL) && + ((!xmlStrcasecmp(encoding, BAD_CAST "UTF-8")) || + (!xmlStrcasecmp(encoding, BAD_CAST "UTF8")))) { + if (ctxt->encoding != NULL) + xmlFree((xmlChar *) ctxt->encoding); + ctxt->encoding = encoding; + } + else if (encoding != NULL) { + xmlCharEncodingHandlerPtr handler; + + if (ctxt->input->encoding != NULL) + xmlFree((xmlChar *) ctxt->input->encoding); + ctxt->input->encoding = encoding; + + handler = xmlFindCharEncodingHandler((const char *) encoding); + if (handler != NULL) { + xmlSwitchToEncoding(ctxt, handler); + } else { + xmlFatalErrMsgStr(ctxt, XML_ERR_UNSUPPORTED_ENCODING, + EMBED_ERRTXT("Unsupported encoding %s\n"), encoding); + return(NULL); + } + } + } + return(encoding); +} + +/** + * xmlParseSDDecl: + * @param ctxt an XML parser context + * + * parse the XML standalone declaration + * + * [32] SDDecl ::= S 'standalone' Eq + * (("'" ('yes' | 'no') "'") | ('"' ('yes' | 'no')'"')) + * + * [ VC: Standalone Document Declaration ] + * The standalone document declaration must have the value "no" + * if any external markup declarations contain declarations of: + * - attributes with default values, if elements to which these + * attributes apply appear in the document without specifications + * of values for these attributes, or + * - entities (other than amp, lt, gt, apos, quot), if references + * to those entities appear in the document, or + * - attributes with values subject to normalization, where the + * attribute appears in the document with a value which will change + * as a result of normalization, or + * - element types with element content, if white space occurs directly + * within any instance of those types. + * + * Returns 1 if standalone, 0 otherwise + */ + +XMLPUBFUNEXPORT int +xmlParseSDDecl(xmlParserCtxtPtr ctxt) { + int standalone = -1; + + SKIP_BLANKS; + if (CMP10(CUR_PTR, 's', 't', 'a', 'n', 'd', 'a', 'l', 'o', 'n', 'e')) { + SKIP(10); + SKIP_BLANKS; + if (RAW != '=') { + xmlFatalErr(ctxt, XML_ERR_EQUAL_REQUIRED, NULL); + return(standalone); + } + NEXT; + SKIP_BLANKS; + if (RAW == '\''){ + NEXT; + if ((RAW == 'n') && (NXT(1) == 'o')) { + standalone = 0; + SKIP(2); + } else if ((RAW == 'y') && (NXT(1) == 'e') && + (NXT(2) == 's')) { + standalone = 1; + SKIP(3); + } else { + xmlFatalErr(ctxt, XML_ERR_STANDALONE_VALUE, NULL); + } + if (RAW != '\'') { + xmlFatalErr(ctxt, XML_ERR_STRING_NOT_CLOSED, NULL); + } else + NEXT; + } else if (RAW == '"'){ + NEXT; + if ((RAW == 'n') && (NXT(1) == 'o')) { + standalone = 0; + SKIP(2); + } else if ((RAW == 'y') && (NXT(1) == 'e') && + (NXT(2) == 's')) { + standalone = 1; + SKIP(3); + } else { + xmlFatalErr(ctxt, XML_ERR_STANDALONE_VALUE, NULL); + } + if (RAW != '"') { + xmlFatalErr(ctxt, XML_ERR_STRING_NOT_CLOSED, NULL); + } else + NEXT; + } else { + xmlFatalErr(ctxt, XML_ERR_STRING_NOT_STARTED, NULL); + } + } + return(standalone); +} + +/** + * xmlParseXMLDecl: + * @param ctxt an XML parser context + * + * parse an XML declaration header + * + * [23] XMLDecl ::= '' + * + * OOM: + */ +XMLPUBFUNEXPORT void +xmlParseXMLDecl(xmlParserCtxtPtr ctxt) { + xmlChar *version; + /* + * We know that 'version != NULL) + xmlFree((void *) ctxt->version); + ctxt->version = version; + } + + /* + * We may have the encoding declaration + */ + if (!IS_BLANK_CH(RAW)) { + if ((RAW == '?') && (NXT(1) == '>')) { + SKIP(2); + return; + } + xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, EMBED_ERRTXT("Blank needed here\n")); + } + xmlParseEncodingDecl(ctxt); + if (ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) { + /* + * The XML REC instructs us to stop parsing right here + */ + return; + } + + /* + * We may have the standalone status. + */ + if ((ctxt->input->encoding != NULL) && (!IS_BLANK_CH(RAW))) { + if ((RAW == '?') && (NXT(1) == '>')) { + SKIP(2); + return; + } + xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, EMBED_ERRTXT("Blank needed here\n")); + } + SKIP_BLANKS; + ctxt->input->standalone = xmlParseSDDecl(ctxt); + + SKIP_BLANKS; + if ((RAW == '?') && (NXT(1) == '>')) { + SKIP(2); + } else if (RAW == '>') { + /* Deprecated old WD ... */ + xmlFatalErr(ctxt, XML_ERR_XMLDECL_NOT_FINISHED, NULL); + NEXT; + } else { + xmlFatalErr(ctxt, XML_ERR_XMLDECL_NOT_FINISHED, NULL); + MOVETO_ENDTAG(CUR_PTR); + NEXT; + } +} + +/** + * xmlParseMisc: + * @param ctxt an XML parser context + * + * parse an XML Misc* optional field. + * + * [27] Misc ::= Comment | PI | S + */ + +XMLPUBFUNEXPORT void +xmlParseMisc(xmlParserCtxtPtr ctxt) { + while (((RAW == '<') && (NXT(1) == '?')) || + (CMP4(CUR_PTR, '<', '!', '-', '-')) || + IS_BLANK_CH(CUR)) { + if ((RAW == '<') && (NXT(1) == '?')) { + xmlParsePI(ctxt); + } else if (IS_BLANK_CH(CUR)) { + NEXT; + } else + xmlParseComment(ctxt); + } +} + +/** + * xmlParseDocument: + * @param ctxt an XML parser context + * + * parse an XML document (and build a tree if using the standard SAX + * interface). + * + * [1] document ::= prolog element Misc* + * + * [22] prolog ::= XMLDecl? Misc* (doctypedecl Misc*)? + * + * Returns 0, -1 in case of error. the parser context is augmented + * as a result of the parsing. + * + * OOM: possible, of course --> check OOM flag [REVIEW NOT FINISHED] + */ + +XMLPUBFUNEXPORT int +xmlParseDocument(xmlParserCtxtPtr ctxt) { + xmlChar start[4]; + xmlCharEncoding enc; + LOAD_GS_SAFE_CTXT(ctxt) + + xmlInitParser(); + if(OOM_FLAG) + return -1; + GROW; + if(OOM_FLAG) + return -1; + + /* + * SAX: detecting the level. + */ + xmlDetectSAX2(ctxt); + if(OOM_FLAG) + return (-1); + /* + * SAX: beginning of the document processing. + */ + if ((ctxt->sax) && (ctxt->sax->setDocumentLocator)) + { + ctxt->sax->setDocumentLocator(ctxt->userData, (xmlSAXLocatorPtr)&xmlDefaultSAXLocator); + if(OOM_FLAG) + return -1; + } + + if ((ctxt->encoding == (const xmlChar*)XML_CHAR_ENCODING_NONE) && + ((ctxt->input->end - ctxt->input->cur) >= 4)) + { + /* + * Get the 4 first bytes and decode the charset + * if enc != XML_CHAR_ENCODING_NONE + * plug some encoding conversion routines. + */ + start[0] = RAW; + start[1] = NXT(1); + start[2] = NXT(2); + start[3] = NXT(3); + enc = xmlDetectCharEncoding(&start[0], 4); + if (enc != XML_CHAR_ENCODING_NONE) { + xmlSwitchEncoding(ctxt, enc); + if(OOM_FLAG) + return -1; + } + } + + + if (CUR == 0) { + xmlFatalErr(ctxt, XML_ERR_DOCUMENT_EMPTY, NULL); + } + + /* + * Check for the XMLDecl in the Prolog. + */ + GROW; + if(OOM_FLAG) + return -1; + if ((CMP5(CUR_PTR, '<', '?', 'x', 'm', 'l')) && (IS_BLANK_CH(NXT(5)))) + { + /* + * Note that we will switch encoding on the fly. + */ + xmlParseXMLDecl(ctxt); + if(OOM_FLAG) + return -1; + if (ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) { + /* + * The XML REC instructs us to stop parsing right here + */ + return(-1); + } + ctxt->standalone = ctxt->input->standalone; + SKIP_BLANKS; + if(OOM_FLAG) + return -1; + } else { + ctxt->version = xmlCharStrdup(XML_DEFAULT_VERSION); + if(OOM_FLAG) + return -1; + } + if ((ctxt->sax) && (ctxt->sax->startDocument) && (!ctxt->disableSAX)) + { + ctxt->sax->startDocument(ctxt->userData); + if(OOM_FLAG) + return -1; + } + /* + * The Misc part of the Prolog + */ + GROW; + if(OOM_FLAG) + return -1; + xmlParseMisc(ctxt); + if(OOM_FLAG) + return -1; + /* + * Then possibly doc type declaration(s) and more Misc + * (doctypedecl Misc*)? + */ + GROW; + if(OOM_FLAG) + return -1; + if (CMP9(CUR_PTR, '<', '!', 'D', 'O', 'C', 'T', 'Y', 'P', 'E')) { + + ctxt->inSubset = 1; + xmlParseDocTypeDecl(ctxt); + if(OOM_FLAG) + return -1; + if (RAW == '[') { + ctxt->instate = XML_PARSER_DTD; + xmlParseInternalSubset(ctxt); + if(OOM_FLAG) + return -1; + } + + /* + * Create and update the external subset. + */ + ctxt->inSubset = 2; + if ((ctxt->sax != NULL) && (ctxt->sax->externalSubset != NULL) && + (!ctxt->disableSAX)) + { + ctxt->sax->externalSubset(ctxt->userData, ctxt->intSubName, + ctxt->extSubSystem, ctxt->extSubURI); + if(OOM_FLAG) + return -1; + } + ctxt->inSubset = 0; + + ctxt->instate = XML_PARSER_PROLOG; + xmlParseMisc(ctxt); + if(OOM_FLAG) + return -1; + } + + /* + * Time to start parsing the tree itself + */ + GROW; + if(OOM_FLAG) + return -1; + if (RAW != '<') { + xmlFatalErrMsg(ctxt, XML_ERR_DOCUMENT_EMPTY, + EMBED_ERRTXT("Start tag expected, '<' not found\n")); + } else { + ctxt->instate = XML_PARSER_CONTENT; + xmlParseElement(ctxt); + if(OOM_FLAG) + return -1; + ctxt->instate = XML_PARSER_EPILOG; + + + /* + * The Misc part at the end + */ + xmlParseMisc(ctxt); + if(OOM_FLAG) + return -1; + if (RAW != 0) { + xmlFatalErr(ctxt, XML_ERR_DOCUMENT_END, NULL); + } + ctxt->instate = XML_PARSER_EOF; + } + + /* + * SAX: end of the document processing. + */ + if ((ctxt->sax) && (ctxt->sax->endDocument != NULL)) + { + ctxt->sax->endDocument(ctxt->userData); + if(OOM_FLAG) + return -1; + } + + /* + * Remove locally kept entity definitions if the tree was not built + */ + if ((ctxt->myDoc != NULL) && + (xmlStrEqual(ctxt->myDoc->version, SAX_COMPAT_MODE))) + { + xmlFreeDoc(ctxt->myDoc); + ctxt->myDoc = NULL; + } + + if (! ctxt->wellFormed) { + ctxt->valid = 0; + return(-1); + } + return(0); +} + +/** + * xmlParseExtParsedEnt: + * @param ctxt an XML parser context + * + * parse a general parsed entity + * An external general parsed entity is well-formed if it matches the + * production labeled extParsedEnt. + * + * [78] extParsedEnt ::= TextDecl? content + * + * Returns 0, -1 in case of error. the parser context is augmented + * as a result of the parsing. + */ + +XMLPUBFUNEXPORT int +xmlParseExtParsedEnt(xmlParserCtxtPtr ctxt) { + xmlChar start[4]; + xmlCharEncoding enc; + LOAD_GS_SAFE_CTXT(ctxt) + + xmlDefaultSAXHandlerInit(); + if(OOM_FLAG) + return -1; + + xmlDetectSAX2(ctxt); + if(OOM_FLAG) + return -1; + + GROW; + if(OOM_FLAG) + return -1; + /* + * SAX: beginning of the document processing. + */ + if ((ctxt->sax) && (ctxt->sax->setDocumentLocator)) + { + ctxt->sax->setDocumentLocator(ctxt->userData, (xmlSAXLocatorPtr)&xmlDefaultSAXLocator); + } + /* + * Get the 4 first bytes and decode the charset + * if enc != XML_CHAR_ENCODING_NONE + * plug some encoding conversion routines. + */ + if ((ctxt->input->end - ctxt->input->cur) >= 4) { + start[0] = RAW; + start[1] = NXT(1); + start[2] = NXT(2); + start[3] = NXT(3); + enc = xmlDetectCharEncoding(start, 4); + if (enc != XML_CHAR_ENCODING_NONE) { + xmlSwitchEncoding(ctxt, enc); + if(OOM_FLAG) + return -1; + } + } + + if (CUR == 0) { + xmlFatalErr(ctxt, XML_ERR_DOCUMENT_EMPTY, NULL); + } + + /* + * Check for the XMLDecl in the Prolog. + */ + GROW; + if(OOM_FLAG) + return -1; + + if ((CMP5(CUR_PTR, '<', '?', 'x', 'm', 'l')) && (IS_BLANK_CH(NXT(5)))) { + + /* + * Note that we will switch encoding on the fly. + */ + xmlParseXMLDecl(ctxt); + if (ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) { + /* + * The XML REC instructs us to stop parsing right here + */ + return(-1); + } + SKIP_BLANKS; + } else { + ctxt->version = xmlCharStrdup(XML_DEFAULT_VERSION); + } + if ((ctxt->sax) && (ctxt->sax->startDocument) && (!ctxt->disableSAX)) + ctxt->sax->startDocument(ctxt->userData); + + /* + * Doing validity checking on chunk doesn't make sense + */ + ctxt->instate = XML_PARSER_CONTENT; + ctxt->validate = 0; + ctxt->loadsubset = 0; + ctxt->depth = 0; + + xmlParseContent(ctxt); + + if ((RAW == '<') && (NXT(1) == '/')) { + xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL); + } else if (RAW != 0) { + xmlFatalErr(ctxt, XML_ERR_EXTRA_CONTENT, NULL); + } + + /* + * SAX: end of the document processing. + */ + if ((ctxt->sax) && (ctxt->sax->endDocument != NULL)) + ctxt->sax->endDocument(ctxt->userData); + + if (! ctxt->wellFormed) return(-1); + return(0); +} + +#ifdef LIBXML_PUSH_ENABLED +/************************************************************************ + * * + * Progressive parsing interfaces * + * * + ************************************************************************/ + +/** + * xmlParseLookupSequence: + * @param ctxt an XML parser context + * @param first the first char to lookup + * @param next the next char to lookup or zero + * @param third the next char to lookup or zero + * + * Try to find if a sequence (first, next, third) or just (first next) or + * (first) is available in the input stream. + * This function has a side effect of (possibly) incrementing ctxt->checkIndex + * to avoid rescanning sequences of bytes, it DOES change the state of the + * parser, do not use liberally. + * + * Returns the index to the current parsing point if the full sequence + * is available, -1 otherwise. + */ +static int +xmlParseLookupSequence(xmlParserCtxtPtr ctxt, xmlChar first, + xmlChar next, xmlChar third) { + int base, len; + xmlParserInputPtr in; + const xmlChar *buf; + + in = ctxt->input; + if (in == NULL) return(-1); + base = in->cur - in->base; + if (base < 0) return(-1); + if (ctxt->checkIndex > base) + base = ctxt->checkIndex; + if (in->buf == NULL) { + buf = in->base; + len = in->length; + } else { + buf = in->buf->buffer->content; + len = in->buf->buffer->use; + } + /* take into account the sequence length */ + if (third) len -= 2; + else if (next) len --; + for (;base < len;base++) { + if (buf[base] == first) { + if (third != 0) { + if ((buf[base + 1] != next) || + (buf[base + 2] != third)) continue; + } else if (next != 0) { + if (buf[base + 1] != next) continue; + } + ctxt->checkIndex = 0; +#ifdef DEBUG_PUSH + if (next == 0) + xmlGenericError(xmlGenericErrorContext, + "PP: lookup '%c' found at %d\n", + first, base); + else if (third == 0) + xmlGenericError(xmlGenericErrorContext, + "PP: lookup '%c%c' found at %d\n", + first, next, base); + else + xmlGenericError(xmlGenericErrorContext, + "PP: lookup '%c%c%c' found at %d\n", + first, next, third, base); +#endif + return(base - (in->cur - in->base)); + } + } + ctxt->checkIndex = base; +#ifdef DEBUG_PUSH + if (next == 0) + xmlGenericError(xmlGenericErrorContext, + "PP: lookup '%c' failed\n", first); + else if (third == 0) + xmlGenericError(xmlGenericErrorContext, + "PP: lookup '%c%c' failed\n", first, next); + else + xmlGenericError(xmlGenericErrorContext, + "PP: lookup '%c%c%c' failed\n", first, next, third); +#endif + return(-1); +} + +/** + * xmlParseGetLasts: + * @param ctxt an XML parser context + * @param lastlt pointer to store the last '<' from the input + * @param lastgt pointer to store the last '>' from the input + * + * Lookup the last < and > in the current chunk + */ +static void +xmlParseGetLasts(xmlParserCtxtPtr ctxt, const xmlChar **lastlt, + const xmlChar **lastgt) { + const xmlChar *tmp; + + if ((ctxt == NULL) || (lastlt == NULL) || (lastgt == NULL)) { + xmlGenericError(xmlGenericErrorContext, + EMBED_ERRTXT("Internal error: xmlParseGetLasts\n")); + return; + } + if ((ctxt->progressive == 1) && (ctxt->inputNr == 1)) { + tmp = ctxt->input->end; + tmp--; + while ((tmp >= ctxt->input->base) && (*tmp != '<') && + (*tmp != '>')) tmp--; + if (tmp < ctxt->input->base) { + *lastlt = NULL; + *lastgt = NULL; + } else if (*tmp == '<') { + *lastlt = tmp; + tmp--; + while ((tmp >= ctxt->input->base) && (*tmp != '>')) tmp--; + if (tmp < ctxt->input->base) + *lastgt = NULL; + else + *lastgt = tmp; + } else { + *lastgt = tmp; + tmp--; + while ((tmp >= ctxt->input->base) && (*tmp != '<')) tmp--; + if (tmp < ctxt->input->base) + *lastlt = NULL; + else + *lastlt = tmp; + } + + } else { + *lastlt = NULL; + *lastgt = NULL; + } +} +/** + * xmlParseTryOrFinish: + * @param ctxt an XML parser context + * @param terminate last chunk indicator + * + * Try to progress on parsing + * + * Returns zero if no parsing was possible + */ +static int +xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) { + int ret = 0; + int avail, tlen; + xmlChar cur, next; + const xmlChar *lastlt, *lastgt; + LOAD_GS_SAFE_CTXT(ctxt) + + if (ctxt->input == NULL) + return(0); + +#ifdef DEBUG_PUSH + switch (ctxt->instate) { + case XML_PARSER_EOF: + xmlGenericError(xmlGenericErrorContext, + "PP: try EOF\n"); break; + case XML_PARSER_START: + xmlGenericError(xmlGenericErrorContext, + "PP: try START\n"); break; + case XML_PARSER_MISC: + xmlGenericError(xmlGenericErrorContext, + "PP: try MISC\n");break; + case XML_PARSER_COMMENT: + xmlGenericError(xmlGenericErrorContext, + "PP: try COMMENT\n");break; + case XML_PARSER_PROLOG: + xmlGenericError(xmlGenericErrorContext, + "PP: try PROLOG\n");break; + case XML_PARSER_START_TAG: + xmlGenericError(xmlGenericErrorContext, + "PP: try START_TAG\n");break; + case XML_PARSER_CONTENT: + xmlGenericError(xmlGenericErrorContext, + "PP: try CONTENT\n");break; + case XML_PARSER_CDATA_SECTION: + xmlGenericError(xmlGenericErrorContext, + "PP: try CDATA_SECTION\n");break; + case XML_PARSER_END_TAG: + xmlGenericError(xmlGenericErrorContext, + "PP: try END_TAG\n");break; + case XML_PARSER_ENTITY_DECL: + xmlGenericError(xmlGenericErrorContext, + "PP: try ENTITY_DECL\n");break; + case XML_PARSER_ENTITY_VALUE: + xmlGenericError(xmlGenericErrorContext, + "PP: try ENTITY_VALUE\n");break; + case XML_PARSER_ATTRIBUTE_VALUE: + xmlGenericError(xmlGenericErrorContext, + "PP: try ATTRIBUTE_VALUE\n");break; + case XML_PARSER_DTD: + xmlGenericError(xmlGenericErrorContext, + "PP: try DTD\n");break; + case XML_PARSER_EPILOG: + xmlGenericError(xmlGenericErrorContext, + "PP: try EPILOG\n");break; + case XML_PARSER_PI: + xmlGenericError(xmlGenericErrorContext, + "PP: try PI\n");break; + case XML_PARSER_IGNORE: + xmlGenericError(xmlGenericErrorContext, + "PP: try IGNORE\n");break; + } +#endif + + if ((ctxt->input != NULL) && (ctxt->input->cur - ctxt->input->base > 4096)) { + xmlSHRINK(ctxt); + ctxt->checkIndex = 0; + } + + xmlParseGetLasts(ctxt, &lastlt, &lastgt); + +while (1) +{ + if ((ctxt->errNo != XML_ERR_OK) && (ctxt->disableSAX == 1)) + return(0); + + /* + * Pop-up of finished entities. + */ + while ((RAW == 0) && (ctxt->inputNr > 1)) + xmlPopInput(ctxt); + + if (ctxt->input == NULL) break; + if (ctxt->input->buf == NULL){ + avail = ctxt->input->length - (ctxt->input->cur - ctxt->input->base); + }else{ + /* + * If we are operating on converted input, try to flush + * remainng chars to avoid them stalling in the non-converted + * buffer. + */ + if ((ctxt->input->buf->raw != NULL) && (ctxt->input->buf->raw->use > 0)) + { + int base = ctxt->input->base - ctxt->input->buf->buffer->content; + int current = ctxt->input->cur - ctxt->input->base; + xmlParserInputBufferPush(ctxt->input->buf, 0, ""); + ctxt->input->base = ctxt->input->buf->buffer->content + base; + ctxt->input->cur = ctxt->input->base + current; + ctxt->input->end = &ctxt->input->buf->buffer->content[ ctxt->input->buf->buffer->use]; + } + + avail = ctxt->input->buf->buffer->use - (ctxt->input->cur - ctxt->input->base); + } + + if (avail < 1) + goto done; + + switch (ctxt->instate) { + + case XML_PARSER_EOF: + /* + * Document parsing is done ! + */ + goto done; + + case XML_PARSER_START: + if (ctxt->charset == XML_CHAR_ENCODING_NONE) { + xmlChar start[4]; + xmlCharEncoding enc; + + /* + * Very first chars read from the document flow. + */ + if (avail < 4) goto done; + /* + * Get the 4 first bytes and decode the charset + * if enc != XML_CHAR_ENCODING_NONE + * plug some encoding conversion routines. + */ + start[0] = RAW; + start[1] = NXT(1); + start[2] = NXT(2); + start[3] = NXT(3); + enc = xmlDetectCharEncoding(start, 4); + if (enc != XML_CHAR_ENCODING_NONE) { + xmlSwitchEncoding(ctxt, enc); + } + break; + } + + if (avail < 2) + goto done; + + cur = ctxt->input->cur[0]; + next = ctxt->input->cur[1]; + + if (cur == 0) { + if ((ctxt->sax) && (ctxt->sax->setDocumentLocator)) + { + ctxt->sax->setDocumentLocator(ctxt->userData, (xmlSAXLocatorPtr)&xmlDefaultSAXLocator); + } + xmlFatalErr(ctxt, XML_ERR_DOCUMENT_EMPTY, NULL); + ctxt->instate = XML_PARSER_EOF; +#ifdef DEBUG_PUSH + xmlGenericError(xmlGenericErrorContext, "PP: entering EOF\n"); +#endif + if ((ctxt->sax) && (ctxt->sax->endDocument != NULL)) + ctxt->sax->endDocument(ctxt->userData); + goto done; + } + + if ((cur == '<') && (next == '?')) { + /* PI or XML decl */ + if (avail < 5) return(ret); + if ((!terminate) && (xmlParseLookupSequence(ctxt, '?', '>', 0) < 0)) + return(ret); + if ((ctxt->sax) && (ctxt->sax->setDocumentLocator)) + { + ctxt->sax->setDocumentLocator(ctxt->userData, (xmlSAXLocatorPtr)&xmlDefaultSAXLocator); + } + if ((ctxt->input->cur[2] == 'x') && + (ctxt->input->cur[3] == 'm') && + (ctxt->input->cur[4] == 'l') && + (IS_BLANK_CH(ctxt->input->cur[5]))) + { + ret += 5; +#ifdef DEBUG_PUSH + xmlGenericError(xmlGenericErrorContext, "PP: Parsing XML Decl\n"); +#endif + xmlParseXMLDecl(ctxt); + if (ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) { + /* + * The XML REC instructs us to stop parsing right + * here + */ + ctxt->instate = XML_PARSER_EOF; + return(0); + } + + ctxt->standalone = ctxt->input->standalone; + + if ((ctxt->encoding == NULL) && (ctxt->input->encoding != NULL)) + ctxt->encoding = xmlStrdup(ctxt->input->encoding); + + if ((ctxt->sax) && (ctxt->sax->startDocument) && (!ctxt->disableSAX)) + ctxt->sax->startDocument(ctxt->userData); + + ctxt->instate = XML_PARSER_MISC; +#ifdef DEBUG_PUSH + xmlGenericError(xmlGenericErrorContext, "PP: entering MISC\n"); +#endif + } + else + { + ctxt->version = xmlCharStrdup(XML_DEFAULT_VERSION); + if ((ctxt->sax) && (ctxt->sax->startDocument) && (!ctxt->disableSAX)) + ctxt->sax->startDocument(ctxt->userData); + + ctxt->instate = XML_PARSER_MISC; +#ifdef DEBUG_PUSH + xmlGenericError(xmlGenericErrorContext, "PP: entering MISC\n"); +#endif + } + } // if ((cur == '<') && (next == '?')) + else + { + if ((ctxt->sax) && (ctxt->sax->setDocumentLocator)) + { + ctxt->sax->setDocumentLocator(ctxt->userData, (xmlSAXLocatorPtr) &xmlDefaultSAXLocator); + } + ctxt->version = xmlCharStrdup(XML_DEFAULT_VERSION); + if(OOM_FLAG) + { + xmlParserOOMErr(ctxt); + return(0); + } + + if ((ctxt->sax) && (ctxt->sax->startDocument) && (!ctxt->disableSAX)) + { + ctxt->sax->startDocument(ctxt->userData); + if(OOM_FLAG) + { + xmlParserOOMErr(ctxt); + return(0); + } + } + ctxt->instate = XML_PARSER_MISC; +#ifdef DEBUG_PUSH + xmlGenericError(xmlGenericErrorContext, "PP: entering MISC\n"); +#endif + } + break; + + case XML_PARSER_START_TAG: { + const xmlChar *name; + const xmlChar *prefix; + const xmlChar *URI; + int nsNr = ctxt->nsNr; + + if ((avail < 2) && (ctxt->inputNr == 1)) + goto done; + + cur = ctxt->input->cur[0]; + if (cur != '<') { + xmlFatalErr(ctxt, XML_ERR_DOCUMENT_EMPTY, NULL); + ctxt->instate = XML_PARSER_EOF; + if ((ctxt->sax) && (ctxt->sax->endDocument != NULL)) + ctxt->sax->endDocument(ctxt->userData); + goto done; + } + + if (!terminate) { + if (ctxt->progressive) { + /* > can be found unescaped in attribute values */ + if ((lastlt == NULL) || (ctxt->input->cur >= lastlt)) + goto done; + } + else if (xmlParseLookupSequence(ctxt, '>', 0, 0) < 0) { + goto done; + } + } + if (ctxt->spaceNr == 0){ + spacePush(ctxt, -1); + }else{ + spacePush(ctxt, *ctxt->space); + } +#ifdef LIBXML_SAX1_ENABLED + if (ctxt->sax2) + { +#endif /* LIBXML_SAX1_ENABLED */ + name = xmlParseStartTag2(ctxt, &prefix, &URI, &tlen); +#ifdef LIBXML_SAX1_ENABLED + } + else + { + name = xmlParseStartTag(ctxt); + } +#endif /* LIBXML_SAX1_ENABLED */ + if(OOM_FLAG) + { + // Note: xmlParseStartTag2 should have set parser into error state already + xmlParserOOMErr(ctxt); // just in case + return(0); + } + + if (name == NULL) { + spacePop(ctxt); + ctxt->instate = XML_PARSER_EOF; + if ((ctxt->sax) && (ctxt->sax->endDocument != NULL)) + ctxt->sax->endDocument(ctxt->userData); + goto done; + } + +#ifdef LIBXML_VALID_ENABLED + /* + * [ VC: Root Element Type ] + * The Name in the document type declaration must match + * the element type of the root element. + */ + if (ctxt->validate && + ctxt->wellFormed && ctxt->myDoc && + ctxt->node && (ctxt->node == ctxt->myDoc->children)) + { + ctxt->valid &= xmlValidateRoot(&ctxt->vctxt, ctxt->myDoc); + } +#endif /* LIBXML_VALID_ENABLED */ + + /* + * Check for an Empty Element. + */ + if ((RAW == '/') && (NXT(1) == '>')) { + SKIP(2); + + if (ctxt->sax2) { + if ((ctxt->sax != NULL) && + (ctxt->sax->endElementNs != NULL) && + (!ctxt->disableSAX)) + { + ctxt->sax->endElementNs(ctxt->userData, name, prefix, URI); + } +#ifdef LIBXML_SAX1_ENABLED + } else { + if ((ctxt->sax != NULL) && + (ctxt->sax->endElement != NULL) && + (!ctxt->disableSAX)) + { + ctxt->sax->endElement(ctxt->userData, name); + } +#endif /* LIBXML_SAX1_ENABLED */ + } + spacePop(ctxt); + if (ctxt->nameNr == 0) { + ctxt->instate = XML_PARSER_EPILOG; + } else { + ctxt->instate = XML_PARSER_CONTENT; + } +// XE: BEGIN NEW CODE + // Remove from namsespaces stack all namespaces + // that were declared in this empty element + nsPop(ctxt, ctxt->lastNsNr*2); +// XE: END NEW CODE + break; + } // if ((RAW == '/') && (NXT(1) == '>')) + + if (RAW == '>') { + NEXT; + } else { + xmlFatalErrMsgStr(ctxt, XML_ERR_GT_REQUIRED, EMBED_ERRTXT("Couldn't find end of Start Tag %s\n"), name); + nodePop(ctxt); + spacePop(ctxt); + } + if (ctxt->sax2){ + nameNsPush(ctxt, name, prefix, URI, ctxt->nsNr - nsNr); +#ifdef LIBXML_SAX1_ENABLED + }else{ + namePush(ctxt, name); +#endif /* LIBXML_SAX1_ENABLED */ + } + + ctxt->instate = XML_PARSER_CONTENT; + break; + } + + case XML_PARSER_CONTENT: { + const xmlChar *test; + unsigned int cons; + if ((avail < 2) && (ctxt->inputNr == 1)) + goto done; + cur = ctxt->input->cur[0]; + next = ctxt->input->cur[1]; + + test = CUR_PTR; + cons = ctxt->input->consumed; + if ((cur == '<') && (next == '/')) { + ctxt->instate = XML_PARSER_END_TAG; + break; + } else if ((cur == '<') && (next == '?')) { + if ((!terminate) && + (xmlParseLookupSequence(ctxt, '?', '>', 0) < 0)) + goto done; + xmlParsePI(ctxt); + } else if ((cur == '<') && (next != '!')) { + ctxt->instate = XML_PARSER_START_TAG; + break; + } else if ((cur == '<') && (next == '!') && + (ctxt->input->cur[2] == '-') && + (ctxt->input->cur[3] == '-')) { + if ((!terminate) && + (xmlParseLookupSequence(ctxt, '-', '-', '>') < 0)) + goto done; + xmlParseComment(ctxt); + ctxt->instate = XML_PARSER_CONTENT; + } else if ((cur == '<') && (ctxt->input->cur[1] == '!') && + (ctxt->input->cur[2] == '[') && + (ctxt->input->cur[3] == 'C') && + (ctxt->input->cur[4] == 'D') && + (ctxt->input->cur[5] == 'A') && + (ctxt->input->cur[6] == 'T') && + (ctxt->input->cur[7] == 'A') && + (ctxt->input->cur[8] == '[')) { + SKIP(9); + ctxt->instate = XML_PARSER_CDATA_SECTION; + break; + } else if ((cur == '<') && (next == '!') && + (avail < 9)) { + goto done; + } else if (cur == '&') { + if ((!terminate) && + (xmlParseLookupSequence(ctxt, ';', 0, 0) < 0)) + goto done; + xmlParseReference(ctxt); + if(OOM_FLAG) + { + return(0); + } + } else { + + /* + * Goal of the following test is: + * - minimize calls to the SAX 'character' callback + * when they are mergeable + * - handle an problem for isBlank when we only parse + * a sequence of blank chars and the next one is + * not available to check against '<' presence. + * - tries to homogenize the differences in SAX + * callbacks between the push and pull versions + * of the parser. + */ + if ((ctxt->inputNr == 1) && + (avail < XML_PARSER_BIG_BUFFER_SIZE)) { + if (!terminate) { + if (ctxt->progressive) { + if ((lastlt == NULL) || + (ctxt->input->cur > lastlt)) + goto done; + } else if (xmlParseLookupSequence(ctxt, + '<', 0, 0) < 0) { + goto done; + } + } + } + ctxt->checkIndex = 0; + xmlParseCharData(ctxt, 0); + } + /* + * Pop-up of finished entities. + */ + while ((RAW == 0) && (ctxt->inputNr > 1)) + xmlPopInput(ctxt); + if ((cons == ctxt->input->consumed) && (test == CUR_PTR)) { + xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR, + EMBED_ERRTXT("detected an error in element content\n")); + ctxt->instate = XML_PARSER_EOF; + break; + } + break; + } +case XML_PARSER_END_TAG: + if (avail < 2) + goto done; + if (!terminate) { + if (ctxt->progressive) { + if ((lastgt == NULL) || (ctxt->input->cur > lastgt)) + goto done; + } else if (xmlParseLookupSequence(ctxt, '>', 0, 0) < 0) { + goto done; + } + } + if (ctxt->sax2) { + xmlParseEndTag2(ctxt, + (xmlChar*) ctxt->pushTab[ctxt->nameNr * 3 - 3], + (xmlChar*) ctxt->pushTab[ctxt->nameNr * 3 - 2], 0, + (int) (long) ctxt->pushTab[ctxt->nameNr * 3 - 1], 0); + nameNsPop(ctxt); + } +#ifdef LIBXML_SAX1_ENABLED + else + xmlParseEndTag1(ctxt, 0); +#endif /* LIBXML_SAX1_ENABLED */ + if (ctxt->nameNr == 0) { + ctxt->instate = XML_PARSER_EPILOG; + } else { + ctxt->instate = XML_PARSER_CONTENT; + } + break; + case XML_PARSER_CDATA_SECTION: { + /* + * The Push mode need to have the SAX callback for + * cdataBlock merge back contiguous callbacks. + */ + int base; + + base = xmlParseLookupSequence(ctxt, ']', ']', '>'); + if (base < 0) { + if (avail >= XML_PARSER_BIG_BUFFER_SIZE + 2) { + int tmp; + + tmp = xmlCheckCdataPush(ctxt->input->cur, + XML_PARSER_BIG_BUFFER_SIZE); + if (tmp < 0) { + tmp = -tmp; + ctxt->input->cur += tmp; + goto encoding_error; + } + if ((ctxt->sax != NULL) && (!ctxt->disableSAX)) { + if (ctxt->sax->cdataBlock != NULL) + ctxt->sax->cdataBlock(ctxt->userData, + ctxt->input->cur, tmp); + else if (ctxt->sax->characters != NULL) + ctxt->sax->characters(ctxt->userData, + ctxt->input->cur, tmp); + } + SKIPL(tmp); + ctxt->checkIndex = 0; + } + goto done; + } else { + int tmp; + + tmp = xmlCheckCdataPush(ctxt->input->cur, base); + if ((tmp < 0) || (tmp != base)) { + tmp = -tmp; + ctxt->input->cur += tmp; + goto encoding_error; + } + if ((ctxt->sax != NULL) && (base > 0) && + (!ctxt->disableSAX)) { + if (ctxt->sax->cdataBlock != NULL) + ctxt->sax->cdataBlock(ctxt->userData, + ctxt->input->cur, base); + else if (ctxt->sax->characters != NULL) + ctxt->sax->characters(ctxt->userData, + ctxt->input->cur, base); + } + SKIPL(base + 3); + ctxt->checkIndex = 0; + ctxt->instate = XML_PARSER_CONTENT; +#ifdef DEBUG_PUSH + xmlGenericError(xmlGenericErrorContext, + "PP: entering CONTENT\n"); +#endif + } + break; + } + case XML_PARSER_MISC: + SKIP_BLANKS; + if (ctxt->input->buf == NULL) + avail = ctxt->input->length - + (ctxt->input->cur - ctxt->input->base); + else + avail = ctxt->input->buf->buffer->use - + (ctxt->input->cur - ctxt->input->base); + if (avail < 2) + goto done; + cur = ctxt->input->cur[0]; + next = ctxt->input->cur[1]; + if ((cur == '<') && (next == '?')) { + if ((!terminate) && + (xmlParseLookupSequence(ctxt, '?', '>', 0) < 0)) + goto done; +#ifdef DEBUG_PUSH + xmlGenericError(xmlGenericErrorContext, + "PP: Parsing PI\n"); +#endif + xmlParsePI(ctxt); + } else if ((cur == '<') && (next == '!') && + (ctxt->input->cur[2] == '-') && + (ctxt->input->cur[3] == '-')) { + if ((!terminate) && + (xmlParseLookupSequence(ctxt, '-', '-', '>') < 0)) + goto done; +#ifdef DEBUG_PUSH + xmlGenericError(xmlGenericErrorContext, + "PP: Parsing Comment\n"); +#endif + xmlParseComment(ctxt); + ctxt->instate = XML_PARSER_MISC; + } else if ((cur == '<') && (next == '!') && + (ctxt->input->cur[2] == 'D') && + (ctxt->input->cur[3] == 'O') && + (ctxt->input->cur[4] == 'C') && + (ctxt->input->cur[5] == 'T') && + (ctxt->input->cur[6] == 'Y') && + (ctxt->input->cur[7] == 'P') && + (ctxt->input->cur[8] == 'E')) { + if ((!terminate) && + (xmlParseLookupSequence(ctxt, '>', 0, 0) < 0)) + goto done; +#ifdef DEBUG_PUSH + xmlGenericError(xmlGenericErrorContext, + "PP: Parsing internal subset\n"); +#endif + ctxt->inSubset = 1; + xmlParseDocTypeDecl(ctxt); + if (RAW == '[') { + ctxt->instate = XML_PARSER_DTD; +#ifdef DEBUG_PUSH + xmlGenericError(xmlGenericErrorContext, + "PP: entering DTD\n"); +#endif + } else { + /* + * Create and update the external subset. + */ + ctxt->inSubset = 2; + if ((ctxt->sax != NULL) && (!ctxt->disableSAX) && + (ctxt->sax->externalSubset != NULL)) + { + ctxt->sax->externalSubset(ctxt->userData, + ctxt->intSubName, ctxt->extSubSystem, + ctxt->extSubURI); + } + ctxt->inSubset = 0; + ctxt->instate = XML_PARSER_PROLOG; +#ifdef DEBUG_PUSH + xmlGenericError(xmlGenericErrorContext, "PP: entering PROLOG\n"); +#endif + } + } else if ((cur == '<') && (next == '!') && (avail < 9)) { + goto done; + } else { + ctxt->instate = XML_PARSER_START_TAG; + ctxt->progressive = 1; + xmlParseGetLasts(ctxt, &lastlt, &lastgt); +#ifdef DEBUG_PUSH + xmlGenericError(xmlGenericErrorContext, + "PP: entering START_TAG\n"); +#endif + } + break; + case XML_PARSER_PROLOG: + SKIP_BLANKS; + if (ctxt->input->buf == NULL) + avail = ctxt->input->length - (ctxt->input->cur - ctxt->input->base); + else + avail = ctxt->input->buf->buffer->use - (ctxt->input->cur - ctxt->input->base); + if (avail < 2) + goto done; + cur = ctxt->input->cur[0]; + next = ctxt->input->cur[1]; + if ((cur == '<') && (next == '?')) { + if ((!terminate) && + (xmlParseLookupSequence(ctxt, '?', '>', 0) < 0)) + goto done; +#ifdef DEBUG_PUSH + xmlGenericError(xmlGenericErrorContext, + "PP: Parsing PI\n"); +#endif + xmlParsePI(ctxt); + } else if ((cur == '<') && (next == '!') && + (ctxt->input->cur[2] == '-') && (ctxt->input->cur[3] == '-')) { + if ((!terminate) && + (xmlParseLookupSequence(ctxt, '-', '-', '>') < 0)) + goto done; +#ifdef DEBUG_PUSH + xmlGenericError(xmlGenericErrorContext, + "PP: Parsing Comment\n"); +#endif + xmlParseComment(ctxt); + ctxt->instate = XML_PARSER_PROLOG; + } else if ((cur == '<') && (next == '!') && + (avail < 4)) { + goto done; + } else { + ctxt->instate = XML_PARSER_START_TAG; + if (ctxt->progressive == 0) + ctxt->progressive = 1; + xmlParseGetLasts(ctxt, &lastlt, &lastgt); +#ifdef DEBUG_PUSH + xmlGenericError(xmlGenericErrorContext, + "PP: entering START_TAG\n"); +#endif + } + break; + case XML_PARSER_EPILOG: + SKIP_BLANKS; + if (ctxt->input->buf == NULL) + avail = ctxt->input->length - (ctxt->input->cur - ctxt->input->base); + else + avail = ctxt->input->buf->buffer->use - (ctxt->input->cur - ctxt->input->base); + if (avail < 2) + goto done; + cur = ctxt->input->cur[0]; + next = ctxt->input->cur[1]; + if ((cur == '<') && (next == '?')) { + if ((!terminate) && + (xmlParseLookupSequence(ctxt, '?', '>', 0) < 0)) + goto done; +#ifdef DEBUG_PUSH + xmlGenericError(xmlGenericErrorContext, + "PP: Parsing PI\n"); +#endif + xmlParsePI(ctxt); + ctxt->instate = XML_PARSER_EPILOG; + } else if ((cur == '<') && (next == '!') && + (ctxt->input->cur[2] == '-') && (ctxt->input->cur[3] == '-')) { + if ((!terminate) && + (xmlParseLookupSequence(ctxt, '-', '-', '>') < 0)) + goto done; +#ifdef DEBUG_PUSH + xmlGenericError(xmlGenericErrorContext, + "PP: Parsing Comment\n"); +#endif + xmlParseComment(ctxt); + ctxt->instate = XML_PARSER_EPILOG; + } else if ((cur == '<') && (next == '!') && + (avail < 4)) { + goto done; + } else { + xmlFatalErr(ctxt, XML_ERR_DOCUMENT_END, NULL); + ctxt->instate = XML_PARSER_EOF; +#ifdef DEBUG_PUSH + xmlGenericError(xmlGenericErrorContext, + "PP: entering EOF\n"); +#endif + if ((ctxt->sax) && (ctxt->sax->endDocument != NULL)) + ctxt->sax->endDocument(ctxt->userData); + goto done; + } + break; + case XML_PARSER_DTD: { + /* + * Sorry but progressive parsing of the internal subset + * is not expected to be supported. We first check that + * the full content of the internal subset is available and + * the parsing is launched only at that point. + * Internal subset ends up with "']' S? '>'" in an unescaped + * section and not in a ']]>' sequence which are conditional + * sections (whoever argued to keep that crap in XML deserve + * a place in hell !). + */ + int base, i; + xmlChar *buf; + xmlChar quote = 0; + + base = ctxt->input->cur - ctxt->input->base; + if (base < 0) return(0); + if (ctxt->checkIndex > base) + base = ctxt->checkIndex; + buf = ctxt->input->buf->buffer->content; + for (;(unsigned int) base < ctxt->input->buf->buffer->use; + base++) { + if (quote != 0) { + if (buf[base] == quote) + quote = 0; + continue; + } + if ((quote == 0) && (buf[base] == '<')) { + int found = 0; + /* special handling of comments */ + if (((unsigned int) base + 4 < + ctxt->input->buf->buffer->use) && + (buf[base + 1] == '!') && + (buf[base + 2] == '-') && + (buf[base + 3] == '-')) { + for (;(unsigned int) base + 3 < + ctxt->input->buf->buffer->use; base++) { + if ((buf[base] == '-') && + (buf[base + 1] == '-') && + (buf[base + 2] == '>')) { + found = 1; + base += 2; + break; + } + } + if (!found) { + break; /* for */ + } + continue; + } + } + if (buf[base] == '"') { + quote = '"'; + continue; + } + if (buf[base] == '\'') { + quote = '\''; + continue; + } + if (buf[base] == ']') { + if ((unsigned int) base +1 >= + ctxt->input->buf->buffer->use) + break; + if (buf[base + 1] == ']') { + /* conditional crap, skip both ']' ! */ + base++; + continue; + } + for (i = 0; + (unsigned int) base + i < ctxt->input->buf->buffer->use; + i++) { + if (buf[base + i] == '>') + goto found_end_int_subset; + } + break; + } + } + /* + * We didn't found the end of the Internal subset + */ + if (quote == 0) + ctxt->checkIndex = base; +#ifdef DEBUG_PUSH + if (next == 0) + xmlGenericError(xmlGenericErrorContext, + "PP: lookup of int subset end filed\n"); +#endif + goto done; + +found_end_int_subset: + xmlParseInternalSubset(ctxt); + if(OOM_FLAG) + { + return 0; + } + ctxt->inSubset = 2; + if ((ctxt->sax != NULL) && (!ctxt->disableSAX) && + (ctxt->sax->externalSubset != NULL)) + ctxt->sax->externalSubset(ctxt->userData, ctxt->intSubName, + ctxt->extSubSystem, ctxt->extSubURI); + ctxt->inSubset = 0; + ctxt->instate = XML_PARSER_PROLOG; + ctxt->checkIndex = 0; +#ifdef DEBUG_PUSH + xmlGenericError(xmlGenericErrorContext, + "PP: entering PROLOG\n"); +#endif + break; + } + case XML_PARSER_COMMENT: + xmlGenericError(xmlGenericErrorContext, + EMBED_ERRTXT("PP: internal error, state == COMMENT\n")); + ctxt->instate = XML_PARSER_CONTENT; +#ifdef DEBUG_PUSH + xmlGenericError(xmlGenericErrorContext, + "PP: entering CONTENT\n"); +#endif + break; + case XML_PARSER_IGNORE: + xmlGenericError(xmlGenericErrorContext, + EMBED_ERRTXT("PP: internal error, state == IGNORE")); + ctxt->instate = XML_PARSER_DTD; +#ifdef DEBUG_PUSH + xmlGenericError(xmlGenericErrorContext, + "PP: entering DTD\n"); +#endif + break; + case XML_PARSER_PI: + xmlGenericError(xmlGenericErrorContext, + EMBED_ERRTXT("PP: internal error, state == PI\n")); + ctxt->instate = XML_PARSER_CONTENT; +#ifdef DEBUG_PUSH + xmlGenericError(xmlGenericErrorContext, + "PP: entering CONTENT\n"); +#endif + break; + case XML_PARSER_ENTITY_DECL: + xmlGenericError(xmlGenericErrorContext, + EMBED_ERRTXT("PP: internal error, state == ENTITY_DECL\n")); + ctxt->instate = XML_PARSER_DTD; +#ifdef DEBUG_PUSH + xmlGenericError(xmlGenericErrorContext, + "PP: entering DTD\n"); +#endif + break; + case XML_PARSER_ENTITY_VALUE: + xmlGenericError(xmlGenericErrorContext, + EMBED_ERRTXT("PP: internal error, state == ENTITY_VALUE\n")); + ctxt->instate = XML_PARSER_CONTENT; +#ifdef DEBUG_PUSH + xmlGenericError(xmlGenericErrorContext, + "PP: entering DTD\n"); +#endif + break; + case XML_PARSER_ATTRIBUTE_VALUE: + xmlGenericError(xmlGenericErrorContext, + EMBED_ERRTXT("PP: internal error, state == ATTRIBUTE_VALUE\n")); + ctxt->instate = XML_PARSER_START_TAG; +#ifdef DEBUG_PUSH + xmlGenericError(xmlGenericErrorContext, + "PP: entering START_TAG\n"); +#endif + break; + case XML_PARSER_SYSTEM_LITERAL: + xmlGenericError(xmlGenericErrorContext, + EMBED_ERRTXT("PP: internal error, state == SYSTEM_LITERAL\n")); + ctxt->instate = XML_PARSER_START_TAG; +#ifdef DEBUG_PUSH + xmlGenericError(xmlGenericErrorContext, + "PP: entering START_TAG\n"); +#endif + break; + case XML_PARSER_PUBLIC_LITERAL: + xmlGenericError(xmlGenericErrorContext, + EMBED_ERRTXT("PP: internal error, state == PUBLIC_LITERAL\n")); + ctxt->instate = XML_PARSER_START_TAG; +#ifdef DEBUG_PUSH + xmlGenericError(xmlGenericErrorContext, + "PP: entering START_TAG\n"); +#endif + break; + } + } +done: +#ifdef DEBUG_PUSH + xmlGenericError(xmlGenericErrorContext, "PP: done %d\n", ret); +#endif + return(ret); +encoding_error: + { + char buffer[150]; + snprintf(buffer, 149, "Bytes: 0x%02X 0x%02X 0x%02X 0x%02X\n", + ctxt->input->cur[0], ctxt->input->cur[1], + ctxt->input->cur[2], ctxt->input->cur[3]); + __xmlErrEncoding(ctxt, XML_ERR_INVALID_CHAR, + "Input is not proper UTF-8, indicate encoding !\n%s", + BAD_CAST buffer, NULL); + } + return(0); +} + +/** + * xmlParseChunk: + * @param ctxt an XML parser context + * @param chunk an char array + * @param size the size in byte of the chunk + * @param terminate last chunk indicator + * + * Parse a Chunk of memory + * + * Returns zero if no error, the xmlParserErrors otherwise. + */ +XMLPUBFUNEXPORT int +xmlParseChunk(xmlParserCtxtPtr ctxt, const char* chunk, int size, int terminate) +{ + LOAD_GS_SAFE_CTXT(ctxt) + if ((ctxt->errNo != XML_ERR_OK) && (ctxt->disableSAX == 1)) + return(ctxt->errNo); + + if (ctxt->instate == XML_PARSER_START) + { + xmlDetectSAX2(ctxt); + if( OOM_FLAG ) + { + xmlParserOOMErr(ctxt); + return(XML_ERR_NO_MEMORY); + } + } + + if (size > 0 && + chunk && + ctxt->input && + ctxt->input->buf && + ctxt->instate != XML_PARSER_EOF) + { + int base = ctxt->input->base - ctxt->input->buf->buffer->content; + int cur = ctxt->input->cur - ctxt->input->base; + + xmlParserInputBufferPush(ctxt->input->buf, size, chunk); + ctxt->input->base = ctxt->input->buf->buffer->content + base; + ctxt->input->cur = ctxt->input->base + cur; + ctxt->input->end = &ctxt->input->buf->buffer->content[ctxt->input->buf->buffer->use]; +#ifdef DEBUG_PUSH + xmlGenericError(xmlGenericErrorContext, "PP: pushed %d\n", size); +#endif + } + else if (ctxt->instate != XML_PARSER_EOF) + { + if (ctxt->input && ctxt->input->buf) + { + xmlParserInputBufferPtr in = ctxt->input->buf; + if (in->encoder && + in->buffer && + in->raw) + { + int nbchars; + + nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw); + if (nbchars < 0) + { + + xmlGenericError(xmlGenericErrorContext, + EMBED_ERRTXT("xmlParseChunk: encoder error\n")); + return(XML_ERR_INVALID_ENCODING); + } + } + } + } + //----------------------------------- + xmlParseTryOrFinish(ctxt, terminate); + //----------------------------------- + if( OOM_FLAG ) + { + xmlParserOOMErr(ctxt); // set error state and disable parser + } + if (ctxt->errNo != XML_ERR_OK && + ctxt->disableSAX == 1) + { + return(ctxt->errNo); + } + if (terminate) + { + /* + * Check for termination + */ + xmlParserInputPtr input = ctxt->input; + int avail = (input->buf + ? input->buf->buffer->use + : input->length ) + - (input->cur - input->base); + + if ( ((ctxt->instate != XML_PARSER_EOF) && + (ctxt->instate != XML_PARSER_EPILOG)) + || + ((ctxt->instate == XML_PARSER_EPILOG) && + (avail > 0)) + ) + { + xmlFatalErr(ctxt, XML_ERR_DOCUMENT_END, NULL); + } + if (ctxt->instate != XML_PARSER_EOF) + { + if (ctxt->sax && ctxt->sax->endDocument) + ctxt->sax->endDocument(ctxt->userData); + } + ctxt->instate = XML_PARSER_EOF; + } + return ((xmlParserErrors) ctxt->errNo); +} + +/************************************************************************ + * * + * I/O front end functions to the parser * + * * + ************************************************************************/ + +/** + * xmlStopParser: + * @param ctxt an XML parser context + * + * Blocks further parser processing + */ +XMLPUBFUNEXPORT void +xmlStopParser(xmlParserCtxtPtr ctxt) { + if (ctxt == NULL) + return; + ctxt->instate = XML_PARSER_EOF; + ctxt->disableSAX = 1; + if (ctxt->input != NULL) + ctxt->input->cur = BAD_CAST""; +} + +/** + * xmlCreatePushParserCtxt: + * @param sax a SAX handler + * @param user_data The user data returned on SAX callbacks + * @param chunk a pointer to an array of chars + * @param size number of chars in the array + * @param filename an optional file name or URI + * + * Create a parser context for using the XML parser in push mode. + * If buffer and size are non-NULL, the data is used to detect + * the encoding. The remaining characters will be parsed so they + * don't need to be fed in again through xmlParseChunk. + * To allow content encoding detection, size should be >= 4 + * The value of filename is used for fetching external entities + * and error/warning reports. + * + * Returns the new parser context or NULL + * + * OOM: possible --> returns NULL + */ + +XMLPUBFUNEXPORT xmlParserCtxtPtr +xmlCreatePushParserCtxt(xmlSAXHandlerPtr sax, void* user_data, + const char* chunk, int size, const char* filename) +{ + LOAD_GS_DIRECT + xmlParserCtxtPtr ctxt; + xmlParserInputPtr inputStream; + xmlParserInputBufferPtr buf; + xmlCharEncoding enc = XML_CHAR_ENCODING_NONE; + + /* + * plug some encoding conversion routines + */ + if (chunk && (size >= 4)) + enc = xmlDetectCharEncoding((const xmlChar*) chunk, size); + + buf = xmlAllocParserInputBuffer(enc); // OOM possible + if (!buf) + goto OOM; + + ctxt = xmlNewParserCtxt(); + if (!ctxt) { + goto OOM_buf; + } + ctxt->pushTab = (void**) xmlMalloc(ctxt->nameMax * 3 * sizeof(xmlChar*)); + + if (!ctxt->pushTab) { + goto OOM_ctxt_buf; + } + + if (sax) { +#ifdef LIBXML_SAX1_ENABLED + if (ctxt->sax != (xmlSAXHandlerPtr) &xmlDefaultSAXHandler) +#endif /* LIBXML_SAX1_ENABLED */ + { + xmlFree(ctxt->sax); + } + ctxt->sax = (xmlSAXHandlerPtr) xmlMalloc(sizeof(xmlSAXHandler)); + if (!ctxt->sax) { + goto OOM_ctxt_buf; + } + memcpy(ctxt->sax, sax, sizeof(xmlSAXHandler)); + if (user_data) + ctxt->userData = user_data; + } + // DONE: just call xmlParserGetDirectory it returns NULL for NULL argument + ctxt->directory = filename + ? xmlParserGetDirectory(filename) + : NULL; + + inputStream = xmlNewInputStream(ctxt); + if (!inputStream) { + goto OOM_ctxt_buf; + } + + inputStream->filename = filename + ? (char *) xmlCanonicPath((const xmlChar*) filename) + : NULL; + + inputStream->buf = buf; + inputStream->base = inputStream->buf->buffer->content; + inputStream->cur = inputStream->buf->buffer->content; + inputStream->end = &inputStream->buf->buffer->content[inputStream->buf->buffer->use]; + + if (inputPush(ctxt, inputStream) < 0) + { + goto OOM_istream_ctxt_buf; + } + + if (size > 0 && + chunk && + ctxt->input && + ctxt->input->buf) + { + int base = ctxt->input->base - ctxt->input->buf->buffer->content; + int cur = ctxt->input->cur - ctxt->input->base; + + xmlParserInputBufferPush(ctxt->input->buf, size, chunk); + + ctxt->input->base = ctxt->input->buf->buffer->content + base; + ctxt->input->cur = ctxt->input->base + cur; + ctxt->input->end = &ctxt->input->buf->buffer->content[ctxt->input->buf->buffer->use]; +#ifdef DEBUG_PUSH + xmlGenericError(xmlGenericErrorContext, "PP: pushed %d\n", size); +#endif + } + + if (enc != XML_CHAR_ENCODING_NONE) { + xmlSwitchEncoding(ctxt, enc); + } + + return(ctxt); +//------------------------------ +OOM_istream_ctxt_buf: + inputStream->buf = NULL; // NOTE: 'buf' is already part of inputStream -- do not free it twice!!! + xmlFreeInputStream(inputStream); +OOM_ctxt_buf: + xmlFreeParserCtxt(ctxt); +OOM_buf: + xmlFreeParserInputBuffer(buf); +OOM: + xmlParserOOMErr(NULL); + return(NULL); +} +#endif /* LIBXML_PUSH_ENABLED */ + + +#ifndef XMLENGINE_EXCLUDE_UNUSED +/** + * xmlCreateIOParserCtxt: + * @param sax a SAX handler + * @param user_data The user data returned on SAX callbacks + * @param ioread an I/O read function + * @param ioclose an I/O close function + * @param ioctx an I/O handler + * @param enc the charset encoding if known + * + * Create a parser context for using the XML parser with an existing + * I/O stream + * + * Returns the new parser context or NULL + */ +xmlParserCtxtPtr +xmlCreateIOParserCtxt(xmlSAXHandlerPtr sax, void *user_data, + xmlInputReadCallback ioread, xmlInputCloseCallback ioclose, + void *ioctx, xmlCharEncoding enc) +{ + xmlParserCtxtPtr ctxt; + xmlParserInputPtr inputStream; + xmlParserInputBufferPtr buf; + + buf = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx, enc); + if (buf == NULL) return(NULL); + + ctxt = xmlNewParserCtxt(); + if (ctxt == NULL) { + xmlFree(buf); + return(NULL); + } + if (sax != NULL) { +#ifdef LIBXML_SAX1_ENABLED + if (ctxt->sax != (xmlSAXHandlerPtr) &xmlDefaultSAXHandler) +#endif /* LIBXML_SAX1_ENABLED */ + xmlFree(ctxt->sax); + ctxt->sax = (xmlSAXHandlerPtr) xmlMalloc(sizeof(xmlSAXHandler)); + if (ctxt->sax == NULL) { + xmlParserOOMErr(ctxt); + xmlFree(ctxt); + return(NULL); + } + memcpy(ctxt->sax, sax, sizeof(xmlSAXHandler)); + if (user_data != NULL) + ctxt->userData = user_data; + } + + inputStream = xmlNewIOInputStream(ctxt, buf, enc); + if (inputStream == NULL) { + xmlFreeParserCtxt(ctxt); + return(NULL); + } + inputPush(ctxt, inputStream); + + return(ctxt); +} +#endif /* ifndef XMLENGINE_EXCLUDE_UNUSED */ + + +#ifdef LIBXML_VALID_ENABLED +/************************************************************************ + * * + * Front ends when parsing a DTD * + * * + ************************************************************************/ + +/** + * xmlIOParseDTD: + * @param sax the SAX handler block or NULL + * @param input an Input Buffer + * @param enc the charset encoding if known + * + * Load and parse a DTD + * + * Returns the resulting xmlDtdPtr or NULL in case of error. + * input will be freed at parsing end. + */ + +xmlDtdPtr +xmlIOParseDTD(xmlSAXHandlerPtr sax, xmlParserInputBufferPtr input, + xmlCharEncoding enc) +{ + xmlDtdPtr ret = NULL; + xmlParserCtxtPtr ctxt; + xmlParserInputPtr pinput = NULL; + xmlChar start[4]; + + if (input == NULL) + return(NULL); + + ctxt = xmlNewParserCtxt(); + if (ctxt == NULL) { + return(NULL); + } + + /* + * Set-up the SAX context + */ + if (sax != NULL) { + if (ctxt->sax != NULL) + xmlFree(ctxt->sax); + ctxt->sax = sax; + ctxt->userData = ctxt; + } + xmlDetectSAX2(ctxt); + + /* + * generate a parser input from the I/O handler + */ + + pinput = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE); + if (pinput == NULL) { + if (sax != NULL) ctxt->sax = NULL; + xmlFreeParserCtxt(ctxt); + return(NULL); + } + + /* + * plug some encoding conversion routines here. + */ + xmlPushInput(ctxt, pinput); + if (enc != XML_CHAR_ENCODING_NONE) { + xmlSwitchEncoding(ctxt, enc); + } + + pinput->filename = NULL; + pinput->line = 1; + pinput->col = 1; + pinput->base = ctxt->input->cur; + pinput->cur = ctxt->input->cur; + pinput->free = NULL; + + /* + * let's parse that entity knowing it's an external subset. + */ + ctxt->inSubset = 2; + ctxt->myDoc = xmlNewDoc(BAD_CAST "1.0"); + ctxt->myDoc->extSubset = xmlNewDtd(ctxt->myDoc, BAD_CAST "none", + BAD_CAST "none", BAD_CAST "none"); + + if ((enc == XML_CHAR_ENCODING_NONE) && + ((ctxt->input->end - ctxt->input->cur) >= 4)) { + /* + * Get the 4 first bytes and decode the charset + * if enc != XML_CHAR_ENCODING_NONE + * plug some encoding conversion routines. + */ + start[0] = RAW; + start[1] = NXT(1); + start[2] = NXT(2); + start[3] = NXT(3); + enc = xmlDetectCharEncoding(start, 4); + if (enc != XML_CHAR_ENCODING_NONE) { + xmlSwitchEncoding(ctxt, enc); + } + } + + xmlParseExternalSubset(ctxt, BAD_CAST "none", BAD_CAST "none"); + + if (ctxt->myDoc != NULL) { + if (ctxt->wellFormed) { + ret = ctxt->myDoc->extSubset; + ctxt->myDoc->extSubset = NULL; + if (ret != NULL) { + xmlNodePtr tmp; + + ret->doc = NULL; + tmp = ret->children; + while (tmp != NULL) { + tmp->doc = NULL; + tmp = tmp->next; + } + } + } else { + ret = NULL; + } + xmlFreeDoc(ctxt->myDoc); + ctxt->myDoc = NULL; + } + if (sax != NULL) ctxt->sax = NULL; + xmlFreeParserCtxt(ctxt); + + return(ret); +} + +/** + * xmlSAXParseDTD: + * @param sax the SAX handler block + * @param ExternalID a NAME* containing the External ID of the DTD + * @param SystemID a NAME* containing the URL to the DTD + * + * Load and parse an external subset. + * + * Returns the resulting xmlDtdPtr or NULL in case of error. + */ + +xmlDtdPtr +xmlSAXParseDTD(xmlSAXHandlerPtr sax, const xmlChar *ExternalID, + const xmlChar *SystemID) { + xmlDtdPtr ret = NULL; + xmlParserCtxtPtr ctxt; + xmlParserInputPtr input = NULL; + xmlCharEncoding enc; + + if ((ExternalID == NULL) && (SystemID == NULL)) return(NULL); + + ctxt = xmlNewParserCtxt(); + if (ctxt == NULL) { + return(NULL); + } + + /* + * Set-up the SAX context + */ + if (sax != NULL) { + if (ctxt->sax != NULL) + xmlFree(ctxt->sax); + ctxt->sax = sax; + ctxt->userData = ctxt; + } + + /* + * Ask the Entity resolver to load the damn thing + */ + + if ((ctxt->sax != NULL) && (ctxt->sax->resolveEntity != NULL)) + input = ctxt->sax->resolveEntity(ctxt, ExternalID, SystemID); + if (input == NULL) { + if (sax != NULL) ctxt->sax = NULL; + xmlFreeParserCtxt(ctxt); + return(NULL); + } + + /* + * plug some encoding conversion routines here. + */ + xmlPushInput(ctxt, input); + if ((ctxt->input->end - ctxt->input->cur) >= 4) { + enc = xmlDetectCharEncoding(ctxt->input->cur, 4); + xmlSwitchEncoding(ctxt, enc); + } + + if (input->filename == NULL) + input->filename = (char *) xmlCanonicPath(SystemID); + input->line = 1; + input->col = 1; + input->base = ctxt->input->cur; + input->cur = ctxt->input->cur; + input->free = NULL; + + /* + * let's parse that entity knowing it's an external subset. + */ + ctxt->inSubset = 2; + ctxt->myDoc = xmlNewDoc(BAD_CAST "1.0"); + ctxt->myDoc->extSubset = xmlNewDtd(ctxt->myDoc, BAD_CAST "none", + ExternalID, SystemID); + xmlParseExternalSubset(ctxt, ExternalID, SystemID); + + if (ctxt->myDoc != NULL) { + if (ctxt->wellFormed) { + ret = ctxt->myDoc->extSubset; + ctxt->myDoc->extSubset = NULL; + if (ret != NULL) { + xmlNodePtr tmp; + + ret->doc = NULL; + tmp = ret->children; + while (tmp != NULL) { + tmp->doc = NULL; + tmp = tmp->next; + } + } + } else { + ret = NULL; + } + xmlFreeDoc(ctxt->myDoc); + ctxt->myDoc = NULL; + } + if (sax != NULL) ctxt->sax = NULL; + xmlFreeParserCtxt(ctxt); + + return(ret); +} + + +/** + * xmlParseDTD: + * @param ExternalID a NAME* containing the External ID of the DTD + * @param SystemID a NAME* containing the URL to the DTD + * + * Load and parse an external subset. + * + * Returns the resulting xmlDtdPtr or NULL in case of error. + */ + +xmlDtdPtr +xmlParseDTD(const xmlChar *ExternalID, const xmlChar *SystemID) { + return(xmlSAXParseDTD(NULL, ExternalID, SystemID)); +} +#endif /* LIBXML_VALID_ENABLED */ + +/************************************************************************ + * * + * Front ends when parsing an Entity * + * * + ************************************************************************/ + +/** + * xmlParseCtxtExternalEntity: + * @param ctx the existing parsing context + * @param URL the URL for the entity to load + * @param ID the System ID for the entity to load + * @param lst the return value for the set of parsed nodes + * + * Parse an external general entity within an existing parsing context + * An external general parsed entity is well-formed if it matches the + * production labeled extParsedEnt. + * + * [78] extParsedEnt ::= TextDecl? content + * + * Returns 0 if the entity is well formed, -1 in case of args problem and + * the parser error code otherwise + */ + +XMLPUBFUNEXPORT int +xmlParseCtxtExternalEntity(xmlParserCtxtPtr ctx, const xmlChar *URL, + const xmlChar *ID, xmlNodePtr *lst) { + xmlParserCtxtPtr ctxt; + xmlDocPtr newDoc; + xmlSAXHandlerPtr oldsax = NULL; + int ret = 0; + xmlChar start[4]; + xmlCharEncoding enc; + + if (ctx->depth > 40) { + return(XML_ERR_ENTITY_LOOP); + } + + if (lst != NULL) + *lst = NULL; + if ((URL == NULL) && (ID == NULL)) + return(-1); + if (ctx->myDoc == NULL) /* @@ relax but check for dereferences */ + return(-1); + + + ctxt = xmlCreateEntityParserCtxt(URL, ID, NULL); + if (ctxt == NULL) return(-1); + ctxt->userData = ctxt; + ctxt->_private = ctx->_private; + oldsax = ctxt->sax; + ctxt->sax = ctx->sax; + xmlDetectSAX2(ctxt); + newDoc = xmlNewDoc(BAD_CAST "1.0"); + if (newDoc == NULL) { + xmlFreeParserCtxt(ctxt); + return(-1); + } + if (ctx->myDoc != NULL) { + newDoc->intSubset = ctx->myDoc->intSubset; + newDoc->extSubset = ctx->myDoc->extSubset; + } + if (ctx->myDoc->URL != NULL) { + newDoc->URL = xmlStrdup(ctx->myDoc->URL); + } + newDoc->children = xmlNewDocNode(newDoc, NULL, BAD_CAST "pseudoroot", NULL); + if (newDoc->children == NULL) { + ctxt->sax = oldsax; + xmlFreeParserCtxt(ctxt); + newDoc->intSubset = NULL; + newDoc->extSubset = NULL; + xmlFreeDoc(newDoc); + return(-1); + } + nodePush(ctxt, newDoc->children); + if (ctx->myDoc == NULL) { + ctxt->myDoc = newDoc; + } else { + ctxt->myDoc = ctx->myDoc; + newDoc->children->doc = ctx->myDoc; + } + + /* + * Get the 4 first bytes and decode the charset + * if enc != XML_CHAR_ENCODING_NONE + * plug some encoding conversion routines. + */ + GROW + if ((ctxt->input->end - ctxt->input->cur) >= 4) { + start[0] = RAW; + start[1] = NXT(1); + start[2] = NXT(2); + start[3] = NXT(3); + enc = xmlDetectCharEncoding(start, 4); + if (enc != XML_CHAR_ENCODING_NONE) { + xmlSwitchEncoding(ctxt, enc); + } + } + + /* + * Parse a possible text declaration first + */ + if ((CMP5(CUR_PTR, '<', '?', 'x', 'm', 'l')) && (IS_BLANK_CH(NXT(5)))) { + xmlParseTextDecl(ctxt); + } + + /* + * Doing validity checking on chunk doesn't make sense + */ + ctxt->instate = XML_PARSER_CONTENT; + ctxt->validate = ctx->validate; + ctxt->valid = ctx->valid; + ctxt->loadsubset = ctx->loadsubset; + ctxt->depth = ctx->depth + 1; + ctxt->replaceEntities = ctx->replaceEntities; + if (ctxt->validate) { + ctxt->vctxt.error = ctx->vctxt.error; + ctxt->vctxt.warning = ctx->vctxt.warning; + } else { + ctxt->vctxt.error = NULL; + ctxt->vctxt.warning = NULL; + } + ctxt->vctxt.nodeTab = NULL; + ctxt->vctxt.nodeNr = 0; + ctxt->vctxt.nodeMax = 0; + ctxt->vctxt.node = NULL; + if (ctxt->dict != NULL) xmlDictFree(ctxt->dict); + ctxt->dict = ctx->dict; + ctxt->str_xml = xmlDictLookup(ctxt->dict, BAD_CAST "xml", 3); + ctxt->str_xmlns = xmlDictLookup(ctxt->dict, BAD_CAST "xmlns", 5); + ctxt->str_xml_ns = xmlDictLookup(ctxt->dict, XML_XML_NAMESPACE, 36); + ctxt->dictNames = ctx->dictNames; + ctxt->attsDefault = ctx->attsDefault; + ctxt->attsSpecial = ctx->attsSpecial; + + xmlParseContent(ctxt); + + ctx->validate = ctxt->validate; + ctx->valid = ctxt->valid; + if ((RAW == '<') && (NXT(1) == '/')) { + xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL); + } else if (RAW != 0) { + xmlFatalErr(ctxt, XML_ERR_EXTRA_CONTENT, NULL); + } + if (ctxt->node != newDoc->children) { + xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL); + } + + if (!ctxt->wellFormed) { + if (ctxt->errNo == 0) + ret = 1; + else + ret = ctxt->errNo; + } else { + if (lst != NULL) { + xmlNodePtr cur; + + /* + * Return the newly created nodeset after unlinking it from + * they pseudo parent. + */ + cur = newDoc->children->children; + *lst = cur; + while (cur != NULL) { + cur->parent = NULL; + cur = cur->next; + } + newDoc->children->children = NULL; + } + ret = 0; + } + ctxt->sax = oldsax; + ctxt->dict = NULL; + ctxt->attsDefault = NULL; + ctxt->attsSpecial = NULL; + xmlFreeParserCtxt(ctxt); + newDoc->intSubset = NULL; + newDoc->extSubset = NULL; + xmlFreeDoc(newDoc); + + return(ret); +} + +/** + * xmlParseExternalEntityPrivate: + * @param doc the document the chunk pertains to + * @param oldctxt the previous parser context if available + * @param sax the SAX handler bloc (possibly NULL) + * @param user_data The user data returned on SAX callbacks (possibly NULL) + * @param depth Used for loop detection, use 0 + * @param URL the URL for the entity to load + * @param systemID the System ID for the entity to load + * @param list the return value for the set of parsed nodes + * + * Private version of xmlParseExternalEntity() + * + * Returns 0 if the entity is well formed, -1 in case of args problem and + * the parser error code otherwise + */ + +static xmlParserErrors +xmlParseExternalEntityPrivate(xmlDocPtr doc, + xmlParserCtxtPtr oldctxt, + xmlSAXHandlerPtr sax, + void *user_data, + int depth, + const xmlChar *URL, + const xmlChar *systemID, + xmlNodePtr *list) +{ + xmlParserCtxtPtr ctxt; + xmlDocPtr newDoc; + xmlSAXHandlerPtr oldsax = NULL; + xmlParserErrors ret = XML_ERR_OK; + xmlChar start[4]; + xmlCharEncoding enc; + + if (depth > 40) { + return(XML_ERR_ENTITY_LOOP); + } + + if (list != NULL) + *list = NULL; + if ((URL == NULL) && (systemID == NULL)) + return(XML_ERR_INTERNAL_ERROR); + if (doc == NULL) /* @@ relax but check for dereferences */ + return(XML_ERR_INTERNAL_ERROR); + + + ctxt = xmlCreateEntityParserCtxt(URL, systemID, NULL); + + if (ctxt == NULL) + return(XML_WAR_UNDECLARED_ENTITY); + ctxt->userData = ctxt; + if (oldctxt != NULL) { + ctxt->_private = oldctxt->_private; + ctxt->loadsubset = oldctxt->loadsubset; + ctxt->validate = oldctxt->validate; + ctxt->external = oldctxt->external; +#ifdef XMLENGINE_ENABLE_PARSER_RECORD_INFO + ctxt->record_info = oldctxt->record_info; + ctxt->node_seq.maximum = oldctxt->node_seq.maximum; + ctxt->node_seq.length = oldctxt->node_seq.length; + ctxt->node_seq.buffer = oldctxt->node_seq.buffer; +#endif + } else { + /* + * Doing validity checking on chunk without context + * doesn't make sense + */ + ctxt->_private = NULL; + ctxt->validate = 0; + ctxt->external = 2; + ctxt->loadsubset = 0; + } + if (sax != NULL) { + oldsax = ctxt->sax; + ctxt->sax = sax; + if (user_data != NULL) + ctxt->userData = user_data; + } + xmlDetectSAX2(ctxt); + newDoc = xmlNewDoc(BAD_CAST "1.0"); + if (newDoc == NULL) { + // OOM +#ifdef XMLENGINE_ENABLE_PARSER_RECORD_INFO + ctxt->node_seq.maximum = 0; + ctxt->node_seq.length = 0; + ctxt->node_seq.buffer = NULL; +#endif + xmlFreeParserCtxt(ctxt); + return(XML_ERR_INTERNAL_ERROR); + } + if (doc != NULL) { + newDoc->intSubset = doc->intSubset; + newDoc->extSubset = doc->extSubset; + if (doc->URL != NULL) { + newDoc->URL = xmlStrdup(doc->URL); + } + } + newDoc->children = xmlNewDocNode(newDoc, NULL, BAD_CAST "pseudoroot", NULL); + if (newDoc->children == NULL) { + // OOM + if (sax != NULL) + ctxt->sax = oldsax; + +#ifdef XMLENGINE_ENABLE_PARSER_RECORD_INFO + ctxt->node_seq.maximum = 0; + ctxt->node_seq.length = 0; + ctxt->node_seq.buffer = NULL; +#endif + xmlFreeParserCtxt(ctxt); + newDoc->intSubset = NULL; + newDoc->extSubset = NULL; + xmlFreeDoc(newDoc); + return(XML_ERR_INTERNAL_ERROR); + } + nodePush(ctxt, newDoc->children); + if (doc == NULL) { + ctxt->myDoc = newDoc; + } else { + ctxt->myDoc = doc; + newDoc->children->doc = doc; + } + + /* + * Get the 4 first bytes and decode the charset + * if enc != XML_CHAR_ENCODING_NONE + * plug some encoding conversion routines. + */ + GROW; + if ((ctxt->input->end - ctxt->input->cur) >= 4) { + start[0] = RAW; + start[1] = NXT(1); + start[2] = NXT(2); + start[3] = NXT(3); + enc = xmlDetectCharEncoding(start, 4); + if (enc != XML_CHAR_ENCODING_NONE) { + xmlSwitchEncoding(ctxt, enc); + } + } + + /* + * Parse a possible text declaration first + */ + if ((CMP5(CUR_PTR, '<', '?', 'x', 'm', 'l')) && (IS_BLANK_CH(NXT(5)))) { + xmlParseTextDecl(ctxt); + } + + ctxt->instate = XML_PARSER_CONTENT; + ctxt->depth = depth; + + xmlParseContent(ctxt); + + if ((RAW == '<') && (NXT(1) == '/')) { + xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL); + } else if (RAW != 0) { + xmlFatalErr(ctxt, XML_ERR_EXTRA_CONTENT, NULL); + } + if (ctxt->node != newDoc->children) { + xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL); + } + + if (!ctxt->wellFormed) { + if (ctxt->errNo == 0) + ret = XML_ERR_INTERNAL_ERROR; + else + ret = (xmlParserErrors)ctxt->errNo; + } else { + if (list != NULL) { + xmlNodePtr cur; + + /* + * Return the newly created nodeset after unlinking it from + * they pseudo parent. + */ + cur = newDoc->children->children; + *list = cur; + while (cur != NULL) { + cur->parent = NULL; + cur = cur->next; + } + newDoc->children->children = NULL; + } + ret = XML_ERR_OK; + } + if (sax != NULL) + ctxt->sax = oldsax; + +#ifdef XMLENGINE_ENABLE_PARSER_RECORD_INFO + if(oldctxt) + { + oldctxt->node_seq.maximum = ctxt->node_seq.maximum; + oldctxt->node_seq.length = ctxt->node_seq.length; + oldctxt->node_seq.buffer = ctxt->node_seq.buffer; + } + ctxt->node_seq.maximum = 0; + ctxt->node_seq.length = 0; + ctxt->node_seq.buffer = NULL; +#endif + + xmlFreeParserCtxt(ctxt); + newDoc->intSubset = NULL; + newDoc->extSubset = NULL; + xmlFreeDoc(newDoc); + + return(ret); +} + +#ifdef LIBXML_SAX1_ENABLED +/** + * xmlParseExternalEntity: + * @param doc the document the chunk pertains to + * @param sax the SAX handler bloc (possibly NULL) + * @param user_data The user data returned on SAX callbacks (possibly NULL) + * @param depth Used for loop detection, use 0 + * @param URL the URL for the entity to load + * @param systemID the System ID for the entity to load + * @param lst the return value for the set of parsed nodes + * + * Parse an external general entity + * An external general parsed entity is well-formed if it matches the + * production labeled extParsedEnt. + * + * [78] extParsedEnt ::= TextDecl? content + * + * Returns 0 if the entity is well formed, -1 in case of args problem and + * the parser error code otherwise + */ + +XMLPUBFUNEXPORT int +xmlParseExternalEntity(xmlDocPtr doc, xmlSAXHandlerPtr sax, void *user_data, + int depth, const xmlChar *URL, const xmlChar *systemID, xmlNodePtr *lst) { + return(xmlParseExternalEntityPrivate(doc, NULL, sax, user_data, depth, URL, + systemID, lst)); +} + +/** + * xmlParseBalancedChunkMemory: + * @param doc the document the chunk pertains to + * @param sax the SAX handler bloc (possibly NULL) + * @param user_data The user data returned on SAX callbacks (possibly NULL) + * @param depth Used for loop detection, use 0 + * @param string the input string in UTF8 or ISO-Latin (zero terminated) + * @param lst the return value for the set of parsed nodes + * + * Parse a well-balanced chunk of an XML document + * called by the parser + * The allowed sequence for the Well Balanced Chunk is the one defined by + * the content production in the XML grammar: + * + * [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)* + * + * Returns 0 if the chunk is well balanced, -1 in case of args problem and + * the parser error code otherwise + */ + +XMLPUBFUNEXPORT int +xmlParseBalancedChunkMemory(xmlDocPtr doc, xmlSAXHandlerPtr sax, + void *user_data, int depth, const xmlChar *string, xmlNodePtr *lst) { + return xmlParseBalancedChunkMemoryRecover( doc, sax, user_data, + depth, string, lst, 0 ); +} +#endif /* LIBXML_SAX1_ENABLED */ + +/** + * xmlParseBalancedChunkMemoryInternal: + * @param oldctxt the existing parsing context + * @param string the input string in UTF8 or ISO-Latin (zero terminated) + * @param user_data the user data field for the parser context + * @param lst the return value for the set of parsed nodes + * + * + * Parse a well-balanced chunk of an XML document + * called by the parser + * The allowed sequence for the Well Balanced Chunk is the one defined by + * the content production in the XML grammar: + * + * [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)* + * + * Returns XML_ERR_OK if the chunk is well balanced, and the parser + * error code otherwise + * + * In case recover is set to 1, the nodelist will not be empty even if + * the parsed chunk is not well balanced. + */ +static xmlParserErrors +xmlParseBalancedChunkMemoryInternal(xmlParserCtxtPtr oldctxt, + const xmlChar *string, void *user_data, xmlNodePtr *lst) { + xmlParserCtxtPtr ctxt; + xmlDocPtr newDoc = NULL; + xmlSAXHandlerPtr oldsax = NULL; + xmlNodePtr content = NULL; + int size; + xmlParserErrors ret = XML_ERR_OK; + LOAD_GS_SAFE_CTXT(oldctxt) + + if (oldctxt->depth > 40) { + return(XML_ERR_ENTITY_LOOP); + } + + + if (lst != NULL) + *lst = NULL; + if (string == NULL) + return(XML_ERR_INTERNAL_ERROR); + + size = xmlStrlen(string); + + ctxt = xmlCreateMemoryParserCtxt((char *) string, size); + if (ctxt == NULL) return(XML_WAR_UNDECLARED_ENTITY); + if (user_data != NULL) + ctxt->userData = user_data; + else + ctxt->userData = ctxt; + if (ctxt->dict != NULL) xmlDictFree(ctxt->dict); + ctxt->dict = oldctxt->dict; + ctxt->str_xml = xmlDictLookup(ctxt->dict, BAD_CAST "xml", 3); + ctxt->str_xmlns = xmlDictLookup(ctxt->dict, BAD_CAST "xmlns", 5); + ctxt->str_xml_ns = xmlDictLookup(ctxt->dict, XML_XML_NAMESPACE, 36); + + oldsax = ctxt->sax; + ctxt->sax = oldctxt->sax; + xmlDetectSAX2(ctxt); + ctxt->replaceEntities = oldctxt->replaceEntities; + ctxt->options = oldctxt->options; + + ctxt->_private = oldctxt->_private; + if (oldctxt->myDoc == NULL) { + newDoc = xmlNewDoc(BAD_CAST "1.0"); + if (newDoc == NULL) { + ctxt->sax = oldsax; + ctxt->dict = NULL; + xmlFreeParserCtxt(ctxt); + return(XML_ERR_INTERNAL_ERROR); + } + ctxt->myDoc = newDoc; + } else { + ctxt->myDoc = oldctxt->myDoc; + content = ctxt->myDoc->children; + } + ctxt->myDoc->children = xmlNewDocNode(ctxt->myDoc, NULL, + BAD_CAST "pseudoroot", NULL); + if (ctxt->myDoc->children == NULL) { + ctxt->sax = oldsax; + ctxt->dict = NULL; + xmlFreeParserCtxt(ctxt); + if (newDoc != NULL) + xmlFreeDoc(newDoc); + return(XML_ERR_INTERNAL_ERROR); + } + nodePush(ctxt, ctxt->myDoc->children); + ctxt->instate = XML_PARSER_CONTENT; // can be XML_PARSER_EOF if error! + ctxt->depth = oldctxt->depth + 1; + + ctxt->validate = 0; + ctxt->loadsubset = oldctxt->loadsubset; + if ((oldctxt->validate) || (oldctxt->replaceEntities != 0)) { + /* + * ID/IDREF registration will be done in xmlValidateElement below + */ + ctxt->loadsubset |= XML_SKIP_IDS; + } + ctxt->dictNames = oldctxt->dictNames; + ctxt->attsDefault = oldctxt->attsDefault; + ctxt->attsSpecial = oldctxt->attsSpecial; + + xmlParseContent(ctxt); + if(OOM_FLAG) + { + xmlFreeParserCtxt(ctxt); + xmlParserOOMErr(ctxt); + return(XML_ERR_NO_MEMORY); + } + if ((RAW == '<') && (NXT(1) == '/')) { + xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL); + } else if (RAW != 0) { + xmlFatalErr(ctxt, XML_ERR_EXTRA_CONTENT, NULL); + } + if (ctxt->node != ctxt->myDoc->children) { + xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL); + } + + if (!ctxt->wellFormed) { + if (ctxt->errNo == 0) + ret = XML_ERR_INTERNAL_ERROR; + else + ret = (xmlParserErrors)ctxt->errNo; + } else { + ret = XML_ERR_OK; + } + + if ((lst != NULL) && (ret == XML_ERR_OK)) { + xmlNodePtr cur; + + /* + * Return the newly created nodeset after unlinking it from + * they pseudo parent. + */ + cur = ctxt->myDoc->children->children; + *lst = cur; + while (cur != NULL) { +#ifdef LIBXML_VALID_ENABLED + if (oldctxt->validate && oldctxt->wellFormed && + oldctxt->myDoc && oldctxt->myDoc->intSubset) { + oldctxt->valid &= xmlValidateElement(&oldctxt->vctxt, + oldctxt->myDoc, cur); + } +#endif /* LIBXML_VALID_ENABLED */ + cur->parent = NULL; + cur = cur->next; + } + ctxt->myDoc->children->children = NULL; + } + if (ctxt->myDoc != NULL) { + xmlFreeNode(ctxt->myDoc->children); + ctxt->myDoc->children = content; + } + + ctxt->sax = oldsax; + ctxt->dict = NULL; + ctxt->attsDefault = NULL; + ctxt->attsSpecial = NULL; + xmlFreeParserCtxt(ctxt); + if (newDoc != NULL) + xmlFreeDoc(newDoc); + + return(ret); +} + +// XMLENGINE: this function [xmlParseInNodeContext] is taken from +// the newer version of the code (2.6.21); +// It is required for WS-Security implementation (xmlsec) + +/** + * xmlParseInNodeContext: + * @param node the context node + * @param data the input string + * @param datalen the input string length in bytes + * @param options a combination of xmlParserOption + * @param lst the return value for the set of parsed nodes + * + * Parse a well-balanced chunk of an XML document + * within the context (DTD, namespaces, etc ...) of the given node. + * + * The allowed sequence for the data is a Well Balanced Chunk defined by + * the content production in the XML grammar: + * + * [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)* + * + * Returns XML_ERR_OK if the chunk is well balanced, and the parser + * error code otherwise + */ +XMLPUBFUNEXPORT xmlParserErrors +xmlParseInNodeContext(xmlNodePtr node, const char *data, int datalen, + int options, xmlNodePtr *lst) +{ +#ifdef SAX2 + xmlParserCtxtPtr ctxt; + xmlDocPtr doc = NULL; + xmlNodePtr fake, cur; + int nsnr = 0; + + xmlParserErrors ret = XML_ERR_OK; + LOAD_GS_SAFE_NODE(node) + + /* + * check all input parameters, grab the document + */ + if ((lst == NULL) || (node == NULL) || (data == NULL) || (datalen < 0)) + { + return(XML_ERR_INTERNAL_ERROR); + } + + switch (node->type) { + case XML_ELEMENT_NODE: + case XML_ATTRIBUTE_NODE: + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: + case XML_ENTITY_REF_NODE: + case XML_PI_NODE: + case XML_COMMENT_NODE: + case XML_DOCUMENT_NODE: + case XML_HTML_DOCUMENT_NODE: + break; + default: + return(XML_ERR_INTERNAL_ERROR); + + } + + while ((node != NULL) && + (node->type != XML_ELEMENT_NODE) && + (node->type != XML_DOCUMENT_NODE) && + (node->type != XML_HTML_DOCUMENT_NODE)) + { + node = node->parent; + } + + if (node == NULL) + return(XML_ERR_INTERNAL_ERROR); + + if (node->type == XML_ELEMENT_NODE){ + doc = node->doc; + } else { + doc = (xmlDocPtr) node; + } + + if (doc == NULL) + return(XML_ERR_INTERNAL_ERROR); + + /* + * allocate a context and set-up everything not related to the + * node position in the tree + */ + if (doc->type == XML_DOCUMENT_NODE) + ctxt = xmlCreateMemoryParserCtxt((char *) data, datalen); +#ifdef LIBXML_HTML_ENABLED + else if (doc->type == XML_HTML_DOCUMENT_NODE) + ctxt = htmlCreateMemoryParserCtxt((char *) data, datalen); +#endif + else + return(XML_ERR_INTERNAL_ERROR); + + if (ctxt == NULL) + return(XML_ERR_NO_MEMORY); + + fake = xmlNewComment(NULL); + if (fake == NULL) { + xmlFreeParserCtxt(ctxt); + return(XML_ERR_NO_MEMORY); + } + xmlAddChild(node, fake); + + /* + * Use input doc's dict if present, else assure XML_PARSE_NODICT is set. + * We need a dictionary for xmlDetectSAX2, so if there's no doc dict + * we must wait until the last moment to free the original one. + */ + if (doc->dict) { + if (ctxt->dict) + xmlDictFree(ctxt->dict); + ctxt->dict = doc->dict; + } else { + options |= XML_PARSE_NODICT; + } + + xmlCtxtUseOptions(ctxt, options); + xmlDetectSAX2(ctxt); + ctxt->myDoc = doc; + if ( OOM_FLAG ) + { + xmlFreeParserCtxt(ctxt); + return(XML_ERR_NO_MEMORY); + } + + if (node->type == XML_ELEMENT_NODE) + { + nodePush(ctxt, node); + /* + * initialize the SAX2 namespaces stack + */ + cur = node; + while ((cur != NULL) && (cur->type == XML_ELEMENT_NODE)) + { + xmlNsPtr ns = cur->nsDef; + const xmlChar *iprefix, *ihref; + + while (ns != NULL) + { + if (ctxt->dict) { + iprefix = xmlDictLookup(ctxt->dict, ns->prefix, -1); + ihref = xmlDictLookup(ctxt->dict, ns->href, -1); + } else { + iprefix = ns->prefix; + ihref = ns->href; + } + + if (xmlGetNamespace(ctxt, iprefix) == NULL) { + nsPush(ctxt, iprefix, ihref); + nsnr++; + } + ns = ns->next; + } + cur = cur->parent; + } + ctxt->instate = XML_PARSER_CONTENT; + } + + if ((ctxt->validate) || (ctxt->replaceEntities != 0)) + { + /* + * ID/IDREF registration will be done in xmlValidateElement below + */ + ctxt->loadsubset |= XML_SKIP_IDS; + } + + xmlParseContent(ctxt); + if ( OOM_FLAG ) + { + xmlFreeParserCtxt(ctxt); + return(XML_ERR_NO_MEMORY); + } + nsPop(ctxt, nsnr); + if ((RAW == '<') && (NXT(1) == '/')) { + xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL); + } else if (RAW != 0) { + xmlFatalErr(ctxt, XML_ERR_EXTRA_CONTENT, NULL); + } + if ((ctxt->node != NULL) && (ctxt->node != node)) { + xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL); + ctxt->wellFormed = 0; + } + + if (!ctxt->wellFormed) { + if (ctxt->errNo == 0) + ret = XML_ERR_INTERNAL_ERROR; + else + ret = (xmlParserErrors)ctxt->errNo; + } else { + ret = XML_ERR_OK; + } + + /* + * Return the newly created nodeset after unlinking it from + * the pseudo sibling. + */ + + cur = fake->next; + fake->next = NULL; + node->last = fake; + + if (cur != NULL) { + cur->prev = NULL; + } + + *lst = cur; + + while (cur != NULL) { + cur->parent = NULL; + cur = cur->next; + } + + xmlUnlinkNode(fake); + xmlFreeNode(fake); + + + if (ret != XML_ERR_OK) { + xmlFreeNodeList(*lst); + *lst = NULL; + } + + if (doc->dict != NULL) + ctxt->dict = NULL; + xmlFreeParserCtxt(ctxt); + + return(ret); +#else /* !SAX2 */ + return(XML_ERR_INTERNAL_ERROR); +#endif +} + +#ifdef LIBXML_SAX1_ENABLED +/** + * xmlParseBalancedChunkMemoryRecover: + * @param doc the document the chunk pertains to + * @param sax the SAX handler bloc (possibly NULL) + * @param user_data The user data returned on SAX callbacks (possibly NULL) + * @param depth Used for loop detection, use 0 + * @param string the input string in UTF8 or ISO-Latin (zero terminated) + * @param lst the return value for the set of parsed nodes + * @param recover return nodes even if the data is broken (use 0) + * + * + * Parse a well-balanced chunk of an XML document + * called by the parser + * The allowed sequence for the Well Balanced Chunk is the one defined by + * the content production in the XML grammar: + * + * [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)* + * + * Returns 0 if the chunk is well balanced, -1 in case of args problem and + * the parser error code otherwise + * + * In case recover is set to 1, the nodelist will not be empty even if + * the parsed chunk is not well balanced. + */ +XMLPUBFUNEXPORT int +xmlParseBalancedChunkMemoryRecover(xmlDocPtr doc, xmlSAXHandlerPtr sax, + void *user_data, int depth, const xmlChar *string, xmlNodePtr *lst, + int recover) { + xmlParserCtxtPtr ctxt; + xmlDocPtr newDoc; + xmlSAXHandlerPtr oldsax = NULL; + xmlNodePtr content; + int size; + int ret = 0; + + if (depth > 40) { + return(XML_ERR_ENTITY_LOOP); + } + + + if (lst != NULL) + *lst = NULL; + if (string == NULL) + return(-1); + + size = xmlStrlen(string); + + ctxt = xmlCreateMemoryParserCtxt((char *) string, size); + if (ctxt == NULL) return(-1); + ctxt->userData = ctxt; + if (sax != NULL) { + oldsax = ctxt->sax; + ctxt->sax = sax; + if (user_data != NULL) + ctxt->userData = user_data; + } + newDoc = xmlNewDoc(BAD_CAST "1.0"); + if (newDoc == NULL) { + xmlFreeParserCtxt(ctxt); + return(-1); + } + if (doc != NULL) { + newDoc->intSubset = doc->intSubset; + newDoc->extSubset = doc->extSubset; + } + newDoc->children = xmlNewDocNode(newDoc, NULL, BAD_CAST "pseudoroot", NULL); + if (newDoc->children == NULL) { + if (sax != NULL) + ctxt->sax = oldsax; + xmlFreeParserCtxt(ctxt); + newDoc->intSubset = NULL; + newDoc->extSubset = NULL; + xmlFreeDoc(newDoc); + return(-1); + } + nodePush(ctxt, newDoc->children); + if (doc == NULL) { + ctxt->myDoc = newDoc; + } else { + ctxt->myDoc = newDoc; + newDoc->children->doc = doc; + } + ctxt->instate = XML_PARSER_CONTENT; + ctxt->depth = depth; + + /* + * Doing validity checking on chunk doesn't make sense + */ + ctxt->validate = 0; + ctxt->loadsubset = 0; + xmlDetectSAX2(ctxt); + + if ( doc != NULL ){ + content = doc->children; + doc->children = NULL; + xmlParseContent(ctxt); + doc->children = content; + } + else { + xmlParseContent(ctxt); + } + if ((RAW == '<') && (NXT(1) == '/')) { + xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL); + } else if (RAW != 0) { + xmlFatalErr(ctxt, XML_ERR_EXTRA_CONTENT, NULL); + } + if (ctxt->node != newDoc->children) { + xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL); + } + + if (!ctxt->wellFormed) { + if (ctxt->errNo == 0) + ret = 1; + else + ret = ctxt->errNo; + } else { + ret = 0; + } + + if (lst != NULL && (ret == 0 || recover == 1)) { + xmlNodePtr cur; + + /* + * Return the newly created nodeset after unlinking it from + * they pseudo parent. + */ + cur = newDoc->children->children; + *lst = cur; + while (cur != NULL) { + cur->parent = NULL; + cur = cur->next; + } + newDoc->children->children = NULL; + } + + if (sax != NULL) + ctxt->sax = oldsax; + xmlFreeParserCtxt(ctxt); + newDoc->intSubset = NULL; + newDoc->extSubset = NULL; + xmlFreeDoc(newDoc); + + return(ret); +} + +/** + * xmlSAXParseEntity: + * @param sax the SAX handler block + * @param filename the filename + * + * parse an XML external entity out of context and build a tree. + * It use the given SAX function block to handle the parsing callback. + * If sax is NULL, fallback to the default DOM tree building routines. + * + * [78] extParsedEnt ::= TextDecl? content + * + * This correspond to a "Well Balanced" chunk + * + * Returns the resulting document tree + */ + +XMLPUBFUNEXPORT xmlDocPtr +xmlSAXParseEntity(xmlSAXHandlerPtr sax, const char *filename) { + xmlDocPtr ret; + xmlParserCtxtPtr ctxt; + + ctxt = xmlCreateFileParserCtxt(filename); + if (ctxt == NULL) { + return(NULL); + } + if (sax != NULL) { + if (ctxt->sax != NULL) + xmlFree(ctxt->sax); + ctxt->sax = sax; + ctxt->userData = NULL; + } + + xmlParseExtParsedEnt(ctxt); + + if (ctxt->wellFormed) + ret = ctxt->myDoc; + else { + ret = NULL; + xmlFreeDoc(ctxt->myDoc); + ctxt->myDoc = NULL; + } + if (sax != NULL) + ctxt->sax = NULL; + xmlFreeParserCtxt(ctxt); + + return(ret); +} + +/** + * xmlParseEntity: + * @param filename the filename + * + * parse an XML external entity out of context and build a tree. + * + * [78] extParsedEnt ::= TextDecl? content + * + * This correspond to a "Well Balanced" chunk + * + * Returns the resulting document tree + */ + +XMLPUBFUNEXPORT xmlDocPtr +xmlParseEntity(const char *filename) { + return(xmlSAXParseEntity(NULL, filename)); +} +#endif /* LIBXML_SAX1_ENABLED */ + +/** + * xmlCreateEntityParserCtxt: + * @param URL the entity URL + * @param ID the entity PUBLIC ID + * @param base a possible base for the target URI + * + * Create a parser context for an external entity + * Automatic support for ZLIB/Compress compressed document is provided + * by default if found at compile-time. + * + * Returns the new parser context or NULL + */ +XMLPUBFUNEXPORT xmlParserCtxtPtr +xmlCreateEntityParserCtxt(const xmlChar* URL, + const xmlChar* ID, + const xmlChar* base) +{ + xmlParserCtxtPtr ctxt; + xmlParserInputPtr inputStream; + // local variable 'directory' was removed (function was optimized) + xmlChar* uri; + + ctxt = xmlNewParserCtxt(); + if (!ctxt) + return(NULL); + + uri = xmlBuildURI(URL, base); + + if (!uri) { + inputStream = xmlLoadExternalEntity((char*) URL, (char*) ID, ctxt); + if (!inputStream) { + xmlFreeParserCtxt(ctxt); + return(NULL); + } + inputPush(ctxt, inputStream); + + if (!ctxt->directory) + ctxt->directory = xmlParserGetDirectory((char*) URL); + } else { + inputStream = xmlLoadExternalEntity((char*) uri, (char*) ID, ctxt); + if (!inputStream) { + xmlFree(uri); + xmlFreeParserCtxt(ctxt); + return(NULL); + } + + inputPush(ctxt, inputStream); + + if (!ctxt->directory) + ctxt->directory = xmlParserGetDirectory((char*) uri); // oom POSSIBLE + + xmlFree(uri); + } + return(ctxt); +} + +/************************************************************************ + * * + * Front ends when parsing from a file * + * * + ************************************************************************/ + +/** + * xmlCreateURLParserCtxt: + * @param filename the filename or URL + * @param options a combination of xmlParserOption + * + * Create a parser context for a file or URL content. + * Automatic support for ZLIB/Compress compressed document is provided + * by default if found at compile-time and for file accesses + * + * Returns the new parser context or NULL + */ +XMLPUBFUNEXPORT xmlParserCtxtPtr +xmlCreateURLParserCtxt(const char* filename, int options) +{ + xmlParserCtxtPtr ctxt; + xmlParserInputPtr inputStream; + // local variable 'directory' was removed (function was optimized) + + ctxt = xmlNewParserCtxt(); + if (!ctxt) { + xmlParserOOMErr(ctxt); + return(NULL); + } + + if (options != 0) + xmlCtxtUseOptions(ctxt, options); + + inputStream = xmlLoadExternalEntity(filename, NULL, ctxt); + if (!inputStream) { + xmlFreeParserCtxt(ctxt); + return(NULL); + } + + inputPush(ctxt, inputStream); + if (!ctxt->directory) + ctxt->directory = xmlParserGetDirectory(filename); + + return(ctxt); +} + + +/** + * xmlCreateFileParserCtxt: + * @param filename the filename + * + * Create a parser context for a file content. + * Automatic support for ZLIB/Compress compressed document is provided + * by default if found at compile-time. + * + * Returns the new parser context or NULL + */ +XMLPUBFUNEXPORT xmlParserCtxtPtr +xmlCreateFileParserCtxt(const char *filename) +{ + return(xmlCreateURLParserCtxt(filename, 0)); +} + +/** + * xmlSAXParseFileWithData: + * @param sax the SAX handler block + * @param filename the filename + * @param recovery work in recovery mode, i.e. tries to read no Well Formed + * documents + * @param data the userdata + * + * parse an XML file and build a tree. Automatic support for ZLIB/Compress + * compressed document is provided by default if found at compile-time. + * It use the given SAX function block to handle the parsing callback. + * If sax is NULL, fallback to the default DOM tree building routines. + * + * User data (void *) is stored within the parser context in the + * context's _private member, so it is available nearly everywhere in libxml + * + * Returns the resulting document tree + */ + +XMLPUBFUNEXPORT xmlDocPtr +xmlSAXParseFileWithData(xmlSAXHandlerPtr sax, const char *filename, + int recovery, void *data) { + xmlDocPtr ret; + xmlParserCtxtPtr ctxt; + // local variable 'directory' was removed (function was optimized) + + xmlInitParser(); + + + ctxt = xmlCreateFileParserCtxt(filename); + if (!ctxt) { + return(NULL); + } + + if (sax) { + if (ctxt->sax) + xmlFree(ctxt->sax); + ctxt->sax = sax; + } + + xmlDetectSAX2(ctxt); + if (data) { + ctxt->_private = data; + } + + if (!ctxt->directory) + ctxt->directory = xmlParserGetDirectory(filename); + + ctxt->recovery = recovery; + + xmlParseDocument(ctxt); + + if (ctxt->wellFormed || recovery) { + ret = ctxt->myDoc; + if (ret) { + if (ctxt->input->buf->compressed > 0) + ret->compression = 9; + else + ret->compression = ctxt->input->buf->compressed; + } + } else { + // not well-formed and w/o recovery + ret = NULL; + xmlFreeDoc(ctxt->myDoc); + ctxt->myDoc = NULL; + } + + if(sax) + ctxt->sax = NULL; + xmlFreeParserCtxt(ctxt); + + return(ret); +} + +/** + * xmlSAXParseFile: + * @param sax the SAX handler block + * @param filename the filename + * @param recovery work in recovery mode, i.e. tries to read no Well Formed + * documents + * + * parse an XML file and build a tree. Automatic support for ZLIB/Compress + * compressed document is provided by default if found at compile-time. + * It use the given SAX function block to handle the parsing callback. + * If sax is NULL, fallback to the default DOM tree building routines. + * + * Returns the resulting document tree + */ + +XMLPUBFUNEXPORT xmlDocPtr +xmlSAXParseFile(xmlSAXHandlerPtr sax, const char *filename, + int recovery) { + return(xmlSAXParseFileWithData(sax,filename,recovery,NULL)); +} + +/** + * xmlRecoverDoc: + * @param cur a pointer to an array of xmlChar + * + * parse an XML in-memory document and build a tree. + * In the case the document is not Well Formed, a tree is built anyway + * + * Returns the resulting document tree + */ + +XMLPUBFUNEXPORT xmlDocPtr +xmlRecoverDoc(xmlChar *cur) { + return(xmlSAXParseDoc(NULL, cur, 0, 1,NULL)); +} + +/** + * xmlRecoverFile: + * @param filename the filename + * + * parse an XML file and build a tree. Automatic support for ZLIB/Compress + * compressed document is provided by default if found at compile-time. + * In the case the document is not Well Formed, a tree is built anyway + * + * Returns the resulting document tree + */ + +XMLPUBFUNEXPORT xmlDocPtr +xmlRecoverFile(const char *filename) { + return(xmlSAXParseFile(NULL, filename, 1)); +} + + +/** + * xmlParseFile: + * @param filename the filename + * + * parse an XML file and build a tree. Automatic support for ZLIB/Compress + * compressed document is provided by default if found at compile-time. + * + * Returns the resulting document tree if the file was wellformed, + * NULL otherwise. + */ + +XMLPUBFUNEXPORT xmlDocPtr +xmlParseFile(const char *filename) { + return(xmlSAXParseFile(NULL, filename, 0)); +} + +/** + * xmlSetupParserForBuffer: + * @param ctxt an XML parser context + * @param buffer a xmlChar * buffer + * @param filename a file name + * + * Setup the parser context to parse a new buffer; Clears any prior + * contents from the parser context. The buffer parameter must not be + * NULL, but the filename parameter can be + */ +XMLPUBFUNEXPORT void +xmlSetupParserForBuffer(xmlParserCtxtPtr ctxt, const xmlChar* buffer, + const char* filename) +{ + xmlParserInputPtr input; + + input = xmlNewInputStream(ctxt); + if (input == NULL) { + xmlParserOOMErr(ctxt); + xmlFree(ctxt); + return; + } + + xmlClearParserCtxt(ctxt); + if (filename != NULL) + input->filename = (char *) xmlCanonicPath((const xmlChar *)filename); + input->base = buffer; + input->cur = buffer; + input->end = &buffer[xmlStrlen(buffer)]; + inputPush(ctxt, input); +} + +/** + * xmlSAXUserParseFile: + * @param sax a SAX handler + * @param user_data The user data returned on SAX callbacks + * @param filename a file name + * + * parse an XML file and call the given SAX handler routines. + * Automatic support for ZLIB/Compress compressed document is provided + * + * Returns 0 in case of success or a error number otherwise + */ +XMLPUBFUNEXPORT int +xmlSAXUserParseFile(xmlSAXHandlerPtr sax, void *user_data, + const char *filename) { + LOAD_GS_DIRECT + + int ret = 0; + xmlParserCtxtPtr ctxt; + + ctxt = xmlCreateFileParserCtxt(filename); + if (ctxt == NULL) return -1; +#ifdef LIBXML_SAX1_ENABLED + if (ctxt->sax != (xmlSAXHandlerPtr) &xmlDefaultSAXHandler) +#endif /* LIBXML_SAX1_ENABLED */ + xmlFree(ctxt->sax); + ctxt->sax = sax; + xmlDetectSAX2(ctxt); + + if (user_data != NULL) + ctxt->userData = user_data; + + xmlParseDocument(ctxt); + + if (ctxt->wellFormed) + ret = 0; + else { + if (ctxt->errNo != 0) + ret = ctxt->errNo; + else + ret = -1; + } + if (sax != NULL) + ctxt->sax = NULL; + + xmlFreeParserCtxt(ctxt); + + return ret; +} + + +/************************************************************************ + * * + * Front-ends when parsing from memory * + * * + ************************************************************************/ + +/** + * xmlCreateMemoryParserCtxt: + * @param buffer a pointer to a char array + * @param size the size of the array + * + * Create a parser context for an XML in-memory document. + * + * Returns the new parser context or NULL + * + * OOM: possible --> returns NULL, OOM flag is set + */ +XMLPUBFUNEXPORT xmlParserCtxtPtr +xmlCreateMemoryParserCtxt(const char *buffer, int size) { + xmlParserCtxtPtr ctxt; + xmlParserInputPtr input; + xmlParserInputBufferPtr buf; + + if (!buffer || size <= 0) + return(NULL); + + ctxt = xmlNewParserCtxt(); + if (!ctxt) + return(NULL); // OOM + + + buf = xmlParserInputBufferCreateMem(buffer, size, XML_CHAR_ENCODING_NONE); + if (!buf) + goto OOM_ctxt; + + input = xmlNewInputStream(ctxt); + if (!input) + goto OOM_buf_ctxt; + + // input->filename = NULL; // It is NULL after xmlNewInputStream() + input->buf = buf; + input->base = input->buf->buffer->content; + input->cur = input->buf->buffer->content; + input->end = &input->buf->buffer->content[input->buf->buffer->use]; + + if( inputPush(ctxt, input) < 0 ){ + xmlFreeInputStream(input); + goto OOM_ctxt; + } + return(ctxt); +//-------------------------------------------- +OOM_buf_ctxt: + xmlFreeParserInputBuffer(buf); +OOM_ctxt: + xmlFreeParserCtxt(ctxt); + return(NULL); +} + +/** + * xmlSAXParseMemoryWithData: + * @param sax the SAX handler block + * @param buffer an pointer to a char array + * @param size the size of the array + * @param recovery work in recovery mode, i.e. tries to read no Well Formed + * documents + * @param data the userdata + * + * parse an XML in-memory block and use the given SAX function block + * to handle the parsing callback. If sax is NULL, fallback to the default + * DOM tree building routines. + * + * User data (void *) is stored within the parser context in the + * context's _private member, so it is available nearly everywhere in libxml + * + * Returns the resulting document tree + */ + +XMLPUBFUNEXPORT xmlDocPtr +xmlSAXParseMemoryWithData(xmlSAXHandlerPtr sax, const char *buffer, + int size, int recovery, void *data) { + xmlDocPtr ret; + xmlParserCtxtPtr ctxt; + + ctxt = xmlCreateMemoryParserCtxt(buffer, size); + if (ctxt == NULL) return(NULL); + if (sax != NULL) { + if (ctxt->sax != NULL) + xmlFree(ctxt->sax); + ctxt->sax = sax; + } + xmlDetectSAX2(ctxt); + if (data!=NULL) { + ctxt->_private=data; + } + + ctxt->recovery = recovery; + + xmlParseDocument(ctxt); + + if ((ctxt->wellFormed) || recovery) + ret = ctxt->myDoc; + else { + ret = NULL; + xmlFreeDoc(ctxt->myDoc); + ctxt->myDoc = NULL; + } + if (sax != NULL) + ctxt->sax = NULL; + xmlFreeParserCtxt(ctxt); + + return(ret); +} + + + +/** + * xmlSAXParseMemory: + * @param sax the SAX handler block + * @param buffer an pointer to a char array + * @param size the size of the array + * @param recovery work in recovery mode, i.e. tries to read not Well Formed + * documents + * + * parse an XML in-memory block and use the given SAX function block + * to handle the parsing callback. If sax is NULL, fallback to the default + * DOM tree building routines. + * + * Returns the resulting document tree + */ +XMLPUBFUNEXPORT xmlDocPtr +xmlSAXParseMemory(xmlSAXHandlerPtr sax, const char *buffer, + int size, int recovery) { + return xmlSAXParseMemoryWithData(sax, buffer, size, recovery, NULL); +} + +/** + * xmlParseMemory: + * @param buffer an pointer to a char array + * @param size the size of the array + * + * parse an XML in-memory block and build a tree. + * + * Returns the resulting document tree + */ + +XMLPUBFUNEXPORT xmlDocPtr xmlParseMemory(const char *buffer, int size) { + return(xmlSAXParseMemory(NULL, buffer, size, 0)); +} + +/** + * xmlRecoverMemory: + * @param buffer an pointer to a char array + * @param size the size of the array + * + * parse an XML in-memory block and build a tree. + * In the case the document is not Well Formed, a tree is built anyway + * + * Returns the resulting document tree + */ + +XMLPUBFUNEXPORT xmlDocPtr xmlRecoverMemory(const char *buffer, int size) { + return(xmlSAXParseMemory(NULL, buffer, size, 1)); +} + +/** + * xmlSAXUserParseMemory: + * @param sax a SAX handler + * @param user_data The user data returned on SAX callbacks + * @param buffer an in-memory XML document input + * @param size the length of the XML document in bytes + * + * A better SAX parsing routine. + * parse an XML in-memory buffer and call the given SAX handler routines. + * + * Returns 0 in case of success or a error number otherwise + */ +XMLPUBFUNEXPORT int xmlSAXUserParseMemory(xmlSAXHandlerPtr sax, void *user_data, + const char *buffer, int size) { + int ret = 0; + xmlParserCtxtPtr ctxt; + xmlSAXHandlerPtr oldsax = NULL; + + if (sax == NULL) return -1; + ctxt = xmlCreateMemoryParserCtxt(buffer, size); + if (ctxt == NULL) return -1; + oldsax = ctxt->sax; + ctxt->sax = sax; + xmlDetectSAX2(ctxt); + if (user_data != NULL) + ctxt->userData = user_data; + + xmlParseDocument(ctxt); + + if (ctxt->wellFormed) + ret = 0; + else { + if (ctxt->errNo != 0) + ret = ctxt->errNo; + else + ret = -1; + } + ctxt->sax = oldsax; + xmlFreeParserCtxt(ctxt); + + return ret; +} + +/** + * xmlCreateDocParserCtxt: + * @param cur a pointer to an array of xmlChar + * @param length size (bytes) of the array (0 if it should be calculated) + * + * Creates a parser context for an XML in-memory document. + * + * Returns the new parser context or NULL + * + * OOM: possible --> returns NULL for cur!=NULL && length>0; OOM flag is set + */ +XMLPUBFUNEXPORT xmlParserCtxtPtr +xmlCreateDocParserCtxt(const xmlChar *cur, int length) { + int len; + + if (!cur) + return(NULL); + len = (length > 0) ? length : xmlStrlen(cur); + return(xmlCreateMemoryParserCtxt((const char *)cur, len)); +} + +//#ifdef LIBXML_SAX1_ENABLED +/** + * xmlSAXParseDoc: + * @param sax the SAX handler block + * @param cur a pointer to an array of xmlChar + * @param length size (bytes) of the array (0 if it should be calculated) + * @param recovery work in recovery mode, i.e. tries to read no Well Formed + * documents + * @param errorCode last error code is recorded, 0 is no errors + * + * parse an XML in-memory document and build a tree. + * It use the given SAX function block to handle the parsing callback. + * If sax is NULL, fallback to the default DOM tree building routines. + * + * Returns the resulting document tree + * + * OOM: possible --> OOM flag is set (and NULL is returned too) + */ + +XMLPUBFUNEXPORT xmlDocPtr +xmlSAXParseDoc(xmlSAXHandlerPtr sax, xmlChar* cur, int length, int recovery, int* errorCode) { + LOAD_GS_DIRECT + + xmlDocPtr ret; + xmlParserCtxtPtr ctxt; + + if (!cur) + return(NULL); + + ctxt = xmlCreateDocParserCtxt(cur, length); // may set OOM flag + if (!ctxt) + return(NULL); // OOM or wrong args + if (sax) { + ctxt->sax = sax; + ctxt->userData = NULL; + } + xmlDetectSAX2(ctxt); + ret = NULL; + + if(OOM_FLAG) + goto cleanup; + + xmlParseDocument(ctxt); // may set OOM flag + + if (!OOM_FLAG && + (ctxt->wellFormed || recovery)) + { + ret = ctxt->myDoc; + } + else + { + //ret = NULL; // Moved upwards + xmlFreeDoc(ctxt->myDoc); + //ctxt->myDoc = NULL; // unneccessary, xmlFreeParserCtxt does not try to free it + } +cleanup: + if (sax) + ctxt->sax = NULL; // do not free set of custom callbacks + if(errorCode) + *errorCode = ctxt->errNo; // write error code to output argument + + xmlFreeParserCtxt(ctxt); + + return(ret); +} + +/** + * xmlParseDoc: + * @param cur a pointer to an array of xmlChar + * + * parse an XML in-memory document and build a tree. + * + * Returns the resulting document tree + */ + +XMLPUBFUNEXPORT xmlDocPtr +xmlParseDoc(xmlChar *cur) { + return(xmlSAXParseDoc(NULL, cur, 0, 0, NULL)); +} +//#endif /* LIBXML_SAX1_ENABLED */ + +#ifdef LIBXML_LEGACY_ENABLED +/************************************************************************ + * * + * Specific function to keep track of entities references * + * and used by the XSLT debugger * + * * + ************************************************************************/ + +static xmlEntityReferenceFunc xmlEntityRefFunc = NULL; + +/** + * xmlAddEntityReference: + * @param ent A valid entity + * @param firstNode A valid first node for children of entity + * @param lastNode A valid last node of children entity + * + * Notify of a reference to an entity of type XML_EXTERNAL_GENERAL_PARSED_ENTITY + */ +static void +xmlAddEntityReference(xmlEntityPtr ent, xmlNodePtr firstNode, + xmlNodePtr lastNode) +{ + if (xmlEntityRefFunc != NULL) { + (*xmlEntityRefFunc) (ent, firstNode, lastNode); + } +} + + +/** + * xmlSetEntityReferenceFunc: + * @param func A valid function + * + * Set the function to call call back when a xml reference has been made + */ +void +xmlSetEntityReferenceFunc(xmlEntityReferenceFunc func) +{ + xmlEntityRefFunc = func; +} +#endif /* LIBXML_LEGACY_ENABLED */ + +/************************************************************************ + * * + * Miscellaneous * + * * + ************************************************************************/ + +#ifdef LIBXML_XPATH_ENABLED +#include +#endif + +extern void xmlGenericErrorDefaultFunc(void *ctx, const char *msg, ...); + +/** + * xmlInitParser: + * + * Initialization function for the XML parser. + * This is not reentrant. Call once before processing in case of + * use in multithreaded programs. + * + * OOM: possible --> OOM flag is set + */ + +XMLPUBFUNEXPORT void +xmlInitParser(void) { + DEFINE_GS_PROXY //note: ensure GS proxy initialize before any GS member access + xmlGlobalStatePtr gs = xmlGetGlobalState(); + if (!gs) + { + gs = xmlCreateAndInitializeGlobalState(); + if (!gs) + return; + } + SET_GS_PROXY(gs) + + if (xmlParserInitialized != 0) + return; + + if ((xmlGenericError == xmlGenericErrorDefaultFunc) || + (xmlGenericError == NULL)) + { + initGenericErrorDefaultFunc(NULL); + } + xmlInitGlobals(); + xmlInitThreads(); + xmlInitMemory(); + xmlInitCharEncodingHandlers(); // may set OOM flag + xmlDefaultSAXHandlerInit(); + xmlRegisterDefaultInputCallbacks(); +#ifdef LIBXML_OUTPUT_ENABLED + xmlRegisterDefaultOutputCallbacks(); +#endif /* LIBXML_OUTPUT_ENABLED */ +#ifdef LIBXML_HTML_ENABLED + htmlInitAutoClose(); + htmlDefaultSAXHandlerInit(); +#endif +#ifdef LIBXML_XPATH_ENABLED + xmlXPathInit(); +#endif + //xmlParserMaxDepth = 1024; + xmlParserInitialized = 1; +} + +/** + * xmlCleanupParser: + * + * Cleanup function for the XML library. It tries to reclaim all + * parsing related global memory allocated for the library processing. + * It doesn't deallocate any document related memory. Calling this + * function should not prevent reusing the library but one should + * call xmlCleanupParser() only when the process has + * finished using the library or XML document built with it. + * + * OOM: never + */ + +XMLPUBFUNEXPORT void +xmlCleanupParser(void) { + LOAD_GS_DIRECT + if (!xmlParserInitialized) + return; + + xmlCleanupCharEncodingHandlers(); +#ifdef LIBXML_CATALOG_ENABLED + xmlCatalogCleanup(); +#endif + xmlCleanupInputCallbacks(); +#ifdef LIBXML_OUTPUT_ENABLED + xmlCleanupOutputCallbacks(); +#endif + xmlCleanupGlobals(); + xmlResetLastError(); + xmlCleanupThreads(); /* must be last if called not from the main thread */ + xmlCleanupMemory(); + xmlParserInitialized = 0; +} + +/************************************************************************ + * * + * New set (2.6.0) of simpler and more flexible APIs * + * * + ************************************************************************/ + +/** + * DICT_FREE: + * @param str a string + * + * Free a string if it is not owned by the "dict" dictionnary in the + * current scope + */ +#define DICT_FREE(str) \ + if ((str) && ((!dict) || \ + (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \ + xmlFree((char *)(str)); + +/** + * xmlCtxtReset: + * @param ctxt an XML parser context + * + * Reset a parser context + */ +XMLPUBFUNEXPORT void +xmlCtxtReset(xmlParserCtxtPtr ctxt) +{ + xmlParserInputPtr input; + xmlDictPtr dict = ctxt->dict; + + while ((input = inputPop(ctxt)) != NULL) { /* Non consuming */ + xmlFreeInputStream(input); + } + ctxt->inputNr = 0; + ctxt->input = NULL; + + ctxt->spaceNr = 0; + ctxt->spaceTab[0] = -1; + ctxt->space = &ctxt->spaceTab[0]; + + + ctxt->nodeNr = 0; + ctxt->node = NULL; + + ctxt->nameNr = 0; + ctxt->name = NULL; + + DICT_FREE(ctxt->version); + ctxt->version = NULL; + DICT_FREE(ctxt->encoding); + ctxt->encoding = NULL; + DICT_FREE(ctxt->directory); + ctxt->directory = NULL; + DICT_FREE(ctxt->extSubURI); + ctxt->extSubURI = NULL; + DICT_FREE(ctxt->extSubSystem); + ctxt->extSubSystem = NULL; + if (ctxt->myDoc != NULL) + xmlFreeDoc(ctxt->myDoc); + ctxt->myDoc = NULL; + + ctxt->standalone = -1; + ctxt->hasExternalSubset = 0; + ctxt->hasPErefs = 0; + ctxt->html = 0; + ctxt->external = 0; + ctxt->instate = XML_PARSER_START; + ctxt->token = 0; + + ctxt->wellFormed = 1; + ctxt->nsWellFormed = 1; + ctxt->disableSAX = 0; + ctxt->valid = 1; + +#if 0 + ctxt->vctxt.userData = ctxt; + ctxt->vctxt.error = xmlParserValidityError; + ctxt->vctxt.warning = xmlParserValidityWarning; +#endif + +#ifdef XMLENGINE_ENABLE_PARSER_RECORD_INFO + + ctxt->record_info = 0; + xmlInitNodeInfoSeq(&ctxt->node_seq); +#endif + ctxt->nbChars = 0; + ctxt->checkIndex = 0; + ctxt->inSubset = 0; + ctxt->errNo = XML_ERR_OK; + ctxt->depth = 0; + ctxt->charset = XML_CHAR_ENCODING_UTF8; + ctxt->catalogs = NULL; + + if (ctxt->attsDefault != NULL) { + xmlHashFree(ctxt->attsDefault, (xmlHashDeallocator) xmlFree); + ctxt->attsDefault = NULL; + } + if (ctxt->attsSpecial != NULL) { + xmlHashFree(ctxt->attsSpecial, NULL); + ctxt->attsSpecial = NULL; + } + +#ifdef LIBXML_CATALOG_ENABLED + if (ctxt->catalogs != NULL) + xmlCatalogFreeLocal(ctxt->catalogs); +#endif + if (ctxt->lastError.code != XML_ERR_OK) + xmlResetError(&ctxt->lastError); +} + +#ifndef XMLENGINE_EXCLUDE_UNUSED +/** + * xmlCtxtResetPush: + * @param ctxt an XML parser context + * @param chunk a pointer to an array of chars + * @param size number of chars in the array + * @param filename an optional file name or URI + * @param encoding the document encoding, or NULL + * + * Reset a push parser context + * + * Returns 0 in case of success and 1 in case of error + */ +int +xmlCtxtResetPush(xmlParserCtxtPtr ctxt, const char *chunk, + int size, const char *filename, const char *encoding) +{ + xmlParserInputPtr inputStream; + xmlParserInputBufferPtr buf; + xmlCharEncoding enc = XML_CHAR_ENCODING_NONE; + + if (ctxt == NULL) + return(1); + + if ((encoding == NULL) && (chunk != NULL) && (size >= 4)) + enc = xmlDetectCharEncoding((const xmlChar *) chunk, size); + + buf = xmlAllocParserInputBuffer(enc); + if (buf == NULL) + return(1); + + if (ctxt == NULL) { + xmlFreeParserInputBuffer(buf); + return(1); + } + + xmlCtxtReset(ctxt); + + if (ctxt->pushTab == NULL) { + ctxt->pushTab = (void **) xmlMalloc(ctxt->nameMax * 3 * + sizeof(xmlChar *)); + if (ctxt->pushTab == NULL) { + xmlParserOOMErr(ctxt); + xmlFreeParserInputBuffer(buf); + return(1); + } + } + + if (filename == NULL) { + ctxt->directory = NULL; + } else { + ctxt->directory = xmlParserGetDirectory(filename); + } + + inputStream = xmlNewInputStream(ctxt); + if (inputStream == NULL) { + xmlFreeParserInputBuffer(buf); + return(1); + } + + if (filename == NULL) + inputStream->filename = NULL; + else + inputStream->filename = (char *) + + xmlCanonicPath((const xmlChar *) filename); + inputStream->buf = buf; + inputStream->base = inputStream->buf->buffer->content; + inputStream->cur = inputStream->buf->buffer->content; + inputStream->end = &inputStream->buf->buffer->content[inputStream->buf->buffer->use]; + + inputPush(ctxt, inputStream); + + if ((size > 0) && (chunk != NULL) && + (ctxt->input != NULL) && + (ctxt->input->buf != NULL)) + { + int base = ctxt->input->base - ctxt->input->buf->buffer->content; + int cur = ctxt->input->cur - ctxt->input->base; + + xmlParserInputBufferPush(ctxt->input->buf, size, chunk); + + ctxt->input->base = ctxt->input->buf->buffer->content + base; + ctxt->input->cur = ctxt->input->base + cur; + ctxt->input->end = + &ctxt->input->buf->buffer->content[ctxt->input->buf->buffer->use]; +#ifdef DEBUG_PUSH + xmlGenericError(xmlGenericErrorContext, "PP: pushed %d\n", size); +#endif + } + + if (encoding != NULL) { + xmlCharEncodingHandlerPtr hdlr; + + hdlr = xmlFindCharEncodingHandler(encoding); + if (hdlr != NULL) { + xmlSwitchToEncoding(ctxt, hdlr); + } else { + xmlFatalErrMsgStr(ctxt, XML_ERR_UNSUPPORTED_ENCODING, + EMBED_ERRTXT("Unsupported encoding %s\n"), BAD_CAST encoding); + } + } else if (enc != XML_CHAR_ENCODING_NONE) { + xmlSwitchEncoding(ctxt, enc); + } + + return(0); +} +#endif /* ifndef XMLENGINE_EXCLUDE_UNUSED */ + + +/** + * xmlCtxtUseOptions: + * @param ctxt an XML parser context + * @param options a combination of xmlParserOption + * + * Applies the options to the parser context + * + * Returns 0 in case of success, the set of unknown or unimplemented options + * in case of error. + */ +XMLPUBFUNEXPORT int +xmlCtxtUseOptions(xmlParserCtxtPtr ctxt, int options) +{ + if (options & XML_PARSE_RECOVER) { + ctxt->recovery = 1; + options -= XML_PARSE_RECOVER; + } else + ctxt->recovery = 0; + if (options & XML_PARSE_DTDLOAD) { + ctxt->loadsubset = XML_DETECT_IDS; + options -= XML_PARSE_DTDLOAD; + } else + ctxt->loadsubset = 0; + if (options & XML_PARSE_DTDATTR) { + ctxt->loadsubset |= XML_COMPLETE_ATTRS; + options -= XML_PARSE_DTDATTR; + } + if (options & XML_PARSE_NOENT) { + ctxt->replaceEntities = 1; + /* ctxt->loadsubset |= XML_DETECT_IDS; */ + options -= XML_PARSE_NOENT; + } else + ctxt->replaceEntities = 0; + if (options & XML_PARSE_NOWARNING) { + ctxt->sax->warning = NULL; + options -= XML_PARSE_NOWARNING; + } + if (options & XML_PARSE_NOERROR) { + ctxt->sax->error = NULL; + ctxt->sax->fatalError = NULL; + options -= XML_PARSE_NOERROR; + } + if (options & XML_PARSE_PEDANTIC) { + ctxt->pedantic = 1; + options -= XML_PARSE_PEDANTIC; + } else + ctxt->pedantic = 0; + if (options & XML_PARSE_NOBLANKS) { + ctxt->keepBlanks = 0; + ctxt->sax->ignorableWhitespace = xmlSAX2IgnorableWhitespace; + options -= XML_PARSE_NOBLANKS; + } else + ctxt->keepBlanks = 1; + if (options & XML_PARSE_DTDVALID) { + ctxt->validate = 1; + if (options & XML_PARSE_NOWARNING) + ctxt->vctxt.warning = NULL; + if (options & XML_PARSE_NOERROR) + ctxt->vctxt.error = NULL; + options -= XML_PARSE_DTDVALID; + } else + ctxt->validate = 0; +#ifdef LIBXML_SAX1_ENABLED + if (options & XML_PARSE_SAX1) { + ctxt->sax->startElement = xmlSAX2StartElement; + ctxt->sax->endElement = xmlSAX2EndElement; + ctxt->sax->startElementNs = NULL; + ctxt->sax->endElementNs = NULL; + ctxt->sax->initialized = 1; + options -= XML_PARSE_SAX1; + } +#endif /* LIBXML_SAX1_ENABLED */ + if (options & XML_PARSE_NODICT) { + ctxt->dictNames = 0; + options -= XML_PARSE_NODICT; + } else { + ctxt->dictNames = 1; + } + if (options & XML_PARSE_NOCDATA) { + ctxt->sax->cdataBlock = NULL; + options -= XML_PARSE_NOCDATA; + } + if (options & XML_PARSE_NSCLEAN) { + ctxt->options |= XML_PARSE_NSCLEAN; + options -= XML_PARSE_NSCLEAN; + } + if (options & XML_PARSE_NONET) { + ctxt->options |= XML_PARSE_NONET; + options -= XML_PARSE_NONET; + } +#ifdef LIBXML_ENABLE_NODE_LINEINFO + ctxt->linenumbers = 1; +#endif + return (options); +} + +/** + * xmlDoRead: + * @param ctxt an XML parser context + * @param URL the base URL to use for the document + * @param encoding the document encoding, or NULL + * @param options a combination of xmlParserOption + * @param reuse keep the context for reuse + * + * Common front-end for the xmlRead functions + * + * Returns the resulting document tree or NULL + */ +static xmlDocPtr +xmlDoRead(xmlParserCtxtPtr ctxt, const char *URL, const char *encoding, + int options, int reuse) +{ + xmlDocPtr ret; + + xmlCtxtUseOptions(ctxt, options); + if (encoding != NULL) { + xmlCharEncodingHandlerPtr hdlr; + + hdlr = xmlFindCharEncodingHandler(encoding); + if (hdlr != NULL) + xmlSwitchToEncoding(ctxt, hdlr); + } + if ((URL != NULL) && + (ctxt->input != NULL) && + (ctxt->input->filename == NULL)) + { + ctxt->input->filename = (char *) xmlStrdup((const xmlChar *) URL); + } + xmlParseDocument(ctxt); + if ((ctxt->wellFormed) || ctxt->recovery) + ret = ctxt->myDoc; + else { + ret = NULL; + if (ctxt->myDoc != NULL) { + xmlFreeDoc(ctxt->myDoc); + } + } + ctxt->myDoc = NULL; + if (!reuse) { + xmlFreeParserCtxt(ctxt); + } + + return (ret); +} + +/** + * xmlReadDoc: + * @param cur a pointer to a zero terminated string + * @param URL the base URL to use for the document + * @param encoding the document encoding, or NULL + * @param options a combination of xmlParserOption + * + * parse an XML in-memory document and build a tree. + * + * Returns the resulting document tree + */ + +XMLPUBFUNEXPORT xmlDocPtr +xmlReadDoc(const xmlChar * cur, const char *URL, const char *encoding, int options) +{ + xmlParserCtxtPtr ctxt; + + if (cur == NULL) + return (NULL); + + ctxt = xmlCreateDocParserCtxt(cur, 0); + if (ctxt == NULL) + return (NULL); + return (xmlDoRead(ctxt, URL, encoding, options, 0)); +} + +#ifndef XMLENGINE_EXCLUDE_UNUSED +/** + * xmlReadFile: + * @param filename a file or URL + * @param encoding the document encoding, or NULL + * @param options a combination of xmlParserOption + * + * parse an XML file from the filesystem or the network. + * + * Returns the resulting document tree + */ +xmlDocPtr +xmlReadFile(const char *filename, const char *encoding, int options) +{ + xmlParserCtxtPtr ctxt; + + ctxt = xmlCreateURLParserCtxt(filename, options); + if (ctxt == NULL) + return (NULL); + return (xmlDoRead(ctxt, NULL, encoding, options, 0)); +} +#endif + +/** + * xmlReadMemory: + * @param buffer a pointer to a char array + * @param size the size of the array + * @param URL the base URL to use for the document + * @param encoding the document encoding, or NULL + * @param options a combination of xmlParserOption + * + * parse an XML in-memory document and build a tree. + * + * Returns the resulting document tree + */ +XMLPUBFUNEXPORT xmlDocPtr +xmlReadMemory(const char *buffer, int size, const char *URL, const char *encoding, int options) +{ + xmlParserCtxtPtr ctxt; + + ctxt = xmlCreateMemoryParserCtxt(buffer, size); + if (ctxt == NULL) + return (NULL); + return (xmlDoRead(ctxt, URL, encoding, options, 0)); +} + +#ifndef XMLENGINE_EXCLUDE_UNUSED +/** + * xmlReadFd: + * @param fd an open file descriptor + * @param URL the base URL to use for the document + * @param encoding the document encoding, or NULL + * @param options a combination of xmlParserOption + * + * parse an XML from a file descriptor and build a tree. + * NOTE that the file descriptor will not be closed when the + * reader is closed or reset. + * + * Returns the resulting document tree + */ +xmlDocPtr +xmlReadFd(int fd, const char *URL, const char *encoding, int options) +{ + xmlParserCtxtPtr ctxt; + xmlParserInputBufferPtr input; + xmlParserInputPtr stream; + + if (fd < 0) + return (NULL); + + input = xmlParserInputBufferCreateFd(fd, XML_CHAR_ENCODING_NONE); + if (input == NULL) + return (NULL); + input->closecallback = NULL; + ctxt = xmlNewParserCtxt(); + if (ctxt == NULL) { + xmlFreeParserInputBuffer(input); + return (NULL); + } + stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE); + if (stream == NULL) { + xmlFreeParserInputBuffer(input); + xmlFreeParserCtxt(ctxt); + return (NULL); + } + inputPush(ctxt, stream); + return (xmlDoRead(ctxt, URL, encoding, options, 0)); +} + + +// XMLENGINE: This may be reused for xDC + +/** + * xmlReadIO: + * @param ioread an I/O read function + * @param ioclose an I/O close function + * @param ioctx an I/O handler + * @param URL the base URL to use for the document + * @param encoding the document encoding, or NULL + * @param options a combination of xmlParserOption + * + * parse an XML document from I/O functions and source and build a tree. + * + * Returns the resulting document tree + */ +xmlDocPtr +xmlReadIO(xmlInputReadCallback ioread, xmlInputCloseCallback ioclose, + void *ioctx, const char *URL, const char *encoding, int options) +{ + xmlParserCtxtPtr ctxt; + xmlParserInputBufferPtr input; + xmlParserInputPtr stream; + + if (ioread == NULL) + return (NULL); + + input = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx, + XML_CHAR_ENCODING_NONE); + if (input == NULL) + return (NULL); + ctxt = xmlNewParserCtxt(); + if (ctxt == NULL) { + xmlFreeParserInputBuffer(input); + return (NULL); + } + stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE); + if (stream == NULL) { + xmlFreeParserInputBuffer(input); + xmlFreeParserCtxt(ctxt); + return (NULL); + } + inputPush(ctxt, stream); + return (xmlDoRead(ctxt, URL, encoding, options, 0)); +} + + +/** + * xmlCtxtReadDoc: + * @param ctxt an XML parser context + * @param cur a pointer to a zero terminated string + * @param URL the base URL to use for the document + * @param encoding the document encoding, or NULL + * @param options a combination of xmlParserOption + * + * parse an XML in-memory document and build a tree. + * This reuses the existing ctxt parser context + * + * Returns the resulting document tree + */ +xmlDocPtr +xmlCtxtReadDoc(xmlParserCtxtPtr ctxt, const xmlChar * cur, + const char *URL, const char *encoding, int options) +{ + xmlParserInputPtr stream; + + if (cur == NULL) + return (NULL); + if (ctxt == NULL) + return (NULL); + + xmlCtxtReset(ctxt); + + stream = xmlNewStringInputStream(ctxt, cur); + if (stream == NULL) { + return (NULL); + } + inputPush(ctxt, stream); + return (xmlDoRead(ctxt, URL, encoding, options, 1)); +} + +/** + * xmlCtxtReadFile: + * @param ctxt an XML parser context + * @param filename a file or URL + * @param encoding the document encoding, or NULL + * @param options a combination of xmlParserOption + * + * parse an XML file from the filesystem or the network. + * This reuses the existing ctxt parser context + * + * Returns the resulting document tree + */ +xmlDocPtr +xmlCtxtReadFile(xmlParserCtxtPtr ctxt, const char *filename, + const char *encoding, int options) +{ + xmlParserInputPtr stream; + + if (filename == NULL) + return (NULL); + if (ctxt == NULL) + return (NULL); + + xmlCtxtReset(ctxt); + + stream = xmlNewInputFromFile(ctxt, filename); + if (stream == NULL) { + return (NULL); + } + inputPush(ctxt, stream); + return (xmlDoRead(ctxt, NULL, encoding, options, 1)); +} + + +/** + * xmlCtxtReadMemory: + * @param ctxt an XML parser context + * @param buffer a pointer to a char array + * @param size the size of the array + * @param URL the base URL to use for the document + * @param encoding the document encoding, or NULL + * @param options a combination of xmlParserOption + * + * parse an XML in-memory document and build a tree. + * This reuses the existing ctxt parser context + * + * Returns the resulting document tree + */ +xmlDocPtr +xmlCtxtReadMemory(xmlParserCtxtPtr ctxt, const char *buffer, int size, + const char *URL, const char *encoding, int options) +{ + xmlParserInputBufferPtr input; + xmlParserInputPtr stream; + + if (ctxt == NULL) + return (NULL); + if (buffer == NULL) + return (NULL); + + xmlCtxtReset(ctxt); + + input = xmlParserInputBufferCreateMem(buffer, size, XML_CHAR_ENCODING_NONE); + if (input == NULL) { + return(NULL); + } + + stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE); + if (stream == NULL) { + xmlFreeParserInputBuffer(input); + return(NULL); + } + + inputPush(ctxt, stream); + return (xmlDoRead(ctxt, URL, encoding, options, 1)); +} + + +/** + * xmlCtxtReadFd: + * @param ctxt an XML parser context + * @param fd an open file descriptor + * @param URL the base URL to use for the document + * @param encoding the document encoding, or NULL + * @param options a combination of xmlParserOption + * + * parse an XML from a file descriptor and build a tree. + * This reuses the existing ctxt parser context + * NOTE that the file descriptor will not be closed when the + * reader is closed or reset. + * + * Returns the resulting document tree + */ +xmlDocPtr +xmlCtxtReadFd(xmlParserCtxtPtr ctxt, int fd, + const char *URL, const char *encoding, int options) +{ + xmlParserInputBufferPtr input; + xmlParserInputPtr stream; + + if (fd < 0) + return (NULL); + if (ctxt == NULL) + return (NULL); + + xmlCtxtReset(ctxt); + + + input = xmlParserInputBufferCreateFd(fd, XML_CHAR_ENCODING_NONE); + if (input == NULL) + return (NULL); + input->closecallback = NULL; + stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE); + if (stream == NULL) { + xmlFreeParserInputBuffer(input); + return (NULL); + } + inputPush(ctxt, stream); + return (xmlDoRead(ctxt, URL, encoding, options, 1)); +} + +/** + * xmlCtxtReadIO: + * @param ctxt an XML parser context + * @param ioread an I/O read function + * @param ioclose an I/O close function + * @param ioctx an I/O handler + * @param URL the base URL to use for the document + * @param encoding the document encoding, or NULL + * @param options a combination of xmlParserOption + * + * parse an XML document from I/O functions and source and build a tree. + * This reuses the existing ctxt parser context + * + * Returns the resulting document tree + */ +xmlDocPtr +xmlCtxtReadIO(xmlParserCtxtPtr ctxt, xmlInputReadCallback ioread, + xmlInputCloseCallback ioclose, void *ioctx, + const char *URL, + const char *encoding, int options) +{ + xmlParserInputBufferPtr input; + xmlParserInputPtr stream; + + if (ioread == NULL) + return (NULL); + if (ctxt == NULL) + return (NULL); + + xmlCtxtReset(ctxt); + + input = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx, + XML_CHAR_ENCODING_NONE); + if (input == NULL) + return (NULL); + stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE); + if (stream == NULL) { + xmlFreeParserInputBuffer(input); + return (NULL); + } + inputPush(ctxt, stream); + return (xmlDoRead(ctxt, URL, encoding, options, 1)); +} +#endif /* ifndef XMLENGINE_EXCLUDE_UNUSED */