15437 lines · 419.3 KB · C
RawDownload
/* * 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 working draft *     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 */ #define IN_LIBXML#include "libxml.h" #if defined(WIN32) && !defined (__CYGWIN__)#define XML_DIR_SEP '\\'#else#define XML_DIR_SEP '/'#endif #include <stdlib.h>#include <limits.h>#include <string.h>#include <stdarg.h>#include <libxml/xmlmemory.h>#include <libxml/threads.h>#include <libxml/globals.h>#include <libxml/tree.h>#include <libxml/parser.h>#include <libxml/parserInternals.h>#include <libxml/valid.h>#include <libxml/entities.h>#include <libxml/xmlerror.h>#include <libxml/encoding.h>#include <libxml/xmlIO.h>#include <libxml/uri.h>#ifdef LIBXML_CATALOG_ENABLED#include <libxml/catalog.h>#endif#ifdef LIBXML_SCHEMAS_ENABLED#include <libxml/xmlschemastypes.h>#include <libxml/relaxng.h>#endif#ifdef HAVE_CTYPE_H#include <ctype.h>#endif#ifdef HAVE_STDLIB_H#include <stdlib.h>#endif#ifdef HAVE_SYS_STAT_H#include <sys/stat.h>#endif#ifdef HAVE_FCNTL_H#include <fcntl.h>#endif#ifdef HAVE_UNISTD_H#include <unistd.h>#endif#ifdef HAVE_ZLIB_H#include <zlib.h>#endif#ifdef HAVE_LZMA_H#include <lzma.h>#endif #include "buf.h"#include "enc.h" static voidxmlFatalErr(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *info); static xmlParserCtxtPtrxmlCreateEntityParserCtxtInternal(const xmlChar *URL, const xmlChar *ID,	                  const xmlChar *base, xmlParserCtxtPtr pctx); /************************************************************************ *									* *	Arbitrary limits set in the parser. See XML_PARSE_HUGE		* *									* ************************************************************************/ #define XML_PARSER_BIG_ENTITY 1000#define XML_PARSER_LOT_ENTITY 5000 /* * XML_PARSER_NON_LINEAR is the threshold where the ratio of parsed entity *    replacement over the size in byte of the input indicates that you have *    and eponential behaviour. A value of 10 correspond to at least 3 entity *    replacement per byte of input. */#define XML_PARSER_NON_LINEAR 10 /* * xmlParserEntityCheck * * Function to check non-linear entity expansion behaviour * This is here to detect and stop exponential linear entity expansion * This is not a limitation of the parser but a safety * boundary feature. It can be disabled with the XML_PARSE_HUGE * parser option. */static intxmlParserEntityCheck(xmlParserCtxtPtr ctxt, size_t size,                     xmlEntityPtr ent){    size_t consumed = 0;     if ((ctxt == NULL) || (ctxt->options & XML_PARSE_HUGE))        return (0);    if (ctxt->lastError.code == XML_ERR_ENTITY_LOOP)        return (1);    if (size != 0) {        /*         * Do the check based on the replacement size of the entity         */        if (size < XML_PARSER_BIG_ENTITY)	    return(0);         /*         * A limit on the amount of text data reasonably used         */        if (ctxt->input != NULL) {            consumed = ctxt->input->consumed +                (ctxt->input->cur - ctxt->input->base);        }        consumed += ctxt->sizeentities;         if ((size < XML_PARSER_NON_LINEAR * consumed) &&	    (ctxt->nbentities * 3 < XML_PARSER_NON_LINEAR * consumed))            return (0);    } else if (ent != NULL) {        /*         * use the number of parsed entities in the replacement         */        size = ent->checked;         /*         * The amount of data parsed counting entities size only once         */        if (ctxt->input != NULL) {            consumed = ctxt->input->consumed +                (ctxt->input->cur - ctxt->input->base);        }        consumed += ctxt->sizeentities;         /*         * Check the density of entities for the amount of data	 * knowing an entity reference will take at least 3 bytes         */        if (size * 3 < consumed * XML_PARSER_NON_LINEAR)            return (0);    } else {        /*         * strange we got no data for checking just return         */        return (0);    }     xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL);    return (1);} /** * xmlParserMaxDepth: * * arbitrary depth limit for the XML documents that we allow to * process. This is not a limitation of the parser but a safety * boundary feature. It can be disabled with the XML_PARSE_HUGE * parser option. */unsigned int xmlParserMaxDepth = 256;   #define SAX2 1#define XML_PARSER_BIG_BUFFER_SIZE 300#define XML_PARSER_BUFFER_SIZE 100#define SAX_COMPAT_MODE BAD_CAST "SAX compatibility mode document" /** * XML_PARSER_CHUNK_SIZE * * When calling GROW that's the minimal amount of data * the parser expected to have received. It is not a hard * limit but an optimization when reading strings like Names * It is not strictly needed as long as inputs available characters * are followed by 0, which should be provided by the I/O level */#define XML_PARSER_CHUNK_SIZE 100 /* * List of XML prefixed PI allowed by W3C specs */ static const char *xmlW3CPIs[] = {    "xml-stylesheet",    "xml-model",    NULL};  /* DEPR void xmlParserHandleReference(xmlParserCtxtPtr ctxt); */static xmlEntityPtr xmlParseStringPEReference(xmlParserCtxtPtr ctxt,                                              const xmlChar **str); static xmlParserErrorsxmlParseExternalEntityPrivate(xmlDocPtr doc, xmlParserCtxtPtr oldctxt,	              xmlSAXHandlerPtr sax,		      void *user_data, int depth, const xmlChar *URL,		      const xmlChar *ID, xmlNodePtr *list); static intxmlCtxtUseOptionsInternal(xmlParserCtxtPtr ctxt, int options,                          const char *encoding);#ifdef LIBXML_LEGACY_ENABLEDstatic voidxmlAddEntityReference(xmlEntityPtr ent, xmlNodePtr firstNode,                      xmlNodePtr lastNode);#endif /* LIBXML_LEGACY_ENABLED */ static xmlParserErrorsxmlParseBalancedChunkMemoryInternal(xmlParserCtxtPtr oldctxt,		      const xmlChar *string, void *user_data, xmlNodePtr *lst); static intxmlLoadEntityContent(xmlParserCtxtPtr ctxt, xmlEntityPtr entity); /************************************************************************ *									* *		Some factorized error routines				* *									* ************************************************************************/ /** * xmlErrAttributeDup: * @ctxt:  an XML parser context * @prefix:  the attribute prefix * @localname:  the attribute localname * * Handle a redefinition of attribute error */static voidxmlErrAttributeDup(xmlParserCtxtPtr ctxt, const xmlChar * prefix,                   const xmlChar * localname){    if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&        (ctxt->instate == XML_PARSER_EOF))	return;    if (ctxt != NULL)	ctxt->errNo = XML_ERR_ATTRIBUTE_REDEFINED;     if (prefix == NULL)        __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER,                        XML_ERR_ATTRIBUTE_REDEFINED, XML_ERR_FATAL, NULL, 0,                        (const char *) localname, NULL, NULL, 0, 0,                        "Attribute %s redefined\n", localname);    else        __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER,                        XML_ERR_ATTRIBUTE_REDEFINED, XML_ERR_FATAL, NULL, 0,                        (const char *) prefix, (const char *) localname,                        NULL, 0, 0, "Attribute %s:%s redefined\n", prefix,                        localname);    if (ctxt != NULL) {	ctxt->wellFormed = 0;	if (ctxt->recovery == 0)	    ctxt->disableSAX = 1;    }} /** * xmlFatalErr: * @ctxt:  an XML parser context * @error:  the error number * @extra:  extra information string * * Handle a fatal parser error, i.e. violating Well-Formedness constraints */static voidxmlFatalErr(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *info){    const char *errmsg;    char errstr[129] = "";     if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&        (ctxt->instate == XML_PARSER_EOF))	return;    switch (error) {        case XML_ERR_INVALID_HEX_CHARREF:            errmsg = "CharRef: invalid hexadecimal value";            break;        case XML_ERR_INVALID_DEC_CHARREF:            errmsg = "CharRef: invalid decimal value";            break;        case XML_ERR_INVALID_CHARREF:            errmsg = "CharRef: invalid value";            break;        case XML_ERR_INTERNAL_ERROR:            errmsg = "internal error";            break;        case XML_ERR_PEREF_AT_EOF:            errmsg = "PEReference at end of document";            break;        case XML_ERR_PEREF_IN_PROLOG:            errmsg = "PEReference in prolog";            break;        case XML_ERR_PEREF_IN_EPILOG:            errmsg = "PEReference in epilog";            break;        case XML_ERR_PEREF_NO_NAME:            errmsg = "PEReference: no name";            break;        case XML_ERR_PEREF_SEMICOL_MISSING:            errmsg = "PEReference: expecting ';'";            break;        case XML_ERR_ENTITY_LOOP:            errmsg = "Detected an entity reference loop";            break;        case XML_ERR_ENTITY_NOT_STARTED:            errmsg = "EntityValue: \" or ' expected";            break;        case XML_ERR_ENTITY_PE_INTERNAL:            errmsg = "PEReferences forbidden in internal subset";            break;        case XML_ERR_ENTITY_NOT_FINISHED:            errmsg = "EntityValue: \" or ' expected";            break;        case XML_ERR_ATTRIBUTE_NOT_STARTED:            errmsg = "AttValue: \" or ' expected";            break;        case XML_ERR_LT_IN_ATTRIBUTE:            errmsg = "Unescaped '<' not allowed in attributes values";            break;        case XML_ERR_LITERAL_NOT_STARTED:            errmsg = "SystemLiteral \" or ' expected";            break;        case XML_ERR_LITERAL_NOT_FINISHED:            errmsg = "Unfinished System or Public ID \" or ' expected";            break;        case XML_ERR_MISPLACED_CDATA_END:            errmsg = "Sequence ']]>' not allowed in content";            break;        case XML_ERR_URI_REQUIRED:            errmsg = "SYSTEM or PUBLIC, the URI is missing";            break;        case XML_ERR_PUBID_REQUIRED:            errmsg = "PUBLIC, the Public Identifier is missing";            break;        case XML_ERR_HYPHEN_IN_COMMENT:            errmsg = "Comment must not contain '--' (double-hyphen)";            break;        case XML_ERR_PI_NOT_STARTED:            errmsg = "xmlParsePI : no target name";            break;        case XML_ERR_RESERVED_XML_NAME:            errmsg = "Invalid PI name";            break;        case XML_ERR_NOTATION_NOT_STARTED:            errmsg = "NOTATION: Name expected here";            break;        case XML_ERR_NOTATION_NOT_FINISHED:            errmsg = "'>' required to close NOTATION declaration";            break;        case XML_ERR_VALUE_REQUIRED:            errmsg = "Entity value required";            break;        case XML_ERR_URI_FRAGMENT:            errmsg = "Fragment not allowed";            break;        case XML_ERR_ATTLIST_NOT_STARTED:            errmsg = "'(' required to start ATTLIST enumeration";            break;        case XML_ERR_NMTOKEN_REQUIRED:            errmsg = "NmToken expected in ATTLIST enumeration";            break;        case XML_ERR_ATTLIST_NOT_FINISHED:            errmsg = "')' required to finish ATTLIST enumeration";            break;        case XML_ERR_MIXED_NOT_STARTED:            errmsg = "MixedContentDecl : '|' or ')*' expected";            break;        case XML_ERR_PCDATA_REQUIRED:            errmsg = "MixedContentDecl : '#PCDATA' expected";            break;        case XML_ERR_ELEMCONTENT_NOT_STARTED:            errmsg = "ContentDecl : Name or '(' expected";            break;        case XML_ERR_ELEMCONTENT_NOT_FINISHED:            errmsg = "ContentDecl : ',' '|' or ')' expected";            break;        case XML_ERR_PEREF_IN_INT_SUBSET:            errmsg =                "PEReference: forbidden within markup decl in internal subset";            break;        case XML_ERR_GT_REQUIRED:            errmsg = "expected '>'";            break;        case XML_ERR_CONDSEC_INVALID:            errmsg = "XML conditional section '[' expected";            break;        case XML_ERR_EXT_SUBSET_NOT_FINISHED:            errmsg = "Content error in the external subset";            break;        case XML_ERR_CONDSEC_INVALID_KEYWORD:            errmsg =                "conditional section INCLUDE or IGNORE keyword expected";            break;        case XML_ERR_CONDSEC_NOT_FINISHED:            errmsg = "XML conditional section not closed";            break;        case XML_ERR_XMLDECL_NOT_STARTED:            errmsg = "Text declaration '<?xml' required";            break;        case XML_ERR_XMLDECL_NOT_FINISHED:            errmsg = "parsing XML declaration: '?>' expected";            break;        case XML_ERR_EXT_ENTITY_STANDALONE:            errmsg = "external parsed entities cannot be standalone";            break;        case XML_ERR_ENTITYREF_SEMICOL_MISSING:            errmsg = "EntityRef: expecting ';'";            break;        case XML_ERR_DOCTYPE_NOT_FINISHED:            errmsg = "DOCTYPE improperly terminated";            break;        case XML_ERR_LTSLASH_REQUIRED:            errmsg = "EndTag: '</' not found";            break;        case XML_ERR_EQUAL_REQUIRED:            errmsg = "expected '='";            break;        case XML_ERR_STRING_NOT_CLOSED:            errmsg = "String not closed expecting \" or '";            break;        case XML_ERR_STRING_NOT_STARTED:            errmsg = "String not started expecting ' or \"";            break;        case XML_ERR_ENCODING_NAME:            errmsg = "Invalid XML encoding name";            break;        case XML_ERR_STANDALONE_VALUE:            errmsg = "standalone accepts only 'yes' or 'no'";            break;        case XML_ERR_DOCUMENT_EMPTY:            errmsg = "Document is empty";            break;        case XML_ERR_DOCUMENT_END:            errmsg = "Extra content at the end of the document";            break;        case XML_ERR_NOT_WELL_BALANCED:            errmsg = "chunk is not well balanced";            break;        case XML_ERR_EXTRA_CONTENT:            errmsg = "extra content at the end of well balanced chunk";            break;        case XML_ERR_VERSION_MISSING:            errmsg = "Malformed declaration expecting version";            break;        case XML_ERR_NAME_TOO_LONG:            errmsg = "Name too long use XML_PARSE_HUGE option";            break;#if 0        case:            errmsg = "";            break;#endif        default:            errmsg = "Unregistered error message";    }    if (info == NULL)        snprintf(errstr, 128, "%s\n", errmsg);    else        snprintf(errstr, 128, "%s: %%s\n", errmsg);    if (ctxt != NULL)	ctxt->errNo = error;    __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER, error,                    XML_ERR_FATAL, NULL, 0, info, NULL, NULL, 0, 0, &errstr[0],                    info);    if (ctxt != NULL) {	ctxt->wellFormed = 0;

Lines 1–500 of 15437.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t