import with 2 small changes: - config.h -> win32config.h - comment out deprecation to avoid warnings while preserving `xmlThrDefTreeIndentString` (for 8c792c25)
From: Daniel Lehman dlehman25@gmail.com
--- include/bcrypt.h | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/include/bcrypt.h b/include/bcrypt.h index b7d6c161467..9691605d69a 100644 --- a/include/bcrypt.h +++ b/include/bcrypt.h @@ -23,6 +23,10 @@ #define WINAPI __stdcall #endif
+#ifndef BCRYPT_SUCCESS +#define BCRYPT_SUCCESS(status) (((NTSTATUS)(status)) >= 0) +#endif + #ifndef IN #define IN #endif
From: Daniel Lehman dlehman25@gmail.com
--- dlls/msxml3/Makefile.in | 1 + libs/xml2/HTMLparser.c | 1345 ++-- libs/xml2/HTMLtree.c | 242 +- libs/xml2/SAX2.c | 865 ++- libs/xml2/buf.c | 190 +- libs/xml2/catalog.c | 192 +- libs/xml2/debugXML.c | 222 +- libs/xml2/dict.c | 139 +- libs/xml2/encoding.c | 754 ++- libs/xml2/entities.c | 501 +- libs/xml2/error.c | 1188 ++-- libs/xml2/globals.c | 117 +- libs/xml2/hash.c | 186 +- libs/xml2/include/libxml/HTMLparser.h | 31 +- libs/xml2/include/libxml/debugXML.h | 2 +- libs/xml2/include/libxml/encoding.h | 9 + libs/xml2/include/libxml/entities.h | 13 +- libs/xml2/include/libxml/hash.h | 19 + libs/xml2/include/libxml/list.h | 4 +- libs/xml2/include/libxml/nanohttp.h | 17 + libs/xml2/include/libxml/parser.h | 114 +- libs/xml2/include/libxml/parserInternals.h | 10 +- libs/xml2/include/libxml/pattern.h | 6 + libs/xml2/include/libxml/tree.h | 44 +- libs/xml2/include/libxml/uri.h | 11 + libs/xml2/include/libxml/valid.h | 31 +- libs/xml2/include/libxml/xinclude.h | 7 + libs/xml2/include/libxml/xmlIO.h | 25 +- libs/xml2/include/libxml/xmlerror.h | 14 + libs/xml2/include/libxml/xmlexports.h | 126 +- libs/xml2/include/libxml/xmlmemory.h | 53 +- libs/xml2/include/libxml/xmlreader.h | 2 + libs/xml2/include/libxml/xmlsave.h | 5 + libs/xml2/include/libxml/xmlunicode.h | 166 +- libs/xml2/include/libxml/xmlversion.h | 176 +- libs/xml2/include/libxml/xpath.h | 4 + libs/xml2/include/private/buf.h | 6 - libs/xml2/include/private/dict.h | 2 + libs/xml2/include/private/entities.h | 16 +- libs/xml2/include/private/error.h | 23 +- libs/xml2/include/private/globals.h | 5 + libs/xml2/include/private/io.h | 26 +- libs/xml2/include/private/parser.h | 65 +- libs/xml2/include/private/regexp.h | 14 + libs/xml2/include/private/save.h | 10 +- libs/xml2/include/private/string.h | 4 + libs/xml2/include/private/tree.h | 9 + libs/xml2/include/private/xpath.h | 9 + libs/xml2/include/win32config.h | 3 - libs/xml2/libxml.h | 7 +- libs/xml2/list.c | 31 +- libs/xml2/parser.c | 6930 +++++++++----------- libs/xml2/parserInternals.c | 1715 +++-- libs/xml2/pattern.c | 121 +- libs/xml2/relaxng.c | 288 +- libs/xml2/threads.c | 21 +- libs/xml2/tree.c | 5593 ++++++++-------- libs/xml2/uri.c | 1351 ++-- libs/xml2/valid.c | 2065 +++--- libs/xml2/xinclude.c | 1131 ++-- libs/xml2/xmlIO.c | 3128 ++++----- libs/xml2/xmlmemory.c | 642 +- libs/xml2/xmlreader.c | 1320 ++-- libs/xml2/xmlregexp.c | 164 +- libs/xml2/xmlsave.c | 880 ++- libs/xml2/xmlschemas.c | 504 +- libs/xml2/xmlschemastypes.c | 998 ++- libs/xml2/xmlstring.c | 187 +- libs/xml2/xpath.c | 2258 +++---- libs/xml2/xpointer.c | 140 +- 70 files changed, 17561 insertions(+), 18936 deletions(-)
diff --git a/dlls/msxml3/Makefile.in b/dlls/msxml3/Makefile.in index 7e59a223143..b7226866caf 100644 --- a/dlls/msxml3/Makefile.in +++ b/dlls/msxml3/Makefile.in @@ -1,6 +1,7 @@ MODULE = msxml3.dll IMPORTS = $(XSLT_PE_LIBS) $(XML2_PE_LIBS) uuid urlmon shlwapi oleaut32 ole32 user32 advapi32 EXTRAINCL = $(XSLT_PE_CFLAGS) $(XML2_PE_CFLAGS) +DELAYIMPORTS = bcrypt
SOURCES = \ attribute.c \ diff --git a/libs/xml2/HTMLparser.c b/libs/xml2/HTMLparser.c index ea6a4f265fd..22135929565 100644 --- a/libs/xml2/HTMLparser.c +++ b/libs/xml2/HTMLparser.c @@ -58,25 +58,9 @@ static void htmlParseComment(htmlParserCtxtPtr ctxt); * Handle a redefinition of attribute error */ static void -htmlErrMemory(xmlParserCtxtPtr ctxt, const char *extra) +htmlErrMemory(xmlParserCtxtPtr ctxt) { - if ((ctxt != NULL) && (ctxt->disableSAX != 0) && - (ctxt->instate == XML_PARSER_EOF)) - return; - if (ctxt != NULL) { - ctxt->errNo = XML_ERR_NO_MEMORY; - ctxt->instate = XML_PARSER_EOF; - ctxt->disableSAX = 1; - } - if (extra) - __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER, - XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra, - NULL, NULL, 0, 0, - "Memory allocation failed : %s\n", extra); - else - __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER, - XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL, - NULL, NULL, 0, 0, "Memory allocation failed\n"); + xmlCtxtErrMemory(ctxt); }
/** @@ -93,18 +77,8 @@ static void LIBXML_ATTR_FORMAT(3,0) htmlParseErr(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *msg, const xmlChar *str1, const xmlChar *str2) { - if ((ctxt != NULL) && (ctxt->disableSAX != 0) && - (ctxt->instate == XML_PARSER_EOF)) - return; - if (ctxt != NULL) - ctxt->errNo = error; - __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_HTML, error, - XML_ERR_ERROR, NULL, 0, - (const char *) str1, (const char *) str2, - NULL, 0, 0, - msg, str1, str2); - if (ctxt != NULL) - ctxt->wellFormed = 0; + xmlCtxtErr(ctxt, NULL, XML_FROM_HTML, error, XML_ERR_ERROR, + str1, str2, NULL, 0, msg, str1, str2); }
/** @@ -120,16 +94,8 @@ static void LIBXML_ATTR_FORMAT(3,0) htmlParseErrInt(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *msg, int val) { - if ((ctxt != NULL) && (ctxt->disableSAX != 0) && - (ctxt->instate == XML_PARSER_EOF)) - return; - if (ctxt != NULL) - ctxt->errNo = error; - __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_HTML, error, - XML_ERR_ERROR, NULL, 0, NULL, NULL, - NULL, val, 0, msg, val); - if (ctxt != NULL) - ctxt->wellFormed = 0; + xmlCtxtErr(ctxt, NULL, XML_FROM_HTML, error, XML_ERR_ERROR, + NULL, NULL, NULL, val, msg, val); }
/************************************************************************ @@ -161,7 +127,7 @@ htmlnamePush(htmlParserCtxtPtr ctxt, const xmlChar * value) tmp = xmlRealloc((xmlChar **) ctxt->nameTab, newSize * sizeof(ctxt->nameTab[0])); if (tmp == NULL) { - htmlErrMemory(ctxt, NULL); + htmlErrMemory(ctxt); return (-1); } ctxt->nameTab = tmp; @@ -219,7 +185,7 @@ htmlNodeInfoPush(htmlParserCtxtPtr ctxt, htmlParserNodeInfo *value) ctxt->nodeInfoMax * sizeof(ctxt->nodeInfoTab[0])); if (ctxt->nodeInfoTab == NULL) { - htmlErrMemory(ctxt, NULL); + htmlErrMemory(ctxt); return (0); } } @@ -289,13 +255,16 @@ htmlNodeInfoPop(htmlParserCtxtPtr ctxt) #define CUR_PTR ctxt->input->cur #define BASE_PTR ctxt->input->base
-#define SHRINK if ((ctxt->input->cur - ctxt->input->base > 2 * INPUT_CHUNK) && \ - (ctxt->input->end - ctxt->input->cur < 2 * INPUT_CHUNK)) \ - xmlParserShrink(ctxt) +#define SHRINK \ + if ((!PARSER_PROGRESSIVE(ctxt)) && \ + (ctxt->input->cur - ctxt->input->base > 2 * INPUT_CHUNK) && \ + (ctxt->input->end - ctxt->input->cur < 2 * INPUT_CHUNK)) \ + xmlParserShrink(ctxt);
-#define GROW if ((ctxt->progressive == 0) && \ - (ctxt->input->end - ctxt->input->cur < INPUT_CHUNK)) \ - xmlParserGrow(ctxt) +#define GROW \ + if ((!PARSER_PROGRESSIVE(ctxt)) && \ + (ctxt->input->end - ctxt->input->cur < INPUT_CHUNK)) \ + xmlParserGrow(ctxt);
#define SKIP_BLANKS htmlSkipBlankChars(ctxt)
@@ -304,14 +273,14 @@ htmlNodeInfoPop(htmlParserCtxtPtr ctxt) #define CUR (*ctxt->input->cur) #define NEXT xmlNextChar(ctxt)
-#define RAW (ctxt->token ? -1 : (*ctxt->input->cur)) +#define RAW (*ctxt->input->cur)
#define NEXTL(l) do { \ if (*(ctxt->input->cur) == '\n') { \ ctxt->input->line++; ctxt->input->col = 1; \ } else ctxt->input->col++; \ - ctxt->token = 0; ctxt->input->cur += l; \ + ctxt->input->cur += l; \ } while (0)
/************ @@ -343,6 +312,7 @@ htmlNodeInfoPop(htmlParserCtxtPtr ctxt) static xmlChar * htmlFindEncoding(xmlParserCtxtPtr ctxt) { const xmlChar *start, *cur, *end; + xmlChar *ret;
if ((ctxt == NULL) || (ctxt->input == NULL) || (ctxt->input->flags & XML_INPUT_HAS_ENCODING)) @@ -374,7 +344,10 @@ htmlFindEncoding(xmlParserCtxtPtr ctxt) { cur++; if (cur == start) return(NULL); - return(xmlStrndup(start, cur - start)); + ret = xmlStrndup(start, cur - start); + if (ret == NULL) + htmlErrMemory(ctxt); + return(ret); }
/** @@ -397,23 +370,11 @@ htmlCurrentChar(xmlParserCtxtPtr ctxt, int *len) { unsigned char c; unsigned int val;
- if (ctxt->instate == XML_PARSER_EOF) - return(0); - - if (ctxt->token != 0) { - *len = 0; - return(ctxt->token); - } - - if (ctxt->input->end - ctxt->input->cur < INPUT_CHUNK) { + if (ctxt->input->end - ctxt->input->cur < INPUT_CHUNK) xmlParserGrow(ctxt); - if (ctxt->instate == XML_PARSER_EOF) - return(0); - }
if ((ctxt->input->flags & XML_INPUT_HAS_ENCODING) == 0) { xmlChar * guess; - xmlCharEncodingHandlerPtr handler;
/* * Assume it's a fixed length encoding (1) with @@ -421,13 +382,18 @@ htmlCurrentChar(xmlParserCtxtPtr ctxt, int *len) { * HTML constructs only use < 128 chars */ if (*ctxt->input->cur < 0x80) { - *len = 1; - if ((*ctxt->input->cur == 0) && - (ctxt->input->cur < ctxt->input->end)) { - htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR, - "Char 0x%X out of allowed range\n", 0); - return(' '); + if (*ctxt->input->cur == 0) { + if (ctxt->input->cur < ctxt->input->end) { + htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR, + "Char 0x%X out of allowed range\n", 0); + *len = 1; + return(' '); + } else { + *len = 0; + return(0); + } } + *len = 1; return(*ctxt->input->cur); }
@@ -438,18 +404,7 @@ htmlCurrentChar(xmlParserCtxtPtr ctxt, int *len) { if (guess == NULL) { xmlSwitchEncoding(ctxt, XML_CHAR_ENCODING_8859_1); } else { - handler = xmlFindCharEncodingHandler((const char *) guess); - if (handler != NULL) { - /* - * Don't use UTF-8 encoder which isn't required and - * can produce invalid UTF-8. - */ - if (!xmlStrEqual(BAD_CAST handler->name, BAD_CAST "UTF-8")) - xmlSwitchToEncoding(ctxt, handler); - } else { - htmlParseErr(ctxt, XML_ERR_INVALID_ENCODING, - "Unsupported encoding %s", guess, NULL); - } + xmlSwitchEncodingName(ctxt, (const char *) guess); xmlFree(guess); } ctxt->input->flags |= XML_INPUT_HAS_ENCODING; @@ -516,12 +471,16 @@ htmlCurrentChar(xmlParserCtxtPtr ctxt, int *len) { } return(val); } else { - if ((*ctxt->input->cur == 0) && - (ctxt->input->cur < ctxt->input->end)) { - htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR, - "Char 0x%X out of allowed range\n", 0); - *len = 1; - return(' '); + if (*ctxt->input->cur == 0) { + if (ctxt->input->cur < ctxt->input->end) { + htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR, + "Char 0x%X out of allowed range\n", 0); + *len = 1; + return(' '); + } else { + *len = 0; + return(0); + } } /* 1-byte code */ *len = 1; @@ -529,20 +488,7 @@ htmlCurrentChar(xmlParserCtxtPtr ctxt, int *len) { }
encoding_error: - { - char buffer[150]; - - if (ctxt->input->end - ctxt->input->cur >= 4) { - 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]); - } else { - snprintf(buffer, 149, "Bytes: 0x%02X\n", ctxt->input->cur[0]); - } - htmlParseErr(ctxt, XML_ERR_INVALID_ENCODING, - "Input is not proper UTF-8, indicate encoding !\n", - BAD_CAST buffer, NULL); - } + xmlCtxtErrIO(ctxt, XML_ERR_INVALID_ENCODING, NULL);
if ((ctxt->input->flags & XML_INPUT_HAS_ENCODING) == 0) xmlSwitchEncoding(ctxt, XML_CHAR_ENCODING_8859_1); @@ -2035,7 +1981,7 @@ static const htmlEntityDesc html40EntitiesTable[] = { buffer##_size *= 2; \ tmp = (xmlChar *) xmlRealloc(buffer, buffer##_size); \ if (tmp == NULL) { \ - htmlErrMemory(ctxt, "growing buffer\n"); \ + htmlErrMemory(ctxt); \ xmlFree(buffer); \ return(NULL); \ } \ @@ -2065,6 +2011,14 @@ htmlEntityLookup(const xmlChar *name) { return(NULL); }
+static int +htmlCompareEntityDesc(const void *vkey, const void *vdesc) { + const unsigned *key = vkey; + const htmlEntityDesc *desc = vdesc; + + return((int) *key - (int) desc->value); +} + /** * htmlEntityValueLookup: * @value: the entity's unicode value @@ -2077,17 +2031,14 @@ htmlEntityLookup(const xmlChar *name) { */ const htmlEntityDesc * htmlEntityValueLookup(unsigned int value) { - unsigned int i; + const htmlEntityDesc *desc; + size_t nmemb;
- for (i = 0;i < (sizeof(html40EntitiesTable)/ - sizeof(html40EntitiesTable[0]));i++) { - if (html40EntitiesTable[i].value >= value) { - if (html40EntitiesTable[i].value > value) - break; - return((htmlEntityDescPtr) &html40EntitiesTable[i]); - } - } - return(NULL); + nmemb = sizeof(html40EntitiesTable) / sizeof(html40EntitiesTable[0]); + desc = bsearch(&value, html40EntitiesTable, nmemb, sizeof(htmlEntityDesc), + htmlCompareEntityDesc); + + return(desc); }
/** @@ -2292,47 +2243,6 @@ htmlEncodeEntities(unsigned char* out, int *outlen, return(0); }
-/************************************************************************ - * * - * Commodity functions to handle streams * - * * - ************************************************************************/ - -#ifdef LIBXML_PUSH_ENABLED -/** - * htmlNewInputStream: - * @ctxt: an HTML parser context - * - * Create a new input stream structure - * Returns the new input stream or NULL - */ -static htmlParserInputPtr -htmlNewInputStream(htmlParserCtxtPtr ctxt) { - htmlParserInputPtr input; - - input = (xmlParserInputPtr) xmlMalloc(sizeof(htmlParserInput)); - if (input == NULL) { - htmlErrMemory(ctxt, "couldn't allocate a new input stream\n"); - return(NULL); - } - memset(input, 0, sizeof(htmlParserInput)); - input->filename = NULL; - input->directory = NULL; - input->base = NULL; - input->cur = NULL; - input->buf = NULL; - input->line = 1; - input->col = 1; - input->buf = NULL; - input->free = NULL; - input->version = NULL; - input->consumed = 0; - input->length = 0; - return(input); -} -#endif - - /************************************************************************ * * * Commodity functions, cleanup needed ? * @@ -2438,10 +2348,8 @@ htmlNewDocNoDtD(const xmlChar *URI, const xmlChar *ExternalID) { * Allocate a new document and fill the fields. */ cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc)); - if (cur == NULL) { - htmlErrMemory(NULL, "HTML document creation failed\n"); + if (cur == NULL) return(NULL); - } memset(cur, 0, sizeof(xmlDoc));
cur->type = XML_HTML_DOCUMENT_NODE; @@ -2461,8 +2369,15 @@ htmlNewDocNoDtD(const xmlChar *URI, const xmlChar *ExternalID) { cur->charset = XML_CHAR_ENCODING_UTF8; cur->properties = XML_DOC_HTML | XML_DOC_USERBUILT; if ((ExternalID != NULL) || - (URI != NULL)) - xmlCreateIntSubset(cur, BAD_CAST "html", ExternalID, URI); + (URI != NULL)) { + xmlDtdPtr intSubset; + + intSubset = xmlCreateIntSubset(cur, BAD_CAST "html", ExternalID, URI); + if (intSubset == NULL) { + xmlFree(cur); + return(NULL); + } + } if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) xmlRegisterNodeDefaultValue((xmlNodePtr)cur); return(cur); @@ -2510,12 +2425,14 @@ htmlSkipBogusComment(htmlParserCtxtPtr ctxt) { htmlParseErr(ctxt, XML_HTML_INCORRECTLY_OPENED_COMMENT, "Incorrectly opened comment\n", NULL, NULL);
- do { + while (PARSER_STOPPED(ctxt) == 0) { c = CUR; if (c == 0) break; NEXT; - } while (c != '>'); + if (c == '>') + break; + } }
/** @@ -2550,7 +2467,7 @@ htmlParseHTMLName(htmlParserCtxtPtr ctxt) {
ret = xmlDictLookup(ctxt->dict, loc, i); if (ret == NULL) - htmlErrMemory(ctxt, NULL); + htmlErrMemory(ctxt);
return(ret); } @@ -2571,6 +2488,7 @@ static const xmlChar * htmlParseHTMLName_nonInvasive(htmlParserCtxtPtr ctxt) { int i = 0; xmlChar loc[HTML_PARSER_BUFFER_SIZE]; + const xmlChar *ret;
if (!IS_ASCII_LETTER(NXT(1)) && (NXT(1) != '_') && (NXT(1) != ':')) return(NULL); @@ -2583,7 +2501,11 @@ htmlParseHTMLName_nonInvasive(htmlParserCtxtPtr ctxt) { i++; }
- return(xmlDictLookup(ctxt->dict, loc, i)); + ret = xmlDictLookup(ctxt->dict, loc, i); + if (ret == NULL) + htmlErrMemory(ctxt); + + return(ret); }
@@ -2625,6 +2547,8 @@ htmlParseName(htmlParserCtxtPtr ctxt) { if ((*in > 0) && (*in < 0x80)) { count = in - ctxt->input->cur; ret = xmlDictLookup(ctxt->dict, ctxt->input->cur, count); + if (ret == NULL) + htmlErrMemory(ctxt); ctxt->input->cur = in; ctxt->input->col += count; return(ret); @@ -2641,6 +2565,7 @@ htmlParseNameComplex(xmlParserCtxtPtr ctxt) { XML_MAX_TEXT_LENGTH : XML_MAX_NAME_LENGTH; const xmlChar *base = ctxt->input->base; + const xmlChar *ret;
/* * Handler for more complex cases @@ -2673,8 +2598,6 @@ htmlParseNameComplex(xmlParserCtxtPtr ctxt) { return(htmlParseNameComplex(ctxt)); } } - if (ctxt->instate == XML_PARSER_EOF) - return(NULL);
if (ctxt->input->cur - ctxt->input->base < len) { /* Sanity check */ @@ -2683,7 +2606,11 @@ htmlParseNameComplex(xmlParserCtxtPtr ctxt) { return (NULL); }
- return(xmlDictLookup(ctxt->dict, ctxt->input->cur - len, len)); + ret = xmlDictLookup(ctxt->dict, ctxt->input->cur - len, len); + if (ret == NULL) + htmlErrMemory(ctxt); + + return(ret); }
@@ -2716,7 +2643,7 @@ htmlParseHTMLAttribute(htmlParserCtxtPtr ctxt, const xmlChar stop) { buffer_size = HTML_PARSER_BUFFER_SIZE; buffer = (xmlChar *) xmlMallocAtomic(buffer_size); if (buffer == NULL) { - htmlErrMemory(ctxt, "buffer allocation failed\n"); + htmlErrMemory(ctxt); return(NULL); } out = buffer; @@ -2724,7 +2651,8 @@ htmlParseHTMLAttribute(htmlParserCtxtPtr ctxt, const xmlChar stop) { /* * Ok loop until we reach one of the ending chars */ - while ((CUR != 0) && (CUR != stop)) { + while ((PARSER_STOPPED(ctxt) == 0) && + (CUR != 0) && (CUR != stop)) { if ((stop == 0) && (CUR == '>')) break; if ((stop == 0) && (IS_BLANK_CH(CUR))) break; if (CUR == '&') { @@ -2810,10 +2738,6 @@ htmlParseHTMLAttribute(htmlParserCtxtPtr ctxt, const xmlChar stop) { out = &buffer[indx]; } c = CUR_CHAR(l); - if (ctxt->instate == XML_PARSER_EOF) { - xmlFree(buffer); - return(NULL); - } if (c < 0x80) { *out++ = c; bits= -6; } else if (c < 0x800) @@ -2966,7 +2890,8 @@ htmlParseSystemLiteral(htmlParserCtxtPtr ctxt) { return(ret); startPosition = CUR_PTR - BASE_PTR;
- while ((CUR != 0) && (CUR != quote)) { + while ((PARSER_STOPPED(ctxt) == 0) && + (CUR != 0) && (CUR != quote)) { /* TODO: Handle UTF-8 */ if (!IS_CHAR_CH(CUR)) { htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR, @@ -2980,8 +2905,13 @@ htmlParseSystemLiteral(htmlParserCtxtPtr ctxt) { htmlParseErr(ctxt, XML_ERR_LITERAL_NOT_FINISHED, "Unfinished SystemLiteral\n", NULL, NULL); } else { - if (err == 0) + if (err == 0) { ret = xmlStrndup((BASE_PTR+startPosition), len); + if (ret == NULL) { + htmlErrMemory(ctxt); + return(NULL); + } + } NEXT; }
@@ -3021,7 +2951,8 @@ htmlParsePubidLiteral(htmlParserCtxtPtr ctxt) { return(ret); startPosition = CUR_PTR - BASE_PTR;
- while ((CUR != 0) && (CUR != quote)) { + while ((PARSER_STOPPED(ctxt) == 0) && + (CUR != 0) && (CUR != quote)) { if (!IS_PUBIDCHAR_CH(CUR)) { htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR, "Invalid char in PubidLiteral 0x%X\n", CUR); @@ -3035,8 +2966,13 @@ htmlParsePubidLiteral(htmlParserCtxtPtr ctxt) { htmlParseErr(ctxt, XML_ERR_LITERAL_NOT_FINISHED, "Unfinished PubidLiteral\n", NULL, NULL); } else { - if (err == 0) + if (err == 0) { ret = xmlStrndup((BASE_PTR + startPosition), len); + if (ret == NULL) { + htmlErrMemory(ctxt); + return(NULL); + } + } NEXT; }
@@ -3125,9 +3061,6 @@ htmlParseScript(htmlParserCtxtPtr ctxt) { cur = CUR_CHAR(l); }
- if (ctxt->instate == XML_PARSER_EOF) - return; - if ((nbchar != 0) && (ctxt->sax != NULL) && (!ctxt->disableSAX)) { buf[nbchar] = 0; if (ctxt->sax->cdataBlock!= NULL) { @@ -3163,9 +3096,10 @@ htmlParseCharDataInternal(htmlParserCtxtPtr ctxt, int readahead) { buf[nbchar++] = readahead;
cur = CUR_CHAR(l); - while (((cur != '<') || (ctxt->token == '<')) && - ((cur != '&') || (ctxt->token == '&')) && - (cur != 0)) { + while ((cur != '<') && + (cur != '&') && + (cur != 0) && + (!PARSER_STOPPED(ctxt))) { if (!(IS_CHAR(cur))) { htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR, "Invalid char in CDATA 0x%X\n", cur); @@ -3200,8 +3134,6 @@ htmlParseCharDataInternal(htmlParserCtxtPtr ctxt, int readahead) { } cur = CUR_CHAR(l); } - if (ctxt->instate == XML_PARSER_EOF) - return; if (nbchar != 0) { buf[nbchar] = 0;
@@ -3301,12 +3233,11 @@ htmlParseExternalID(htmlParserCtxtPtr ctxt, xmlChar **publicID) { }
/** - * xmlParsePI: - * @ctxt: an XML parser context - * - * parse an XML Processing Instruction. + * htmlParsePI: + * @ctxt: an HTML parser context * - * [16] PI ::= '<?' PITarget (S (Char* - (Char* '?>' Char*)))? '?>' + * Parse an XML Processing Instruction. HTML5 doesn't allow processing + * instructions, so this will be removed at some point. */ static void htmlParsePI(htmlParserCtxtPtr ctxt) { @@ -3344,13 +3275,11 @@ htmlParsePI(htmlParserCtxtPtr ctxt) { (ctxt->sax->processingInstruction != NULL)) ctxt->sax->processingInstruction(ctxt->userData, target, NULL); - ctxt->instate = state; - return; + goto done; } buf = (xmlChar *) xmlMallocAtomic(size); if (buf == NULL) { - htmlErrMemory(ctxt, NULL); - ctxt->instate = state; + htmlErrMemory(ctxt); return; } cur = CUR; @@ -3367,9 +3296,8 @@ htmlParsePI(htmlParserCtxtPtr ctxt) { size *= 2; tmp = (xmlChar *) xmlRealloc(buf, size); if (tmp == NULL) { - htmlErrMemory(ctxt, NULL); + htmlErrMemory(ctxt); xmlFree(buf); - ctxt->instate = state; return; } buf = tmp; @@ -3385,17 +3313,12 @@ htmlParsePI(htmlParserCtxtPtr ctxt) { htmlParseErr(ctxt, XML_ERR_PI_NOT_FINISHED, "PI %s too long", target, NULL); xmlFree(buf); - ctxt->instate = state; - return; + goto done; } NEXTL(l); cur = CUR_CHAR(l); } buf[len] = 0; - if (ctxt->instate == XML_PARSER_EOF) { - xmlFree(buf); - return; - } if (cur != '>') { htmlParseErr(ctxt, XML_ERR_PI_NOT_FINISHED, "ParsePI: PI %s never end ...\n", target, NULL); @@ -3415,6 +3338,8 @@ htmlParsePI(htmlParserCtxtPtr ctxt) { htmlParseErr(ctxt, XML_ERR_PI_NOT_STARTED, "PI is not started correctly", NULL, NULL); } + +done: ctxt->instate = state; } } @@ -3423,9 +3348,7 @@ htmlParsePI(htmlParserCtxtPtr ctxt) { * htmlParseComment: * @ctxt: an HTML parser context * - * Parse an XML (SGML) comment <!-- .... --> - * - * [15] Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->' + * Parse an HTML comment */ static void htmlParseComment(htmlParserCtxtPtr ctxt) { @@ -3452,8 +3375,7 @@ htmlParseComment(htmlParserCtxtPtr ctxt) { SKIP(4); buf = (xmlChar *) xmlMallocAtomic(size); if (buf == NULL) { - htmlErrMemory(ctxt, "buffer allocation failed\n"); - ctxt->instate = state; + htmlErrMemory(ctxt); return; } len = 0; @@ -3497,8 +3419,7 @@ htmlParseComment(htmlParserCtxtPtr ctxt) { tmp = (xmlChar *) xmlRealloc(buf, size); if (tmp == NULL) { xmlFree(buf); - htmlErrMemory(ctxt, "growing buffer failed\n"); - ctxt->instate = state; + htmlErrMemory(ctxt); return; } buf = tmp; @@ -3526,10 +3447,6 @@ htmlParseComment(htmlParserCtxtPtr ctxt) { } finished: buf[len] = 0; - if (ctxt->instate == XML_PARSER_EOF) { - xmlFree(buf); - return; - } if (cur == '>') { NEXT; if ((ctxt->sax != NULL) && (ctxt->sax->comment != NULL) && @@ -3563,12 +3480,8 @@ int htmlParseCharRef(htmlParserCtxtPtr ctxt) { int val = 0;
- if ((ctxt == NULL) || (ctxt->input == NULL)) { - htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR, - "htmlParseCharRef: context error\n", - NULL, NULL); + if ((ctxt == NULL) || (ctxt->input == NULL)) return(0); - } if ((CUR == '&') && (NXT(1) == '#') && ((NXT(2) == 'x') || NXT(2) == 'X')) { SKIP(3); @@ -3681,7 +3594,7 @@ htmlParseDocTypeDecl(htmlParserCtxtPtr ctxt) { "DOCTYPE improperly terminated\n", NULL, NULL); /* Ignore bogus content */ while ((CUR != 0) && (CUR != '>') && - (ctxt->instate != XML_PARSER_EOF)) + (PARSER_STOPPED(ctxt) == 0)) NEXT; } if (CUR == '>') @@ -3762,6 +3675,7 @@ htmlParseAttribute(htmlParserCtxtPtr ctxt, xmlChar **value) { static void htmlCheckEncoding(htmlParserCtxtPtr ctxt, const xmlChar *attvalue) { const xmlChar *encoding; + xmlChar *copy;
if (!attvalue) return; @@ -3777,7 +3691,10 @@ htmlCheckEncoding(htmlParserCtxtPtr ctxt, const xmlChar *attvalue) { encoding = xmlStrcasestr(attvalue, BAD_CAST"="); if (encoding && *encoding == '=') { encoding ++; - xmlSetDeclaredEncoding(ctxt, xmlStrdup(encoding)); + copy = xmlStrdup(encoding); + if (copy == NULL) + htmlErrMemory(ctxt); + xmlSetDeclaredEncoding(ctxt, copy); } }
@@ -3802,13 +3719,21 @@ htmlCheckMeta(htmlParserCtxtPtr ctxt, const xmlChar **atts) { att = atts[i++]; while (att != NULL) { value = atts[i++]; - if ((value != NULL) && (!xmlStrcasecmp(att, BAD_CAST"http-equiv")) - && (!xmlStrcasecmp(value, BAD_CAST"Content-Type"))) - http = 1; - else if ((value != NULL) && (!xmlStrcasecmp(att, BAD_CAST"charset"))) - xmlSetDeclaredEncoding(ctxt, xmlStrdup(value)); - else if ((value != NULL) && (!xmlStrcasecmp(att, BAD_CAST"content"))) - content = value; + if (value != NULL) { + if ((!xmlStrcasecmp(att, BAD_CAST "http-equiv")) && + (!xmlStrcasecmp(value, BAD_CAST "Content-Type"))) { + http = 1; + } else if (!xmlStrcasecmp(att, BAD_CAST "charset")) { + xmlChar *copy; + + copy = xmlStrdup(value); + if (copy == NULL) + htmlErrMemory(ctxt); + xmlSetDeclaredEncoding(ctxt, copy); + } else if (!xmlStrcasecmp(att, BAD_CAST "content")) { + content = value; + } + } att = atts[i++]; } if ((http) && (content != NULL)) @@ -3848,13 +3773,8 @@ htmlParseStartTag(htmlParserCtxtPtr ctxt) { int i; int discardtag = 0;
- if ((ctxt == NULL) || (ctxt->input == NULL)) { - htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR, - "htmlParseStartTag: context error\n", NULL, NULL); + if ((ctxt == NULL) || (ctxt->input == NULL)) return -1; - } - if (ctxt->instate == XML_PARSER_EOF) - return(-1); if (CUR != '<') return -1; NEXT;
@@ -3869,7 +3789,7 @@ htmlParseStartTag(htmlParserCtxtPtr ctxt) { NULL, NULL); /* Dump the bogus tag like browsers do */ while ((CUR != 0) && (CUR != '>') && - (ctxt->instate != XML_PARSER_EOF)) + (PARSER_STOPPED(ctxt) == 0)) NEXT; return -1; } @@ -3927,7 +3847,7 @@ htmlParseStartTag(htmlParserCtxtPtr ctxt) { while ((CUR != 0) && (CUR != '>') && ((CUR != '/') || (NXT(1) != '>')) && - (ctxt->instate != XML_PARSER_EOF)) { + (PARSER_STOPPED(ctxt) == 0)) { GROW; attname = htmlParseAttribute(ctxt, &attvalue); if (attname != NULL) { @@ -3953,7 +3873,7 @@ htmlParseStartTag(htmlParserCtxtPtr ctxt) { atts = (const xmlChar **) xmlMalloc(maxatts * sizeof(xmlChar *)); if (atts == NULL) { - htmlErrMemory(ctxt, NULL); + htmlErrMemory(ctxt); if (attvalue != NULL) xmlFree(attvalue); goto failed; @@ -3967,7 +3887,7 @@ htmlParseStartTag(htmlParserCtxtPtr ctxt) { n = (const xmlChar **) xmlRealloc((void *) atts, maxatts * sizeof(const xmlChar *)); if (n == NULL) { - htmlErrMemory(ctxt, NULL); + htmlErrMemory(ctxt); if (attvalue != NULL) xmlFree(attvalue); goto failed; @@ -3989,7 +3909,7 @@ htmlParseStartTag(htmlParserCtxtPtr ctxt) { while ((CUR != 0) && !(IS_BLANK_CH(CUR)) && (CUR != '>') && ((CUR != '/') || (NXT(1) != '>')) && - (ctxt->instate != XML_PARSER_EOF)) + (PARSER_STOPPED(ctxt) == 0)) NEXT; }
@@ -4066,7 +3986,8 @@ htmlParseEndTag(htmlParserCtxtPtr ctxt) htmlParseErr(ctxt, XML_ERR_GT_REQUIRED, "End tag : expected '>'\n", NULL, NULL); /* Skip to next '>' */ - while ((CUR != 0) && (CUR != '>')) + while ((PARSER_STOPPED(ctxt) == 0) && + (CUR != 0) && (CUR != '>')) NEXT; } if (CUR == '>') @@ -4227,12 +4148,9 @@ htmlParseContent(htmlParserCtxtPtr ctxt) {
currentNode = xmlStrdup(ctxt->name); depth = ctxt->nameNr; - while (1) { + while (!PARSER_STOPPED(ctxt)) { GROW;
- if (ctxt->instate == XML_PARSER_EOF) - break; - /* * Our tag or one of it's parent or children is ending. */ @@ -4387,14 +4305,8 @@ htmlParseElement(htmlParserCtxtPtr ctxt) { int depth; const xmlChar *oldptr;
- if ((ctxt == NULL) || (ctxt->input == NULL)) { - htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR, - "htmlParseElement: context error\n", NULL, NULL); + if ((ctxt == NULL) || (ctxt->input == NULL)) return; - } - - if (ctxt->instate == XML_PARSER_EOF) - return;
/* Capture start position */ if (ctxt->record_info) { @@ -4534,14 +4446,8 @@ htmlParseElementInternal(htmlParserCtxtPtr ctxt) { htmlParserNodeInfo node_info = { NULL, 0, 0, 0, 0 }; int failed;
- if ((ctxt == NULL) || (ctxt->input == NULL)) { - htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR, - "htmlParseElementInternal: context error\n", NULL, NULL); + if ((ctxt == NULL) || (ctxt->input == NULL)) return; - } - - if (ctxt->instate == XML_PARSER_EOF) - return;
/* Capture start position */ if (ctxt->record_info) { @@ -4632,16 +4538,13 @@ htmlParseContentInternal(htmlParserCtxtPtr ctxt) { } else { currentNode = xmlStrdup(ctxt->name); if (currentNode == NULL) { - htmlErrMemory(ctxt, NULL); + htmlErrMemory(ctxt); return; } } - while (1) { + while (PARSER_STOPPED(ctxt) == 0) { GROW;
- if (ctxt->instate == XML_PARSER_EOF) - break; - /* * Our tag or one of it's parent or children is ending. */ @@ -4657,7 +4560,7 @@ htmlParseContentInternal(htmlParserCtxtPtr ctxt) { } else { currentNode = xmlStrdup(ctxt->name); if (currentNode == NULL) { - htmlErrMemory(ctxt, NULL); + htmlErrMemory(ctxt); break; } } @@ -4681,10 +4584,14 @@ htmlParseContentInternal(htmlParserCtxtPtr ctxt) { if (currentNode != NULL) xmlFree(currentNode);
- currentNode = xmlStrdup(ctxt->name); - if (currentNode == NULL) { - htmlErrMemory(ctxt, NULL); - break; + if (ctxt->name == NULL) { + currentNode = NULL; + } else { + currentNode = xmlStrdup(ctxt->name); + if (currentNode == NULL) { + htmlErrMemory(ctxt); + break; + } } depth = ctxt->nameNr; continue; @@ -4708,10 +4615,14 @@ htmlParseContentInternal(htmlParserCtxtPtr ctxt) { htmlParserFinishElementParsing(ctxt); if (currentNode != NULL) xmlFree(currentNode);
- currentNode = xmlStrdup(ctxt->name); - if (currentNode == NULL) { - htmlErrMemory(ctxt, NULL); - break; + if (ctxt->name == NULL) { + currentNode = NULL; + } else { + currentNode = xmlStrdup(ctxt->name); + if (currentNode == NULL) { + htmlErrMemory(ctxt); + break; + } } depth = ctxt->nameNr; continue; @@ -4763,10 +4674,14 @@ htmlParseContentInternal(htmlParserCtxtPtr ctxt) { htmlParseElementInternal(ctxt); if (currentNode != NULL) xmlFree(currentNode);
- currentNode = xmlStrdup(ctxt->name); - if (currentNode == NULL) { - htmlErrMemory(ctxt, NULL); - break; + if (ctxt->name == NULL) { + currentNode = NULL; + } else { + currentNode = xmlStrdup(ctxt->name); + if (currentNode == NULL) { + htmlErrMemory(ctxt); + break; + } } depth = ctxt->nameNr; } @@ -4824,31 +4739,25 @@ __htmlParseContent(void *ctxt) { * htmlParseDocument: * @ctxt: an HTML parser context * - * parse an HTML document (and build a tree if using the standard SAX - * interface). + * Parse an HTML document and invoke the SAX handlers. This is useful + * if you're only interested in custom SAX callbacks. If you want a + * document tree, use htmlCtxtParseDocument. * - * Returns 0, -1 in case of error. the parser context is augmented - * as a result of the parsing. + * Returns 0, -1 in case of error. */
int htmlParseDocument(htmlParserCtxtPtr ctxt) { xmlDtdPtr dtd;
- xmlInitParser(); + if ((ctxt == NULL) || (ctxt->input == NULL)) + return(-1);
- if ((ctxt == NULL) || (ctxt->input == NULL)) { - htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR, - "htmlParseDocument: context error\n", NULL, NULL); - return(XML_ERR_INTERNAL_ERROR); + if ((ctxt->sax) && (ctxt->sax->setDocumentLocator)) { + ctxt->sax->setDocumentLocator(ctxt->userData, + (xmlSAXLocator *) &xmlDefaultSAXLocator); }
- /* - * SAX: beginning of the document processing. - */ - if ((ctxt->sax) && (ctxt->sax->setDocumentLocator)) - ctxt->sax->setDocumentLocator(ctxt->userData, &xmlDefaultSAXLocator); - xmlDetectEncoding(ctxt);
/* @@ -4871,7 +4780,6 @@ htmlParseDocument(htmlParserCtxtPtr ctxt) { if ((ctxt->sax) && (ctxt->sax->startDocument) && (!ctxt->disableSAX)) ctxt->sax->startDocument(ctxt->userData);
- /* * Parse possible comments and PIs before any content */ @@ -4900,9 +4808,10 @@ htmlParseDocument(htmlParserCtxtPtr ctxt) { /* * Parse possible comments and PIs before any content */ - while (((CUR == '<') && (NXT(1) == '!') && - (NXT(2) == '-') && (NXT(3) == '-')) || - ((CUR == '<') && (NXT(1) == '?'))) { + while ((PARSER_STOPPED(ctxt) == 0) && + (((CUR == '<') && (NXT(1) == '!') && + (NXT(2) == '-') && (NXT(3) == '-')) || + ((CUR == '<') && (NXT(1) == '?')))) { htmlParseComment(ctxt); htmlParsePI(ctxt); SKIP_BLANKS; @@ -4928,11 +4837,14 @@ htmlParseDocument(htmlParserCtxtPtr ctxt) {
if ((!(ctxt->options & HTML_PARSE_NODEFDTD)) && (ctxt->myDoc != NULL)) { dtd = xmlGetIntSubset(ctxt->myDoc); - if (dtd == NULL) + if (dtd == NULL) { ctxt->myDoc->intSubset = xmlCreateIntSubset(ctxt->myDoc, BAD_CAST "html", BAD_CAST "-//W3C//DTD HTML 4.0 Transitional//EN", BAD_CAST "http://www.w3.org/TR/REC-html40/loose.dtd"); + if (ctxt->myDoc->intSubset == NULL) + htmlErrMemory(ctxt); + } } if (! ctxt->wellFormed) return(-1); return(0); @@ -4964,17 +4876,13 @@ htmlInitParserCtxt(htmlParserCtxtPtr ctxt, const htmlSAXHandler *sax, memset(ctxt, 0, sizeof(htmlParserCtxt));
ctxt->dict = xmlDictCreate(); - if (ctxt->dict == NULL) { - htmlErrMemory(NULL, "htmlInitParserCtxt: out of memory\n"); + if (ctxt->dict == NULL) return(-1); - }
if (ctxt->sax == NULL) ctxt->sax = (htmlSAXHandler *) xmlMalloc(sizeof(htmlSAXHandler)); - if (ctxt->sax == NULL) { - htmlErrMemory(NULL, "htmlInitParserCtxt: out of memory\n"); + if (ctxt->sax == NULL) return(-1); - } if (sax == NULL) { memset(ctxt->sax, 0, sizeof(htmlSAXHandler)); xmlSAX2InitHtmlDefaultSAXHandler(ctxt->sax); @@ -4987,13 +4895,8 @@ htmlInitParserCtxt(htmlParserCtxtPtr ctxt, const htmlSAXHandler *sax, /* Allocate the Input stack */ ctxt->inputTab = (htmlParserInputPtr *) xmlMalloc(5 * sizeof(htmlParserInputPtr)); - if (ctxt->inputTab == NULL) { - htmlErrMemory(NULL, "htmlInitParserCtxt: out of memory\n"); - ctxt->inputNr = 0; - ctxt->inputMax = 0; - ctxt->input = NULL; + if (ctxt->inputTab == NULL) return(-1); - } ctxt->inputNr = 0; ctxt->inputMax = 5; ctxt->input = NULL; @@ -5004,35 +4907,16 @@ htmlInitParserCtxt(htmlParserCtxtPtr ctxt, const htmlSAXHandler *sax,
/* Allocate the Node stack */ ctxt->nodeTab = (htmlNodePtr *) xmlMalloc(10 * sizeof(htmlNodePtr)); - if (ctxt->nodeTab == NULL) { - htmlErrMemory(NULL, "htmlInitParserCtxt: out of memory\n"); - ctxt->nodeNr = 0; - ctxt->nodeMax = 0; - ctxt->node = NULL; - ctxt->inputNr = 0; - ctxt->inputMax = 0; - ctxt->input = NULL; + if (ctxt->nodeTab == NULL) return(-1); - } ctxt->nodeNr = 0; ctxt->nodeMax = 10; ctxt->node = NULL;
/* Allocate the Name stack */ ctxt->nameTab = (const xmlChar **) xmlMalloc(10 * sizeof(xmlChar *)); - if (ctxt->nameTab == NULL) { - htmlErrMemory(NULL, "htmlInitParserCtxt: out of memory\n"); - ctxt->nameNr = 0; - ctxt->nameMax = 0; - ctxt->name = NULL; - ctxt->nodeNr = 0; - ctxt->nodeMax = 0; - ctxt->node = NULL; - ctxt->inputNr = 0; - ctxt->inputMax = 0; - ctxt->input = NULL; + if (ctxt->nameTab == NULL) return(-1); - } ctxt->nameNr = 0; ctxt->nameMax = 10; ctxt->name = NULL; @@ -5076,7 +4960,19 @@ htmlFreeParserCtxt(htmlParserCtxtPtr ctxt) /** * htmlNewParserCtxt: * - * Allocate and initialize a new parser context. + * Allocate and initialize a new HTML parser context. + * + * This can be used to parse HTML documents into DOM trees with + * functions like xmlCtxtReadFile or xmlCtxtReadMemory. + * + * See htmlCtxtUseOptions for parser options. + * + * See xmlCtxtSetErrorHandler for advanced error handling. + * + * See xmlNewInputURL, xmlNewInputMemory, xmlNewInputIO and similar + * functions for advanced input control. + * + * See htmlNewSAXParserCtxt for custom SAX parsers. * * Returns the htmlParserCtxtPtr or NULL in case of allocation error */ @@ -5092,8 +4988,14 @@ htmlNewParserCtxt(void) * @sax: SAX handler * @userData: user data * - * Allocate and initialize a new SAX parser context. If userData is NULL, - * the parser context will be passed as user data. + * Allocate and initialize a new HTML SAX parser context. If userData + * is NULL, the parser context will be passed as user data. + * + * Available since 2.11.0. If you want support older versions, + * it's best to invoke htmlNewParserCtxt and set ctxt->sax with + * struct assignment. + * + * Also see htmlNewParserCtxt. * * Returns the htmlParserCtxtPtr or NULL in case of allocation error */ @@ -5103,11 +5005,11 @@ htmlNewSAXParserCtxt(const htmlSAXHandler *sax, void *userData) { xmlParserCtxtPtr ctxt;
+ xmlInitParser(); + ctxt = (xmlParserCtxtPtr) xmlMalloc(sizeof(xmlParserCtxt)); - if (ctxt == NULL) { - htmlErrMemory(NULL, "NewParserCtxt: out of memory\n"); + if (ctxt == NULL) return(NULL); - } memset(ctxt, 0, sizeof(xmlParserCtxt)); if (htmlInitParserCtxt(ctxt, sax, userData) < 0) { htmlFreeParserCtxt(ctxt); @@ -5116,67 +5018,65 @@ htmlNewSAXParserCtxt(const htmlSAXHandler *sax, void *userData) return(ctxt); }
-/** - * htmlCreateMemoryParserCtxt: - * @buffer: a pointer to a char array - * @size: the size of the array - * - * Create a parser context for an HTML in-memory document. - * - * Returns the new parser context or NULL - */ -htmlParserCtxtPtr -htmlCreateMemoryParserCtxt(const char *buffer, int size) { +static htmlParserCtxtPtr +htmlCreateMemoryParserCtxtInternal(const char *url, + const char *buffer, size_t size, + const char *encoding) { xmlParserCtxtPtr ctxt; xmlParserInputPtr input; - xmlParserInputBufferPtr buf;
if (buffer == NULL) return(NULL); - if (size <= 0) - return(NULL);
ctxt = htmlNewParserCtxt(); if (ctxt == NULL) return(NULL);
- buf = xmlParserInputBufferCreateMem(buffer, size, XML_CHAR_ENCODING_NONE); - if (buf == NULL) { - xmlFreeParserCtxt(ctxt); - return(NULL); - } - - input = xmlNewInputStream(ctxt); + input = xmlNewInputMemory(ctxt, url, buffer, size, encoding, 0); if (input == NULL) { - xmlFreeParserInputBuffer(buf); xmlFreeParserCtxt(ctxt); - return(NULL); + return(NULL); }
- input->filename = NULL; - input->buf = buf; - xmlBufResetInput(buf->buffer, input); - inputPush(ctxt, input); + return(ctxt); }
/** - * htmlCreateDocParserCtxt: - * @str: a pointer to an array of xmlChar - * @encoding: a free form C string describing the HTML document encoding, or NULL + * htmlCreateMemoryParserCtxt: + * @buffer: a pointer to a char array + * @size: the size of the array * - * Create a parser context for an HTML document. + * DEPRECATED: Use htmlNewParserCtxt and htmlCtxtReadMemory. * - * TODO: check the need to add encoding handling there + * Create a parser context for an HTML in-memory document. The input + * buffer must not contain any terminating null bytes. * * Returns the new parser context or NULL */ +htmlParserCtxtPtr +htmlCreateMemoryParserCtxt(const char *buffer, int size) { + if (size <= 0) + return(NULL); + + return(htmlCreateMemoryParserCtxtInternal(NULL, buffer, size, NULL)); +} + +/** + * htmlCreateDocParserCtxt: + * @str: a pointer to an array of xmlChar + * @encoding: encoding (optional) + * + * Create a parser context for a null-terminated string. + * + * Returns the new parser context or NULL if a memory allocation failed. + */ static htmlParserCtxtPtr -htmlCreateDocParserCtxt(const xmlChar *str, const char *encoding) { +htmlCreateDocParserCtxt(const xmlChar *str, const char *url, + const char *encoding) { xmlParserCtxtPtr ctxt; xmlParserInputPtr input; - xmlParserInputBufferPtr buf;
if (str == NULL) return(NULL); @@ -5185,55 +5085,14 @@ htmlCreateDocParserCtxt(const xmlChar *str, const char *encoding) { if (ctxt == NULL) return(NULL);
- buf = xmlParserInputBufferCreateString(str); - if (buf == NULL) { - xmlFreeParserCtxt(ctxt); - return(NULL); - } - - input = xmlNewInputStream(ctxt); + input = xmlNewInputString(ctxt, url, (const char *) str, encoding, 0); if (input == NULL) { - xmlFreeParserInputBuffer(buf); xmlFreeParserCtxt(ctxt); return(NULL); }
- input->filename = NULL; - input->buf = buf; - xmlBufResetInput(buf->buffer, input); - inputPush(ctxt, input);
- if (encoding != NULL) { - xmlCharEncoding enc; - xmlCharEncodingHandlerPtr handler; - - enc = xmlParseCharEncoding(encoding); - /* - * registered set of known encodings - */ - if (enc != XML_CHAR_ENCODING_ERROR) { - xmlSwitchEncoding(ctxt, enc); - if (ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) { - htmlParseErr(ctxt, XML_ERR_UNSUPPORTED_ENCODING, - "Unsupported encoding %s\n", - (const xmlChar *) encoding, NULL); - } - } else { - /* - * fallback for unknown encodings - */ - handler = xmlFindCharEncodingHandler((const char *) encoding); - if (handler != NULL) { - xmlSwitchToEncoding(ctxt, handler); - } else { - htmlParseErr(ctxt, XML_ERR_UNSUPPORTED_ENCODING, - "Unsupported encoding %s\n", - (const xmlChar *) encoding, NULL); - } - } - } - return(ctxt); }
@@ -5379,7 +5238,7 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
htmlParserNodeInfo node_info;
- while (1) { + while (PARSER_STOPPED(ctxt) == 0) {
in = ctxt->input; if (in == NULL) break; @@ -5434,14 +5293,13 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) { SKIP_BLANKS; avail = in->end - in->cur; } - if ((ctxt->sax) && (ctxt->sax->setDocumentLocator)) - ctxt->sax->setDocumentLocator(ctxt->userData, - &xmlDefaultSAXLocator); + if ((ctxt->sax) && (ctxt->sax->setDocumentLocator)) { + ctxt->sax->setDocumentLocator(ctxt->userData, + (xmlSAXLocator *) &xmlDefaultSAXLocator); + } if ((ctxt->sax) && (ctxt->sax->startDocument) && (!ctxt->disableSAX)) ctxt->sax->startDocument(ctxt->userData); - if (ctxt->instate == XML_PARSER_EOF) - goto done;
cur = in->cur[0]; next = in->cur[1]; @@ -5454,8 +5312,6 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) { (htmlParseLookupSequence(ctxt, '>', 0, 0, 1) < 0)) goto done; htmlParseDocTypeDecl(ctxt); - if (ctxt->instate == XML_PARSER_EOF) - goto done; ctxt->instate = XML_PARSER_PROLOG; } else { ctxt->instate = XML_PARSER_MISC; @@ -5486,16 +5342,12 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) { if ((!terminate) && (htmlParseLookupCommentEnd(ctxt) < 0)) goto done; htmlParseComment(ctxt); - if (ctxt->instate == XML_PARSER_EOF) - goto done; ctxt->instate = XML_PARSER_MISC; } else if ((cur == '<') && (next == '?')) { if ((!terminate) && (htmlParseLookupSequence(ctxt, '>', 0, 0, 0) < 0)) goto done; htmlParsePI(ctxt); - if (ctxt->instate == XML_PARSER_EOF) - goto done; ctxt->instate = XML_PARSER_MISC; } else if ((cur == '<') && (next == '!') && (UPP(2) == 'D') && (UPP(3) == 'O') && @@ -5506,8 +5358,6 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) { (htmlParseLookupSequence(ctxt, '>', 0, 0, 1) < 0)) goto done; htmlParseDocTypeDecl(ctxt); - if (ctxt->instate == XML_PARSER_EOF) - goto done; ctxt->instate = XML_PARSER_PROLOG; } else if ((cur == '<') && (next == '!') && (avail < 9)) { @@ -5528,16 +5378,12 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) { if ((!terminate) && (htmlParseLookupCommentEnd(ctxt) < 0)) goto done; htmlParseComment(ctxt); - if (ctxt->instate == XML_PARSER_EOF) - goto done; ctxt->instate = XML_PARSER_PROLOG; } else if ((cur == '<') && (next == '?')) { if ((!terminate) && (htmlParseLookupSequence(ctxt, '>', 0, 0, 0) < 0)) goto done; htmlParsePI(ctxt); - if (ctxt->instate == XML_PARSER_EOF) - goto done; ctxt->instate = XML_PARSER_PROLOG; } else if ((cur == '<') && (next == '!') && (avail < 4)) { @@ -5563,16 +5409,12 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) { if ((!terminate) && (htmlParseLookupCommentEnd(ctxt) < 0)) goto done; htmlParseComment(ctxt); - if (ctxt->instate == XML_PARSER_EOF) - goto done; ctxt->instate = XML_PARSER_EPILOG; } else if ((cur == '<') && (next == '?')) { if ((!terminate) && (htmlParseLookupSequence(ctxt, '>', 0, 0, 0) < 0)) goto done; htmlParsePI(ctxt); - if (ctxt->instate == XML_PARSER_EOF) - goto done; ctxt->instate = XML_PARSER_EPILOG; } else if ((cur == '<') && (next == '!') && (avail < 4)) { @@ -5655,8 +5497,6 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) { if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL)) ctxt->sax->endElement(ctxt->userData, name); htmlnamePop(ctxt); - if (ctxt->instate == XML_PARSER_EOF) - goto done; ctxt->instate = XML_PARSER_CONTENT; break; } @@ -5679,8 +5519,6 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) { if (ctxt->record_info) htmlNodeInfoPush(ctxt, &node_info);
- if (ctxt->instate == XML_PARSER_EOF) - goto done; ctxt->instate = XML_PARSER_CONTENT; break; } @@ -5697,8 +5535,6 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) { if (ctxt->record_info) htmlNodeInfoPush(ctxt, &node_info);
- if (ctxt->instate == XML_PARSER_EOF) - goto done; ctxt->instate = XML_PARSER_CONTENT; break; } @@ -5708,14 +5544,6 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) { /* * Handle preparsed entities and charRef */ - if (ctxt->token != 0) { - chr[0] = ctxt->token; - htmlCheckParagraph(ctxt); - if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL)) - ctxt->sax->characters(ctxt->userData, chr, 1); - ctxt->token = 0; - ctxt->checkIndex = 0; - } if ((avail == 1) && (terminate)) { cur = in->cur[0]; if ((cur != '<') && (cur != '&')) { @@ -5738,7 +5566,6 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) { ctxt->userData, chr, 1); } } - ctxt->token = 0; ctxt->checkIndex = 0; in->cur++; break; @@ -5771,8 +5598,6 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) { } } htmlParseScript(ctxt); - if (ctxt->instate == XML_PARSER_EOF) - goto done; if ((cur == '<') && (next == '/')) { ctxt->instate = XML_PARSER_END_TAG; ctxt->checkIndex = 0; @@ -5800,8 +5625,6 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) { (htmlParseLookupCommentEnd(ctxt) < 0)) goto done; htmlParseComment(ctxt); - if (ctxt->instate == XML_PARSER_EOF) - goto done; ctxt->instate = XML_PARSER_CONTENT; } else { if ((!terminate) && @@ -5814,8 +5637,6 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) { (htmlParseLookupSequence(ctxt, '>', 0, 0, 0) < 0)) goto done; htmlParsePI(ctxt); - if (ctxt->instate == XML_PARSER_EOF) - goto done; ctxt->instate = XML_PARSER_CONTENT; } else if ((cur == '<') && (next == '/')) { ctxt->instate = XML_PARSER_END_TAG; @@ -5844,7 +5665,7 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) { (htmlParseLookupSequence(ctxt, '<', 0, 0, 0) < 0)) goto done; ctxt->checkIndex = 0; - while ((ctxt->instate != XML_PARSER_EOF) && + while ((PARSER_STOPPED(ctxt) == 0) && (cur != '<') && (in->cur < in->end)) { if (cur == '&') { htmlParseReference(ctxt); @@ -5864,8 +5685,6 @@ htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) { (htmlParseLookupSequence(ctxt, '>', 0, 0, 0) < 0)) goto done; htmlParseEndTag(ctxt); - if (ctxt->instate == XML_PARSER_EOF) - goto done; if (ctxt->nameNr == 0) { ctxt->instate = XML_PARSER_EPILOG; } else { @@ -5897,11 +5716,14 @@ done: (ctxt->instate == XML_PARSER_EPILOG))) { xmlDtdPtr dtd; dtd = xmlGetIntSubset(ctxt->myDoc); - if (dtd == NULL) + if (dtd == NULL) { ctxt->myDoc->intSubset = xmlCreateIntSubset(ctxt->myDoc, BAD_CAST "html", BAD_CAST "-//W3C//DTD HTML 4.0 Transitional//EN", BAD_CAST "http://www.w3.org/TR/REC-html40/loose.dtd"); + if (ctxt->myDoc->intSubset == NULL) + htmlErrMemory(ctxt); + } } return(ret); } @@ -5909,24 +5731,33 @@ done: /** * htmlParseChunk: * @ctxt: an HTML parser context - * @chunk: an char array - * @size: the size in byte of the chunk + * @chunk: chunk of memory + * @size: size of chunk in bytes * @terminate: last chunk indicator * - * Parse a Chunk of memory + * Parse a chunk of memory in push parser mode. + * + * Assumes that the parser context was initialized with + * htmlCreatePushParserCtxt. * - * Returns zero if no error, the xmlParserErrors otherwise. + * The last chunk, which will often be empty, must be marked with + * the @terminate flag. With the default SAX callbacks, the resulting + * document will be available in ctxt->myDoc. This pointer will not + * be freed by the library. + * + * If the document isn't well-formed, ctxt->myDoc is set to NULL. + * + * Returns an xmlParserErrors code (0 on success). */ int htmlParseChunk(htmlParserCtxtPtr ctxt, const char *chunk, int size, int terminate) { - if ((ctxt == NULL) || (ctxt->input == NULL)) { - htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR, - "htmlParseChunk: context error\n", NULL, NULL); - return(XML_ERR_INTERNAL_ERROR); - } + if ((ctxt == NULL) || (ctxt->input == NULL)) + return(XML_ERR_ARGUMENT); + if (PARSER_STOPPED(ctxt) != 0) + return(ctxt->errNo); if ((size > 0) && (chunk != NULL) && (ctxt->input != NULL) && - (ctxt->input->buf != NULL) && (ctxt->instate != XML_PARSER_EOF)) { + (ctxt->input->buf != NULL)) { size_t pos = ctxt->input->cur - ctxt->input->base; int res;
@@ -5941,12 +5772,6 @@ htmlParseChunk(htmlParserCtxtPtr ctxt, const char *chunk, int size, } htmlParseTryOrFinish(ctxt, terminate); if (terminate) { - if ((ctxt->instate != XML_PARSER_EOF) && - (ctxt->instate != XML_PARSER_EPILOG) && - (ctxt->instate != XML_PARSER_MISC)) { - ctxt->errNo = XML_ERR_DOCUMENT_END; - ctxt->wellFormed = 0; - } if (ctxt->instate != XML_PARSER_EOF) { if ((ctxt->sax) && (ctxt->sax->endDocument != NULL)) ctxt->sax->endDocument(ctxt->userData); @@ -5964,77 +5789,37 @@ htmlParseChunk(htmlParserCtxtPtr ctxt, const char *chunk, int size,
/** * htmlCreatePushParserCtxt: - * @sax: a SAX handler - * @user_data: The user data returned on SAX callbacks - * @chunk: a pointer to an array of chars + * @sax: a SAX handler (optional) + * @user_data: The user data returned on SAX callbacks (optional) + * @chunk: a pointer to an array of chars (optional) * @size: number of chars in the array - * @filename: an optional file name or URI - * @enc: an optional encoding + * @filename: only used for error reporting (optional) + * @enc: encoding (deprecated, pass XML_CHAR_ENCODING_NONE) * - * Create a parser context for using the HTML parser in push mode - * The value of @filename is used for fetching external entities - * and error/warning reports. + * Create a parser context for using the HTML parser in push mode. * - * Returns the new parser context or NULL + * Returns the new parser context or NULL if a memory allocation + * failed. */ htmlParserCtxtPtr htmlCreatePushParserCtxt(htmlSAXHandlerPtr sax, void *user_data, const char *chunk, int size, const char *filename, xmlCharEncoding enc) { htmlParserCtxtPtr ctxt; - htmlParserInputPtr inputStream; - xmlParserInputBufferPtr buf; - - xmlInitParser(); - - buf = xmlAllocParserInputBuffer(XML_CHAR_ENCODING_NONE); - if (buf == NULL) return(NULL); + htmlParserInputPtr input; + const char *encoding;
ctxt = htmlNewSAXParserCtxt(sax, user_data); - if (ctxt == NULL) { - xmlFreeParserInputBuffer(buf); + if (ctxt == NULL) return(NULL); - } - if (filename == NULL) { - ctxt->directory = NULL; - } else { - ctxt->directory = xmlParserGetDirectory(filename); - }
- inputStream = htmlNewInputStream(ctxt); - if (inputStream == NULL) { - xmlFreeParserCtxt(ctxt); - xmlFreeParserInputBuffer(buf); + encoding = xmlGetCharEncodingName(enc); + input = xmlNewInputPush(ctxt, filename, chunk, size, encoding); + if (input == NULL) { + htmlFreeParserCtxt(ctxt); return(NULL); } - - if (filename == NULL) - inputStream->filename = NULL; - else - inputStream->filename = (char *) - xmlCanonicPath((const xmlChar *) filename); - inputStream->buf = buf; - xmlBufResetInput(buf->buffer, inputStream); - - inputPush(ctxt, inputStream); - - if (enc != XML_CHAR_ENCODING_NONE) - xmlSwitchEncoding(ctxt, enc); - - if ((size > 0) && (chunk != NULL) && (ctxt->input != NULL) && - (ctxt->input->buf != NULL)) { - size_t pos = ctxt->input->cur - ctxt->input->base; - int res; - - res = xmlParserInputBufferPush(ctxt->input->buf, size, chunk); - xmlBufUpdateInput(ctxt->input->buf->buffer, ctxt->input, pos); - if (res < 0) { - htmlParseErr(ctxt, ctxt->input->buf->error, - "xmlParserInputBufferPush failed\n", NULL, NULL); - xmlHaltParser(ctxt); - } - } - ctxt->progressive = 1; + inputPush(ctxt, input);
return(ctxt); } @@ -6063,25 +5848,20 @@ htmlSAXParseDoc(const xmlChar *cur, const char *encoding, htmlDocPtr ret; htmlParserCtxtPtr ctxt;
- xmlInitParser(); - - if (cur == NULL) return(NULL); + if (cur == NULL) + return(NULL);
+ ctxt = htmlCreateDocParserCtxt(cur, NULL, encoding); + if (ctxt == NULL) + return(NULL);
- ctxt = htmlCreateDocParserCtxt(cur, encoding); - if (ctxt == NULL) return(NULL); if (sax != NULL) { - if (ctxt->sax != NULL) xmlFree (ctxt->sax); - ctxt->sax = sax; + *ctxt->sax = *sax; ctxt->userData = userData; }
htmlParseDocument(ctxt); ret = ctxt->myDoc; - if (sax != NULL) { - ctxt->sax = NULL; - ctxt->userData = NULL; - } htmlFreeParserCtxt(ctxt);
return(ret); @@ -6090,9 +5870,13 @@ htmlSAXParseDoc(const xmlChar *cur, const char *encoding, /** * htmlParseDoc: * @cur: a pointer to an array of xmlChar - * @encoding: a free form C string describing the HTML document encoding, or NULL + * @encoding: the encoding (optional) * - * parse an HTML in-memory document and build a tree. + * DEPRECATED: Use htmlReadDoc. + * + * Parse an HTML in-memory document and build a tree. + * + * This function uses deprecated global parser options. * * Returns the resulting document tree */ @@ -6106,20 +5890,24 @@ htmlParseDoc(const xmlChar *cur, const char *encoding) { /** * htmlCreateFileParserCtxt: * @filename: the filename - * @encoding: a free form C string describing the HTML document encoding, or NULL + * @encoding: optional encoding + * + * DEPRECATED: Use htmlNewParserCtxt and htmlCtxtReadFile. + * + * Create a parser context to read from a file. + * + * A non-NULL encoding overrides encoding declarations in the document. * - * 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 + * Returns the new parser context or NULL if a memory allocation failed. */ htmlParserCtxtPtr htmlCreateFileParserCtxt(const char *filename, const char *encoding) { htmlParserCtxtPtr ctxt; - htmlParserInputPtr inputStream; - char *canonicFilename; + htmlParserInputPtr input;
if (filename == NULL) return(NULL); @@ -6128,30 +5916,13 @@ htmlCreateFileParserCtxt(const char *filename, const char *encoding) if (ctxt == NULL) { return(NULL); } - canonicFilename = (char *) xmlCanonicPath((const xmlChar *) filename); - if (canonicFilename == NULL) { - xmlFreeParserCtxt(ctxt); - return(NULL); - }
- inputStream = xmlLoadExternalEntity(canonicFilename, NULL, ctxt); - xmlFree(canonicFilename); - if (inputStream == NULL) { + input = xmlNewInputURL(ctxt, filename, NULL, encoding, 0); + if (input == NULL) { xmlFreeParserCtxt(ctxt); return(NULL); } - - inputPush(ctxt, inputStream); - - /* set encoding */ - if (encoding) { - xmlCharEncodingHandlerPtr hdlr; - - hdlr = xmlFindCharEncodingHandler(encoding); - if (hdlr != NULL) { - xmlSwitchToEncoding(ctxt, hdlr); - } - } + inputPush(ctxt, input);
return(ctxt); } @@ -6159,7 +5930,7 @@ htmlCreateFileParserCtxt(const char *filename, const char *encoding) /** * htmlSAXParseFile: * @filename: the filename - * @encoding: a free form C string describing the HTML document encoding, or NULL + * @encoding: encoding (optional) * @sax: the SAX handler block * @userData: if using SAX, this pointer will be provided on callbacks. * @@ -6181,8 +5952,6 @@ htmlSAXParseFile(const char *filename, const char *encoding, htmlSAXHandlerPtr s htmlParserCtxtPtr ctxt; htmlSAXHandlerPtr oldsax = NULL;
- xmlInitParser(); - ctxt = htmlCreateFileParserCtxt(filename, encoding); if (ctxt == NULL) return(NULL); if (sax != NULL) { @@ -6206,10 +5975,11 @@ htmlSAXParseFile(const char *filename, const char *encoding, htmlSAXHandlerPtr s /** * htmlParseFile: * @filename: the filename - * @encoding: a free form C string describing the HTML document encoding, or NULL + * @encoding: encoding (optional) * - * parse an HTML file and build a tree. Automatic support for ZLIB/Compress - * compressed document is provided by default if found at compile-time. + * Parse an HTML file and build a tree. + * + * See xmlNewInputURL for details. * * Returns the resulting document tree */ @@ -6223,6 +5993,8 @@ htmlParseFile(const char *filename, const char *encoding) { * htmlHandleOmittedElem: * @val: int 0 or 1 * + * DEPRECATED: Use HTML_PARSE_NOIMPLIED + * * Set and return the previous value for handling HTML omitted tags. * * Returns the last value for 0 for no handling, 1 for auto insertion. @@ -6328,7 +6100,7 @@ htmlAttrAllowed(const htmlElemDesc* elt, const xmlChar* attr, int legacy) { * for other nodes, HTML_NA (no checks performed) */ htmlStatus -htmlNodeStatus(const htmlNodePtr node, int legacy) { +htmlNodeStatus(htmlNodePtr node, int legacy) { if ( ! node ) return HTML_INVALID ;
@@ -6380,7 +6152,6 @@ htmlCtxtReset(htmlParserCtxtPtr ctxt) if (ctxt == NULL) return;
- xmlInitParser(); dict = ctxt->dict;
while ((input = inputPop(ctxt)) != NULL) { /* Non consuming */ @@ -6410,12 +6181,16 @@ htmlCtxtReset(htmlParserCtxtPtr ctxt) 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->directory != NULL) { + xmlFree(ctxt->directory); + ctxt->directory = NULL; + } + if (ctxt->myDoc != NULL) xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL; @@ -6424,9 +6199,7 @@ htmlCtxtReset(htmlParserCtxtPtr ctxt) ctxt->hasExternalSubset = 0; ctxt->hasPErefs = 0; ctxt->html = 1; - ctxt->external = 0; ctxt->instate = XML_PARSER_START; - ctxt->token = 0;
ctxt->wellFormed = 1; ctxt->nsWellFormed = 1; @@ -6533,263 +6306,281 @@ htmlCtxtUseOptions(htmlParserCtxtPtr ctxt, int options) }
/** - * htmlDoRead: + * htmlCtxtParseDocument: * @ctxt: an HTML parser context - * @URL: the base URL to use for the document - * @encoding: the document encoding, or NULL - * @options: a combination of htmlParserOption(s) - * @reuse: keep the context for reuse + * @input: parser input + * + * Parse an HTML document and return the resulting document tree. * - * Common front-end for the htmlRead functions + * Available since 2.13.0. * * Returns the resulting document tree or NULL */ -static htmlDocPtr -htmlDoRead(htmlParserCtxtPtr ctxt, const char *URL, const char *encoding, - int options, int reuse) +htmlDocPtr +htmlCtxtParseDocument(htmlParserCtxtPtr ctxt, xmlParserInputPtr input) { htmlDocPtr ret;
- htmlCtxtUseOptions(ctxt, options); - ctxt->html = 1; - if (encoding != NULL) { - xmlCharEncodingHandlerPtr hdlr; + if ((ctxt == NULL) || (input == NULL)) + return(NULL);
- hdlr = xmlFindCharEncodingHandler(encoding); - if (hdlr != NULL) { - xmlSwitchToEncoding(ctxt, hdlr); - } + /* assert(ctxt->inputNr == 0); */ + while (ctxt->inputNr > 0) + xmlFreeInputStream(inputPop(ctxt)); + + if (inputPush(ctxt, input) < 0) { + xmlFreeInputStream(input); + return(NULL); } - if ((URL != NULL) && (ctxt->input != NULL) && - (ctxt->input->filename == NULL)) - ctxt->input->filename = (char *) xmlStrdup((const xmlChar *) URL); + + ctxt->html = 1; htmlParseDocument(ctxt); - ret = ctxt->myDoc; - ctxt->myDoc = NULL; - if (!reuse) { - if ((ctxt->dictNames) && - (ret != NULL) && - (ret->dict == ctxt->dict)) - ctxt->dict = NULL; - xmlFreeParserCtxt(ctxt); + + if (ctxt->errNo != XML_ERR_NO_MEMORY) { + ret = ctxt->myDoc; + } else { + ret = NULL; + xmlFreeDoc(ctxt->myDoc); } - return (ret); + ctxt->myDoc = NULL; + + /* assert(ctxt->inputNr == 1); */ + while (ctxt->inputNr > 0) + xmlFreeInputStream(inputPop(ctxt)); + + return(ret); }
/** * htmlReadDoc: - * @cur: a pointer to a zero terminated string - * @URL: the base URL to use for the document - * @encoding: the document encoding, or NULL - * @options: a combination of htmlParserOption(s) + * @str: a pointer to a zero terminated string + * @url: only used for error reporting (optoinal) + * @encoding: the document encoding (optional) + * @options: a combination of htmlParserOptions * - * parse an XML in-memory document and build a tree. + * Convenience function to parse an HTML document from a zero-terminated + * string. * - * Returns the resulting document tree + * See htmlCtxtReadDoc for details. + * + * Returns the resulting document tree. */ htmlDocPtr -htmlReadDoc(const xmlChar * cur, const char *URL, const char *encoding, int options) +htmlReadDoc(const xmlChar *str, const char *url, const char *encoding, + int options) { htmlParserCtxtPtr ctxt; + xmlParserInputPtr input; + htmlDocPtr doc;
- if (cur == NULL) - return (NULL); - - xmlInitParser(); - ctxt = htmlCreateDocParserCtxt(cur, NULL); + ctxt = htmlNewParserCtxt(); if (ctxt == NULL) - return (NULL); - return (htmlDoRead(ctxt, URL, encoding, options, 0)); + return(NULL); + + htmlCtxtUseOptions(ctxt, options); + + input = xmlNewInputString(ctxt, url, (const char *) str, encoding, + XML_INPUT_BUF_STATIC); + + doc = htmlCtxtParseDocument(ctxt, input); + + htmlFreeParserCtxt(ctxt); + return(doc); }
/** * htmlReadFile: * @filename: a file or URL - * @encoding: the document encoding, or NULL - * @options: a combination of htmlParserOption(s) + * @encoding: the document encoding (optional) + * @options: a combination of htmlParserOptions * - * parse an XML file from the filesystem or the network. + * Convenience function to parse an HTML file from the filesystem, + * the network or a global user-defined resource loader. * - * Returns the resulting document tree + * See htmlCtxtReadFile for details. + * + * Returns the resulting document tree. */ htmlDocPtr htmlReadFile(const char *filename, const char *encoding, int options) { htmlParserCtxtPtr ctxt; + xmlParserInputPtr input; + htmlDocPtr doc;
- xmlInitParser(); - ctxt = htmlCreateFileParserCtxt(filename, encoding); + ctxt = htmlNewParserCtxt(); if (ctxt == NULL) - return (NULL); - return (htmlDoRead(ctxt, NULL, NULL, options, 0)); + return(NULL); + + htmlCtxtUseOptions(ctxt, options); + + input = xmlNewInputURL(ctxt, filename, NULL, encoding, 0); + + doc = htmlCtxtParseDocument(ctxt, input); + + htmlFreeParserCtxt(ctxt); + return(doc); }
/** * htmlReadMemory: * @buffer: a pointer to a char array * @size: the size of the array - * @URL: the base URL to use for the document + * @url: only used for error reporting (optional) * @encoding: the document encoding, or NULL * @options: a combination of htmlParserOption(s) * - * parse an XML in-memory document and build a tree. + * Convenience function to parse an HTML document from memory. + * The input buffer must not contain any terminating null bytes. + * + * See htmlCtxtReadMemory for details. * * Returns the resulting document tree */ htmlDocPtr -htmlReadMemory(const char *buffer, int size, const char *URL, const char *encoding, int options) +htmlReadMemory(const char *buffer, int size, const char *url, + const char *encoding, int options) { htmlParserCtxtPtr ctxt; + xmlParserInputPtr input; + htmlDocPtr doc;
- xmlInitParser(); - ctxt = htmlCreateMemoryParserCtxt(buffer, size); + if (size < 0) + return(NULL); + + ctxt = htmlNewParserCtxt(); if (ctxt == NULL) - return (NULL); - return (htmlDoRead(ctxt, URL, encoding, options, 0)); + return(NULL); + + htmlCtxtUseOptions(ctxt, options); + + input = xmlNewInputMemory(ctxt, url, buffer, size, encoding, + XML_INPUT_BUF_STATIC); + + doc = htmlCtxtParseDocument(ctxt, input); + + htmlFreeParserCtxt(ctxt); + return(doc); }
/** * htmlReadFd: * @fd: an open file descriptor - * @URL: the base URL to use for the document + * @url: only used for error reporting (optional) * @encoding: the document encoding, or NULL - * @options: a combination of htmlParserOption(s) + * @options: a combination of htmlParserOptions + * + * Convenience function to parse an HTML document from a + * file descriptor. * - * parse an HTML from a file descriptor and build a tree. * NOTE that the file descriptor will not be closed when the - * reader is closed or reset. + * context is freed or reset. + * + * See htmlCtxtReadFd for details. * * Returns the resulting document tree */ htmlDocPtr -htmlReadFd(int fd, const char *URL, const char *encoding, int options) +htmlReadFd(int fd, const char *url, const char *encoding, int options) { htmlParserCtxtPtr ctxt; - xmlParserInputBufferPtr input; - htmlParserInputPtr stream; - - if (fd < 0) - return (NULL); + xmlParserInputPtr input; + htmlDocPtr doc;
- xmlInitParser(); - input = xmlParserInputBufferCreateFd(fd, XML_CHAR_ENCODING_NONE); - if (input == NULL) - return (NULL); - input->closecallback = NULL; ctxt = htmlNewParserCtxt(); - if (ctxt == NULL) { - xmlFreeParserInputBuffer(input); - return (NULL); - } - stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE); - if (stream == NULL) { - xmlFreeParserInputBuffer(input); - htmlFreeParserCtxt(ctxt); - return (NULL); - } - inputPush(ctxt, stream); - return (htmlDoRead(ctxt, URL, encoding, options, 0)); + if (ctxt == NULL) + return(NULL); + + htmlCtxtUseOptions(ctxt, options); + + input = xmlNewInputFd(ctxt, url, fd, encoding, 0); + + doc = htmlCtxtParseDocument(ctxt, input); + + htmlFreeParserCtxt(ctxt); + return(doc); }
/** * htmlReadIO: * @ioread: an I/O read function - * @ioclose: an I/O close function + * @ioclose: an I/O close function (optional) * @ioctx: an I/O handler - * @URL: the base URL to use for the document - * @encoding: the document encoding, or NULL + * @url: only used for error reporting (optional) + * @encoding: the document encoding (optional) * @options: a combination of htmlParserOption(s) * - * parse an HTML document from I/O functions and source and build a tree. + * Convenience function to parse an HTML document from I/O functions + * and context. + * + * See htmlCtxtReadIO for details. * * Returns the resulting document tree */ htmlDocPtr htmlReadIO(xmlInputReadCallback ioread, xmlInputCloseCallback ioclose, - void *ioctx, const char *URL, const char *encoding, int options) + void *ioctx, const char *url, const char *encoding, int options) { htmlParserCtxtPtr ctxt; - xmlParserInputBufferPtr input; - xmlParserInputPtr stream; - - if (ioread == NULL) - return (NULL); - xmlInitParser(); + xmlParserInputPtr input; + htmlDocPtr doc;
- input = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx, - XML_CHAR_ENCODING_NONE); - if (input == NULL) { - if (ioclose != NULL) - ioclose(ioctx); - return (NULL); - } ctxt = htmlNewParserCtxt(); - if (ctxt == NULL) { - xmlFreeParserInputBuffer(input); - return (NULL); - } - stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE); - if (stream == NULL) { - xmlFreeParserInputBuffer(input); - xmlFreeParserCtxt(ctxt); + if (ctxt == NULL) return (NULL); - } - inputPush(ctxt, stream); - return (htmlDoRead(ctxt, URL, encoding, options, 0)); + + htmlCtxtUseOptions(ctxt, options); + + input = xmlNewInputIO(ctxt, url, ioread, ioclose, ioctx, encoding, 0); + + doc = htmlCtxtParseDocument(ctxt, input); + + htmlFreeParserCtxt(ctxt); + return(doc); }
/** * htmlCtxtReadDoc: * @ctxt: an HTML parser context * @str: a pointer to a zero terminated string - * @URL: the base URL to use for the document - * @encoding: the document encoding, or NULL - * @options: a combination of htmlParserOption(s) + * @URL: only used for error reporting (optional) + * @encoding: the document encoding (optional) + * @options: a combination of htmlParserOptions * - * parse an XML in-memory document and build a tree. - * This reuses the existing @ctxt parser context + * Parse an HTML in-memory document and build a tree. + * + * See htmlCtxtUseOptions for details. * * Returns the resulting document tree */ htmlDocPtr htmlCtxtReadDoc(htmlParserCtxtPtr ctxt, const xmlChar *str, - const char *URL, const char *encoding, int options) + const char *URL, const char *encoding, int options) { - xmlParserInputBufferPtr input; - xmlParserInputPtr stream; + xmlParserInputPtr input;
if (ctxt == NULL) return (NULL); - if (str == NULL) - return (NULL); - xmlInitParser();
htmlCtxtReset(ctxt); + htmlCtxtUseOptions(ctxt, options);
- input = xmlParserInputBufferCreateString(str); - if (input == NULL) { - return(NULL); - } - - stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE); - if (stream == NULL) { - xmlFreeParserInputBuffer(input); - return(NULL); - } + input = xmlNewInputString(ctxt, URL, (const char *) str, encoding, 0);
- inputPush(ctxt, stream); - return (htmlDoRead(ctxt, URL, encoding, options, 1)); + return(htmlCtxtParseDocument(ctxt, input)); }
/** * htmlCtxtReadFile: * @ctxt: an HTML parser context * @filename: a file or URL - * @encoding: the document encoding, or NULL - * @options: a combination of htmlParserOption(s) + * @encoding: the document encoding (optional) + * @options: a combination of htmlParserOptions * - * parse an XML file from the filesystem or the network. - * This reuses the existing @ctxt parser context + * Parse an HTML file from the filesystem, the network or a + * user-defined resource loader. + * + * See xmlNewInputURL and htmlCtxtUseOptions for details. * * Returns the resulting document tree */ @@ -6797,22 +6588,17 @@ htmlDocPtr htmlCtxtReadFile(htmlParserCtxtPtr ctxt, const char *filename, const char *encoding, int options) { - xmlParserInputPtr stream; + xmlParserInputPtr input;
- if (filename == NULL) - return (NULL); if (ctxt == NULL) return (NULL); - xmlInitParser();
htmlCtxtReset(ctxt); + htmlCtxtUseOptions(ctxt, options);
- stream = xmlLoadExternalEntity(filename, NULL, ctxt); - if (stream == NULL) { - return (NULL); - } - inputPush(ctxt, stream); - return (htmlDoRead(ctxt, NULL, encoding, options, 1)); + input = xmlNewInputURL(ctxt, filename, NULL, encoding, 0); + + return(htmlCtxtParseDocument(ctxt, input)); }
/** @@ -6820,12 +6606,14 @@ htmlCtxtReadFile(htmlParserCtxtPtr ctxt, const char *filename, * @ctxt: an HTML parser context * @buffer: a pointer to a char array * @size: the size of the array - * @URL: the base URL to use for the document - * @encoding: the document encoding, or NULL - * @options: a combination of htmlParserOption(s) + * @URL: only used for error reporting (optional) + * @encoding: the document encoding (optinal) + * @options: a combination of htmlParserOptions + * + * Parse an HTML in-memory document and build a tree. The input buffer must + * not contain any terminating null bytes. * - * parse an XML in-memory document and build a tree. - * This reuses the existing @ctxt parser context + * See htmlCtxtUseOptions for details. * * Returns the resulting document tree */ @@ -6833,43 +6621,34 @@ htmlDocPtr htmlCtxtReadMemory(htmlParserCtxtPtr ctxt, const char *buffer, int size, const char *URL, const char *encoding, int options) { - xmlParserInputBufferPtr input; - xmlParserInputPtr stream; + xmlParserInputPtr input;
- if (ctxt == NULL) - return (NULL); - if (buffer == NULL) + if ((ctxt == NULL) || (size < 0)) return (NULL); - xmlInitParser();
htmlCtxtReset(ctxt); + htmlCtxtUseOptions(ctxt, options);
- input = xmlParserInputBufferCreateStatic(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); - } + input = xmlNewInputMemory(ctxt, URL, buffer, size, encoding, + XML_INPUT_BUF_STATIC);
- inputPush(ctxt, stream); - return (htmlDoRead(ctxt, URL, encoding, options, 1)); + return(htmlCtxtParseDocument(ctxt, input)); }
/** * htmlCtxtReadFd: * @ctxt: an HTML parser context * @fd: an open file descriptor - * @URL: the base URL to use for the document - * @encoding: the document encoding, or NULL - * @options: a combination of htmlParserOption(s) + * @URL: only used for error reporting (optional) + * @encoding: the document encoding (optinal) + * @options: a combination of htmlParserOptions + * + * Parse an HTML from a file descriptor and build a tree. + * + * See htmlCtxtUseOptions for details. * - * 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 + * context is freed or reset. * * Returns the resulting document tree */ @@ -6877,28 +6656,17 @@ htmlDocPtr htmlCtxtReadFd(htmlParserCtxtPtr ctxt, int fd, const char *URL, const char *encoding, int options) { - xmlParserInputBufferPtr input; - xmlParserInputPtr stream; + xmlParserInputPtr input;
- if (fd < 0) - return (NULL); if (ctxt == NULL) - return (NULL); - xmlInitParser(); + return(NULL);
htmlCtxtReset(ctxt); + htmlCtxtUseOptions(ctxt, options);
+ input = xmlNewInputFd(ctxt, URL, fd, encoding, 0);
- input = xmlParserInputBufferCreateFd(fd, 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 (htmlDoRead(ctxt, URL, encoding, options, 1)); + return(htmlCtxtParseDocument(ctxt, input)); }
/** @@ -6911,8 +6679,9 @@ htmlCtxtReadFd(htmlParserCtxtPtr ctxt, int fd, * @encoding: the document encoding, or NULL * @options: a combination of htmlParserOption(s) * - * parse an HTML document from I/O functions and source and build a tree. - * This reuses the existing @ctxt parser context + * Parse an HTML document from I/O functions and source and build a tree. + * + * See xmlNewInputIO and htmlCtxtUseOptions for details. * * Returns the resulting document tree */ @@ -6922,31 +6691,17 @@ htmlCtxtReadIO(htmlParserCtxtPtr ctxt, xmlInputReadCallback ioread, const char *URL, const char *encoding, int options) { - xmlParserInputBufferPtr input; - xmlParserInputPtr stream; + xmlParserInputPtr input;
- if (ioread == NULL) - return (NULL); if (ctxt == NULL) return (NULL); - xmlInitParser();
htmlCtxtReset(ctxt); + htmlCtxtUseOptions(ctxt, options);
- input = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx, - XML_CHAR_ENCODING_NONE); - if (input == NULL) { - if (ioclose != NULL) - ioclose(ioctx); - return (NULL); - } - stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE); - if (stream == NULL) { - xmlFreeParserInputBuffer(input); - return (NULL); - } - inputPush(ctxt, stream); - return (htmlDoRead(ctxt, URL, encoding, options, 1)); + input = xmlNewInputIO(ctxt, URL, ioread, ioclose, ioctx, encoding, 0); + + return(htmlCtxtParseDocument(ctxt, input)); }
#endif /* LIBXML_HTML_ENABLED */ diff --git a/libs/xml2/HTMLtree.c b/libs/xml2/HTMLtree.c index 8698f53e821..8fa022c11b8 100644 --- a/libs/xml2/HTMLtree.c +++ b/libs/xml2/HTMLtree.c @@ -334,17 +334,6 @@ htmlIsBooleanAttr(const xmlChar *name) * Output error handlers * * * ************************************************************************/ -/** - * htmlSaveErrMemory: - * @extra: extra information - * - * Handle an out of memory condition - */ -static void -htmlSaveErrMemory(const char *extra) -{ - __xmlSimpleError(XML_FROM_OUTPUT, XML_ERR_NO_MEMORY, NULL, NULL, extra); -}
/** * htmlSaveErr: @@ -358,6 +347,7 @@ static void htmlSaveErr(int code, xmlNodePtr node, const char *extra) { const char *msg = NULL; + int res;
switch(code) { case XML_SAVE_NOT_UTF8: @@ -375,7 +365,13 @@ htmlSaveErr(int code, xmlNodePtr node, const char *extra) default: msg = "unexpected error number\n"; } - __xmlSimpleError(XML_FROM_OUTPUT, code, node, msg, extra); + + res = __xmlRaiseError(NULL, NULL, NULL, NULL, node, + XML_FROM_OUTPUT, code, XML_ERR_ERROR, NULL, 0, + extra, NULL, NULL, 0, 0, + msg, extra); + if (res < 0) + xmlRaiseMemoryError(NULL, NULL, NULL, XML_FROM_OUTPUT, NULL); }
/************************************************************************ @@ -384,6 +380,27 @@ htmlSaveErr(int code, xmlNodePtr node, const char *extra) * * ************************************************************************/
+static xmlCharEncodingHandler * +htmlFindOutputEncoder(const char *encoding) { + xmlCharEncodingHandler *handler = NULL; + + if (encoding != NULL) { + int res; + + res = xmlOpenCharEncodingHandler(encoding, /* output */ 1, + &handler); + if (res != XML_ERR_OK) + htmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, NULL, encoding); + } else { + /* + * Fallback to HTML when the encoding is unspecified + */ + xmlOpenCharEncodingHandler("HTML", /* output */ 1, &handler); + } + + return(handler); +} + /** * htmlBufNodeDumpFormat: * @buf: the xmlBufPtr output @@ -399,20 +416,18 @@ static size_t htmlBufNodeDumpFormat(xmlBufPtr buf, xmlDocPtr doc, xmlNodePtr cur, int format) { size_t use; - int ret; + size_t ret; xmlOutputBufferPtr outbuf;
if (cur == NULL) { - return (-1); + return ((size_t) -1); } if (buf == NULL) { - return (-1); + return ((size_t) -1); } outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer)); - if (outbuf == NULL) { - htmlSaveErrMemory("allocating HTML output buffer"); - return (-1); - } + if (outbuf == NULL) + return ((size_t) -1); memset(outbuf, 0, sizeof(xmlOutputBuffer)); outbuf->buffer = buf; outbuf->encoder = NULL; @@ -423,8 +438,11 @@ htmlBufNodeDumpFormat(xmlBufPtr buf, xmlDocPtr doc, xmlNodePtr cur,
use = xmlBufUse(buf); htmlNodeDumpFormatOutput(outbuf, doc, cur, NULL, format); + if (outbuf->error) + ret = (size_t) -1; + else + ret = xmlBufUse(buf) - use; xmlFree(outbuf); - ret = xmlBufUse(buf) - use; return (ret); }
@@ -452,6 +470,7 @@ htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur) { if (buffer == NULL) return(-1);
+ xmlBufSetAllocationScheme(buffer, XML_BUFFER_ALLOC_DOUBLEIT); ret = htmlBufNodeDumpFormat(buffer, doc, cur, 1);
xmlBufBackToBuffer(buffer); @@ -479,35 +498,20 @@ int htmlNodeDumpFileFormat(FILE *out, xmlDocPtr doc, xmlNodePtr cur, const char *encoding, int format) { xmlOutputBufferPtr buf; - xmlCharEncodingHandlerPtr handler = NULL; + xmlCharEncodingHandlerPtr handler; int ret;
xmlInitParser();
- if (encoding != NULL) { - xmlCharEncoding enc; - - enc = xmlParseCharEncoding(encoding); - if (enc != XML_CHAR_ENCODING_UTF8) { - handler = xmlFindCharEncodingHandler(encoding); - if (handler == NULL) - htmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, NULL, encoding); - } - } else { - /* - * Fallback to HTML or ASCII when the encoding is unspecified - */ - if (handler == NULL) - handler = xmlFindCharEncodingHandler("HTML"); - if (handler == NULL) - handler = xmlFindCharEncodingHandler("ascii"); - } - /* * save the content to a temp buffer. */ + handler = htmlFindOutputEncoder(encoding); buf = xmlOutputBufferCreateFile(out, handler); - if (buf == NULL) return(0); + if (buf == NULL) { + xmlCharEncCloseFunc(handler); + return(0); + }
htmlNodeDumpFormatOutput(buf, doc, cur, NULL, format);
@@ -549,52 +553,34 @@ htmlDocDumpMemoryFormat(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
if ((mem == NULL) || (size == NULL)) return; - if (cur == NULL) { - *mem = NULL; - *size = 0; + *mem = NULL; + *size = 0; + if (cur == NULL) return; - }
encoding = (const char *) htmlGetMetaEncoding(cur); - - if (encoding != NULL) { - xmlCharEncoding enc; - - enc = xmlParseCharEncoding(encoding); - if (enc != XML_CHAR_ENCODING_UTF8) { - handler = xmlFindCharEncodingHandler(encoding); - if (handler == NULL) - htmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, NULL, encoding); - - } - } else { - /* - * Fallback to HTML or ASCII when the encoding is unspecified - */ - if (handler == NULL) - handler = xmlFindCharEncodingHandler("HTML"); - if (handler == NULL) - handler = xmlFindCharEncodingHandler("ascii"); - } - + handler = htmlFindOutputEncoder(encoding); buf = xmlAllocOutputBufferInternal(handler); if (buf == NULL) { - *mem = NULL; - *size = 0; + xmlCharEncCloseFunc(handler); return; }
htmlDocContentDumpFormatOutput(buf, cur, NULL, format);
xmlOutputBufferFlush(buf); - if (buf->conv != NULL) { - *size = xmlBufUse(buf->conv); - *mem = xmlStrndup(xmlBufContent(buf->conv), *size); - } else { - *size = xmlBufUse(buf->buffer); - *mem = xmlStrndup(xmlBufContent(buf->buffer), *size); + + if (!buf->error) { + if (buf->conv != NULL) { + *size = xmlBufUse(buf->conv); + *mem = xmlStrndup(xmlBufContent(buf->conv), *size); + } else { + *size = xmlBufUse(buf->buffer); + *mem = xmlStrndup(xmlBufContent(buf->buffer), *size); + } } - (void)xmlOutputBufferClose(buf); + + xmlOutputBufferClose(buf); }
/** @@ -641,15 +627,15 @@ htmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlOutputBufferWriteString(buf, (const char *)cur->name); if (cur->ExternalID != NULL) { xmlOutputBufferWriteString(buf, " PUBLIC "); - xmlBufWriteQuotedString(buf->buffer, cur->ExternalID); + xmlOutputBufferWriteQuotedString(buf, cur->ExternalID); if (cur->SystemID != NULL) { xmlOutputBufferWriteString(buf, " "); - xmlBufWriteQuotedString(buf->buffer, cur->SystemID); + xmlOutputBufferWriteQuotedString(buf, cur->SystemID); } } else if (cur->SystemID != NULL && xmlStrcmp(cur->SystemID, BAD_CAST "about:legacy-compat")) { xmlOutputBufferWriteString(buf, " SYSTEM "); - xmlBufWriteQuotedString(buf->buffer, cur->SystemID); + xmlOutputBufferWriteQuotedString(buf, cur->SystemID); } xmlOutputBufferWriteString(buf, ">\n"); } @@ -709,17 +695,17 @@ htmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) { escaped = xmlURIEscapeStr(tmp, BAD_CAST ""#$%&+,/:;<=>?@[\]^`{|}"); if (escaped != NULL) { - xmlBufWriteQuotedString(buf->buffer, escaped); + xmlOutputBufferWriteQuotedString(buf, escaped); xmlFree(escaped); } else { - xmlBufWriteQuotedString(buf->buffer, value); + buf->error = XML_ERR_NO_MEMORY; } } else { - xmlBufWriteQuotedString(buf->buffer, value); + xmlOutputBufferWriteQuotedString(buf, value); } xmlFree(value); } else { - xmlOutputBufferWriteString(buf, "="""); + buf->error = XML_ERR_NO_MEMORY; } } } @@ -860,10 +846,12 @@ htmlNodeDumpFormatOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlChar *buffer;
buffer = xmlEncodeEntitiesReentrant(doc, cur->content); - if (buffer != NULL) { - xmlOutputBufferWriteString(buf, (const char *)buffer); - xmlFree(buffer); + if (buffer == NULL) { + buf->error = XML_ERR_NO_MEMORY; + return; } + xmlOutputBufferWriteString(buf, (const char *)buffer); + xmlFree(buffer); } else { xmlOutputBufferWriteString(buf, (const char *)cur->content); } @@ -1039,28 +1027,12 @@ htmlDocDump(FILE *f, xmlDocPtr cur) { }
encoding = (const char *) htmlGetMetaEncoding(cur); - - if (encoding != NULL) { - xmlCharEncoding enc; - - enc = xmlParseCharEncoding(encoding); - if (enc != XML_CHAR_ENCODING_UTF8) { - handler = xmlFindCharEncodingHandler(encoding); - if (handler == NULL) - htmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, NULL, encoding); - } - } else { - /* - * Fallback to HTML or ASCII when the encoding is unspecified - */ - if (handler == NULL) - handler = xmlFindCharEncodingHandler("HTML"); - if (handler == NULL) - handler = xmlFindCharEncodingHandler("ascii"); - } - + handler = htmlFindOutputEncoder(encoding); buf = xmlOutputBufferCreateFile(f, handler); - if (buf == NULL) return(-1); + if (buf == NULL) { + xmlCharEncCloseFunc(handler); + return(-1); + } htmlDocContentDumpOutput(buf, cur, NULL);
ret = xmlOutputBufferClose(buf); @@ -1089,31 +1061,12 @@ htmlSaveFile(const char *filename, xmlDocPtr cur) { xmlInitParser();
encoding = (const char *) htmlGetMetaEncoding(cur); - - if (encoding != NULL) { - xmlCharEncoding enc; - - enc = xmlParseCharEncoding(encoding); - if (enc != XML_CHAR_ENCODING_UTF8) { - handler = xmlFindCharEncodingHandler(encoding); - if (handler == NULL) - htmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, NULL, encoding); - } - } else { - /* - * Fallback to HTML or ASCII when the encoding is unspecified - */ - if (handler == NULL) - handler = xmlFindCharEncodingHandler("HTML"); - if (handler == NULL) - handler = xmlFindCharEncodingHandler("ascii"); - } - - /* - * save the content to a temp buffer. - */ + handler = htmlFindOutputEncoder(encoding); buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression); - if (buf == NULL) return(0); + if (buf == NULL) { + xmlCharEncCloseFunc(handler); + return(0); + }
htmlDocContentDumpOutput(buf, cur, NULL);
@@ -1144,33 +1097,20 @@ htmlSaveFileFormat(const char *filename, xmlDocPtr cur,
xmlInitParser();
- if (encoding != NULL) { - xmlCharEncoding enc; - - enc = xmlParseCharEncoding(encoding); - if (enc != XML_CHAR_ENCODING_UTF8) { - handler = xmlFindCharEncodingHandler(encoding); - if (handler == NULL) - htmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, NULL, encoding); - } - htmlSetMetaEncoding(cur, (const xmlChar *) encoding); - } else { + handler = htmlFindOutputEncoder(encoding); + if (handler != NULL) + htmlSetMetaEncoding(cur, (const xmlChar *) handler->name); + else htmlSetMetaEncoding(cur, (const xmlChar *) "UTF-8");
- /* - * Fallback to HTML or ASCII when the encoding is unspecified - */ - if (handler == NULL) - handler = xmlFindCharEncodingHandler("HTML"); - if (handler == NULL) - handler = xmlFindCharEncodingHandler("ascii"); - } - /* * save the content to a temp buffer. */ buf = xmlOutputBufferCreateFilename(filename, handler, 0); - if (buf == NULL) return(0); + if (buf == NULL) { + xmlCharEncCloseFunc(handler); + return(0); + }
htmlDocContentDumpFormatOutput(buf, cur, encoding, format);
diff --git a/libs/xml2/SAX2.c b/libs/xml2/SAX2.c index bb72e1606b8..3d0257c240e 100644 --- a/libs/xml2/SAX2.c +++ b/libs/xml2/SAX2.c @@ -31,52 +31,16 @@ #include "private/parser.h" #include "private/tree.h"
-/** - * TODO: - * - * macro to flag unimplemented blocks - * XML_CATALOG_PREFER user env to select between system/public preferred - * option. C.f. Richard Tobin richard@cogsci.ed.ac.uk - *> Just FYI, I am using an environment variable XML_CATALOG_PREFER with - *> values "system" and "public". I have made the default be "system" to - *> match yours. - */ -#define TODO \ - xmlGenericError(xmlGenericErrorContext, \ - "Unimplemented block at %s:%d\n", \ - __FILE__, __LINE__); +#define XML_MAX_URI_LENGTH 2000
/* * xmlSAX2ErrMemory: * @ctxt: an XML validation parser context * @msg: a string to accompany the error message */ -static void LIBXML_ATTR_FORMAT(2,0) -xmlSAX2ErrMemory(xmlParserCtxtPtr ctxt, const char *msg) { - xmlStructuredErrorFunc schannel = NULL; - const char *str1 = "out of memory\n"; - - if (ctxt != NULL) { - ctxt->errNo = XML_ERR_NO_MEMORY; - 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_PARSER, XML_ERR_NO_MEMORY, - XML_ERR_ERROR, NULL, 0, (const char *) str1, - NULL, NULL, 0, 0, - msg, (const char *) str1, NULL); - ctxt->errNo = XML_ERR_NO_MEMORY; - ctxt->instate = XML_PARSER_EOF; - ctxt->disableSAX = 1; - } else { - __xmlRaiseError(schannel, - NULL, NULL, - ctxt, NULL, XML_FROM_PARSER, XML_ERR_NO_MEMORY, - XML_ERR_ERROR, NULL, 0, (const char *) str1, - NULL, NULL, 0, 0, - msg, (const char *) str1, NULL); - } +static void +xmlSAX2ErrMemory(xmlParserCtxtPtr ctxt) { + xmlCtxtErrMemory(ctxt); }
/** @@ -91,32 +55,12 @@ xmlSAX2ErrMemory(xmlParserCtxtPtr ctxt, const char *msg) { */ static void LIBXML_ATTR_FORMAT(3,0) xmlErrValid(xmlParserCtxtPtr ctxt, xmlParserErrors error, - const char *msg, const char *str1, const char *str2) + const char *msg, const xmlChar *str1, const xmlChar *str2) { - xmlStructuredErrorFunc schannel = NULL; - - if ((ctxt != NULL) && (ctxt->disableSAX != 0) && - (ctxt->instate == XML_PARSER_EOF)) - return; - if (ctxt != NULL) { - 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, - (const char *) str2, NULL, 0, 0, - msg, (const char *) str1, (const char *) str2); + xmlCtxtErr(ctxt, NULL, XML_FROM_DTD, error, XML_ERR_ERROR, + str1, str2, NULL, 0, msg, str1, str2); + if (ctxt != NULL) ctxt->valid = 0; - } else { - __xmlRaiseError(schannel, - NULL, NULL, - ctxt, NULL, XML_FROM_DTD, error, - XML_ERR_ERROR, NULL, 0, (const char *) str1, - (const char *) str2, NULL, 0, 0, - msg, (const char *) str1, (const char *) str2); - } }
/** @@ -133,21 +77,8 @@ static void LIBXML_ATTR_FORMAT(3,0) xmlFatalErrMsg(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *msg, const xmlChar *str1, const xmlChar *str2) { - if ((ctxt != NULL) && (ctxt->disableSAX != 0) && - (ctxt->instate == XML_PARSER_EOF)) - return; - if (ctxt != NULL) - 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, 0, 0, msg, str1, str2); - if (ctxt != NULL) { - ctxt->wellFormed = 0; - ctxt->valid = 0; - if (ctxt->recovery == 0) - ctxt->disableSAX = 1; - } + xmlCtxtErr(ctxt, NULL, XML_FROM_PARSER, error, XML_ERR_FATAL, + str1, str2, NULL, 0, msg, str1, str2); }
/** @@ -164,15 +95,8 @@ static void LIBXML_ATTR_FORMAT(3,0) xmlWarnMsg(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *msg, const xmlChar *str1) { - if ((ctxt != NULL) && (ctxt->disableSAX != 0) && - (ctxt->instate == XML_PARSER_EOF)) - return; - if (ctxt != NULL) - ctxt->errNo = error; - __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER, error, - XML_ERR_WARNING, NULL, 0, - (const char *) str1, NULL, - NULL, 0, 0, msg, str1); + xmlCtxtErr(ctxt, NULL, XML_FROM_PARSER, error, XML_ERR_WARNING, + str1, NULL, NULL, 0, msg, str1); }
/** @@ -188,15 +112,8 @@ static void LIBXML_ATTR_FORMAT(3,0) xmlNsWarnMsg(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *msg, const xmlChar *str1, const xmlChar *str2) { - if ((ctxt != NULL) && (ctxt->disableSAX != 0) && - (ctxt->instate == XML_PARSER_EOF)) - return; - if (ctxt != NULL) - ctxt->errNo = error; - __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_NAMESPACE, error, - XML_ERR_WARNING, NULL, 0, - (const char *) str1, (const char *) str2, - NULL, 0, 0, msg, str1, str2); + xmlCtxtErr(ctxt, NULL, XML_FROM_NAMESPACE, error, XML_ERR_WARNING, + str1, str2, NULL, 0, msg, str1, str2); }
/** @@ -341,7 +258,7 @@ xmlSAX2InternalSubset(void *ctx, const xmlChar *name, ctxt->myDoc->intSubset = xmlCreateIntSubset(ctxt->myDoc, name, ExternalID, SystemID); if (ctxt->myDoc->intSubset == NULL) - xmlSAX2ErrMemory(ctxt, "xmlSAX2InternalSubset"); + xmlSAX2ErrMemory(ctxt); }
/** @@ -359,8 +276,9 @@ xmlSAX2ExternalSubset(void *ctx, const xmlChar *name, { xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; if (ctx == NULL) return; - if (((ExternalID != NULL) || (SystemID != NULL)) && - (((ctxt->validate) || (ctxt->loadsubset != 0)) && + if ((SystemID != NULL) && + ((ctxt->options & XML_PARSE_NO_XXE) == 0) && + (((ctxt->validate) || (ctxt->loadsubset)) && (ctxt->wellFormed && ctxt->myDoc))) { /* * Try to fetch and parse the external subset. @@ -371,7 +289,6 @@ xmlSAX2ExternalSubset(void *ctx, const xmlChar *name, xmlParserInputPtr *oldinputTab; xmlParserInputPtr input = NULL; const xmlChar *oldencoding; - int oldprogressive; unsigned long consumed; size_t buffered;
@@ -385,7 +302,11 @@ xmlSAX2ExternalSubset(void *ctx, const xmlChar *name, return; }
- xmlNewDtd(ctxt->myDoc, name, ExternalID, SystemID); + if (xmlNewDtd(ctxt->myDoc, name, ExternalID, SystemID) == NULL) { + xmlSAX2ErrMemory(ctxt); + xmlFreeInputStream(input); + return; + }
/* * make sure we won't destroy the main document context @@ -395,21 +316,18 @@ xmlSAX2ExternalSubset(void *ctx, const xmlChar *name, oldinputMax = ctxt->inputMax; oldinputTab = ctxt->inputTab; oldencoding = ctxt->encoding; - oldprogressive = ctxt->progressive; ctxt->encoding = NULL; - ctxt->progressive = 0;
ctxt->inputTab = (xmlParserInputPtr *) xmlMalloc(5 * sizeof(xmlParserInputPtr)); if (ctxt->inputTab == NULL) { - xmlSAX2ErrMemory(ctxt, "xmlSAX2ExternalSubset"); + xmlSAX2ErrMemory(ctxt); xmlFreeInputStream(input); ctxt->input = oldinput; ctxt->inputNr = oldinputNr; ctxt->inputMax = oldinputMax; ctxt->inputTab = oldinputTab; ctxt->encoding = oldencoding; - ctxt->progressive = oldprogressive; return; } ctxt->inputNr = 0; @@ -463,7 +381,6 @@ xmlSAX2ExternalSubset(void *ctx, const xmlChar *name, (!xmlDictOwns(ctxt->dict, ctxt->encoding)))) xmlFree((xmlChar *) ctxt->encoding); ctxt->encoding = oldencoding; - ctxt->progressive = oldprogressive; /* ctxt->wellFormed = oldwellFormed; */ } } @@ -486,22 +403,50 @@ xmlParserInputPtr xmlSAX2ResolveEntity(void *ctx, const xmlChar *publicId, const xmlChar *systemId) { xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; - xmlParserInputPtr ret; - xmlChar *URI; - const char *base = NULL; + xmlParserInputPtr ret = NULL; + xmlChar *URI = NULL;
if (ctx == NULL) return(NULL); - if (ctxt->input != NULL) - base = ctxt->input->filename; - if (base == NULL) - base = ctxt->directory;
- URI = xmlBuildURI(systemId, (const xmlChar *) base); + if (systemId != NULL) { + const xmlChar *base = NULL; + int res; + + if (ctxt->input != NULL) + base = BAD_CAST ctxt->input->filename; + + /* + * We don't really need the 'directory' struct member, but some + * users set it manually to a base URI for memory streams. + */ + if (base == NULL) + base = BAD_CAST ctxt->directory; + + if ((xmlStrlen(systemId) > XML_MAX_URI_LENGTH) || + (xmlStrlen(base) > XML_MAX_URI_LENGTH)) { + xmlFatalErr(ctxt, XML_ERR_RESOURCE_LIMIT, "URI too long"); + return(NULL); + } + res = xmlBuildURISafe(systemId, base, &URI); + if (URI == NULL) { + if (res < 0) + xmlSAX2ErrMemory(ctxt); + else + xmlWarnMsg(ctxt, XML_ERR_INVALID_URI, + "Can't resolve URI: %s\n", systemId); + return(NULL); + } + if (xmlStrlen(URI) > XML_MAX_URI_LENGTH) { + xmlFatalErr(ctxt, XML_ERR_RESOURCE_LIMIT, "URI too long"); + xmlFree(URI); + return(NULL); + } + }
ret = xmlLoadExternalEntity((const char *) URI, - (const char *) publicId, ctxt); - if (URI != NULL) - xmlFree(URI); + (const char *) publicId, ctxt); + + xmlFree(URI); return(ret); }
@@ -590,50 +535,80 @@ xmlSAX2EntityDecl(void *ctx, const xmlChar *name, int type, { xmlEntityPtr ent; xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + int extSubset; + int res;
- if (ctx == NULL) return; - if (ctxt->inSubset == 1) { - ent = xmlAddDocEntity(ctxt->myDoc, name, type, publicId, - systemId, content); - if ((ent == NULL) && (ctxt->pedantic)) - xmlWarnMsg(ctxt, XML_WAR_ENTITY_REDEFINED, - "Entity(%s) already defined in the internal subset\n", - name); - if ((ent != NULL) && (ent->URI == NULL) && (systemId != NULL)) { - xmlChar *URI; - const char *base = NULL; - - if (ctxt->input != NULL) - base = ctxt->input->filename; - if (base == NULL) - base = ctxt->directory; - - URI = xmlBuildURI(systemId, (const xmlChar *) base); - ent->URI = URI; - } - } else if (ctxt->inSubset == 2) { - ent = xmlAddDtdEntity(ctxt->myDoc, name, type, publicId, - systemId, content); - if ((ent == NULL) && (ctxt->pedantic) && - (ctxt->sax != NULL) && (ctxt->sax->warning != NULL)) - ctxt->sax->warning(ctxt->userData, - "Entity(%s) already defined in the external subset\n", name); - if ((ent != NULL) && (ent->URI == NULL) && (systemId != NULL)) { - xmlChar *URI; - const char *base = NULL; - - if (ctxt->input != NULL) - base = ctxt->input->filename; - if (base == NULL) - base = ctxt->directory; - - URI = xmlBuildURI(systemId, (const xmlChar *) base); - ent->URI = URI; - } - } else { - xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_PROCESSING, - "SAX.xmlSAX2EntityDecl(%s) called while not in subset\n", - name, NULL); + if ((ctxt == NULL) || (ctxt->myDoc == NULL)) + return; + + extSubset = ctxt->inSubset == 2; + res = xmlAddEntity(ctxt->myDoc, extSubset, name, type, publicId, systemId, + content, &ent); + switch (res) { + case XML_ERR_OK: + break; + case XML_ERR_NO_MEMORY: + xmlSAX2ErrMemory(ctxt); + return; + case XML_WAR_ENTITY_REDEFINED: + if (ctxt->pedantic) { + if (extSubset) + xmlWarnMsg(ctxt, res, "Entity(%s) already defined in the" + " external subset\n", name); + else + xmlWarnMsg(ctxt, res, "Entity(%s) already defined in the" + " internal subset\n", name); + } + return; + case XML_ERR_REDECL_PREDEF_ENTITY: + /* + * Technically an error but it's a common mistake to get double + * escaping according to "4.6 Predefined Entities" wrong. + */ + xmlWarnMsg(ctxt, res, "Invalid redeclaration of predefined" + " entity '%s'", name); + return; + default: + xmlFatalErrMsg(ctxt, XML_ERR_INTERNAL_ERROR, + "Unexpected error code from xmlAddEntity\n", + NULL, NULL); + return; + } + + if ((ent->URI == NULL) && (systemId != NULL)) { + xmlChar *URI; + const char *base = NULL; + int i; + + for (i = ctxt->inputNr - 1; i >= 0; i--) { + if (ctxt->inputTab[i]->filename != NULL) { + base = ctxt->inputTab[i]->filename; + break; + } + } + + /* + * We don't really need the 'directory' struct member, but some + * users set it manually to a base URI for memory streams. + */ + if (base == NULL) + base = ctxt->directory; + + res = xmlBuildURISafe(systemId, (const xmlChar *) base, &URI); + + if (URI == NULL) { + if (res < 0) { + xmlSAX2ErrMemory(ctxt); + } else { + xmlWarnMsg(ctxt, XML_ERR_INVALID_URI, + "Can't resolve URI: %s\n", systemId); + } + } else if (xmlStrlen(URI) > XML_MAX_URI_LENGTH) { + xmlFatalErr(ctxt, XML_ERR_RESOURCE_LIMIT, "URI too long"); + xmlFree(URI); + } else { + ent->URI = URI; + } } }
@@ -676,6 +651,8 @@ xmlSAX2AttributeDecl(void *ctx, const xmlChar *elem, const xmlChar *fullname, } /* TODO: optimize name/prefix allocation */ name = xmlSplitQName(ctxt, fullname, &prefix); + if (name == NULL) + xmlSAX2ErrMemory(ctxt); ctxt->vctxt.valid = 1; if (ctxt->inSubset == 1) attr = xmlAddAttributeDecl(&ctxt->vctxt, ctxt->myDoc->intSubset, elem, @@ -690,6 +667,7 @@ xmlSAX2AttributeDecl(void *ctx, const xmlChar *elem, const xmlChar *fullname, "SAX.xmlSAX2AttributeDecl(%s) called while not in subset\n", name, NULL); xmlFree(name); + xmlFree(prefix); xmlFreeEnumeration(tree); return; } @@ -814,54 +792,8 @@ xmlSAX2UnparsedEntityDecl(void *ctx, const xmlChar *name, const xmlChar *publicId, const xmlChar *systemId, const xmlChar *notationName) { - xmlEntityPtr ent; - xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; - if (ctx == NULL) return; - if (ctxt->inSubset == 1) { - ent = xmlAddDocEntity(ctxt->myDoc, name, - XML_EXTERNAL_GENERAL_UNPARSED_ENTITY, - publicId, systemId, notationName); - if ((ent == NULL) && (ctxt->pedantic) && - (ctxt->sax != NULL) && (ctxt->sax->warning != NULL)) - ctxt->sax->warning(ctxt->userData, - "Entity(%s) already defined in the internal subset\n", name); - if ((ent != NULL) && (ent->URI == NULL) && (systemId != NULL)) { - xmlChar *URI; - const char *base = NULL; - - if (ctxt->input != NULL) - base = ctxt->input->filename; - if (base == NULL) - base = ctxt->directory; - - URI = xmlBuildURI(systemId, (const xmlChar *) base); - ent->URI = URI; - } - } else if (ctxt->inSubset == 2) { - ent = xmlAddDtdEntity(ctxt->myDoc, name, - XML_EXTERNAL_GENERAL_UNPARSED_ENTITY, - publicId, systemId, notationName); - if ((ent == NULL) && (ctxt->pedantic) && - (ctxt->sax != NULL) && (ctxt->sax->warning != NULL)) - ctxt->sax->warning(ctxt->userData, - "Entity(%s) already defined in the external subset\n", name); - if ((ent != NULL) && (ent->URI == NULL) && (systemId != NULL)) { - xmlChar *URI; - const char *base = NULL; - - if (ctxt->input != NULL) - base = ctxt->input->filename; - if (base == NULL) - base = ctxt->directory; - - URI = xmlBuildURI(systemId, (const xmlChar *) base); - ent->URI = URI; - } - } else { - xmlFatalErrMsg(ctxt, XML_ERR_INTERNAL_ERROR, - "SAX.xmlSAX2UnparsedEntityDecl(%s) called while not in subset\n", - name, NULL); - } + xmlSAX2EntityDecl(ctx, name, XML_EXTERNAL_GENERAL_UNPARSED_ENTITY, + publicId, systemId, (xmlChar *) notationName); }
/** @@ -891,25 +823,19 @@ xmlSAX2StartDocument(void *ctx)
if (ctx == NULL) return;
- if (ctxt->html) { #ifdef LIBXML_HTML_ENABLED + if (ctxt->html) { if (ctxt->myDoc == NULL) ctxt->myDoc = htmlNewDocNoDtD(NULL, NULL); if (ctxt->myDoc == NULL) { - xmlSAX2ErrMemory(ctxt, "xmlSAX2StartDocument"); + xmlSAX2ErrMemory(ctxt); return; } ctxt->myDoc->properties = XML_DOC_HTML; ctxt->myDoc->parseFlags = ctxt->options; -#else - xmlGenericError(xmlGenericErrorContext, - "libxml2 built without HTML support\n"); - ctxt->errNo = XML_ERR_INTERNAL_ERROR; - ctxt->instate = XML_PARSER_EOF; - ctxt->disableSAX = 1; - return; + } else #endif - } else { + { doc = ctxt->myDoc = xmlNewDoc(ctxt->version); if (doc != NULL) { doc->properties = 0; @@ -918,7 +844,7 @@ xmlSAX2StartDocument(void *ctx) doc->parseFlags = ctxt->options; doc->standalone = ctxt->standalone; } else { - xmlSAX2ErrMemory(ctxt, "xmlSAX2StartDocument"); + xmlSAX2ErrMemory(ctxt); return; } if ((ctxt->dictNames) && (doc != NULL)) { @@ -930,7 +856,7 @@ xmlSAX2StartDocument(void *ctx) (ctxt->input != NULL) && (ctxt->input->filename != NULL)) { ctxt->myDoc->URL = xmlPathToURI((const xmlChar *)ctxt->input->filename); if (ctxt->myDoc->URL == NULL) - xmlSAX2ErrMemory(ctxt, "xmlSAX2StartDocument"); + xmlSAX2ErrMemory(ctxt); } }
@@ -960,11 +886,47 @@ xmlSAX2EndDocument(void *ctx) if (encoding != NULL) { doc->encoding = xmlStrdup(encoding); if (doc->encoding == NULL) - xmlSAX2ErrMemory(ctxt, "xmlSAX2EndDocument"); + xmlSAX2ErrMemory(ctxt); } } }
+static void +xmlSAX2AppendChild(xmlParserCtxtPtr ctxt, xmlNodePtr node) { + xmlNodePtr parent; + xmlNodePtr last; + + if (ctxt->inSubset == 1) { + parent = (xmlNodePtr) ctxt->myDoc->intSubset; + } else if (ctxt->inSubset == 2) { + parent = (xmlNodePtr) ctxt->myDoc->extSubset; + } else { + parent = ctxt->node; + if (parent == NULL) + parent = (xmlNodePtr) ctxt->myDoc; + } + + last = parent->last; + if (last == NULL) { + parent->children = node; + } else { + last->next = node; + node->prev = last; + } + + parent->last = node; + node->parent = parent; + + if ((node->type != XML_TEXT_NODE) && + (ctxt->linenumbers) && + (ctxt->input != NULL)) { + if ((unsigned) ctxt->input->line < (unsigned) USHRT_MAX) + node->line = ctxt->input->line; + else + node->line = USHRT_MAX; + } +} + #if defined(LIBXML_SAX1_ENABLED) || defined(LIBXML_HTML_ENABLED) || defined(LIBXML_WRITER_ENABLED) || defined(LIBXML_LEGACY_ENABLED) /** * xmlNsErrMsg: @@ -980,15 +942,8 @@ static void LIBXML_ATTR_FORMAT(3,0) xmlNsErrMsg(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *msg, const xmlChar *str1, const xmlChar *str2) { - if ((ctxt != NULL) && (ctxt->disableSAX != 0) && - (ctxt->instate == XML_PARSER_EOF)) - return; - if (ctxt != NULL) - ctxt->errNo = error; - __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_NAMESPACE, error, - XML_ERR_ERROR, NULL, 0, - (const char *) str1, (const char *) str2, - NULL, 0, 0, msg, str1, str2); + xmlCtxtErr(ctxt, NULL, XML_FROM_NAMESPACE, error, XML_ERR_ERROR, + str1, str2, NULL, 0, msg, str1, str2); }
/** @@ -1041,7 +996,7 @@ xmlSAX2AttributeInternal(void *ctx, const xmlChar *fullname, } } if (name == NULL) { - xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElement"); + xmlSAX2ErrMemory(ctxt); if (ns != NULL) xmlFree(ns); return; @@ -1051,6 +1006,8 @@ xmlSAX2AttributeInternal(void *ctx, const xmlChar *fullname, if ((ctxt->html) && (value == NULL) && (htmlIsBooleanAttr(fullname))) { nval = xmlStrdup(fullname); + if (nval == NULL) + xmlSAX2ErrMemory(ctxt); value = (const xmlChar *) nval; } else #endif @@ -1088,12 +1045,10 @@ xmlSAX2AttributeInternal(void *ctx, const xmlChar *fullname, (void) nsret;
if (!ctxt->replaceEntities) { - ctxt->depth++; - val = xmlStringDecodeEntities(ctxt, value, XML_SUBSTITUTE_REF, - 0,0,0); - ctxt->depth--; + /* TODO: normalize if needed */ + val = xmlExpandEntitiesInAttValue(ctxt, value, /* normalize */ 0); if (val == NULL) { - xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElement"); + xmlSAX2ErrMemory(ctxt); if (name != NULL) xmlFree(name); if (nval != NULL) @@ -1107,16 +1062,16 @@ xmlSAX2AttributeInternal(void *ctx, const xmlChar *fullname, if (val[0] != 0) { xmlURIPtr uri;
- uri = xmlParseURI((const char *)val); + if (xmlParseURISafe((const char *)val, &uri) < 0) + xmlSAX2ErrMemory(ctxt); if (uri == NULL) { - if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL)) - ctxt->sax->warning(ctxt->userData, - "xmlns: %s not a valid URI\n", val); + xmlNsWarnMsg(ctxt, XML_WAR_NS_URI, + "xmlns:%s: %s not a valid URI\n", name, value); } else { if (uri->scheme == NULL) { - if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL)) - ctxt->sax->warning(ctxt->userData, - "xmlns: URI %s is not absolute\n", val); + xmlNsWarnMsg(ctxt, XML_WAR_NS_URI_RELATIVE, + "xmlns:%s: URI %s is not absolute\n", + name, value); } xmlFreeURI(uri); } @@ -1124,16 +1079,19 @@ xmlSAX2AttributeInternal(void *ctx, const xmlChar *fullname,
/* a default namespace definition */ nsret = xmlNewNs(ctxt->node, val, NULL); - + if (nsret == NULL) { + xmlSAX2ErrMemory(ctxt); + } #ifdef LIBXML_VALID_ENABLED /* * Validate also for namespace decls, they are attributes from * an XML-1.0 perspective */ - if (nsret != NULL && ctxt->validate && ctxt->wellFormed && - ctxt->myDoc && ctxt->myDoc->intSubset) + else if (ctxt->validate && ctxt->wellFormed && + ctxt->myDoc && ctxt->myDoc->intSubset) { ctxt->valid &= xmlValidateOneNamespace(&ctxt->vctxt, ctxt->myDoc, ctxt->node, prefix, nsret, val); + } #endif /* LIBXML_VALID_ENABLED */ if (name != NULL) xmlFree(name); @@ -1153,12 +1111,10 @@ xmlSAX2AttributeInternal(void *ctx, const xmlChar *fullname, (void) nsret;
if (!ctxt->replaceEntities) { - ctxt->depth++; - val = xmlStringDecodeEntities(ctxt, value, XML_SUBSTITUTE_REF, - 0,0,0); - ctxt->depth--; + /* TODO: normalize if needed */ + val = xmlExpandEntitiesInAttValue(ctxt, value, /* normalize */ 0); if (val == NULL) { - xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElement"); + xmlSAX2ErrMemory(ctxt); xmlFree(ns); if (name != NULL) xmlFree(name); @@ -1177,7 +1133,8 @@ xmlSAX2AttributeInternal(void *ctx, const xmlChar *fullname, if ((ctxt->pedantic != 0) && (val[0] != 0)) { xmlURIPtr uri;
- uri = xmlParseURI((const char *)val); + if (xmlParseURISafe((const char *)val, &uri) < 0) + xmlSAX2ErrMemory(ctxt); if (uri == NULL) { xmlNsWarnMsg(ctxt, XML_WAR_NS_URI, "xmlns:%s: %s not a valid URI\n", name, value); @@ -1193,15 +1150,20 @@ xmlSAX2AttributeInternal(void *ctx, const xmlChar *fullname, /* a standard namespace definition */ nsret = xmlNewNs(ctxt->node, val, name); xmlFree(ns); + + if (nsret == NULL) { + xmlSAX2ErrMemory(ctxt); + } #ifdef LIBXML_VALID_ENABLED /* * Validate also for namespace decls, they are attributes from * an XML-1.0 perspective */ - if (nsret != NULL && ctxt->validate && ctxt->wellFormed && - ctxt->myDoc && ctxt->myDoc->intSubset) + else if (ctxt->validate && ctxt->wellFormed && + ctxt->myDoc && ctxt->myDoc->intSubset) { ctxt->valid &= xmlValidateOneNamespace(&ctxt->vctxt, ctxt->myDoc, ctxt->node, prefix, nsret, value); + } #endif /* LIBXML_VALID_ENABLED */ if (name != NULL) xmlFree(name); @@ -1213,7 +1175,11 @@ xmlSAX2AttributeInternal(void *ctx, const xmlChar *fullname, }
if (ns != NULL) { - namespace = xmlSearchNs(ctxt->myDoc, ctxt->node, ns); + int res; + + res = xmlSearchNsSafe(ctxt->node, ns, &namespace); + if (res < 0) + xmlSAX2ErrMemory(ctxt);
if (namespace == NULL) { xmlNsErrMsg(ctxt, XML_NS_ERR_UNDEFINED_NAMESPACE, @@ -1228,11 +1194,11 @@ xmlSAX2AttributeInternal(void *ctx, const xmlChar *fullname, if ((xmlStrEqual(name, prop->name)) && ((namespace == prop->ns) || (xmlStrEqual(namespace->href, prop->ns->href)))) { - xmlNsErrMsg(ctxt, XML_ERR_ATTRIBUTE_REDEFINED, - "Attribute %s in %s redefined\n", - name, namespace->href); - ctxt->wellFormed = 0; - if (ctxt->recovery == 0) ctxt->disableSAX = 1; + xmlCtxtErr(ctxt, NULL, XML_FROM_PARSER, + XML_ERR_ATTRIBUTE_REDEFINED, XML_ERR_FATAL, + name, NULL, NULL, 0, + "Attribute %s in %s redefined\n", + name, namespace->href); if (name != NULL) xmlFree(name); goto error; @@ -1247,25 +1213,22 @@ xmlSAX2AttributeInternal(void *ctx, const xmlChar *fullname,
/* !!!!!! <a toto:arg="" xmlns:toto="http://toto.com"> */ ret = xmlNewNsPropEatName(ctxt->node, namespace, name, NULL); - if (ret == NULL) + if (ret == NULL) { + xmlSAX2ErrMemory(ctxt); goto error; + }
if ((ctxt->replaceEntities == 0) && (!ctxt->html)) { - xmlNodePtr tmp; - - ret->children = xmlStringGetNodeList(ctxt->myDoc, value); - tmp = ret->children; - while (tmp != NULL) { - tmp->parent = (xmlNodePtr) ret; - if (tmp->next == NULL) - ret->last = tmp; - tmp = tmp->next; - } + if (xmlNodeParseContent((xmlNodePtr) ret, value, INT_MAX) < 0) + xmlSAX2ErrMemory(ctxt); } else if (value != NULL) { ret->children = xmlNewDocText(ctxt->myDoc, value); - ret->last = ret->children; - if (ret->children != NULL) + if (ret->children == NULL) { + xmlSAX2ErrMemory(ctxt); + } else { + ret->last = ret->children; ret->children->parent = (xmlNodePtr) ret; + } }
#ifdef LIBXML_VALID_ENABLED @@ -1279,10 +1242,8 @@ xmlSAX2AttributeInternal(void *ctx, const xmlChar *fullname, if (!ctxt->replaceEntities) { xmlChar *val;
- ctxt->depth++; - val = xmlStringDecodeEntities(ctxt, value, XML_SUBSTITUTE_REF, - 0,0,0); - ctxt->depth--; + /* TODO: normalize if needed */ + val = xmlExpandEntitiesInAttValue(ctxt, value, /* normalize */ 0);
if (val == NULL) ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt, @@ -1295,8 +1256,9 @@ xmlSAX2AttributeInternal(void *ctx, const xmlChar *fullname, * It need to be done twice ... it's an extra burden related * to the ability to keep xmlSAX2References in attributes */ - nvalnorm = xmlValidNormalizeAttributeValue(ctxt->myDoc, - ctxt->node, fullname, val); + nvalnorm = xmlValidCtxtNormalizeAttributeValue( + &ctxt->vctxt, ctxt->myDoc, + ctxt->node, fullname, val); if (nvalnorm != NULL) { xmlFree(val); val = nvalnorm; @@ -1313,8 +1275,7 @@ xmlSAX2AttributeInternal(void *ctx, const xmlChar *fullname, } else #endif /* LIBXML_VALID_ENABLED */ if (((ctxt->loadsubset & XML_SKIP_IDS) == 0) && - (((ctxt->replaceEntities == 0) && (ctxt->external != 2)) || - ((ctxt->replaceEntities != 0) && (ctxt->inSubset == 0))) && + (ctxt->input->entity == NULL) && /* Don't create IDs containing entity references */ (ret->children != NULL) && (ret->children->type == XML_TEXT_NODE) && @@ -1332,14 +1293,20 @@ xmlSAX2AttributeInternal(void *ctx, const xmlChar *fullname, */ if (xmlValidateNCName(content, 1) != 0) { xmlErrValid(ctxt, XML_DTD_XMLID_VALUE, - "xml:id : attribute value %s is not an NCName\n", - (const char *) content, NULL); + "xml:id : attribute value %s is not an NCName\n", + content, NULL); } xmlAddID(&ctxt->vctxt, ctxt->myDoc, content, ret); - } else if (xmlIsID(ctxt->myDoc, ctxt->node, ret)) - xmlAddID(&ctxt->vctxt, ctxt->myDoc, content, ret); - else if (xmlIsRef(ctxt->myDoc, ctxt->node, ret)) - xmlAddRef(&ctxt->vctxt, ctxt->myDoc, content, ret); + } else { + int res = xmlIsID(ctxt->myDoc, ctxt->node, ret); + + if (res < 0) + xmlCtxtErrMemory(ctxt); + else if (res > 0) + xmlAddID(&ctxt->vctxt, ctxt->myDoc, content, ret); + else if (xmlIsRef(ctxt->myDoc, ctxt->node, ret)) + xmlAddRef(&ctxt->vctxt, ctxt->myDoc, content, ret); + } }
error: @@ -1391,13 +1358,15 @@ process_external_subset:
if (attr->prefix != NULL) { fulln = xmlStrdup(attr->prefix); - fulln = xmlStrcat(fulln, BAD_CAST ":"); - fulln = xmlStrcat(fulln, attr->name); + if (fulln != NULL) + fulln = xmlStrcat(fulln, BAD_CAST ":"); + if (fulln != NULL) + fulln = xmlStrcat(fulln, attr->name); } else { fulln = xmlStrdup(attr->name); } if (fulln == NULL) { - xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElement"); + xmlSAX2ErrMemory(ctxt); break; }
@@ -1419,8 +1388,8 @@ process_external_subset: if (att == NULL) { xmlErrValid(ctxt, XML_DTD_STANDALONE_DEFAULTED, "standalone: attribute %s on %s defaulted from external subset\n", - (const char *)fulln, - (const char *)attr->elem); + fulln, + attr->elem); } xmlFree(fulln); } @@ -1463,7 +1432,7 @@ process_external_subset:
fulln = xmlBuildQName(attr->name, attr->prefix, fn, 50); if (fulln == NULL) { - xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElement"); + xmlSAX2ErrMemory(ctxt); return; }
@@ -1547,6 +1516,10 @@ xmlSAX2StartElement(void *ctx, const xmlChar *fullname, const xmlChar **atts) * Split the full name into a namespace prefix and the tag name */ name = xmlSplitQName(ctxt, fullname, &prefix); + if (name == NULL) { + xmlSAX2ErrMemory(ctxt); + return; + } }
/* @@ -1556,26 +1529,22 @@ xmlSAX2StartElement(void *ctx, const xmlChar *fullname, const xmlChar **atts) */ ret = xmlNewDocNodeEatName(ctxt->myDoc, NULL, name, NULL); if (ret == NULL) { - if (prefix != NULL) - xmlFree(prefix); - xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElement"); + xmlFree(prefix); + xmlSAX2ErrMemory(ctxt); return; } ctxt->nodemem = -1; - if (ctxt->linenumbers) { - if (ctxt->input != NULL) { - if ((unsigned) ctxt->input->line < (unsigned) USHRT_MAX) - ret->line = ctxt->input->line; - else - ret->line = USHRT_MAX; - } - }
/* Initialize parent before pushing node */ parent = ctxt->node; if (parent == NULL) parent = (xmlNodePtr) ctxt->myDoc;
+ /* + * Link the child element + */ + xmlSAX2AppendChild(ctxt, ret); + /* * We are parsing a new node. */ @@ -1587,12 +1556,9 @@ xmlSAX2StartElement(void *ctx, const xmlChar *fullname, const xmlChar **atts) return; }
- /* - * Link the child element - */ - xmlAddChild(parent, ret); - if (!ctxt->html) { + int res; + /* * Insert all the defaulted attributes from the DTD especially * namespaces @@ -1623,14 +1589,21 @@ xmlSAX2StartElement(void *ctx, const xmlChar *fullname, const xmlChar **atts) * Search the namespace, note that since the attributes have been * processed, the local namespaces are available. */ - ns = xmlSearchNs(ctxt->myDoc, ret, prefix); - if ((ns == NULL) && (parent != NULL)) - ns = xmlSearchNs(ctxt->myDoc, parent, prefix); + res = xmlSearchNsSafe(ret, prefix, &ns); + if (res < 0) + xmlSAX2ErrMemory(ctxt); + if ((ns == NULL) && (parent != NULL)) { + res = xmlSearchNsSafe(parent, prefix, &ns); + if (res < 0) + xmlSAX2ErrMemory(ctxt); + } if ((prefix != NULL) && (ns == NULL)) { - ns = xmlNewNs(ret, NULL, prefix); xmlNsWarnMsg(ctxt, XML_NS_ERR_UNDEFINED_NAMESPACE, "Namespace prefix %s is not defined\n", prefix, NULL); + ns = xmlNewNs(ret, NULL, prefix); + if (ns == NULL) + xmlSAX2ErrMemory(ctxt); }
/* @@ -1751,7 +1724,7 @@ xmlSAX2TextNode(xmlParserCtxtPtr ctxt, const xmlChar *str, int len) { ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); } if (ret == NULL) { - xmlErrMemory(ctxt, "xmlSAX2Characters"); + xmlCtxtErrMemory(ctxt); return(NULL); } memset(ret, 0, sizeof(xmlNode)); @@ -1772,6 +1745,11 @@ xmlSAX2TextNode(xmlParserCtxtPtr ctxt, const xmlChar *str, int len) { } else if ((len <= 3) && ((cur == '"') || (cur == ''') || ((cur == '<') && (str[len + 1] != '!')))) { intern = xmlDictLookup(ctxt->dict, str, len); + if (intern == NULL) { + xmlSAX2ErrMemory(ctxt); + xmlFree(ret); + return(NULL); + } } else if (IS_BLANK_CH(*str) && (len < 60) && (cur == '<') && (str[len + 1] != '!')) { int i; @@ -1780,6 +1758,11 @@ xmlSAX2TextNode(xmlParserCtxtPtr ctxt, const xmlChar *str, int len) { if (!IS_BLANK_CH(str[i])) goto skip; } intern = xmlDictLookup(ctxt->dict, str, len); + if (intern == NULL) { + xmlSAX2ErrMemory(ctxt); + xmlFree(ret); + return(NULL); + } } } skip: @@ -1789,7 +1772,7 @@ skip: if (intern == NULL) { ret->content = xmlStrndup(str, len); if (ret->content == NULL) { - xmlSAX2ErrMemory(ctxt, "xmlSAX2TextNode"); + xmlSAX2ErrMemory(ctxt); xmlFree(ret); return(NULL); } @@ -1816,7 +1799,6 @@ static xmlChar * xmlSAX2DecodeAttrEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, const xmlChar *end) { const xmlChar *in; - xmlChar *ret;
in = str; while (in < end) @@ -1824,11 +1806,12 @@ xmlSAX2DecodeAttrEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, goto decode; return(NULL); decode: - ctxt->depth++; - ret = xmlStringLenDecodeEntities(ctxt, str, end - str, - XML_SUBSTITUTE_REF, 0,0,0); - ctxt->depth--; - return(ret); + /* + * If the value contains '&', we can be sure it was allocated and is + * zero-terminated. + */ + /* TODO: normalize if needed */ + return(xmlExpandEntitiesInAttValue(ctxt, str, /* normalize */ 0)); } #endif /* LIBXML_VALID_ENABLED */
@@ -1865,7 +1848,11 @@ xmlSAX2AttributeNs(xmlParserCtxtPtr ctxt, if (prefix != NULL) { namespace = xmlParserNsLookupSax(ctxt, prefix); if ((namespace == NULL) && (xmlStrEqual(prefix, BAD_CAST "xml"))) { - namespace = xmlSearchNs(ctxt->myDoc, ctxt->node, prefix); + int res; + + res = xmlSearchNsSafe(ctxt->node, prefix, &namespace); + if (res < 0) + xmlSAX2ErrMemory(ctxt); } }
@@ -1879,7 +1866,7 @@ xmlSAX2AttributeNs(xmlParserCtxtPtr ctxt, } else { ret = xmlMalloc(sizeof(*ret)); if (ret == NULL) { - xmlSAX2ErrMemory(ctxt, NULL); + xmlSAX2ErrMemory(ctxt); return(NULL); } } @@ -1900,10 +1887,13 @@ xmlSAX2AttributeNs(xmlParserCtxtPtr ctxt, ret->doc = ctxt->node->doc; ret->ns = namespace;
- if (ctxt->dictNames) + if (ctxt->dictNames) { ret->name = localname; - else + } else { ret->name = xmlStrdup(localname); + if (ret->name == NULL) + xmlSAX2ErrMemory(ctxt); + }
if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) xmlRegisterNodeDefaultValue((xmlNodePtr)ret); @@ -1924,17 +1914,10 @@ xmlSAX2AttributeNs(xmlParserCtxtPtr ctxt, tmp->doc = ret->doc; tmp->parent = (xmlNodePtr) ret; } - } else { - ret->children = xmlStringLenGetNodeList(ctxt->myDoc, value, - valueend - value); - tmp = ret->children; - while (tmp != NULL) { - tmp->doc = ret->doc; - tmp->parent = (xmlNodePtr) ret; - if (tmp->next == NULL) - ret->last = tmp; - tmp = tmp->next; - } + } else if (valueend > value) { + if (xmlNodeParseContent((xmlNodePtr) ret, value, + valueend - value) < 0) + xmlSAX2ErrMemory(ctxt); } } else if (value != NULL) { xmlNodePtr tmp; @@ -1968,6 +1951,8 @@ xmlSAX2AttributeNs(xmlParserCtxtPtr ctxt, * entry points in the full validation code */ dup = xmlStrndup(value, valueend - value); + if (dup == NULL) + xmlSAX2ErrMemory(ctxt);
ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt, ctxt->myDoc, ctxt->node, ret, dup); @@ -1986,7 +1971,9 @@ xmlSAX2AttributeNs(xmlParserCtxtPtr ctxt, xmlChar *fullname;
fullname = xmlBuildQName(localname, prefix, fn, 50); - if (fullname != NULL) { + if (fullname == NULL) { + xmlSAX2ErrMemory(ctxt); + } else { ctxt->vctxt.valid = 1; nvalnorm = xmlValidCtxtNormalizeAttributeValue( &ctxt->vctxt, ctxt->myDoc, @@ -2012,6 +1999,8 @@ xmlSAX2AttributeNs(xmlParserCtxtPtr ctxt, * the attribute as passed is already normalized */ dup = xmlStrndup(value, valueend - value); + if (dup == NULL) + xmlSAX2ErrMemory(ctxt);
ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt, ctxt->myDoc, ctxt->node, ret, dup); @@ -2019,8 +2008,7 @@ xmlSAX2AttributeNs(xmlParserCtxtPtr ctxt, } else #endif /* LIBXML_VALID_ENABLED */ if (((ctxt->loadsubset & XML_SKIP_IDS) == 0) && - (((ctxt->replaceEntities == 0) && (ctxt->external != 2)) || - ((ctxt->replaceEntities != 0) && (ctxt->inSubset == 0))) && + (ctxt->input->entity == NULL) && /* Don't create IDs containing entity references */ (ret->children != NULL) && (ret->children->type == XML_TEXT_NODE) && @@ -2040,14 +2028,19 @@ xmlSAX2AttributeNs(xmlParserCtxtPtr ctxt, */ if (xmlValidateNCName(content, 1) != 0) { xmlErrValid(ctxt, XML_DTD_XMLID_VALUE, - "xml:id : attribute value %s is not an NCName\n", - (const char *) content, NULL); + "xml:id : attribute value %s is not an NCName\n", + content, NULL); } xmlAddID(&ctxt->vctxt, ctxt->myDoc, content, ret); - } else if (xmlIsID(ctxt->myDoc, ctxt->node, ret)) { - xmlAddID(&ctxt->vctxt, ctxt->myDoc, content, ret); - } else if (xmlIsRef(ctxt->myDoc, ctxt->node, ret)) { - xmlAddRef(&ctxt->vctxt, ctxt->myDoc, content, ret); + } else { + int res = xmlIsID(ctxt->myDoc, ctxt->node, ret); + + if (res < 0) + xmlCtxtErrMemory(ctxt); + else if (res > 0) + xmlAddID(&ctxt->vctxt, ctxt->myDoc, content, ret); + else if (xmlIsRef(ctxt->myDoc, ctxt->node, ret)) + xmlAddRef(&ctxt->vctxt, ctxt->myDoc, content, ret); } } if (dup != NULL) @@ -2086,7 +2079,6 @@ xmlSAX2StartElementNs(void *ctx, { xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; xmlNodePtr ret; - xmlNodePtr parent; xmlNsPtr last = NULL, ns; const xmlChar *uri, *pref; xmlChar *lname = NULL; @@ -2115,10 +2107,17 @@ xmlSAX2StartElementNs(void *ctx, const xmlChar *fullname;
fullname = xmlDictQLookup(ctxt->dict, prefix, localname); - if (fullname != NULL) - localname = fullname; + if (fullname == NULL) { + xmlSAX2ErrMemory(ctxt); + return; + } + localname = fullname; } else { lname = xmlBuildQName(localname, prefix, NULL, 0); + if (lname == NULL) { + xmlSAX2ErrMemory(ctxt); + return; + } } } /* @@ -2140,7 +2139,7 @@ xmlSAX2StartElementNs(void *ctx, else ret->name = lname; if (ret->name == NULL) { - xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElementNs"); + xmlSAX2ErrMemory(ctxt); xmlFree(ret); return; } @@ -2157,18 +2156,10 @@ xmlSAX2StartElementNs(void *ctx, ret = xmlNewDocNodeEatName(ctxt->myDoc, NULL, (xmlChar *) lname, NULL); if (ret == NULL) { - xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElementNs"); + xmlSAX2ErrMemory(ctxt); return; } } - if (ctxt->linenumbers) { - if (ctxt->input != NULL) { - if ((unsigned) ctxt->input->line < (unsigned) USHRT_MAX) - ret->line = ctxt->input->line; - else - ret->line = USHRT_MAX; - } - }
/* * Build the namespace list @@ -2187,11 +2178,7 @@ xmlSAX2StartElementNs(void *ctx, if ((URI != NULL) && (prefix == pref)) ret->ns = ns; } else { - /* - * any out of memory error would already have been raised - * but we can't be guaranteed it's the actual error due to the - * API, best is to skip in this case - */ + xmlSAX2ErrMemory(ctxt); continue; }
@@ -2207,10 +2194,10 @@ xmlSAX2StartElementNs(void *ctx, } ctxt->nodemem = -1;
- /* Initialize parent before pushing node */ - parent = ctxt->node; - if (parent == NULL) - parent = (xmlNodePtr) ctxt->myDoc; + /* + * Link the child element + */ + xmlSAX2AppendChild(ctxt, ret);
/* * We are parsing a new node. @@ -2221,11 +2208,6 @@ xmlSAX2StartElementNs(void *ctx, return; }
- /* - * Link the child element - */ - xmlAddChild(parent, ret); - /* * Insert the defaulted attributes from the DTD only if requested: */ @@ -2240,13 +2222,17 @@ xmlSAX2StartElementNs(void *ctx, if ((URI != NULL) && (ret->ns == NULL)) { ret->ns = xmlParserNsLookupSax(ctxt, prefix); if ((ret->ns == NULL) && (xmlStrEqual(prefix, BAD_CAST "xml"))) { - ret->ns = xmlSearchNs(ctxt->myDoc, ret, prefix); + int res; + + res = xmlSearchNsSafe(ret, prefix, &ret->ns); + if (res < 0) + xmlSAX2ErrMemory(ctxt); } if (ret->ns == NULL) { ns = xmlNewNs(ret, NULL, prefix); if (ns == NULL) {
- xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElementNs"); + xmlSAX2ErrMemory(ctxt); return; } if (prefix != NULL) @@ -2278,22 +2264,26 @@ xmlSAX2StartElementNs(void *ctx,
fullname = xmlDictQLookup(ctxt->dict, attributes[j+1], attributes[j]); - if (fullname != NULL) { - attr = xmlSAX2AttributeNs(ctxt, fullname, NULL, - attributes[j+3], - attributes[j+4]); - goto have_attr; - } + if (fullname == NULL) { + xmlSAX2ErrMemory(ctxt); + return; + } + attr = xmlSAX2AttributeNs(ctxt, fullname, NULL, + attributes[j+3], + attributes[j+4]); + goto have_attr; } else { lname = xmlBuildQName(attributes[j], attributes[j+1], NULL, 0); - if (lname != NULL) { - attr = xmlSAX2AttributeNs(ctxt, lname, NULL, - attributes[j+3], - attributes[j+4]); - xmlFree(lname); - goto have_attr; - } + if (lname == NULL) { + xmlSAX2ErrMemory(ctxt); + return; + } + attr = xmlSAX2AttributeNs(ctxt, lname, NULL, + attributes[j+3], + attributes[j+4]); + xmlFree(lname); + goto have_attr; } } attr = xmlSAX2AttributeNs(ctxt, attributes[j], attributes[j+1], @@ -2383,9 +2373,12 @@ xmlSAX2Reference(void *ctx, const xmlChar *name)
if (ctx == NULL) return; ret = xmlNewReference(ctxt->myDoc, name); - if (xmlAddChild(ctxt->node, ret) == NULL) { - xmlFreeNode(ret); + if (ret == NULL) { + xmlSAX2ErrMemory(ctxt); + return; } + + xmlSAX2AppendChild(ctxt, ret); }
/** @@ -2432,7 +2425,7 @@ xmlSAX2Text(xmlParserCtxtPtr ctxt, const xmlChar *ch, int len, ctxt->nodelen = len; ctxt->nodemem = len + 1; } else { - xmlSAX2ErrMemory(ctxt, "xmlSAX2Characters"); + xmlSAX2ErrMemory(ctxt); return; } } else { @@ -2441,6 +2434,10 @@ xmlSAX2Text(xmlParserCtxtPtr ctxt, const xmlChar *ch, int len, ((type != XML_TEXT_NODE) || (lastChild->name == xmlStringText)); if ((coalesceText) && (ctxt->nodemem != 0)) { + int maxLength = (ctxt->options & XML_PARSE_HUGE) ? + XML_MAX_HUGE_LENGTH : + XML_MAX_TEXT_LENGTH; + /* * The whole point of maintaining nodelen and nodemem, * xmlTextConcat is too costly, i.e. compute length, @@ -2456,16 +2453,13 @@ xmlSAX2Text(xmlParserCtxtPtr ctxt, const xmlChar *ch, int len, lastChild->content = xmlStrdup(lastChild->content); } if (lastChild->content == NULL) { - xmlSAX2ErrMemory(ctxt, "xmlSAX2Characters: xmlStrdup returned NULL"); + xmlSAX2ErrMemory(ctxt); return; } - if (ctxt->nodelen > INT_MAX - len) { - xmlSAX2ErrMemory(ctxt, "xmlSAX2Characters overflow prevented"); - return; - } - if ((ctxt->nodelen + len > XML_MAX_TEXT_LENGTH) && - ((ctxt->options & XML_PARSE_HUGE) == 0)) { - xmlSAX2ErrMemory(ctxt, "xmlSAX2Characters: huge text node"); + if ((len > maxLength) || (ctxt->nodelen > maxLength - len)) { + xmlFatalErr(ctxt, XML_ERR_RESOURCE_LIMIT, + "Text node too long, try XML_PARSE_HUGE"); + xmlHaltParser(ctxt); return; } if (ctxt->nodelen + len >= ctxt->nodemem) { @@ -2478,7 +2472,7 @@ xmlSAX2Text(xmlParserCtxtPtr ctxt, const xmlChar *ch, int len, size = size > INT_MAX / 2 ? INT_MAX : size * 2; newbuf = (xmlChar *) xmlRealloc(lastChild->content,size); if (newbuf == NULL) { - xmlSAX2ErrMemory(ctxt, "xmlSAX2Characters"); + xmlSAX2ErrMemory(ctxt); return; } ctxt->nodemem = size; @@ -2489,7 +2483,7 @@ xmlSAX2Text(xmlParserCtxtPtr ctxt, const xmlChar *ch, int len, lastChild->content[ctxt->nodelen] = 0; } else if (coalesceText) { if (xmlTextConcat(lastChild, ch, len)) { - xmlSAX2ErrMemory(ctxt, "xmlSAX2Characters"); + xmlSAX2ErrMemory(ctxt); } if (ctxt->node->children != NULL) { ctxt->nodelen = xmlStrlen(lastChild->content); @@ -2503,8 +2497,10 @@ xmlSAX2Text(xmlParserCtxtPtr ctxt, const xmlChar *ch, int len, lastChild->doc = ctxt->myDoc; } else lastChild = xmlNewCDataBlock(ctxt->myDoc, ch, len); - if (lastChild != NULL) { - xmlAddChild(ctxt->node, lastChild); + if (lastChild == NULL) { + xmlSAX2ErrMemory(ctxt); + } else { + xmlSAX2AppendChild(ctxt, lastChild); if (ctxt->node->children != NULL) { ctxt->nodelen = len; ctxt->nodemem = len + 1; @@ -2569,38 +2565,16 @@ xmlSAX2ProcessingInstruction(void *ctx, const xmlChar *target, { xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; xmlNodePtr ret; - xmlNodePtr parent;
if (ctx == NULL) return; - parent = ctxt->node;
ret = xmlNewDocPI(ctxt->myDoc, target, data); - if (ret == NULL) return; - - if (ctxt->linenumbers) { - if (ctxt->input != NULL) { - if ((unsigned) ctxt->input->line < (unsigned) USHRT_MAX) - ret->line = ctxt->input->line; - else - ret->line = USHRT_MAX; - } - } - if (ctxt->inSubset == 1) { - xmlAddChild((xmlNodePtr) ctxt->myDoc->intSubset, ret); - return; - } else if (ctxt->inSubset == 2) { - xmlAddChild((xmlNodePtr) ctxt->myDoc->extSubset, ret); - return; - } - if (parent == NULL) { - xmlAddChild((xmlNodePtr) ctxt->myDoc, (xmlNodePtr) ret); - return; - } - if (parent->type == XML_ELEMENT_NODE) { - xmlAddChild(parent, ret); - } else { - xmlAddSibling(parent, ret); + if (ret == NULL) { + xmlSAX2ErrMemory(ctxt); + return; } + + xmlSAX2AppendChild(ctxt, ret); }
/** @@ -2615,37 +2589,16 @@ xmlSAX2Comment(void *ctx, const xmlChar *value) { xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; xmlNodePtr ret; - xmlNodePtr parent;
if (ctx == NULL) return; - parent = ctxt->node; + ret = xmlNewDocComment(ctxt->myDoc, value); - if (ret == NULL) return; - if (ctxt->linenumbers) { - if (ctxt->input != NULL) { - if ((unsigned) ctxt->input->line < (unsigned) USHRT_MAX) - ret->line = ctxt->input->line; - else - ret->line = USHRT_MAX; - } + if (ret == NULL) { + xmlSAX2ErrMemory(ctxt); + return; }
- if (ctxt->inSubset == 1) { - xmlAddChild((xmlNodePtr) ctxt->myDoc->intSubset, ret); - return; - } else if (ctxt->inSubset == 2) { - xmlAddChild((xmlNodePtr) ctxt->myDoc->extSubset, ret); - return; - } - if (parent == NULL) { - xmlAddChild((xmlNodePtr) ctxt->myDoc, (xmlNodePtr) ret); - return; - } - if (parent->type == XML_ELEMENT_NODE) { - xmlAddChild(parent, ret); - } else { - xmlAddSibling(parent, ret); - } + xmlSAX2AppendChild(ctxt, ret); }
/** diff --git a/libs/xml2/buf.c b/libs/xml2/buf.c index 469fe64d524..c486bf2b69f 100644 --- a/libs/xml2/buf.c +++ b/libs/xml2/buf.c @@ -89,10 +89,9 @@ struct _xmlBuf { * To be improved... */ static void -xmlBufMemoryError(xmlBufPtr buf, const char *extra) +xmlBufMemoryError(xmlBufPtr buf) { - __xmlSimpleError(XML_FROM_BUFFER, XML_ERR_NO_MEMORY, NULL, NULL, extra); - if ((buf) && (buf->error == 0)) + if (buf->error == 0) buf->error = XML_ERR_NO_MEMORY; }
@@ -104,10 +103,9 @@ xmlBufMemoryError(xmlBufPtr buf, const char *extra) * To be improved... */ static void -xmlBufOverflowError(xmlBufPtr buf, const char *extra) +xmlBufOverflowError(xmlBufPtr buf) { - __xmlSimpleError(XML_FROM_BUFFER, XML_BUF_OVERFLOW, NULL, NULL, extra); - if ((buf) && (buf->error == 0)) + if (buf->error == 0) buf->error = XML_BUF_OVERFLOW; }
@@ -123,10 +121,8 @@ xmlBufCreate(void) { xmlBufPtr ret;
ret = (xmlBufPtr) xmlMalloc(sizeof(xmlBuf)); - if (ret == NULL) { - xmlBufMemoryError(NULL, "creating buffer"); + if (ret == NULL) return(NULL); - } ret->use = 0; ret->error = 0; ret->buffer = NULL; @@ -135,7 +131,6 @@ xmlBufCreate(void) { ret->alloc = xmlBufferAllocScheme; ret->content = (xmlChar *) xmlMallocAtomic(ret->size); if (ret->content == NULL) { - xmlBufMemoryError(ret, "creating buffer"); xmlFree(ret); return(NULL); } @@ -158,10 +153,8 @@ xmlBufCreateSize(size_t size) { if (size == SIZE_MAX) return(NULL); ret = (xmlBufPtr) xmlMalloc(sizeof(xmlBuf)); - if (ret == NULL) { - xmlBufMemoryError(NULL, "creating buffer"); + if (ret == NULL) return(NULL); - } ret->use = 0; ret->error = 0; ret->buffer = NULL; @@ -171,7 +164,6 @@ xmlBufCreateSize(size_t size) { if (ret->size){ ret->content = (xmlChar *) xmlMallocAtomic(ret->size); if (ret->content == NULL) { - xmlBufMemoryError(ret, "creating buffer"); xmlFree(ret); return(NULL); } @@ -203,8 +195,16 @@ xmlBufDetach(xmlBufPtr buf) { if (buf->error) return(NULL);
- ret = buf->content; + if ((buf->alloc == XML_BUFFER_ALLOC_IO) && + (buf->content != buf->contentIO)) { + ret = xmlStrndup(buf->content, buf->use); + xmlFree(buf->contentIO); + } else { + ret = buf->content; + } + buf->content = NULL; + buf->contentIO = NULL; buf->size = 0; buf->use = 0; UPDATE_COMPAT(buf); @@ -383,7 +383,7 @@ xmlBufGrowInternal(xmlBufPtr buf, size_t len) { if (len < buf->size - buf->use) return(buf->size - buf->use - 1); if (len >= SIZE_MAX - buf->use) { - xmlBufMemoryError(buf, "growing buffer past SIZE_MAX"); + xmlBufMemoryError(buf); return(0); }
@@ -400,7 +400,7 @@ xmlBufGrowInternal(xmlBufPtr buf, size_t len) { */ if ((buf->use + len + 1 >= XML_MAX_TEXT_LENGTH) || (buf->size >= XML_MAX_TEXT_LENGTH)) { - xmlBufMemoryError(buf, "buffer error: text too long\n"); + xmlBufMemoryError(buf); return(0); } if (size >= XML_MAX_TEXT_LENGTH) @@ -411,7 +411,7 @@ xmlBufGrowInternal(xmlBufPtr buf, size_t len) {
newbuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + size); if (newbuf == NULL) { - xmlBufMemoryError(buf, "growing buffer"); + xmlBufMemoryError(buf); return(0); } buf->contentIO = newbuf; @@ -419,7 +419,7 @@ xmlBufGrowInternal(xmlBufPtr buf, size_t len) { } else { newbuf = (xmlChar *) xmlRealloc(buf->content, size); if (newbuf == NULL) { - xmlBufMemoryError(buf, "growing buffer"); + xmlBufMemoryError(buf); return(0); } buf->content = newbuf; @@ -641,7 +641,7 @@ xmlBufResize(xmlBufPtr buf, size_t size) * Used to provide parsing limits */ if (size >= XML_MAX_TEXT_LENGTH) { - xmlBufMemoryError(buf, "buffer error: text too long\n"); + xmlBufMemoryError(buf); return(0); } } @@ -662,7 +662,7 @@ xmlBufResize(xmlBufPtr buf, size_t size) } while (size > newSize) { if (newSize > SIZE_MAX / 2) { - xmlBufMemoryError(buf, "growing buffer"); + xmlBufMemoryError(buf); return 0; } newSize *= 2; @@ -678,7 +678,7 @@ xmlBufResize(xmlBufPtr buf, size_t size) newSize = buf->size; while (size > newSize) { if (newSize > SIZE_MAX / 2) { - xmlBufMemoryError(buf, "growing buffer"); + xmlBufMemoryError(buf); return 0; } newSize *= 2; @@ -703,7 +703,7 @@ xmlBufResize(xmlBufPtr buf, size_t size) } else { rebuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + newSize); if (rebuf == NULL) { - xmlBufMemoryError(buf, "growing buffer"); + xmlBufMemoryError(buf); return 0; } buf->contentIO = rebuf; @@ -731,7 +731,7 @@ xmlBufResize(xmlBufPtr buf, size_t size) } } if (rebuf == NULL) { - xmlBufMemoryError(buf, "growing buffer"); + xmlBufMemoryError(buf); return 0; } buf->content = rebuf; @@ -751,8 +751,7 @@ xmlBufResize(xmlBufPtr buf, size_t size) * Add a string range to an XML buffer. if len == -1, the length of * str is recomputed. * - * Returns 0 successful, a positive error code number otherwise - * and -1 in case of internal or API error. + * Returns 0 if successful, -1 in case of error. */ int xmlBufAdd(xmlBufPtr buf, const xmlChar *str, int len) { @@ -776,7 +775,7 @@ xmlBufAdd(xmlBufPtr buf, const xmlChar *str, int len) { /* Note that both buf->size and buf->use can be zero here. */ if ((size_t) len >= buf->size - buf->use) { if ((size_t) len >= SIZE_MAX - buf->use) { - xmlBufMemoryError(buf, "growing buffer past SIZE_MAX"); + xmlBufMemoryError(buf); return(-1); } needSize = buf->use + len + 1; @@ -785,14 +784,12 @@ xmlBufAdd(xmlBufPtr buf, const xmlChar *str, int len) { * Used to provide parsing limits */ if (needSize >= XML_MAX_TEXT_LENGTH) { - xmlBufMemoryError(buf, "buffer error: text too long\n"); + xmlBufMemoryError(buf); return(-1); } } - if (!xmlBufResize(buf, needSize)){ - xmlBufMemoryError(buf, "growing buffer"); - return XML_ERR_NO_MEMORY; - } + if (!xmlBufResize(buf, needSize)) + return(-1); }
memmove(&buf->content[buf->use], str, len); @@ -821,72 +818,6 @@ xmlBufCat(xmlBufPtr buf, const xmlChar *str) { return xmlBufAdd(buf, str, -1); }
-/** - * xmlBufCCat: - * @buf: the buffer to dump - * @str: the C char string - * - * Append a zero terminated C string to an XML buffer. - * - * Returns 0 successful, a positive error code number otherwise - * and -1 in case of internal or API error. - */ -int -xmlBufCCat(xmlBufPtr buf, const char *str) { - return xmlBufCat(buf, (const xmlChar *) str); -} - -/** - * xmlBufWriteQuotedString: - * @buf: the XML buffer output - * @string: the string to add - * - * routine which manage and grows an output buffer. This one writes - * a quoted or double quoted #xmlChar string, checking first if it holds - * quote or double-quotes internally - * - * Returns 0 if successful, a positive error code number otherwise - * and -1 in case of internal or API error. - */ -int -xmlBufWriteQuotedString(xmlBufPtr buf, const xmlChar *string) { - const xmlChar *cur, *base; - if ((buf == NULL) || (buf->error)) - return(-1); - CHECK_COMPAT(buf) - if (xmlStrchr(string, '"')) { - if (xmlStrchr(string, ''')) { - xmlBufCCat(buf, """); - base = cur = string; - while(*cur != 0){ - if(*cur == '"'){ - if (base != cur) - xmlBufAdd(buf, base, cur - base); - xmlBufAdd(buf, BAD_CAST """, 6); - cur++; - base = cur; - } - else { - cur++; - } - } - if (base != cur) - xmlBufAdd(buf, base, cur - base); - xmlBufCCat(buf, """); - } - else{ - xmlBufCCat(buf, "'"); - xmlBufCat(buf, string); - xmlBufCCat(buf, "'"); - } - } else { - xmlBufCCat(buf, """); - xmlBufCat(buf, string); - xmlBufCCat(buf, """); - } - return(0); -} - /** * xmlBufFromBuffer: * @buffer: incoming old buffer to convert to a new one @@ -907,7 +838,6 @@ xmlBufFromBuffer(xmlBufferPtr buffer) {
ret = (xmlBufPtr) xmlMalloc(sizeof(xmlBuf)); if (ret == NULL) { - xmlBufMemoryError(NULL, "creating buffer"); return(NULL); } ret->use = buffer->use; @@ -941,12 +871,19 @@ xmlBufBackToBuffer(xmlBufPtr buf) { if (buf == NULL) return(NULL); CHECK_COMPAT(buf) - if ((buf->error) || (buf->buffer == NULL)) { + ret = buf->buffer; + + if ((buf->error) || (ret == NULL)) { xmlBufFree(buf); + if (ret != NULL) { + ret->content = NULL; + ret->contentIO = NULL; + ret->use = 0; + ret->size = 0; + } return(NULL); }
- ret = buf->buffer; /* * What to do in case of error in the buffer ??? */ @@ -956,7 +893,7 @@ xmlBufBackToBuffer(xmlBufPtr buf) { * maximum allowed memory for an xmlBuffer on this architecture. * Keep the buffer but provide a truncated size value. */ - xmlBufOverflowError(buf, "Used size too big for xmlBuffer"); + xmlBufOverflowError(buf); ret->use = INT_MAX; ret->size = INT_MAX; } else if (buf->size > INT_MAX) { @@ -966,7 +903,7 @@ xmlBufBackToBuffer(xmlBufPtr buf) { * limit. * Keep the buffer but provide a truncated size value. */ - xmlBufOverflowError(buf, "Allocated size too big for xmlBuffer"); + xmlBufOverflowError(buf); ret->use = buf->use; ret->size = INT_MAX; } else { @@ -980,32 +917,6 @@ xmlBufBackToBuffer(xmlBufPtr buf) { return(ret); }
-/** - * xmlBufMergeBuffer: - * @buf: an xmlBufPtr - * @buffer: the buffer to consume into @buf - * - * The content of @buffer is appended to @buf and @buffer is freed - * - * Returns -1 in case of error, 0 otherwise, in any case @buffer is freed - */ -int -xmlBufMergeBuffer(xmlBufPtr buf, xmlBufferPtr buffer) { - int ret = 0; - - if ((buf == NULL) || (buf->error)) { - xmlBufferFree(buffer); - return(-1); - } - CHECK_COMPAT(buf) - if ((buffer != NULL) && (buffer->content != NULL) && - (buffer->use > 0)) { - ret = xmlBufAdd(buf, buffer->content, buffer->use); - } - xmlBufferFree(buffer); - return(ret); -} - /** * xmlBufResetInput: * @buf: an xmlBufPtr @@ -1017,16 +928,7 @@ xmlBufMergeBuffer(xmlBufPtr buf, xmlBufferPtr buffer) { */ int xmlBufResetInput(xmlBufPtr buf, xmlParserInputPtr input) { - if (input == NULL) - return(-1); - if ((buf == NULL) || (buf->error)) { - input->base = input->cur = input->end = BAD_CAST ""; - return(-1); - } - CHECK_COMPAT(buf) - input->base = input->cur = buf->content; - input->end = &buf->content[buf->use]; - return(0); + return(xmlBufUpdateInput(buf, input, 0)); }
/** @@ -1042,16 +944,8 @@ xmlBufResetInput(xmlBufPtr buf, xmlParserInputPtr input) { */ int xmlBufUpdateInput(xmlBufPtr buf, xmlParserInputPtr input, size_t pos) { - if (input == NULL) + if ((buf == NULL) || (input == NULL)) return(-1); - /* - * TODO: It might be safer to keep using the buffer content if there - * was an error. - */ - if ((buf == NULL) || (buf->error)) { - input->base = input->cur = input->end = BAD_CAST ""; - return(-1); - } CHECK_COMPAT(buf) input->base = buf->content; input->cur = input->base + pos; diff --git a/libs/xml2/catalog.c b/libs/xml2/catalog.c index 945ea2c8776..27af95f47ab 100644 --- a/libs/xml2/catalog.c +++ b/libs/xml2/catalog.c @@ -16,6 +16,7 @@ #include "libxml.h"
#ifdef LIBXML_CATALOG_ENABLED +#include <stdio.h> #include <stdlib.h> #include <string.h> #ifdef HAVE_SYS_STAT_H @@ -49,21 +50,6 @@ # define PATH_SEPARATOR ':' #endif
-/** - * TODO: - * - * macro to flag unimplemented blocks - * XML_CATALOG_PREFER user env to select between system/public preferred - * option. C.f. Richard Tobin <richard@cogsci.ed.ac.uk> - *> Just FYI, I am using an environment variable XML_CATALOG_PREFER with - *> values "system" and "public". I have made the default be "system" to - *> match yours. - */ -#define TODO \ - xmlGenericError(xmlGenericErrorContext, \ - "Unimplemented block at %s:%d\n", \ - __FILE__, __LINE__); - #define XML_URN_PUBID "urn:publicid:" #define XML_CATAL_BREAK ((xmlChar *) -1) #ifndef XML_XML_DEFAULT_CATALOG @@ -73,15 +59,6 @@ #define XML_SGML_DEFAULT_CATALOG "file://" SYSCONFDIR "/sgml/catalog" #endif
-#if defined(_WIN32) && defined(_MSC_VER) -#undef XML_XML_DEFAULT_CATALOG -static char XML_XML_DEFAULT_CATALOG[256] = "file://" SYSCONFDIR "/xml/catalog"; -#if !defined(_WINDOWS_) -void* __stdcall GetModuleHandleA(const char*); -unsigned long __stdcall GetModuleFileNameA(void*, char*, unsigned long); -#endif -#endif - static xmlChar *xmlCatalogNormalizePublic(const xmlChar *pubID); static int xmlExpandCatalog(xmlCatalogPtr catal, const char *filename);
@@ -212,12 +189,9 @@ static int xmlCatalogInitialized = 0; * Handle an out of memory condition */ static void -xmlCatalogErrMemory(const char *extra) +xmlCatalogErrMemory(void) { - __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_CATALOG, - XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0, - extra, NULL, NULL, 0, 0, - "Memory allocation failed : %s\n", extra); + xmlRaiseMemoryError(NULL, NULL, NULL, XML_FROM_CATALOG, NULL); }
/** @@ -234,11 +208,15 @@ xmlCatalogErr(xmlCatalogEntryPtr catal, xmlNodePtr node, int error, const char *msg, const xmlChar *str1, const xmlChar *str2, const xmlChar *str3) { - __xmlRaiseError(NULL, NULL, NULL, catal, node, XML_FROM_CATALOG, - error, XML_ERR_ERROR, NULL, 0, - (const char *) str1, (const char *) str2, - (const char *) str3, 0, 0, - msg, str1, str2, str3); + int res; + + res = __xmlRaiseError(NULL, NULL, NULL, catal, node, + XML_FROM_CATALOG, error, XML_ERR_ERROR, NULL, 0, + (const char *) str1, (const char *) str2, + (const char *) str3, 0, 0, + msg, str1, str2, str3); + if (res < 0) + xmlCatalogErrMemory(); }
@@ -270,7 +248,7 @@ xmlNewCatalogEntry(xmlCatalogEntryType type, const xmlChar *name,
ret = (xmlCatalogEntryPtr) xmlMalloc(sizeof(xmlCatalogEntry)); if (ret == NULL) { - xmlCatalogErrMemory("allocating catalog entry"); + xmlCatalogErrMemory(); return(NULL); } ret->next = NULL; @@ -328,13 +306,13 @@ xmlFreeCatalogEntry(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
if (xmlDebugCatalogs) { if (ret->name != NULL) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Free catalog entry %s\n", ret->name); else if (ret->value != NULL) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Free catalog entry %s\n", ret->value); else - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Free catalog entry\n"); }
@@ -408,7 +386,7 @@ xmlCreateNewCatalog(xmlCatalogType type, xmlCatalogPrefer prefer) {
ret = (xmlCatalogPtr) xmlMalloc(sizeof(xmlCatalog)); if (ret == NULL) { - xmlCatalogErrMemory("allocating catalog"); + xmlCatalogErrMemory(); return(NULL); } memset(ret, 0, sizeof(xmlCatalog)); @@ -792,7 +770,7 @@ xmlConvertSGMLCatalog(xmlCatalogPtr catal) { return(-1);
if (xmlDebugCatalogs) { - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Converting SGML catalog to XML\n"); } xmlHashScan(catal->sgml, xmlCatalogConvertEntry, &catal); @@ -884,13 +862,12 @@ xmlDocPtr xmlParseCatalogFile(const char *filename) { xmlDocPtr ret; xmlParserCtxtPtr ctxt; - char *directory = NULL; xmlParserInputPtr inputStream; xmlParserInputBufferPtr buf;
ctxt = xmlNewParserCtxt(); if (ctxt == NULL) { - xmlCatalogErrMemory("allocating parser context"); + xmlCatalogErrMemory(); return(NULL); }
@@ -912,10 +889,7 @@ xmlParseCatalogFile(const char *filename) { xmlBufResetInput(buf->buffer, inputStream);
inputPush(ctxt, inputStream); - if (ctxt->directory == NULL) - directory = xmlParserGetDirectory(filename); - if ((ctxt->directory == NULL) && (directory != NULL)) - ctxt->directory = directory; + ctxt->valid = 0; ctxt->validate = 0; ctxt->loadsubset = 0; @@ -986,7 +960,7 @@ xmlLoadFileContent(const char *filename) #endif content = (xmlChar*)xmlMallocAtomic(size + 10); if (content == NULL) { - xmlCatalogErrMemory("allocating catalog data"); + xmlCatalogErrMemory(); #ifdef HAVE_STAT close(fd); #else @@ -1171,10 +1145,10 @@ xmlParseXMLCatalogOneNode(xmlNodePtr cur, xmlCatalogEntryType type, if (URL != NULL) { if (xmlDebugCatalogs > 1) { if (nameValue != NULL) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Found %s: '%s' '%s'\n", name, nameValue, URL); else - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Found %s: '%s'\n", name, URL); } ret = xmlNewCatalogEntry(type, nameValue, uriValue, URL, prefer, cgroup); @@ -1343,13 +1317,13 @@ xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename) { doc = xmlParseCatalogFile((const char *) filename); if (doc == NULL) { if (xmlDebugCatalogs) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Failed to parse catalog %s\n", filename); return(NULL); }
if (xmlDebugCatalogs) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "%d Parsing catalog %s\n", xmlGetThreadId(), filename);
cur = xmlDocGetRootElement(doc); @@ -1422,7 +1396,7 @@ xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal) { xmlHashLookup(xmlCatalogXMLFiles, catal->URL); if (doc != NULL) { if (xmlDebugCatalogs) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Found %s in file hash\n", catal->URL);
if (catal->type == XML_CATA_CATALOG) @@ -1434,7 +1408,7 @@ xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal) { return(0); } if (xmlDebugCatalogs) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "%s not found in file hash\n", catal->URL); }
@@ -1461,7 +1435,7 @@ xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal) { xmlCatalogXMLFiles = xmlHashCreate(10); if (xmlCatalogXMLFiles != NULL) { if (xmlDebugCatalogs) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "%s added to file hash\n", catal->URL); xmlHashAddEntry(xmlCatalogXMLFiles, catal->URL, doc); } @@ -1507,7 +1481,7 @@ xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type, typ = xmlGetXMLCatalogEntryType(type); if (typ == XML_CATA_NONE) { if (xmlDebugCatalogs) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Failed to add unknown element %s to catalog\n", type); return(-1); } @@ -1521,7 +1495,7 @@ xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type, if ((orig != NULL) && (cur->type == typ) && (xmlStrEqual(orig, cur->name))) { if (xmlDebugCatalogs) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Updating element %s to catalog\n", type); if (cur->value != NULL) xmlFree(cur->value); @@ -1537,7 +1511,7 @@ xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type, } } if (xmlDebugCatalogs) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Adding element %s to catalog\n", type); if (cur == NULL) catal->children = xmlNewCatalogEntry(typ, orig, replace, @@ -1589,10 +1563,10 @@ xmlDelXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *value) { (xmlStrEqual(value, cur->value))) { if (xmlDebugCatalogs) { if (cur->name != NULL) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Removing element %s from catalog\n", cur->name); else - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Removing element %s from catalog\n", cur->value); } cur->type = XML_CATA_REMOVED; @@ -1648,7 +1622,7 @@ xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID, case XML_CATA_SYSTEM: if (xmlStrEqual(sysID, cur->name)) { if (xmlDebugCatalogs) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Found system match %s, using %s\n", cur->name, cur->URL); catal->depth--; @@ -1677,7 +1651,7 @@ xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID, } if (rewrite != NULL) { if (xmlDebugCatalogs) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Using rewriting rule %s\n", rewrite->name); ret = xmlStrdup(rewrite->URL); if (ret != NULL) @@ -1712,7 +1686,7 @@ xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID, } if (cur->children != NULL) { if (xmlDebugCatalogs) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Trying system delegate %s\n", cur->URL); ret = xmlCatalogListXMLResolve( cur->children, NULL, sysID); @@ -1742,7 +1716,7 @@ xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID, case XML_CATA_PUBLIC: if (xmlStrEqual(pubID, cur->name)) { if (xmlDebugCatalogs) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Found public match %s\n", cur->name); catal->depth--; return(xmlStrdup(cur->URL)); @@ -1791,7 +1765,7 @@ xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID, } if (cur->children != NULL) { if (xmlDebugCatalogs) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Trying public delegate %s\n", cur->URL); ret = xmlCatalogListXMLResolve( cur->children, pubID, NULL); @@ -1881,7 +1855,7 @@ xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) { case XML_CATA_URI: if (xmlStrEqual(URI, cur->name)) { if (xmlDebugCatalogs) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Found URI match %s\n", cur->name); return(xmlStrdup(cur->URL)); } @@ -1908,7 +1882,7 @@ xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) { } if (rewrite != NULL) { if (xmlDebugCatalogs) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Using rewriting rule %s\n", rewrite->name); ret = xmlStrdup(rewrite->URL); if (ret != NULL) @@ -1943,7 +1917,7 @@ xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) { } if (cur->children != NULL) { if (xmlDebugCatalogs) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Trying URI delegate %s\n", cur->URL); ret = xmlCatalogListXMLResolveURI( cur->children, URI); @@ -2012,10 +1986,10 @@ xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID, urnID = xmlCatalogUnWrapURN(pubID); if (xmlDebugCatalogs) { if (urnID == NULL) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Public URN ID %s expanded to NULL\n", pubID); else - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Public URN ID expanded to %s\n", urnID); } ret = xmlCatalogListXMLResolve(catal, urnID, sysID); @@ -2029,10 +2003,10 @@ xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID, urnID = xmlCatalogUnWrapURN(sysID); if (xmlDebugCatalogs) { if (urnID == NULL) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "System URN ID %s expanded to NULL\n", sysID); else - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "System URN ID expanded to %s\n", urnID); } if (pubID == NULL) @@ -2096,10 +2070,10 @@ xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) { urnID = xmlCatalogUnWrapURN(URI); if (xmlDebugCatalogs) { if (urnID == NULL) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "URN ID %s expanded to NULL\n", URI); else - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "URN ID expanded to %s\n", urnID); } ret = xmlCatalogListXMLResolve(catal, urnID, NULL); @@ -2186,7 +2160,7 @@ xmlParseSGMLCatalogPubid(const xmlChar *cur, xmlChar **id) { } buf = (xmlChar *) xmlMallocAtomic(size); if (buf == NULL) { - xmlCatalogErrMemory("allocating public ID"); + xmlCatalogErrMemory(); return(NULL); } while (IS_PUBIDCHAR_CH(*cur) || (*cur == '?')) { @@ -2198,7 +2172,7 @@ xmlParseSGMLCatalogPubid(const xmlChar *cur, xmlChar **id) { size *= 2; tmp = (xmlChar *) xmlRealloc(buf, size); if (tmp == NULL) { - xmlCatalogErrMemory("allocating public ID"); + xmlCatalogErrMemory(); xmlFree(buf); return(NULL); } @@ -2778,7 +2752,7 @@ xmlACatalogResolveSystem(xmlCatalogPtr catal, const xmlChar *sysID) { return(NULL);
if (xmlDebugCatalogs) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Resolve sysID %s\n", sysID);
if (catal->type == XML_XML_CATALOG_TYPE) { @@ -2813,7 +2787,7 @@ xmlACatalogResolvePublic(xmlCatalogPtr catal, const xmlChar *pubID) { return(NULL);
if (xmlDebugCatalogs) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Resolve pubID %s\n", pubID);
if (catal->type == XML_XML_CATALOG_TYPE) { @@ -2852,13 +2826,13 @@ xmlACatalogResolve(xmlCatalogPtr catal, const xmlChar * pubID,
if (xmlDebugCatalogs) { if ((pubID != NULL) && (sysID != NULL)) { - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Resolve: pubID %s sysID %s\n", pubID, sysID); } else if (pubID != NULL) { - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Resolve: pubID %s\n", pubID); } else { - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Resolve: sysID %s\n", sysID); } } @@ -2895,7 +2869,7 @@ xmlACatalogResolveURI(xmlCatalogPtr catal, const xmlChar *URI) { return(NULL);
if (xmlDebugCatalogs) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Resolve URI %s\n", URI);
if (catal->type == XML_XML_CATALOG_TYPE) { @@ -3112,35 +3086,7 @@ xmlInitializeCatalog(void) {
catalogs = (const char *) getenv("XML_CATALOG_FILES"); if (catalogs == NULL) -#if defined(_WIN32) && defined(_MSC_VER) - { - void* hmodule; - hmodule = GetModuleHandleA("libxml2.dll"); - if (hmodule == NULL) - hmodule = GetModuleHandleA(NULL); - if (hmodule != NULL) { - char buf[256]; - unsigned long len = GetModuleFileNameA(hmodule, buf, 255); - if (len != 0) { - char* p = &(buf[len]); - while (*p != '\' && p > buf) - p--; - if (p != buf) { - xmlChar* uri; - strncpy(p, "\..\etc\catalog", 255 - (p - buf)); - uri = xmlCanonicPath((const xmlChar*)buf); - if (uri != NULL) { - strncpy(XML_XML_DEFAULT_CATALOG, (char* )uri, 255); - xmlFree(uri); - } - } - } - } - catalogs = XML_XML_DEFAULT_CATALOG; - } -#else catalogs = XML_XML_DEFAULT_CATALOG; -#endif
catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, xmlCatalogDefaultPrefer); @@ -3272,7 +3218,7 @@ xmlCatalogCleanup(void) {
xmlRMutexLock(xmlCatalogMutex); if (xmlDebugCatalogs) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Catalogs cleanup\n"); if (xmlCatalogXMLFiles != NULL) xmlHashFree(xmlCatalogXMLFiles, xmlFreeCatalogHashEntryList); @@ -3500,19 +3446,19 @@ xmlCatalogSetDefaults(xmlCatalogAllow allow) { if (xmlDebugCatalogs) { switch (allow) { case XML_CATA_ALLOW_NONE: - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Disabling catalog usage\n"); break; case XML_CATA_ALLOW_GLOBAL: - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Allowing only global catalogs\n"); break; case XML_CATA_ALLOW_DOCUMENT: - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Allowing only catalogs from the document\n"); break; case XML_CATA_ALLOW_ALL: - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Allowing all catalogs\n"); break; } @@ -3540,11 +3486,11 @@ xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer) { if (xmlDebugCatalogs) { switch (prefer) { case XML_CATA_PREFER_PUBLIC: - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Setting catalog preference to PUBLIC\n"); break; case XML_CATA_PREFER_SYSTEM: - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Setting catalog preference to SYSTEM\n"); break; default: @@ -3620,7 +3566,7 @@ xmlCatalogAddLocal(void *catalogs, const xmlChar *URL) { return(catalogs);
if (xmlDebugCatalogs) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Adding document catalog %s\n", URL);
add = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, URL, NULL, @@ -3664,13 +3610,13 @@ xmlCatalogLocalResolve(void *catalogs, const xmlChar *pubID,
if (xmlDebugCatalogs) { if ((pubID != NULL) && (sysID != NULL)) { - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Local Resolve: pubID %s sysID %s\n", pubID, sysID); } else if (pubID != NULL) { - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Local Resolve: pubID %s\n", pubID); } else { - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Local Resolve: sysID %s\n", sysID); } } @@ -3707,7 +3653,7 @@ xmlCatalogLocalResolveURI(void *catalogs, const xmlChar *URI) { return(NULL);
if (xmlDebugCatalogs) - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Resolve URI %s\n", URI);
catal = (xmlCatalogEntryPtr) catalogs; @@ -3743,7 +3689,7 @@ xmlCatalogGetSystem(const xmlChar *sysID) { xmlInitializeCatalog();
if (msg == 0) { - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Use of deprecated xmlCatalogGetSystem() call\n"); msg++; } @@ -3787,7 +3733,7 @@ xmlCatalogGetPublic(const xmlChar *pubID) { xmlInitializeCatalog();
if (msg == 0) { - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Use of deprecated xmlCatalogGetPublic() call\n"); msg++; } diff --git a/libs/xml2/debugXML.c b/libs/xml2/debugXML.c index 303515ec8c6..ed56b0f882a 100644 --- a/libs/xml2/debugXML.c +++ b/libs/xml2/debugXML.c @@ -154,31 +154,21 @@ static void xmlDebugErr(xmlDebugCtxtPtr ctxt, int error, const char *msg) { ctxt->errors++; - __xmlRaiseError(NULL, NULL, NULL, - NULL, ctxt->node, XML_FROM_CHECK, - error, XML_ERR_ERROR, NULL, 0, - NULL, NULL, NULL, 0, 0, - "%s", msg); + fprintf(ctxt->output, "ERROR %d: %s", error, msg); } static void LIBXML_ATTR_FORMAT(3,0) xmlDebugErr2(xmlDebugCtxtPtr ctxt, int error, const char *msg, int extra) { ctxt->errors++; - __xmlRaiseError(NULL, NULL, NULL, - NULL, ctxt->node, XML_FROM_CHECK, - error, XML_ERR_ERROR, NULL, 0, - NULL, NULL, NULL, 0, 0, - msg, extra); + fprintf(ctxt->output, "ERROR %d: ", error); + fprintf(ctxt->output, msg, extra); } static void LIBXML_ATTR_FORMAT(3,0) xmlDebugErr3(xmlDebugCtxtPtr ctxt, int error, const char *msg, const char *extra) { ctxt->errors++; - __xmlRaiseError(NULL, NULL, NULL, - NULL, ctxt->node, XML_FROM_CHECK, - error, XML_ERR_ERROR, NULL, 0, - NULL, NULL, NULL, 0, 0, - msg, extra); + fprintf(ctxt->output, "ERROR %d: ", error); + fprintf(ctxt->output, msg, extra); }
/** @@ -1824,47 +1814,47 @@ xmlShellPrintXPathError(int errorType, const char *arg)
switch (errorType) { case XPATH_UNDEFINED: - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "%s: no such node\n", arg); break;
case XPATH_BOOLEAN: - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "%s is a Boolean\n", arg); break; case XPATH_NUMBER: - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "%s is a number\n", arg); break; case XPATH_STRING: - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "%s is a string\n", arg); break; #ifdef LIBXML_XPTR_LOCS_ENABLED case XPATH_POINT: - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "%s is a point\n", arg); break; case XPATH_RANGE: - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "%s is a range\n", arg); break; case XPATH_LOCATIONSET: - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "%s is a range\n", arg); break; #endif /* LIBXML_XPTR_LOCS_ENABLED */ case XPATH_USERS: - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "%s is user-defined\n", arg); break; case XPATH_XSLT_TREE: - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "%s is an XSLT value tree\n", arg); break; } #if 0 - xmlGenericError(xmlGenericErrorContext, + fprintf(stderr, "Try casting the result string function (xpath builtin)\n", arg); #endif @@ -1940,26 +1930,26 @@ xmlShellPrintXPathResultCtxt(xmlShellCtxtPtr ctxt,xmlXPathObjectPtr list) list->nodesetval->nodeTab[indx]); } } else { - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "Empty node set\n"); } break; #else - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "Node set\n"); #endif /* LIBXML_OUTPUT_ENABLED */ } case XPATH_BOOLEAN: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "Is a Boolean:%s\n", xmlBoolToText(list->boolval)); break; case XPATH_NUMBER: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "Is a number:%0g\n", list->floatval); break; case XPATH_STRING: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "Is a string:%s\n", list->stringval); break;
@@ -2331,6 +2321,16 @@ xmlShellSetContent(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED, return (0); }
+static void +xmlShellPrintf(void *ctx, const char *msg, ...) { + xmlShellCtxtPtr sctxt = ctx; + va_list ap; + + va_start(ap, msg); + vfprintf(sctxt->output, msg, ap); + va_end(ap); +} + #ifdef LIBXML_SCHEMAS_ENABLED /** * xmlShellRNGValidate: @@ -2355,23 +2355,23 @@ xmlShellRNGValidate(xmlShellCtxtPtr sctxt, char *schemas, int ret;
ctxt = xmlRelaxNGNewParserCtxt(schemas); - xmlRelaxNGSetParserErrors(ctxt, xmlGenericError, xmlGenericError, NULL); + xmlRelaxNGSetParserErrors(ctxt, xmlShellPrintf, xmlShellPrintf, sctxt); relaxngschemas = xmlRelaxNGParse(ctxt); xmlRelaxNGFreeParserCtxt(ctxt); if (relaxngschemas == NULL) { - xmlGenericError(xmlGenericErrorContext, + fprintf(sctxt->output, "Relax-NG schema %s failed to compile\n", schemas); return(-1); } vctxt = xmlRelaxNGNewValidCtxt(relaxngschemas); - xmlRelaxNGSetValidErrors(vctxt, xmlGenericError, xmlGenericError, NULL); + xmlRelaxNGSetValidErrors(vctxt, xmlShellPrintf, xmlShellPrintf, sctxt); ret = xmlRelaxNGValidateDoc(vctxt, sctxt->doc); if (ret == 0) { - fprintf(stderr, "%s validates\n", sctxt->filename); + fprintf(sctxt->output, "%s validates\n", sctxt->filename); } else if (ret > 0) { - fprintf(stderr, "%s fails to validate\n", sctxt->filename); + fprintf(sctxt->output, "%s fails to validate\n", sctxt->filename); } else { - fprintf(stderr, "%s validation generated an internal error\n", + fprintf(sctxt->output, "%s validation generated an internal error\n", sctxt->filename); } xmlRelaxNGFreeValidCtxt(vctxt); @@ -2506,7 +2506,7 @@ xmlShellWrite(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node, } #ifdef W_OK if (access((char *) filename, W_OK)) { - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "Cannot write to %s\n", filename); return (-1); } @@ -2514,7 +2514,7 @@ xmlShellWrite(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node, switch (node->type) { case XML_DOCUMENT_NODE: if (xmlSaveFile((char *) filename, ctxt->doc) < -1) { - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "Failed to write to %s\n", filename); return (-1); } @@ -2522,13 +2522,13 @@ xmlShellWrite(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node, case XML_HTML_DOCUMENT_NODE: #ifdef LIBXML_HTML_ENABLED if (htmlSaveFile((char *) filename, ctxt->doc) < 0) { - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "Failed to write to %s\n", filename); return (-1); } #else if (xmlSaveFile((char *) filename, ctxt->doc) < -1) { - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "Failed to write to %s\n", filename); return (-1); } @@ -2539,7 +2539,7 @@ xmlShellWrite(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node,
f = fopen((char *) filename, "w"); if (f == NULL) { - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "Failed to write to %s\n", filename); return (-1); } @@ -2575,7 +2575,7 @@ xmlShellSave(xmlShellCtxtPtr ctxt, char *filename, return (-1); #ifdef W_OK if (access((char *) filename, W_OK)) { - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "Cannot save to %s\n", filename); return (-1); } @@ -2583,25 +2583,25 @@ xmlShellSave(xmlShellCtxtPtr ctxt, char *filename, switch (ctxt->doc->type) { case XML_DOCUMENT_NODE: if (xmlSaveFile((char *) filename, ctxt->doc) < 0) { - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "Failed to save to %s\n", filename); } break; case XML_HTML_DOCUMENT_NODE: #ifdef LIBXML_HTML_ENABLED if (htmlSaveFile((char *) filename, ctxt->doc) < 0) { - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "Failed to save to %s\n", filename); } #else if (xmlSaveFile((char *) filename, ctxt->doc) < 0) { - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "Failed to save to %s\n", filename); } #endif /* LIBXML_HTML_ENABLED */ break; default: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "To save to subparts of a document use the 'write' command\n"); return (-1);
@@ -2634,8 +2634,9 @@ xmlShellValidate(xmlShellCtxtPtr ctxt, char *dtd,
if ((ctxt == NULL) || (ctxt->doc == NULL)) return(-1); memset(&vctxt, 0, sizeof(vctxt)); - vctxt.error = xmlGenericError; - vctxt.warning = xmlGenericError; + vctxt.error = xmlShellPrintf; + vctxt.warning = xmlShellPrintf; + vctxt.userData = ctxt;
if ((dtd == NULL) || (dtd[0] == 0)) { res = xmlValidateDocument(&vctxt, ctxt->doc); @@ -2791,7 +2792,7 @@ xmlShellPwd(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED, char *buffer, * using a environment similar to a UNIX commandline. */ void -xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input, +xmlShell(xmlDocPtr doc, const char *filename, xmlShellReadlineFunc input, FILE * output) { char prompt[500] = "/ > "; @@ -2936,22 +2937,13 @@ xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input, xmlShellSave(ctxt, arg, NULL, NULL); } else if (!strcmp(command, "write")) { if (arg[0] == 0) - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "Write command requires a filename argument\n"); else xmlShellWrite(ctxt, arg, ctxt->node, NULL); #endif /* LIBXML_OUTPUT_ENABLED */ } else if (!strcmp(command, "grep")) { xmlShellGrep(ctxt, arg, ctxt->node, NULL); - } else if (!strcmp(command, "free")) { - if (arg[0] == 0) { - xmlMemShow(ctxt->output, 0); - } else { - int len = 0; - - sscanf(arg, "%d", &len); - xmlMemShow(ctxt->output, len); - } } else if (!strcmp(command, "pwd")) { char dir[500];
@@ -2971,7 +2963,7 @@ xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input, if (list != NULL) { switch (list->type) { case XPATH_UNDEFINED: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s: no such node\n", arg); break; case XPATH_NODESET:{ @@ -2989,37 +2981,37 @@ xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input, break; } case XPATH_BOOLEAN: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a Boolean\n", arg); break; case XPATH_NUMBER: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a number\n", arg); break; case XPATH_STRING: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a string\n", arg); break; #ifdef LIBXML_XPTR_LOCS_ENABLED case XPATH_POINT: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a point\n", arg); break; case XPATH_RANGE: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a range\n", arg); break; case XPATH_LOCATIONSET: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a range\n", arg); break; #endif /* LIBXML_XPTR_LOCS_ENABLED */ case XPATH_USERS: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is user-defined\n", arg); break; case XPATH_XSLT_TREE: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is an XSLT value tree\n", arg); break; @@ -3028,7 +3020,7 @@ xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input, xmlXPathFreeObject(list); #endif } else { - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s: no such node\n", arg); } ctxt->pctxt->node = NULL; @@ -3040,7 +3032,7 @@ xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input, #ifdef LIBXML_XPATH_ENABLED } else if (!strcmp(command, "setns")) { if (arg[0] == 0) { - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "setns: prefix=[nsuri] required\n"); } else { xmlShellRegisterNamespace(ctxt, arg, NULL, NULL); @@ -3052,7 +3044,7 @@ xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input, xmlShellRegisterRootNamespaces(ctxt, NULL, root, NULL); } else if (!strcmp(command, "xpath")) { if (arg[0] == 0) { - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "xpath: expression required\n"); } else { ctxt->pctxt->node = ctxt->node; @@ -3084,7 +3076,7 @@ xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input, if (list != NULL) { switch (list->type) { case XPATH_UNDEFINED: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s: no such node\n", arg); break; case XPATH_NODESET:{ @@ -3108,37 +3100,37 @@ xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input, break; } case XPATH_BOOLEAN: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a Boolean\n", arg); break; case XPATH_NUMBER: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a number\n", arg); break; case XPATH_STRING: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a string\n", arg); break; #ifdef LIBXML_XPTR_LOCS_ENABLED case XPATH_POINT: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a point\n", arg); break; case XPATH_RANGE: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a range\n", arg); break; case XPATH_LOCATIONSET: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a range\n", arg); break; #endif /* LIBXML_XPTR_LOCS_ENABLED */ case XPATH_USERS: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is user-defined\n", arg); break; case XPATH_XSLT_TREE: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is an XSLT value tree\n", arg); break; @@ -3147,7 +3139,7 @@ xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input, xmlXPathFreeObject(list); #endif } else { - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s: no such node\n", arg); } ctxt->pctxt->node = NULL; @@ -3168,7 +3160,7 @@ xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input, if (list != NULL) { switch (list->type) { case XPATH_UNDEFINED: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s: no such node\n", arg); break; case XPATH_NODESET:{ @@ -3187,37 +3179,37 @@ xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input, break; } case XPATH_BOOLEAN: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a Boolean\n", arg); break; case XPATH_NUMBER: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a number\n", arg); break; case XPATH_STRING: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a string\n", arg); break; #ifdef LIBXML_XPTR_LOCS_ENABLED case XPATH_POINT: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a point\n", arg); break; case XPATH_RANGE: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a range\n", arg); break; case XPATH_LOCATIONSET: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a range\n", arg); break; #endif /* LIBXML_XPTR_LOCS_ENABLED */ case XPATH_USERS: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is user-defined\n", arg); break; case XPATH_XSLT_TREE: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is an XSLT value tree\n", arg); break; @@ -3226,7 +3218,7 @@ xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input, xmlXPathFreeObject(list); #endif } else { - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s: no such node\n", arg); } ctxt->pctxt->node = NULL; @@ -3249,7 +3241,7 @@ xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input, if (list != NULL) { switch (list->type) { case XPATH_UNDEFINED: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s: no such node\n", arg); break; case XPATH_NODESET: @@ -3259,52 +3251,52 @@ xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input, if ((ctxt->node != NULL) && (ctxt->node->type == XML_NAMESPACE_DECL)) { - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "cannot cd to namespace\n"); ctxt->node = NULL; } } else - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a %d Node Set\n", arg, list->nodesetval->nodeNr); } else - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is an empty Node Set\n", arg); break; case XPATH_BOOLEAN: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a Boolean\n", arg); break; case XPATH_NUMBER: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a number\n", arg); break; case XPATH_STRING: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a string\n", arg); break; #ifdef LIBXML_XPTR_LOCS_ENABLED case XPATH_POINT: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a point\n", arg); break; case XPATH_RANGE: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a range\n", arg); break; case XPATH_LOCATIONSET: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a range\n", arg); break; #endif /* LIBXML_XPTR_LOCS_ENABLED */ case XPATH_USERS: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is user-defined\n", arg); break; case XPATH_XSLT_TREE: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is an XSLT value tree\n", arg); break; @@ -3313,7 +3305,7 @@ xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input, xmlXPathFreeObject(list); #endif } else { - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s: no such node\n", arg); } ctxt->pctxt->node = NULL; @@ -3333,7 +3325,7 @@ xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input, if (list != NULL) { switch (list->type) { case XPATH_UNDEFINED: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s: no such node\n", arg); break; case XPATH_NODESET:{ @@ -3354,37 +3346,37 @@ xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input, break; } case XPATH_BOOLEAN: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a Boolean\n", arg); break; case XPATH_NUMBER: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a number\n", arg); break; case XPATH_STRING: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a string\n", arg); break; #ifdef LIBXML_XPTR_LOCS_ENABLED case XPATH_POINT: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a point\n", arg); break; case XPATH_RANGE: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a range\n", arg); break; case XPATH_LOCATIONSET: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is a range\n", arg); break; #endif /* LIBXML_XPTR_LOCS_ENABLED */ case XPATH_USERS: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is user-defined\n", arg); break; case XPATH_XSLT_TREE: - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s is an XSLT value tree\n", arg); break; @@ -3393,14 +3385,14 @@ xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input, xmlXPathFreeObject(list); #endif } else { - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "%s: no such node\n", arg); } ctxt->pctxt->node = NULL; } #endif /* LIBXML_OUTPUT_ENABLED */ } else { - xmlGenericError(xmlGenericErrorContext, + fprintf(ctxt->output, "Unknown command %s\n", command); } free(cmdline); /* not xmlFree here ! */ diff --git a/libs/xml2/dict.c b/libs/xml2/dict.c index 217e5607f69..37553ac80e1 100644 --- a/libs/xml2/dict.c +++ b/libs/xml2/dict.c @@ -19,11 +19,13 @@ #define IN_LIBXML #include "libxml.h"
+#include <errno.h> #include <limits.h> +#include <stdlib.h> #include <string.h> -#include <time.h>
#include "private/dict.h" +#include "private/globals.h" #include "private/threads.h"
#include <libxml/parser.h> @@ -508,6 +510,15 @@ xmlDictHashQName(unsigned seed, const xmlChar *prefix, const xmlChar *name, return(h2 | MAX_HASH_SIZE); }
+/** + * xmlDictComputeHash: + * @dict: dictionary + * @string: C string + * + * Compute the hash value of a C string. + * + * Returns the hash value. + */ unsigned xmlDictComputeHash(const xmlDict *dict, const xmlChar *string) { size_t len; @@ -516,6 +527,15 @@ xmlDictComputeHash(const xmlDict *dict, const xmlChar *string) {
#define HASH_ROL31(x,n) ((x) << (n) | ((x) & 0x7FFFFFFF) >> (31 - (n)))
+/** + * xmlDictCombineHash: + * @v1: first hash value + * @v2: second hash value + * + * Combine two hash values. + * + * Returns the combined hash value. + */ ATTRIBUTE_NO_SANITIZE_INTEGER unsigned xmlDictCombineHash(unsigned v1, unsigned v2) { @@ -904,30 +924,88 @@ xmlDictQLookup(xmlDictPtr dict, const xmlChar *prefix, const xmlChar *name) { * Pseudo-random generator */
+#ifdef _WIN32 + #define WIN32_LEAN_AND_MEAN + #include <windows.h> + #include <bcrypt.h> +#else + #if defined(HAVE_GETENTROPY) + #ifdef HAVE_UNISTD_H + #include <unistd.h> + #endif + #ifdef HAVE_SYS_RANDOM_H + #include <sys/random.h> + #endif + #endif + #include <time.h> +#endif + static xmlMutex xmlRngMutex;
static unsigned globalRngState[2];
-#ifdef XML_THREAD_LOCAL -static XML_THREAD_LOCAL int localRngInitialized = 0; -static XML_THREAD_LOCAL unsigned localRngState[2]; -#endif - +/* + * xmlInitRandom: + * + * Initialize the PRNG. + */ ATTRIBUTE_NO_SANITIZE_INTEGER void xmlInitRandom(void) { - int var; - xmlInitMutex(&xmlRngMutex);
- /* TODO: Get seed values from system PRNG */ + { +#ifdef _WIN32 + NTSTATUS status; + + status = BCryptGenRandom(NULL, (unsigned char *) globalRngState, + sizeof(globalRngState), + BCRYPT_USE_SYSTEM_PREFERRED_RNG); + if (!BCRYPT_SUCCESS(status)) { + fprintf(stderr, "libxml2: BCryptGenRandom failed with " + "error code %lu\n", GetLastError()); + abort(); + } +#else + int var; + +#if defined(HAVE_GETENTROPY) + while (1) { + if (getentropy(globalRngState, sizeof(globalRngState)) == 0) + return; + + /* + * This most likely means that libxml2 was compiled on + * a system supporting certain system calls and is running + * on a system that doesn't support these calls, as can + * be the case on Linux. + */ + if (errno == ENOSYS) + break;
- globalRngState[0] = (unsigned) time(NULL) ^ - HASH_ROL((unsigned) (size_t) &xmlInitRandom, 8); - globalRngState[1] = HASH_ROL((unsigned) (size_t) &xmlRngMutex, 16) ^ - HASH_ROL((unsigned) (size_t) &var, 24); + if (errno != EINTR) { + fprintf(stderr, "libxml2: getentropy failed with " + "error code %d\n", errno); + abort(); + } + } +#endif + + globalRngState[0] = + (unsigned) time(NULL) ^ + HASH_ROL((unsigned) ((size_t) &xmlInitRandom & 0xFFFFFFFF), 8); + globalRngState[1] = + HASH_ROL((unsigned) ((size_t) &xmlRngMutex & 0xFFFFFFFF), 16) ^ + HASH_ROL((unsigned) ((size_t) &var & 0xFFFFFFFF), 24); +#endif + } }
+/* + * xmlCleanupRandom: + * + * Clean up PRNG globals. + */ void xmlCleanupRandom(void) { xmlCleanupMutex(&xmlRngMutex); @@ -947,19 +1025,15 @@ xoroshiro64ss(unsigned *s) { return(result & 0xFFFFFFFF); }
+/* + * xmlGlobalRandom: + * + * Generate a pseudo-random value using the global PRNG. + * + * Returns a random value. + */ unsigned -xmlRandom(void) { -#ifdef XML_THREAD_LOCAL - if (!localRngInitialized) { - xmlMutexLock(&xmlRngMutex); - localRngState[0] = xoroshiro64ss(globalRngState); - localRngState[1] = xoroshiro64ss(globalRngState); - localRngInitialized = 1; - xmlMutexUnlock(&xmlRngMutex); - } - - return(xoroshiro64ss(localRngState)); -#else +xmlGlobalRandom(void) { unsigned ret;
xmlMutexLock(&xmlRngMutex); @@ -967,5 +1041,20 @@ xmlRandom(void) { xmlMutexUnlock(&xmlRngMutex);
return(ret); +} + +/* + * xmlRandom: + * + * Generate a pseudo-random value using the thread-local PRNG. + * + * Returns a random value. + */ +unsigned +xmlRandom(void) { +#ifdef LIBXML_THREAD_ENABLED + return(xoroshiro64ss(xmlGetLocalRngState())); +#else + return(xmlGlobalRandom()); #endif } diff --git a/libs/xml2/encoding.c b/libs/xml2/encoding.c index ba660a43035..ec9962fa442 100644 --- a/libs/xml2/encoding.c +++ b/libs/xml2/encoding.c @@ -71,57 +71,6 @@ static int xmlCharEncodingAliasesMax = 0;
static int xmlLittleEndian = 1;
-#ifdef LIBXML_ICU_ENABLED -static uconv_t* -openIcuConverter(const char* name, int toUnicode) -{ - UErrorCode status = U_ZERO_ERROR; - uconv_t *conv = (uconv_t *) xmlMalloc(sizeof(uconv_t)); - if (conv == NULL) - return NULL; - - conv->pivot_source = conv->pivot_buf; - conv->pivot_target = conv->pivot_buf; - - conv->uconv = ucnv_open(name, &status); - if (U_FAILURE(status)) - goto error; - - status = U_ZERO_ERROR; - if (toUnicode) { - ucnv_setToUCallBack(conv->uconv, UCNV_TO_U_CALLBACK_STOP, - NULL, NULL, NULL, &status); - } - else { - ucnv_setFromUCallBack(conv->uconv, UCNV_FROM_U_CALLBACK_STOP, - NULL, NULL, NULL, &status); - } - if (U_FAILURE(status)) - goto error; - - status = U_ZERO_ERROR; - conv->utf8 = ucnv_open("UTF-8", &status); - if (U_SUCCESS(status)) - return conv; - -error: - if (conv->uconv) - ucnv_close(conv->uconv); - xmlFree(conv); - return NULL; -} - -static void -closeIcuConverter(uconv_t *conv) -{ - if (conv != NULL) { - ucnv_close(conv->uconv); - ucnv_close(conv->utf8); - xmlFree(conv); - } -} -#endif /* LIBXML_ICU_ENABLED */ - /************************************************************************ * * * Conversions To/From UTF8 encoding * @@ -1315,7 +1264,7 @@ DECLARE_ISO_FUNCS(16) #endif /* LIBXML_ISO8859X_ENABLED */
#ifdef LIBXML_ICONV_ENABLED - #define EMPTY_ICONV , (iconv_t) 0, (iconv_t) 0 + #define EMPTY_ICONV , (iconv_t) -1, (iconv_t) -1 #else #define EMPTY_ICONV #endif @@ -1330,9 +1279,8 @@ DECLARE_ISO_FUNCS(16) { (char *) name, in, out EMPTY_ICONV EMPTY_UCONV }
static const xmlCharEncodingHandler defaultHandlers[] = { - MAKE_HANDLER("UTF-8", UTF8ToUTF8, UTF8ToUTF8) #ifdef LIBXML_OUTPUT_ENABLED - ,MAKE_HANDLER("UTF-16LE", UTF16LEToUTF8, UTF8ToUTF16LE) + MAKE_HANDLER("UTF-16LE", UTF16LEToUTF8, UTF8ToUTF16LE) ,MAKE_HANDLER("UTF-16BE", UTF16BEToUTF8, UTF8ToUTF16BE) ,MAKE_HANDLER("UTF-16", UTF16LEToUTF8, UTF8ToUTF16) ,MAKE_HANDLER("ISO-8859-1", isolat1ToUTF8, UTF8Toisolat1) @@ -1342,7 +1290,7 @@ static const xmlCharEncodingHandler defaultHandlers[] = { ,MAKE_HANDLER("HTML", NULL, UTF8ToHtml) #endif #else - ,MAKE_HANDLER("UTF-16LE", UTF16LEToUTF8, NULL) + MAKE_HANDLER("UTF-16LE", UTF16LEToUTF8, NULL) ,MAKE_HANDLER("UTF-16BE", UTF16BEToUTF8, NULL) ,MAKE_HANDLER("UTF-16", UTF16LEToUTF8, NULL) ,MAKE_HANDLER("ISO-8859-1", isolat1ToUTF8, NULL) @@ -1372,8 +1320,13 @@ static const xmlCharEncodingHandler defaultHandlers[] = { #define NUM_DEFAULT_HANDLERS \ (sizeof(defaultHandlers) / sizeof(defaultHandlers[0]))
-static const xmlCharEncodingHandler *xmlUTF16LEHandler = &defaultHandlers[1]; -static const xmlCharEncodingHandler *xmlUTF16BEHandler = &defaultHandlers[2]; +static const xmlCharEncodingHandler xmlUTF8Handler = + MAKE_HANDLER("UTF-8", UTF8ToUTF8, UTF8ToUTF8); + +static const xmlCharEncodingHandler *xmlUTF16LEHandler = &defaultHandlers[0]; +static const xmlCharEncodingHandler *xmlUTF16BEHandler = &defaultHandlers[1]; +static const xmlCharEncodingHandler *xmlLatin1Handler = &defaultHandlers[3]; +static const xmlCharEncodingHandler *xmlAsciiHandler = &defaultHandlers[4];
/* the size should be growable, but it's not a big deal ... */ #define MAX_ENCODING_HANDLERS 50 @@ -1436,8 +1389,8 @@ xmlNewCharEncodingHandler(const char *name, handler->name = up;
#ifdef LIBXML_ICONV_ENABLED - handler->iconv_in = NULL; - handler->iconv_out = NULL; + handler->iconv_in = (iconv_t) -1; + handler->iconv_out = (iconv_t) -1; #endif #ifdef LIBXML_ICU_ENABLED handler->uconv_in = NULL; @@ -1535,162 +1488,471 @@ free_handler: } }
+#ifdef LIBXML_ICONV_ENABLED +static int +xmlCreateIconvHandler(const char *name, xmlCharEncodingHandler **out) { + xmlCharEncodingHandlerPtr enc = NULL; + iconv_t icv_in = (iconv_t) -1; + iconv_t icv_out = (iconv_t) -1; + int ret; + + *out = NULL; + + icv_in = iconv_open("UTF-8", name); + if (icv_in == (iconv_t) -1) { + if (errno == EINVAL) + ret = XML_ERR_UNSUPPORTED_ENCODING; + else if (errno == ENOMEM) + ret = XML_ERR_NO_MEMORY; + else + ret = XML_ERR_SYSTEM; + goto error; + } + + icv_out = iconv_open(name, "UTF-8"); + if (icv_out == (iconv_t) -1) { + if (errno == EINVAL) + ret = XML_ERR_UNSUPPORTED_ENCODING; + else if (errno == ENOMEM) + ret = XML_ERR_NO_MEMORY; + else + ret = XML_ERR_SYSTEM; + goto error; + } + + enc = xmlMalloc(sizeof(*enc)); + if (enc == NULL) { + ret = XML_ERR_NO_MEMORY; + goto error; + } + memset(enc, 0, sizeof(*enc)); + + enc->name = xmlMemStrdup(name); + if (enc->name == NULL) { + ret = XML_ERR_NO_MEMORY; + goto error; + } + enc->iconv_in = icv_in; + enc->iconv_out = icv_out; + + *out = enc; + return(0); + +error: + if (enc != NULL) + xmlFree(enc); + if (icv_in != (iconv_t) -1) + iconv_close(icv_in); + if (icv_out != (iconv_t) -1) + iconv_close(icv_out); + return(ret); +} +#endif /* LIBXML_ICONV_ENABLED */ + +#ifdef LIBXML_ICU_ENABLED +static int +openIcuConverter(const char* name, int toUnicode, uconv_t **out) +{ + UErrorCode status; + uconv_t *conv; + + *out = NULL; + + conv = (uconv_t *) xmlMalloc(sizeof(uconv_t)); + if (conv == NULL) + return(XML_ERR_NO_MEMORY); + + conv->pivot_source = conv->pivot_buf; + conv->pivot_target = conv->pivot_buf; + + status = U_ZERO_ERROR; + conv->uconv = ucnv_open(name, &status); + if (U_FAILURE(status)) + goto error; + + status = U_ZERO_ERROR; + if (toUnicode) { + ucnv_setToUCallBack(conv->uconv, UCNV_TO_U_CALLBACK_STOP, + NULL, NULL, NULL, &status); + } + else { + ucnv_setFromUCallBack(conv->uconv, UCNV_FROM_U_CALLBACK_STOP, + NULL, NULL, NULL, &status); + } + if (U_FAILURE(status)) + goto error; + + status = U_ZERO_ERROR; + conv->utf8 = ucnv_open("UTF-8", &status); + if (U_FAILURE(status)) + goto error; + + *out = conv; + return(0); + +error: + if (conv->uconv) + ucnv_close(conv->uconv); + xmlFree(conv); + + if (status == U_FILE_ACCESS_ERROR) + return(XML_ERR_UNSUPPORTED_ENCODING); + if (status == U_MEMORY_ALLOCATION_ERROR) + return(XML_ERR_NO_MEMORY); + return(XML_ERR_SYSTEM); +} + +static void +closeIcuConverter(uconv_t *conv) +{ + if (conv == NULL) + return; + ucnv_close(conv->uconv); + ucnv_close(conv->utf8); + xmlFree(conv); +} + +static int +xmlCreateUconvHandler(const char *name, xmlCharEncodingHandler **out) { + xmlCharEncodingHandlerPtr enc = NULL; + uconv_t *ucv_in = NULL; + uconv_t *ucv_out = NULL; + int ret; + + ret = openIcuConverter(name, 1, &ucv_in); + if (ret != 0) + goto error; + ret = openIcuConverter(name, 0, &ucv_out); + if (ret != 0) + goto error; + + enc = (xmlCharEncodingHandlerPtr) + xmlMalloc(sizeof(xmlCharEncodingHandler)); + if (enc == NULL) { + ret = XML_ERR_NO_MEMORY; + goto error; + } + memset(enc, 0, sizeof(xmlCharEncodingHandler)); + + enc->name = xmlMemStrdup(name); + if (enc->name == NULL) { + ret = XML_ERR_NO_MEMORY; + goto error; + } + enc->input = NULL; + enc->output = NULL; +#ifdef LIBXML_ICONV_ENABLED + enc->iconv_in = (iconv_t) -1; + enc->iconv_out = (iconv_t) -1; +#endif + enc->uconv_in = ucv_in; + enc->uconv_out = ucv_out; + + *out = enc; + return(0); + +error: + if (enc != NULL) + xmlFree(enc); + if (ucv_in != NULL) + closeIcuConverter(ucv_in); + if (ucv_out != NULL) + closeIcuConverter(ucv_out); + return(ret); +} +#endif /* LIBXML_ICU_ENABLED */ + /** - * xmlGetCharEncodingHandler: + * xmlFindExtraHandler: + * @name: a string describing the char encoding. + * @output: boolean, use handler for output + * @out: pointer to resulting handler + * + * Search the non-default handlers for an exact match. + * + * Returns 0 on success, 1 if no handler was found, -1 if a memory + * allocation failed. + */ +static int +xmlFindExtraHandler(const char *name, int output, + xmlCharEncodingHandler **out) { + int ret; + int i; + + (void) ret; + + if (handlers != NULL) { + for (i = 0; i < nbCharEncodingHandler; i++) { + xmlCharEncodingHandler *handler = handlers[i]; + + if (!xmlStrcasecmp((const xmlChar *) name, + (const xmlChar *) handler->name)) { + if (output) { + if (handler->output != NULL) { + *out = handler; + return(0); + } + } else { + if (handler->input != NULL) { + *out = handler; + return(0); + } + } + } + } + } + +#ifdef LIBXML_ICONV_ENABLED + ret = xmlCreateIconvHandler(name, out); + if (*out != NULL) + return(0); + if (ret != XML_ERR_UNSUPPORTED_ENCODING) + return(ret); +#endif /* LIBXML_ICONV_ENABLED */ + +#ifdef LIBXML_ICU_ENABLED + ret = xmlCreateUconvHandler(name, out); + if (*out != NULL) + return(0); + if (ret != XML_ERR_UNSUPPORTED_ENCODING) + return(ret); +#endif /* LIBXML_ICU_ENABLED */ + + return(XML_ERR_UNSUPPORTED_ENCODING); +} + +/** + * xmlFindHandler: + * @name: a string describing the char encoding. + * @output: boolean, use handler for output + * @out: pointer to resulting handler + * + * Search all handlers for an exact match. + * + * Returns 0 on success, 1 if no handler was found, -1 if a memory + * allocation failed. + */ +static int +xmlFindHandler(const char *name, int output, xmlCharEncodingHandler **out) { + int i; + + /* + * Check for default handlers + */ + for (i = 0; i < (int) NUM_DEFAULT_HANDLERS; i++) { + xmlCharEncodingHandler *handler; + + handler = (xmlCharEncodingHandler *) &defaultHandlers[i]; + + if (xmlStrcasecmp((const xmlChar *) name, + (const xmlChar *) handler->name) == 0) { + if (output) { + if (handler->output != NULL) { + *out = handler; + return(0); + } + } else { + if (handler->input != NULL) { + *out = handler; + return(0); + } + } + } + } + + /* + * Check for other handlers + */ + return(xmlFindExtraHandler(name, output, out)); +} + +/** + * xmlLookupCharEncodingHandler: * @enc: an xmlCharEncoding value. + * @out: pointer to result * - * Search in the registered set the handler able to read/write that encoding. + * Find or create a handler matching the encoding. If no default or + * registered handler could be found, try to create a handler using + * iconv or ICU if supported. * - * Returns the handler or NULL if not found + * The handler must be closed with xmlCharEncCloseFunc. + * + * Available since 2.13.0. + * + * Returns an xmlParserErrors error code. */ -xmlCharEncodingHandlerPtr -xmlGetCharEncodingHandler(xmlCharEncoding enc) { - xmlCharEncodingHandlerPtr handler; +int +xmlLookupCharEncodingHandler(xmlCharEncoding enc, + xmlCharEncodingHandler **out) { + const char *name = NULL; + static const char *const ebcdicNames[] = { + "EBCDIC", "ebcdic", "EBCDIC-US", "IBM-037" + }; + static const char *const ucs4Names[] = { + "ISO-10646-UCS-4", "UCS-4", "UCS4" + }; + static const char *const ucs2Names[] = { + "ISO-10646-UCS-2", "UCS-2", "UCS2" + }; + static const char *const shiftJisNames[] = { + "SHIFT-JIS", "SHIFT_JIS", "Shift_JIS", + }; + const char *const *names = NULL; + int numNames = 0; + int ret; + int i; + + if (out == NULL) + return(XML_ERR_ARGUMENT); + *out = NULL;
switch (enc) { case XML_CHAR_ENCODING_ERROR: - return(NULL); + return(XML_ERR_UNSUPPORTED_ENCODING); case XML_CHAR_ENCODING_NONE: - return(NULL); + return(0); case XML_CHAR_ENCODING_UTF8: - return(NULL); + return(0); case XML_CHAR_ENCODING_UTF16LE: - return((xmlCharEncodingHandlerPtr) xmlUTF16LEHandler); + *out = (xmlCharEncodingHandler *) xmlUTF16LEHandler; + return(0); case XML_CHAR_ENCODING_UTF16BE: - return((xmlCharEncodingHandlerPtr) xmlUTF16BEHandler); + *out = (xmlCharEncodingHandler *) xmlUTF16BEHandler; + return(0); case XML_CHAR_ENCODING_EBCDIC: - handler = xmlFindCharEncodingHandler("EBCDIC"); - if (handler != NULL) return(handler); - handler = xmlFindCharEncodingHandler("ebcdic"); - if (handler != NULL) return(handler); - handler = xmlFindCharEncodingHandler("EBCDIC-US"); - if (handler != NULL) return(handler); - handler = xmlFindCharEncodingHandler("IBM-037"); - if (handler != NULL) return(handler); + names = ebcdicNames; + numNames = sizeof(ebcdicNames) / sizeof(ebcdicNames[0]); break; case XML_CHAR_ENCODING_UCS4BE: - handler = xmlFindCharEncodingHandler("ISO-10646-UCS-4"); - if (handler != NULL) return(handler); - handler = xmlFindCharEncodingHandler("UCS-4"); - if (handler != NULL) return(handler); - handler = xmlFindCharEncodingHandler("UCS4"); - if (handler != NULL) return(handler); - break; case XML_CHAR_ENCODING_UCS4LE: - handler = xmlFindCharEncodingHandler("ISO-10646-UCS-4"); - if (handler != NULL) return(handler); - handler = xmlFindCharEncodingHandler("UCS-4"); - if (handler != NULL) return(handler); - handler = xmlFindCharEncodingHandler("UCS4"); - if (handler != NULL) return(handler); + names = ucs4Names; + numNames = sizeof(ucs4Names) / sizeof(ucs4Names[0]); break; case XML_CHAR_ENCODING_UCS4_2143: break; case XML_CHAR_ENCODING_UCS4_3412: break; case XML_CHAR_ENCODING_UCS2: - handler = xmlFindCharEncodingHandler("ISO-10646-UCS-2"); - if (handler != NULL) return(handler); - handler = xmlFindCharEncodingHandler("UCS-2"); - if (handler != NULL) return(handler); - handler = xmlFindCharEncodingHandler("UCS2"); - if (handler != NULL) return(handler); + names = ucs2Names; + numNames = sizeof(ucs2Names) / sizeof(ucs2Names[0]); break;
- /* - * We used to keep ISO Latin encodings native in the - * generated data. This led to so many problems that - * this has been removed. One can still change this - * back by registering no-ops encoders for those - */ + case XML_CHAR_ENCODING_ASCII: + *out = (xmlCharEncodingHandler *) xmlAsciiHandler; + return(0); case XML_CHAR_ENCODING_8859_1: - handler = xmlFindCharEncodingHandler("ISO-8859-1"); - if (handler != NULL) return(handler); - break; + *out = (xmlCharEncodingHandler *) xmlLatin1Handler; + return(0); case XML_CHAR_ENCODING_8859_2: - handler = xmlFindCharEncodingHandler("ISO-8859-2"); - if (handler != NULL) return(handler); + name = "ISO-8859-2"; break; case XML_CHAR_ENCODING_8859_3: - handler = xmlFindCharEncodingHandler("ISO-8859-3"); - if (handler != NULL) return(handler); + name = "ISO-8859-3"; break; case XML_CHAR_ENCODING_8859_4: - handler = xmlFindCharEncodingHandler("ISO-8859-4"); - if (handler != NULL) return(handler); + name = "ISO-8859-4"; break; case XML_CHAR_ENCODING_8859_5: - handler = xmlFindCharEncodingHandler("ISO-8859-5"); - if (handler != NULL) return(handler); + name = "ISO-8859-5"; break; case XML_CHAR_ENCODING_8859_6: - handler = xmlFindCharEncodingHandler("ISO-8859-6"); - if (handler != NULL) return(handler); + name = "ISO-8859-6"; break; case XML_CHAR_ENCODING_8859_7: - handler = xmlFindCharEncodingHandler("ISO-8859-7"); - if (handler != NULL) return(handler); + name = "ISO-8859-7"; break; case XML_CHAR_ENCODING_8859_8: - handler = xmlFindCharEncodingHandler("ISO-8859-8"); - if (handler != NULL) return(handler); + name = "ISO-8859-8"; break; case XML_CHAR_ENCODING_8859_9: - handler = xmlFindCharEncodingHandler("ISO-8859-9"); - if (handler != NULL) return(handler); + name = "ISO-8859-9"; break;
- case XML_CHAR_ENCODING_2022_JP: - handler = xmlFindCharEncodingHandler("ISO-2022-JP"); - if (handler != NULL) return(handler); + name = "ISO-2022-JP"; break; case XML_CHAR_ENCODING_SHIFT_JIS: - handler = xmlFindCharEncodingHandler("SHIFT-JIS"); - if (handler != NULL) return(handler); - handler = xmlFindCharEncodingHandler("SHIFT_JIS"); - if (handler != NULL) return(handler); - handler = xmlFindCharEncodingHandler("Shift_JIS"); - if (handler != NULL) return(handler); + names = shiftJisNames; + numNames = sizeof(shiftJisNames) / sizeof(shiftJisNames[0]); break; case XML_CHAR_ENCODING_EUC_JP: - handler = xmlFindCharEncodingHandler("EUC-JP"); - if (handler != NULL) return(handler); + name = "EUC-JP"; break; default: break; }
- return(NULL); + if (name != NULL) + return(xmlFindExtraHandler(name, 0, out)); + + if (names != NULL) { + for (i = 0; i < numNames; i++) { + ret = xmlFindExtraHandler(names[i], 0, out); + if (*out != NULL) + return(0); + if (ret != XML_ERR_UNSUPPORTED_ENCODING) + return(ret); + } + } + + return(XML_ERR_UNSUPPORTED_ENCODING); }
/** - * xmlFindCharEncodingHandler: - * @name: a string describing the char encoding. + * xmlGetCharEncodingHandler: + * @enc: an xmlCharEncoding value. * - * Search in the registered set the handler able to read/write that encoding - * or create a new one. + * DEPRECATED: Use xmlLookupCharEncodingHandler which has better error + * reporting. * - * Returns the handler or NULL if not found + * Returns the handler or NULL if no handler was found or an error + * occurred. */ xmlCharEncodingHandlerPtr -xmlFindCharEncodingHandler(const char *name) { +xmlGetCharEncodingHandler(xmlCharEncoding enc) { + xmlCharEncodingHandler *ret; + + xmlLookupCharEncodingHandler(enc, &ret); + return(ret); +} + +/** + * xmlOpenCharEncodingHandler: + * @name: a string describing the char encoding. + * @output: boolean, use handler for output + * @out: pointer to result + * + * Find or create a handler matching the encoding. If no default or + * registered handler could be found, try to create a handler using + * iconv or ICU if supported. + * + * The handler must be closed with xmlCharEncCloseFunc. + * + * If the encoding is UTF-8, a NULL handler and no error code will + * be returned. + * + * Available since 2.13.0. + * + * Returns an xmlParserErrors error code. + */ +int +xmlOpenCharEncodingHandler(const char *name, int output, + xmlCharEncodingHandler **out) { const char *nalias; const char *norig; - xmlCharEncoding alias; -#ifdef LIBXML_ICONV_ENABLED - xmlCharEncodingHandlerPtr enc; - iconv_t icv_in, icv_out; -#endif /* LIBXML_ICONV_ENABLED */ -#ifdef LIBXML_ICU_ENABLED - xmlCharEncodingHandlerPtr encu; - uconv_t *ucv_in, *ucv_out; -#endif /* LIBXML_ICU_ENABLED */ - char upper[100]; - int i; + xmlCharEncoding enc; + int ret;
- if (name == NULL) return(NULL); - if (name[0] == 0) return(NULL); + if (out == NULL) + return(XML_ERR_ARGUMENT); + *out = NULL; + + if (name == NULL) + return(XML_ERR_ARGUMENT); + + if ((xmlStrcasecmp(BAD_CAST name, BAD_CAST "UTF-8") == 0) || + (xmlStrcasecmp(BAD_CAST name, BAD_CAST "UTF8") == 0)) + return(XML_ERR_OK);
/* * Do the alias resolution @@ -1700,111 +1962,46 @@ xmlFindCharEncodingHandler(const char *name) { if (nalias != NULL) name = nalias;
+ ret = xmlFindHandler(name, output, out); + if (*out != NULL) + return(0); + if (ret != XML_ERR_UNSUPPORTED_ENCODING) + return(ret); + /* - * Check first for directly registered encoding names + * Fallback using the canonical names + * + * TODO: We should make sure that the name of the returned + * handler equals norig. */ - for (i = 0;i < 99;i++) { - upper[i] = (char) toupper((unsigned char) name[i]); - if (upper[i] == 0) break; - } - upper[i] = 0; - - for (i = 0; i < (int) NUM_DEFAULT_HANDLERS; i++) { - if (strcmp(upper, defaultHandlers[i].name) == 0) - return((xmlCharEncodingHandlerPtr) &defaultHandlers[i]); - } - - if (handlers != NULL) { - for (i = 0;i < nbCharEncodingHandler; i++) { - if (!strcmp(upper, handlers[i]->name)) { - return(handlers[i]); - } - } - } + enc = xmlParseCharEncoding(norig); + return(xmlLookupCharEncodingHandler(enc, out)); +}
-#ifdef LIBXML_ICONV_ENABLED - /* check whether iconv can handle this */ - icv_in = iconv_open("UTF-8", name); - icv_out = iconv_open(name, "UTF-8"); - if (icv_in == (iconv_t) -1) { - icv_in = iconv_open("UTF-8", upper); - } - if (icv_out == (iconv_t) -1) { - icv_out = iconv_open(upper, "UTF-8"); - } - if ((icv_in != (iconv_t) -1) && (icv_out != (iconv_t) -1)) { - enc = (xmlCharEncodingHandlerPtr) - xmlMalloc(sizeof(xmlCharEncodingHandler)); - if (enc == NULL) { - iconv_close(icv_in); - iconv_close(icv_out); - return(NULL); - } - memset(enc, 0, sizeof(xmlCharEncodingHandler)); - enc->name = xmlMemStrdup(name); - if (enc->name == NULL) { - xmlFree(enc); - iconv_close(icv_in); - iconv_close(icv_out); - return(NULL); - } - enc->input = NULL; - enc->output = NULL; - enc->iconv_in = icv_in; - enc->iconv_out = icv_out; - return enc; - } else if ((icv_in != (iconv_t) -1) || icv_out != (iconv_t) -1) { - if (icv_in != (iconv_t) -1) - iconv_close(icv_in); - else - iconv_close(icv_out); - } -#endif /* LIBXML_ICONV_ENABLED */ -#ifdef LIBXML_ICU_ENABLED - /* check whether icu can handle this */ - ucv_in = openIcuConverter(name, 1); - ucv_out = openIcuConverter(name, 0); - if (ucv_in != NULL && ucv_out != NULL) { - encu = (xmlCharEncodingHandlerPtr) - xmlMalloc(sizeof(xmlCharEncodingHandler)); - if (encu == NULL) { - closeIcuConverter(ucv_in); - closeIcuConverter(ucv_out); - return(NULL); - } - memset(encu, 0, sizeof(xmlCharEncodingHandler)); - encu->name = xmlMemStrdup(name); - if (encu->name == NULL) { - xmlFree(encu); - closeIcuConverter(ucv_in); - closeIcuConverter(ucv_out); - return(NULL); - } - encu->input = NULL; - encu->output = NULL; - encu->uconv_in = ucv_in; - encu->uconv_out = ucv_out; - return encu; - } else if (ucv_in != NULL || ucv_out != NULL) { - closeIcuConverter(ucv_in); - closeIcuConverter(ucv_out); - } -#endif /* LIBXML_ICU_ENABLED */ +/** + * xmlFindCharEncodingHandler: + * @name: a string describing the char encoding. + * + * DEPRECATED: Use xmlOpenCharEncodingHandler which has better error + * reporting. + * + * Returns the handler or NULL if no handler was found or an error + * occurred. + */ +xmlCharEncodingHandlerPtr +xmlFindCharEncodingHandler(const char *name) { + xmlCharEncodingHandler *ret;
/* - * Fallback using the canonical names + * This handler shouldn't be used, but we must return a non-NULL + * handler. */ - alias = xmlParseCharEncoding(norig); - if (alias != XML_CHAR_ENCODING_ERROR) { - const char* canon; - canon = xmlGetCharEncodingName(alias); - if ((canon != NULL) && (strcmp(name, canon))) { - return(xmlFindCharEncodingHandler(canon)); - } - } + if ((xmlStrcasecmp(BAD_CAST name, BAD_CAST "UTF-8") == 0) || + (xmlStrcasecmp(BAD_CAST name, BAD_CAST "UTF8") == 0)) + return((xmlCharEncodingHandlerPtr) &xmlUTF8Handler);
- /* If "none of the above", give up */ - return(NULL); + xmlOpenCharEncodingHandler(name, 0, &ret); + return(ret); }
/************************************************************************ @@ -2007,7 +2204,7 @@ xmlEncInputChunk(xmlCharEncodingHandler *handler, unsigned char *out, } } #ifdef LIBXML_ICONV_ENABLED - else if (handler->iconv_in != NULL) { + else if (handler->iconv_in != (iconv_t) -1) { ret = xmlIconvWrapper(handler->iconv_in, out, outlen, in, inlen); } #endif /* LIBXML_ICONV_ENABLED */ @@ -2067,7 +2264,7 @@ xmlEncOutputChunk(xmlCharEncodingHandler *handler, unsigned char *out, } } #ifdef LIBXML_ICONV_ENABLED - else if (handler->iconv_out != NULL) { + else if (handler->iconv_out != (iconv_t) -1) { ret = xmlIconvWrapper(handler->iconv_out, out, outlen, in, inlen); } #endif /* LIBXML_ICONV_ENABLED */ @@ -2169,7 +2366,8 @@ xmlCharEncInput(xmlParserInputBufferPtr input) else input->rawconsumed += c_in;
- if ((c_out == 0) && (ret != 0)) { + if (((ret != 0) && (c_out == 0)) || + (ret == XML_ENC_ERR_MEMORY)) { if (input->error == 0) input->error = xmlEncConvertError(ret); return(ret); @@ -2277,7 +2475,10 @@ retry: if (toconv > 64 * 1024) toconv = 64 * 1024; if (toconv * 4 >= written) { - xmlBufGrow(out, toconv * 4); + if (xmlBufGrow(out, toconv * 4) < 0) { + ret = XML_ENC_ERR_MEMORY; + goto error; + } written = xmlBufAvail(out); } if (written > 256 * 1024) @@ -2314,7 +2515,6 @@ retry: */ charrefLen = snprintf((char *) &charref[0], sizeof(charref), "&#%d;", cur); - xmlBufShrink(in, len); xmlBufGrow(out, charrefLen * 4); c_out = xmlBufAvail(out); c_in = charrefLen; @@ -2325,13 +2525,15 @@ retry: goto error; }
+ xmlBufShrink(in, len); xmlBufAddLen(out, c_out); writtentot += c_out; goto retry; }
error: - if ((writtentot <= 0) && (ret != 0)) { + if (((writtentot <= 0) && (ret != 0)) || + (ret == XML_ENC_ERR_MEMORY)) { if (output->error == 0) output->error = xmlEncConvertError(ret); return(ret); @@ -2474,17 +2676,17 @@ xmlCharEncCloseFunc(xmlCharEncodingHandler *handler) { * Iconv handlers can be used only once, free the whole block. * and the associated icon resources. */ - if ((handler->iconv_out != NULL) || (handler->iconv_in != NULL)) { + if ((handler->iconv_out != (iconv_t) -1) || (handler->iconv_in != (iconv_t) -1)) { tofree = 1; - if (handler->iconv_out != NULL) { + if (handler->iconv_out != (iconv_t) -1) { if (iconv_close(handler->iconv_out)) ret = -1; - handler->iconv_out = NULL; + handler->iconv_out = (iconv_t) -1; } - if (handler->iconv_in != NULL) { + if (handler->iconv_in != (iconv_t) -1) { if (iconv_close(handler->iconv_in)) ret = -1; - handler->iconv_in = NULL; + handler->iconv_in = (iconv_t) -1; } } #endif /* LIBXML_ICONV_ENABLED */ @@ -2762,7 +2964,7 @@ ISO8859xToUTF8(unsigned char* out, int *outlen, * Lookup tables for ISO-8859-2..ISO-8859-16 transcoding * ************************************************************************/
-static unsigned short const xmlunicodetable_ISO8859_2 [128] = { +static const unsigned short xmlunicodetable_ISO8859_2 [128] = { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, @@ -2811,7 +3013,7 @@ static const unsigned char xmltranscodetable_ISO8859_2 [48 + 6 * 64] = { "\x00\x00\x00\xf3\xf4\x00\xf6\xf7\x00\x00\xfa\x00\xfc\xfd\x00\x00" };
-static unsigned short const xmlunicodetable_ISO8859_3 [128] = { +static const unsigned short xmlunicodetable_ISO8859_3 [128] = { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, @@ -2864,7 +3066,7 @@ static const unsigned char xmltranscodetable_ISO8859_3 [48 + 7 * 64] = { "\x00\xf1\xf2\xf3\xf4\x00\xf6\xf7\x00\xf9\xfa\xfb\xfc\x00\x00\x00" };
-static unsigned short const xmlunicodetable_ISO8859_4 [128] = { +static const unsigned short xmlunicodetable_ISO8859_4 [128] = { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, @@ -2913,7 +3115,7 @@ static const unsigned char xmltranscodetable_ISO8859_4 [48 + 6 * 64] = { "\x00\x00\x00\x00\xf4\xf5\xf6\xf7\xf8\x00\xfa\xfb\xfc\x00\x00\x00" };
-static unsigned short const xmlunicodetable_ISO8859_5 [128] = { +static const unsigned short xmlunicodetable_ISO8859_5 [128] = { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, @@ -2962,7 +3164,7 @@ static const unsigned char xmltranscodetable_ISO8859_5 [48 + 6 * 64] = { "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" };
-static unsigned short const xmlunicodetable_ISO8859_6 [128] = { +static const unsigned short xmlunicodetable_ISO8859_6 [128] = { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, @@ -3007,7 +3209,7 @@ static const unsigned char xmltranscodetable_ISO8859_6 [48 + 5 * 64] = { "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" };
-static unsigned short const xmlunicodetable_ISO8859_7 [128] = { +static const unsigned short xmlunicodetable_ISO8859_7 [128] = { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, @@ -3060,7 +3262,7 @@ static const unsigned char xmltranscodetable_ISO8859_7 [48 + 7 * 64] = { "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" };
-static unsigned short const xmlunicodetable_ISO8859_8 [128] = { +static const unsigned short xmlunicodetable_ISO8859_8 [128] = { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, @@ -3113,7 +3315,7 @@ static const unsigned char xmltranscodetable_ISO8859_8 [48 + 7 * 64] = { "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" };
-static unsigned short const xmlunicodetable_ISO8859_9 [128] = { +static const unsigned short xmlunicodetable_ISO8859_9 [128] = { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, @@ -3158,7 +3360,7 @@ static const unsigned char xmltranscodetable_ISO8859_9 [48 + 5 * 64] = { "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" };
-static unsigned short const xmlunicodetable_ISO8859_10 [128] = { +static const unsigned short xmlunicodetable_ISO8859_10 [128] = { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, @@ -3211,7 +3413,7 @@ static const unsigned char xmltranscodetable_ISO8859_10 [48 + 7 * 64] = { "\xf0\x00\x00\xf3\xf4\xf5\xf6\x00\xf8\x00\xfa\xfb\xfc\xfd\xfe\x00" };
-static unsigned short const xmlunicodetable_ISO8859_11 [128] = { +static const unsigned short xmlunicodetable_ISO8859_11 [128] = { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, @@ -3260,7 +3462,7 @@ static const unsigned char xmltranscodetable_ISO8859_11 [48 + 6 * 64] = { "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" };
-static unsigned short const xmlunicodetable_ISO8859_13 [128] = { +static const unsigned short xmlunicodetable_ISO8859_13 [128] = { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, @@ -3313,7 +3515,7 @@ static const unsigned char xmltranscodetable_ISO8859_13 [48 + 7 * 64] = { "\x00\x00\x00\x00\x00\x00\xcd\xed\x00\x00\x00\xcf\xef\x00\x00\x00" };
-static unsigned short const xmlunicodetable_ISO8859_14 [128] = { +static const unsigned short xmlunicodetable_ISO8859_14 [128] = { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, @@ -3378,7 +3580,7 @@ static const unsigned char xmltranscodetable_ISO8859_14 [48 + 10 * 64] = { "\x00\xf1\xf2\xf3\xf4\xf5\xf6\x00\xf8\xf9\xfa\xfb\xfc\xfd\x00\xff" };
-static unsigned short const xmlunicodetable_ISO8859_15 [128] = { +static const unsigned short xmlunicodetable_ISO8859_15 [128] = { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, @@ -3427,7 +3629,7 @@ static const unsigned char xmltranscodetable_ISO8859_15 [48 + 6 * 64] = { "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff" };
-static unsigned short const xmlunicodetable_ISO8859_16 [128] = { +static const unsigned short xmlunicodetable_ISO8859_16 [128] = { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, diff --git a/libs/xml2/entities.c b/libs/xml2/entities.c index aec51441476..f7792a8138e 100644 --- a/libs/xml2/entities.c +++ b/libs/xml2/entities.c @@ -24,6 +24,7 @@ #include <libxml/parserInternals.h> #include <libxml/xmlerror.h> #include <libxml/dict.h> +#include <libxml/xmlsave.h>
#include "private/entities.h" #include "private/error.h" @@ -68,50 +69,11 @@ static xmlEntity xmlEntityApos = { NULL, NULL, NULL, NULL, 0, 0, 0 };
-/** - * xmlEntitiesErrMemory: - * @extra: extra information - * - * Handle an out of memory condition - */ -static void -xmlEntitiesErrMemory(const char *extra) -{ - __xmlSimpleError(XML_FROM_TREE, XML_ERR_NO_MEMORY, NULL, NULL, extra); -} - -/** - * xmlEntitiesErr: - * @code: the error code - * @msg: the message - * - * Raise an error. - */ -static void LIBXML_ATTR_FORMAT(2,0) -xmlEntitiesErr(xmlParserErrors code, const char *msg) -{ - __xmlSimpleError(XML_FROM_TREE, code, NULL, msg, NULL); -} - -/** - * xmlEntitiesWarn: - * @code: the error code - * @msg: the message - * - * Raise a warning. - */ -static void LIBXML_ATTR_FORMAT(2,0) -xmlEntitiesWarn(xmlParserErrors code, const char *msg, const xmlChar *str1) -{ - __xmlRaiseError(NULL, NULL, NULL, - NULL, NULL, XML_FROM_TREE, code, - XML_ERR_WARNING, NULL, 0, - (const char *)str1, NULL, NULL, 0, 0, - msg, (const char *)str1, NULL); -} - /* - * xmlFreeEntity : clean-up an entity record. + * xmlFreeEntity: + * @entity: an entity + * + * Frees the entity. */ void xmlFreeEntity(xmlEntityPtr entity) @@ -125,7 +87,7 @@ xmlFreeEntity(xmlEntityPtr entity) dict = entity->doc->dict;
- if ((entity->children) && (entity->owner == 1) && + if ((entity->children) && (entity == (xmlEntityPtr) entity->children->parent)) xmlFreeNodeList(entity->children); if ((entity->name != NULL) && @@ -150,37 +112,43 @@ xmlFreeEntity(xmlEntityPtr entity) * internal routine doing the entity node structures allocations */ static xmlEntityPtr -xmlCreateEntity(xmlDictPtr dict, const xmlChar *name, int type, +xmlCreateEntity(xmlDocPtr doc, const xmlChar *name, int type, const xmlChar *ExternalID, const xmlChar *SystemID, const xmlChar *content) { xmlEntityPtr ret;
ret = (xmlEntityPtr) xmlMalloc(sizeof(xmlEntity)); - if (ret == NULL) { - xmlEntitiesErrMemory("xmlCreateEntity: malloc failed"); + if (ret == NULL) return(NULL); - } memset(ret, 0, sizeof(xmlEntity)); + ret->doc = doc; ret->type = XML_ENTITY_DECL;
/* * fill the structure. */ ret->etype = (xmlEntityType) type; - if (dict == NULL) { + if ((doc == NULL) || (doc->dict == NULL)) ret->name = xmlStrdup(name); - if (ExternalID != NULL) - ret->ExternalID = xmlStrdup(ExternalID); - if (SystemID != NULL) - ret->SystemID = xmlStrdup(SystemID); - } else { - ret->name = xmlDictLookup(dict, name, -1); - ret->ExternalID = xmlStrdup(ExternalID); - ret->SystemID = xmlStrdup(SystemID); + else + ret->name = xmlDictLookup(doc->dict, name, -1); + if (ret->name == NULL) + goto error; + if (ExternalID != NULL) { + ret->ExternalID = xmlStrdup(ExternalID); + if (ret->ExternalID == NULL) + goto error; + } + if (SystemID != NULL) { + ret->SystemID = xmlStrdup(SystemID); + if (ret->SystemID == NULL) + goto error; } if (content != NULL) { ret->length = xmlStrlen(content); ret->content = xmlStrndup(content, ret->length); + if (ret->content == NULL) + goto error; } else { ret->length = 0; ret->content = NULL; @@ -188,28 +156,53 @@ xmlCreateEntity(xmlDictPtr dict, const xmlChar *name, int type, ret->URI = NULL; /* to be computed by the layer knowing the defining entity */ ret->orig = NULL; - ret->owner = 0;
return(ret); + +error: + xmlFreeEntity(ret); + return(NULL); }
-/* - * xmlAddEntity : register a new entity for an entities table. +/** + * xmlAddEntity: + * @doc: the document + * @extSubset: add to the external or internal subset + * @name: the entity name + * @type: the entity type XML_xxx_yyy_ENTITY + * @ExternalID: the entity external ID if available + * @SystemID: the entity system ID if available + * @content: the entity content + * @out: pointer to resulting entity (optional) + * + * Register a new entity for this document. + * + * Available since 2.13.0. + * + * Returns an xmlParserErrors error code. */ -static xmlEntityPtr -xmlAddEntity(xmlDtdPtr dtd, const xmlChar *name, int type, +int +xmlAddEntity(xmlDocPtr doc, int extSubset, const xmlChar *name, int type, const xmlChar *ExternalID, const xmlChar *SystemID, - const xmlChar *content) { + const xmlChar *content, xmlEntityPtr *out) { + xmlDtdPtr dtd; xmlDictPtr dict = NULL; xmlEntitiesTablePtr table = NULL; xmlEntityPtr ret, predef; + int res;
- if (name == NULL) - return(NULL); + if (out != NULL) + *out = NULL; + if ((doc == NULL) || (name == NULL)) + return(XML_ERR_ARGUMENT); + dict = doc->dict; + + if (extSubset) + dtd = doc->extSubset; + else + dtd = doc->intSubset; if (dtd == NULL) - return(NULL); - if (dtd->doc != NULL) - dict = dtd->doc->dict; + return(XML_DTD_NO_DTD);
switch (type) { case XML_INTERNAL_GENERAL_ENTITY: @@ -246,41 +239,60 @@ xmlAddEntity(xmlDtdPtr dtd, const xmlChar *name, int type, } } } - if (!valid) { - xmlEntitiesWarn(XML_ERR_ENTITY_PROCESSING, - "xmlAddEntity: invalid redeclaration of predefined" - " entity '%s'", name); - return(NULL); - } + if (!valid) + return(XML_ERR_REDECL_PREDEF_ENTITY); } - if (dtd->entities == NULL) + if (dtd->entities == NULL) { dtd->entities = xmlHashCreateDict(0, dict); + if (dtd->entities == NULL) + return(XML_ERR_NO_MEMORY); + } table = dtd->entities; break; case XML_INTERNAL_PARAMETER_ENTITY: case XML_EXTERNAL_PARAMETER_ENTITY: - if (dtd->pentities == NULL) + if (dtd->pentities == NULL) { dtd->pentities = xmlHashCreateDict(0, dict); + if (dtd->pentities == NULL) + return(XML_ERR_NO_MEMORY); + } table = dtd->pentities; break; - case XML_INTERNAL_PREDEFINED_ENTITY: - return(NULL); + default: + return(XML_ERR_ARGUMENT); } - if (table == NULL) - return(NULL); - ret = xmlCreateEntity(dict, name, type, ExternalID, SystemID, content); + ret = xmlCreateEntity(dtd->doc, name, type, ExternalID, SystemID, content); if (ret == NULL) - return(NULL); - ret->doc = dtd->doc; + return(XML_ERR_NO_MEMORY);
- if (xmlHashAddEntry(table, name, ret)) { + res = xmlHashAdd(table, name, ret); + if (res < 0) { + xmlFreeEntity(ret); + return(XML_ERR_NO_MEMORY); + } else if (res == 0) { /* * entity was already defined at another level. */ xmlFreeEntity(ret); - return(NULL); + return(XML_WAR_ENTITY_REDEFINED); } - return(ret); + + /* + * Link it to the DTD + */ + ret->parent = dtd; + ret->doc = dtd->doc; + if (dtd->last == NULL) { + dtd->children = dtd->last = (xmlNodePtr) ret; + } else { + dtd->last->next = (xmlNodePtr) ret; + ret->prev = dtd->last; + dtd->last = (xmlNodePtr) ret; + } + + if (out != NULL) + *out = ret; + return(0); }
/** @@ -337,34 +349,8 @@ xmlAddDtdEntity(xmlDocPtr doc, const xmlChar *name, int type, const xmlChar *ExternalID, const xmlChar *SystemID, const xmlChar *content) { xmlEntityPtr ret; - xmlDtdPtr dtd;
- if (doc == NULL) { - xmlEntitiesErr(XML_DTD_NO_DOC, - "xmlAddDtdEntity: document is NULL"); - return(NULL); - } - if (doc->extSubset == NULL) { - xmlEntitiesErr(XML_DTD_NO_DTD, - "xmlAddDtdEntity: document without external subset"); - return(NULL); - } - dtd = doc->extSubset; - ret = xmlAddEntity(dtd, name, type, ExternalID, SystemID, content); - if (ret == NULL) return(NULL); - - /* - * Link it to the DTD - */ - ret->parent = dtd; - ret->doc = dtd->doc; - if (dtd->last == NULL) { - dtd->children = dtd->last = (xmlNodePtr) ret; - } else { - dtd->last->next = (xmlNodePtr) ret; - ret->prev = dtd->last; - dtd->last = (xmlNodePtr) ret; - } + xmlAddEntity(doc, 1, name, type, ExternalID, SystemID, content, &ret); return(ret); }
@@ -386,34 +372,8 @@ xmlAddDocEntity(xmlDocPtr doc, const xmlChar *name, int type, const xmlChar *ExternalID, const xmlChar *SystemID, const xmlChar *content) { xmlEntityPtr ret; - xmlDtdPtr dtd; - - if (doc == NULL) { - xmlEntitiesErr(XML_DTD_NO_DOC, - "xmlAddDocEntity: document is NULL"); - return(NULL); - } - if (doc->intSubset == NULL) { - xmlEntitiesErr(XML_DTD_NO_DTD, - "xmlAddDocEntity: document without internal subset"); - return(NULL); - } - dtd = doc->intSubset; - ret = xmlAddEntity(dtd, name, type, ExternalID, SystemID, content); - if (ret == NULL) return(NULL);
- /* - * Link it to the DTD - */ - ret->parent = dtd; - ret->doc = dtd->doc; - if (dtd->last == NULL) { - dtd->children = dtd->last = (xmlNodePtr) ret; - } else { - dtd->last->next = (xmlNodePtr) ret; - ret->prev = dtd->last; - dtd->last = (xmlNodePtr) ret; - } + xmlAddEntity(doc, 0, name, type, ExternalID, SystemID, content, &ret); return(ret); }
@@ -438,21 +398,12 @@ xmlEntityPtr xmlNewEntity(xmlDocPtr doc, const xmlChar *name, int type, const xmlChar *ExternalID, const xmlChar *SystemID, const xmlChar *content) { - xmlEntityPtr ret; - xmlDictPtr dict; - if ((doc != NULL) && (doc->intSubset != NULL)) { return(xmlAddDocEntity(doc, name, type, ExternalID, SystemID, content)); } - if (doc != NULL) - dict = doc->dict; - else - dict = NULL; - ret = xmlCreateEntity(dict, name, type, ExternalID, SystemID, content); - if (ret == NULL) + if (name == NULL) return(NULL); - ret->doc = doc; - return(ret); + return(xmlCreateEntity(doc, name, type, ExternalID, SystemID, content)); }
/** @@ -604,10 +555,8 @@ xmlEncodeEntitiesInternal(xmlDocPtr doc, const xmlChar *input, int attr) { */ buffer_size = 1000; buffer = (xmlChar *) xmlMalloc(buffer_size); - if (buffer == NULL) { - xmlEntitiesErrMemory("xmlEncodeEntities: malloc failed"); + if (buffer == NULL) return(NULL); - } out = buffer;
while (*cur != '\0') { @@ -707,53 +656,18 @@ xmlEncodeEntitiesInternal(xmlDocPtr doc, const xmlChar *input, int attr) { * cur[3] is 10xxxxxx if cur[0] is 1111xxxx * cur[0] is not 11111xxx */ - char buf[11], *ptr; - int val = 0, l = 1; - - if (((cur[0] & 0xC0) != 0xC0) || - ((cur[1] & 0xC0) != 0x80) || - (((cur[0] & 0xE0) == 0xE0) && ((cur[2] & 0xC0) != 0x80)) || - (((cur[0] & 0xF0) == 0xF0) && ((cur[3] & 0xC0) != 0x80)) || - (((cur[0] & 0xF8) == 0xF8))) { - xmlEntitiesErr(XML_CHECK_NOT_UTF8, - "xmlEncodeEntities: input not UTF-8"); - snprintf(buf, sizeof(buf), "&#%d;", *cur); - buf[sizeof(buf) - 1] = 0; - ptr = buf; - while (*ptr != 0) *out++ = *ptr++; - cur++; - continue; - } else if (*cur < 0xE0) { - val = (cur[0]) & 0x1F; - val <<= 6; - val |= (cur[1]) & 0x3F; - l = 2; - } else if (*cur < 0xF0) { - val = (cur[0]) & 0x0F; - val <<= 6; - val |= (cur[1]) & 0x3F; - val <<= 6; - val |= (cur[2]) & 0x3F; - l = 3; - } else if (*cur < 0xF8) { - val = (cur[0]) & 0x07; - val <<= 6; - val |= (cur[1]) & 0x3F; - val <<= 6; - val |= (cur[2]) & 0x3F; - val <<= 6; - val |= (cur[3]) & 0x3F; - l = 4; - } - if ((l == 1) || (!IS_CHAR(val))) { - xmlEntitiesErr(XML_ERR_INVALID_CHAR, - "xmlEncodeEntities: char out of range\n"); - snprintf(buf, sizeof(buf), "&#%d;", *cur); - buf[sizeof(buf) - 1] = 0; - ptr = buf; - while (*ptr != 0) *out++ = *ptr++; - cur++; - continue; + char buf[13], *ptr; + int val, l; + + l = 4; + val = xmlGetUTF8Char(cur, &l); + if (val < 0) { + val = 0xFFFD; + cur++; + } else { + if (!IS_CHAR(val)) + val = 0xFFFD; + cur += l; } /* * We could do multiple things here. Just save as a char ref @@ -762,7 +676,6 @@ xmlEncodeEntitiesInternal(xmlDocPtr doc, const xmlChar *input, int attr) { buf[sizeof(buf) - 1] = 0; ptr = buf; while (*ptr != 0) *out++ = *ptr++; - cur += l; continue; } } else if (IS_BYTE_CHAR(*cur)) { @@ -779,7 +692,6 @@ xmlEncodeEntitiesInternal(xmlDocPtr doc, const xmlChar *input, int attr) { return(buffer);
mem_error: - xmlEntitiesErrMemory("xmlEncodeEntities: realloc failed"); xmlFree(buffer); return(NULL); } @@ -840,10 +752,8 @@ xmlEncodeSpecialChars(const xmlDoc *doc ATTRIBUTE_UNUSED, const xmlChar *input) */ buffer_size = 1000; buffer = (xmlChar *) xmlMalloc(buffer_size); - if (buffer == NULL) { - xmlEntitiesErrMemory("xmlEncodeSpecialChars: malloc failed"); + if (buffer == NULL) return(NULL); - } out = buffer;
while (*cur != '\0') { @@ -899,7 +809,6 @@ xmlEncodeSpecialChars(const xmlDoc *doc ATTRIBUTE_UNUSED, const xmlChar *input) return(buffer);
mem_error: - xmlEntitiesErrMemory("xmlEncodeSpecialChars: realloc failed"); xmlFree(buffer); return(NULL); } @@ -956,27 +865,47 @@ xmlCopyEntity(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) { xmlEntityPtr cur;
cur = (xmlEntityPtr) xmlMalloc(sizeof(xmlEntity)); - if (cur == NULL) { - xmlEntitiesErrMemory("xmlCopyEntity:: malloc failed"); + if (cur == NULL) return(NULL); - } memset(cur, 0, sizeof(xmlEntity)); cur->type = XML_ENTITY_DECL;
cur->etype = ent->etype; - if (ent->name != NULL) + if (ent->name != NULL) { cur->name = xmlStrdup(ent->name); - if (ent->ExternalID != NULL) + if (cur->name == NULL) + goto error; + } + if (ent->ExternalID != NULL) { cur->ExternalID = xmlStrdup(ent->ExternalID); - if (ent->SystemID != NULL) + if (cur->ExternalID == NULL) + goto error; + } + if (ent->SystemID != NULL) { cur->SystemID = xmlStrdup(ent->SystemID); - if (ent->content != NULL) + if (cur->SystemID == NULL) + goto error; + } + if (ent->content != NULL) { cur->content = xmlStrdup(ent->content); - if (ent->orig != NULL) + if (cur->content == NULL) + goto error; + } + if (ent->orig != NULL) { cur->orig = xmlStrdup(ent->orig); - if (ent->URI != NULL) + if (cur->orig == NULL) + goto error; + } + if (ent->URI != NULL) { cur->URI = xmlStrdup(ent->URI); + if (cur->URI == NULL) + goto error; + } return(cur); + +error: + xmlFreeEntity(cur); + return(NULL); }
/** @@ -989,52 +918,12 @@ xmlCopyEntity(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) { */ xmlEntitiesTablePtr xmlCopyEntitiesTable(xmlEntitiesTablePtr table) { - return(xmlHashCopy(table, xmlCopyEntity)); + return(xmlHashCopySafe(table, xmlCopyEntity, xmlFreeEntityWrapper)); } #endif /* LIBXML_TREE_ENABLED */
#ifdef LIBXML_OUTPUT_ENABLED
-/** - * xmlDumpEntityContent: - * @buf: An XML buffer. - * @content: The entity content. - * - * This will dump the quoted string value, taking care of the special - * treatment required by % - */ -static void -xmlDumpEntityContent(xmlBufferPtr buf, const xmlChar *content) { - if (xmlStrchr(content, '%')) { - const xmlChar * base, *cur; - - xmlBufferCCat(buf, """); - base = cur = content; - while (*cur != 0) { - if (*cur == '"') { - if (base != cur) - xmlBufferAdd(buf, base, cur - base); - xmlBufferAdd(buf, BAD_CAST """, 6); - cur++; - base = cur; - } else if (*cur == '%') { - if (base != cur) - xmlBufferAdd(buf, base, cur - base); - xmlBufferAdd(buf, BAD_CAST "%", 6); - cur++; - base = cur; - } else { - cur++; - } - } - if (base != cur) - xmlBufferAdd(buf, base, cur - base); - xmlBufferCCat(buf, """); - } else { - xmlBufferWriteQuotedString(buf, content); - } -} - /** * xmlDumpEntityDecl: * @buf: An XML buffer. @@ -1044,81 +933,15 @@ xmlDumpEntityContent(xmlBufferPtr buf, const xmlChar *content) { */ void xmlDumpEntityDecl(xmlBufferPtr buf, xmlEntityPtr ent) { - if ((buf == NULL) || (ent == NULL)) return; - switch (ent->etype) { - case XML_INTERNAL_GENERAL_ENTITY: - xmlBufferWriteChar(buf, "<!ENTITY "); - xmlBufferWriteCHAR(buf, ent->name); - xmlBufferWriteChar(buf, " "); - if (ent->orig != NULL) - xmlBufferWriteQuotedString(buf, ent->orig); - else - xmlDumpEntityContent(buf, ent->content); - xmlBufferWriteChar(buf, ">\n"); - break; - case XML_EXTERNAL_GENERAL_PARSED_ENTITY: - xmlBufferWriteChar(buf, "<!ENTITY "); - xmlBufferWriteCHAR(buf, ent->name); - if (ent->ExternalID != NULL) { - xmlBufferWriteChar(buf, " PUBLIC "); - xmlBufferWriteQuotedString(buf, ent->ExternalID); - xmlBufferWriteChar(buf, " "); - xmlBufferWriteQuotedString(buf, ent->SystemID); - } else { - xmlBufferWriteChar(buf, " SYSTEM "); - xmlBufferWriteQuotedString(buf, ent->SystemID); - } - xmlBufferWriteChar(buf, ">\n"); - break; - case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY: - xmlBufferWriteChar(buf, "<!ENTITY "); - xmlBufferWriteCHAR(buf, ent->name); - if (ent->ExternalID != NULL) { - xmlBufferWriteChar(buf, " PUBLIC "); - xmlBufferWriteQuotedString(buf, ent->ExternalID); - xmlBufferWriteChar(buf, " "); - xmlBufferWriteQuotedString(buf, ent->SystemID); - } else { - xmlBufferWriteChar(buf, " SYSTEM "); - xmlBufferWriteQuotedString(buf, ent->SystemID); - } - if (ent->content != NULL) { /* Should be true ! */ - xmlBufferWriteChar(buf, " NDATA "); - if (ent->orig != NULL) - xmlBufferWriteCHAR(buf, ent->orig); - else - xmlBufferWriteCHAR(buf, ent->content); - } - xmlBufferWriteChar(buf, ">\n"); - break; - case XML_INTERNAL_PARAMETER_ENTITY: - xmlBufferWriteChar(buf, "<!ENTITY % "); - xmlBufferWriteCHAR(buf, ent->name); - xmlBufferWriteChar(buf, " "); - if (ent->orig == NULL) - xmlDumpEntityContent(buf, ent->content); - else - xmlBufferWriteQuotedString(buf, ent->orig); - xmlBufferWriteChar(buf, ">\n"); - break; - case XML_EXTERNAL_PARAMETER_ENTITY: - xmlBufferWriteChar(buf, "<!ENTITY % "); - xmlBufferWriteCHAR(buf, ent->name); - if (ent->ExternalID != NULL) { - xmlBufferWriteChar(buf, " PUBLIC "); - xmlBufferWriteQuotedString(buf, ent->ExternalID); - xmlBufferWriteChar(buf, " "); - xmlBufferWriteQuotedString(buf, ent->SystemID); - } else { - xmlBufferWriteChar(buf, " SYSTEM "); - xmlBufferWriteQuotedString(buf, ent->SystemID); - } - xmlBufferWriteChar(buf, ">\n"); - break; - default: - xmlEntitiesErr(XML_DTD_UNKNOWN_ENTITY, - "xmlDumpEntitiesDecl: internal: unknown type entity type"); - } + xmlSaveCtxtPtr save; + + if ((buf == NULL) || (ent == NULL)) + return; + + save = xmlSaveToBuffer(buf, NULL, 0); + xmlSaveTree(save, (xmlNodePtr) ent); + if (xmlSaveFinish(save) != XML_ERR_OK) + xmlFree(xmlBufferDetach(buf)); }
/** @@ -1129,9 +952,9 @@ xmlDumpEntityDecl(xmlBufferPtr buf, xmlEntityPtr ent) { * When using the hash table scan function, arguments need to be reversed */ static void -xmlDumpEntityDeclScan(void *ent, void *buf, +xmlDumpEntityDeclScan(void *ent, void *save, const xmlChar *name ATTRIBUTE_UNUSED) { - xmlDumpEntityDecl((xmlBufferPtr) buf, (xmlEntityPtr) ent); + xmlSaveTree(save, ent); }
/** @@ -1143,6 +966,14 @@ xmlDumpEntityDeclScan(void *ent, void *buf, */ void xmlDumpEntitiesTable(xmlBufferPtr buf, xmlEntitiesTablePtr table) { - xmlHashScan(table, xmlDumpEntityDeclScan, buf); + xmlSaveCtxtPtr save; + + if ((buf == NULL) || (table == NULL)) + return; + + save = xmlSaveToBuffer(buf, NULL, 0); + xmlHashScan(table, xmlDumpEntityDeclScan, save); + if (xmlSaveFinish(save) != XML_ERR_OK) + xmlFree(xmlBufferDetach(buf)); } #endif /* LIBXML_OUTPUT_ENABLED */ diff --git a/libs/xml2/error.c b/libs/xml2/error.c index 746b73716bc..b678a0ee004 100644 --- a/libs/xml2/error.c +++ b/libs/xml2/error.c @@ -11,45 +11,169 @@
#include <string.h> #include <stdarg.h> +#include <stdlib.h> #include <libxml/parser.h> #include <libxml/xmlerror.h> #include <libxml/xmlmemory.h>
#include "private/error.h" +#include "private/string.h"
-#define XML_MAX_ERRORS 100 - -#define XML_GET_VAR_STR(msg, str) { \ - int size, prev_size = -1; \ - int chars; \ - char *larger; \ - va_list ap; \ - \ - str = (char *) xmlMalloc(150); \ - if (str != NULL) { \ - \ - size = 150; \ - \ - while (size < 64000) { \ - va_start(ap, msg); \ - chars = vsnprintf(str, size, msg, ap); \ - va_end(ap); \ - if ((chars > -1) && (chars < size)) { \ - if (prev_size == chars) { \ - break; \ - } else { \ - prev_size = chars; \ - } \ - } \ - if (chars > -1) \ - size += chars + 1; \ - else \ - size += 100; \ - if ((larger = (char *) xmlRealloc(str, size)) == NULL) {\ - break; \ - } \ - str = larger; \ - }} \ +/************************************************************************ + * * + * Error struct * + * * + ************************************************************************/ + +static int +xmlVSetError(xmlError *err, + void *ctxt, xmlNodePtr node, + int domain, int code, xmlErrorLevel level, + const char *file, int line, + const char *str1, const char *str2, const char *str3, + int int1, int col, + const char *fmt, va_list ap) +{ + char *message = NULL; + char *fileCopy = NULL; + char *str1Copy = NULL; + char *str2Copy = NULL; + char *str3Copy = NULL; + + if (code == XML_ERR_OK) { + xmlResetError(err); + return(0); + } + + /* + * Formatting the message + */ + if (fmt == NULL) { + message = xmlMemStrdup("No error message provided"); + } else { + xmlChar *tmp; + int res; + + res = xmlStrVASPrintf(&tmp, MAX_ERR_MSG_SIZE, fmt, ap); + if (res < 0) + goto err_memory; + message = (char *) tmp; + } + if (message == NULL) + goto err_memory; + + if (file != NULL) { + fileCopy = (char *) xmlStrdup((const xmlChar *) file); + if (fileCopy == NULL) + goto err_memory; + } + if (str1 != NULL) { + str1Copy = (char *) xmlStrdup((const xmlChar *) str1); + if (str1Copy == NULL) + goto err_memory; + } + if (str2 != NULL) { + str2Copy = (char *) xmlStrdup((const xmlChar *) str2); + if (str2Copy == NULL) + goto err_memory; + } + if (str3 != NULL) { + str3Copy = (char *) xmlStrdup((const xmlChar *) str3); + if (str3Copy == NULL) + goto err_memory; + } + + xmlResetError(err); + + err->domain = domain; + err->code = code; + err->message = message; + err->level = level; + err->file = fileCopy; + err->line = line; + err->str1 = str1Copy; + err->str2 = str2Copy; + err->str3 = str3Copy; + err->int1 = int1; + err->int2 = col; + err->node = node; + err->ctxt = ctxt; + + return(0); + +err_memory: + xmlFree(message); + xmlFree(fileCopy); + xmlFree(str1Copy); + xmlFree(str2Copy); + xmlFree(str3Copy); + return(-1); +} + +static int LIBXML_ATTR_FORMAT(14,15) +xmlSetError(xmlError *err, + void *ctxt, xmlNodePtr node, + int domain, int code, xmlErrorLevel level, + const char *file, int line, + const char *str1, const char *str2, const char *str3, + int int1, int col, + const char *fmt, ...) +{ + va_list ap; + int res; + + va_start(ap, fmt); + res = xmlVSetError(err, ctxt, node, domain, code, level, file, line, + str1, str2, str3, int1, col, fmt, ap); + va_end(ap); + + return(res); +} + +static int +xmlVUpdateError(xmlError *err, + void *ctxt, xmlNodePtr node, + int domain, int code, xmlErrorLevel level, + const char *file, int line, + const char *str1, const char *str2, const char *str3, + int int1, int col, + const char *fmt, va_list ap) +{ + int res; + + /* + * Find first element parent. + */ + if (node != NULL) { + int i; + + for (i = 0; i < 10; i++) { + if ((node->type == XML_ELEMENT_NODE) || + (node->parent == NULL)) + break; + node = node->parent; + } + } + + /* + * Get file and line from node. + */ + if (node != NULL) { + if ((file == NULL) && (node->doc != NULL)) + file = (const char *) node->doc->URL; + + if (line == 0) { + if (node->type == XML_ELEMENT_NODE) + line = node->line; + if ((line == 0) || (line == 65535)) + line = xmlGetLineNo(node); + } + } + + res = xmlVSetError(err, ctxt, node, domain, code, level, file, line, + str1, str2, str3, int1, col, fmt, ap); + + return(res); }
/************************************************************************ @@ -101,14 +225,21 @@ initGenericErrorDefaultFunc(xmlGenericErrorFunc * handler) * @ctx: the new error handling context * @handler: the new handler function * - * Function to reset the handler and the error context for out of - * context error messages. - * This simply means that @handler will be called for subsequent - * error messages while not parsing nor validating. And @ctx will - * be passed as first argument to @handler - * One can simply force messages to be emitted to another FILE * than - * stderr by setting @ctx to this file handle and @handler to NULL. - * For multi-threaded applications, this must be set separately for each thread. + * DEPRECATED: See xmlSetStructuredErrorFunc for alternatives. + * + * Set the global "generic" handler and context for error messages. + * The generic error handler will only receive fragments of error + * messages which should be concatenated or printed to a stream. + * + * If handler is NULL, use the built-in default handler which prints + * to stderr. + * + * Since this is a global setting, it's a good idea to reset the + * error handler to its default value after collecting the errors + * you're interested in. + * + * For multi-threaded applications, this must be set separately for + * each thread. */ void xmlSetGenericErrorFunc(void *ctx, xmlGenericErrorFunc handler) { @@ -124,12 +255,30 @@ xmlSetGenericErrorFunc(void *ctx, xmlGenericErrorFunc handler) { * @ctx: the new error handling context * @handler: the new handler function * - * Function to reset the handler and the error context for out of - * context structured error messages. - * This simply means that @handler will be called for subsequent - * error messages while not parsing nor validating. And @ctx will - * be passed as first argument to @handler - * For multi-threaded applications, this must be set separately for each thread. + * DEPRECATED: Use a per-context error handler. + * + * It's recommended to use the per-context error handlers instead: + * + * - xmlCtxtSetErrorHandler (since 2.13.0) + * - xmlTextReaderSetStructuredErrorHandler + * - xmlXPathSetErrorHandler (since 2.13.0) + * - xmlXIncludeSetErrorHandler (since 2.13.0) + * - xmlSchemaSetParserStructuredErrors + * - xmlSchemaSetValidStructuredErrors + * - xmlRelaxNGSetParserStructuredErrors + * - xmlRelaxNGSetValidStructuredErrors + * + * Set the global "structured" handler and context for error messages. + * If handler is NULL, the error handler is deactivated. + * + * The structured error handler takes precedence over "generic" + * handlers, even per-context generic handlers. + * + * Since this is a global setting, it's a good idea to deactivate the + * error handler after collecting the errors you're interested in. + * + * For multi-threaded applications, this must be set separately for + * each thread. */ void xmlSetStructuredErrorFunc(void *ctx, xmlStructuredErrorFunc handler) { @@ -147,6 +296,8 @@ xmlSetStructuredErrorFunc(void *ctx, xmlStructuredErrorFunc handler) { * xmlParserPrintFileInfo: * @input: an xmlParserInputPtr input * + * DEPRECATED: Use xmlFormatError. + * * Displays the associated file and line information for the current input */
@@ -238,6 +389,8 @@ xmlParserPrintFileContextInternal(xmlParserInputPtr input , * xmlParserPrintFileContext: * @input: an xmlParserInputPtr input * + * DEPRECATED: Use xmlFormatError. + * * Displays current context within the input content for error tracking */ void @@ -247,35 +400,37 @@ xmlParserPrintFileContext(xmlParserInputPtr input) { }
/** - * xmlReportError: - * @err: the error - * @ctx: the parser context or NULL - * @str: the formatted error message + * xmlFormatError: + * @err: the error + * @channel: callback + * @data: user data for callback + * + * Report a formatted error to a printf-like callback. * - * Report an error with its context, replace the 4 old error/warning - * routines. + * This can result in a verbose multi-line report including additional + * information from the parser context. + * + * Available since 2.13.0. */ -static void -xmlReportError(xmlErrorPtr err, xmlParserCtxtPtr ctxt, const char *str, - xmlGenericErrorFunc channel, void *data) +void +xmlFormatError(const xmlError *err, xmlGenericErrorFunc channel, void *data) { - char *file = NULL; - int line = 0; - int code = -1; + const char *message; + const char *file; + int line; + int code; int domain; const xmlChar *name = NULL; xmlNodePtr node; xmlErrorLevel level; + xmlParserCtxtPtr ctxt = NULL; xmlParserInputPtr input = NULL; xmlParserInputPtr cur = NULL;
- if (err == NULL) + if ((err == NULL) || (channel == NULL)) return;
- if (channel == NULL) { - channel = xmlGenericError; - data = xmlGenericErrorContext; - } + message = err->message; file = err->file; line = err->line; code = err->code; @@ -286,25 +441,30 @@ xmlReportError(xmlErrorPtr err, xmlParserCtxtPtr ctxt, const char *str, if (code == XML_ERR_OK) return;
- if ((node != NULL) && (node->type == XML_ELEMENT_NODE)) + if ((domain == XML_FROM_PARSER) || (domain == XML_FROM_HTML) || + (domain == XML_FROM_DTD) || (domain == XML_FROM_NAMESPACE) || + (domain == XML_FROM_IO) || (domain == XML_FROM_VALID)) { + ctxt = err->ctxt; + } + + if ((node != NULL) && (node->type == XML_ELEMENT_NODE) && + (domain != XML_FROM_SCHEMASV)) name = node->name;
/* * Maintain the compatibility with the legacy error handling */ - if (ctxt != NULL) { + if ((ctxt != NULL) && (ctxt->input != NULL)) { input = ctxt->input; - if ((input != NULL) && (input->filename == NULL) && + if ((input->filename == NULL) && (ctxt->inputNr > 1)) { cur = input; input = ctxt->inputTab[ctxt->inputNr - 2]; } - if (input != NULL) { - if (input->filename) - channel(data, "%s:%d: ", input->filename, input->line); - else if ((line != 0) && (domain == XML_FROM_PARSER)) - channel(data, "Entity: line %d: ", input->line); - } + if (input->filename) + channel(data, "%s:%d: ", input->filename, input->line); + else if ((line != 0) && (domain == XML_FROM_PARSER)) + channel(data, "Entity: line %d: ", input->line); } else { if (file != NULL) channel(data, "%s:%d: ", file, line); @@ -405,19 +565,35 @@ xmlReportError(xmlErrorPtr err, xmlParserCtxtPtr ctxt, const char *str, channel(data, "error : "); break; } - if (str != NULL) { + if (message != NULL) { int len; - len = xmlStrlen((const xmlChar *)str); - if ((len > 0) && (str[len - 1] != '\n')) - channel(data, "%s\n", str); + len = xmlStrlen((const xmlChar *) message); + if ((len > 0) && (message[len - 1] != '\n')) + channel(data, "%s\n", message); else - channel(data, "%s", str); + channel(data, "%s", message); } else { - channel(data, "%s\n", "out of memory error"); + channel(data, "%s\n", "No error message provided"); }
if (ctxt != NULL) { + if ((input != NULL) && + ((input->buf == NULL) || (input->buf->encoder == NULL)) && + (code == XML_ERR_INVALID_ENCODING) && + (input->cur < input->end)) { + int i; + + channel(data, "Bytes:"); + for (i = 0; i < 4; i++) { + if (input->cur + i >= input->end) + break; + channel(data, " 0x%02X", input->cur[i]); + } + channel(data, "\n"); + } + xmlParserPrintFileContextInternal(input, channel, data); + if (cur != NULL) { if (cur->filename) channel(data, "%s:%d: \n", cur->filename, cur->line); @@ -442,12 +618,53 @@ xmlReportError(xmlErrorPtr err, xmlParserCtxtPtr ctxt, const char *str, }
/** - * __xmlRaiseError: + * xmlRaiseMemoryError: + * @schannel: the structured callback channel + * @channel: the old callback channel + * @data: the callback data + * @domain: the domain for the error + * @error: optional error struct to be filled + * + * Update the global and optional error structure, then forward the + * error to an error handler. + * + * This function doesn't make memory allocations which are likely + * to fail after an OOM error. + */ +void +xmlRaiseMemoryError(xmlStructuredErrorFunc schannel, xmlGenericErrorFunc channel, + void *data, int domain, xmlError *error) +{ + xmlError *lastError = &xmlLastError; + + xmlResetLastError(); + lastError->domain = domain; + lastError->code = XML_ERR_NO_MEMORY; + lastError->level = XML_ERR_FATAL; + + if (error != NULL) { + xmlResetError(error); + error->domain = domain; + error->code = XML_ERR_NO_MEMORY; + error->level = XML_ERR_FATAL; + } + + if (schannel != NULL) { + schannel(data, lastError); + } else if (xmlStructuredError != NULL) { + xmlStructuredError(xmlStructuredErrorContext, lastError); + } else if (channel != NULL) { + channel(data, "libxml2: out of memory\n"); + } +} + +/** + * xmlVRaiseError: * @schannel: the structured callback channel * @channel: the old callback channel * @data: the callback data * @ctx: the parser context or NULL - * @ctx: the parser context or NULL + * @node: the current node or NULL * @domain: the domain for the error * @code: the code for the error * @level: the xmlErrorLevel for the error @@ -459,258 +676,128 @@ xmlReportError(xmlErrorPtr err, xmlParserCtxtPtr ctxt, const char *str, * @int1: extra int info * @col: column number of the error or 0 if N/A * @msg: the message to display/transmit - * @...: extra parameters for the message display + * @ap: extra parameters for the message display * * Update the appropriate global or contextual error structure, * then forward the error message down the parser or generic * error callback handler + * + * Returns 0 on success, -1 if a memory allocation failed. */ -void -__xmlRaiseError(xmlStructuredErrorFunc schannel, - xmlGenericErrorFunc channel, void *data, void *ctx, - void *nod, int domain, int code, xmlErrorLevel level, - const char *file, int line, const char *str1, - const char *str2, const char *str3, int int1, int col, - const char *msg, ...) +int +xmlVRaiseError(xmlStructuredErrorFunc schannel, + xmlGenericErrorFunc channel, void *data, void *ctx, + xmlNode *node, int domain, int code, xmlErrorLevel level, + const char *file, int line, const char *str1, + const char *str2, const char *str3, int int1, int col, + const char *msg, va_list ap) { xmlParserCtxtPtr ctxt = NULL; - xmlNodePtr node = (xmlNodePtr) nod; - char *str = NULL; - xmlParserInputPtr input = NULL; - xmlErrorPtr to = &xmlLastError; - xmlNodePtr baseptr = NULL; + /* xmlLastError is a macro retrieving the per-thread global. */ + xmlErrorPtr lastError = &xmlLastError; + xmlErrorPtr to = lastError;
if (code == XML_ERR_OK) - return; + return(0); +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + if (code == XML_ERR_INTERNAL_ERROR) { + fprintf(stderr, "Unexpected error: %d\n", code); + abort(); + } +#endif if ((xmlGetWarningsDefaultValue == 0) && (level == XML_ERR_WARNING)) - return; + return(0); + if ((domain == XML_FROM_PARSER) || (domain == XML_FROM_HTML) || (domain == XML_FROM_DTD) || (domain == XML_FROM_NAMESPACE) || (domain == XML_FROM_IO) || (domain == XML_FROM_VALID)) { ctxt = (xmlParserCtxtPtr) ctx;
- if (ctxt != NULL) { - if (level == XML_ERR_WARNING) { - if (ctxt->nbWarnings >= XML_MAX_ERRORS) - return; - ctxt->nbWarnings += 1; - } else { - if (ctxt->nbErrors >= XML_MAX_ERRORS) - return; - ctxt->nbErrors += 1; - } - - if ((schannel == NULL) && (ctxt->sax != NULL) && - (ctxt->sax->initialized == XML_SAX2_MAGIC) && - (ctxt->sax->serror != NULL)) { - schannel = ctxt->sax->serror; - data = ctxt->userData; - } - } - } - /* - * Check if structured error handler set - */ - if (schannel == NULL) { - schannel = xmlStructuredError; - /* - * if user has defined handler, change data ptr to user's choice - */ - if (schannel != NULL) - data = xmlStructuredErrorContext; - } - /* - * Formatting the message - */ - if (msg == NULL) { - str = (char *) xmlStrdup(BAD_CAST "No error message provided"); - } else { - XML_GET_VAR_STR(msg, str); + if (ctxt != NULL) + to = &ctxt->lastError; }
- /* - * specific processing if a parser context is provided - */ - if (ctxt != NULL) { - if (file == NULL) { - input = ctxt->input; - if ((input != NULL) && (input->filename == NULL) && - (ctxt->inputNr > 1)) { - input = ctxt->inputTab[ctxt->inputNr - 2]; - } - if (input != NULL) { - file = input->filename; - line = input->line; - col = input->col; - } - } - to = &ctxt->lastError; - } else if ((node != NULL) && (file == NULL)) { - int i; - - if ((node->doc != NULL) && (node->doc->URL != NULL)) { - baseptr = node; -/* file = (const char *) node->doc->URL; */ - } - for (i = 0; - ((i < 10) && (node != NULL) && (node->type != XML_ELEMENT_NODE)); - i++) - node = node->parent; - if ((baseptr == NULL) && (node != NULL) && - (node->doc != NULL) && (node->doc->URL != NULL)) - baseptr = node; - - if ((node != NULL) && (node->type == XML_ELEMENT_NODE)) - line = node->line; - if ((line == 0) || (line == 65535)) - line = xmlGetLineNo(node); - } + if (xmlVUpdateError(to, ctxt, node, domain, code, level, file, line, + str1, str2, str3, int1, col, msg, ap)) + return(-1);
- /* - * Save the information about the error - */ - xmlResetError(to); - to->domain = domain; - to->code = code; - to->message = str; - to->level = level; - if (file != NULL) - to->file = (char *) xmlStrdup((const xmlChar *) file); - else if (baseptr != NULL) { -#ifdef LIBXML_XINCLUDE_ENABLED - /* - * We check if the error is within an XInclude section and, - * if so, attempt to print out the href of the XInclude instead - * of the usual "base" (doc->URL) for the node (bug 152623). - */ - xmlNodePtr prev = baseptr; - char *href = NULL; - int inclcount = 0; - while (prev != NULL) { - if (prev->prev == NULL) - prev = prev->parent; - else { - prev = prev->prev; - if (prev->type == XML_XINCLUDE_START) { - if (inclcount > 0) { - --inclcount; - } else { - href = (char *) xmlGetProp(prev, BAD_CAST "href"); - if (href != NULL) - break; - } - } else if (prev->type == XML_XINCLUDE_END) - inclcount++; - } - } - if (href != NULL) - to->file = href; - else -#endif - to->file = (char *) xmlStrdup(baseptr->doc->URL); - if ((to->file == NULL) && (node != NULL) && (node->doc != NULL)) { - to->file = (char *) xmlStrdup(node->doc->URL); - } + if (to != lastError) { + if (xmlCopyError(to, lastError) < 0) + return(-1); } - to->line = line; - if (str1 != NULL) - to->str1 = (char *) xmlStrdup((const xmlChar *) str1); - if (str2 != NULL) - to->str2 = (char *) xmlStrdup((const xmlChar *) str2); - if (str3 != NULL) - to->str3 = (char *) xmlStrdup((const xmlChar *) str3); - to->int1 = int1; - to->int2 = col; - to->node = node; - to->ctxt = ctx; - - if (to != &xmlLastError) - xmlCopyError(to,&xmlLastError);
if (schannel != NULL) { schannel(data, to); - return; - } - - /* - * Find the callback channel if channel param is NULL - */ - if ((ctxt != NULL) && (channel == NULL) && - (xmlStructuredError == NULL) && (ctxt->sax != NULL)) { - if (level == XML_ERR_WARNING) - channel = ctxt->sax->warning; + } else if (xmlStructuredError != NULL) { + xmlStructuredError(xmlStructuredErrorContext, to); + } else if (channel != NULL) { + /* Don't invoke legacy error handlers */ + if ((channel == xmlGenericErrorDefaultFunc) || + (channel == xmlParserError) || + (channel == xmlParserWarning) || + (channel == xmlParserValidityError) || + (channel == xmlParserValidityWarning)) + xmlFormatError(to, xmlGenericError, xmlGenericErrorContext); else - channel = ctxt->sax->error; - data = ctxt->userData; - } else if (channel == NULL) { - channel = xmlGenericError; - if (ctxt != NULL) { - data = ctxt; - } else { - data = xmlGenericErrorContext; - } + channel(data, "%s", to->message); } - if (channel == NULL) - return;
- if ((channel == xmlParserError) || - (channel == xmlParserWarning) || - (channel == xmlParserValidityError) || - (channel == xmlParserValidityWarning)) - xmlReportError(to, ctxt, str, NULL, NULL); - else if (((void(*)(void)) channel == (void(*)(void)) fprintf) || - (channel == xmlGenericErrorDefaultFunc)) - xmlReportError(to, ctxt, str, channel, data); - else - channel(data, "%s", str); + return(0); }
/** - * __xmlSimpleError: - * @domain: where the error comes from - * @code: the error code - * @node: the context node - * @extra: extra information - * - * Handle an out of memory condition - */ -void -__xmlSimpleError(int domain, int code, xmlNodePtr node, - const char *msg, const char *extra) -{ - - if (code == XML_ERR_NO_MEMORY) { - if (extra) - __xmlRaiseError(NULL, NULL, NULL, NULL, node, domain, - XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra, - NULL, NULL, 0, 0, - "Memory allocation failed : %s\n", extra); - else - __xmlRaiseError(NULL, NULL, NULL, NULL, node, domain, - XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL, - NULL, NULL, 0, 0, "Memory allocation failed\n"); - } else { - __xmlRaiseError(NULL, NULL, NULL, NULL, node, domain, - code, XML_ERR_ERROR, NULL, 0, extra, - NULL, NULL, 0, 0, msg, extra); - } -} -/** - * xmlParserError: - * @ctx: an XML parser context + * __xmlRaiseError: + * @schannel: the structured callback channel + * @channel: the old callback channel + * @data: the callback data + * @ctx: the parser context or NULL + * @nod: the node or NULL + * @domain: the domain for the error + * @code: the code for the error + * @level: the xmlErrorLevel for the error + * @file: the file source of the error (or NULL) + * @line: the line of the error or 0 if N/A + * @str1: extra string info + * @str2: extra string info + * @str3: extra string info + * @int1: extra int info + * @col: column number of the error or 0 if N/A * @msg: the message to display/transmit * @...: extra parameters for the message display * - * Display and format an error messages, gives file, line, position and - * extra parameters. + * Update the appropriate global or contextual error structure, + * then forward the error message down the parser or generic + * error callback handler + * + * Returns 0 on success, -1 if a memory allocation failed. */ -void -xmlParserError(void *ctx, const char *msg, ...) +int +__xmlRaiseError(xmlStructuredErrorFunc schannel, + xmlGenericErrorFunc channel, void *data, void *ctx, + xmlNode *node, int domain, int code, xmlErrorLevel level, + const char *file, int line, const char *str1, + const char *str2, const char *str3, int int1, int col, + const char *msg, ...) { + va_list ap; + int res; + + va_start(ap, msg); + res = xmlVRaiseError(schannel, channel, data, ctx, node, domain, code, + level, file, line, str1, str2, str3, int1, col, msg, + ap); + va_end(ap); + + return(res); +} + +static void +xmlVFormatLegacyError(void *ctx, const char *level, + const char *fmt, va_list ap) { xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; xmlParserInputPtr input = NULL; xmlParserInputPtr cur = NULL; - char * str; + xmlChar *str = NULL;
if (ctxt != NULL) { input = ctxt->input; @@ -722,11 +809,13 @@ xmlParserError(void *ctx, const char *msg, ...) xmlParserPrintFileInfo(input); }
- xmlGenericError(xmlGenericErrorContext, "error: "); - XML_GET_VAR_STR(msg, str); - xmlGenericError(xmlGenericErrorContext, "%s", str); - if (str != NULL) + xmlGenericError(xmlGenericErrorContext, "%s: ", level); + + xmlStrVASPrintf(&str, MAX_ERR_MSG_SIZE, fmt, ap); + if (str != NULL) { + xmlGenericError(xmlGenericErrorContext, "%s", (char *) str); xmlFree(str); + }
if (ctxt != NULL) { xmlParserPrintFileContext(input); @@ -739,54 +828,43 @@ xmlParserError(void *ctx, const char *msg, ...) }
/** - * xmlParserWarning: + * xmlParserError: * @ctx: an XML parser context * @msg: the message to display/transmit * @...: extra parameters for the message display * - * Display and format a warning messages, gives file, line, position and + * Display and format an error messages, gives file, line, position and * extra parameters. */ void -xmlParserWarning(void *ctx, const char *msg, ...) +xmlParserError(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...) { - xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; - xmlParserInputPtr input = NULL; - xmlParserInputPtr cur = NULL; - char * str; + va_list ap;
- if (ctxt != NULL) { - input = ctxt->input; - if ((input != NULL) && (input->filename == NULL) && - (ctxt->inputNr > 1)) { - cur = input; - input = ctxt->inputTab[ctxt->inputNr - 2]; - } - xmlParserPrintFileInfo(input); - } + va_start(ap, msg); + xmlVFormatLegacyError(ctx, "error", msg, ap); + va_end(ap); +}
- xmlGenericError(xmlGenericErrorContext, "warning: "); - XML_GET_VAR_STR(msg, str); - xmlGenericError(xmlGenericErrorContext, "%s", str); - if (str != NULL) - xmlFree(str); +/** + * xmlParserWarning: + * @ctx: an XML parser context + * @msg: the message to display/transmit + * @...: extra parameters for the message display + * + * Display and format a warning messages, gives file, line, position and + * extra parameters. + */ +void +xmlParserWarning(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...) +{ + va_list ap;
- if (ctxt != NULL) { - xmlParserPrintFileContext(input); - if (cur != NULL) { - xmlParserPrintFileInfo(cur); - xmlGenericError(xmlGenericErrorContext, "\n"); - xmlParserPrintFileContext(cur); - } - } + va_start(ap, msg); + xmlVFormatLegacyError(ctx, "warning", msg, ap); + va_end(ap); }
-/************************************************************************ - * * - * Handling of validation errors * - * * - ************************************************************************/ - /** * xmlParserValidityError: * @ctx: an XML parser context @@ -797,38 +875,13 @@ xmlParserWarning(void *ctx, const char *msg, ...) * line, position and extra parameters. */ void -xmlParserValidityError(void *ctx, const char *msg, ...) +xmlParserValidityError(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...) { - xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; - xmlParserInputPtr input = NULL; - char * str; - int len = xmlStrlen((const xmlChar *) msg); - static int had_info = 0; - - if ((len > 1) && (msg[len - 2] != ':')) { - if (ctxt != NULL) { - input = ctxt->input; - if ((input->filename == NULL) && (ctxt->inputNr > 1)) - input = ctxt->inputTab[ctxt->inputNr - 2]; - - if (had_info == 0) { - xmlParserPrintFileInfo(input); - } - } - xmlGenericError(xmlGenericErrorContext, "validity error: "); - had_info = 0; - } else { - had_info = 1; - } + va_list ap;
- XML_GET_VAR_STR(msg, str); - xmlGenericError(xmlGenericErrorContext, "%s", str); - if (str != NULL) - xmlFree(str); - - if ((ctxt != NULL) && (input != NULL)) { - xmlParserPrintFileContext(input); - } + va_start(ap, msg); + xmlVFormatLegacyError(ctx, "validity error", msg, ap); + va_end(ap); }
/** @@ -841,30 +894,13 @@ xmlParserValidityError(void *ctx, const char *msg, ...) * position and extra parameters. */ void -xmlParserValidityWarning(void *ctx, const char *msg, ...) +xmlParserValidityWarning(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...) { - xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; - xmlParserInputPtr input = NULL; - char * str; - int len = xmlStrlen((const xmlChar *) msg); - - if ((ctxt != NULL) && (len != 0) && (msg[len - 1] != ':')) { - input = ctxt->input; - if ((input->filename == NULL) && (ctxt->inputNr > 1)) - input = ctxt->inputTab[ctxt->inputNr - 2]; - - xmlParserPrintFileInfo(input); - } - - xmlGenericError(xmlGenericErrorContext, "validity warning: "); - XML_GET_VAR_STR(msg, str); - xmlGenericError(xmlGenericErrorContext, "%s", str); - if (str != NULL) - xmlFree(str); + va_list ap;
- if (ctxt != NULL) { - xmlParserPrintFileContext(input); - } + va_start(ap, msg); + xmlVFormatLegacyError(ctx, "validity warning", msg, ap); + va_end(ap); }
@@ -982,41 +1018,351 @@ xmlCtxtResetLastError(void *ctx) */ int xmlCopyError(const xmlError *from, xmlErrorPtr to) { - char *message, *file, *str1, *str2, *str3; + const char *fmt = NULL;
if ((from == NULL) || (to == NULL)) return(-1);
- message = (char *) xmlStrdup((xmlChar *) from->message); - file = (char *) xmlStrdup ((xmlChar *) from->file); - str1 = (char *) xmlStrdup ((xmlChar *) from->str1); - str2 = (char *) xmlStrdup ((xmlChar *) from->str2); - str3 = (char *) xmlStrdup ((xmlChar *) from->str3); - - if (to->message != NULL) - xmlFree(to->message); - if (to->file != NULL) - xmlFree(to->file); - if (to->str1 != NULL) - xmlFree(to->str1); - if (to->str2 != NULL) - xmlFree(to->str2); - if (to->str3 != NULL) - xmlFree(to->str3); - to->domain = from->domain; - to->code = from->code; - to->level = from->level; - to->line = from->line; - to->node = from->node; - to->int1 = from->int1; - to->int2 = from->int2; - to->node = from->node; - to->ctxt = from->ctxt; - to->message = message; - to->file = file; - to->str1 = str1; - to->str2 = str2; - to->str3 = str3; - - return 0; + if (from->message != NULL) + fmt = "%s"; + + return(xmlSetError(to, from->ctxt, from->node, + from->domain, from->code, from->level, + from->file, from->line, + from->str1, from->str2, from->str3, + from->int1, from->int2, + fmt, from->message)); +} + +/** + * xmlErrString: + * @code: an xmlParserErrors code + * + * Returns an error message for a code. + */ +const char * +xmlErrString(xmlParserErrors code) { + const char *errmsg; + + switch (code) { + 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_INT_SUBSET_NOT_FINISHED: + errmsg = "Content error in the internal subset"; + 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"; + break; + case XML_ERR_INVALID_ENCODING: + errmsg = "Invalid bytes in character encoding"; + break; + case XML_ERR_RESOURCE_LIMIT: + errmsg = "Resource limit exceeded"; + break; + case XML_ERR_ARGUMENT: + errmsg = "Invalid argument"; + break; + case XML_ERR_SYSTEM: + errmsg = "Out of system resources"; + break; + case XML_ERR_REDECL_PREDEF_ENTITY: + errmsg = "Invalid redeclaration of predefined entity"; + break; + case XML_ERR_UNSUPPORTED_ENCODING: + errmsg = "Unsupported encoding"; + break; + case XML_ERR_INVALID_CHAR: + errmsg = "Invalid character"; + break; + + case XML_IO_UNKNOWN: + errmsg = "Unknown IO error"; break; + case XML_IO_EACCES: + errmsg = "Permission denied"; break; + case XML_IO_EAGAIN: + errmsg = "Resource temporarily unavailable"; break; + case XML_IO_EBADF: + errmsg = "Bad file descriptor"; break; + case XML_IO_EBADMSG: + errmsg = "Bad message"; break; + case XML_IO_EBUSY: + errmsg = "Resource busy"; break; + case XML_IO_ECANCELED: + errmsg = "Operation canceled"; break; + case XML_IO_ECHILD: + errmsg = "No child processes"; break; + case XML_IO_EDEADLK: + errmsg = "Resource deadlock avoided"; break; + case XML_IO_EDOM: + errmsg = "Domain error"; break; + case XML_IO_EEXIST: + errmsg = "File exists"; break; + case XML_IO_EFAULT: + errmsg = "Bad address"; break; + case XML_IO_EFBIG: + errmsg = "File too large"; break; + case XML_IO_EINPROGRESS: + errmsg = "Operation in progress"; break; + case XML_IO_EINTR: + errmsg = "Interrupted function call"; break; + case XML_IO_EINVAL: + errmsg = "Invalid argument"; break; + case XML_IO_EIO: + errmsg = "Input/output error"; break; + case XML_IO_EISDIR: + errmsg = "Is a directory"; break; + case XML_IO_EMFILE: + errmsg = "Too many open files"; break; + case XML_IO_EMLINK: + errmsg = "Too many links"; break; + case XML_IO_EMSGSIZE: + errmsg = "Inappropriate message buffer length"; break; + case XML_IO_ENAMETOOLONG: + errmsg = "Filename too long"; break; + case XML_IO_ENFILE: + errmsg = "Too many open files in system"; break; + case XML_IO_ENODEV: + errmsg = "No such device"; break; + case XML_IO_ENOENT: + errmsg = "No such file or directory"; break; + case XML_IO_ENOEXEC: + errmsg = "Exec format error"; break; + case XML_IO_ENOLCK: + errmsg = "No locks available"; break; + case XML_IO_ENOMEM: + errmsg = "Not enough space"; break; + case XML_IO_ENOSPC: + errmsg = "No space left on device"; break; + case XML_IO_ENOSYS: + errmsg = "Function not implemented"; break; + case XML_IO_ENOTDIR: + errmsg = "Not a directory"; break; + case XML_IO_ENOTEMPTY: + errmsg = "Directory not empty"; break; + case XML_IO_ENOTSUP: + errmsg = "Not supported"; break; + case XML_IO_ENOTTY: + errmsg = "Inappropriate I/O control operation"; break; + case XML_IO_ENXIO: + errmsg = "No such device or address"; break; + case XML_IO_EPERM: + errmsg = "Operation not permitted"; break; + case XML_IO_EPIPE: + errmsg = "Broken pipe"; break; + case XML_IO_ERANGE: + errmsg = "Result too large"; break; + case XML_IO_EROFS: + errmsg = "Read-only file system"; break; + case XML_IO_ESPIPE: + errmsg = "Invalid seek"; break; + case XML_IO_ESRCH: + errmsg = "No such process"; break; + case XML_IO_ETIMEDOUT: + errmsg = "Operation timed out"; break; + case XML_IO_EXDEV: + errmsg = "Improper link"; break; + case XML_IO_NETWORK_ATTEMPT: + errmsg = "Attempt to load network entity"; break; + case XML_IO_ENCODER: + errmsg = "encoder error"; break; + case XML_IO_FLUSH: + errmsg = "flush error"; break; + case XML_IO_WRITE: + errmsg = "write error"; break; + case XML_IO_NO_INPUT: + errmsg = "no input"; break; + case XML_IO_BUFFER_FULL: + errmsg = "buffer full"; break; + case XML_IO_LOAD_ERROR: + errmsg = "loading error"; break; + case XML_IO_ENOTSOCK: + errmsg = "not a socket"; break; + case XML_IO_EISCONN: + errmsg = "already connected"; break; + case XML_IO_ECONNREFUSED: + errmsg = "connection refused"; break; + case XML_IO_ENETUNREACH: + errmsg = "unreachable network"; break; + case XML_IO_EADDRINUSE: + errmsg = "address in use"; break; + case XML_IO_EALREADY: + errmsg = "already in use"; break; + case XML_IO_EAFNOSUPPORT: + errmsg = "unknown address family"; break; + case XML_IO_UNSUPPORTED_PROTOCOL: + errmsg = "unsupported protocol"; break; + + default: + errmsg = "Unregistered error message"; + } + + return(errmsg); } diff --git a/libs/xml2/globals.c b/libs/xml2/globals.c index 6193f388cbb..6dc8d3341d3 100644 --- a/libs/xml2/globals.c +++ b/libs/xml2/globals.c @@ -20,13 +20,13 @@ #include <libxml/xmlerror.h> #include <libxml/xmlmemory.h> #include <libxml/xmlIO.h> -#include <libxml/HTMLparser.h> #include <libxml/parser.h> #include <libxml/threads.h> #include <libxml/tree.h> #include <libxml/SAX.h> #include <libxml/SAX2.h>
+#include "private/dict.h" #include "private/error.h" #include "private/globals.h" #include "private/threads.h" @@ -76,10 +76,13 @@ struct _xmlGlobalState { void *waitHandle; #endif
+#ifdef LIBXML_THREAD_ENABLED + unsigned localRngState[2]; +#endif + #define XML_OP XML_DECLARE_MEMBER XML_GLOBALS_ALLOC XML_GLOBALS_ERROR -XML_GLOBALS_HTML XML_GLOBALS_IO XML_GLOBALS_PARSER XML_GLOBALS_TREE @@ -164,17 +167,14 @@ xmlFreeGlobalState(void *state); * * ************************************************************************/
+#ifdef LIBXML_THREAD_ENABLED +static unsigned xmlMainThreadRngState[2]; +#endif + /* * Memory allocation routines */
-#if defined(DEBUG_MEMORY_LOCATION) -xmlFreeFunc xmlFree = (xmlFreeFunc) xmlMemFree; -xmlMallocFunc xmlMalloc = (xmlMallocFunc) xmlMemMalloc; -xmlMallocFunc xmlMallocAtomic = (xmlMallocFunc) xmlMemMalloc; -xmlReallocFunc xmlRealloc = (xmlReallocFunc) xmlMemRealloc; -xmlStrdupFunc xmlMemStrdup = (xmlStrdupFunc) xmlMemoryStrdup; -#else /** * xmlFree: * @mem: an already allocated block of memory @@ -233,7 +233,6 @@ xmlPosixStrdup(const char *cur) { * Returns the copy of the string or NULL in case of error */ xmlStrdupFunc xmlMemStrdup = xmlPosixStrdup; -#endif /* DEBUG_MEMORY_LOCATION */
/** * xmlBufferAllocScheme: @@ -264,7 +263,7 @@ static int xmlDefaultBufferSizeThrDef = BASE_BUFFER_SIZE; * * Global setting, DEPRECATED. */ -int oldXMLWDcompatibility = 0; /* DEPRECATED */ +const int oldXMLWDcompatibility = 0; /* DEPRECATED */ /** * xmlParserDebugEntities: * @@ -274,8 +273,7 @@ int oldXMLWDcompatibility = 0; /* DEPRECATED */ * while handling entities. * Disabled by default */ -int xmlParserDebugEntities = 0; -static int xmlParserDebugEntitiesThrDef = 0; +const int xmlParserDebugEntities = 0; /** * xmlDoValidityCheckingDefaultValue: * @@ -289,7 +287,7 @@ static int xmlDoValidityCheckingDefaultValueThrDef = 0; /** * xmlGetWarningsDefaultValue: * - * DEPRECATED: Don't use + * DEPRECATED: Use the modern options API with XML_PARSE_NOWARNING. * * Global setting, indicate that the DTD validation should provide warnings. * Activated by default. @@ -460,7 +458,7 @@ static int xmlSaveNoEmptyTagsThrDef = 0; * * Default SAX version1 handler for XML, builds the DOM tree */ -xmlSAXHandlerV1 xmlDefaultSAXHandler = { +const xmlSAXHandlerV1 xmlDefaultSAXHandler = { xmlSAX2InternalSubset, xmlSAX2IsStandalone, xmlSAX2HasInternalSubset, @@ -500,7 +498,7 @@ xmlSAXHandlerV1 xmlDefaultSAXHandler = { * The default SAX Locator * { getPublicId, getSystemId, getLineNumber, getColumnNumber} */ -xmlSAXLocator xmlDefaultSAXLocator = { +const xmlSAXLocator xmlDefaultSAXLocator = { xmlSAX2GetPublicId, xmlSAX2GetSystemId, xmlSAX2GetLineNumber, @@ -516,7 +514,7 @@ xmlSAXLocator xmlDefaultSAXLocator = { * * Default old SAX v1 handler for HTML, builds the DOM tree */ -xmlSAXHandlerV1 htmlDefaultSAXHandler = { +const xmlSAXHandlerV1 htmlDefaultSAXHandler = { xmlSAX2InternalSubset, NULL, NULL, @@ -596,6 +594,11 @@ void xmlInitGlobalsInternal(void) { #endif mainthread = GetCurrentThreadId(); #endif + +#ifdef LIBXML_THREAD_ENABLED + xmlMainThreadRngState[0] = xmlGlobalRandom(); + xmlMainThreadRngState[1] = xmlGlobalRandom(); +#endif }
/** @@ -756,36 +759,21 @@ static void xmlInitGlobalState(xmlGlobalStatePtr gs) { xmlMutexLock(&xmlThrDefMutex);
-#if defined(LIBXML_HTML_ENABLED) && defined(LIBXML_LEGACY_ENABLED) && defined(LIBXML_SAX1_ENABLED) - inithtmlDefaultSAXHandler(&gs->gs_htmlDefaultSAXHandler); +#ifdef LIBXML_THREAD_ENABLED + gs->localRngState[0] = xmlGlobalRandom(); + gs->localRngState[1] = xmlGlobalRandom(); #endif
- gs->gs_oldXMLWDcompatibility = 0; gs->gs_xmlBufferAllocScheme = xmlBufferAllocSchemeThrDef; gs->gs_xmlDefaultBufferSize = xmlDefaultBufferSizeThrDef; -#if defined(LIBXML_SAX1_ENABLED) && defined(LIBXML_LEGACY_ENABLED) - initxmlDefaultSAXHandler(&gs->gs_xmlDefaultSAXHandler, 1); -#endif /* LIBXML_SAX1_ENABLED */ - gs->gs_xmlDefaultSAXLocator.getPublicId = xmlSAX2GetPublicId; - gs->gs_xmlDefaultSAXLocator.getSystemId = xmlSAX2GetSystemId; - gs->gs_xmlDefaultSAXLocator.getLineNumber = xmlSAX2GetLineNumber; - gs->gs_xmlDefaultSAXLocator.getColumnNumber = xmlSAX2GetColumnNumber; gs->gs_xmlDoValidityCheckingDefaultValue = xmlDoValidityCheckingDefaultValueThrDef; #ifdef LIBXML_THREAD_ALLOC_ENABLED -#ifdef DEBUG_MEMORY_LOCATION - gs->gs_xmlFree = xmlMemFree; - gs->gs_xmlMalloc = xmlMemMalloc; - gs->gs_xmlMallocAtomic = xmlMemMalloc; - gs->gs_xmlRealloc = xmlMemRealloc; - gs->gs_xmlMemStrdup = xmlMemoryStrdup; -#else gs->gs_xmlFree = free; gs->gs_xmlMalloc = malloc; gs->gs_xmlMallocAtomic = malloc; gs->gs_xmlRealloc = realloc; gs->gs_xmlMemStrdup = xmlPosixStrdup; -#endif #endif gs->gs_xmlGetWarningsDefaultValue = xmlGetWarningsDefaultValueThrDef; #ifdef LIBXML_OUTPUT_ENABLED @@ -796,7 +784,6 @@ xmlInitGlobalState(xmlGlobalStatePtr gs) { gs->gs_xmlKeepBlanksDefaultValue = xmlKeepBlanksDefaultValueThrDef; gs->gs_xmlLineNumbersDefaultValue = xmlLineNumbersDefaultValueThrDef; gs->gs_xmlLoadExtDtdDefaultValue = xmlLoadExtDtdDefaultValueThrDef; - gs->gs_xmlParserDebugEntities = xmlParserDebugEntitiesThrDef; gs->gs_xmlPedanticParserDefaultValue = xmlPedanticParserDefaultValueThrDef; gs->gs_xmlSubstituteEntitiesDefaultValue = xmlSubstituteEntitiesDefaultValueThrDef; @@ -904,12 +891,26 @@ xmlGetThreadLocalStorage(int allowFailure) { #define XML_OP XML_DEFINE_GLOBAL_WRAPPER XML_GLOBALS_ALLOC XML_GLOBALS_ERROR -XML_GLOBALS_HTML XML_GLOBALS_IO XML_GLOBALS_PARSER XML_GLOBALS_TREE #undef XML_OP
+#ifdef LIBXML_THREAD_ENABLED +/** + * xmlGetLocalRngState: + * + * Returns the local RNG state. + */ +unsigned * +xmlGetLocalRngState(void) { + if (IS_MAIN_THREAD) + return(xmlMainThreadRngState); + else + return(xmlGetThreadLocalStorage(0)->localRngState); +} +#endif + /* For backward compatibility */
const char *const * @@ -917,6 +918,35 @@ __xmlParserVersion(void) { return &xmlParserVersion; }
+const int * +__oldXMLWDcompatibility(void) { + return &oldXMLWDcompatibility; +} + +const int * +__xmlParserDebugEntities(void) { + return &xmlParserDebugEntities; +} + +const xmlSAXLocator * +__xmlDefaultSAXLocator(void) { + return &xmlDefaultSAXLocator; +} + +#ifdef LIBXML_SAX1_ENABLED +const xmlSAXHandlerV1 * +__xmlDefaultSAXHandler(void) { + return &xmlDefaultSAXHandler; +} + +#ifdef LIBXML_HTML_ENABLED +const xmlSAXHandlerV1 * +__htmlDefaultSAXHandler(void) { + return &htmlDefaultSAXHandler; +} +#endif /* LIBXML_HTML_ENABLED */ +#endif /* LIBXML_SAX1_ENABLED */ + #endif /* LIBXML_THREAD_ENABLED */
/** @@ -950,6 +980,8 @@ xmlCheckThreadLocalStorage(void) { return(0); }
+/** DOC_DISABLE */ + /** * DllMain: * @hinstDLL: handle to DLL instance @@ -1115,13 +1147,8 @@ int xmlThrDefLoadExtDtdDefaultValue(int v) { return ret; }
-int xmlThrDefParserDebugEntities(int v) { - int ret; - xmlMutexLock(&xmlThrDefMutex); - ret = xmlParserDebugEntitiesThrDef; - xmlParserDebugEntitiesThrDef = v; - xmlMutexUnlock(&xmlThrDefMutex); - return ret; +int xmlThrDefParserDebugEntities(int v ATTRIBUTE_UNUSED) { + return(xmlParserDebugEntities); }
int xmlThrDefPedanticParserDefaultValue(int v) { @@ -1206,3 +1233,5 @@ xmlThrDefOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc fun
return(old); } + +/** DOC_ENABLE */ diff --git a/libs/xml2/hash.c b/libs/xml2/hash.c index 183a6f93895..b3548297db7 100644 --- a/libs/xml2/hash.c +++ b/libs/xml2/hash.c @@ -445,16 +445,9 @@ xmlHashUpdateInternal(xmlHashTablePtr hash, const xmlChar *key, if (dealloc) dealloc(entry->payload, entry->key); entry->payload = payload; - return(0); - } else { - /* - * xmlHashAddEntry found an existing entry. - * - * TODO: We should return a different error code here to - * distinguish from malloc failures. - */ - return(-1); } + + return(0); }
/* @@ -589,7 +582,7 @@ xmlHashUpdateInternal(xmlHashTablePtr hash, const xmlChar *key,
hash->nbElems++;
- return(0); + return(1); }
/** @@ -604,6 +597,70 @@ xmlHashDefaultDeallocator(void *entry, const xmlChar *key ATTRIBUTE_UNUSED) { xmlFree(entry); }
+/** + * xmlHashAdd: + * @hash: hash table + * @key: string key + * @payload: pointer to the payload + * + * Add a hash table entry. If an entry with this key already exists, + * payload will not be updated and 0 is returned. This return value + * can't be distinguished from out-of-memory errors, so this function + * should be used with care. + * + * Available since 2.13.0. + * + * Returns 1 on success, 0 if an entry exists and -1 in case of error. + */ +int +xmlHashAdd(xmlHashTablePtr hash, const xmlChar *key, void *payload) { + return(xmlHashUpdateInternal(hash, key, NULL, NULL, payload, NULL, 0)); +} + +/** + * xmlHashAdd2: + * @hash: hash table + * @key: first string key + * @key2: second string key + * @payload: pointer to the payload + * + * Add a hash table entry with two strings as key. + * + * See xmlHashAdd. + * + * Available since 2.13.0. + * + * Returns 1 on success, 0 if an entry exists and -1 in case of error. + */ +int +xmlHashAdd2(xmlHashTablePtr hash, const xmlChar *key, + const xmlChar *key2, void *payload) { + return(xmlHashUpdateInternal(hash, key, key2, NULL, payload, NULL, 0)); +} + +/** + * xmlHashAdd3: + * @hash: hash table + * @key: first string key + * @key2: second string key + * @key3: third string key + * @payload: pointer to the payload + * + * Add a hash table entry with three strings as key. + * + * See xmlHashAdd. + * + * Available since 2.13.0. + * + * Returns 1 on success, 0 if an entry exists and -1 in case of error. + */ +int +xmlHashAdd3(xmlHashTablePtr hash, const xmlChar *key, + const xmlChar *key2, const xmlChar *key3, + void *payload) { + return(xmlHashUpdateInternal(hash, key, key2, key3, payload, NULL, 0)); +} + /** * xmlHashAddEntry: * @hash: hash table @@ -615,11 +672,21 @@ xmlHashDefaultDeallocator(void *entry, const xmlChar *key ATTRIBUTE_UNUSED) { * can't be distinguished from out-of-memory errors, so this function * should be used with care. * + * NOTE: This function doesn't allow to distinguish malloc failures from + * existing entries. Use xmlHashAdd instead. + * * Returns 0 on success and -1 in case of error. */ int xmlHashAddEntry(xmlHashTablePtr hash, const xmlChar *key, void *payload) { - return(xmlHashUpdateInternal(hash, key, NULL, NULL, payload, NULL, 0)); + int res = xmlHashUpdateInternal(hash, key, NULL, NULL, payload, NULL, 0); + + if (res == 0) + res = -1; + else if (res == 1) + res = 0; + + return(res); }
/** @@ -638,7 +705,14 @@ xmlHashAddEntry(xmlHashTablePtr hash, const xmlChar *key, void *payload) { int xmlHashAddEntry2(xmlHashTablePtr hash, const xmlChar *key, const xmlChar *key2, void *payload) { - return(xmlHashUpdateInternal(hash, key, key2, NULL, payload, NULL, 0)); + int res = xmlHashUpdateInternal(hash, key, key2, NULL, payload, NULL, 0); + + if (res == 0) + res = -1; + else if (res == 1) + res = 0; + + return(res); }
/** @@ -659,7 +733,14 @@ int xmlHashAddEntry3(xmlHashTablePtr hash, const xmlChar *key, const xmlChar *key2, const xmlChar *key3, void *payload) { - return(xmlHashUpdateInternal(hash, key, key2, key3, payload, NULL, 0)); + int res = xmlHashUpdateInternal(hash, key, key2, key3, payload, NULL, 0); + + if (res == 0) + res = -1; + else if (res == 1) + res = 0; + + return(res); }
/** @@ -677,8 +758,13 @@ xmlHashAddEntry3(xmlHashTablePtr hash, const xmlChar *key, int xmlHashUpdateEntry(xmlHashTablePtr hash, const xmlChar *key, void *payload, xmlHashDeallocator dealloc) { - return(xmlHashUpdateInternal(hash, key, NULL, NULL, payload, - dealloc, 1)); + int res = xmlHashUpdateInternal(hash, key, NULL, NULL, payload, + dealloc, 1); + + if (res == 1) + res = 0; + + return(res); }
/** @@ -699,8 +785,13 @@ int xmlHashUpdateEntry2(xmlHashTablePtr hash, const xmlChar *key, const xmlChar *key2, void *payload, xmlHashDeallocator dealloc) { - return(xmlHashUpdateInternal(hash, key, key2, NULL, payload, - dealloc, 1)); + int res = xmlHashUpdateInternal(hash, key, key2, NULL, payload, + dealloc, 1); + + if (res == 1) + res = 0; + + return(res); }
/** @@ -722,8 +813,13 @@ int xmlHashUpdateEntry3(xmlHashTablePtr hash, const xmlChar *key, const xmlChar *key2, const xmlChar *key3, void *payload, xmlHashDeallocator dealloc) { - return(xmlHashUpdateInternal(hash, key, key2, key3, payload, - dealloc, 1)); + int res = xmlHashUpdateInternal(hash, key, key2, key3, payload, + dealloc, 1); + + if (res == 1) + res = 0; + + return(res); }
/** @@ -1037,21 +1133,25 @@ xmlHashScanFull3(xmlHashTablePtr hash, const xmlChar *key, } }
-/** - * xmlHashCopy: +/* + * xmlHashCopySafe: * @hash: hash table - * @copy: copier function for items in the hash + * @copyFunc: copier function for items in the hash + * @deallocFunc: deallocation function in case of errors + * + * Copy the hash table using @copyFunc to copy payloads. * - * Copy the hash @table using @copy to copy payloads. + * Available since 2.13.0. * * Returns the new table or NULL if a memory allocation failed. */ xmlHashTablePtr -xmlHashCopy(xmlHashTablePtr hash, xmlHashCopier copy) { +xmlHashCopySafe(xmlHashTablePtr hash, xmlHashCopier copyFunc, + xmlHashDeallocator deallocFunc) { const xmlHashEntry *entry, *end; xmlHashTablePtr ret;
- if ((hash == NULL) || (copy == NULL)) + if ((hash == NULL) || (copyFunc == NULL)) return(NULL);
ret = xmlHashCreate(hash->size); @@ -1064,12 +1164,42 @@ xmlHashCopy(xmlHashTablePtr hash, xmlHashCopier copy) { end = &hash->table[hash->size];
for (entry = hash->table; entry < end; entry++) { - if (entry->hashValue != 0) - xmlHashAddEntry3(ret, entry->key, entry->key2, entry->key3, - copy(entry->payload, entry->key)); + if (entry->hashValue != 0) { + void *copy; + + copy = copyFunc(entry->payload, entry->key); + if (copy == NULL) + goto error; + if (xmlHashAdd3(ret, entry->key, entry->key2, entry->key3, + copy) <= 0) { + if (deallocFunc != NULL) + deallocFunc(copy, entry->key); + goto error; + } + } }
return(ret); + +error: + xmlHashFree(ret, deallocFunc); + return(NULL); +} + +/* + * xmlHashCopy: + * @hash: hash table + * @copy: copier function for items in the hash + * + * DEPRECATED: Leaks memory in error case. + * + * Copy the hash table using @copy to copy payloads. + * + * Returns the new table or NULL if a memory allocation failed. + */ +xmlHashTablePtr +xmlHashCopy(xmlHashTablePtr hash, xmlHashCopier copy) { + return(xmlHashCopySafe(hash, copy, NULL)); }
/** diff --git a/libs/xml2/include/libxml/HTMLparser.h b/libs/xml2/include/libxml/HTMLparser.h index e16d77492b2..7be3d2b8a43 100644 --- a/libs/xml2/include/libxml/HTMLparser.h +++ b/libs/xml2/include/libxml/HTMLparser.h @@ -80,22 +80,17 @@ struct _htmlEntityDesc { const char *desc; /* the description */ };
-/** DOC_DISABLE */ #ifdef LIBXML_SAX1_ENABLED - #define XML_GLOBALS_HTML \ - XML_OP(htmlDefaultSAXHandler, xmlSAXHandlerV1, XML_DEPRECATED) -#else - #define XML_GLOBALS_HTML -#endif
-#define XML_OP XML_DECLARE_GLOBAL -XML_GLOBALS_HTML -#undef XML_OP +XML_DEPRECATED +XMLPUBVAR const xmlSAXHandlerV1 htmlDefaultSAXHandler;
-#if defined(LIBXML_THREAD_ENABLED) && !defined(XML_GLOBALS_NO_REDEFINITION) - #define htmlDefaultSAXHandler XML_GLOBAL_MACRO(htmlDefaultSAXHandler) +#ifdef LIBXML_THREAD_ENABLED +XML_DEPRECATED +XMLPUBFUN const xmlSAXHandlerV1 *__htmlDefaultSAXHandler(void); #endif -/** DOC_ENABLE */ + +#endif /* LIBXML_SAX1_ENABLED */
/* * There is only few public functions. @@ -173,6 +168,7 @@ XMLPUBFUN int int *inlen, int quoteChar); XMLPUBFUN int htmlIsScriptAttribute(const xmlChar *name); +XML_DEPRECATED XMLPUBFUN int htmlHandleOmittedElem(int val);
@@ -251,6 +247,9 @@ XMLPUBFUN htmlDocPtr const char *URL, const char *encoding, int options); +XMLPUBFUN htmlDocPtr + htmlCtxtParseDocument (htmlParserCtxtPtr ctxt, + xmlParserInputPtr input); XMLPUBFUN htmlDocPtr htmlCtxtReadDoc (xmlParserCtxtPtr ctxt, const xmlChar *cur, @@ -300,7 +299,7 @@ typedef enum { XMLPUBFUN htmlStatus htmlAttrAllowed(const htmlElemDesc*, const xmlChar*, int) ; XMLPUBFUN int htmlElementAllowedHere(const htmlElemDesc*, const xmlChar*) ; XMLPUBFUN htmlStatus htmlElementStatusHere(const htmlElemDesc*, const htmlElemDesc*) ; -XMLPUBFUN htmlStatus htmlNodeStatus(const htmlNodePtr, int) ; +XMLPUBFUN htmlStatus htmlNodeStatus(htmlNodePtr, int) ; /** * htmlDefaultSubelement: * @elt: HTML element @@ -333,11 +332,5 @@ XMLPUBFUN htmlStatus htmlNodeStatus(const htmlNodePtr, int) ; } #endif
-#else /* LIBXML_HTML_ENABLED */ - -/** DOC_DISABLE */ -#define XML_GLOBALS_HTML -/** DOC_ENABLE */ - #endif /* LIBXML_HTML_ENABLED */ #endif /* __HTML_PARSER_H__ */ diff --git a/libs/xml2/include/libxml/debugXML.h b/libs/xml2/include/libxml/debugXML.h index 82746873648..1332dd73d9c 100644 --- a/libs/xml2/include/libxml/debugXML.h +++ b/libs/xml2/include/libxml/debugXML.h @@ -203,7 +203,7 @@ XMLPUBFUN int */ XMLPUBFUN void xmlShell (xmlDocPtr doc, - char *filename, + const char *filename, xmlShellReadlineFunc input, FILE *output);
diff --git a/libs/xml2/include/libxml/encoding.h b/libs/xml2/include/libxml/encoding.h index 8594cffc173..599a03e12cd 100644 --- a/libs/xml2/include/libxml/encoding.h +++ b/libs/xml2/include/libxml/encoding.h @@ -162,6 +162,13 @@ XMLPUBFUN void xmlCleanupCharEncodingHandlers (void); XMLPUBFUN void xmlRegisterCharEncodingHandler (xmlCharEncodingHandlerPtr handler); +XMLPUBFUN int + xmlLookupCharEncodingHandler (xmlCharEncoding enc, + xmlCharEncodingHandlerPtr *out); +XMLPUBFUN int + xmlOpenCharEncodingHandler (const char *name, + int output, + xmlCharEncodingHandlerPtr *out); XMLPUBFUN xmlCharEncodingHandlerPtr xmlGetCharEncodingHandler (xmlCharEncoding enc); XMLPUBFUN xmlCharEncodingHandlerPtr @@ -195,7 +202,9 @@ XMLPUBFUN xmlCharEncoding xmlDetectCharEncoding (const unsigned char *in, int len);
+/** DOC_DISABLE */ struct _xmlBuffer; +/** DOC_ENABLE */ XMLPUBFUN int xmlCharEncOutFunc (xmlCharEncodingHandler *handler, struct _xmlBuffer *out, diff --git a/libs/xml2/include/libxml/entities.h b/libs/xml2/include/libxml/entities.h index f679375321e..a0cfca8133f 100644 --- a/libs/xml2/include/libxml/entities.h +++ b/libs/xml2/include/libxml/entities.h @@ -11,10 +11,12 @@ #ifndef __XML_ENTITIES_H__ #define __XML_ENTITIES_H__
+/** DOC_DISABLE */ #include <libxml/xmlversion.h> #define XML_TREE_INTERNALS #include <libxml/tree.h> #undef XML_TREE_INTERNALS +/** DOC_ENABLE */
#ifdef __cplusplus extern "C" { @@ -57,7 +59,7 @@ struct _xmlEntity {
struct _xmlEntity *nexte; /* unused */ const xmlChar *URI; /* the full URI as computed */ - int owner; /* does the entity own the childrens */ + int owner; /* unused */ int flags; /* various flags */ unsigned long expandedSize; /* expanded size */ }; @@ -89,6 +91,15 @@ XMLPUBFUN xmlEntityPtr const xmlChar *content); XMLPUBFUN void xmlFreeEntity (xmlEntityPtr entity); +XMLPUBFUN int + xmlAddEntity (xmlDocPtr doc, + int extSubset, + const xmlChar *name, + int type, + const xmlChar *ExternalID, + const xmlChar *SystemID, + const xmlChar *content, + xmlEntityPtr *out); XMLPUBFUN xmlEntityPtr xmlAddDocEntity (xmlDocPtr doc, const xmlChar *name, diff --git a/libs/xml2/include/libxml/hash.h b/libs/xml2/include/libxml/hash.h index f4af09ee5f9..135b69669b3 100644 --- a/libs/xml2/include/libxml/hash.h +++ b/libs/xml2/include/libxml/hash.h @@ -109,6 +109,10 @@ XMLPUBFUN void /* * Add a new entry to the hash table. */ +XMLPUBFUN int + xmlHashAdd (xmlHashTablePtr hash, + const xmlChar *name, + void *userdata); XMLPUBFUN int xmlHashAddEntry (xmlHashTablePtr hash, const xmlChar *name, @@ -118,6 +122,11 @@ XMLPUBFUN int const xmlChar *name, void *userdata, xmlHashDeallocator dealloc); +XMLPUBFUN int + xmlHashAdd2 (xmlHashTablePtr hash, + const xmlChar *name, + const xmlChar *name2, + void *userdata); XMLPUBFUN int xmlHashAddEntry2 (xmlHashTablePtr hash, const xmlChar *name, @@ -129,6 +138,12 @@ XMLPUBFUN int const xmlChar *name2, void *userdata, xmlHashDeallocator dealloc); +XMLPUBFUN int + xmlHashAdd3 (xmlHashTablePtr hash, + const xmlChar *name, + const xmlChar *name2, + const xmlChar *name3, + void *userdata); XMLPUBFUN int xmlHashAddEntry3 (xmlHashTablePtr hash, const xmlChar *name, @@ -199,6 +214,10 @@ XMLPUBFUN void * /* * Helpers. */ +XMLPUBFUN xmlHashTablePtr + xmlHashCopySafe (xmlHashTablePtr hash, + xmlHashCopier copy, + xmlHashDeallocator dealloc); XMLPUBFUN xmlHashTablePtr xmlHashCopy (xmlHashTablePtr hash, xmlHashCopier copy); diff --git a/libs/xml2/include/libxml/list.h b/libs/xml2/include/libxml/list.h index 5eab8f59d83..1fa76aff084 100644 --- a/libs/xml2/include/libxml/list.h +++ b/libs/xml2/include/libxml/list.h @@ -119,10 +119,10 @@ XMLPUBFUN void xmlListMerge (xmlListPtr l1, xmlListPtr l2); XMLPUBFUN xmlListPtr - xmlListDup (const xmlListPtr old); + xmlListDup (xmlListPtr old); XMLPUBFUN int xmlListCopy (xmlListPtr cur, - const xmlListPtr old); + xmlListPtr old); /* Link operators */ XMLPUBFUN void * xmlLinkGetData (xmlLinkPtr lk); diff --git a/libs/xml2/include/libxml/nanohttp.h b/libs/xml2/include/libxml/nanohttp.h index 3b5e037fc5b..c70d1c26bb8 100644 --- a/libs/xml2/include/libxml/nanohttp.h +++ b/libs/xml2/include/libxml/nanohttp.h @@ -18,16 +18,21 @@ #ifdef __cplusplus extern "C" { #endif +XML_DEPRECATED XMLPUBFUN void xmlNanoHTTPInit (void); +XML_DEPRECATED XMLPUBFUN void xmlNanoHTTPCleanup (void); +XML_DEPRECATED XMLPUBFUN void xmlNanoHTTPScanProxy (const char *URL); +XML_DEPRECATED XMLPUBFUN int xmlNanoHTTPFetch (const char *URL, const char *filename, char **contentType); +XML_DEPRECATED XMLPUBFUN void * xmlNanoHTTPMethod (const char *URL, const char *method, @@ -35,6 +40,7 @@ XMLPUBFUN void * char **contentType, const char *headers, int ilen); +XML_DEPRECATED XMLPUBFUN void * xmlNanoHTTPMethodRedir (const char *URL, const char *method, @@ -43,34 +49,45 @@ XMLPUBFUN void * char **redir, const char *headers, int ilen); +XML_DEPRECATED XMLPUBFUN void * xmlNanoHTTPOpen (const char *URL, char **contentType); +XML_DEPRECATED XMLPUBFUN void * xmlNanoHTTPOpenRedir (const char *URL, char **contentType, char **redir); +XML_DEPRECATED XMLPUBFUN int xmlNanoHTTPReturnCode (void *ctx); +XML_DEPRECATED XMLPUBFUN const char * xmlNanoHTTPAuthHeader (void *ctx); +XML_DEPRECATED XMLPUBFUN const char * xmlNanoHTTPRedir (void *ctx); +XML_DEPRECATED XMLPUBFUN int xmlNanoHTTPContentLength( void * ctx ); +XML_DEPRECATED XMLPUBFUN const char * xmlNanoHTTPEncoding (void *ctx); +XML_DEPRECATED XMLPUBFUN const char * xmlNanoHTTPMimeType (void *ctx); +XML_DEPRECATED XMLPUBFUN int xmlNanoHTTPRead (void *ctx, void *dest, int len); #ifdef LIBXML_OUTPUT_ENABLED +XML_DEPRECATED XMLPUBFUN int xmlNanoHTTPSave (void *ctxt, const char *filename); #endif /* LIBXML_OUTPUT_ENABLED */ +XML_DEPRECATED XMLPUBFUN void xmlNanoHTTPClose (void *ctx); #ifdef __cplusplus diff --git a/libs/xml2/include/libxml/parser.h b/libs/xml2/include/libxml/parser.h index fd6d52074d6..78d29cada2a 100644 --- a/libs/xml2/include/libxml/parser.h +++ b/libs/xml2/include/libxml/parser.h @@ -10,6 +10,7 @@ #ifndef __XML_PARSER_H__ #define __XML_PARSER_H__
+/** DOC_DISABLE */ #include <libxml/xmlversion.h> #define XML_TREE_INTERNALS #include <libxml/tree.h> @@ -26,6 +27,7 @@ /* for compatibility */ #include <libxml/SAX2.h> #include <libxml/threads.h> +/** DOC_ENABLE */
#ifdef __cplusplus extern "C" { @@ -62,11 +64,11 @@ struct _xmlParserInput { xmlParserInputBufferPtr buf; /* UTF-8 encoded buffer */
const char *filename; /* The file analyzed, if any */ - const char *directory; /* the directory/base of the file */ + const char *directory; /* unused */ const xmlChar *base; /* Base of the array to parse */ const xmlChar *cur; /* Current char being parsed */ const xmlChar *end; /* end of the array to parse */ - int length; /* length if known */ + int length; /* unused */ int line; /* Current line */ int col; /* Current column */ unsigned long consumed; /* How many xmlChars already consumed */ @@ -75,7 +77,7 @@ struct _xmlParserInput { const xmlChar *version; /* the version string for entity */ int flags; /* Flags */ int id; /* an unique identifier for the entity */ - unsigned long parentConsumed; /* consumed bytes from parents */ + unsigned long parentConsumed; /* unused */ xmlEntityPtr entity; /* entity, if any */ };
@@ -134,30 +136,14 @@ typedef enum { XML_PARSER_XML_DECL /* before XML decl (but after BOM) */ } xmlParserInputState;
-/** - * XML_DETECT_IDS: - * - * Bit in the loadsubset context field to tell to do ID/REFs lookups. - * Use it to initialize xmlLoadExtDtdDefaultValue. +/** DOC_DISABLE */ +/* + * Internal bits in the 'loadsubset' context member */ #define XML_DETECT_IDS 2 - -/** - * XML_COMPLETE_ATTRS: - * - * Bit in the loadsubset context field to tell to do complete the - * elements attributes lists with the ones defaulted from the DTDs. - * Use it to initialize xmlLoadExtDtdDefaultValue. - */ #define XML_COMPLETE_ATTRS 4 - -/** - * XML_SKIP_IDS: - * - * Bit in the loadsubset context field to tell to not do ID/REFs registration. - * Used to initialize xmlLoadExtDtdDefaultValue in some special cases. - */ #define XML_SKIP_IDS 8 +/** DOC_ENABLE */
/** * xmlParserMode: @@ -222,16 +208,16 @@ struct _xmlParserCtxt {
int hasExternalSubset; /* reference and external subset */ int hasPErefs; /* the internal subset has PE refs */ - int external; /* are we parsing an external entity */ + int external; /* unused */
int valid; /* is the document valid */ int validate; /* shall we try to validate ? */ xmlValidCtxt vctxt; /* The validity context */
- xmlParserInputState instate; /* current type of input */ - int token; /* next char look-ahead */ + xmlParserInputState instate; /* push parser state */ + int token; /* unused */
- char *directory; /* the data directory */ + char *directory; /* unused */
/* Node name stack */ const xmlChar *name; /* Current parsed Node */ @@ -255,7 +241,7 @@ struct _xmlParserCtxt { int * spaceTab; /* array of space infos */
int depth; /* to prevent entity substitution loops */ - xmlParserInputPtr entity; /* used to check entities boundaries */ + xmlParserInputPtr entity; /* unused */ int charset; /* unused */ int nodelen; /* Those two fields are there to */ int nodemem; /* Speed up large node parsing */ @@ -266,11 +252,11 @@ struct _xmlParserCtxt { int linenumbers; /* set line number in element content */ void *catalogs; /* document's own catalog */ int recovery; /* run in recovery mode */ - int progressive; /* is this a progressive parsing */ + int progressive; /* unused */ xmlDictPtr dict; /* dictionary for the parser */ const xmlChar * *atts; /* array for the attributes callbacks */ int maxatts; /* the size of the array */ - int docdict; /* use strings from dict to build tree */ + int docdict; /* unused */
/* * pre-interned strings @@ -308,7 +294,7 @@ struct _xmlParserCtxt { xmlError lastError; xmlParserMode parseMode; /* the parser mode */ unsigned long nbentities; /* unused */ - unsigned long sizeentities; /* size of parsed entities */ + unsigned long sizeentities; /* size of external entities */
/* for use by HTML non-recursive parser */ xmlParserNodeInfo *nodeInfo; /* Current NodeInfo */ @@ -327,6 +313,9 @@ struct _xmlParserCtxt { xmlParserNsData *nsdb; /* namespace database */ unsigned attrHashMax; /* allocated size */ xmlAttrHashBucket *attrHash; /* atttribute hash table */ + + xmlStructuredErrorFunc errorHandler; + void *errorCtxt; };
/** @@ -843,21 +832,39 @@ typedef xmlParserInputPtr (*xmlExternalEntityLoader) (const char *URL, */
XMLPUBVAR const char *const xmlParserVersion; +XML_DEPRECATED +XMLPUBVAR const int oldXMLWDcompatibility; +XML_DEPRECATED +XMLPUBVAR const int xmlParserDebugEntities; +XML_DEPRECATED +XMLPUBVAR const xmlSAXLocator xmlDefaultSAXLocator; +#ifdef LIBXML_SAX1_ENABLED +XML_DEPRECATED +XMLPUBVAR const xmlSAXHandlerV1 xmlDefaultSAXHandler; +#endif + #ifdef LIBXML_THREAD_ENABLED /* backward compatibility */ XMLPUBFUN const char *const *__xmlParserVersion(void); +XML_DEPRECATED +XMLPUBFUN const int *__oldXMLWDcompatibility(void); +XML_DEPRECATED +XMLPUBFUN const int *__xmlParserDebugEntities(void); +XML_DEPRECATED +XMLPUBFUN const xmlSAXLocator *__xmlDefaultSAXLocator(void); +#ifdef LIBXML_SAX1_ENABLED +XML_DEPRECATED +XMLPUBFUN const xmlSAXHandlerV1 *__xmlDefaultSAXHandler(void); +#endif #endif
/** DOC_DISABLE */ #define XML_GLOBALS_PARSER_CORE \ - XML_OP(oldXMLWDcompatibility, int, XML_DEPRECATED) \ - XML_OP(xmlDefaultSAXLocator, xmlSAXLocator, XML_DEPRECATED) \ XML_OP(xmlDoValidityCheckingDefaultValue, int, XML_DEPRECATED) \ XML_OP(xmlGetWarningsDefaultValue, int, XML_DEPRECATED) \ XML_OP(xmlKeepBlanksDefaultValue, int, XML_DEPRECATED) \ XML_OP(xmlLineNumbersDefaultValue, int, XML_DEPRECATED) \ XML_OP(xmlLoadExtDtdDefaultValue, int, XML_DEPRECATED) \ - XML_OP(xmlParserDebugEntities, int, XML_DEPRECATED) \ XML_OP(xmlPedanticParserDefaultValue, int, XML_DEPRECATED) \ XML_OP(xmlSubstituteEntitiesDefaultValue, int, XML_DEPRECATED)
@@ -870,26 +877,15 @@ XMLPUBFUN const char *const *__xmlParserVersion(void); #define XML_GLOBALS_PARSER_OUTPUT #endif
-#ifdef LIBXML_SAX1_ENABLED - #define XML_GLOBALS_PARSER_SAX1 \ - XML_OP(xmlDefaultSAXHandler, xmlSAXHandlerV1, XML_DEPRECATED) -#else - #define XML_GLOBALS_PARSER_SAX1 -#endif - #define XML_GLOBALS_PARSER \ XML_GLOBALS_PARSER_CORE \ - XML_GLOBALS_PARSER_OUTPUT \ - XML_GLOBALS_PARSER_SAX1 + XML_GLOBALS_PARSER_OUTPUT
#define XML_OP XML_DECLARE_GLOBAL XML_GLOBALS_PARSER #undef XML_OP
#if defined(LIBXML_THREAD_ENABLED) && !defined(XML_GLOBALS_NO_REDEFINITION) - #define oldXMLWDcompatibility XML_GLOBAL_MACRO(oldXMLWDcompatibility) - #define xmlDefaultSAXHandler XML_GLOBAL_MACRO(xmlDefaultSAXHandler) - #define xmlDefaultSAXLocator XML_GLOBAL_MACRO(xmlDefaultSAXLocator) #define xmlDoValidityCheckingDefaultValue \ XML_GLOBAL_MACRO(xmlDoValidityCheckingDefaultValue) #define xmlGetWarningsDefaultValue \ @@ -898,7 +894,6 @@ XML_GLOBALS_PARSER #define xmlLineNumbersDefaultValue \ XML_GLOBAL_MACRO(xmlLineNumbersDefaultValue) #define xmlLoadExtDtdDefaultValue XML_GLOBAL_MACRO(xmlLoadExtDtdDefaultValue) - #define xmlParserDebugEntities XML_GLOBAL_MACRO(xmlParserDebugEntities) #define xmlPedanticParserDefaultValue \ XML_GLOBAL_MACRO(xmlPedanticParserDefaultValue) #define xmlSubstituteEntitiesDefaultValue \ @@ -1185,18 +1180,18 @@ XMLPUBFUN xmlParserInputPtr * Node infos. */ XMLPUBFUN const xmlParserNodeInfo* - xmlParserFindNodeInfo (const xmlParserCtxtPtr ctxt, - const xmlNodePtr node); + xmlParserFindNodeInfo (xmlParserCtxtPtr ctxt, + xmlNodePtr node); XMLPUBFUN void xmlInitNodeInfoSeq (xmlParserNodeInfoSeqPtr seq); XMLPUBFUN void xmlClearNodeInfoSeq (xmlParserNodeInfoSeqPtr seq); XMLPUBFUN unsigned long - xmlParserFindNodeInfoIndex(const xmlParserNodeInfoSeqPtr seq, - const xmlNodePtr node); + xmlParserFindNodeInfoIndex(xmlParserNodeInfoSeqPtr seq, + xmlNodePtr node); XMLPUBFUN void xmlParserAddNodeInfo (xmlParserCtxtPtr ctxt, - const xmlParserNodeInfoPtr info); + xmlParserNodeInfoPtr info);
/* * External entities handling actually implemented in xmlIO. @@ -1251,7 +1246,8 @@ typedef enum { XML_PARSE_HUGE = 1<<19,/* relax any hardcoded limit from the parser */ XML_PARSE_OLDSAX = 1<<20,/* parse using SAX2 interface before 2.7.0 */ XML_PARSE_IGNORE_ENC= 1<<21,/* ignore internal document encoding hint */ - XML_PARSE_BIG_LINES = 1<<22 /* Store big lines numbers in text PSVI field */ + XML_PARSE_BIG_LINES = 1<<22,/* Store big lines numbers in text PSVI field */ + XML_PARSE_NO_XXE = 1<<23 /* disable loading of external content */ } xmlParserOption;
XMLPUBFUN void @@ -1262,9 +1258,16 @@ XMLPUBFUN int int size, const char *filename, const char *encoding); +XMLPUBFUN int + xmlCtxtSetOptions (xmlParserCtxtPtr ctxt, + int options); XMLPUBFUN int xmlCtxtUseOptions (xmlParserCtxtPtr ctxt, int options); +XMLPUBFUN void + xmlCtxtSetErrorHandler (xmlParserCtxtPtr ctxt, + xmlStructuredErrorFunc handler, + void *data); XMLPUBFUN void xmlCtxtSetMaxAmplification(xmlParserCtxtPtr ctxt, unsigned maxAmpl); @@ -1295,6 +1298,9 @@ XMLPUBFUN xmlDocPtr const char *URL, const char *encoding, int options); +XMLPUBFUN xmlDocPtr + xmlCtxtParseDocument (xmlParserCtxtPtr ctxt, + xmlParserInputPtr input); XMLPUBFUN xmlDocPtr xmlCtxtReadDoc (xmlParserCtxtPtr ctxt, const xmlChar *cur, @@ -1368,7 +1374,7 @@ typedef enum { XML_WITH_MODULES = 27, XML_WITH_DEBUG = 28, XML_WITH_DEBUG_MEM = 29, - XML_WITH_DEBUG_RUN = 30, + XML_WITH_DEBUG_RUN = 30, /* unused */ XML_WITH_ZLIB = 31, XML_WITH_ICU = 32, XML_WITH_LZMA = 33, diff --git a/libs/xml2/include/libxml/parserInternals.h b/libs/xml2/include/libxml/parserInternals.h index 017ed27358a..c4d4363b53a 100644 --- a/libs/xml2/include/libxml/parserInternals.h +++ b/libs/xml2/include/libxml/parserInternals.h @@ -25,11 +25,14 @@ extern "C" { /** * xmlParserMaxDepth: * + * DEPRECATED: has no effect + * * 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, use XML_PARSE_HUGE option to override it. */ -XMLPUBVAR unsigned int xmlParserMaxDepth; +XML_DEPRECATED +XMLPUBVAR const unsigned int xmlParserMaxDepth;
/** * XML_MAX_TEXT_LENGTH: @@ -313,9 +316,14 @@ XMLPUBFUN xmlParserCtxtPtr xmlCreateEntityParserCtxt(const xmlChar *URL, const xmlChar *ID, const xmlChar *base); +XMLPUBFUN void + xmlCtxtErrMemory (xmlParserCtxtPtr ctxt); XMLPUBFUN int xmlSwitchEncoding (xmlParserCtxtPtr ctxt, xmlCharEncoding enc); +XMLPUBFUN int + xmlSwitchEncodingName (xmlParserCtxtPtr ctxt, + const char *encoding); XMLPUBFUN int xmlSwitchToEncoding (xmlParserCtxtPtr ctxt, xmlCharEncodingHandlerPtr handler); diff --git a/libs/xml2/include/libxml/pattern.h b/libs/xml2/include/libxml/pattern.h index 72bf2390356..947f0900a23 100644 --- a/libs/xml2/include/libxml/pattern.h +++ b/libs/xml2/include/libxml/pattern.h @@ -54,6 +54,12 @@ XMLPUBFUN xmlPatternPtr xmlDict *dict, int flags, const xmlChar **namespaces); +XMLPUBFUN int + xmlPatternCompileSafe (const xmlChar *pattern, + xmlDict *dict, + int flags, + const xmlChar **namespaces, + xmlPatternPtr *patternOut); XMLPUBFUN int xmlPatternMatch (xmlPatternPtr comp, xmlNodePtr node); diff --git a/libs/xml2/include/libxml/tree.h b/libs/xml2/include/libxml/tree.h index 61c1ed49d95..77d17cd0d8f 100644 --- a/libs/xml2/include/libxml/tree.h +++ b/libs/xml2/include/libxml/tree.h @@ -173,13 +173,13 @@ typedef enum { XML_TEXT_NODE= 3, XML_CDATA_SECTION_NODE= 4, XML_ENTITY_REF_NODE= 5, - XML_ENTITY_NODE= 6, + XML_ENTITY_NODE= 6, /* unused */ XML_PI_NODE= 7, XML_COMMENT_NODE= 8, XML_DOCUMENT_NODE= 9, - XML_DOCUMENT_TYPE_NODE= 10, + XML_DOCUMENT_TYPE_NODE= 10, /* unused */ XML_DOCUMENT_FRAG_NODE= 11, - XML_NOTATION_NODE= 12, + XML_NOTATION_NODE= 12, /* unused */ XML_HTML_DOCUMENT_NODE= 13, XML_DTD_NODE= 14, XML_ELEMENT_DECL= 15, @@ -449,6 +449,7 @@ struct _xmlAttr { xmlNs *ns; /* pointer to the associated namespace */ xmlAttributeType atype; /* the attribute type if validating */ void *psvi; /* for type/PSVI information */ + struct _xmlID *id; /* the ID struct */ };
/** @@ -1011,10 +1012,10 @@ XMLPUBFUN void xmlFreeNodeList (xmlNodePtr cur); XMLPUBFUN void xmlFreeNode (xmlNodePtr cur); -XMLPUBFUN void +XMLPUBFUN int xmlSetTreeDoc (xmlNodePtr tree, xmlDocPtr doc); -XMLPUBFUN void +XMLPUBFUN int xmlSetListDoc (xmlNodePtr list, xmlDocPtr doc); /* @@ -1030,6 +1031,10 @@ XMLPUBFUN xmlNsPtr const xmlChar *href); #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || \ defined(LIBXML_SCHEMAS_ENABLED) +XMLPUBFUN int + xmlGetNsListSafe (const xmlDoc *doc, + const xmlNode *node, + xmlNsPtr **out); XMLPUBFUN xmlNsPtr * xmlGetNsList (const xmlDoc *doc, const xmlNode *node); @@ -1059,6 +1064,11 @@ XMLPUBFUN xmlAttrPtr const xmlChar *value); #endif /* defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || \ defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_HTML_ENABLED) */ +XMLPUBFUN int + xmlNodeGetAttrValue (const xmlNode *node, + const xmlChar *name, + const xmlChar *nsUri, + xmlChar **out); XMLPUBFUN xmlChar * xmlGetNoNsProp (const xmlNode *node, const xmlChar *name); @@ -1093,19 +1103,19 @@ XMLPUBFUN xmlChar * const xmlNode *list, int inLine); #endif /* LIBXML_TREE_ENABLED */ -XMLPUBFUN void +XMLPUBFUN int xmlNodeSetContent (xmlNodePtr cur, const xmlChar *content); #ifdef LIBXML_TREE_ENABLED -XMLPUBFUN void +XMLPUBFUN int xmlNodeSetContentLen (xmlNodePtr cur, const xmlChar *content, int len); #endif /* LIBXML_TREE_ENABLED */ -XMLPUBFUN void +XMLPUBFUN int xmlNodeAddContent (xmlNodePtr cur, const xmlChar *content); -XMLPUBFUN void +XMLPUBFUN int xmlNodeAddContentLen (xmlNodePtr cur, const xmlChar *content, int len); @@ -1124,18 +1134,22 @@ XMLPUBFUN xmlChar * XMLPUBFUN int xmlNodeGetSpacePreserve (const xmlNode *cur); #ifdef LIBXML_TREE_ENABLED -XMLPUBFUN void +XMLPUBFUN int xmlNodeSetLang (xmlNodePtr cur, const xmlChar *lang); -XMLPUBFUN void +XMLPUBFUN int xmlNodeSetSpacePreserve (xmlNodePtr cur, int val); #endif /* LIBXML_TREE_ENABLED */ +XMLPUBFUN int + xmlNodeGetBaseSafe (const xmlDoc *doc, + const xmlNode *cur, + xmlChar **baseOut); XMLPUBFUN xmlChar * xmlNodeGetBase (const xmlDoc *doc, const xmlNode *cur); #if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) -XMLPUBFUN void +XMLPUBFUN int xmlNodeSetBase (xmlNodePtr cur, const xmlChar *uri); #endif @@ -1283,8 +1297,10 @@ XMLPUBFUN int XMLPUBFUN void xmlSetDocCompressMode (xmlDocPtr doc, int mode); +XML_DEPRECATED XMLPUBFUN int xmlGetCompressMode (void); +XML_DEPRECATED XMLPUBFUN void xmlSetCompressMode (int mode);
@@ -1338,12 +1354,16 @@ XMLPUBFUN xmlNodePtr xmlPreviousElementSibling (xmlNodePtr node); #endif
+XML_DEPRECATED XMLPUBFUN xmlRegisterNodeFunc xmlRegisterNodeDefault (xmlRegisterNodeFunc func); +XML_DEPRECATED XMLPUBFUN xmlDeregisterNodeFunc xmlDeregisterNodeDefault (xmlDeregisterNodeFunc func); +XML_DEPRECATED XMLPUBFUN xmlRegisterNodeFunc xmlThrDefRegisterNodeDefault(xmlRegisterNodeFunc func); +XML_DEPRECATED XMLPUBFUN xmlDeregisterNodeFunc xmlThrDefDeregisterNodeDefault(xmlDeregisterNodeFunc func);
diff --git a/libs/xml2/include/libxml/uri.h b/libs/xml2/include/libxml/uri.h index eb8631cf081..19980b711c5 100644 --- a/libs/xml2/include/libxml/uri.h +++ b/libs/xml2/include/libxml/uri.h @@ -52,14 +52,25 @@ struct _xmlURI { */ XMLPUBFUN xmlURIPtr xmlCreateURI (void); +XMLPUBFUN int + xmlBuildURISafe (const xmlChar *URI, + const xmlChar *base, + xmlChar **out); XMLPUBFUN xmlChar * xmlBuildURI (const xmlChar *URI, const xmlChar *base); +XMLPUBFUN int + xmlBuildRelativeURISafe (const xmlChar *URI, + const xmlChar *base, + xmlChar **out); XMLPUBFUN xmlChar * xmlBuildRelativeURI (const xmlChar *URI, const xmlChar *base); XMLPUBFUN xmlURIPtr xmlParseURI (const char *str); +XMLPUBFUN int + xmlParseURISafe (const char *str, + xmlURIPtr *uri); XMLPUBFUN xmlURIPtr xmlParseURIRaw (const char *str, int raw); diff --git a/libs/xml2/include/libxml/valid.h b/libs/xml2/include/libxml/valid.h index 3e04b55217c..e1698d7a340 100644 --- a/libs/xml2/include/libxml/valid.h +++ b/libs/xml2/include/libxml/valid.h @@ -11,6 +11,7 @@ #ifndef __XML_VALID_H__ #define __XML_VALID_H__
+/** DOC_DISABLE */ #include <libxml/xmlversion.h> #include <libxml/xmlerror.h> #define XML_TREE_INTERNALS @@ -19,6 +20,7 @@ #include <libxml/list.h> #include <libxml/xmlautomata.h> #include <libxml/xmlregexp.h> +/** DOC_ENABLE */
#ifdef __cplusplus extern "C" { @@ -150,9 +152,11 @@ XMLPUBFUN xmlNotationTablePtr XMLPUBFUN void xmlFreeNotationTable (xmlNotationTablePtr table); #ifdef LIBXML_OUTPUT_ENABLED +XML_DEPRECATED XMLPUBFUN void xmlDumpNotationDecl (xmlBufferPtr buf, xmlNotationPtr nota); +/* XML_DEPRECATED, still used in lxml */ XMLPUBFUN void xmlDumpNotationTable (xmlBufferPtr buf, xmlNotationTablePtr table); @@ -184,13 +188,12 @@ XMLPUBFUN void xmlElementContentPtr content, int englob); #ifdef LIBXML_OUTPUT_ENABLED -/* DEPRECATED */ +XML_DEPRECATED XMLPUBFUN void xmlSprintfElementContent(char *buf, xmlElementContentPtr content, int englob); #endif /* LIBXML_OUTPUT_ENABLED */ -/* DEPRECATED */
/* Element */ XMLPUBFUN xmlElementPtr @@ -206,9 +209,11 @@ XMLPUBFUN xmlElementTablePtr XMLPUBFUN void xmlFreeElementTable (xmlElementTablePtr table); #ifdef LIBXML_OUTPUT_ENABLED +XML_DEPRECATED XMLPUBFUN void xmlDumpElementTable (xmlBufferPtr buf, xmlElementTablePtr table); +XML_DEPRECATED XMLPUBFUN void xmlDumpElementDecl (xmlBufferPtr buf, xmlElementPtr elem); @@ -242,15 +247,20 @@ XMLPUBFUN xmlAttributeTablePtr XMLPUBFUN void xmlFreeAttributeTable (xmlAttributeTablePtr table); #ifdef LIBXML_OUTPUT_ENABLED +XML_DEPRECATED XMLPUBFUN void xmlDumpAttributeTable (xmlBufferPtr buf, xmlAttributeTablePtr table); +XML_DEPRECATED XMLPUBFUN void xmlDumpAttributeDecl (xmlBufferPtr buf, xmlAttributePtr attr); #endif /* LIBXML_OUTPUT_ENABLED */
/* IDs */ +XMLPUBFUN int + xmlAddIDSafe (xmlAttrPtr attr, + const xmlChar *value); XMLPUBFUN xmlIDPtr xmlAddID (xmlValidCtxtPtr ctxt, xmlDocPtr doc, @@ -303,31 +313,38 @@ XMLPUBFUN xmlValidCtxtPtr XMLPUBFUN void xmlFreeValidCtxt(xmlValidCtxtPtr);
+XML_DEPRECATED XMLPUBFUN int xmlValidateRoot (xmlValidCtxtPtr ctxt, xmlDocPtr doc); +XML_DEPRECATED XMLPUBFUN int xmlValidateElementDecl (xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlElementPtr elem); +XML_DEPRECATED XMLPUBFUN xmlChar * xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem, const xmlChar *name, const xmlChar *value); +XML_DEPRECATED XMLPUBFUN xmlChar * xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem, const xmlChar *name, const xmlChar *value); +XML_DEPRECATED XMLPUBFUN int xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlAttributePtr attr); +XML_DEPRECATED XMLPUBFUN int xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value); +XML_DEPRECATED XMLPUBFUN int xmlValidateNotationDecl (xmlValidCtxtPtr ctxt, xmlDocPtr doc, @@ -336,6 +353,7 @@ XMLPUBFUN int xmlValidateDtd (xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd); +XML_DEPRECATED XMLPUBFUN int xmlValidateDtdFinal (xmlValidCtxtPtr ctxt, xmlDocPtr doc); @@ -346,16 +364,19 @@ XMLPUBFUN int xmlValidateElement (xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem); +XML_DEPRECATED XMLPUBFUN int xmlValidateOneElement (xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem); +XML_DEPRECATED XMLPUBFUN int xmlValidateOneAttribute (xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value); +XML_DEPRECATED XMLPUBFUN int xmlValidateOneNamespace (xmlValidCtxtPtr ctxt, xmlDocPtr doc, @@ -363,12 +384,14 @@ XMLPUBFUN int const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value); +XML_DEPRECATED XMLPUBFUN int xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc); #endif /* LIBXML_VALID_ENABLED */
#if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) +XML_DEPRECATED XMLPUBFUN int xmlValidateNotationUse (xmlValidCtxtPtr ctxt, xmlDocPtr doc, @@ -424,19 +447,23 @@ XMLPUBFUN int /* * Validation based on the regexp support */ +XML_DEPRECATED XMLPUBFUN int xmlValidBuildContentModel(xmlValidCtxtPtr ctxt, xmlElementPtr elem);
+XML_DEPRECATED XMLPUBFUN int xmlValidatePushElement (xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem, const xmlChar *qname); +XML_DEPRECATED XMLPUBFUN int xmlValidatePushCData (xmlValidCtxtPtr ctxt, const xmlChar *data, int len); +XML_DEPRECATED XMLPUBFUN int xmlValidatePopElement (xmlValidCtxtPtr ctxt, xmlDocPtr doc, diff --git a/libs/xml2/include/libxml/xinclude.h b/libs/xml2/include/libxml/xinclude.h index e1d135b3bae..71fa4c20dc2 100644 --- a/libs/xml2/include/libxml/xinclude.h +++ b/libs/xml2/include/libxml/xinclude.h @@ -14,6 +14,7 @@ #define __XML_XINCLUDE_H__
#include <libxml/xmlversion.h> +#include <libxml/xmlerror.h> #include <libxml/tree.h>
#ifdef LIBXML_XINCLUDE_ENABLED @@ -115,6 +116,12 @@ XMLPUBFUN xmlXIncludeCtxtPtr XMLPUBFUN int xmlXIncludeSetFlags (xmlXIncludeCtxtPtr ctxt, int flags); +XMLPUBFUN void + xmlXIncludeSetErrorHandler(xmlXIncludeCtxtPtr ctxt, + xmlStructuredErrorFunc handler, + void *data); +XMLPUBFUN int + xmlXIncludeGetLastError (xmlXIncludeCtxtPtr ctxt); XMLPUBFUN void xmlXIncludeFreeContext (xmlXIncludeCtxtPtr ctxt); XMLPUBFUN int diff --git a/libs/xml2/include/libxml/xmlIO.h b/libs/xml2/include/libxml/xmlIO.h index 2487be3be0d..5a35dc64b30 100644 --- a/libs/xml2/include/libxml/xmlIO.h +++ b/libs/xml2/include/libxml/xmlIO.h @@ -10,12 +10,14 @@ #ifndef __XML_IO_H__ #define __XML_IO_H__
+/** DOC_DISABLE */ #include <stdio.h> #include <libxml/xmlversion.h> #include <libxml/encoding.h> #define XML_TREE_INTERNALS #include <libxml/tree.h> #undef XML_TREE_INTERNALS +/** DOC_ENABLE */
#ifdef __cplusplus extern "C" { @@ -323,12 +325,14 @@ xmlOutputBufferPtr
#ifdef LIBXML_HTTP_ENABLED /* This function only exists if HTTP support built into the library */ +XML_DEPRECATED XMLPUBFUN void xmlRegisterHTTPPostCallbacks (void ); #endif /* LIBXML_HTTP_ENABLED */
#endif /* LIBXML_OUTPUT_ENABLED */
+XML_DEPRECATED XMLPUBFUN xmlParserInputPtr xmlCheckHTTPInput (xmlParserCtxtPtr ctxt, xmlParserInputPtr ret); @@ -341,26 +345,28 @@ XMLPUBFUN xmlParserInputPtr const char *ID, xmlParserCtxtPtr ctxt);
-/* - * xmlNormalizeWindowsPath is obsolete, don't use it. - * Check xmlCanonicPath in uri.h for a better alternative. - */ +XML_DEPRECATED XMLPUBFUN xmlChar * xmlNormalizeWindowsPath (const xmlChar *path);
+XML_DEPRECATED XMLPUBFUN int xmlCheckFilename (const char *path); /** * Default 'file://' protocol callbacks */ +XML_DEPRECATED XMLPUBFUN int xmlFileMatch (const char *filename); +XML_DEPRECATED XMLPUBFUN void * xmlFileOpen (const char *filename); +XML_DEPRECATED XMLPUBFUN int xmlFileRead (void * context, char * buffer, int len); +XML_DEPRECATED XMLPUBFUN int xmlFileClose (void * context);
@@ -368,19 +374,24 @@ XMLPUBFUN int * Default 'http://' protocol callbacks */ #ifdef LIBXML_HTTP_ENABLED +XML_DEPRECATED XMLPUBFUN int xmlIOHTTPMatch (const char *filename); +XML_DEPRECATED XMLPUBFUN void * xmlIOHTTPOpen (const char *filename); #ifdef LIBXML_OUTPUT_ENABLED +XML_DEPRECATED XMLPUBFUN void * xmlIOHTTPOpenW (const char * post_uri, int compression ); #endif /* LIBXML_OUTPUT_ENABLED */ +XML_DEPRECATED XMLPUBFUN int xmlIOHTTPRead (void * context, char * buffer, int len); +XML_DEPRECATED XMLPUBFUN int xmlIOHTTPClose (void * context); #endif /* LIBXML_HTTP_ENABLED */ @@ -389,14 +400,18 @@ XMLPUBFUN int * Default 'ftp://' protocol callbacks */ #if defined(LIBXML_FTP_ENABLED) +XML_DEPRECATED XMLPUBFUN int xmlIOFTPMatch (const char *filename); +XML_DEPRECATED XMLPUBFUN void * xmlIOFTPOpen (const char *filename); +XML_DEPRECATED XMLPUBFUN int xmlIOFTPRead (void * context, char * buffer, int len); +XML_DEPRECATED XMLPUBFUN int xmlIOFTPClose (void * context); #endif /* defined(LIBXML_FTP_ENABLED) */ @@ -407,9 +422,11 @@ XMLPUBFUN xmlParserInputBufferCreateFilenameFunc XMLPUBFUN xmlOutputBufferCreateFilenameFunc xmlOutputBufferCreateFilenameDefault( xmlOutputBufferCreateFilenameFunc func); +XML_DEPRECATED XMLPUBFUN xmlOutputBufferCreateFilenameFunc xmlThrDefOutputBufferCreateFilenameDefault( xmlOutputBufferCreateFilenameFunc func); +XML_DEPRECATED XMLPUBFUN xmlParserInputBufferCreateFilenameFunc xmlThrDefParserInputBufferCreateFilenameDefault( xmlParserInputBufferCreateFilenameFunc func); diff --git a/libs/xml2/include/libxml/xmlerror.h b/libs/xml2/include/libxml/xmlerror.h index 1f0ab4a3a2f..36381bec51e 100644 --- a/libs/xml2/include/libxml/xmlerror.h +++ b/libs/xml2/include/libxml/xmlerror.h @@ -211,6 +211,11 @@ typedef enum { XML_ERR_USER_STOP, /* 111 */ XML_ERR_COMMENT_ABRUPTLY_ENDED, /* 112 */ XML_WAR_ENCODING_MISMATCH, /* 113 */ + XML_ERR_RESOURCE_LIMIT, /* 114 */ + XML_ERR_ARGUMENT, /* 115 */ + XML_ERR_SYSTEM, /* 116 */ + XML_ERR_REDECL_PREDEF_ENTITY, /* 117 */ + XML_ERR_INT_SUBSET_NOT_FINISHED, /* 118 */ XML_NS_ERR_XML_NAMESPACE = 200, XML_NS_ERR_UNDEFINED_NAMESPACE, /* 201 */ XML_NS_ERR_QNAME, /* 202 */ @@ -473,6 +478,7 @@ typedef enum { XML_IO_EADDRINUSE, /* 1554 */ XML_IO_EALREADY, /* 1555 */ XML_IO_EAFNOSUPPORT, /* 1556 */ + XML_IO_UNSUPPORTED_PROTOCOL, /* 1557 */ XML_XINCLUDE_RECURSION=1600, XML_XINCLUDE_PARSE_VALUE, /* 1601 */ XML_XINCLUDE_ENTITY_DEF_MISMATCH, /* 1602 */ @@ -886,6 +892,7 @@ XML_GLOBALS_ERROR XMLPUBFUN void xmlSetGenericErrorFunc (void *ctx, xmlGenericErrorFunc handler); +XML_DEPRECATED XMLPUBFUN void xmlThrDefSetGenericErrorFunc(void *ctx, xmlGenericErrorFunc handler); @@ -896,6 +903,7 @@ XMLPUBFUN void XMLPUBFUN void xmlSetStructuredErrorFunc (void *ctx, xmlStructuredErrorFunc handler); +XML_DEPRECATED XMLPUBFUN void xmlThrDefSetStructuredErrorFunc(void *ctx, xmlStructuredErrorFunc handler); @@ -919,11 +927,17 @@ XMLPUBFUN void xmlParserValidityWarning (void *ctx, const char *msg, ...) LIBXML_ATTR_FORMAT(2,3); +/** DOC_DISABLE */ struct _xmlParserInput; +/** DOC_ENABLE */ XMLPUBFUN void xmlParserPrintFileInfo (struct _xmlParserInput *input); XMLPUBFUN void xmlParserPrintFileContext (struct _xmlParserInput *input); +XMLPUBFUN void +xmlFormatError (const xmlError *err, + xmlGenericErrorFunc channel, + void *data);
/* * Extended error information routines diff --git a/libs/xml2/include/libxml/xmlexports.h b/libs/xml2/include/libxml/xmlexports.h index bb04c742eec..71e87a222b9 100644 --- a/libs/xml2/include/libxml/xmlexports.h +++ b/libs/xml2/include/libxml/xmlexports.h @@ -9,6 +9,11 @@ #define __XML_EXPORTS_H__
/** DOC_DISABLE */ + +/* + * Symbol visibility + */ + #if defined(_WIN32) || defined(__CYGWIN__) #ifdef LIBXML_STATIC #define XMLPUBLIC @@ -20,29 +25,120 @@ #else /* not Windows */ #define XMLPUBLIC #endif /* platform switch */ -/** DOC_ENABLE */
-/* - * XMLPUBFUN: - * - * Macro which declares an exportable function - */ #define XMLPUBFUN XMLPUBLIC
-/** - * XMLPUBVAR: - * - * Macro which declares an exportable variable - */ #define XMLPUBVAR XMLPUBLIC extern
-/** DOC_DISABLE */ /* Compatibility */ #define XMLCALL #define XMLCDECL -#if !defined(LIBXML_DLL_IMPORT) -#define LIBXML_DLL_IMPORT XMLPUBVAR +#ifndef LIBXML_DLL_IMPORT + #define LIBXML_DLL_IMPORT XMLPUBVAR +#endif + +/* + * Attributes + */ + +#ifndef ATTRIBUTE_UNUSED + #if __GNUC__ * 100 + __GNUC_MINOR__ >= 207 || defined(__clang__) + #define ATTRIBUTE_UNUSED __attribute__((unused)) + #else + #define ATTRIBUTE_UNUSED + #endif +#endif + +#if !defined(__clang__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403) + #define LIBXML_ATTR_ALLOC_SIZE(x) __attribute__((alloc_size(x))) +#else + #define LIBXML_ATTR_ALLOC_SIZE(x) +#endif + +#if __GNUC__ * 100 + __GNUC_MINOR__ >= 303 + #define LIBXML_ATTR_FORMAT(fmt,args) \ + __attribute__((__format__(__printf__,fmt,args))) +#else + #define LIBXML_ATTR_FORMAT(fmt,args) +#endif + +#ifndef XML_DEPRECATED + #if defined(IN_LIBXML) + #define XML_DEPRECATED + #elif __GNUC__ * 100 + __GNUC_MINOR__ >= 301 + #define XML_DEPRECATED __attribute__((deprecated)) + #elif defined(_MSC_VER) && _MSC_VER >= 1400 + /* Available since Visual Studio 2005 */ + #define XML_DEPRECATED __declspec(deprecated) + #else + #define XML_DEPRECATED + #endif +#endif + +/* + * Warnings pragmas, should be moved from public headers + */ + +#if defined(__LCC__) + + #define XML_IGNORE_FPTR_CAST_WARNINGS + #define XML_POP_WARNINGS \ + _Pragma("diag_default 1215") + +#elif defined(__clang__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 406) + + #if defined(__clang__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 800) + #define XML_IGNORE_FPTR_CAST_WARNINGS \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored "-Wpedantic"") \ + _Pragma("GCC diagnostic ignored "-Wcast-function-type"") + #else + #define XML_IGNORE_FPTR_CAST_WARNINGS \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored "-Wpedantic"") + #endif + #define XML_POP_WARNINGS \ + _Pragma("GCC diagnostic pop") + +#elif defined(_MSC_VER) && _MSC_VER >= 1400 + + #define XML_IGNORE_FPTR_CAST_WARNINGS __pragma(warning(push)) + #define XML_POP_WARNINGS __pragma(warning(pop)) + +#else + + #define XML_IGNORE_FPTR_CAST_WARNINGS + #define XML_POP_WARNINGS + +#endif + +/* + * Accessors for globals + */ + +#define XML_NO_ATTR + +#ifdef LIBXML_THREAD_ENABLED + #define XML_DECLARE_GLOBAL(name, type, attrs) \ + attrs XMLPUBFUN type *__##name(void); + #define XML_GLOBAL_MACRO(name) (*__##name()) +#else + #define XML_DECLARE_GLOBAL(name, type, attrs) \ + attrs XMLPUBVAR type name; +#endif + +/* + * Originally declared in xmlversion.h which is generated + */ + +#ifdef __cplusplus +extern "C" { +#endif + +XMLPUBFUN void xmlCheckVersion(int version); + +#ifdef __cplusplus +} #endif -/** DOC_ENABLE */
#endif /* __XML_EXPORTS_H__ */ diff --git a/libs/xml2/include/libxml/xmlmemory.h b/libs/xml2/include/libxml/xmlmemory.h index dac3b804f45..51d7d3a9167 100644 --- a/libs/xml2/include/libxml/xmlmemory.h +++ b/libs/xml2/include/libxml/xmlmemory.h @@ -147,12 +147,16 @@ XMLPUBFUN int xmlMemUsed (void); XMLPUBFUN int xmlMemBlocks (void); +XML_DEPRECATED XMLPUBFUN void xmlMemDisplay (FILE *fp); +XML_DEPRECATED XMLPUBFUN void xmlMemDisplayLast(FILE *fp, long nbBytes); +XML_DEPRECATED XMLPUBFUN void xmlMemShow (FILE *fp, int nr); +XML_DEPRECATED XMLPUBFUN void xmlMemoryDump (void); XMLPUBFUN void * @@ -163,60 +167,19 @@ XMLPUBFUN void xmlMemFree (void *ptr); XMLPUBFUN char * xmlMemoryStrdup (const char *str); +XML_DEPRECATED XMLPUBFUN void * xmlMallocLoc (size_t size, const char *file, int line) LIBXML_ATTR_ALLOC_SIZE(1); +XML_DEPRECATED XMLPUBFUN void * xmlReallocLoc (void *ptr, size_t size, const char *file, int line); +XML_DEPRECATED XMLPUBFUN void * xmlMallocAtomicLoc (size_t size, const char *file, int line) LIBXML_ATTR_ALLOC_SIZE(1); +XML_DEPRECATED XMLPUBFUN char * xmlMemStrdupLoc (const char *str, const char *file, int line);
- -/** DOC_DISABLE */ -#ifdef DEBUG_MEMORY_LOCATION -/** - * xmlMalloc: - * @size: number of bytes to allocate - * - * Wrapper for the malloc() function used in the XML library. - * - * Returns the pointer to the allocated area or NULL in case of error. - */ -#define xmlMalloc(size) xmlMallocLoc((size), __FILE__, __LINE__) -/** - * xmlMallocAtomic: - * @size: number of bytes to allocate - * - * Wrapper for the malloc() function used in the XML library for allocation - * of block not containing pointers to other areas. - * - * Returns the pointer to the allocated area or NULL in case of error. - */ -#define xmlMallocAtomic(size) xmlMallocAtomicLoc((size), __FILE__, __LINE__) -/** - * xmlRealloc: - * @ptr: pointer to the existing allocated area - * @size: number of bytes to allocate - * - * Wrapper for the realloc() function used in the XML library. - * - * Returns the pointer to the allocated area or NULL in case of error. - */ -#define xmlRealloc(ptr, size) xmlReallocLoc((ptr), (size), __FILE__, __LINE__) -/** - * xmlMemStrdup: - * @str: pointer to the existing string - * - * Wrapper for the strdup() function, xmlStrdup() is usually preferred. - * - * Returns the pointer to the allocated area or NULL in case of error. - */ -#define xmlMemStrdup(str) xmlMemStrdupLoc((str), __FILE__, __LINE__) - -#endif /* DEBUG_MEMORY_LOCATION */ -/** DOC_ENABLE */ - #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/libs/xml2/include/libxml/xmlreader.h b/libs/xml2/include/libxml/xmlreader.h index 514f74e6572..573f452c612 100644 --- a/libs/xml2/include/libxml/xmlreader.h +++ b/libs/xml2/include/libxml/xmlreader.h @@ -127,6 +127,8 @@ XMLPUBFUN int XMLPUBFUN void xmlTextReaderSetMaxAmplification(xmlTextReaderPtr reader, unsigned maxAmpl); +XMLPUBFUN const xmlError * + xmlTextReaderGetLastError(xmlTextReaderPtr reader);
/* * Iterators diff --git a/libs/xml2/include/libxml/xmlsave.h b/libs/xml2/include/libxml/xmlsave.h index ec2ba53c653..3195aa75531 100644 --- a/libs/xml2/include/libxml/xmlsave.h +++ b/libs/xml2/include/libxml/xmlsave.h @@ -73,6 +73,8 @@ XMLPUBFUN int xmlSaveFlush (xmlSaveCtxtPtr ctxt); XMLPUBFUN int xmlSaveClose (xmlSaveCtxtPtr ctxt); +XMLPUBFUN int + xmlSaveFinish (xmlSaveCtxtPtr ctxt); XMLPUBFUN int xmlSaveSetEscape (xmlSaveCtxtPtr ctxt, xmlCharEncodingOutputFunc escape); @@ -80,10 +82,13 @@ XMLPUBFUN int xmlSaveSetAttrEscape (xmlSaveCtxtPtr ctxt, xmlCharEncodingOutputFunc escape);
+XML_DEPRECATED XMLPUBFUN int xmlThrDefIndentTreeOutput(int v); +/* XML_DEPRECATED - at 2.13, replacement added at v2.14 */ XMLPUBFUN const char * xmlThrDefTreeIndentString(const char * v); +XML_DEPRECATED XMLPUBFUN int xmlThrDefSaveNoEmptyTags(int v);
diff --git a/libs/xml2/include/libxml/xmlunicode.h b/libs/xml2/include/libxml/xmlunicode.h index 2e50a49f9b2..b6d795b267d 100644 --- a/libs/xml2/include/libxml/xmlunicode.h +++ b/libs/xml2/include/libxml/xmlunicode.h @@ -7,7 +7,7 @@ * http://www.unicode.org/Public/4.0-Update1/UCD-4.0.1.html * using the genUnicode.py Python script. * - * Generation date: Mon Mar 27 11:09:52 2006 + * Generation date: Tue Apr 30 17:30:38 2024 * Sources: Blocks-4.0.1.txt UnicodeData-4.0.1.txt * Author: Daniel Veillard */ @@ -23,172 +23,336 @@ extern "C" { #endif
+XML_DEPRECATED XMLPUBFUN int xmlUCSIsAegeanNumbers (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsAlphabeticPresentationForms (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsArabic (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsArabicPresentationFormsA (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsArabicPresentationFormsB (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsArmenian (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsArrows (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsBasicLatin (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsBengali (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsBlockElements (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsBopomofo (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsBopomofoExtended (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsBoxDrawing (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsBraillePatterns (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsBuhid (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsByzantineMusicalSymbols (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCJKCompatibility (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCJKCompatibilityForms (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCJKCompatibilityIdeographs (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCJKCompatibilityIdeographsSupplement (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCJKRadicalsSupplement (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCJKSymbolsandPunctuation (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCJKUnifiedIdeographs (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCJKUnifiedIdeographsExtensionA (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCJKUnifiedIdeographsExtensionB (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCherokee (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCombiningDiacriticalMarks (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCombiningDiacriticalMarksforSymbols (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCombiningHalfMarks (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCombiningMarksforSymbols (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsControlPictures (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCurrencySymbols (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCypriotSyllabary (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCyrillic (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCyrillicSupplement (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsDeseret (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsDevanagari (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsDingbats (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsEnclosedAlphanumerics (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsEnclosedCJKLettersandMonths (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsEthiopic (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsGeneralPunctuation (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsGeometricShapes (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsGeorgian (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsGothic (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsGreek (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsGreekExtended (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsGreekandCoptic (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsGujarati (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsGurmukhi (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsHalfwidthandFullwidthForms (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsHangulCompatibilityJamo (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsHangulJamo (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsHangulSyllables (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsHanunoo (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsHebrew (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsHighPrivateUseSurrogates (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsHighSurrogates (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsHiragana (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsIPAExtensions (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsIdeographicDescriptionCharacters (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsKanbun (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsKangxiRadicals (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsKannada (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsKatakana (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsKatakanaPhoneticExtensions (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsKhmer (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsKhmerSymbols (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsLao (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsLatin1Supplement (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsLatinExtendedA (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsLatinExtendedB (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsLatinExtendedAdditional (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsLetterlikeSymbols (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsLimbu (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsLinearBIdeograms (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsLinearBSyllabary (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsLowSurrogates (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsMalayalam (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsMathematicalAlphanumericSymbols (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsMathematicalOperators (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsMiscellaneousMathematicalSymbolsA (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsMiscellaneousMathematicalSymbolsB (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsMiscellaneousSymbols (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsMiscellaneousSymbolsandArrows (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsMiscellaneousTechnical (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsMongolian (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsMusicalSymbols (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsMyanmar (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsNumberForms (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsOgham (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsOldItalic (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsOpticalCharacterRecognition (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsOriya (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsOsmanya (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsPhoneticExtensions (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsPrivateUse (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsPrivateUseArea (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsRunic (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsShavian (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsSinhala (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsSmallFormVariants (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsSpacingModifierLetters (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsSpecials (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsSuperscriptsandSubscripts (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsSupplementalArrowsA (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsSupplementalArrowsB (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsSupplementalMathematicalOperators (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsSupplementaryPrivateUseAreaA (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsSupplementaryPrivateUseAreaB (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsSyriac (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsTagalog (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsTagbanwa (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsTags (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsTaiLe (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsTaiXuanJingSymbols (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsTamil (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsTelugu (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsThaana (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsThai (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsTibetan (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsUgaritic (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsUnifiedCanadianAboriginalSyllabics (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsVariationSelectors (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsVariationSelectorsSupplement (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsYiRadicals (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsYiSyllables (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsYijingHexagramSymbols (int code);
XMLPUBFUN int xmlUCSIsBlock (int code, const char *block);
+XML_DEPRECATED XMLPUBFUN int xmlUCSIsCatC (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCatCc (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCatCf (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCatCo (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCatCs (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCatL (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCatLl (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCatLm (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCatLo (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCatLt (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCatLu (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCatM (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCatMc (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCatMe (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCatMn (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCatN (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCatNd (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCatNl (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCatNo (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCatP (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCatPc (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCatPd (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCatPe (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCatPf (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCatPi (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCatPo (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCatPs (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCatS (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCatSc (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCatSk (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCatSm (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCatSo (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCatZ (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCatZl (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCatZp (int code); +XML_DEPRECATED XMLPUBFUN int xmlUCSIsCatZs (int code);
XMLPUBFUN int xmlUCSIsCat (int code, const char *cat); diff --git a/libs/xml2/include/libxml/xmlversion.h b/libs/xml2/include/libxml/xmlversion.h index 74e77b376f7..69b9fee19ce 100644 --- a/libs/xml2/include/libxml/xmlversion.h +++ b/libs/xml2/include/libxml/xmlversion.h @@ -10,40 +10,26 @@ #ifndef __XML_VERSION_H__ #define __XML_VERSION_H__
-#include <libxml/xmlexports.h> - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * use those to be sure nothing nasty will happen if - * your library and includes mismatch - */ -#ifndef LIBXML2_COMPILING_MSCCDEF -XMLPUBFUN void xmlCheckVersion(int version); -#endif /* LIBXML2_COMPILING_MSCCDEF */ - /** * LIBXML_DOTTED_VERSION: * * the version string like "1.2.3" */ -#define LIBXML_DOTTED_VERSION "2.12.10" +#define LIBXML_DOTTED_VERSION "2.13.8"
/** * LIBXML_VERSION: * * the version number: 1.2.3 value is 10203 */ -#define LIBXML_VERSION 21210 +#define LIBXML_VERSION 21308
/** * LIBXML_VERSION_STRING: * * the version number string, 1.2.3 value is "10203" */ -#define LIBXML_VERSION_STRING "21210" +#define LIBXML_VERSION_STRING "21308"
/** * LIBXML_VERSION_EXTRA: @@ -58,32 +44,7 @@ XMLPUBFUN void xmlCheckVersion(int version); * Macro to check that the libxml version in use is compatible with * the version the software has been compiled against */ -#define LIBXML_TEST_VERSION xmlCheckVersion(21210); - -#ifndef VMS -#if 0 -/** - * WITH_TRIO: - * - * defined if the trio support need to be configured in - */ -#define WITH_TRIO -#else -/** - * WITHOUT_TRIO: - * - * defined if the trio support should not be configured in - */ -#define WITHOUT_TRIO -#endif -#else /* VMS */ -/** - * WITH_TRIO: - * - * defined if the trio support need to be configured in - */ -#define WITH_TRIO 1 -#endif /* VMS */ +#define LIBXML_TEST_VERSION xmlCheckVersion(21308);
/** * LIBXML_THREAD_ENABLED: @@ -301,24 +262,6 @@ XMLPUBFUN void xmlCheckVersion(int version); #define LIBXML_DEBUG_ENABLED #endif
-/** - * DEBUG_MEMORY_LOCATION: - * - * Whether the memory debugging is configured in - */ -#if 0 -#define DEBUG_MEMORY_LOCATION -#endif - -/** - * LIBXML_DEBUG_RUNTIME: - * - * Removed - */ -#if 0 -#define LIBXML_DEBUG_RUNTIME -#endif - /** * LIBXML_UNICODE_ENABLED: * @@ -346,17 +289,6 @@ XMLPUBFUN void xmlCheckVersion(int version); #define LIBXML_AUTOMATA_ENABLED #endif
-/** - * LIBXML_EXPR_ENABLED: - * - * Whether the formal expressions interfaces are compiled in - * - * This code is unused and disabled unconditionally for now. - */ -#if 0 -#define LIBXML_EXPR_ENABLED -#endif - /** * LIBXML_SCHEMAS_ENABLED: * @@ -408,102 +340,6 @@ XMLPUBFUN void xmlCheckVersion(int version); #define LIBXML_LZMA_ENABLED #endif
-#ifdef __GNUC__ -/** DOC_DISABLE */ - -#ifndef ATTRIBUTE_UNUSED -# if ((__GNUC__ > 2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 7))) -# define ATTRIBUTE_UNUSED __attribute__((unused)) -# else -# define ATTRIBUTE_UNUSED -# endif -#endif - -#ifndef LIBXML_ATTR_ALLOC_SIZE -# if (!defined(__clang__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)))) -# define LIBXML_ATTR_ALLOC_SIZE(x) __attribute__((alloc_size(x))) -# else -# define LIBXML_ATTR_ALLOC_SIZE(x) -# endif -#else -# define LIBXML_ATTR_ALLOC_SIZE(x) -#endif - -#ifndef LIBXML_ATTR_FORMAT -# if ((__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3))) -# define LIBXML_ATTR_FORMAT(fmt,args) __attribute__((__format__(__printf__,fmt,args))) -# else -# define LIBXML_ATTR_FORMAT(fmt,args) -# endif -#else -# define LIBXML_ATTR_FORMAT(fmt,args) -#endif - -#ifndef XML_DEPRECATED -# if defined (IN_LIBXML) || (__GNUC__ * 100 + __GNUC_MINOR__ < 301) -# define XML_DEPRECATED -/* Available since at least GCC 3.1 */ -# else -# define XML_DEPRECATED __attribute__((deprecated)) -# endif -#endif - -#if defined(__clang__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 406) - #if defined(__clang__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 800) - #define XML_IGNORE_FPTR_CAST_WARNINGS \ - _Pragma("GCC diagnostic push") \ - _Pragma("GCC diagnostic ignored "-Wpedantic"") \ - _Pragma("GCC diagnostic ignored "-Wcast-function-type"") - #else - #define XML_IGNORE_FPTR_CAST_WARNINGS \ - _Pragma("GCC diagnostic push") \ - _Pragma("GCC diagnostic ignored "-Wpedantic"") - #endif - #define XML_POP_WARNINGS \ - _Pragma("GCC diagnostic pop") -#else - #define XML_IGNORE_FPTR_CAST_WARNINGS - #define XML_POP_WARNINGS -#endif - -#else /* ! __GNUC__ */ -#define ATTRIBUTE_UNUSED -#define LIBXML_ATTR_ALLOC_SIZE(x) -#define LIBXML_ATTR_FORMAT(fmt,args) -#ifndef XML_DEPRECATED -# if defined (IN_LIBXML) || !defined (_MSC_VER) -# define XML_DEPRECATED -/* Available since Visual Studio 2005 */ -# elif defined (_MSC_VER) && (_MSC_VER >= 1400) -# define XML_DEPRECATED __declspec(deprecated) -# endif -#endif -#if defined (_MSC_VER) && (_MSC_VER >= 1400) -# define XML_IGNORE_FPTR_CAST_WARNINGS __pragma(warning(push)) -#else -# define XML_IGNORE_FPTR_CAST_WARNINGS -#endif -#ifndef XML_POP_WARNINGS -# if defined (_MSC_VER) && (_MSC_VER >= 1400) -# define XML_POP_WARNINGS __pragma(warning(pop)) -# else -# define XML_POP_WARNINGS -# endif -#endif -#endif /* __GNUC__ */ - -#define XML_NO_ATTR - -#ifdef LIBXML_THREAD_ENABLED - #define XML_DECLARE_GLOBAL(name, type, attrs) \ - attrs XMLPUBFUN type *__##name(void); - #define XML_GLOBAL_MACRO(name) (*__##name()) -#else - #define XML_DECLARE_GLOBAL(name, type, attrs) \ - attrs XMLPUBVAR type name; -#endif - -#ifdef __cplusplus -} -#endif /* __cplusplus */ +#include <libxml/xmlexports.h> + #endif diff --git a/libs/xml2/include/libxml/xpath.h b/libs/xml2/include/libxml/xpath.h index 6dae0780d83..b89e105c08f 100644 --- a/libs/xml2/include/libxml/xpath.h +++ b/libs/xml2/include/libxml/xpath.h @@ -515,6 +515,10 @@ XMLPUBFUN xmlXPathContextPtr xmlXPathNewContext (xmlDocPtr doc); XMLPUBFUN void xmlXPathFreeContext (xmlXPathContextPtr ctxt); +XMLPUBFUN void + xmlXPathSetErrorHandler(xmlXPathContextPtr ctxt, + xmlStructuredErrorFunc handler, + void *context); XMLPUBFUN int xmlXPathContextSetCache(xmlXPathContextPtr ctxt, int active, diff --git a/libs/xml2/include/private/buf.h b/libs/xml2/include/private/buf.h index 6fef4ce05dd..982b9eea00b 100644 --- a/libs/xml2/include/private/buf.h +++ b/libs/xml2/include/private/buf.h @@ -28,10 +28,6 @@ XML_HIDDEN int xmlBufAdd(xmlBufPtr buf, const xmlChar *str, int len); XML_HIDDEN int xmlBufCat(xmlBufPtr buf, const xmlChar *str); -XML_HIDDEN int -xmlBufCCat(xmlBufPtr buf, const char *str); -XML_HIDDEN int -xmlBufWriteQuotedString(xmlBufPtr buf, const xmlChar *string);
XML_HIDDEN size_t xmlBufAvail(const xmlBufPtr buf); @@ -56,8 +52,6 @@ XML_HIDDEN xmlBufPtr xmlBufFromBuffer(xmlBufferPtr buffer); XML_HIDDEN xmlBufferPtr xmlBufBackToBuffer(xmlBufPtr buf); -XML_HIDDEN int -xmlBufMergeBuffer(xmlBufPtr buf, xmlBufferPtr buffer);
XML_HIDDEN int xmlBufResetInput(xmlBufPtr buf, xmlParserInputPtr input); diff --git a/libs/xml2/include/private/dict.h b/libs/xml2/include/private/dict.h index 9b0be621adc..826ac54a51f 100644 --- a/libs/xml2/include/private/dict.h +++ b/libs/xml2/include/private/dict.h @@ -67,6 +67,8 @@ xmlInitRandom(void); XML_HIDDEN void xmlCleanupRandom(void); XML_HIDDEN unsigned +xmlGlobalRandom(void); +XML_HIDDEN unsigned xmlRandom(void);
#endif /* XML_DICT_H_PRIVATE__ */ diff --git a/libs/xml2/include/private/entities.h b/libs/xml2/include/private/entities.h index c3f15e6812d..d262ef47f65 100644 --- a/libs/xml2/include/private/entities.h +++ b/libs/xml2/include/private/entities.h @@ -9,13 +9,17 @@ * * XML_ENT_PARSED: The entity was parsed and `children` points to the * content. - * XML_ENT_CHECKED: The entity was checked for loops. + * + * XML_ENT_CHECKED: The entity was checked for loops and amplification. + * expandedSize was set. + * + * XML_ENT_VALIDATED: The entity contains a valid attribute value. + * Only used when entities aren't substituted. */ -#define XML_ENT_PARSED (1<<0) -#define XML_ENT_CHECKED (1<<1) -#define XML_ENT_EXPANDING (1<<2) -#define XML_ENT_CHECKED_LT (1<<3) -#define XML_ENT_CONTAINS_LT (1<<4) +#define XML_ENT_PARSED (1u << 0) +#define XML_ENT_CHECKED (1u << 1) +#define XML_ENT_VALIDATED (1u << 2) +#define XML_ENT_EXPANDING (1u << 3)
XML_HIDDEN xmlChar * xmlEncodeAttributeEntities(xmlDocPtr doc, const xmlChar *input); diff --git a/libs/xml2/include/private/error.h b/libs/xml2/include/private/error.h index 165b782b136..506405a1f06 100644 --- a/libs/xml2/include/private/error.h +++ b/libs/xml2/include/private/error.h @@ -4,20 +4,31 @@ #include <libxml/xmlerror.h> #include <libxml/xmlversion.h>
+#define MAX_ERR_MSG_SIZE 64000 + struct _xmlNode;
XML_HIDDEN void -__xmlRaiseError(xmlStructuredErrorFunc schannel, - xmlGenericErrorFunc channel, void *data, void *ctx, - void *nod, int domain, int code, xmlErrorLevel level, +xmlRaiseMemoryError(xmlStructuredErrorFunc schannel, xmlGenericErrorFunc channel, + void *data, int domain, xmlError *error); +XML_HIDDEN int +xmlVRaiseError(xmlStructuredErrorFunc schannel, xmlGenericErrorFunc channel, + void *data, void *ctx, struct _xmlNode *node, + int domain, int code, xmlErrorLevel level, + const char *file, int line, const char *str1, + const char *str2, const char *str3, int int1, int col, + const char *msg, va_list ap); +XML_HIDDEN int +__xmlRaiseError(xmlStructuredErrorFunc schannel, xmlGenericErrorFunc channel, + void *data, void *ctx, struct _xmlNode *node, + int domain, int code, xmlErrorLevel level, const char *file, int line, const char *str1, const char *str2, const char *str3, int int1, int col, const char *msg, ...) LIBXML_ATTR_FORMAT(16,17); XML_HIDDEN void -__xmlSimpleError(int domain, int code, struct _xmlNode *node, - const char *msg, const char *extra) LIBXML_ATTR_FORMAT(4,0); -XML_HIDDEN void xmlGenericErrorDefaultFunc(void *ctx, const char *msg, ...) LIBXML_ATTR_FORMAT(2,3); +XML_HIDDEN const char * +xmlErrString(xmlParserErrors code);
#endif /* XML_ERROR_H_PRIVATE__ */ diff --git a/libs/xml2/include/private/globals.h b/libs/xml2/include/private/globals.h index 5f3f112207d..828b6d50fe7 100644 --- a/libs/xml2/include/private/globals.h +++ b/libs/xml2/include/private/globals.h @@ -6,4 +6,9 @@ xmlInitGlobalsInternal(void); XML_HIDDEN void xmlCleanupGlobalsInternal(void);
+#ifdef LIBXML_THREAD_ENABLED +XML_HIDDEN unsigned * +xmlGetLocalRngState(void); +#endif + #endif /* XML_GLOBALS_H_PRIVATE__ */ diff --git a/libs/xml2/include/private/io.h b/libs/xml2/include/private/io.h index 5f4b210a80e..d116fadaa59 100644 --- a/libs/xml2/include/private/io.h +++ b/libs/xml2/include/private/io.h @@ -6,17 +6,33 @@ #include <libxml/xmlversion.h>
XML_HIDDEN void +xmlInitIOCallbacks(void); + +XML_HIDDEN int __xmlIOErr(int domain, int code, const char *extra); -XML_HIDDEN void -__xmlLoaderErr(void *ctx, const char *msg, - const char *filename) LIBXML_ATTR_FORMAT(2,0);
-xmlParserInputBufferPtr -xmlParserInputBufferCreateString(const xmlChar *str); +XML_HIDDEN int +xmlNoNetExists(const char *filename); + +XML_HIDDEN int +xmlParserInputBufferCreateFilenameSafe(const char *URI, xmlCharEncoding enc, + xmlParserInputBufferPtr *out); + +XML_HIDDEN xmlParserInputBufferPtr +xmlNewInputBufferString(const char *str, int flags); +XML_HIDDEN xmlParserInputBufferPtr +xmlNewInputBufferMemory(const void *mem, size_t size, int flags, + xmlCharEncoding enc); + +XML_HIDDEN int +xmlInputFromFd(xmlParserInputBufferPtr buf, int fd, int unzip);
#ifdef LIBXML_OUTPUT_ENABLED XML_HIDDEN xmlOutputBufferPtr xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder); +XML_HIDDEN void +xmlOutputBufferWriteQuotedString(xmlOutputBufferPtr buf, + const xmlChar *string); #endif
#endif /* XML_IO_H_PRIVATE__ */ diff --git a/libs/xml2/include/private/parser.h b/libs/xml2/include/private/parser.h index 7f8f6912a98..4a8004207b3 100644 --- a/libs/xml2/include/private/parser.h +++ b/libs/xml2/include/private/parser.h @@ -25,18 +25,41 @@ #define XML_INPUT_AUTO_OTHER (4u << 1) #define XML_INPUT_USES_ENC_DECL (1u << 4) #define XML_INPUT_ENCODING_ERROR (1u << 5) +#define XML_INPUT_PROGRESSIVE (1u << 6)
+#define PARSER_STOPPED(ctxt) ((ctxt)->disableSAX > 1) + +#define PARSER_PROGRESSIVE(ctxt) \ + ((ctxt)->input->flags & XML_INPUT_PROGRESSIVE) + +#define PARSER_IN_PE(ctxt) \ + (((ctxt)->input->entity != NULL) && \ + (((ctxt)->input->entity->etype == XML_INTERNAL_PARAMETER_ENTITY) || \ + ((ctxt)->input->entity->etype == XML_EXTERNAL_PARAMETER_ENTITY))) + +#define PARSER_EXTERNAL(ctxt) \ + (((ctxt)->inSubset == 2) || \ + (((ctxt)->input->entity != NULL) && \ + ((ctxt)->input->entity->etype == XML_EXTERNAL_PARAMETER_ENTITY))) + +XML_HIDDEN void +xmlCtxtVErr(xmlParserCtxtPtr ctxt, xmlNodePtr node, xmlErrorDomain domain, + xmlParserErrors code, xmlErrorLevel level, + const xmlChar *str1, const xmlChar *str2, const xmlChar *str3, + int int1, const char *msg, va_list ap); XML_HIDDEN void -xmlErrMemory(xmlParserCtxtPtr ctxt, const char *extra); +xmlCtxtErr(xmlParserCtxtPtr ctxt, xmlNodePtr node, xmlErrorDomain domain, + xmlParserErrors code, xmlErrorLevel level, + const xmlChar *str1, const xmlChar *str2, const xmlChar *str3, + int int1, const char *msg, ...); XML_HIDDEN void xmlFatalErr(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *info); XML_HIDDEN void LIBXML_ATTR_FORMAT(3,0) xmlWarningMsg(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *msg, const xmlChar *str1, const xmlChar *str2); XML_HIDDEN void -__xmlErrEncoding(xmlParserCtxtPtr ctxt, xmlParserErrors xmlerr, - const char *msg, const xmlChar *str1, - const xmlChar *str2) LIBXML_ATTR_FORMAT(3,0); +xmlCtxtErrIO(xmlParserCtxtPtr ctxt, int code, const char *uri); + XML_HIDDEN void xmlHaltParser(xmlParserCtxtPtr ctxt); XML_HIDDEN int @@ -65,4 +88,38 @@ xmlParserNsUpdateSax(xmlParserCtxtPtr ctxt, const xmlChar *prefix, XML_HIDDEN void * xmlParserNsLookupSax(xmlParserCtxtPtr ctxt, const xmlChar *prefix);
+#define XML_INPUT_BUF_STATIC (1u << 1) +#define XML_INPUT_BUF_ZERO_TERMINATED (1u << 2) +#define XML_INPUT_UNZIP (1u << 3) + +/* Internal parser option */ +#define XML_PARSE_UNZIP (1 << 24) + +XML_HIDDEN xmlParserInputPtr +xmlNewInputURL(xmlParserCtxtPtr ctxt, const char *url, const char *publicId, + const char *encoding, int flags); +XML_HIDDEN xmlParserInputPtr +xmlNewInputMemory(xmlParserCtxtPtr ctxt, const char *url, + const void *mem, size_t size, + const char *encoding, int flags); +XML_HIDDEN xmlParserInputPtr +xmlNewInputString(xmlParserCtxtPtr ctxt, const char *url, const char *str, + const char *encoding, int flags); +XML_HIDDEN xmlParserInputPtr +xmlNewInputFd(xmlParserCtxtPtr ctxt, const char *filename, int fd, + const char *encoding, int flags); +XML_HIDDEN xmlParserInputPtr +xmlNewInputIO(xmlParserCtxtPtr ctxt, const char *url, + xmlInputReadCallback ioRead, + xmlInputCloseCallback ioClose, + void *ioCtxt, + const char *encoding, int flags); +XML_HIDDEN xmlParserInputPtr +xmlNewInputPush(xmlParserCtxtPtr ctxt, const char *url, + const char *chunk, int size, const char *encoding); + +XML_HIDDEN xmlChar * +xmlExpandEntitiesInAttValue(xmlParserCtxtPtr ctxt, const xmlChar *str, + int normalize); + #endif /* XML_PARSER_H_PRIVATE__ */ diff --git a/libs/xml2/include/private/regexp.h b/libs/xml2/include/private/regexp.h index f2024939e3c..b55c932bc0e 100644 --- a/libs/xml2/include/private/regexp.h +++ b/libs/xml2/include/private/regexp.h @@ -3,7 +3,21 @@
#include <libxml/xmlautomata.h>
+#ifdef LIBXML_REGEXP_ENABLED + +/* + * -2 and -3 are used by xmlValidateElementType for other things. + */ +#define XML_REGEXP_OK 0 +#define XML_REGEXP_NOT_FOUND (-1) +#define XML_REGEXP_INTERNAL_ERROR (-4) +#define XML_REGEXP_OUT_OF_MEMORY (-5) +#define XML_REGEXP_INTERNAL_LIMIT (-6) +#define XML_REGEXP_INVALID_UTF8 (-7) + XML_HIDDEN void xmlAutomataSetFlags(xmlAutomataPtr am, int flags);
+#endif /* LIBXML_REGEXP_ENABLED */ + #endif /* XML_REGEXP_H_PRIVATE__ */ diff --git a/libs/xml2/include/private/save.h b/libs/xml2/include/private/save.h index f09512e9d19..324f03047a3 100644 --- a/libs/xml2/include/private/save.h +++ b/libs/xml2/include/private/save.h @@ -2,13 +2,19 @@ #define XML_SAVE_H_PRIVATE__
#include <libxml/tree.h> +#include <libxml/xmlsave.h> #include <libxml/xmlversion.h>
#ifdef LIBXML_OUTPUT_ENABLED
+XML_HIDDEN int +xmlSaveNotationDecl(xmlSaveCtxtPtr ctxt, xmlNotationPtr cur); +XML_HIDDEN int +xmlSaveNotationTable(xmlSaveCtxtPtr ctxt, xmlNotationTablePtr cur); + XML_HIDDEN void -xmlBufAttrSerializeTxtContent(xmlBufPtr buf, xmlDocPtr doc, - xmlAttrPtr attr, const xmlChar * string); +xmlBufAttrSerializeTxtContent(xmlOutputBufferPtr buf, xmlDocPtr doc, + const xmlChar *string); XML_HIDDEN void xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur);
diff --git a/libs/xml2/include/private/string.h b/libs/xml2/include/private/string.h index 9665fc47238..34f4c96cb20 100644 --- a/libs/xml2/include/private/string.h +++ b/libs/xml2/include/private/string.h @@ -3,6 +3,10 @@
#include <libxml/xmlstring.h>
+XML_HIDDEN int +xmlStrVASPrintf(xmlChar **out, int maxSize, const char *msg, va_list ap); +XML_HIDDEN int +xmlStrASPrintf(xmlChar **out, int maxSize, const char *msg, ...); XML_HIDDEN xmlChar * xmlEscapeFormatString(xmlChar **msg);
diff --git a/libs/xml2/include/private/tree.h b/libs/xml2/include/private/tree.h index fb5e1623715..2d651d53f4b 100644 --- a/libs/xml2/include/private/tree.h +++ b/libs/xml2/include/private/tree.h @@ -9,10 +9,19 @@ XML_HIDDEN extern int __xmlRegisterCallbacks;
+XML_HIDDEN int +xmlSearchNsSafe(xmlNodePtr node, const xmlChar *href, xmlNsPtr *out); +XML_HIDDEN int +xmlSearchNsByHrefSafe(xmlNodePtr node, const xmlChar *href, xmlNsPtr *out); + +XML_HIDDEN int +xmlNodeParseContent(xmlNodePtr node, const xmlChar *content, int len); XML_HIDDEN xmlNodePtr xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent, int extended); XML_HIDDEN xmlNodePtr xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent); +XML_HIDDEN const xmlChar * +xmlSplitQName4(const xmlChar *name, xmlChar **prefixPtr);
#endif /* XML_TREE_H_PRIVATE__ */ diff --git a/libs/xml2/include/private/xpath.h b/libs/xml2/include/private/xpath.h index 0e8d752568e..72a69720332 100644 --- a/libs/xml2/include/private/xpath.h +++ b/libs/xml2/include/private/xpath.h @@ -1,7 +1,16 @@ #ifndef XML_XPATH_H_PRIVATE__ #define XML_XPATH_H_PRIVATE__
+#include <libxml/xpath.h> + XML_HIDDEN void xmlInitXPathInternal(void);
+#ifdef LIBXML_XPATH_ENABLED +XML_HIDDEN void +xmlXPathErrMemory(xmlXPathContextPtr ctxt); +XML_HIDDEN void +xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt); +#endif + #endif /* XML_XPATH_H_PRIVATE__ */ diff --git a/libs/xml2/include/win32config.h b/libs/xml2/include/win32config.h index 5d7fed2755e..a25e0385024 100644 --- a/libs/xml2/include/win32config.h +++ b/libs/xml2/include/win32config.h @@ -5,9 +5,6 @@ #define HAVE_STAT #define HAVE_FCNTL_H
-#include <io.h> -#include <direct.h> - #if defined(__MINGW32__) || (defined(_MSC_VER) && _MSC_VER >= 1600) #define HAVE_STDINT_H #endif diff --git a/libs/xml2/libxml.h b/libs/xml2/libxml.h index bc0149c41a5..67f3b56bacc 100644 --- a/libs/xml2/libxml.h +++ b/libs/xml2/libxml.h @@ -38,11 +38,6 @@ #define SYSCONFDIR "/etc" #endif
-#ifdef WITH_TRIO - #define TRIO_REPLACE_STDIO - #include "trio.h" -#endif - #if !defined(_WIN32) && \ !defined(__CYGWIN__) && \ (defined(__clang__) || \ @@ -53,7 +48,7 @@ #endif
#if defined(__clang__) || \ - (defined(__GNUC__) && (__GNUC__ >= 8)) + (defined(__GNUC__) && (__GNUC__ >= 8) && !defined(__EDG__)) #define ATTRIBUTE_NO_SANITIZE(arg) __attribute__((no_sanitize(arg))) #else #define ATTRIBUTE_NO_SANITIZE(arg) diff --git a/libs/xml2/list.c b/libs/xml2/list.c index 4927a263020..20df26c87c7 100644 --- a/libs/xml2/list.c +++ b/libs/xml2/list.c @@ -188,18 +188,13 @@ xmlListPtr xmlListCreate(xmlListDeallocator deallocator, xmlListDataCompare compare) { xmlListPtr l; - if (NULL == (l = (xmlListPtr )xmlMalloc( sizeof(xmlList)))) { - xmlGenericError(xmlGenericErrorContext, - "Cannot initialize memory for list"); + if (NULL == (l = (xmlListPtr )xmlMalloc( sizeof(xmlList)))) return (NULL); - } /* Initialize the list to NULL */ memset(l, 0, sizeof(xmlList));
/* Add the sentinel */ if (NULL ==(l->sentinel = (xmlLinkPtr )xmlMalloc(sizeof(xmlLink)))) { - xmlGenericError(xmlGenericErrorContext, - "Cannot initialize memory for sentinel"); xmlFree(l); return (NULL); } @@ -279,11 +274,8 @@ xmlListInsert(xmlListPtr l, void *data) lkPlace = xmlListLowerSearch(l, data); /* Add the new link */ lkNew = (xmlLinkPtr) xmlMalloc(sizeof(xmlLink)); - if (lkNew == NULL) { - xmlGenericError(xmlGenericErrorContext, - "Cannot initialize memory for new link"); + if (lkNew == NULL) return (1); - } lkNew->data = data; lkPlace = lkPlace->prev; lkNew->next = lkPlace->next; @@ -311,11 +303,8 @@ int xmlListAppend(xmlListPtr l, void *data) lkPlace = xmlListHigherSearch(l, data); /* Add the new link */ lkNew = (xmlLinkPtr) xmlMalloc(sizeof(xmlLink)); - if (lkNew == NULL) { - xmlGenericError(xmlGenericErrorContext, - "Cannot initialize memory for new link"); + if (lkNew == NULL) return (1); - } lkNew->data = data; lkNew->next = lkPlace->next; (lkPlace->next)->prev = lkNew; @@ -548,11 +537,8 @@ xmlListPushFront(xmlListPtr l, void *data) lkPlace = l->sentinel; /* Add the new link */ lkNew = (xmlLinkPtr) xmlMalloc(sizeof(xmlLink)); - if (lkNew == NULL) { - xmlGenericError(xmlGenericErrorContext, - "Cannot initialize memory for new link"); + if (lkNew == NULL) return (0); - } lkNew->data = data; lkNew->next = lkPlace->next; (lkPlace->next)->prev = lkNew; @@ -579,11 +565,8 @@ xmlListPushBack(xmlListPtr l, void *data) return(0); lkPlace = l->sentinel->prev; /* Add the new link */ - if (NULL ==(lkNew = (xmlLinkPtr )xmlMalloc(sizeof(xmlLink)))) { - xmlGenericError(xmlGenericErrorContext, - "Cannot initialize memory for new link"); + if (NULL ==(lkNew = (xmlLinkPtr )xmlMalloc(sizeof(xmlLink)))) return (0); - } lkNew->data = data; lkNew->next = lkPlace->next; (lkPlace->next)->prev = lkNew; @@ -729,7 +712,7 @@ xmlListMerge(xmlListPtr l1, xmlListPtr l2) * Returns a new copy of the list or NULL in case of error */ xmlListPtr -xmlListDup(const xmlListPtr old) +xmlListDup(xmlListPtr old) { xmlListPtr cur;
@@ -758,7 +741,7 @@ xmlListDup(const xmlListPtr old) * Returns 0 in case of success 1 in case of error */ int -xmlListCopy(xmlListPtr cur, const xmlListPtr old) +xmlListCopy(xmlListPtr cur, xmlListPtr old) { /* Walk the old tree and insert the data into the new one */ xmlLinkPtr lk; diff --git a/libs/xml2/parser.c b/libs/xml2/parser.c index 3e8a588f536..6941a22557f 100644 --- a/libs/xml2/parser.c +++ b/libs/xml2/parser.c @@ -79,6 +79,10 @@ #define URI_HASH_EMPTY 0xD943A04E #define URI_HASH_XML 0xF0451F02
+#ifndef STDIN_FILENO + #define STDIN_FILENO 0 +#endif + struct _xmlStartTag { const xmlChar *prefix; const xmlChar *URI; @@ -108,23 +112,25 @@ struct _xmlParserNsData {
unsigned elementId; int defaultNsIndex; + int minNsIndex; };
struct _xmlAttrHashBucket { int index; };
-static xmlParserCtxtPtr -xmlCreateEntityParserCtxtInternal(xmlSAXHandlerPtr sax, void *userData, - const xmlChar *URL, const xmlChar *ID, const xmlChar *base, - xmlParserCtxtPtr pctx); - static int xmlParseElementStart(xmlParserCtxtPtr ctxt);
static void xmlParseElementEnd(xmlParserCtxtPtr ctxt);
+static xmlEntityPtr +xmlLookupGeneralEntity(xmlParserCtxtPtr ctxt, const xmlChar *name, int inAttr); + +static const xmlChar * +xmlParseEntityRefInternal(xmlParserCtxtPtr ctxt); + /************************************************************************ * * * Arbitrary limits set in the parser. See XML_PARSE_HUGE * @@ -159,7 +165,7 @@ xmlParseElementEnd(xmlParserCtxtPtr ctxt); * boundary feature. It can be disabled with the XML_PARSE_HUGE * parser option. */ -unsigned int xmlParserMaxDepth = 256; +const unsigned int xmlParserMaxDepth = 256;
@@ -201,23 +207,8 @@ static const char* const xmlW3CPIs[] = { static 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); - -static int -xmlCtxtUseOptionsInternal(xmlParserCtxtPtr ctxt, int options); -#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); +xmlCtxtParseEntity(xmlParserCtxtPtr ctxt, xmlEntityPtr ent);
static int xmlLoadEntityContent(xmlParserCtxtPtr ctxt, xmlEntityPtr entity); @@ -228,6 +219,11 @@ xmlLoadEntityContent(xmlParserCtxtPtr ctxt, xmlEntityPtr entity); * * ************************************************************************/
+static void +xmlErrMemory(xmlParserCtxtPtr ctxt) { + xmlCtxtErrMemory(ctxt); +} + /** * xmlErrAttributeDup: * @ctxt: an XML parser context @@ -240,28 +236,14 @@ static void xmlErrAttributeDup(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); + xmlCtxtErr(ctxt, NULL, XML_FROM_PARSER, XML_ERR_ATTRIBUTE_REDEFINED, + XML_ERR_FATAL, localname, NULL, NULL, 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; - } + xmlCtxtErr(ctxt, NULL, XML_FROM_PARSER, XML_ERR_ATTRIBUTE_REDEFINED, + XML_ERR_FATAL, prefix, localname, NULL, 0, + "Attribute %s:%s redefined\n", prefix, localname); }
/** @@ -276,18 +258,8 @@ static void LIBXML_ATTR_FORMAT(3,0) xmlFatalErrMsg(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *msg) { - if ((ctxt != NULL) && (ctxt->disableSAX != 0) && - (ctxt->instate == XML_PARSER_EOF)) - return; - if (ctxt != NULL) - ctxt->errNo = error; - __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER, error, - XML_ERR_FATAL, NULL, 0, NULL, NULL, NULL, 0, 0, "%s", msg); - if (ctxt != NULL) { - ctxt->wellFormed = 0; - if (ctxt->recovery == 0) - ctxt->disableSAX = 1; - } + xmlCtxtErr(ctxt, NULL, XML_FROM_PARSER, error, XML_ERR_FATAL, + NULL, NULL, NULL, 0, "%s", msg); }
/** @@ -304,29 +276,8 @@ void LIBXML_ATTR_FORMAT(3,0) 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; - if ((ctxt != NULL) && (ctxt->sax != NULL) && - (ctxt->sax->initialized == XML_SAX2_MAGIC)) - schannel = ctxt->sax->serror; - if (ctxt != NULL) { - __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); - } else { - __xmlRaiseError(schannel, NULL, NULL, - 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); - } + xmlCtxtErr(ctxt, NULL, XML_FROM_PARSER, error, XML_ERR_WARNING, + str1, str2, NULL, 0, msg, str1, str2); }
/** @@ -342,31 +293,10 @@ static void LIBXML_ATTR_FORMAT(3,0) xmlValidityError(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *msg, const xmlChar *str1, const xmlChar *str2) { - xmlStructuredErrorFunc schannel = NULL; + ctxt->valid = 0;
- if ((ctxt != NULL) && (ctxt->disableSAX != 0) && - (ctxt->instate == XML_PARSER_EOF)) - return; - if (ctxt != NULL) { - ctxt->errNo = error; - if ((ctxt->sax != NULL) && (ctxt->sax->initialized == XML_SAX2_MAGIC)) - schannel = ctxt->sax->serror; - } - if (ctxt != NULL) { - __xmlRaiseError(schannel, - ctxt->vctxt.error, ctxt->vctxt.userData, - ctxt, NULL, XML_FROM_DTD, error, - XML_ERR_ERROR, NULL, 0, (const char *) str1, - (const char *) str2, NULL, 0, 0, - msg, (const char *) str1, (const char *) str2); - ctxt->valid = 0; - } else { - __xmlRaiseError(schannel, NULL, NULL, - ctxt, NULL, XML_FROM_DTD, error, - XML_ERR_ERROR, NULL, 0, (const char *) str1, - (const char *) str2, NULL, 0, 0, - msg, (const char *) str1, (const char *) str2); - } + xmlCtxtErr(ctxt, NULL, XML_FROM_DTD, error, XML_ERR_ERROR, + str1, str2, NULL, 0, msg, str1, str2); }
/** @@ -382,19 +312,8 @@ static void LIBXML_ATTR_FORMAT(3,0) xmlFatalErrMsgInt(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *msg, int val) { - if ((ctxt != NULL) && (ctxt->disableSAX != 0) && - (ctxt->instate == XML_PARSER_EOF)) - return; - if (ctxt != NULL) - 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); - if (ctxt != NULL) { - ctxt->wellFormed = 0; - if (ctxt->recovery == 0) - ctxt->disableSAX = 1; - } + xmlCtxtErr(ctxt, NULL, XML_FROM_PARSER, error, XML_ERR_FATAL, + NULL, NULL, NULL, val, msg, val); }
/** @@ -413,20 +332,8 @@ 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; - if (ctxt != NULL) - 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); - if (ctxt != NULL) { - ctxt->wellFormed = 0; - if (ctxt->recovery == 0) - ctxt->disableSAX = 1; - } + xmlCtxtErr(ctxt, NULL, XML_FROM_PARSER, error, XML_ERR_FATAL, + str1, str2, NULL, val, msg, str1, val, str2); }
/** @@ -442,20 +349,8 @@ static void LIBXML_ATTR_FORMAT(3,0) xmlFatalErrMsgStr(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *msg, const xmlChar * val) { - if ((ctxt != NULL) && (ctxt->disableSAX != 0) && - (ctxt->instate == XML_PARSER_EOF)) - return; - if (ctxt != NULL) - 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); - if (ctxt != NULL) { - ctxt->wellFormed = 0; - if (ctxt->recovery == 0) - ctxt->disableSAX = 1; - } + xmlCtxtErr(ctxt, NULL, XML_FROM_PARSER, error, XML_ERR_FATAL, + val, NULL, NULL, 0, msg, val); }
/** @@ -471,15 +366,8 @@ static void LIBXML_ATTR_FORMAT(3,0) xmlErrMsgStr(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *msg, const xmlChar * val) { - if ((ctxt != NULL) && (ctxt->disableSAX != 0) && - (ctxt->instate == XML_PARSER_EOF)) - return; - if (ctxt != NULL) - 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); + xmlCtxtErr(ctxt, NULL, XML_FROM_PARSER, error, XML_ERR_ERROR, + val, NULL, NULL, 0, msg, val); }
/** @@ -498,17 +386,10 @@ xmlNsErr(xmlParserCtxtPtr ctxt, xmlParserErrors error, const xmlChar * info1, const xmlChar * info2, const xmlChar * info3) { - if ((ctxt != NULL) && (ctxt->disableSAX != 0) && - (ctxt->instate == XML_PARSER_EOF)) - return; - if (ctxt != NULL) - 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); - if (ctxt != NULL) - ctxt->nsWellFormed = 0; + ctxt->nsWellFormed = 0; + + xmlCtxtErr(ctxt, NULL, XML_FROM_NAMESPACE, error, XML_ERR_ERROR, + info1, info2, info3, 0, msg, info1, info2, info3); }
/** @@ -527,13 +408,8 @@ xmlNsWarn(xmlParserCtxtPtr ctxt, xmlParserErrors error, const xmlChar * info1, const xmlChar * info2, const xmlChar * info3) { - if ((ctxt != NULL) && (ctxt->disableSAX != 0) && - (ctxt->instate == XML_PARSER_EOF)) - return; - __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_NAMESPACE, error, - XML_ERR_WARNING, NULL, 0, (const char *) info1, - (const char *) info2, (const char *) info3, 0, 0, msg, - info1, info2, info3); + xmlCtxtErr(ctxt, NULL, XML_FROM_NAMESPACE, error, XML_ERR_WARNING, + info1, info2, info3, 0, msg, info1, info2, info3); }
static void @@ -559,7 +435,7 @@ xmlSaturatedAddSizeT(unsigned long *dst, unsigned long val) { * * Check for non-linear entity expansion behaviour. * - * In some cases like xmlStringDecodeEntities, this function is called + * In some cases like xmlExpandEntityInAttValue, this function is called * for each, possibly nested entity and its unexpanded content length. * * In other cases like xmlParseReference, it's only called for each @@ -580,37 +456,41 @@ static int xmlParserEntityCheck(xmlParserCtxtPtr ctxt, unsigned long extra) { unsigned long consumed; + unsigned long *expandedSize; xmlParserInputPtr input = ctxt->input; xmlEntityPtr entity = input->entity;
+ if ((entity) && (entity->flags & XML_ENT_CHECKED)) + return(0); + /* * Compute total consumed bytes so far, including input streams of * external entities. */ - consumed = input->parentConsumed; - if ((entity == NULL) || - ((entity->etype == XML_EXTERNAL_PARAMETER_ENTITY) && - ((entity->flags & XML_ENT_PARSED) == 0))) { - xmlSaturatedAdd(&consumed, input->consumed); - xmlSaturatedAddSizeT(&consumed, input->cur - input->base); - } + consumed = input->consumed; + xmlSaturatedAddSizeT(&consumed, input->cur - input->base); xmlSaturatedAdd(&consumed, ctxt->sizeentities);
+ if (entity) + expandedSize = &entity->expandedSize; + else + expandedSize = &ctxt->sizeentcopy; + /* * Add extra cost and some fixed cost. */ - xmlSaturatedAdd(&ctxt->sizeentcopy, extra); - xmlSaturatedAdd(&ctxt->sizeentcopy, XML_ENT_FIXED_COST); + xmlSaturatedAdd(expandedSize, extra); + xmlSaturatedAdd(expandedSize, XML_ENT_FIXED_COST);
/* * It's important to always use saturation arithmetic when tracking * entity sizes to make the size checks reliable. If "sizeentcopy" * overflows, we have to abort. */ - if ((ctxt->sizeentcopy > XML_PARSER_ALLOWED_EXPANSION) && - ((ctxt->sizeentcopy >= ULONG_MAX) || - (ctxt->sizeentcopy / ctxt->maxAmpl > consumed))) { - xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_LOOP, + if ((*expandedSize > XML_PARSER_ALLOWED_EXPANSION) && + ((*expandedSize >= ULONG_MAX) || + (*expandedSize / ctxt->maxAmpl > consumed))) { + xmlFatalErrMsg(ctxt, XML_ERR_RESOURCE_LIMIT, "Maximum entity amplification factor exceeded, see " "xmlCtxtSetMaxAmplification.\n"); xmlHaltParser(ctxt); @@ -809,12 +689,6 @@ xmlHasFeature(xmlFeature feature) return(0); #endif case XML_WITH_DEBUG_MEM: -#ifdef DEBUG_MEMORY_LOCATION - return(1); -#else - return(0); -#endif - case XML_WITH_DEBUG_RUN: return(0); case XML_WITH_ZLIB: #ifdef LIBXML_ZLIB_ENABLED @@ -840,6 +714,220 @@ xmlHasFeature(xmlFeature feature) return(0); }
+/************************************************************************ + * * + * Simple string buffer * + * * + ************************************************************************/ + +typedef struct { + xmlChar *mem; + unsigned size; + unsigned cap; /* size < cap */ + unsigned max; /* size <= max */ + xmlParserErrors code; +} xmlSBuf; + +static void +xmlSBufInit(xmlSBuf *buf, unsigned max) { + buf->mem = NULL; + buf->size = 0; + buf->cap = 0; + buf->max = max; + buf->code = XML_ERR_OK; +} + +static int +xmlSBufGrow(xmlSBuf *buf, unsigned len) { + xmlChar *mem; + unsigned cap; + + if (len >= UINT_MAX / 2 - buf->size) { + if (buf->code == XML_ERR_OK) + buf->code = XML_ERR_RESOURCE_LIMIT; + return(-1); + } + + cap = (buf->size + len) * 2; + if (cap < 240) + cap = 240; + + mem = xmlRealloc(buf->mem, cap); + if (mem == NULL) { + buf->code = XML_ERR_NO_MEMORY; + return(-1); + } + + buf->mem = mem; + buf->cap = cap; + + return(0); +} + +static void +xmlSBufAddString(xmlSBuf *buf, const xmlChar *str, unsigned len) { + if (buf->max - buf->size < len) { + if (buf->code == XML_ERR_OK) + buf->code = XML_ERR_RESOURCE_LIMIT; + return; + } + + if (buf->cap - buf->size <= len) { + if (xmlSBufGrow(buf, len) < 0) + return; + } + + if (len > 0) + memcpy(buf->mem + buf->size, str, len); + buf->size += len; +} + +static void +xmlSBufAddCString(xmlSBuf *buf, const char *str, unsigned len) { + xmlSBufAddString(buf, (const xmlChar *) str, len); +} + +static void +xmlSBufAddChar(xmlSBuf *buf, int c) { + xmlChar *end; + + if (buf->max - buf->size < 4) { + if (buf->code == XML_ERR_OK) + buf->code = XML_ERR_RESOURCE_LIMIT; + return; + } + + if (buf->cap - buf->size <= 4) { + if (xmlSBufGrow(buf, 4) < 0) + return; + } + + end = buf->mem + buf->size; + + if (c < 0x80) { + *end = (xmlChar) c; + buf->size += 1; + } else { + buf->size += xmlCopyCharMultiByte(end, c); + } +} + +static void +xmlSBufAddReplChar(xmlSBuf *buf) { + xmlSBufAddCString(buf, "\xEF\xBF\xBD", 3); +} + +static void +xmlSBufReportError(xmlSBuf *buf, xmlParserCtxtPtr ctxt, const char *errMsg) { + if (buf->code == XML_ERR_NO_MEMORY) + xmlCtxtErrMemory(ctxt); + else + xmlFatalErr(ctxt, buf->code, errMsg); +} + +static xmlChar * +xmlSBufFinish(xmlSBuf *buf, int *sizeOut, xmlParserCtxtPtr ctxt, + const char *errMsg) { + if (buf->mem == NULL) { + buf->mem = xmlMalloc(1); + if (buf->mem == NULL) { + buf->code = XML_ERR_NO_MEMORY; + } else { + buf->mem[0] = 0; + } + } else { + buf->mem[buf->size] = 0; + } + + if (buf->code == XML_ERR_OK) { + if (sizeOut != NULL) + *sizeOut = buf->size; + return(buf->mem); + } + + xmlSBufReportError(buf, ctxt, errMsg); + + xmlFree(buf->mem); + + if (sizeOut != NULL) + *sizeOut = 0; + return(NULL); +} + +static void +xmlSBufCleanup(xmlSBuf *buf, xmlParserCtxtPtr ctxt, const char *errMsg) { + if (buf->code != XML_ERR_OK) + xmlSBufReportError(buf, ctxt, errMsg); + + xmlFree(buf->mem); +} + +static int +xmlUTF8MultibyteLen(xmlParserCtxtPtr ctxt, const xmlChar *str, + const char *errMsg) { + int c = str[0]; + int c1 = str[1]; + + if ((c1 & 0xC0) != 0x80) + goto encoding_error; + + if (c < 0xE0) { + /* 2-byte sequence */ + if (c < 0xC2) + goto encoding_error; + + return(2); + } else { + int c2 = str[2]; + + if ((c2 & 0xC0) != 0x80) + goto encoding_error; + + if (c < 0xF0) { + /* 3-byte sequence */ + if (c == 0xE0) { + /* overlong */ + if (c1 < 0xA0) + goto encoding_error; + } else if (c == 0xED) { + /* surrogate */ + if (c1 >= 0xA0) + goto encoding_error; + } else if (c == 0xEF) { + /* U+FFFE and U+FFFF are invalid Chars */ + if ((c1 == 0xBF) && (c2 >= 0xBE)) + xmlFatalErrMsg(ctxt, XML_ERR_INVALID_CHAR, errMsg); + } + + return(3); + } else { + /* 4-byte sequence */ + if ((str[3] & 0xC0) != 0x80) + goto encoding_error; + if (c == 0xF0) { + /* overlong */ + if (c1 < 0x90) + goto encoding_error; + } else if (c >= 0xF4) { + /* greater than 0x10FFFF */ + if ((c > 0xF4) || (c1 >= 0x90)) + goto encoding_error; + } + + return(4); + } + } + +encoding_error: + /* Only report the first error */ + if ((ctxt->input->flags & XML_INPUT_ENCODING_ERROR) == 0) { + xmlCtxtErrIO(ctxt, XML_ERR_INVALID_ENCODING, NULL); + ctxt->input->flags |= XML_INPUT_ENCODING_ERROR; + } + + return(0); +} + /************************************************************************ * * * SAX2 defaulted attributes handling * @@ -847,18 +935,25 @@ xmlHasFeature(xmlFeature feature) ************************************************************************/
/** - * xmlDetectSAX2: + * xmlCtxtInitializeLate: * @ctxt: an XML parser context * - * Do the SAX2 detection and specific initialization + * Final initialization of the parser context before starting to parse. + * + * This accounts for users modifying struct members of parser context + * directly. */ static void -xmlDetectSAX2(xmlParserCtxtPtr ctxt) { +xmlCtxtInitializeLate(xmlParserCtxtPtr ctxt) { xmlSAXHandlerPtr sax;
/* Avoid unused variable warning if features are disabled. */ (void) sax;
+ /* + * Changing the SAX struct directly is still widespread practice + * in internal and external code. + */ if (ctxt == NULL) return; sax = ctxt->sax; #ifdef LIBXML_SAX1_ENABLED @@ -866,7 +961,9 @@ xmlDetectSAX2(xmlParserCtxtPtr ctxt) { * Only enable SAX2 if there SAX2 element handlers, except when there * are no element handlers at all. */ - if ((sax) && (sax->initialized == XML_SAX2_MAGIC) && + if (((ctxt->options & XML_PARSE_SAX1) == 0) && + (sax) && + (sax->initialized == XML_SAX2_MAGIC) && ((sax->startElementNs != NULL) || (sax->endElementNs != NULL) || ((sax->startElement == NULL) && (sax->endElement == NULL)))) @@ -875,12 +972,16 @@ xmlDetectSAX2(xmlParserCtxtPtr ctxt) { ctxt->sax2 = 1; #endif /* LIBXML_SAX1_ENABLED */
+ /* + * Some users replace the dictionary directly in the context struct. + * We really need an API function to do that cleanly. + */ 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->str_xml==NULL) || (ctxt->str_xmlns==NULL) || (ctxt->str_xml_ns == NULL)) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); } }
@@ -945,65 +1046,6 @@ xmlAttrNormalizeSpace(const xmlChar *src, xmlChar *dst) return(dst); }
-/** - * xmlAttrNormalizeSpace2: - * @src: the source string - * - * Normalize the space in non CDATA attribute values, a slightly more complex - * front end to avoid allocation problems when running on attribute values - * coming from the input. - * - * Returns a pointer to the normalized value (dst) or NULL if no conversion - * is needed. - */ -static const xmlChar * -xmlAttrNormalizeSpace2(xmlParserCtxtPtr ctxt, xmlChar *src, int *len) -{ - int i; - int remove_head = 0; - int need_realloc = 0; - const xmlChar *cur; - - if ((ctxt == NULL) || (src == NULL) || (len == NULL)) - return(NULL); - i = *len; - if (i <= 0) - return(NULL); - - cur = src; - while (*cur == 0x20) { - cur++; - remove_head++; - } - while (*cur != 0) { - if (*cur == 0x20) { - cur++; - if ((*cur == 0x20) || (*cur == 0)) { - need_realloc = 1; - break; - } - } else - cur++; - } - if (need_realloc) { - xmlChar *ret; - - ret = xmlStrndup(src + remove_head, i - remove_head + 1); - if (ret == NULL) { - xmlErrMemory(ctxt, NULL); - return(NULL); - } - xmlAttrNormalizeSpace(ret, ret); - *len = strlen((const char *)ret); - return(ret); - } else if (remove_head) { - *len -= remove_head; - memmove(src, src + remove_head, 1 + *len); - return(src); - } - return(NULL); -} - /** * xmlAddDefAttrs: * @ctxt: an XML parser context @@ -1115,13 +1157,13 @@ xmlAddDefAttrs(xmlParserCtxtPtr ctxt, attr->prefix = prefix; attr->value = hvalue; attr->valueEnd = hvalue.name + len; - attr->external = ctxt->external; + attr->external = PARSER_EXTERNAL(ctxt); attr->expandedSize = expandedSize;
return;
mem_error: - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); return; }
@@ -1146,15 +1188,13 @@ xmlAddSpecialAttr(xmlParserCtxtPtr ctxt, goto mem_error; }
- if (xmlHashLookup2(ctxt->attsSpecial, fullname, fullattr) != NULL) - return; - - xmlHashAddEntry2(ctxt->attsSpecial, fullname, fullattr, - (void *) (ptrdiff_t) type); + if (xmlHashAdd2(ctxt->attsSpecial, fullname, fullattr, + (void *) (ptrdiff_t) type) < 0) + goto mem_error; return;
mem_error: - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); return; }
@@ -1399,8 +1439,8 @@ region_m49: * * ************************************************************************/
-static xmlEntityPtr xmlParseStringEntityRef(xmlParserCtxtPtr ctxt, - const xmlChar ** str); +static xmlChar * +xmlParseStringEntityRef(xmlParserCtxtPtr ctxt, const xmlChar **str);
/** * xmlParserNsCreate: @@ -1545,8 +1585,12 @@ xmlParserNsLookupUri(xmlParserCtxtPtr ctxt, const xmlHashedString *prefix) { if (prefix->name == ctxt->str_xml) return(ctxt->str_xml_ns);
+ /* + * minNsIndex is used when building an entity tree. We must + * ignore namespaces declared outside the entity. + */ nsIndex = xmlParserNsLookup(ctxt, prefix, NULL); - if (nsIndex == INT_MAX) + if ((nsIndex == INT_MAX) || (nsIndex < ctxt->nsdb->minNsIndex)) return(NULL);
ret = ctxt->nsTab[nsIndex * 2 + 1]; @@ -1579,7 +1623,7 @@ xmlParserNsLookupSax(xmlParserCtxtPtr ctxt, const xmlChar *prefix) { else hprefix.hashValue = 0; nsIndex = xmlParserNsLookup(ctxt, &hprefix, NULL); - if (nsIndex == INT_MAX) + if ((nsIndex == INT_MAX) || (nsIndex < ctxt->nsdb->minNsIndex)) return(NULL);
return(ctxt->nsdb->extra[nsIndex].saxData); @@ -1612,7 +1656,7 @@ xmlParserNsUpdateSax(xmlParserCtxtPtr ctxt, const xmlChar *prefix, else hprefix.hashValue = 0; nsIndex = xmlParserNsLookup(ctxt, &hprefix, NULL); - if (nsIndex == INT_MAX) + if ((nsIndex == INT_MAX) || (nsIndex < ctxt->nsdb->minNsIndex)) return(-1);
ctxt->nsdb->extra[nsIndex].saxData = saxData; @@ -1651,7 +1695,7 @@ xmlParserNsGrow(xmlParserCtxtPtr ctxt) { return(0);
error: - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); return(-1); }
@@ -1680,7 +1724,7 @@ xmlParserNsPush(xmlParserCtxtPtr ctxt, const xmlHashedString *prefix, return(0);
if ((ctxt->nsNr >= ctxt->nsMax) && (xmlParserNsGrow(ctxt) < 0)) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); return(-1); }
@@ -1746,13 +1790,13 @@ xmlParserNsPush(xmlParserCtxtPtr ctxt, const xmlHashedString *prefix, unsigned newSize, i, index;
if (ctxt->nsdb->hashSize > UINT_MAX / 2) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); return(-1); } newSize = ctxt->nsdb->hashSize ? ctxt->nsdb->hashSize * 2 : 16; newHash = xmlMalloc(newSize * sizeof(newHash[0])); if (newHash == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); return(-1); } memset(newHash, 0, newSize * sizeof(newHash[0])); @@ -1880,7 +1924,7 @@ xmlCtxtGrowAttrs(xmlParserCtxtPtr ctxt, int nr) { } return(ctxt->maxatts); mem_error: - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); return(-1); }
@@ -1896,8 +1940,11 @@ mem_error: int inputPush(xmlParserCtxtPtr ctxt, xmlParserInputPtr value) { + char *directory = NULL; + if ((ctxt == NULL) || (value == NULL)) return(-1); + if (ctxt->inputNr >= ctxt->inputMax) { size_t newSize = ctxt->inputMax * 2; xmlParserInputPtr *tmp; @@ -1905,15 +1952,30 @@ inputPush(xmlParserCtxtPtr ctxt, xmlParserInputPtr value) tmp = (xmlParserInputPtr *) xmlRealloc(ctxt->inputTab, newSize * sizeof(*tmp)); if (tmp == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); return (-1); } ctxt->inputTab = tmp; ctxt->inputMax = newSize; } + + if ((ctxt->inputNr == 0) && (value->filename != NULL)) { + directory = xmlParserGetDirectory(value->filename); + if (directory == NULL) { + xmlErrMemory(ctxt); + return(-1); + } + } + ctxt->inputTab[ctxt->inputNr] = value; ctxt->input = value; - return (ctxt->inputNr++); + + if (ctxt->inputNr == 0) { + xmlFree(ctxt->directory); + ctxt->directory = directory; + } + + return(ctxt->inputNr++); } /** * inputPop: @@ -1955,7 +2017,19 @@ inputPop(xmlParserCtxtPtr ctxt) int nodePush(xmlParserCtxtPtr ctxt, xmlNodePtr value) { - if (ctxt == NULL) return(0); + int maxDepth; + + if (ctxt == NULL) + return(0); + + maxDepth = (ctxt->options & XML_PARSE_HUGE) ? 2048 : 256; + if (ctxt->nodeNr > maxDepth) { + xmlFatalErrMsgInt(ctxt, XML_ERR_RESOURCE_LIMIT, + "Excessive depth in document: %d use XML_PARSE_HUGE option\n", + ctxt->nodeNr); + xmlHaltParser(ctxt); + return(-1); + } if (ctxt->nodeNr >= ctxt->nodeMax) { xmlNodePtr *tmp;
@@ -1963,20 +2037,12 @@ nodePush(xmlParserCtxtPtr ctxt, xmlNodePtr value) ctxt->nodeMax * 2 * sizeof(ctxt->nodeTab[0])); if (tmp == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); return (-1); } ctxt->nodeTab = tmp; ctxt->nodeMax *= 2; } - if ((((unsigned int) ctxt->nodeNr) > xmlParserMaxDepth) && - ((ctxt->options & XML_PARSE_HUGE) == 0)) { - xmlFatalErrMsgInt(ctxt, XML_ERR_INTERNAL_ERROR, - "Excessive depth in document: %d use XML_PARSE_HUGE option\n", - xmlParserMaxDepth); - xmlHaltParser(ctxt); - return(-1); - } ctxt->nodeTab[ctxt->nodeNr] = value; ctxt->node = value; return (ctxt->nodeNr++); @@ -2064,7 +2130,7 @@ nameNsPush(xmlParserCtxtPtr ctxt, const xmlChar * value, tag->nsNr = nsNr; return (ctxt->nameNr++); mem_error: - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); return (-1); } #ifdef LIBXML_PUSH_ENABLED @@ -2125,7 +2191,7 @@ namePush(xmlParserCtxtPtr ctxt, const xmlChar * value) ctxt->name = value; return (ctxt->nameNr++); mem_error: - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); return (-1); }
@@ -2164,7 +2230,7 @@ static int spacePush(xmlParserCtxtPtr ctxt, int val) { tmp = (int *) xmlRealloc(ctxt->spaceTab, ctxt->spaceMax * sizeof(ctxt->spaceTab[0])); if (tmp == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); ctxt->spaceMax /=2; return(-1); } @@ -2265,18 +2331,21 @@ static int spacePop(xmlParserCtxtPtr ctxt) { xmlParserGrow(ctxt); \ } while (0)
-/* Don't shrink push parser buffer. */ #define SHRINK \ - if (((ctxt->progressive == 0) || (ctxt->inputNr > 1)) && \ + if ((!PARSER_PROGRESSIVE(ctxt)) && \ (ctxt->input->cur - ctxt->input->base > 2 * INPUT_CHUNK) && \ (ctxt->input->end - ctxt->input->cur < 2 * INPUT_CHUNK)) \ xmlParserShrink(ctxt);
-#define GROW if (ctxt->input->end - ctxt->input->cur < INPUT_CHUNK) \ +#define GROW \ + if ((!PARSER_PROGRESSIVE(ctxt)) && \ + (ctxt->input->end - ctxt->input->cur < INPUT_CHUNK)) \ xmlParserGrow(ctxt);
#define SKIP_BLANKS xmlSkipBlankChars(ctxt)
+#define SKIP_BLANKS_PE xmlSkipBlankCharsPE(ctxt) + #define NEXT xmlNextChar(ctxt)
#define NEXT1 { \ @@ -2306,112 +2375,161 @@ static int spacePop(xmlParserCtxtPtr ctxt) { * * DEPRECATED: Internal function, do not use. * - * 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. + * Skip whitespace in the input stream. * * Returns the number of space chars skipped */ - int xmlSkipBlankChars(xmlParserCtxtPtr ctxt) { + const xmlChar *cur; 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)) || - (ctxt->instate == XML_PARSER_START)) { - 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; - } else { - ctxt->input->col++; - } - cur++; - if (res < INT_MAX) - res++; - if (*cur == 0) { - ctxt->input->cur = cur; - xmlParserGrow(ctxt); - cur = ctxt->input->cur; - } - } - ctxt->input->cur = cur; - } else { - int expandPE = ((ctxt->external != 0) || (ctxt->inputNr != 1)); + cur = ctxt->input->cur; + while (IS_BLANK_CH(*cur)) { + if (*cur == '\n') { + ctxt->input->line++; ctxt->input->col = 1; + } else { + ctxt->input->col++; + } + cur++; + if (res < INT_MAX) + res++; + if (*cur == 0) { + ctxt->input->cur = cur; + xmlParserGrow(ctxt); + cur = ctxt->input->cur; + } + } + ctxt->input->cur = cur;
- while (ctxt->instate != XML_PARSER_EOF) { - if (IS_BLANK_CH(CUR)) { /* CHECKED tstblanks.xml */ - NEXT; - } else if (CUR == '%') { - /* - * Need to handle support of entities branching here - */ - if ((expandPE == 0) || (IS_BLANK_CH(NXT(1))) || (NXT(1) == 0)) - break; - xmlParsePEReference(ctxt); - } else if (CUR == 0) { - unsigned long consumed; - xmlEntityPtr ent; + return(res); +}
- if (ctxt->inputNr <= 1) - break; +static void +xmlPopPE(xmlParserCtxtPtr ctxt) { + unsigned long consumed; + xmlEntityPtr ent;
- consumed = ctxt->input->consumed; - xmlSaturatedAddSizeT(&consumed, - ctxt->input->cur - ctxt->input->base); + ent = ctxt->input->entity;
- /* - * Add to sizeentities when parsing an external entity - * for the first time. - */ - ent = ctxt->input->entity; - if ((ent->etype == XML_EXTERNAL_PARAMETER_ENTITY) && - ((ent->flags & XML_ENT_PARSED) == 0)) { - ent->flags |= XML_ENT_PARSED; + ent->flags &= ~XML_ENT_EXPANDING;
- xmlSaturatedAdd(&ctxt->sizeentities, consumed); - } + if ((ent->flags & XML_ENT_CHECKED) == 0) { + int result; + + /* + * Read the rest of the stream in case of errors. We want + * to account for the whole entity size. + */ + do { + ctxt->input->cur = ctxt->input->end; + xmlParserShrink(ctxt); + result = xmlParserGrow(ctxt); + } while (result > 0);
- xmlParserEntityCheck(ctxt, consumed); + consumed = ctxt->input->consumed; + xmlSaturatedAddSizeT(&consumed, + ctxt->input->end - ctxt->input->base);
- xmlPopInput(ctxt); - } else { - break; - } + xmlSaturatedAdd(&ent->expandedSize, consumed);
- /* - * Also increase the counter when entering or exiting a PERef. - * The spec says: "When a parameter-entity reference is recognized - * in the DTD and included, its replacement text MUST be enlarged - * by the attachment of one leading and one following space (#x20) - * character." - */ - if (res < INT_MAX) - res++; + /* + * Add to sizeentities when parsing an external entity + * for the first time. + */ + if (ent->etype == XML_EXTERNAL_PARAMETER_ENTITY) { + xmlSaturatedAdd(&ctxt->sizeentities, consumed); } + + ent->flags |= XML_ENT_CHECKED; } - return(res); -}
-/************************************************************************ - * * - * Commodity functions to handle entities * - * * - ************************************************************************/ + xmlPopInput(ctxt); + + xmlParserEntityCheck(ctxt, ent->expandedSize); +}
/** - * xmlPopInput: - * @ctxt: an XML parser context + * xmlSkipBlankCharsPE: + * @ctxt: the XML parser context * - * xmlPopInput: the current input pointed by ctxt->input came to an end - * pop it and return the next char. + * Skip whitespace in the input stream, also handling parameter + * entities. + * + * Returns the number of space chars skipped + */ +static int +xmlSkipBlankCharsPE(xmlParserCtxtPtr ctxt) { + int res = 0; + int inParam; + int expandParam; + + inParam = PARSER_IN_PE(ctxt); + expandParam = PARSER_EXTERNAL(ctxt); + + if (!inParam && !expandParam) + return(xmlSkipBlankChars(ctxt)); + + while (PARSER_STOPPED(ctxt) == 0) { + if (IS_BLANK_CH(CUR)) { /* CHECKED tstblanks.xml */ + NEXT; + } else if (CUR == '%') { + if ((expandParam == 0) || + (IS_BLANK_CH(NXT(1))) || (NXT(1) == 0)) + break; + + /* + * Expand parameter entity. We continue to consume + * whitespace at the start of the entity and possible + * even consume the whole entity and pop it. We might + * even pop multiple PEs in this loop. + */ + xmlParsePEReference(ctxt); + + inParam = PARSER_IN_PE(ctxt); + expandParam = PARSER_EXTERNAL(ctxt); + } else if (CUR == 0) { + if (inParam == 0) + break; + + xmlPopPE(ctxt); + + inParam = PARSER_IN_PE(ctxt); + expandParam = PARSER_EXTERNAL(ctxt); + } else { + break; + } + + /* + * Also increase the counter when entering or exiting a PERef. + * The spec says: "When a parameter-entity reference is recognized + * in the DTD and included, its replacement text MUST be enlarged + * by the attachment of one leading and one following space (#x20) + * character." + */ + if (res < INT_MAX) + res++; + } + + return(res); +} + +/************************************************************************ + * * + * Commodity functions to handle entities * + * * + ************************************************************************/ + +/** + * xmlPopInput: + * @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 */ @@ -2420,16 +2538,7 @@ xmlPopInput(xmlParserCtxtPtr ctxt) { xmlParserInputPtr input;
if ((ctxt == NULL) || (ctxt->inputNr <= 1)) return(0); - if (xmlParserDebugEntities) - xmlGenericError(xmlGenericErrorContext, - "Popping input %d\n", ctxt->inputNr); - if ((ctxt->inputNr > 1) && (ctxt->inSubset == 0) && - (ctxt->instate != XML_PARSER_EOF)) - xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR, - "Unfinished entity outside the DTD"); input = inputPop(ctxt); - if (input->entity != NULL) - input->entity->flags &= ~XML_ENT_EXPANDING; xmlFreeInputStream(input); if (*ctxt->input->cur == 0) xmlParserGrow(ctxt); @@ -2441,33 +2550,26 @@ xmlPopInput(xmlParserCtxtPtr ctxt) { * @ctxt: an XML parser context * @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). + * Push an input stream onto the stack. + * * Returns -1 in case of error or the index in the input stack */ int xmlPushInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr input) { + int maxDepth; int ret; - if (input == NULL) return(-1); - - if (xmlParserDebugEntities) { - if ((ctxt->input != NULL) && (ctxt->input->filename)) - xmlGenericError(xmlGenericErrorContext, - "%s(%d): ", ctxt->input->filename, - ctxt->input->line); - xmlGenericError(xmlGenericErrorContext, - "Pushing input %d : %.30s\n", ctxt->inputNr+1, input->cur); - } - if (((ctxt->inputNr > 40) && ((ctxt->options & XML_PARSE_HUGE) == 0)) || - (ctxt->inputNr > 100)) { - xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL); - while (ctxt->inputNr > 1) - xmlFreeInputStream(inputPop(ctxt)); + + if ((ctxt == NULL) || (input == NULL)) + return(-1); + + maxDepth = (ctxt->options & XML_PARSE_HUGE) ? 40 : 20; + if (ctxt->inputNr > maxDepth) { + xmlFatalErrMsg(ctxt, XML_ERR_RESOURCE_LIMIT, + "Maximum entity nesting depth exceeded"); + xmlHaltParser(ctxt); return(-1); } ret = inputPush(ctxt, input); - if (ctxt->instate == XML_PARSER_EOF) - return(-1); GROW; return(ret); } @@ -2501,12 +2603,10 @@ xmlParseCharRef(xmlParserCtxtPtr ctxt) { (NXT(2) == 'x')) { SKIP(3); GROW; - while (RAW != ';') { /* loop blocked by count */ + while ((RAW != ';') && (PARSER_STOPPED(ctxt) == 0)) { if (count++ > 20) { count = 0; GROW; - if (ctxt->instate == XML_PARSER_EOF) - return(0); } if ((RAW >= '0') && (RAW <= '9')) val = val * 16 + (CUR - '0'); @@ -2537,8 +2637,6 @@ xmlParseCharRef(xmlParserCtxtPtr ctxt) { if (count++ > 20) { count = 0; GROW; - if (ctxt->instate == XML_PARSER_EOF) - return(0); } if ((RAW >= '0') && (RAW <= '9')) val = val * 10 + (CUR - '0'); @@ -2713,288 +2811,9 @@ xmlParseStringCharRef(xmlParserCtxtPtr ctxt, const xmlChar **str) { */ void xmlParserHandlePEReference(xmlParserCtxtPtr ctxt) { - 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_XML_DECL: - 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; - } - xmlParsePEReference(ctxt); }
-/* - * Macro used to grow the current buffer. - * buffer##_size is expected to be a size_t - * mem_error: is expected to handle memory allocation failures - */ -#define growBuffer(buffer, n) { \ - xmlChar *tmp; \ - size_t new_size = buffer##_size * 2 + n; \ - if (new_size < buffer##_size) goto mem_error; \ - tmp = (xmlChar *) xmlRealloc(buffer, new_size); \ - if (tmp == NULL) goto mem_error; \ - buffer = tmp; \ - buffer##_size = new_size; \ -} - -/** - * xmlStringDecodeEntitiesInt: - * @ctxt: the parser context - * @str: the input string - * @len: the string length - * @what: combination of XML_SUBSTITUTE_REF and XML_SUBSTITUTE_PEREF - * @end: an end marker xmlChar, 0 if none - * @end2: an end marker xmlChar, 0 if none - * @end3: an end marker xmlChar, 0 if none - * @check: whether to perform entity checks - */ -static xmlChar * -xmlStringDecodeEntitiesInt(xmlParserCtxtPtr ctxt, const xmlChar *str, int len, - int what, xmlChar end, xmlChar end2, xmlChar end3, - int check) { - xmlChar *buffer = NULL; - size_t buffer_size = 0; - size_t nbchars = 0; - - xmlChar *current = NULL; - xmlChar *rep = NULL; - const xmlChar *last; - xmlEntityPtr ent; - int c,l; - - if (str == NULL) - return(NULL); - last = str + len; - - if (((ctxt->depth > 40) && - ((ctxt->options & XML_PARSE_HUGE) == 0)) || - (ctxt->depth > 100)) { - xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_LOOP, - "Maximum entity nesting depth exceeded"); - return(NULL); - } - - /* - * allocate a translation buffer. - */ - buffer_size = XML_PARSER_BIG_BUFFER_SIZE; - buffer = (xmlChar *) xmlMallocAtomic(buffer_size); - 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) && - (ctxt->instate != XML_PARSER_EOF)) { - - if (c == 0) break; - if ((c == '&') && (str[1] == '#')) { - int val = xmlParseStringCharRef(ctxt, &str); - if (val == 0) - goto int_error; - COPY_BUF(buffer, nbchars, val); - if (nbchars + XML_PARSER_BUFFER_SIZE > buffer_size) { - growBuffer(buffer, XML_PARSER_BUFFER_SIZE); - } - } else if ((c == '&') && (what & XML_SUBSTITUTE_REF)) { - if (xmlParserDebugEntities) - xmlGenericError(xmlGenericErrorContext, - "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(buffer, nbchars, ent->content[0]); - if (nbchars + XML_PARSER_BUFFER_SIZE > buffer_size) { - growBuffer(buffer, XML_PARSER_BUFFER_SIZE); - } - } else { - xmlFatalErrMsg(ctxt, XML_ERR_INTERNAL_ERROR, - "predefined entity has no content\n"); - goto int_error; - } - } else if ((ent != NULL) && (ent->content != NULL)) { - if ((check) && (xmlParserEntityCheck(ctxt, ent->length))) - goto int_error; - - if (ent->flags & XML_ENT_EXPANDING) { - xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL); - xmlHaltParser(ctxt); - ent->content[0] = 0; - goto int_error; - } - - ent->flags |= XML_ENT_EXPANDING; - ctxt->depth++; - rep = xmlStringDecodeEntitiesInt(ctxt, ent->content, - ent->length, what, 0, 0, 0, check); - ctxt->depth--; - ent->flags &= ~XML_ENT_EXPANDING; - - if (rep == NULL) { - ent->content[0] = 0; - goto int_error; - } - - current = rep; - while (*current != 0) { /* non input consuming loop */ - buffer[nbchars++] = *current++; - if (nbchars + XML_PARSER_BUFFER_SIZE > buffer_size) { - growBuffer(buffer, XML_PARSER_BUFFER_SIZE); - } - } - xmlFree(rep); - rep = NULL; - } else if (ent != NULL) { - int i = xmlStrlen(ent->name); - const xmlChar *cur = ent->name; - - buffer[nbchars++] = '&'; - if (nbchars + i + XML_PARSER_BUFFER_SIZE > buffer_size) { - growBuffer(buffer, i + XML_PARSER_BUFFER_SIZE); - } - for (;i > 0;i--) - buffer[nbchars++] = *cur++; - buffer[nbchars++] = ';'; - } - } else if (c == '%' && (what & XML_SUBSTITUTE_PEREF)) { - if (xmlParserDebugEntities) - xmlGenericError(xmlGenericErrorContext, - "String decoding PE Reference: %.30s\n", str); - ent = xmlParseStringPEReference(ctxt, &str); - if (ent != NULL) { - if (ent->content == NULL) { - /* - * Note: external parsed entities will not be loaded, - * it is not required for a non-validating parser to - * complete external PEReferences coming from the - * internal subset - */ - if (((ctxt->options & XML_PARSE_NOENT) != 0) || - ((ctxt->options & XML_PARSE_DTDVALID) != 0) || - (ctxt->validate != 0)) { - xmlLoadEntityContent(ctxt, ent); - } else { - xmlWarningMsg(ctxt, XML_ERR_ENTITY_PROCESSING, - "not validating will not read content for PE entity %s\n", - ent->name, NULL); - } - } - - if ((check) && (xmlParserEntityCheck(ctxt, ent->length))) - goto int_error; - - if (ent->flags & XML_ENT_EXPANDING) { - xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL); - xmlHaltParser(ctxt); - if (ent->content != NULL) - ent->content[0] = 0; - goto int_error; - } - - ent->flags |= XML_ENT_EXPANDING; - ctxt->depth++; - rep = xmlStringDecodeEntitiesInt(ctxt, ent->content, - ent->length, what, 0, 0, 0, check); - ctxt->depth--; - ent->flags &= ~XML_ENT_EXPANDING; - - if (rep == NULL) { - if (ent->content != NULL) - ent->content[0] = 0; - goto int_error; - } - current = rep; - while (*current != 0) { /* non input consuming loop */ - buffer[nbchars++] = *current++; - if (nbchars + XML_PARSER_BUFFER_SIZE > buffer_size) { - growBuffer(buffer, XML_PARSER_BUFFER_SIZE); - } - } - xmlFree(rep); - rep = NULL; - } - } else { - COPY_BUF(buffer, nbchars, c); - str += l; - if (nbchars + XML_PARSER_BUFFER_SIZE > buffer_size) { - growBuffer(buffer, XML_PARSER_BUFFER_SIZE); - } - } - if (str < last) - c = CUR_SCHAR(str, l); - else - c = 0; - } - buffer[nbchars] = 0; - return(buffer); - -mem_error: - xmlErrMemory(ctxt, NULL); -int_error: - if (rep != NULL) - xmlFree(rep); - if (buffer != NULL) - xmlFree(buffer); - return(NULL); -} - /** * xmlStringLenDecodeEntities: * @ctxt: the parser context @@ -3007,23 +2826,21 @@ int_error: * * DEPRECATED: Internal function, don't use. * - * 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 ! */ xmlChar * xmlStringLenDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, int len, - int what, xmlChar end, xmlChar end2, - xmlChar end3) { + int what ATTRIBUTE_UNUSED, + xmlChar end, xmlChar end2, xmlChar end3) { if ((ctxt == NULL) || (str == NULL) || (len < 0)) return(NULL); - return(xmlStringDecodeEntitiesInt(ctxt, str, len, what, - end, end2, end3, 0)); + + if ((str[len] != 0) || + (end != 0) || (end2 != 0) || (end3 != 0)) + return(NULL); + + return(xmlExpandEntitiesInAttValue(ctxt, str, 0)); }
/** @@ -3037,21 +2854,20 @@ xmlStringLenDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, int len, * * DEPRECATED: Internal function, don't use. * - * 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 ! */ xmlChar * -xmlStringDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, int what, +xmlStringDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, + int what ATTRIBUTE_UNUSED, xmlChar end, xmlChar end2, xmlChar end3) { - if ((ctxt == NULL) || (str == NULL)) return(NULL); - return(xmlStringDecodeEntitiesInt(ctxt, str, xmlStrlen(str), what, - end, end2, end3, 0)); + if ((ctxt == NULL) || (str == NULL)) + return(NULL); + + if ((end != 0) || (end2 != 0) || (end3 != 0)) + return(NULL); + + return(xmlExpandEntitiesInAttValue(ctxt, str, 0)); }
/************************************************************************ @@ -3074,7 +2890,7 @@ xmlStringDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, int what,
static int areBlanks(xmlParserCtxtPtr ctxt, const xmlChar *str, int len, int blank_chars) { - int i, ret; + int i; xmlNodePtr lastChild;
/* @@ -3104,9 +2920,25 @@ static int areBlanks(xmlParserCtxtPtr ctxt, const xmlChar *str, int len, */ if (ctxt->node == NULL) return(0); if (ctxt->myDoc != NULL) { - ret = xmlIsMixedElement(ctxt->myDoc, ctxt->node->name); - if (ret == 0) return(1); - if (ret == 1) return(0); + xmlElementPtr elemDecl = NULL; + xmlDocPtr doc = ctxt->myDoc; + const xmlChar *prefix = NULL; + + if (ctxt->node->ns) + prefix = ctxt->node->ns->prefix; + if (doc->intSubset != NULL) + elemDecl = xmlHashLookup2(doc->intSubset->elements, ctxt->node->name, + prefix); + if ((elemDecl == NULL) && (doc->extSubset != NULL)) + elemDecl = xmlHashLookup2(doc->extSubset->elements, ctxt->node->name, + prefix); + if (elemDecl != NULL) { + if (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT) + return(1); + if ((elemDecl->etype == XML_ELEMENT_TYPE_ANY) || + (elemDecl->etype == XML_ELEMENT_TYPE_MIXED)) + return(0); + } }
/* @@ -3139,7 +2971,7 @@ static int areBlanks(xmlParserCtxtPtr ctxt, const xmlChar *str, int len, * xmlSplitQName: * @ctxt: an XML parser context * @name: an XML parser context - * @prefix: a xmlChar ** + * @prefixOut: a xmlChar ** * * parse an UTF8 encoded XML qualified name string * @@ -3154,27 +2986,21 @@ static int areBlanks(xmlParserCtxtPtr ctxt, const xmlChar *str, int len, */
xmlChar * -xmlSplitQName(xmlParserCtxtPtr ctxt, const xmlChar *name, xmlChar **prefix) { +xmlSplitQName(xmlParserCtxtPtr ctxt, const xmlChar *name, xmlChar **prefixOut) { xmlChar buf[XML_MAX_NAMELEN + 5]; xmlChar *buffer = NULL; int len = 0; int max = XML_MAX_NAMELEN; xmlChar *ret = NULL; + xmlChar *prefix; const xmlChar *cur = name; int c;
- if (prefix == NULL) return(NULL); - *prefix = NULL; + if (prefixOut == NULL) return(NULL); + *prefixOut = 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)); @@ -3193,7 +3019,7 @@ xmlSplitQName(xmlParserCtxtPtr ctxt, const xmlChar *name, xmlChar **prefix) {
buffer = (xmlChar *) xmlMallocAtomic(max); if (buffer == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); return(NULL); } memcpy(buffer, buf, len); @@ -3205,7 +3031,7 @@ xmlSplitQName(xmlParserCtxtPtr ctxt, const xmlChar *name, xmlChar **prefix) { tmp = (xmlChar *) xmlRealloc(buffer, max); if (tmp == NULL) { xmlFree(buffer); - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); return(NULL); } buffer = tmp; @@ -3219,13 +3045,16 @@ xmlSplitQName(xmlParserCtxtPtr ctxt, const xmlChar *name, xmlChar **prefix) { if ((c == ':') && (*cur == 0)) { if (buffer != NULL) xmlFree(buffer); - *prefix = NULL; return(xmlStrdup(name)); }
- if (buffer == NULL) + if (buffer == NULL) { ret = xmlStrndup(buf, len); - else { + if (ret == NULL) { + xmlErrMemory(ctxt); + return(NULL); + } + } else { ret = buffer; buffer = NULL; max = XML_MAX_NAMELEN; @@ -3234,9 +3063,15 @@ xmlSplitQName(xmlParserCtxtPtr ctxt, const xmlChar *name, xmlChar **prefix) {
if (c == ':') { c = *cur; - *prefix = ret; + prefix = ret; if (c == 0) { - return(xmlStrndup(BAD_CAST "", 0)); + ret = xmlStrndup(BAD_CAST "", 0); + if (ret == NULL) { + xmlFree(prefix); + return(NULL); + } + *prefixOut = prefix; + return(ret); } len = 0;
@@ -3271,7 +3106,8 @@ xmlSplitQName(xmlParserCtxtPtr ctxt, const xmlChar *name, xmlChar **prefix) {
buffer = (xmlChar *) xmlMallocAtomic(max); if (buffer == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); + xmlFree(prefix); return(NULL); } memcpy(buffer, buf, len); @@ -3282,7 +3118,8 @@ xmlSplitQName(xmlParserCtxtPtr ctxt, const xmlChar *name, xmlChar **prefix) { max *= 2; tmp = (xmlChar *) xmlRealloc(buffer, max); if (tmp == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); + xmlFree(prefix); xmlFree(buffer); return(NULL); } @@ -3294,11 +3131,17 @@ xmlSplitQName(xmlParserCtxtPtr ctxt, const xmlChar *name, xmlChar **prefix) { buffer[len] = 0; }
- if (buffer == NULL) + if (buffer == NULL) { ret = xmlStrndup(buf, len); - else { + if (ret == NULL) { + xmlFree(prefix); + return(NULL); + } + } else { ret = buffer; } + + *prefixOut = prefix; }
return(ret); @@ -3397,11 +3240,9 @@ xmlIsNameChar(xmlParserCtxtPtr ctxt, int c) { return(0); }
-static xmlChar * xmlParseAttValueInternal(xmlParserCtxtPtr ctxt, - int *len, int *alloc, int normalize); - static const xmlChar * xmlParseNameComplex(xmlParserCtxtPtr ctxt) { + const xmlChar *ret; int len = 0, l; int c; int maxLength = (ctxt->options & XML_PARSE_HUGE) ? @@ -3486,8 +3327,6 @@ xmlParseNameComplex(xmlParserCtxtPtr ctxt) { c = CUR_CHAR(l); } } - if (ctxt->instate == XML_PARSER_EOF) - return(NULL); if (len > maxLength) { xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "Name"); return(NULL); @@ -3503,8 +3342,12 @@ xmlParseNameComplex(xmlParserCtxtPtr ctxt) { return (NULL); } if ((*ctxt->input->cur == '\n') && (ctxt->input->cur[-1] == '\r')) - return(xmlDictLookup(ctxt->dict, ctxt->input->cur - (len + 1), len)); - return(xmlDictLookup(ctxt->dict, ctxt->input->cur - len, len)); + ret = xmlDictLookup(ctxt->dict, ctxt->input->cur - (len + 1), len); + else + ret = xmlDictLookup(ctxt->dict, ctxt->input->cur - len, len); + if (ret == NULL) + xmlErrMemory(ctxt); + return(ret); }
/** @@ -3535,8 +3378,6 @@ xmlParseName(xmlParserCtxtPtr ctxt) { XML_MAX_NAME_LENGTH;
GROW; - if (ctxt->instate == XML_PARSER_EOF) - return(NULL);
/* * Accelerator for simple ASCII names @@ -3562,7 +3403,7 @@ xmlParseName(xmlParserCtxtPtr ctxt) { ctxt->input->cur = in; ctxt->input->col += count; if (ret == NULL) - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); return(ret); } } @@ -3600,13 +3441,13 @@ xmlParseNCNameComplex(xmlParserCtxtPtr ctxt) { NEXTL(l); c = CUR_CHAR(l); } - if (ctxt->instate == XML_PARSER_EOF) - return(ret); if (len > maxLength) { xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "NCName"); return(ret); } ret = xmlDictLookupHashed(ctxt->dict, (BASE_PTR + startPosition), len); + if (ret.name == NULL) + xmlErrMemory(ctxt); return(ret); }
@@ -3663,7 +3504,7 @@ xmlParseNCName(xmlParserCtxtPtr ctxt) { ctxt->input->cur = in; ctxt->input->col += count; if (ret.name == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); } return(ret); } @@ -3690,8 +3531,6 @@ xmlParseNameAndCompare(xmlParserCtxtPtr ctxt, xmlChar const *other) { const xmlChar *ret;
GROW; - if (ctxt->instate == XML_PARSER_EOF) - return(NULL);
in = ctxt->input->cur; while (*in != 0 && *in == *cmp) { @@ -3734,6 +3573,7 @@ xmlParseNameAndCompare(xmlParserCtxtPtr ctxt, xmlChar const *other) { static xmlChar * xmlParseStringName(xmlParserCtxtPtr ctxt, const xmlChar** str) { xmlChar buf[XML_MAX_NAMELEN + 5]; + xmlChar *ret; const xmlChar *cur = *str; int len = 0, l; int c; @@ -3763,7 +3603,7 @@ xmlParseStringName(xmlParserCtxtPtr ctxt, const xmlChar** str) {
buffer = (xmlChar *) xmlMallocAtomic(max); if (buffer == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); return(NULL); } memcpy(buffer, buf, len); @@ -3774,7 +3614,7 @@ xmlParseStringName(xmlParserCtxtPtr ctxt, const xmlChar** str) { max *= 2; tmp = (xmlChar *) xmlRealloc(buffer, max); if (tmp == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); xmlFree(buffer); return(NULL); } @@ -3799,7 +3639,10 @@ xmlParseStringName(xmlParserCtxtPtr ctxt, const xmlChar** str) { return(NULL); } *str = cur; - return(xmlStrndup(buf, len)); + ret = xmlStrndup(buf, len); + if (ret == NULL) + xmlErrMemory(ctxt); + return(ret); }
/** @@ -3820,6 +3663,7 @@ xmlParseStringName(xmlParserCtxtPtr ctxt, const xmlChar** str) { xmlChar * xmlParseNmtoken(xmlParserCtxtPtr ctxt) { xmlChar buf[XML_MAX_NAMELEN + 5]; + xmlChar *ret; int len = 0, l; int c; int maxLength = (ctxt->options & XML_PARSE_HUGE) ? @@ -3842,7 +3686,7 @@ xmlParseNmtoken(xmlParserCtxtPtr ctxt) {
buffer = (xmlChar *) xmlMallocAtomic(max); if (buffer == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); return(NULL); } memcpy(buffer, buf, len); @@ -3853,7 +3697,7 @@ xmlParseNmtoken(xmlParserCtxtPtr ctxt) { max *= 2; tmp = (xmlChar *) xmlRealloc(buffer, max); if (tmp == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); xmlFree(buffer); return(NULL); } @@ -3869,436 +3713,820 @@ xmlParseNmtoken(xmlParserCtxtPtr ctxt) { c = CUR_CHAR(l); } buffer[len] = 0; - if (ctxt->instate == XML_PARSER_EOF) { - xmlFree(buffer); - return(NULL); - } return(buffer); } } - if (ctxt->instate == XML_PARSER_EOF) - return(NULL); if (len == 0) return(NULL); if (len > maxLength) { xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "NmToken"); return(NULL); } - return(xmlStrndup(buf, len)); + ret = xmlStrndup(buf, len); + if (ret == NULL) + xmlErrMemory(ctxt); + return(ret); }
/** - * xmlParseEntityValue: - * @ctxt: an XML parser context - * @orig: if non-NULL store a copy of the original entity value - * - * DEPRECATED: Internal function, don't use. - * - * parse a value for ENTITY declarations - * - * [9] EntityValue ::= '"' ([^%&"] | PEReference | Reference)* '"' | - * "'" ([^%&'] | PEReference | Reference)* "'" + * xmlExpandPEsInEntityValue: + * @ctxt: parser context + * @buf: string buffer + * @str: entity value + * @length: size of entity value + * @depth: nesting depth * - * Returns the EntityValue parsed with reference substituted or NULL + * Validate an entity value and expand parameter entities. */ - -xmlChar * -xmlParseEntityValue(xmlParserCtxtPtr ctxt, xmlChar **orig) { - xmlChar *buf = NULL; - int len = 0; - int size = XML_PARSER_BUFFER_SIZE; +static void +xmlExpandPEsInEntityValue(xmlParserCtxtPtr ctxt, xmlSBuf *buf, + const xmlChar *str, int length, int depth) { + int maxDepth = (ctxt->options & XML_PARSE_HUGE) ? 40 : 20; + const xmlChar *end, *chunk; int c, l; - int maxLength = (ctxt->options & XML_PARSE_HUGE) ? - XML_MAX_HUGE_LENGTH : - XML_MAX_TEXT_LENGTH; - 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); - if (buf == NULL) { - xmlErrMemory(ctxt, NULL); - return(NULL); - } + if (str == NULL) + return;
- /* - * The content of the entity definition is copied in a buffer. - */ + depth += 1; + if (depth > maxDepth) { + xmlFatalErrMsg(ctxt, XML_ERR_RESOURCE_LIMIT, + "Maximum entity nesting depth exceeded"); + return; + }
- ctxt->instate = XML_PARSER_ENTITY_VALUE; - input = ctxt->input; - GROW; - if (ctxt->instate == XML_PARSER_EOF) - goto error; - 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))) && (ctxt->instate != XML_PARSER_EOF)) { - if (len + 5 >= size) { - xmlChar *tmp; + end = str + length; + chunk = str;
- size *= 2; - tmp = (xmlChar *) xmlRealloc(buf, size); - if (tmp == NULL) { - xmlErrMemory(ctxt, NULL); - goto error; - } - buf = tmp; - } - COPY_BUF(buf, len, c); - NEXTL(l); + while ((str < end) && (!PARSER_STOPPED(ctxt))) { + c = *str;
- GROW; - c = CUR_CHAR(l); - if (c == 0) { - GROW; - c = CUR_CHAR(l); - } + if (c >= 0x80) { + l = xmlUTF8MultibyteLen(ctxt, str, + "invalid character in entity value\n"); + if (l == 0) { + if (chunk < str) + xmlSBufAddString(buf, chunk, str - chunk); + xmlSBufAddReplChar(buf); + str += 1; + chunk = str; + } else { + str += l; + } + } else if (c == '&') { + if (str[1] == '#') { + if (chunk < str) + xmlSBufAddString(buf, chunk, str - chunk);
- if (len > maxLength) { - xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_NOT_FINISHED, - "entity value too long\n"); - goto error; + c = xmlParseStringCharRef(ctxt, &str); + if (c == 0) + return; + + xmlSBufAddChar(buf, c); + + chunk = str; + } else { + xmlChar *name; + + /* + * General entity references are checked for + * syntactic validity. + */ + str++; + name = xmlParseStringName(ctxt, &str); + + if ((name == NULL) || (*str++ != ';')) { + xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_CHAR_ERROR, + "EntityValue: '&' forbidden except for entities " + "references\n"); + xmlFree(name); + return; + } + + xmlFree(name); + } + } else if (c == '%') { + xmlEntityPtr ent; + + if (chunk < str) + xmlSBufAddString(buf, chunk, str - chunk); + + ent = xmlParseStringPEReference(ctxt, &str); + if (ent == NULL) + return; + + if (!PARSER_EXTERNAL(ctxt)) { + xmlFatalErr(ctxt, XML_ERR_ENTITY_PE_INTERNAL, NULL); + return; + } + + if (ent->content == NULL) { + /* + * Note: external parsed entities will not be loaded, + * it is not required for a non-validating parser to + * complete external PEReferences coming from the + * internal subset + */ + if (((ctxt->options & XML_PARSE_NO_XXE) == 0) && + ((ctxt->replaceEntities) || + (ctxt->validate))) { + xmlLoadEntityContent(ctxt, ent); + } else { + xmlWarningMsg(ctxt, XML_ERR_ENTITY_PROCESSING, + "not validating will not read content for " + "PE entity %s\n", ent->name, NULL); + } + } + + /* + * TODO: Skip if ent->content is still NULL. + */ + + if (xmlParserEntityCheck(ctxt, ent->length)) + return; + + if (ent->flags & XML_ENT_EXPANDING) { + xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL); + xmlHaltParser(ctxt); + return; + } + + ent->flags |= XML_ENT_EXPANDING; + xmlExpandPEsInEntityValue(ctxt, buf, ent->content, ent->length, + depth); + ent->flags &= ~XML_ENT_EXPANDING; + + chunk = str; + } else { + /* Normal ASCII char */ + if (!IS_BYTE_CHAR(c)) { + xmlFatalErrMsg(ctxt, XML_ERR_INVALID_CHAR, + "invalid character in entity value\n"); + if (chunk < str) + xmlSBufAddString(buf, chunk, str - chunk); + xmlSBufAddReplChar(buf); + str += 1; + chunk = str; + } else { + str += 1; + } } } - buf[len] = 0; - if (ctxt->instate == XML_PARSER_EOF) - goto error; - if (c != stop) { - xmlFatalErr(ctxt, XML_ERR_ENTITY_NOT_FINISHED, NULL); - goto error; + + if (chunk < str) + xmlSBufAddString(buf, chunk, str - chunk); + + return; +} + +/** + * xmlParseEntityValue: + * @ctxt: an XML parser context + * @orig: if non-NULL store a copy of the original entity value + * + * DEPRECATED: Internal function, don't use. + * + * parse a value for ENTITY declarations + * + * [9] EntityValue ::= '"' ([^%&"] | PEReference | Reference)* '"' | + * "'" ([^%&'] | PEReference | Reference)* "'" + * + * Returns the EntityValue parsed with reference substituted or NULL + */ +xmlChar * +xmlParseEntityValue(xmlParserCtxtPtr ctxt, xmlChar **orig) { + unsigned maxLength = (ctxt->options & XML_PARSE_HUGE) ? + XML_MAX_HUGE_LENGTH : + XML_MAX_TEXT_LENGTH; + xmlSBuf buf; + const xmlChar *start; + int quote, length; + + xmlSBufInit(&buf, maxLength); + + GROW; + + quote = CUR; + if ((quote != '"') && (quote != ''')) { + xmlFatalErr(ctxt, XML_ERR_ATTRIBUTE_NOT_STARTED, NULL); + return(NULL); } - NEXT; + CUR_PTR++; + + length = 0;
/* - * Raise problem w.r.t. '&' and '%' being used in non-entities - * reference constructs. Note Charref will be handled in - * xmlStringDecodeEntities() + * Copy raw content of the entity into a buffer */ - cur = buf; - while (*cur != 0) { /* non input consuming */ - if ((*cur == '%') || ((*cur == '&') && (cur[1] != '#'))) { - xmlChar *name; - xmlChar tmp = *cur; - int nameOk = 0; + while (1) { + int c;
- cur++; - name = xmlParseStringName(ctxt, &cur); - if (name != NULL) { - nameOk = 1; - xmlFree(name); - } - if ((nameOk == 0) || (*cur != ';')) { - xmlFatalErrMsgInt(ctxt, XML_ERR_ENTITY_CHAR_ERROR, - "EntityValue: '%c' forbidden except for entities references\n", - tmp); - goto error; - } - if ((tmp == '%') && (ctxt->inSubset == 1) && - (ctxt->inputNr == 1)) { - xmlFatalErr(ctxt, XML_ERR_ENTITY_PE_INTERNAL, NULL); - goto error; - } - if (*cur == 0) - break; - } - cur++; + if (PARSER_STOPPED(ctxt)) + goto error; + + if (CUR_PTR >= ctxt->input->end) { + xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_NOT_FINISHED, NULL); + goto error; + } + + c = CUR; + + if (c == 0) { + xmlFatalErrMsg(ctxt, XML_ERR_INVALID_CHAR, + "invalid character in entity value\n"); + goto error; + } + if (c == quote) + break; + NEXTL(1); + length += 1; + + /* + * TODO: Check growth threshold + */ + if (ctxt->input->end - CUR_PTR < 10) + GROW; }
- /* - * Then PEReference entities are substituted. - * - * 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. - */ - ++ctxt->depth; - ret = xmlStringDecodeEntitiesInt(ctxt, buf, len, XML_SUBSTITUTE_PEREF, - 0, 0, 0, /* check */ 1); - --ctxt->depth; + start = CUR_PTR - length;
if (orig != NULL) { - *orig = buf; - buf = NULL; + *orig = xmlStrndup(start, length); + if (*orig == NULL) + xmlErrMemory(ctxt); }
+ xmlExpandPEsInEntityValue(ctxt, &buf, start, length, ctxt->inputNr); + + NEXTL(1); + + return(xmlSBufFinish(&buf, NULL, ctxt, "entity length too long")); + error: - if (buf != NULL) - xmlFree(buf); - return(ret); + xmlSBufCleanup(&buf, ctxt, "entity length too long"); + return(NULL); }
/** - * xmlParseAttValueComplex: - * @ctxt: an XML parser context - * @len: the resulting attribute len - * @normalize: whether 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. + * xmlCheckEntityInAttValue: + * @ctxt: parser context + * @pent: entity + * @depth: nesting depth * - * Returns the AttValue parsed or NULL. The value has to be freed by the caller. + * Check an entity reference in an attribute value for validity + * without expanding it. */ -static xmlChar * -xmlParseAttValueComplex(xmlParserCtxtPtr ctxt, int *attlen, int normalize) { - xmlChar limit = 0; - xmlChar *buf = NULL; - xmlChar *rep = NULL; - size_t len = 0; - size_t buf_size = 0; - size_t maxLength = (ctxt->options & XML_PARSE_HUGE) ? - XML_MAX_HUGE_LENGTH : - XML_MAX_TEXT_LENGTH; - int c, l, in_space = 0; - xmlChar *current = NULL; - xmlEntityPtr ent; +static void +xmlCheckEntityInAttValue(xmlParserCtxtPtr ctxt, xmlEntityPtr pent, int depth) { + int maxDepth = (ctxt->options & XML_PARSE_HUGE) ? 40 : 20; + const xmlChar *str; + unsigned long expandedSize = pent->length; + int c, flags; + + depth += 1; + if (depth > maxDepth) { + xmlFatalErrMsg(ctxt, XML_ERR_RESOURCE_LIMIT, + "Maximum entity nesting depth exceeded"); + return; + }
- 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); + if (pent->flags & XML_ENT_EXPANDING) { + xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL); + xmlHaltParser(ctxt); + return; }
/* - * allocate a translation buffer. + * If we're parsing a default attribute value in DTD content, + * the entity might reference other entities which weren't + * defined yet, so the check isn't reliable. */ - buf_size = XML_PARSER_BUFFER_SIZE; - buf = (xmlChar *) xmlMallocAtomic(buf_size); - if (buf == NULL) goto mem_error; + if (ctxt->inSubset == 0) + flags = XML_ENT_CHECKED | XML_ENT_VALIDATED; + else + flags = XML_ENT_VALIDATED; + + str = pent->content; + if (str == NULL) + goto done;
/* - * OK loop until we reach one of the ending char or a size limit. + * Note that entity values are already validated. We only check + * for illegal less-than signs and compute the expanded size + * of the entity. No special handling for multi-byte characters + * is needed. */ - c = CUR_CHAR(l); - while (((NXT(0) != limit) && /* checked */ - (IS_CHAR(c)) && (c != '<')) && - (ctxt->instate != XML_PARSER_EOF)) { - if (c == '&') { - in_space = 0; - if (NXT(1) == '#') { - int val = xmlParseCharRef(ctxt); - - if (val == '&') { - if (ctxt->replaceEntities) { - if (len + 10 > buf_size) { - growBuffer(buf, 10); - } - buf[len++] = '&'; - } else { - /* - * The reparsing will be done in xmlStringGetNodeList() - * called by the attribute() function in SAX.c - */ - if (len + 10 > buf_size) { - growBuffer(buf, 10); - } - buf[len++] = '&'; - buf[len++] = '#'; - buf[len++] = '3'; - buf[len++] = '8'; - buf[len++] = ';'; - } - } else if (val != 0) { - if (len + 10 > buf_size) { - growBuffer(buf, 10); - } - len += xmlCopyChar(0, &buf[len], val); - } - } else { - ent = xmlParseEntityRef(ctxt); - if ((ent != NULL) && - (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) { - if (len + 10 > buf_size) { - growBuffer(buf, 10); - } - 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)) { - if (ent->etype != XML_INTERNAL_PREDEFINED_ENTITY) { - if (xmlParserEntityCheck(ctxt, ent->length)) - goto error; + while (!PARSER_STOPPED(ctxt)) { + c = *str;
- ++ctxt->depth; - rep = xmlStringDecodeEntitiesInt(ctxt, ent->content, - ent->length, XML_SUBSTITUTE_REF, 0, 0, 0, - /* check */ 1); - --ctxt->depth; - if (rep != NULL) { - current = rep; - while (*current != 0) { /* non input consuming */ - if ((*current == 0xD) || (*current == 0xA) || - (*current == 0x9)) { - buf[len++] = 0x20; - current++; - } else - buf[len++] = *current++; - if (len + 10 > buf_size) { - growBuffer(buf, 10); - } - } - xmlFree(rep); - rep = NULL; - } - } else { - if (len + 10 > buf_size) { - growBuffer(buf, 10); - } - if (ent->content != NULL) - buf[len++] = ent->content[0]; - } - } else if (ent != NULL) { - int i = xmlStrlen(ent->name); - const xmlChar *cur = ent->name; + if (c != '&') { + if (c == 0) + break;
- /* - * We also check for recursion and amplification - * when entities are not substituted. They're - * often expanded later. - */ - if ((ent->etype != XML_INTERNAL_PREDEFINED_ENTITY) && - (ent->content != NULL)) { - if ((ent->flags & XML_ENT_CHECKED) == 0) { - unsigned long oldCopy = ctxt->sizeentcopy; - - ctxt->sizeentcopy = ent->length; - - ++ctxt->depth; - rep = xmlStringDecodeEntitiesInt(ctxt, - ent->content, ent->length, - XML_SUBSTITUTE_REF, 0, 0, 0, - /* check */ 1); - --ctxt->depth; - - /* - * If we're parsing DTD content, the entity - * might reference other entities which - * weren't defined yet, so the check isn't - * reliable. - */ - if (ctxt->inSubset == 0) { - ent->flags |= XML_ENT_CHECKED; - ent->expandedSize = ctxt->sizeentcopy; - } + if (c == '<') + xmlFatalErrMsgStr(ctxt, XML_ERR_LT_IN_ATTRIBUTE, + "'<' in entity '%s' is not allowed in attributes " + "values\n", pent->name);
- if (rep != NULL) { - xmlFree(rep); - rep = NULL; - } else { - ent->content[0] = 0; - } + str += 1; + } else if (str[1] == '#') { + int val;
- if (xmlParserEntityCheck(ctxt, oldCopy)) - goto error; - } else { - if (xmlParserEntityCheck(ctxt, ent->expandedSize)) - goto error; - } - } + val = xmlParseStringCharRef(ctxt, &str); + if (val == 0) { + pent->content[0] = 0; + break; + } + } else { + xmlChar *name; + xmlEntityPtr ent;
- /* - * Just output the reference - */ - buf[len++] = '&'; - while (len + i + 10 > buf_size) { - growBuffer(buf, i + 10); - } - for (;i > 0;i--) - buf[len++] = *cur++; - buf[len++] = ';'; - } - } + name = xmlParseStringEntityRef(ctxt, &str); + if (name == NULL) { + pent->content[0] = 0; + break; + } + + ent = xmlLookupGeneralEntity(ctxt, name, /* inAttr */ 1); + xmlFree(name); + + if ((ent != NULL) && + (ent->etype != XML_INTERNAL_PREDEFINED_ENTITY)) { + if ((ent->flags & flags) != flags) { + pent->flags |= XML_ENT_EXPANDING; + xmlCheckEntityInAttValue(ctxt, ent, depth); + pent->flags &= ~XML_ENT_EXPANDING; + } + + xmlSaturatedAdd(&expandedSize, ent->expandedSize); + xmlSaturatedAdd(&expandedSize, XML_ENT_FIXED_COST); + } + } + } + +done: + if (ctxt->inSubset == 0) + pent->expandedSize = expandedSize; + + pent->flags |= flags; +} + +/** + * xmlExpandEntityInAttValue: + * @ctxt: parser context + * @buf: string buffer + * @str: entity or attribute value + * @pent: entity for entity value, NULL for attribute values + * @normalize: whether to collapse whitespace + * @inSpace: whitespace state + * @depth: nesting depth + * @check: whether to check for amplification + * + * Expand general entity references in an entity or attribute value. + * Perform attribute value normalization. + */ +static void +xmlExpandEntityInAttValue(xmlParserCtxtPtr ctxt, xmlSBuf *buf, + const xmlChar *str, xmlEntityPtr pent, int normalize, + int *inSpace, int depth, int check) { + int maxDepth = (ctxt->options & XML_PARSE_HUGE) ? 40 : 20; + int c, chunkSize; + + if (str == NULL) + return; + + depth += 1; + if (depth > maxDepth) { + xmlFatalErrMsg(ctxt, XML_ERR_RESOURCE_LIMIT, + "Maximum entity nesting depth exceeded"); + return; + } + + if (pent != NULL) { + if (pent->flags & XML_ENT_EXPANDING) { + xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL); + xmlHaltParser(ctxt); + return; + } + + if (check) { + if (xmlParserEntityCheck(ctxt, pent->length)) + return; + } + } + + chunkSize = 0; + + /* + * Note that entity values are already validated. No special + * handling for multi-byte characters is needed. + */ + while (!PARSER_STOPPED(ctxt)) { + c = *str; + + if (c != '&') { + if (c == 0) + break; + + /* + * If this function is called without an entity, it is used to + * expand entities in an attribute content where less-than was + * already unscaped and is allowed. + */ + if ((pent != NULL) && (c == '<')) { + xmlFatalErrMsgStr(ctxt, XML_ERR_LT_IN_ATTRIBUTE, + "'<' in entity '%s' is not allowed in attributes " + "values\n", pent->name); + break; + } + + if (c <= 0x20) { + if ((normalize) && (*inSpace)) { + /* Skip char */ + if (chunkSize > 0) { + xmlSBufAddString(buf, str - chunkSize, chunkSize); + chunkSize = 0; + } + } else if (c < 0x20) { + if (chunkSize > 0) { + xmlSBufAddString(buf, str - chunkSize, chunkSize); + chunkSize = 0; + } + + xmlSBufAddCString(buf, " ", 1); + } else { + chunkSize += 1; + } + + *inSpace = 1; + } else { + chunkSize += 1; + *inSpace = 0; + } + + str += 1; + } else if (str[1] == '#') { + int val; + + if (chunkSize > 0) { + xmlSBufAddString(buf, str - chunkSize, chunkSize); + chunkSize = 0; + } + + val = xmlParseStringCharRef(ctxt, &str); + if (val == 0) { + if (pent != NULL) + pent->content[0] = 0; + break; + } + + if (val == ' ') { + if ((!normalize) || (!*inSpace)) + xmlSBufAddCString(buf, " ", 1); + *inSpace = 1; + } else { + xmlSBufAddChar(buf, val); + *inSpace = 0; + } } else { - if ((c == 0x20) || (c == 0xD) || (c == 0xA) || (c == 0x9)) { - if ((len != 0) || (!normalize)) { - if ((!normalize) || (!in_space)) { - COPY_BUF(buf, len, 0x20); - while (len + 10 > buf_size) { - growBuffer(buf, 10); - } - } - in_space = 1; - } - } else { - in_space = 0; - COPY_BUF(buf, len, c); - if (len + 10 > buf_size) { - growBuffer(buf, 10); - } + xmlChar *name; + xmlEntityPtr ent; + + if (chunkSize > 0) { + xmlSBufAddString(buf, str - chunkSize, chunkSize); + chunkSize = 0; + } + + name = xmlParseStringEntityRef(ctxt, &str); + if (name == NULL) { + if (pent != NULL) + pent->content[0] = 0; + break; + } + + ent = xmlLookupGeneralEntity(ctxt, name, /* inAttr */ 1); + xmlFree(name); + + if ((ent != NULL) && + (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) { + if (ent->content == NULL) { + xmlFatalErrMsg(ctxt, XML_ERR_INTERNAL_ERROR, + "predefined entity has no content\n"); + break; + } + + xmlSBufAddString(buf, ent->content, ent->length); + + *inSpace = 0; + } else if ((ent != NULL) && (ent->content != NULL)) { + if (pent != NULL) + pent->flags |= XML_ENT_EXPANDING; + xmlExpandEntityInAttValue(ctxt, buf, ent->content, ent, + normalize, inSpace, depth, check); + if (pent != NULL) + pent->flags &= ~XML_ENT_EXPANDING; } - NEXTL(l); - } - GROW; - c = CUR_CHAR(l); - if (len > maxLength) { - xmlFatalErrMsg(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED, - "AttValue length too long\n"); - goto mem_error; } } - if (ctxt->instate == XML_PARSER_EOF) - goto error;
- if ((in_space) && (normalize)) { - while ((len > 0) && (buf[len - 1] == 0x20)) len--; + if (chunkSize > 0) + xmlSBufAddString(buf, str - chunkSize, chunkSize); + + return; +} + +/** + * xmlExpandEntitiesInAttValue: + * @ctxt: parser context + * @str: entity or attribute value + * @normalize: whether to collapse whitespace + * + * Expand general entity references in an entity or attribute value. + * Perform attribute value normalization. + * + * Returns the expanded attribtue value. + */ +xmlChar * +xmlExpandEntitiesInAttValue(xmlParserCtxtPtr ctxt, const xmlChar *str, + int normalize) { + unsigned maxLength = (ctxt->options & XML_PARSE_HUGE) ? + XML_MAX_HUGE_LENGTH : + XML_MAX_TEXT_LENGTH; + xmlSBuf buf; + int inSpace = 1; + + xmlSBufInit(&buf, maxLength); + + xmlExpandEntityInAttValue(ctxt, &buf, str, NULL, normalize, &inSpace, + ctxt->inputNr, /* check */ 0); + + if ((normalize) && (inSpace) && (buf.size > 0)) + buf.size--; + + return(xmlSBufFinish(&buf, NULL, ctxt, "AttValue length too long")); +} + +/** + * xmlParseAttValueInternal: + * @ctxt: an XML parser context + * @len: attribute len result + * @alloc: whether the attribute was reallocated as a new string + * @normalize: if 1 then further non-CDATA normalization must be done + * + * parse a value for an attribute. + * NOTE: if no normalization is needed, the routine will return pointers + * directly from the data buffer. + * + * 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 if it was copied, this can be detected by val[*len] == 0. + */ +static xmlChar * +xmlParseAttValueInternal(xmlParserCtxtPtr ctxt, int *attlen, int *alloc, + int normalize, int isNamespace) { + unsigned maxLength = (ctxt->options & XML_PARSE_HUGE) ? + XML_MAX_HUGE_LENGTH : + XML_MAX_TEXT_LENGTH; + xmlSBuf buf; + xmlChar *ret; + int c, l, quote, flags, chunkSize; + int inSpace = 1; + int replaceEntities; + + /* Always expand namespace URIs */ + replaceEntities = (ctxt->replaceEntities) || (isNamespace); + + xmlSBufInit(&buf, maxLength); + + GROW; + + quote = CUR; + if ((quote != '"') && (quote != ''')) { + xmlFatalErr(ctxt, XML_ERR_ATTRIBUTE_NOT_STARTED, NULL); + return(NULL); } - buf[len] = 0; - if (RAW == '<') { - xmlFatalErr(ctxt, XML_ERR_LT_IN_ATTRIBUTE, NULL); - } else if (RAW != limit) { - if ((c != 0) && (!IS_CHAR(c))) { - xmlFatalErrMsg(ctxt, XML_ERR_INVALID_CHAR, - "invalid character in attribute value\n"); - } else { - xmlFatalErrMsg(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED, - "AttValue: ' expected\n"); + NEXTL(1); + + if (ctxt->inSubset == 0) + flags = XML_ENT_CHECKED | XML_ENT_VALIDATED; + else + flags = XML_ENT_VALIDATED; + + inSpace = 1; + chunkSize = 0; + + while (1) { + if (PARSER_STOPPED(ctxt)) + goto error; + + if (CUR_PTR >= ctxt->input->end) { + xmlFatalErrMsg(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED, + "AttValue: ' expected\n"); + goto error; } - } else - NEXT;
- if (attlen != NULL) *attlen = len; - return(buf); + /* + * TODO: Check growth threshold + */ + if (ctxt->input->end - CUR_PTR < 10) + GROW; + + c = CUR; + + if (c >= 0x80) { + l = xmlUTF8MultibyteLen(ctxt, CUR_PTR, + "invalid character in attribute value\n"); + if (l == 0) { + if (chunkSize > 0) { + xmlSBufAddString(&buf, CUR_PTR - chunkSize, chunkSize); + chunkSize = 0; + } + xmlSBufAddReplChar(&buf); + NEXTL(1); + } else { + chunkSize += l; + NEXTL(l); + } + + inSpace = 0; + } else if (c != '&') { + if (c > 0x20) { + if (c == quote) + break; + + if (c == '<') + xmlFatalErr(ctxt, XML_ERR_LT_IN_ATTRIBUTE, NULL); + + chunkSize += 1; + inSpace = 0; + } else if (!IS_BYTE_CHAR(c)) { + xmlFatalErrMsg(ctxt, XML_ERR_INVALID_CHAR, + "invalid character in attribute value\n"); + if (chunkSize > 0) { + xmlSBufAddString(&buf, CUR_PTR - chunkSize, chunkSize); + chunkSize = 0; + } + xmlSBufAddReplChar(&buf); + inSpace = 0; + } else { + /* Whitespace */ + if ((normalize) && (inSpace)) { + /* Skip char */ + if (chunkSize > 0) { + xmlSBufAddString(&buf, CUR_PTR - chunkSize, chunkSize); + chunkSize = 0; + } + } else if (c < 0x20) { + /* Convert to space */ + if (chunkSize > 0) { + xmlSBufAddString(&buf, CUR_PTR - chunkSize, chunkSize); + chunkSize = 0; + } + + xmlSBufAddCString(&buf, " ", 1); + } else { + chunkSize += 1; + } + + inSpace = 1; + + if ((c == 0xD) && (NXT(1) == 0xA)) + CUR_PTR++; + } + + NEXTL(1); + } else if (NXT(1) == '#') { + int val; + + if (chunkSize > 0) { + xmlSBufAddString(&buf, CUR_PTR - chunkSize, chunkSize); + chunkSize = 0; + } + + val = xmlParseCharRef(ctxt); + if (val == 0) + goto error; + + if ((val == '&') && (!replaceEntities)) { + /* + * The reparsing will be done in xmlStringGetNodeList() + * called by the attribute() function in SAX.c + */ + xmlSBufAddCString(&buf, "&", 5); + inSpace = 0; + } else if (val == ' ') { + if ((!normalize) || (!inSpace)) + xmlSBufAddCString(&buf, " ", 1); + inSpace = 1; + } else { + xmlSBufAddChar(&buf, val); + inSpace = 0; + } + } else { + const xmlChar *name; + xmlEntityPtr ent; + + if (chunkSize > 0) { + xmlSBufAddString(&buf, CUR_PTR - chunkSize, chunkSize); + chunkSize = 0; + } + + name = xmlParseEntityRefInternal(ctxt); + if (name == NULL) { + /* + * Probably a literal '&' which wasn't escaped. + * TODO: Handle gracefully in recovery mode. + */ + continue; + } + + ent = xmlLookupGeneralEntity(ctxt, name, /* isAttr */ 1); + if (ent == NULL) + continue; + + if (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY) { + if ((ent->content[0] == '&') && (!replaceEntities)) + xmlSBufAddCString(&buf, "&", 5); + else + xmlSBufAddString(&buf, ent->content, ent->length); + inSpace = 0; + } else if (replaceEntities) { + xmlExpandEntityInAttValue(ctxt, &buf, ent->content, ent, + normalize, &inSpace, ctxt->inputNr, + /* check */ 1); + } else { + if ((ent->flags & flags) != flags) + xmlCheckEntityInAttValue(ctxt, ent, ctxt->inputNr); + + if (xmlParserEntityCheck(ctxt, ent->expandedSize)) { + ent->content[0] = 0; + goto error; + } + + /* + * Just output the reference + */ + xmlSBufAddCString(&buf, "&", 1); + xmlSBufAddString(&buf, ent->name, xmlStrlen(ent->name)); + xmlSBufAddCString(&buf, ";", 1); + + inSpace = 0; + } + } + } + + if ((buf.mem == NULL) && (alloc != NULL)) { + ret = (xmlChar *) CUR_PTR - chunkSize; + + if (attlen != NULL) + *attlen = chunkSize; + if ((normalize) && (inSpace) && (chunkSize > 0)) + *attlen -= 1; + *alloc = 0; + + /* Report potential error */ + xmlSBufCleanup(&buf, ctxt, "AttValue length too long"); + } else { + if (chunkSize > 0) + xmlSBufAddString(&buf, CUR_PTR - chunkSize, chunkSize); + + if ((normalize) && (inSpace) && (buf.size > 0)) + buf.size--; + + ret = xmlSBufFinish(&buf, attlen, ctxt, "AttValue length too long"); + + if (ret != NULL) { + if (attlen != NULL) + *attlen = buf.size; + if (alloc != NULL) + *alloc = 1; + } + } + + NEXTL(1); + + return(ret);
-mem_error: - xmlErrMemory(ctxt, NULL); error: - if (buf != NULL) - xmlFree(buf); - if (rep != NULL) - xmlFree(rep); + xmlSBufCleanup(&buf, ctxt, "AttValue length too long"); return(NULL); }
@@ -4341,7 +4569,7 @@ error: xmlChar * xmlParseAttValue(xmlParserCtxtPtr ctxt) { if ((ctxt == NULL) || (ctxt->input == NULL)) return(NULL); - return(xmlParseAttValueInternal(ctxt, NULL, NULL, 0)); + return(xmlParseAttValueInternal(ctxt, NULL, NULL, 0, 0)); }
/** @@ -4367,7 +4595,6 @@ xmlParseSystemLiteral(xmlParserCtxtPtr ctxt) { XML_MAX_TEXT_LENGTH : XML_MAX_NAME_LENGTH; xmlChar stop; - int state = ctxt->instate;
if (RAW == '"') { NEXT; @@ -4382,10 +4609,9 @@ xmlParseSystemLiteral(xmlParserCtxtPtr ctxt) {
buf = (xmlChar *) xmlMallocAtomic(size); if (buf == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); return(NULL); } - ctxt->instate = XML_PARSER_SYSTEM_LITERAL; cur = CUR_CHAR(l); while ((IS_CHAR(cur)) && (cur != stop)) { /* checked */ if (len + 5 >= size) { @@ -4395,8 +4621,7 @@ xmlParseSystemLiteral(xmlParserCtxtPtr ctxt) { tmp = (xmlChar *) xmlRealloc(buf, size); if (tmp == NULL) { xmlFree(buf); - xmlErrMemory(ctxt, NULL); - ctxt->instate = (xmlParserInputState) state; + xmlErrMemory(ctxt); return(NULL); } buf = tmp; @@ -4405,18 +4630,12 @@ xmlParseSystemLiteral(xmlParserCtxtPtr ctxt) { if (len > maxLength) { xmlFatalErr(ctxt, XML_ERR_NAME_TOO_LONG, "SystemLiteral"); xmlFree(buf); - ctxt->instate = (xmlParserInputState) state; return(NULL); } NEXTL(l); cur = CUR_CHAR(l); } buf[len] = 0; - if (ctxt->instate == XML_PARSER_EOF) { - xmlFree(buf); - return(NULL); - } - ctxt->instate = (xmlParserInputState) state; if (!IS_CHAR(cur)) { xmlFatalErr(ctxt, XML_ERR_LITERAL_NOT_FINISHED, NULL); } else { @@ -4448,7 +4667,6 @@ xmlParsePubidLiteral(xmlParserCtxtPtr ctxt) { XML_MAX_NAME_LENGTH; xmlChar cur; xmlChar stop; - xmlParserInputState oldstate = ctxt->instate;
if (RAW == '"') { NEXT; @@ -4462,19 +4680,19 @@ xmlParsePubidLiteral(xmlParserCtxtPtr ctxt) { } buf = (xmlChar *) xmlMallocAtomic(size); if (buf == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); return(NULL); } - ctxt->instate = XML_PARSER_PUBLIC_LITERAL; cur = CUR; - while ((IS_PUBIDCHAR_CH(cur)) && (cur != stop)) { /* checked */ + while ((IS_PUBIDCHAR_CH(cur)) && (cur != stop) && + (PARSER_STOPPED(ctxt) == 0)) { /* checked */ if (len + 1 >= size) { xmlChar *tmp;
size *= 2; tmp = (xmlChar *) xmlRealloc(buf, size); if (tmp == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); xmlFree(buf); return(NULL); } @@ -4490,16 +4708,11 @@ xmlParsePubidLiteral(xmlParserCtxtPtr ctxt) { cur = CUR; } buf[len] = 0; - if (ctxt->instate == XML_PARSER_EOF) { - xmlFree(buf); - return(NULL); - } if (cur != stop) { xmlFatalErr(ctxt, XML_ERR_LITERAL_NOT_FINISHED, NULL); } else { NEXTL(1); } - ctxt->instate = oldstate; return(buf); }
@@ -4630,8 +4843,7 @@ get_more: if (*in == ']') { if ((in[1] == ']') && (in[2] == '>')) { xmlFatalErr(ctxt, XML_ERR_MISPLACED_CDATA_END, NULL); - if (ctxt->instate != XML_PARSER_EOF) - ctxt->input->cur = in + 1; + ctxt->input->cur = in + 1; return; } in++; @@ -4669,8 +4881,6 @@ get_more: line = ctxt->input->line; col = ctxt->input->col; } - if (ctxt->instate == XML_PARSER_EOF) - return; } ctxt->input->cur = in; if (*in == 0xD) { @@ -4691,8 +4901,6 @@ get_more: } SHRINK; GROW; - if (ctxt->instate == XML_PARSER_EOF) - return; in = ctxt->input->cur; } while (((*in >= 0x20) && (*in <= 0x7F)) || (*in == 0x09) || (*in == 0x0a)); @@ -4749,15 +4957,10 @@ xmlParseCharDataComplex(xmlParserCtxtPtr ctxt, int partial) { } } nbchar = 0; - /* something really bad happened in the SAX callback */ - if (ctxt->instate != XML_PARSER_CONTENT) - return; SHRINK; } cur = CUR_CHAR(l); } - if (ctxt->instate == XML_PARSER_EOF) - return; if (nbchar != 0) { buf[nbchar] = 0; /* @@ -4779,9 +4982,8 @@ xmlParseCharDataComplex(xmlParserCtxtPtr ctxt, int partial) { /* * cur == 0 can mean * - * - XML_PARSER_EOF or memory error. This is checked above. - * - An actual 0 character. * - End of buffer. + * - An actual 0 character. * - An incomplete UTF-8 sequence. This is allowed if partial is set. */ if (ctxt->input->cur < ctxt->input->end) { @@ -4910,16 +5112,13 @@ xmlParseCommentComplex(xmlParserCtxtPtr ctxt, xmlChar *buf, size_t maxLength = (ctxt->options & XML_PARSE_HUGE) ? XML_MAX_HUGE_LENGTH : XML_MAX_TEXT_LENGTH; - int inputid; - - inputid = ctxt->input->id;
if (buf == NULL) { len = 0; size = XML_PARSER_BUFFER_SIZE; buf = (xmlChar *) xmlMallocAtomic(size); if (buf == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); return; } } @@ -4962,7 +5161,7 @@ xmlParseCommentComplex(xmlParserCtxtPtr ctxt, xmlChar *buf, new_buf = (xmlChar *) xmlRealloc(buf, new_size); if (new_buf == NULL) { xmlFree (buf); - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); return; } buf = new_buf; @@ -4986,10 +5185,6 @@ xmlParseCommentComplex(xmlParserCtxtPtr ctxt, xmlChar *buf,
} buf[len] = 0; - if (ctxt->instate == XML_PARSER_EOF) { - xmlFree(buf); - return; - } if (cur == 0) { xmlFatalErrMsgStr(ctxt, XML_ERR_COMMENT_NOT_FINISHED, "Comment not terminated \n<!--%.50s\n", buf); @@ -4998,11 +5193,6 @@ xmlParseCommentComplex(xmlParserCtxtPtr ctxt, xmlChar *buf, "xmlParseComment: invalid xmlChar value %d\n", cur); } else { - if (inputid != ctxt->input->id) { - xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY, - "Comment doesn't start and stop in the same" - " entity\n"); - } NEXT; if ((ctxt->sax != NULL) && (ctxt->sax->comment != NULL) && (!ctxt->disableSAX)) @@ -5038,11 +5228,9 @@ xmlParseComment(xmlParserCtxtPtr ctxt) { size_t maxLength = (ctxt->options & XML_PARSE_HUGE) ? XML_MAX_HUGE_LENGTH : XML_MAX_TEXT_LENGTH; - xmlParserInputState state; const xmlChar *in; size_t nbchar = 0; int ccol; - int inputid;
/* * Check that there is a comment right here. @@ -5052,9 +5240,6 @@ xmlParseComment(xmlParserCtxtPtr ctxt) { SKIP(2); if ((RAW != '-') || (NXT(1) != '-')) return; - state = ctxt->instate; - ctxt->instate = XML_PARSER_COMMENT; - inputid = ctxt->input->id; SKIP(2); GROW;
@@ -5098,8 +5283,7 @@ get_more: size = XML_PARSER_BUFFER_SIZE + nbchar; buf = (xmlChar *) xmlMallocAtomic(size); if (buf == NULL) { - xmlErrMemory(ctxt, NULL); - ctxt->instate = state; + xmlErrMemory(ctxt); return; } len = 0; @@ -5109,8 +5293,7 @@ get_more: new_buf = (xmlChar *) xmlRealloc(buf, size); if (new_buf == NULL) { xmlFree (buf); - xmlErrMemory(ctxt, NULL); - ctxt->instate = state; + xmlErrMemory(ctxt); return; } buf = new_buf; @@ -5142,19 +5325,10 @@ get_more: } SHRINK; GROW; - if (ctxt->instate == XML_PARSER_EOF) { - xmlFree(buf); - return; - } in = ctxt->input->cur; if (*in == '-') { if (in[1] == '-') { if (in[2] == '>') { - if (ctxt->input->id != inputid) { - xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY, - "comment doesn't start and stop in the" - " same entity\n"); - } SKIP(3); if ((ctxt->sax != NULL) && (ctxt->sax->comment != NULL) && (!ctxt->disableSAX)) { @@ -5165,8 +5339,6 @@ get_more: } if (buf != NULL) xmlFree(buf); - if (ctxt->instate != XML_PARSER_EOF) - ctxt->instate = state; return; } if (buf != NULL) { @@ -5177,10 +5349,6 @@ get_more: } else xmlFatalErrMsgStr(ctxt, XML_ERR_HYPHEN_IN_COMMENT, "Double hyphen within comment\n", NULL); - if (ctxt->instate == XML_PARSER_EOF) { - xmlFree(buf); - return; - } in++; ctxt->input->col++; } @@ -5190,7 +5358,6 @@ get_more: } } while (((*in >= 0x20) && (*in <= 0x7F)) || (*in == 0x09) || (*in == 0x0a)); xmlParseCommentComplex(ctxt, buf, len, size); - ctxt->instate = state; return; }
@@ -5291,6 +5458,12 @@ xmlParseCatalogPI(xmlParserCtxtPtr ctxt, const xmlChar *catalog) { goto error;
if (URL != NULL) { + /* + * Unfortunately, the catalog API doesn't report OOM errors. + * xmlGetLastError isn't very helpful since we don't know + * where the last error came from. We'd have to reset it + * before this call and restore it afterwards. + */ ctxt->catalogs = xmlCatalogAddLocal(ctxt->catalogs, URL); xmlFree(URL); } @@ -5328,12 +5501,8 @@ xmlParsePI(xmlParserCtxtPtr ctxt) { XML_MAX_TEXT_LENGTH; int cur, l; const xmlChar *target; - xmlParserInputState state;
if ((RAW == '<') && (NXT(1) == '?')) { - int inputid = ctxt->input->id; - state = ctxt->instate; - ctxt->instate = XML_PARSER_PI; /* * this is a Processing Instruction. */ @@ -5346,11 +5515,6 @@ xmlParsePI(xmlParserCtxtPtr ctxt) { target = xmlParsePITarget(ctxt); if (target != NULL) { if ((RAW == '?') && (NXT(1) == '>')) { - if (inputid != ctxt->input->id) { - xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY, - "PI declaration doesn't start and stop in" - " the same entity\n"); - } SKIP(2);
/* @@ -5360,14 +5524,11 @@ xmlParsePI(xmlParserCtxtPtr ctxt) { (ctxt->sax->processingInstruction != NULL)) ctxt->sax->processingInstruction(ctxt->userData, target, NULL); - if (ctxt->instate != XML_PARSER_EOF) - ctxt->instate = state; return; } buf = (xmlChar *) xmlMallocAtomic(size); if (buf == NULL) { - xmlErrMemory(ctxt, NULL); - ctxt->instate = state; + xmlErrMemory(ctxt); return; } if (SKIP_BLANKS == 0) { @@ -5382,9 +5543,8 @@ xmlParsePI(xmlParserCtxtPtr ctxt) { size_t new_size = size * 2; tmp = (xmlChar *) xmlRealloc(buf, new_size); if (tmp == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); xmlFree(buf); - ctxt->instate = state; return; } buf = tmp; @@ -5395,31 +5555,20 @@ xmlParsePI(xmlParserCtxtPtr ctxt) { xmlFatalErrMsgStr(ctxt, XML_ERR_PI_NOT_FINISHED, "PI %s too big found", target); xmlFree(buf); - ctxt->instate = state; return; } NEXTL(l); cur = CUR_CHAR(l); } buf[len] = 0; - if (ctxt->instate == XML_PARSER_EOF) { - xmlFree(buf); - return; - } if (cur != '?') { xmlFatalErrMsgStr(ctxt, XML_ERR_PI_NOT_FINISHED, "ParsePI: PI %s never end ...\n", target); } else { - if (inputid != ctxt->input->id) { - xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY, - "PI declaration doesn't start and stop in" - " the same entity\n"); - } SKIP(2);
#ifdef LIBXML_CATALOG_ENABLED - if (((state == XML_PARSER_MISC) || - (state == XML_PARSER_START)) && + if ((ctxt->inSubset == 0) && (xmlStrEqual(target, XML_CATALOG_PI))) { xmlCatalogAllow allow = xmlCatalogGetDefaults(); if ((allow == XML_CATA_ALLOW_DOCUMENT) || @@ -5441,8 +5590,6 @@ xmlParsePI(xmlParserCtxtPtr ctxt) { } else { xmlFatalErr(ctxt, XML_ERR_PI_NOT_STARTED, NULL); } - if (ctxt->instate != XML_PARSER_EOF) - ctxt->instate = state; } }
@@ -5477,7 +5624,7 @@ xmlParseNotationDecl(xmlParserCtxtPtr ctxt) { if (CMP8(CUR_PTR, 'N', 'O', 'T', 'A', 'T', 'I', 'O', 'N')) { int inputid = ctxt->input->id; SKIP(8); - if (SKIP_BLANKS == 0) { + if (SKIP_BLANKS_PE == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space required after '<!NOTATION'\n"); return; @@ -5493,7 +5640,7 @@ xmlParseNotationDecl(xmlParserCtxtPtr ctxt) { "colons are forbidden from notation names '%s'\n", name, NULL, NULL); } - if (SKIP_BLANKS == 0) { + if (SKIP_BLANKS_PE == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space required after the NOTATION name'\n"); return; @@ -5503,7 +5650,7 @@ xmlParseNotationDecl(xmlParserCtxtPtr ctxt) { * Parse the IDs. */ Systemid = xmlParseExternalID(ctxt, &Pubid, 0); - SKIP_BLANKS; + SKIP_BLANKS_PE;
if (RAW == '>') { if (inputid != ctxt->input->id) { @@ -5564,14 +5711,14 @@ xmlParseEntityDecl(xmlParserCtxtPtr ctxt) { if (CMP6(CUR_PTR, 'E', 'N', 'T', 'I', 'T', 'Y')) { int inputid = ctxt->input->id; SKIP(6); - if (SKIP_BLANKS == 0) { + if (SKIP_BLANKS_PE == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space required after '<!ENTITY'\n"); }
if (RAW == '%') { NEXT; - if (SKIP_BLANKS == 0) { + if (SKIP_BLANKS_PE == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space required after '%%'\n"); } @@ -5589,12 +5736,11 @@ xmlParseEntityDecl(xmlParserCtxtPtr ctxt) { "colons are forbidden from entities names '%s'\n", name, NULL, NULL); } - if (SKIP_BLANKS == 0) { + if (SKIP_BLANKS_PE == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space required after the entity name\n"); }
- ctxt->instate = XML_PARSER_ENTITY_DECL; /* * handle the various case of definitions... */ @@ -5614,34 +5760,16 @@ xmlParseEntityDecl(xmlParserCtxtPtr ctxt) { xmlFatalErr(ctxt, XML_ERR_VALUE_REQUIRED, NULL); } if (URI) { - xmlURIPtr uri; - - uri = xmlParseURI((const char *) URI); - if (uri == NULL) { - xmlErrMsgStr(ctxt, XML_ERR_INVALID_URI, - "Invalid URI: %s\n", URI); - /* - * This really ought to be a well formedness error - * but the XML Core WG decided otherwise c.f. issue - * E26 of the XML erratas. - */ - } else { - if (uri->fragment != NULL) { - /* - * Okay this is foolish to block those but not - * invalid URIs. - */ - xmlFatalErr(ctxt, XML_ERR_URI_FRAGMENT, NULL); - } else { - if ((ctxt->sax != NULL) && - (!ctxt->disableSAX) && - (ctxt->sax->entityDecl != NULL)) - ctxt->sax->entityDecl(ctxt->userData, name, - XML_EXTERNAL_PARAMETER_ENTITY, - literal, URI, NULL); - } - xmlFreeURI(uri); - } + if (xmlStrchr(URI, '#')) { + xmlFatalErr(ctxt, XML_ERR_URI_FRAGMENT, NULL); + } else { + if ((ctxt->sax != NULL) && + (!ctxt->disableSAX) && + (ctxt->sax->entityDecl != NULL)) + ctxt->sax->entityDecl(ctxt->userData, name, + XML_EXTERNAL_PARAMETER_ENTITY, + literal, URI, NULL); + } } } } else { @@ -5660,14 +5788,19 @@ xmlParseEntityDecl(xmlParserCtxtPtr ctxt) { if (ctxt->myDoc == NULL) { ctxt->myDoc = xmlNewDoc(SAX_COMPAT_MODE); if (ctxt->myDoc == NULL) { - xmlErrMemory(ctxt, "New Doc failed"); + xmlErrMemory(ctxt); goto done; } ctxt->myDoc->properties = XML_DOC_INTERNAL; } - if (ctxt->myDoc->intSubset == NULL) + if (ctxt->myDoc->intSubset == NULL) { ctxt->myDoc->intSubset = xmlNewDtd(ctxt->myDoc, BAD_CAST "fake", NULL, NULL); + if (ctxt->myDoc->intSubset == NULL) { + xmlErrMemory(ctxt); + goto done; + } + }
xmlSAX2EntityDecl(ctxt, name, XML_INTERNAL_GENERAL_ENTITY, NULL, NULL, value); @@ -5678,35 +5811,17 @@ xmlParseEntityDecl(xmlParserCtxtPtr ctxt) { xmlFatalErr(ctxt, XML_ERR_VALUE_REQUIRED, NULL); } if (URI) { - xmlURIPtr uri; - - uri = xmlParseURI((const char *)URI); - if (uri == NULL) { - xmlErrMsgStr(ctxt, XML_ERR_INVALID_URI, - "Invalid URI: %s\n", URI); - /* - * This really ought to be a well formedness error - * but the XML Core WG decided otherwise c.f. issue - * E26 of the XML erratas. - */ - } else { - if (uri->fragment != NULL) { - /* - * Okay this is foolish to block those but not - * invalid URIs. - */ - xmlFatalErr(ctxt, XML_ERR_URI_FRAGMENT, NULL); - } - xmlFreeURI(uri); - } + if (xmlStrchr(URI, '#')) { + xmlFatalErr(ctxt, XML_ERR_URI_FRAGMENT, NULL); + } } - if ((RAW != '>') && (SKIP_BLANKS == 0)) { + if ((RAW != '>') && (SKIP_BLANKS_PE == 0)) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space required before 'NDATA'\n"); } if (CMP5(CUR_PTR, 'N', 'D', 'A', 'T', 'A')) { SKIP(5); - if (SKIP_BLANKS == 0) { + if (SKIP_BLANKS_PE == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space required after 'NDATA'\n"); } @@ -5731,15 +5846,20 @@ xmlParseEntityDecl(xmlParserCtxtPtr ctxt) { if (ctxt->myDoc == NULL) { ctxt->myDoc = xmlNewDoc(SAX_COMPAT_MODE); if (ctxt->myDoc == NULL) { - xmlErrMemory(ctxt, "New Doc failed"); + xmlErrMemory(ctxt); goto done; } ctxt->myDoc->properties = XML_DOC_INTERNAL; }
- if (ctxt->myDoc->intSubset == NULL) + if (ctxt->myDoc->intSubset == NULL) { ctxt->myDoc->intSubset = xmlNewDtd(ctxt->myDoc, BAD_CAST "fake", NULL, NULL); + if (ctxt->myDoc->intSubset == NULL) { + xmlErrMemory(ctxt); + goto done; + } + } xmlSAX2EntityDecl(ctxt, name, XML_EXTERNAL_GENERAL_PARSED_ENTITY, literal, URI, NULL); @@ -5747,9 +5867,7 @@ xmlParseEntityDecl(xmlParserCtxtPtr ctxt) { } } } - if (ctxt->instate == XML_PARSER_EOF) - goto done; - SKIP_BLANKS; + SKIP_BLANKS_PE; if (RAW != '>') { xmlFatalErrMsgStr(ctxt, XML_ERR_ENTITY_NOT_FINISHED, "xmlParseEntityDecl: entity %s not terminated\n", name); @@ -5843,13 +5961,12 @@ xmlParseDefaultDecl(xmlParserCtxtPtr ctxt, xmlChar **value) { if (CMP6(CUR_PTR, '#', 'F', 'I', 'X', 'E', 'D')) { SKIP(6); val = XML_ATTRIBUTE_FIXED; - if (SKIP_BLANKS == 0) { + if (SKIP_BLANKS_PE == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space required after '#FIXED'\n"); } } ret = xmlParseAttValue(ctxt); - ctxt->instate = XML_PARSER_DTD; if (ret == NULL) { xmlFatalErrMsg(ctxt, (xmlParserErrors)ctxt->errNo, "Attribute default value declaration error\n"); @@ -5888,7 +6005,7 @@ xmlParseNotationType(xmlParserCtxtPtr ctxt) { } do { NEXT; - SKIP_BLANKS; + SKIP_BLANKS_PE; name = xmlParseName(ctxt); if (name == NULL) { xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED, @@ -5911,6 +6028,7 @@ xmlParseNotationType(xmlParserCtxtPtr ctxt) { if (tmp == NULL) { cur = xmlCreateEnumeration(name); if (cur == NULL) { + xmlErrMemory(ctxt); xmlFreeEnumeration(ret); return(NULL); } @@ -5920,7 +6038,7 @@ xmlParseNotationType(xmlParserCtxtPtr ctxt) { last = cur; } } - SKIP_BLANKS; + SKIP_BLANKS_PE; } while (RAW == '|'); if (RAW != ')') { xmlFatalErr(ctxt, XML_ERR_NOTATION_NOT_FINISHED, NULL); @@ -5959,7 +6077,7 @@ xmlParseEnumerationType(xmlParserCtxtPtr ctxt) { } do { NEXT; - SKIP_BLANKS; + SKIP_BLANKS_PE; name = xmlParseNmtoken(ctxt); if (name == NULL) { xmlFatalErr(ctxt, XML_ERR_NMTOKEN_REQUIRED, NULL); @@ -5982,6 +6100,7 @@ xmlParseEnumerationType(xmlParserCtxtPtr ctxt) { if (!xmlDictOwns(ctxt->dict, name)) xmlFree(name); if (cur == NULL) { + xmlErrMemory(ctxt); xmlFreeEnumeration(ret); return(NULL); } @@ -5991,7 +6110,7 @@ xmlParseEnumerationType(xmlParserCtxtPtr ctxt) { last = cur; } } - SKIP_BLANKS; + SKIP_BLANKS_PE; } while (RAW == '|'); if (RAW != ')') { xmlFatalErr(ctxt, XML_ERR_ATTLIST_NOT_FINISHED, NULL); @@ -6022,7 +6141,7 @@ int xmlParseEnumeratedType(xmlParserCtxtPtr ctxt, xmlEnumerationPtr *tree) { if (CMP8(CUR_PTR, 'N', 'O', 'T', 'A', 'T', 'I', 'O', 'N')) { SKIP(8); - if (SKIP_BLANKS == 0) { + if (SKIP_BLANKS_PE == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space required after 'NOTATION'\n"); return(0); @@ -6140,7 +6259,7 @@ xmlParseAttributeListDecl(xmlParserCtxtPtr ctxt) { int inputid = ctxt->input->id;
SKIP(7); - if (SKIP_BLANKS == 0) { + if (SKIP_BLANKS_PE == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space required after '<!ATTLIST'\n"); } @@ -6150,9 +6269,9 @@ xmlParseAttributeListDecl(xmlParserCtxtPtr ctxt) { "ATTLIST: no name for Element\n"); return; } - SKIP_BLANKS; + SKIP_BLANKS_PE; GROW; - while ((RAW != '>') && (ctxt->instate != XML_PARSER_EOF)) { + while ((RAW != '>') && (PARSER_STOPPED(ctxt) == 0)) { int type; int def; xmlChar *defaultValue = NULL; @@ -6166,7 +6285,7 @@ xmlParseAttributeListDecl(xmlParserCtxtPtr ctxt) { break; } GROW; - if (SKIP_BLANKS == 0) { + if (SKIP_BLANKS_PE == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space required after the attribute name\n"); break; @@ -6178,7 +6297,7 @@ xmlParseAttributeListDecl(xmlParserCtxtPtr ctxt) { }
GROW; - if (SKIP_BLANKS == 0) { + if (SKIP_BLANKS_PE == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space required after the attribute type\n"); if (tree != NULL) @@ -6199,7 +6318,7 @@ xmlParseAttributeListDecl(xmlParserCtxtPtr ctxt) {
GROW; if (RAW != '>') { - if (SKIP_BLANKS == 0) { + if (SKIP_BLANKS_PE == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space required after the attribute default value\n"); if (defaultValue != NULL) @@ -6268,7 +6387,7 @@ xmlParseElementMixedContentDecl(xmlParserCtxtPtr ctxt, int inputchk) { GROW; if (CMP7(CUR_PTR, '#', 'P', 'C', 'D', 'A', 'T', 'A')) { SKIP(7); - SKIP_BLANKS; + SKIP_BLANKS_PE; if (RAW == ')') { if (ctxt->input->id != inputchk) { xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY, @@ -6278,7 +6397,7 @@ xmlParseElementMixedContentDecl(xmlParserCtxtPtr ctxt, int inputchk) { NEXT; ret = xmlNewDocElementContent(ctxt->myDoc, NULL, XML_ELEMENT_CONTENT_PCDATA); if (ret == NULL) - return(NULL); + goto mem_error; if (RAW == '*') { ret->ocur = XML_ELEMENT_CONTENT_MULT; NEXT; @@ -6287,35 +6406,29 @@ xmlParseElementMixedContentDecl(xmlParserCtxtPtr ctxt, int inputchk) { } if ((RAW == '(') || (RAW == '|')) { ret = cur = xmlNewDocElementContent(ctxt->myDoc, NULL, XML_ELEMENT_CONTENT_PCDATA); - if (ret == NULL) return(NULL); + if (ret == NULL) + goto mem_error; } - while ((RAW == '|') && (ctxt->instate != XML_PARSER_EOF)) { + while ((RAW == '|') && (PARSER_STOPPED(ctxt) == 0)) { NEXT; + n = xmlNewDocElementContent(ctxt->myDoc, NULL, XML_ELEMENT_CONTENT_OR); + if (n == NULL) + goto mem_error; if (elem == NULL) { - ret = xmlNewDocElementContent(ctxt->myDoc, NULL, XML_ELEMENT_CONTENT_OR); - if (ret == NULL) { - xmlFreeDocElementContent(ctxt->myDoc, cur); - return(NULL); - } - ret->c1 = cur; + n->c1 = cur; if (cur != NULL) - cur->parent = ret; - cur = ret; + cur->parent = n; + ret = cur = n; } else { - n = xmlNewDocElementContent(ctxt->myDoc, NULL, XML_ELEMENT_CONTENT_OR); - if (n == NULL) { - xmlFreeDocElementContent(ctxt->myDoc, ret); - return(NULL); - } - n->c1 = xmlNewDocElementContent(ctxt->myDoc, elem, XML_ELEMENT_CONTENT_ELEMENT); - if (n->c1 != NULL) - n->c1->parent = n; cur->c2 = n; - if (n != NULL) - n->parent = cur; + n->parent = cur; + n->c1 = xmlNewDocElementContent(ctxt->myDoc, elem, XML_ELEMENT_CONTENT_ELEMENT); + if (n->c1 == NULL) + goto mem_error; + n->c1->parent = n; cur = n; } - SKIP_BLANKS; + SKIP_BLANKS_PE; elem = xmlParseName(ctxt); if (elem == NULL) { xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED, @@ -6323,15 +6436,16 @@ xmlParseElementMixedContentDecl(xmlParserCtxtPtr ctxt, int inputchk) { xmlFreeDocElementContent(ctxt->myDoc, ret); return(NULL); } - SKIP_BLANKS; + SKIP_BLANKS_PE; GROW; } if ((RAW == ')') && (NXT(1) == '*')) { if (elem != NULL) { cur->c2 = xmlNewDocElementContent(ctxt->myDoc, elem, XML_ELEMENT_CONTENT_ELEMENT); - if (cur->c2 != NULL) - cur->c2->parent = cur; + if (cur->c2 == NULL) + goto mem_error; + cur->c2->parent = cur; } if (ret != NULL) ret->ocur = XML_ELEMENT_CONTENT_MULT; @@ -6351,6 +6465,11 @@ xmlParseElementMixedContentDecl(xmlParserCtxtPtr ctxt, int inputchk) { xmlFatalErr(ctxt, XML_ERR_PCDATA_REQUIRED, NULL); } return(ret); + +mem_error: + xmlErrMemory(ctxt); + xmlFreeDocElementContent(ctxt->myDoc, ret); + return(NULL); }
/** @@ -6388,30 +6507,30 @@ xmlParseElementMixedContentDecl(xmlParserCtxtPtr ctxt, int inputchk) { static xmlElementContentPtr xmlParseElementChildrenContentDeclPriv(xmlParserCtxtPtr ctxt, int inputchk, int depth) { + int maxDepth = (ctxt->options & XML_PARSE_HUGE) ? 2048 : 256; xmlElementContentPtr ret = NULL, cur = NULL, last = NULL, op = NULL; const xmlChar *elem; xmlChar type = 0;
- if (((depth > 128) && ((ctxt->options & XML_PARSE_HUGE) == 0)) || - (depth > 2048)) { - xmlFatalErrMsgInt(ctxt, XML_ERR_ELEMCONTENT_NOT_FINISHED, -"xmlParseElementChildrenContentDecl : depth %d too deep, use XML_PARSE_HUGE\n", - depth); + if (depth > maxDepth) { + xmlFatalErrMsgInt(ctxt, XML_ERR_RESOURCE_LIMIT, + "xmlParseElementChildrenContentDecl : depth %d too deep, " + "use XML_PARSE_HUGE\n", depth); return(NULL); } - SKIP_BLANKS; + SKIP_BLANKS_PE; GROW; if (RAW == '(') { int inputid = ctxt->input->id;
/* Recurse on first child */ NEXT; - SKIP_BLANKS; + SKIP_BLANKS_PE; cur = ret = xmlParseElementChildrenContentDeclPriv(ctxt, inputid, depth + 1); if (cur == NULL) return(NULL); - SKIP_BLANKS; + SKIP_BLANKS_PE; GROW; } else { elem = xmlParseName(ctxt); @@ -6421,7 +6540,7 @@ xmlParseElementChildrenContentDeclPriv(xmlParserCtxtPtr ctxt, int inputchk, } cur = ret = xmlNewDocElementContent(ctxt->myDoc, elem, XML_ELEMENT_CONTENT_ELEMENT); if (cur == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); return(NULL); } GROW; @@ -6439,8 +6558,8 @@ xmlParseElementChildrenContentDeclPriv(xmlParserCtxtPtr ctxt, int inputchk, } GROW; } - SKIP_BLANKS; - while ((RAW != ')') && (ctxt->instate != XML_PARSER_EOF)) { + SKIP_BLANKS_PE; + while ((RAW != ')') && (PARSER_STOPPED(ctxt) == 0)) { /* * Each loop we parse one separator and one element. */ @@ -6464,6 +6583,7 @@ xmlParseElementChildrenContentDeclPriv(xmlParserCtxtPtr ctxt, int inputchk,
op = xmlNewDocElementContent(ctxt->myDoc, NULL, XML_ELEMENT_CONTENT_SEQ); if (op == NULL) { + xmlErrMemory(ctxt); if ((last != NULL) && (last != ret)) xmlFreeDocElementContent(ctxt->myDoc, last); xmlFreeDocElementContent(ctxt->myDoc, ret); @@ -6504,6 +6624,7 @@ xmlParseElementChildrenContentDeclPriv(xmlParserCtxtPtr ctxt, int inputchk,
op = xmlNewDocElementContent(ctxt->myDoc, NULL, XML_ELEMENT_CONTENT_OR); if (op == NULL) { + xmlErrMemory(ctxt); if ((last != NULL) && (last != ret)) xmlFreeDocElementContent(ctxt->myDoc, last); if (ret != NULL) @@ -6534,13 +6655,13 @@ xmlParseElementChildrenContentDeclPriv(xmlParserCtxtPtr ctxt, int inputchk, return(NULL); } GROW; - SKIP_BLANKS; + SKIP_BLANKS_PE; GROW; if (RAW == '(') { int inputid = ctxt->input->id; /* Recurse on second child */ NEXT; - SKIP_BLANKS; + SKIP_BLANKS_PE; last = xmlParseElementChildrenContentDeclPriv(ctxt, inputid, depth + 1); if (last == NULL) { @@ -6548,7 +6669,7 @@ xmlParseElementChildrenContentDeclPriv(xmlParserCtxtPtr ctxt, int inputchk, xmlFreeDocElementContent(ctxt->myDoc, ret); return(NULL); } - SKIP_BLANKS; + SKIP_BLANKS_PE; } else { elem = xmlParseName(ctxt); if (elem == NULL) { @@ -6559,6 +6680,7 @@ xmlParseElementChildrenContentDeclPriv(xmlParserCtxtPtr ctxt, int inputchk, } last = xmlNewDocElementContent(ctxt->myDoc, elem, XML_ELEMENT_CONTENT_ELEMENT); if (last == NULL) { + xmlErrMemory(ctxt); if (ret != NULL) xmlFreeDocElementContent(ctxt->myDoc, ret); return(NULL); @@ -6576,7 +6698,7 @@ xmlParseElementChildrenContentDeclPriv(xmlParserCtxtPtr ctxt, int inputchk, last->ocur = XML_ELEMENT_CONTENT_ONCE; } } - SKIP_BLANKS; + SKIP_BLANKS_PE; GROW; } if ((cur != NULL) && (last != NULL)) { @@ -6728,9 +6850,7 @@ xmlParseElementContentDecl(xmlParserCtxtPtr ctxt, const xmlChar *name, } NEXT; GROW; - if (ctxt->instate == XML_PARSER_EOF) - return(-1); - SKIP_BLANKS; + SKIP_BLANKS_PE; if (CMP7(CUR_PTR, '#', 'P', 'C', 'D', 'A', 'T', 'A')) { tree = xmlParseElementMixedContentDecl(ctxt, inputid); res = XML_ELEMENT_TYPE_MIXED; @@ -6738,7 +6858,7 @@ xmlParseElementContentDecl(xmlParserCtxtPtr ctxt, const xmlChar *name, tree = xmlParseElementChildrenContentDeclPriv(ctxt, inputid, 1); res = XML_ELEMENT_TYPE_ELEMENT; } - SKIP_BLANKS; + SKIP_BLANKS_PE; *result = tree; return(res); } @@ -6773,7 +6893,7 @@ xmlParseElementDecl(xmlParserCtxtPtr ctxt) { int inputid = ctxt->input->id;
SKIP(7); - if (SKIP_BLANKS == 0) { + if (SKIP_BLANKS_PE == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space required after 'ELEMENT'\n"); return(-1); @@ -6784,7 +6904,7 @@ xmlParseElementDecl(xmlParserCtxtPtr ctxt) { "xmlParseElementDecl: no name for Element\n"); return(-1); } - if (SKIP_BLANKS == 0) { + if (SKIP_BLANKS_PE == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space required after the element name\n"); } @@ -6807,18 +6927,12 @@ xmlParseElementDecl(xmlParserCtxtPtr ctxt) { /* * [ WFC: PEs in Internal Subset ] error handling. */ - if ((RAW == '%') && (ctxt->external == 0) && - (ctxt->inputNr == 1)) { - xmlFatalErrMsg(ctxt, XML_ERR_PEREF_IN_INT_SUBSET, - "PEReference: forbidden within markup decl in internal subset\n"); - } else { - xmlFatalErrMsg(ctxt, XML_ERR_ELEMCONTENT_NOT_STARTED, - "xmlParseElementDecl: 'EMPTY', 'ANY' or '(' expected\n"); - } + xmlFatalErrMsg(ctxt, XML_ERR_ELEMCONTENT_NOT_STARTED, + "xmlParseElementDecl: 'EMPTY', 'ANY' or '(' expected\n"); return(-1); }
- SKIP_BLANKS; + SKIP_BLANKS_PE;
if (RAW != '>') { xmlFatalErr(ctxt, XML_ERR_GT_REQUIRED, NULL); @@ -6875,16 +6989,16 @@ xmlParseConditionalSections(xmlParserCtxtPtr ctxt) { size_t inputIdsSize = 0; size_t depth = 0;
- while (ctxt->instate != XML_PARSER_EOF) { + while (PARSER_STOPPED(ctxt) == 0) { if ((RAW == '<') && (NXT(1) == '!') && (NXT(2) == '[')) { int id = ctxt->input->id;
SKIP(3); - SKIP_BLANKS; + SKIP_BLANKS_PE;
if (CMP7(CUR_PTR, 'I', 'N', 'C', 'L', 'U', 'D', 'E')) { SKIP(7); - SKIP_BLANKS; + SKIP_BLANKS_PE; if (RAW != '[') { xmlFatalErr(ctxt, XML_ERR_CONDSEC_INVALID, NULL); xmlHaltParser(ctxt); @@ -6904,7 +7018,7 @@ xmlParseConditionalSections(xmlParserCtxtPtr ctxt) { tmp = (int *) xmlRealloc(inputIds, inputIdsSize * sizeof(int)); if (tmp == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); goto error; } inputIds = tmp; @@ -6915,7 +7029,7 @@ xmlParseConditionalSections(xmlParserCtxtPtr ctxt) { size_t ignoreDepth = 0;
SKIP(6); - SKIP_BLANKS; + SKIP_BLANKS_PE; if (RAW != '[') { xmlFatalErr(ctxt, XML_ERR_CONDSEC_INVALID, NULL); xmlHaltParser(ctxt); @@ -6928,36 +7042,35 @@ xmlParseConditionalSections(xmlParserCtxtPtr ctxt) { } NEXT;
- while (RAW != 0) { + while (PARSER_STOPPED(ctxt) == 0) { + if (RAW == 0) { + xmlFatalErr(ctxt, XML_ERR_CONDSEC_NOT_FINISHED, NULL); + goto error; + } if ((RAW == '<') && (NXT(1) == '!') && (NXT(2) == '[')) { SKIP(3); ignoreDepth++; /* Check for integer overflow */ if (ignoreDepth == 0) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); goto error; } } else if ((RAW == ']') && (NXT(1) == ']') && (NXT(2) == '>')) { + SKIP(3); if (ignoreDepth == 0) break; - SKIP(3); ignoreDepth--; } else { NEXT; } }
- if (RAW == 0) { - xmlFatalErr(ctxt, XML_ERR_CONDSEC_NOT_FINISHED, NULL); - goto error; - } if (ctxt->input->id != id) { xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY, "All markup of the conditional section is" " not in the same entity\n"); } - SKIP(3); } else { xmlFatalErr(ctxt, XML_ERR_CONDSEC_INVALID_KEYWORD, NULL); xmlHaltParser(ctxt); @@ -6983,7 +7096,7 @@ xmlParseConditionalSections(xmlParserCtxtPtr ctxt) { if (depth == 0) break;
- SKIP_BLANKS; + SKIP_BLANKS_PE; SHRINK; GROW; } @@ -7040,7 +7153,11 @@ xmlParseMarkupDecl(xmlParserCtxtPtr ctxt) { xmlParseComment(ctxt); break; default: - /* there is an error but it will be detected later */ + xmlFatalErr(ctxt, + ctxt->inSubset == 2 ? + XML_ERR_EXT_SUBSET_NOT_FINISHED : + XML_ERR_INT_SUBSET_NOT_FINISHED, + NULL); SKIP(2); break; } @@ -7048,15 +7165,6 @@ xmlParseMarkupDecl(xmlParserCtxtPtr ctxt) { xmlParsePI(ctxt); } } - - /* - * detect requirement to exit there and act accordingly - * and avoid having instate overridden later on - */ - if (ctxt->instate == XML_PARSER_EOF) - return; - - ctxt->instate = XML_PARSER_DTD; }
/** @@ -7073,7 +7181,6 @@ xmlParseMarkupDecl(xmlParserCtxtPtr ctxt) { void xmlParseTextDecl(xmlParserCtxtPtr ctxt) { xmlChar *version; - int oldstate;
/* * We know that '<?xml' is here. @@ -7085,10 +7192,6 @@ xmlParseTextDecl(xmlParserCtxtPtr ctxt) { return; }
- /* Avoid expansion of parameter entities when skipping blanks. */ - oldstate = ctxt->instate; - ctxt->instate = XML_PARSER_START; - if (SKIP_BLANKS == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space needed after '<?xml'\n"); @@ -7098,9 +7201,13 @@ xmlParseTextDecl(xmlParserCtxtPtr ctxt) { * We may have the VersionInfo here. */ version = xmlParseVersionInfo(ctxt); - if (version == NULL) + if (version == NULL) { version = xmlCharStrdup(XML_DEFAULT_VERSION); - else { + if (version == NULL) { + xmlErrMemory(ctxt); + return; + } + } else { if (SKIP_BLANKS == 0) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Space needed here\n"); @@ -7112,15 +7219,6 @@ xmlParseTextDecl(xmlParserCtxtPtr ctxt) { * We must have the encoding declaration */ xmlParseEncodingDecl(ctxt); - if (ctxt->instate == XML_PARSER_EOF) - return; - if (ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) { - /* - * The XML REC instructs us to stop parsing right here - */ - ctxt->instate = oldstate; - return; - }
SKIP_BLANKS; if ((RAW == '?') && (NXT(1) == '>')) { @@ -7133,15 +7231,12 @@ xmlParseTextDecl(xmlParserCtxtPtr ctxt) { int c;
xmlFatalErr(ctxt, XML_ERR_XMLDECL_NOT_FINISHED, NULL); - while ((c = CUR) != 0) { + while ((PARSER_STOPPED(ctxt) == 0) && ((c = CUR) != 0)) { NEXT; if (c == '>') break; } } - - if (ctxt->instate != XML_PARSER_EOF) - ctxt->instate = oldstate; }
/** @@ -7159,35 +7254,34 @@ xmlParseTextDecl(xmlParserCtxtPtr ctxt) { void xmlParseExternalSubset(xmlParserCtxtPtr ctxt, const xmlChar *ExternalID, const xmlChar *SystemID) { - xmlDetectSAX2(ctxt); + int oldInputNr; + + xmlCtxtInitializeLate(ctxt);
xmlDetectEncoding(ctxt);
if (CMP5(CUR_PTR, '<', '?', 'x', 'm', 'l')) { xmlParseTextDecl(ctxt); - if (ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) { - /* - * The XML REC instructs us to stop parsing right here - */ - xmlHaltParser(ctxt); - return; - } } if (ctxt->myDoc == NULL) { ctxt->myDoc = xmlNewDoc(BAD_CAST "1.0"); if (ctxt->myDoc == NULL) { - xmlErrMemory(ctxt, "New Doc failed"); + xmlErrMemory(ctxt); return; } ctxt->myDoc->properties = XML_DOC_INTERNAL; } - if ((ctxt->myDoc != NULL) && (ctxt->myDoc->intSubset == NULL)) - xmlCreateIntSubset(ctxt->myDoc, NULL, ExternalID, SystemID); + if ((ctxt->myDoc != NULL) && (ctxt->myDoc->intSubset == NULL) && + (xmlCreateIntSubset(ctxt->myDoc, NULL, ExternalID, SystemID) == NULL)) { + xmlErrMemory(ctxt); + }
- ctxt->instate = XML_PARSER_DTD; - ctxt->external = 1; - SKIP_BLANKS; - while ((ctxt->instate != XML_PARSER_EOF) && (RAW != 0)) { + ctxt->inSubset = 2; + oldInputNr = ctxt->inputNr; + + SKIP_BLANKS_PE; + while (((RAW != 0) || (ctxt->inputNr > oldInputNr)) && + (!PARSER_STOPPED(ctxt))) { GROW; if ((RAW == '<') && (NXT(1) == '!') && (NXT(2) == '[')) { xmlParseConditionalSections(ctxt); @@ -7198,14 +7292,16 @@ xmlParseExternalSubset(xmlParserCtxtPtr ctxt, const xmlChar *ExternalID, xmlHaltParser(ctxt); return; } - SKIP_BLANKS; + SKIP_BLANKS_PE; SHRINK; }
+ while (ctxt->inputNr > oldInputNr) + xmlPopPE(ctxt); + if (RAW != 0) { xmlFatalErr(ctxt, XML_ERR_EXT_SUBSET_NOT_FINISHED, NULL); } - }
/** @@ -7225,12 +7321,9 @@ xmlParseExternalSubset(xmlParserCtxtPtr ctxt, const xmlChar *ExternalID, */ void xmlParseReference(xmlParserCtxtPtr ctxt) { - xmlEntityPtr ent; + xmlEntityPtr ent = NULL; + const xmlChar *name; xmlChar *val; - int was_checked; - xmlNodePtr list = NULL; - xmlParserErrors ret = XML_ERR_OK; -
if (RAW != '&') return; @@ -7260,11 +7353,24 @@ xmlParseReference(xmlParserCtxtPtr ctxt) { /* * We are seeing an entity reference */ - ent = xmlParseEntityRef(ctxt); - if (ent == NULL) return; + name = xmlParseEntityRefInternal(ctxt); + if (name == NULL) + return; + ent = xmlLookupGeneralEntity(ctxt, name, /* isAttr */ 0); + if (ent == NULL) { + /* + * Create a reference for undeclared entities. + */ + if ((ctxt->replaceEntities == 0) && + (ctxt->sax != NULL) && + (ctxt->disableSAX == 0) && + (ctxt->sax->reference != NULL)) { + ctxt->sax->reference(ctxt->userData, name); + } + return; + } if (!ctxt->wellFormed) return; - was_checked = ent->flags & XML_ENT_PARSED;
/* special case of predefined entities */ if ((ent->name == NULL) || @@ -7316,9 +7422,6 @@ xmlParseReference(xmlParserCtxtPtr ctxt) { * * Proposed fix: * - * - Remove the ent->owner optimization which tries to avoid the - * initial copy of the entity. Always make entities own the - * subtree. * - Ignore current namespace declarations when parsing the * entity. If a prefix can't be resolved, don't report an error * but mark it as unresolved. @@ -7331,385 +7434,189 @@ xmlParseReference(xmlParserCtxtPtr ctxt) { * expansion like we already do with custom SAX callbacks. * External entity content should be cached in this case. */ - if (((ent->flags & XML_ENT_PARSED) == 0) && - ((ent->etype != XML_EXTERNAL_GENERAL_PARSED_ENTITY) || - (ctxt->options & (XML_PARSE_NOENT | XML_PARSE_DTDVALID)))) { - unsigned long oldsizeentcopy = ctxt->sizeentcopy; - - /* - * This is a bit hackish but this seems the best - * way to make sure both SAX and DOM entity support - * behaves okay. - */ - void *user_data; - if (ctxt->userData == ctxt) - user_data = NULL; - else - user_data = ctxt->userData; - - /* Avoid overflow as much as possible */ - ctxt->sizeentcopy = 0; - - if (ent->flags & XML_ENT_EXPANDING) { - xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL); - xmlHaltParser(ctxt); - return; - } - - ent->flags |= XML_ENT_EXPANDING; - - /* - * Check that this entity is well formed - * 4.3.2: An internal general parsed entity is well-formed - * if its replacement text matches the production labeled - * content. - */ - if (ent->etype == XML_INTERNAL_GENERAL_ENTITY) { - ctxt->depth++; - ret = xmlParseBalancedChunkMemoryInternal(ctxt, ent->content, - user_data, &list); - ctxt->depth--; - - } else if (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY) { - ctxt->depth++; - ret = xmlParseExternalEntityPrivate(ctxt->myDoc, ctxt, ctxt->sax, - user_data, ctxt->depth, ent->URI, - ent->ExternalID, &list); - ctxt->depth--; - } else { - ret = XML_ERR_ENTITY_PE_INTERNAL; - xmlErrMsgStr(ctxt, XML_ERR_INTERNAL_ERROR, - "invalid entity type found\n", NULL); - } - - ent->flags &= ~XML_ENT_EXPANDING; - ent->flags |= XML_ENT_PARSED | XML_ENT_CHECKED; - ent->expandedSize = ctxt->sizeentcopy; - if (ret == XML_ERR_ENTITY_LOOP) { - xmlHaltParser(ctxt); - xmlFreeNodeList(list); - return; - } - if (xmlParserEntityCheck(ctxt, oldsizeentcopy)) { - xmlFreeNodeList(list); - return; - } - - if ((ret == XML_ERR_OK) && (list != NULL)) { - ent->children = list; + if ((ent->etype == XML_INTERNAL_GENERAL_ENTITY) || + (((ctxt->options & XML_PARSE_NO_XXE) == 0) && + ((ctxt->replaceEntities) || + (ctxt->validate)))) { + if ((ent->flags & XML_ENT_PARSED) == 0) { + xmlCtxtParseEntity(ctxt, ent); + } else if (ent->children == NULL) { /* - * Prune it directly in the generated document - * except for single text nodes. + * Probably running in SAX mode and the callbacks don't + * build the entity content. Parse the entity again. + * + * This will also be triggered in normal tree builder mode + * if an entity happens to be empty, causing unnecessary + * reloads. It's hard to come up with a reliable check in + * which mode we're running. */ - if ((ctxt->replaceEntities == 0) || - (ctxt->parseMode == XML_PARSE_READER) || - ((list->type == XML_TEXT_NODE) && - (list->next == NULL))) { - ent->owner = 1; - while (list != NULL) { - list->parent = (xmlNodePtr) ent; - if (list->doc != ent->doc) - xmlSetTreeDoc(list, ent->doc); - if (list->next == NULL) - ent->last = list; - list = list->next; - } - list = NULL; - } else { - ent->owner = 0; - while (list != NULL) { - list->parent = (xmlNodePtr) ctxt->node; - list->doc = ctxt->myDoc; - if (list->next == NULL) - ent->last = list; - list = list->next; - } - list = ent->children; -#ifdef LIBXML_LEGACY_ENABLED - if (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY) - xmlAddEntityReference(ent, list, NULL); -#endif /* LIBXML_LEGACY_ENABLED */ - } - } else if ((ret != XML_ERR_OK) && - (ret != XML_WAR_UNDECLARED_ENTITY)) { - xmlFatalErrMsgStr(ctxt, XML_ERR_UNDECLARED_ENTITY, - "Entity '%s' failed to parse\n", ent->name); - if (ent->content != NULL) - ent->content[0] = 0; - } else if (list != NULL) { - xmlFreeNodeList(list); - list = NULL; - } - - /* Prevent entity from being parsed and expanded twice (Bug 760367). */ - was_checked = 0; - } - - /* - * Now that the entity content has been gathered - * provide it to the application, this can take different forms based - * on the parsing modes. - */ - if (ent->children == NULL) { - /* - * Probably running in SAX mode and the callbacks don't - * build the entity content. So unless we already went - * though parsing for first checking go though the entity - * content to generate callbacks associated to the entity - */ - if (was_checked != 0) { - void *user_data; - /* - * This is a bit hackish but this seems the best - * way to make sure both SAX and DOM entity support - * behaves okay. - */ - if (ctxt->userData == ctxt) - user_data = NULL; - else - user_data = ctxt->userData; - - if (ent->etype == XML_INTERNAL_GENERAL_ENTITY) { - ctxt->depth++; - ret = xmlParseBalancedChunkMemoryInternal(ctxt, - ent->content, user_data, NULL); - ctxt->depth--; - } else if (ent->etype == - XML_EXTERNAL_GENERAL_PARSED_ENTITY) { - unsigned long oldsizeentities = ctxt->sizeentities; - - ctxt->depth++; - ret = xmlParseExternalEntityPrivate(ctxt->myDoc, ctxt, - ctxt->sax, user_data, ctxt->depth, - ent->URI, ent->ExternalID, NULL); - ctxt->depth--; - - /* Undo the change to sizeentities */ - ctxt->sizeentities = oldsizeentities; - } else { - ret = XML_ERR_ENTITY_PE_INTERNAL; - xmlErrMsgStr(ctxt, XML_ERR_INTERNAL_ERROR, - "invalid entity type found\n", NULL); - } - if (ret == XML_ERR_ENTITY_LOOP) { - xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL); - return; - } - if (xmlParserEntityCheck(ctxt, 0)) - return; - } - if ((ctxt->sax != NULL) && (ctxt->sax->reference != NULL) && - (ctxt->replaceEntities == 0) && (!ctxt->disableSAX)) { - /* - * Entity reference callback comes second, it's somewhat - * superfluous but a compatibility to historical behaviour - */ - ctxt->sax->reference(ctxt->userData, ent->name); - } - return; + xmlCtxtParseEntity(ctxt, ent); + } }
/* * We also check for amplification if entities aren't substituted. * They might be expanded later. */ - if ((was_checked != 0) && - (xmlParserEntityCheck(ctxt, ent->expandedSize))) + if (xmlParserEntityCheck(ctxt, ent->expandedSize)) return;
- /* - * If we didn't get any children for the entity being built - */ - if ((ctxt->sax != NULL) && (ctxt->sax->reference != NULL) && - (ctxt->replaceEntities == 0) && (!ctxt->disableSAX)) { + if ((ctxt->sax == NULL) || (ctxt->disableSAX)) + return; + + if (ctxt->replaceEntities == 0) { /* - * Create a node. + * Create a reference */ - ctxt->sax->reference(ctxt->userData, ent->name); - return; - } + if (ctxt->sax->reference != NULL) + ctxt->sax->reference(ctxt->userData, ent->name); + } else if ((ent->children != NULL) && (ctxt->node != NULL)) { + xmlNodePtr copy, cur;
- if (ctxt->replaceEntities) { - /* - * There is a problem on the handling of _private for entities - * (bug 155816): Should we copy the content of the field from - * the entity (possibly overwriting some value set by the user - * when a copy is created), should we leave it alone, or should - * we try to take care of different situations? The problem - * is exacerbated by the usage of this field by the xmlReader. - * To fix this bug, we look at _private on the created node - * and, if it's NULL, we copy in whatever was in the entity. - * If it's not NULL we leave it alone. This is somewhat of a - * hack - maybe we should have further tests to determine - * what to do. + /* + * Seems we are generating the DOM content, copy the tree */ - if (ctxt->node != NULL) { - /* - * Seems we are generating the DOM content, do - * a simple tree copy for all references except the first - * In the first occurrence list contains the replacement. - */ - if (((list == NULL) && (ent->owner == 0)) || - (ctxt->parseMode == XML_PARSE_READER)) { - xmlNodePtr nw = NULL, cur, firstChild = NULL; + cur = ent->children;
- /* - * when operating on a reader, the entities definitions - * are always owning the entities subtree. - if (ctxt->parseMode == XML_PARSE_READER) - ent->owner = 1; - */ + /* + * Handle first text node with SAX to coalesce text efficiently + */ + if ((cur->type == XML_TEXT_NODE) || + (cur->type == XML_CDATA_SECTION_NODE)) { + int len = xmlStrlen(cur->content);
- cur = ent->children; - while (cur != NULL) { - nw = xmlDocCopyNode(cur, ctxt->myDoc, 1); - if (nw != NULL) { - if (nw->_private == NULL) - nw->_private = cur->_private; - if (firstChild == NULL){ - firstChild = nw; - } - nw = xmlAddChild(ctxt->node, nw); - } - if (cur == ent->last) { - /* - * needed to detect some strange empty - * node cases in the reader tests - */ - if ((ctxt->parseMode == XML_PARSE_READER) && - (nw != NULL) && - (nw->type == XML_ELEMENT_NODE) && - (nw->children == NULL)) - nw->extra = 1; + if ((cur->type == XML_TEXT_NODE) || + (ctxt->sax->cdataBlock == NULL)) { + if (ctxt->sax->characters != NULL) + ctxt->sax->characters(ctxt, cur->content, len); + } else { + if (ctxt->sax->cdataBlock != NULL) + ctxt->sax->cdataBlock(ctxt, cur->content, len); + }
- break; - } - cur = cur->next; - } -#ifdef LIBXML_LEGACY_ENABLED - if (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY) - xmlAddEntityReference(ent, firstChild, nw); -#endif /* LIBXML_LEGACY_ENABLED */ - } else if ((list == NULL) || (ctxt->inputNr > 0)) { - xmlNodePtr nw = NULL, cur, next, last, - firstChild = NULL; + cur = cur->next; + }
- /* - * Copy the entity child list and make it the new - * entity child list. The goal is to make sure any - * ID or REF referenced will be the one from the - * document content and not the entity copy. - */ - cur = ent->children; - ent->children = NULL; - last = ent->last; - ent->last = NULL; - while (cur != NULL) { - next = cur->next; - cur->next = NULL; - cur->parent = NULL; - nw = xmlDocCopyNode(cur, ctxt->myDoc, 1); - if (nw != NULL) { - if (nw->_private == NULL) - nw->_private = cur->_private; - if (firstChild == NULL){ - firstChild = cur; - } - xmlAddChild((xmlNodePtr) ent, nw); - } - xmlAddChild(ctxt->node, cur); - if (cur == last) - break; - cur = next; - } - if (ent->owner == 0) - ent->owner = 1; -#ifdef LIBXML_LEGACY_ENABLED - if (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY) - xmlAddEntityReference(ent, firstChild, nw); -#endif /* LIBXML_LEGACY_ENABLED */ - } else { - const xmlChar *nbktext; + while (cur != NULL) { + xmlNodePtr last;
- /* - * the name change is to avoid coalescing of the - * node with a possible previous text one which - * would make ent->children a dangling pointer - */ - nbktext = xmlDictLookup(ctxt->dict, BAD_CAST "nbktext", - -1); - if (ent->children->type == XML_TEXT_NODE) - ent->children->name = nbktext; - if ((ent->last != ent->children) && - (ent->last->type == XML_TEXT_NODE)) - ent->last->name = nbktext; - xmlAddChildList(ctxt->node, ent->children); - } + /* + * Handle last text node with SAX to coalesce text efficiently + */ + if ((cur->next == NULL) && + ((cur->type == XML_TEXT_NODE) || + (cur->type == XML_CDATA_SECTION_NODE))) { + int len = xmlStrlen(cur->content);
- /* - * This is to avoid a nasty side effect, see - * characters() in SAX.c - */ - ctxt->nodemem = 0; - ctxt->nodelen = 0; - return; - } - } -} + if ((cur->type == XML_TEXT_NODE) || + (ctxt->sax->cdataBlock == NULL)) { + if (ctxt->sax->characters != NULL) + ctxt->sax->characters(ctxt, cur->content, len); + } else { + if (ctxt->sax->cdataBlock != NULL) + ctxt->sax->cdataBlock(ctxt, cur->content, len); + }
-/** - * xmlParseEntityRef: - * @ctxt: an XML parser context - * - * DEPRECATED: Internal function, don't use. - * - * Parse an entitiy reference. Always consumes '&'. - * - * [68] EntityRef ::= '&' Name ';' - * - * [ 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 Name given in the entity reference - * must match that in an entity declaration, except that well-formed - * documents need not declare any of the following entities: amp, lt, - * gt, apos, quot. The declaration of a parameter entity must precede - * any reference to it. Similarly, the declaration of a general entity - * must precede any reference to it which appears in a default value in an - * attribute-list declaration. Note that if entities are declared in the - * external subset or in external parameter entities, a non-validating - * processor is not obligated to read and process their declarations; - * for such documents, the rule that an entity must be declared is a - * well-formedness constraint only if standalone='yes'. - * - * [ WFC: Parsed Entity ] - * An entity reference must not contain the name of an unparsed entity - * - * Returns the xmlEntityPtr if found, or NULL otherwise. - */ -xmlEntityPtr -xmlParseEntityRef(xmlParserCtxtPtr ctxt) { - const xmlChar *name; - xmlEntityPtr ent = NULL; + break; + } + + /* + * Reset coalesce buffer stats only for non-text nodes. + */ + ctxt->nodemem = 0; + ctxt->nodelen = 0; + + copy = xmlDocCopyNode(cur, ctxt->myDoc, 1); + + if (copy == NULL) { + xmlErrMemory(ctxt); + break; + }
- GROW; - if (ctxt->instate == XML_PARSER_EOF) - return(NULL); + if (ctxt->parseMode == XML_PARSE_READER) { + /* Needed for reader */ + copy->extra = cur->extra; + /* Maybe needed for reader */ + copy->_private = cur->_private; + }
- if (RAW != '&') - return(NULL); - NEXT; - name = xmlParseName(ctxt); - if (name == NULL) { - xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED, - "xmlParseEntityRef: no name\n"); - return(NULL); + copy->parent = ctxt->node; + last = ctxt->node->last; + if (last == NULL) { + ctxt->node->children = copy; + } else { + last->next = copy; + copy->prev = last; + } + ctxt->node->last = copy; + + cur = cur->next; + } } - if (RAW != ';') { - xmlFatalErr(ctxt, XML_ERR_ENTITYREF_SEMICOL_MISSING, NULL); - return(NULL); +} + +static void +xmlHandleUndeclaredEntity(xmlParserCtxtPtr ctxt, const xmlChar *name) { + /* + * [ 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 + * Name given in the entity reference must match that in an + * entity declaration, except that well-formed documents + * need not declare any of the following entities: amp, lt, + * gt, apos, quot. + * The declaration of a parameter entity must precede any + * reference to it. + * Similarly, the declaration of a general entity must + * precede any reference to it which appears in a default + * value in an attribute-list declaration. Note that if + * entities are declared in the external subset or in + * external parameter entities, a non-validating processor + * is not obligated to read and process their declarations; + * for such documents, the rule that an entity must be + * declared is a well-formedness constraint only if + * standalone='yes'. + */ + if ((ctxt->standalone == 1) || + ((ctxt->hasExternalSubset == 0) && + (ctxt->hasPErefs == 0))) { + xmlFatalErrMsgStr(ctxt, XML_ERR_UNDECLARED_ENTITY, + "Entity '%s' not defined\n", name); + } else if (ctxt->validate) { + /* + * [ 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... + */ + xmlValidityError(ctxt, XML_ERR_UNDECLARED_ENTITY, + "Entity '%s' not defined\n", name, NULL); + } else if ((ctxt->loadsubset) || + ((ctxt->replaceEntities) && + ((ctxt->options & XML_PARSE_NO_XXE) == 0))) { + /* + * Also raise a non-fatal error + * + * - if the external subset is loaded and all entity declarations + * should be available, or + * - entity substition was requested without restricting + * external entity access. + */ + xmlErrMsgStr(ctxt, XML_WAR_UNDECLARED_ENTITY, + "Entity '%s' not defined\n", name); + } else { + xmlWarningMsg(ctxt, XML_WAR_UNDECLARED_ENTITY, + "Entity '%s' not defined\n", name, NULL); } - NEXT; + + ctxt->valid = 0; +} + +static xmlEntityPtr +xmlLookupGeneralEntity(xmlParserCtxtPtr ctxt, const xmlChar *name, int inAttr) { + xmlEntityPtr ent;
/* * Predefined entities override any extra definition @@ -7735,46 +7642,9 @@ xmlParseEntityRef(xmlParserCtxtPtr ctxt) { ent = xmlSAX2GetEntity(ctxt, name); } } - if (ctxt->instate == XML_PARSER_EOF) - return(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 - * Name given in the entity reference must match that in an - * entity declaration, except that well-formed documents - * need not declare any of the following entities: amp, lt, - * gt, apos, quot. - * The declaration of a parameter entity must precede any - * reference to it. - * Similarly, the declaration of a general entity must - * precede any reference to it which appears in a default - * value in an attribute-list declaration. Note that if - * entities are declared in the external subset or in - * external parameter entities, a non-validating processor - * is not obligated to read and process their declarations; - * for such documents, the rule that an entity must be - * declared is a well-formedness constraint only if - * standalone='yes'. - */ + if (ent == NULL) { - if ((ctxt->standalone == 1) || - ((ctxt->hasExternalSubset == 0) && - (ctxt->hasPErefs == 0))) { - xmlFatalErrMsgStr(ctxt, XML_ERR_UNDECLARED_ENTITY, - "Entity '%s' not defined\n", name); - } else { - xmlErrMsgStr(ctxt, XML_WAR_UNDECLARED_ENTITY, - "Entity '%s' not defined\n", name); - if ((ctxt->inSubset == 0) && - (ctxt->sax != NULL) && - (ctxt->disableSAX == 0) && - (ctxt->sax->reference != NULL)) { - ctxt->sax->reference(ctxt->userData, name); - } - } - ctxt->valid = 0; + xmlHandleUndeclaredEntity(ctxt, name); }
/* @@ -7785,6 +7655,7 @@ xmlParseEntityRef(xmlParserCtxtPtr ctxt) { else if (ent->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) { xmlFatalErrMsgStr(ctxt, XML_ERR_UNPARSED_ENTITY, "Entity reference to unparsed entity %s\n", name); + ent = NULL; }
/* @@ -7792,53 +7663,72 @@ xmlParseEntityRef(xmlParserCtxtPtr ctxt) { * Attribute values cannot contain direct or indirect * entity references to external entities. */ - else if ((ctxt->instate == XML_PARSER_ATTRIBUTE_VALUE) && - (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY)) { - xmlFatalErrMsgStr(ctxt, XML_ERR_ENTITY_IS_EXTERNAL, - "Attribute references external entity '%s'\n", name); - } - /* - * [ WFC: No < in Attribute Values ] - * The replacement text of any entity referred to directly or - * indirectly in an attribute value (other than "<") must - * not contain a <. - */ - else if ((ctxt->instate == XML_PARSER_ATTRIBUTE_VALUE) && - (ent->etype != XML_INTERNAL_PREDEFINED_ENTITY)) { - if ((ent->flags & XML_ENT_CHECKED_LT) == 0) { - if ((ent->content != NULL) && (xmlStrchr(ent->content, '<'))) - ent->flags |= XML_ENT_CONTAINS_LT; - ent->flags |= XML_ENT_CHECKED_LT; + else if (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY) { + if (inAttr) { + xmlFatalErrMsgStr(ctxt, XML_ERR_ENTITY_IS_EXTERNAL, + "Attribute references external entity '%s'\n", name); + ent = NULL; } - if (ent->flags & XML_ENT_CONTAINS_LT) - xmlFatalErrMsgStr(ctxt, XML_ERR_LT_IN_ATTRIBUTE, - "'<' in entity '%s' is not allowed in attributes " - "values\n", name); }
- /* - * Internal check, no parameter entities here ... - */ - else { - switch (ent->etype) { - case XML_INTERNAL_PARAMETER_ENTITY: - case XML_EXTERNAL_PARAMETER_ENTITY: - xmlFatalErrMsgStr(ctxt, XML_ERR_ENTITY_IS_PARAMETER, - "Attempt to reference the parameter entity '%s'\n", - name); - break; - default: - break; - } + return(ent); +} + +/** + * xmlParseEntityRefInternal: + * @ctxt: an XML parser context + * @inAttr: whether we are in an attribute value + * + * Parse an entity reference. Always consumes '&'. + * + * [68] EntityRef ::= '&' Name ';' + * + * Returns the name, or NULL in case of error. + */ +static const xmlChar * +xmlParseEntityRefInternal(xmlParserCtxtPtr ctxt) { + const xmlChar *name; + + GROW; + + if (RAW != '&') + return(NULL); + NEXT; + name = xmlParseName(ctxt); + if (name == NULL) { + xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED, + "xmlParseEntityRef: no name\n"); + return(NULL); + } + if (RAW != ';') { + xmlFatalErr(ctxt, XML_ERR_ENTITYREF_SEMICOL_MISSING, NULL); + return(NULL); } + NEXT;
- /* - * [ WFC: No Recursion ] - * A parsed entity must not contain a recursive reference - * to itself, either directly or indirectly. - * Done somewhere else - */ - return(ent); + return(name); +} + +/** + * xmlParseEntityRef: + * @ctxt: an XML parser context + * + * DEPRECATED: Internal function, don't use. + * + * Returns the xmlEntityPtr if found, or NULL otherwise. + */ +xmlEntityPtr +xmlParseEntityRef(xmlParserCtxtPtr ctxt) { + const xmlChar *name; + + if (ctxt == NULL) + return(NULL); + + name = xmlParseEntityRefInternal(ctxt); + if (name == NULL) + return(NULL); + + return(xmlLookupGeneralEntity(ctxt, name, /* inAttr */ 0)); }
/** @@ -7872,12 +7762,11 @@ xmlParseEntityRef(xmlParserCtxtPtr ctxt) { * Returns the xmlEntityPtr if found, or NULL otherwise. The str pointer * is updated to the current location in the string. */ -static xmlEntityPtr +static xmlChar * xmlParseStringEntityRef(xmlParserCtxtPtr ctxt, const xmlChar ** str) { xmlChar *name; const xmlChar *ptr; xmlChar cur; - xmlEntityPtr ent = NULL;
if ((str == NULL) || (*str == NULL)) return(NULL); @@ -7902,137 +7791,8 @@ xmlParseStringEntityRef(xmlParserCtxtPtr ctxt, const xmlChar ** str) { } ptr++;
- - /* - * Predefined entities override any extra definition - */ - if ((ctxt->options & XML_PARSE_OLDSAX) == 0) { - ent = xmlGetPredefinedEntity(name); - if (ent != NULL) { - xmlFree(name); - *str = ptr; - return(ent); - } - } - - /* - * Ask first SAX for entity resolution, otherwise try the - * entities which may have stored in the parser context. - */ - if (ctxt->sax != NULL) { - if (ctxt->sax->getEntity != NULL) - ent = ctxt->sax->getEntity(ctxt->userData, name); - if ((ent == NULL) && (ctxt->options & XML_PARSE_OLDSAX)) - ent = xmlGetPredefinedEntity(name); - if ((ent == NULL) && (ctxt->userData==ctxt)) { - ent = xmlSAX2GetEntity(ctxt, name); - } - } - if (ctxt->instate == XML_PARSER_EOF) { - xmlFree(name); - return(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 - * Name given in the entity reference must match that in an - * entity declaration, except that well-formed documents - * need not declare any of the following entities: amp, lt, - * gt, apos, quot. - * The declaration of a parameter entity must precede any - * reference to it. - * Similarly, the declaration of a general entity must - * precede any reference to it which appears in a default - * value in an attribute-list declaration. Note that if - * entities are declared in the external subset or in - * external parameter entities, a non-validating processor - * is not obligated to read and process their declarations; - * for such documents, the rule that an entity must be - * declared is a well-formedness constraint only if - * standalone='yes'. - */ - if (ent == NULL) { - if ((ctxt->standalone == 1) || - ((ctxt->hasExternalSubset == 0) && - (ctxt->hasPErefs == 0))) { - xmlFatalErrMsgStr(ctxt, XML_ERR_UNDECLARED_ENTITY, - "Entity '%s' not defined\n", name); - } else { - xmlErrMsgStr(ctxt, XML_WAR_UNDECLARED_ENTITY, - "Entity '%s' not defined\n", - name); - } - /* TODO ? check regressions ctxt->valid = 0; */ - } - - /* - * [ WFC: Parsed Entity ] - * An entity reference must not contain the name of an - * unparsed entity - */ - else if (ent->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) { - xmlFatalErrMsgStr(ctxt, XML_ERR_UNPARSED_ENTITY, - "Entity reference to unparsed entity %s\n", name); - } - - /* - * [ WFC: No External Entity References ] - * Attribute values cannot contain direct or indirect - * entity references to external entities. - */ - else if ((ctxt->instate == XML_PARSER_ATTRIBUTE_VALUE) && - (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY)) { - xmlFatalErrMsgStr(ctxt, XML_ERR_ENTITY_IS_EXTERNAL, - "Attribute references external entity '%s'\n", name); - } - /* - * [ WFC: No < in Attribute Values ] - * The replacement text of any entity referred to directly or - * indirectly in an attribute value (other than "<") must - * not contain a <. - */ - else if ((ctxt->instate == XML_PARSER_ATTRIBUTE_VALUE) && - (ent->etype != XML_INTERNAL_PREDEFINED_ENTITY)) { - if ((ent->flags & XML_ENT_CHECKED_LT) == 0) { - if ((ent->content != NULL) && (xmlStrchr(ent->content, '<'))) - ent->flags |= XML_ENT_CONTAINS_LT; - ent->flags |= XML_ENT_CHECKED_LT; - } - if (ent->flags & XML_ENT_CONTAINS_LT) - xmlFatalErrMsgStr(ctxt, XML_ERR_LT_IN_ATTRIBUTE, - "'<' in entity '%s' is not allowed in attributes " - "values\n", name); - } - - /* - * Internal check, no parameter entities here ... - */ - else { - switch (ent->etype) { - case XML_INTERNAL_PARAMETER_ENTITY: - case XML_EXTERNAL_PARAMETER_ENTITY: - xmlFatalErrMsgStr(ctxt, XML_ERR_ENTITY_IS_PARAMETER, - "Attempt to reference the parameter entity '%s'\n", - name); - break; - default: - break; - } - } - - /* - * [ WFC: No Recursion ] - * A parsed entity must not contain a recursive reference - * to itself, either directly or indirectly. - * Done somewhere else - */ - - xmlFree(name); *str = ptr; - return(ent); + return(name); }
/** @@ -8082,9 +7842,6 @@ xmlParsePEReference(xmlParserCtxtPtr ctxt) xmlFatalErrMsg(ctxt, XML_ERR_PEREF_NO_NAME, "PEReference: no name\n"); return; } - if (xmlParserDebugEntities) - xmlGenericError(xmlGenericErrorContext, - "PEReference: %s\n", name); if (RAW != ';') { xmlFatalErr(ctxt, XML_ERR_PEREF_SEMICOL_MISSING, NULL); return; @@ -8092,47 +7849,18 @@ xmlParsePEReference(xmlParserCtxtPtr ctxt)
NEXT;
+ /* Must be set before xmlHandleUndeclaredEntity */ + ctxt->hasPErefs = 1; + /* * Request the entity from SAX */ if ((ctxt->sax != NULL) && (ctxt->sax->getParameterEntity != NULL)) entity = ctxt->sax->getParameterEntity(ctxt->userData, name); - if (ctxt->instate == XML_PARSER_EOF) - return; + 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, - "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, - "PEReference: %%%s; not found\n", - name, NULL); - } else - xmlWarningMsg(ctxt, XML_WAR_UNDECLARED_ENTITY, - "PEReference: %%%s; not found\n", - name, NULL); - ctxt->valid = 0; - } + xmlHandleUndeclaredEntity(ctxt, name); } else { /* * Internal checking in case the entity quest barfed @@ -8143,16 +7871,11 @@ xmlParsePEReference(xmlParserCtxtPtr ctxt) "Internal: %%%s; is not a parameter entity\n", name, NULL); } else { - unsigned long parentConsumed; - xmlEntityPtr oldEnt; - if ((entity->etype == XML_EXTERNAL_PARAMETER_ENTITY) && - ((ctxt->options & XML_PARSE_NOENT) == 0) && - ((ctxt->options & XML_PARSE_DTDVALID) == 0) && - ((ctxt->options & XML_PARSE_DTDLOAD) == 0) && - ((ctxt->options & XML_PARSE_DTDATTR) == 0) && - (ctxt->replaceEntities == 0) && - (ctxt->validate == 0)) + ((ctxt->options & XML_PARSE_NO_XXE) || + ((ctxt->loadsubset == 0) && + (ctxt->replaceEntities == 0) && + (ctxt->validate == 0)))) return;
if (entity->flags & XML_ENT_EXPANDING) { @@ -8161,17 +7884,6 @@ xmlParsePEReference(xmlParserCtxtPtr ctxt) return; }
- /* Must be computed from old input before pushing new input. */ - parentConsumed = ctxt->input->parentConsumed; - oldEnt = ctxt->input->entity; - if ((oldEnt == NULL) || - ((oldEnt->etype == XML_EXTERNAL_PARAMETER_ENTITY) && - ((oldEnt->flags & XML_ENT_PARSED) == 0))) { - xmlSaturatedAdd(&parentConsumed, ctxt->input->consumed); - xmlSaturatedAddSizeT(&parentConsumed, - ctxt->input->cur - ctxt->input->base); - } - input = xmlNewEntityInputStream(ctxt, entity); if (xmlPushInput(ctxt, input) < 0) { xmlFreeInputStream(input); @@ -8180,8 +7892,6 @@ xmlParsePEReference(xmlParserCtxtPtr ctxt)
entity->flags |= XML_ENT_EXPANDING;
- input->parentConsumed = parentConsumed; - if (entity->etype == XML_EXTERNAL_PARAMETER_ENTITY) { xmlDetectEncoding(ctxt);
@@ -8192,7 +7902,6 @@ xmlParsePEReference(xmlParserCtxtPtr ctxt) } } } - ctxt->hasPErefs = 1; }
/** @@ -8213,7 +7922,7 @@ xmlLoadEntityContent(xmlParserCtxtPtr ctxt, xmlEntityPtr entity) { const xmlChar *oldencoding; xmlChar *content = NULL; size_t length, i; - int oldinputNr, oldinputMax, oldprogressive; + int oldinputNr, oldinputMax; int ret = -1; int res;
@@ -8221,38 +7930,29 @@ xmlLoadEntityContent(xmlParserCtxtPtr ctxt, xmlEntityPtr entity) { ((entity->etype != XML_EXTERNAL_PARAMETER_ENTITY) && (entity->etype != XML_EXTERNAL_GENERAL_PARSED_ENTITY)) || (entity->content != NULL)) { - xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR, + xmlFatalErr(ctxt, XML_ERR_ARGUMENT, "xmlLoadEntityContent parameter error"); return(-1); }
- if (xmlParserDebugEntities) - xmlGenericError(xmlGenericErrorContext, - "Reading %s entity content input\n", entity->name); - input = xmlLoadExternalEntity((char *) entity->URI, (char *) entity->ExternalID, ctxt); - if (input == NULL) { - xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR, - "xmlLoadEntityContent input error"); + if (input == NULL) return(-1); - }
oldinput = ctxt->input; oldinputNr = ctxt->inputNr; oldinputMax = ctxt->inputMax; oldinputTab = ctxt->inputTab; oldencoding = ctxt->encoding; - oldprogressive = ctxt->progressive;
ctxt->input = NULL; ctxt->inputNr = 0; ctxt->inputMax = 1; ctxt->encoding = NULL; - ctxt->progressive = 0; ctxt->inputTab = xmlMalloc(sizeof(xmlParserInputPtr)); if (ctxt->inputTab == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); xmlFreeInputStream(input); goto error; } @@ -8278,9 +7978,6 @@ xmlLoadEntityContent(xmlParserCtxtPtr ctxt, xmlEntityPtr entity) { } }
- if (ctxt->instate == XML_PARSER_EOF) - goto error; - length = input->cur - input->base; xmlBufShrink(input->buf->buffer, length); xmlSaturatedAdd(&ctxt->sizeentities, length); @@ -8291,7 +7988,7 @@ xmlLoadEntityContent(xmlParserCtxtPtr ctxt, xmlEntityPtr entity) { xmlBufResetInput(input->buf->buffer, input);
if (res < 0) { - xmlFatalErr(ctxt, input->buf->error, NULL); + xmlCtxtErrIO(ctxt, input->buf->error, NULL); goto error; }
@@ -8299,7 +7996,7 @@ xmlLoadEntityContent(xmlParserCtxtPtr ctxt, xmlEntityPtr entity) { content = xmlBufDetach(input->buf->buffer);
if (length > INT_MAX) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); goto error; }
@@ -8333,7 +8030,6 @@ error: ctxt->inputMax = oldinputMax; ctxt->inputTab = oldinputTab; ctxt->encoding = oldencoding; - ctxt->progressive = oldprogressive;
xmlFree(content);
@@ -8400,43 +8096,18 @@ xmlParseStringPEReference(xmlParserCtxtPtr ctxt, const xmlChar **str) { } ptr++;
+ /* Must be set before xmlHandleUndeclaredEntity */ + ctxt->hasPErefs = 1; + /* * Request the entity from SAX */ if ((ctxt->sax != NULL) && (ctxt->sax->getParameterEntity != NULL)) entity = ctxt->sax->getParameterEntity(ctxt->userData, name); - if (ctxt->instate == XML_PARSER_EOF) { - xmlFree(name); - *str = ptr; - return(NULL); - } + 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, - "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... - */ - xmlWarningMsg(ctxt, XML_WAR_UNDECLARED_ENTITY, - "PEReference: %%%s; not found\n", - name, NULL); - ctxt->valid = 0; - } + xmlHandleUndeclaredEntity(ctxt, name); } else { /* * Internal checking in case the entity quest barfed @@ -8448,7 +8119,7 @@ xmlParseStringPEReference(xmlParserCtxtPtr ctxt, const xmlChar **str) { name, NULL); } } - ctxt->hasPErefs = 1; + xmlFree(name); *str = ptr; return(entity); @@ -8514,8 +8185,6 @@ xmlParseDocTypeDecl(xmlParserCtxtPtr ctxt) { if ((ctxt->sax != NULL) && (ctxt->sax->internalSubset != NULL) && (!ctxt->disableSAX)) ctxt->sax->internalSubset(ctxt->userData, name, ExternalID, URI); - if (ctxt->instate == XML_PARSER_EOF) - return;
/* * Is there any internal subset declarations ? @@ -8548,8 +8217,8 @@ xmlParseInternalSubset(xmlParserCtxtPtr ctxt) { * Is there any DTD definition ? */ if (RAW == '[') { - int baseInputNr = ctxt->inputNr; - ctxt->instate = XML_PARSER_DTD; + int oldInputNr = ctxt->inputNr; + NEXT; /* * Parse the succession of Markup declarations and @@ -8557,14 +8226,14 @@ xmlParseInternalSubset(xmlParserCtxtPtr ctxt) { * Subsequence (markupdecl | PEReference | S)* */ SKIP_BLANKS; - while (((RAW != ']') || (ctxt->inputNr > baseInputNr)) && - (ctxt->instate != XML_PARSER_EOF)) { + while (((RAW != ']') || (ctxt->inputNr > oldInputNr)) && + (PARSER_STOPPED(ctxt) == 0)) {
/* * Conditional sections are allowed from external entities included * by PE References in the internal subset. */ - if ((ctxt->inputNr > 1) && (ctxt->input->filename != NULL) && + if ((PARSER_EXTERNAL(ctxt)) && (RAW == '<') && (NXT(1) == '!') && (NXT(2) == '[')) { xmlParseConditionalSections(ctxt); } else if ((RAW == '<') && ((NXT(1) == '!') || (NXT(1) == '?'))) { @@ -8572,16 +8241,17 @@ xmlParseInternalSubset(xmlParserCtxtPtr ctxt) { } else if (RAW == '%') { xmlParsePEReference(ctxt); } else { - xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR, - "xmlParseInternalSubset: error detected in" - " Markup declaration\n"); - xmlHaltParser(ctxt); - return; + xmlFatalErr(ctxt, XML_ERR_INT_SUBSET_NOT_FINISHED, NULL); + break; } - SKIP_BLANKS; + SKIP_BLANKS_PE; SHRINK; GROW; } + + while (ctxt->inputNr > oldInputNr) + xmlPopPE(ctxt); + if (RAW == ']') { NEXT; SKIP_BLANKS; @@ -8591,7 +8261,7 @@ xmlParseInternalSubset(xmlParserCtxtPtr ctxt) { /* * We should be at the end of the DOCTYPE declaration. */ - if (RAW != '>') { + if ((ctxt->wellFormed) && (RAW != '>')) { xmlFatalErr(ctxt, XML_ERR_DOCTYPE_NOT_FINISHED, NULL); return; } @@ -8656,7 +8326,6 @@ xmlParseAttribute(xmlParserCtxtPtr ctxt, xmlChar **value) { NEXT; SKIP_BLANKS; val = xmlParseAttValue(ctxt); - ctxt->instate = XML_PARSER_CONTENT; } else { xmlFatalErrMsgStr(ctxt, XML_ERR_ATTRIBUTE_WITHOUT_VALUE, "Specification mandates value for attribute %s\n", name); @@ -8754,13 +8423,10 @@ xmlParseStartTag(xmlParserCtxtPtr ctxt) {
while (((RAW != '>') && ((RAW != '/') || (NXT(1) != '>')) && - (IS_BYTE_CHAR(RAW))) && (ctxt->instate != XML_PARSER_EOF)) { + (IS_BYTE_CHAR(RAW))) && (PARSER_STOPPED(ctxt) == 0)) { attname = xmlParseAttribute(ctxt, &attvalue); - if (attname == NULL) { - xmlFatalErrMsg(ctxt, XML_ERR_INTERNAL_ERROR, - "xmlParseStartTag: problem parsing attributes\n"); + if (attname == NULL) break; - } if (attvalue != NULL) { /* * [ WFC: Unique Att Spec ] @@ -8782,7 +8448,7 @@ xmlParseStartTag(xmlParserCtxtPtr ctxt) { atts = (const xmlChar **) xmlMalloc(maxatts * sizeof(xmlChar *)); if (atts == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); if (attvalue != NULL) xmlFree(attvalue); goto failed; @@ -8796,7 +8462,7 @@ xmlParseStartTag(xmlParserCtxtPtr ctxt) { n = (const xmlChar **) xmlRealloc((void *) atts, maxatts * sizeof(const xmlChar *)); if (n == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); if (attvalue != NULL) xmlFree(attvalue); goto failed; @@ -8961,8 +8627,6 @@ xmlParseQNameHashed(xmlParserCtxtPtr ctxt, xmlHashedString *prefix) { p.name = NULL;
GROW; - if (ctxt->instate == XML_PARSER_EOF) - return(l); start = CUR_PTR - BASE_PTR;
l = xmlParseNCName(ctxt); @@ -8979,17 +8643,17 @@ xmlParseQNameHashed(xmlParserCtxtPtr ctxt, xmlHashedString *prefix) {
l.name = NULL; p.name = NULL; - if (ctxt->instate == XML_PARSER_EOF) - return(l); if ((isNCName == 0) && (CUR != ':')) return(l); tmp = xmlParseNmtoken(ctxt); if (tmp != NULL) xmlFree(tmp); - if (ctxt->instate == XML_PARSER_EOF) - return(l); l = xmlDictLookupHashed(ctxt->dict, BASE_PTR + start, CUR_PTR - (BASE_PTR + start)); + if (l.name == NULL) { + xmlErrMemory(ctxt); + return(l); + } xmlNsErr(ctxt, XML_NS_ERR_QNAME, "Failed to parse QName '%s'\n", l.name, NULL, NULL); } @@ -9079,202 +8743,6 @@ xmlParseQNameAndCompare(xmlParserCtxtPtr ctxt, xmlChar const *name, return ret; }
-/** - * xmlParseAttValueInternal: - * @ctxt: an XML parser context - * @len: attribute len result - * @alloc: whether the attribute was reallocated as a new string - * @normalize: if 1 then further non-CDATA normalization must be done - * - * parse a value for an attribute. - * NOTE: if no normalization is needed, the routine will return pointers - * directly from the data buffer. - * - * 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 if it was copied, this can be detected by val[*len] == 0. - */ - -#define GROW_PARSE_ATT_VALUE_INTERNAL(ctxt, in, start, end) \ - const xmlChar *oldbase = ctxt->input->base;\ - GROW;\ - if (ctxt->instate == XML_PARSER_EOF)\ - return(NULL);\ - if (oldbase != ctxt->input->base) {\ - ptrdiff_t delta = ctxt->input->base - oldbase;\ - start = start + delta;\ - in = in + delta;\ - }\ - end = ctxt->input->end; - -static xmlChar * -xmlParseAttValueInternal(xmlParserCtxtPtr ctxt, int *len, int *alloc, - int normalize) -{ - xmlChar limit = 0; - const xmlChar *in = NULL, *start, *end, *last; - xmlChar *ret = NULL; - int line, col; - int maxLength = (ctxt->options & XML_PARSE_HUGE) ? - XML_MAX_HUGE_LENGTH : - XML_MAX_TEXT_LENGTH; - - GROW; - in = (xmlChar *) CUR_PTR; - line = ctxt->input->line; - col = ctxt->input->col; - if (*in != '"' && *in != ''') { - xmlFatalErr(ctxt, XML_ERR_ATTRIBUTE_NOT_STARTED, NULL); - return (NULL); - } - ctxt->instate = XML_PARSER_ATTRIBUTE_VALUE; - - /* - * try to handle in this routine the most common case where no - * allocation of a new string is required and where content is - * pure ASCII. - */ - limit = *in++; - col++; - end = ctxt->input->end; - start = in; - if (in >= end) { - GROW_PARSE_ATT_VALUE_INTERNAL(ctxt, in, start, end) - } - if (normalize) { - /* - * Skip any leading spaces - */ - while ((in < end) && (*in != limit) && - ((*in == 0x20) || (*in == 0x9) || - (*in == 0xA) || (*in == 0xD))) { - if (*in == 0xA) { - line++; col = 1; - } else { - col++; - } - in++; - start = in; - if (in >= end) { - GROW_PARSE_ATT_VALUE_INTERNAL(ctxt, in, start, end) - if ((in - start) > maxLength) { - xmlFatalErrMsg(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED, - "AttValue length too long\n"); - return(NULL); - } - } - } - while ((in < end) && (*in != limit) && (*in >= 0x20) && - (*in <= 0x7f) && (*in != '&') && (*in != '<')) { - col++; - if ((*in++ == 0x20) && (*in == 0x20)) break; - if (in >= end) { - GROW_PARSE_ATT_VALUE_INTERNAL(ctxt, in, start, end) - if ((in - start) > maxLength) { - xmlFatalErrMsg(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED, - "AttValue length too long\n"); - return(NULL); - } - } - } - last = in; - /* - * skip the trailing blanks - */ - while ((last[-1] == 0x20) && (last > start)) last--; - while ((in < end) && (*in != limit) && - ((*in == 0x20) || (*in == 0x9) || - (*in == 0xA) || (*in == 0xD))) { - if (*in == 0xA) { - line++, col = 1; - } else { - col++; - } - in++; - if (in >= end) { - const xmlChar *oldbase = ctxt->input->base; - GROW; - if (ctxt->instate == XML_PARSER_EOF) - return(NULL); - if (oldbase != ctxt->input->base) { - ptrdiff_t delta = ctxt->input->base - oldbase; - start = start + delta; - in = in + delta; - last = last + delta; - } - end = ctxt->input->end; - if ((in - start) > maxLength) { - xmlFatalErrMsg(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED, - "AttValue length too long\n"); - return(NULL); - } - } - } - if ((in - start) > maxLength) { - xmlFatalErrMsg(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED, - "AttValue length too long\n"); - return(NULL); - } - if (*in != limit) goto need_complex; - } else { - while ((in < end) && (*in != limit) && (*in >= 0x20) && - (*in <= 0x7f) && (*in != '&') && (*in != '<')) { - in++; - col++; - if (in >= end) { - GROW_PARSE_ATT_VALUE_INTERNAL(ctxt, in, start, end) - if ((in - start) > maxLength) { - xmlFatalErrMsg(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED, - "AttValue length too long\n"); - return(NULL); - } - } - } - last = in; - if ((in - start) > maxLength) { - xmlFatalErrMsg(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED, - "AttValue length too long\n"); - return(NULL); - } - if (*in != limit) goto need_complex; - } - in++; - col++; - if (len != NULL) { - if (alloc) *alloc = 0; - *len = last - start; - ret = (xmlChar *) start; - } else { - if (alloc) *alloc = 1; - ret = xmlStrndup(start, last - start); - } - CUR_PTR = in; - ctxt->input->line = line; - ctxt->input->col = col; - return ret; -need_complex: - if (alloc) *alloc = 1; - return xmlParseAttValueComplex(ctxt, len, normalize); -} - /** * xmlParseAttribute2: * @ctxt: an XML parser context @@ -9298,8 +8766,9 @@ xmlParseAttribute2(xmlParserCtxtPtr ctxt, { xmlHashedString hname; const xmlChar *prefix, *name; - xmlChar *val, *internal_val = NULL; + xmlChar *val = NULL, *internal_val = NULL; int normalize = 0; + int isNamespace;
*value = NULL; GROW; @@ -9335,34 +8804,17 @@ xmlParseAttribute2(xmlParserCtxtPtr ctxt, if (RAW == '=') { NEXT; SKIP_BLANKS; - val = xmlParseAttValueInternal(ctxt, len, alloc, normalize); - if (val == NULL) { - hname.name = NULL; - return(hname); - } - if (normalize) { - /* - * Sometimes a second normalisation pass for spaces is needed - * but that only happens if charrefs or entities references - * have been used in the attribute value, i.e. the attribute - * value have been extracted in an allocated string already. - */ - if (*alloc) { - const xmlChar *val2; - - val2 = xmlAttrNormalizeSpace2(ctxt, val, len); - if ((val2 != NULL) && (val2 != val)) { - xmlFree(val); - val = (xmlChar *) val2; - } - } - } - ctxt->instate = XML_PARSER_CONTENT; + isNamespace = (((prefix == NULL) && (name == ctxt->str_xmlns)) || + (prefix == ctxt->str_xmlns)); + val = xmlParseAttValueInternal(ctxt, len, alloc, normalize, + isNamespace); + if (val == NULL) + goto error; } else { xmlFatalErrMsgStr(ctxt, XML_ERR_ATTRIBUTE_WITHOUT_VALUE, "Specification mandates value for attribute %s\n", name); - return(hname); + goto error; }
if (prefix == ctxt->str_xml) { @@ -9373,6 +8825,8 @@ xmlParseAttribute2(xmlParserCtxtPtr ctxt, */ if ((ctxt->pedantic) && (xmlStrEqual(name, BAD_CAST "lang"))) { internal_val = xmlStrndup(val, *len); + if (internal_val == NULL) + goto mem_error; if (!xmlCheckLanguageID(internal_val)) { xmlWarningMsg(ctxt, XML_WAR_LANG_VALUE, "Malformed value for xml:lang : %s\n", @@ -9385,6 +8839,8 @@ xmlParseAttribute2(xmlParserCtxtPtr ctxt, */ if (xmlStrEqual(name, BAD_CAST "space")) { internal_val = xmlStrndup(val, *len); + if (internal_val == NULL) + goto mem_error; if (xmlStrEqual(internal_val, BAD_CAST "default")) *(ctxt->space) = 0; else if (xmlStrEqual(internal_val, BAD_CAST "preserve")) @@ -9402,6 +8858,13 @@ xmlParseAttribute2(xmlParserCtxtPtr ctxt,
*value = val; return (hname); + +mem_error: + xmlErrMemory(ctxt); +error: + if ((val != NULL) && (*alloc != 0)) + xmlFree(val); + return(hname); }
/** @@ -9527,7 +8990,7 @@ xmlParseStartTag2(xmlParserCtxtPtr ctxt, const xmlChar **pref, const xmlChar **atts = ctxt->atts; unsigned attrHashSize = 0; int maxatts = ctxt->maxatts; - int nratts, nbatts, nbdef, inputid; + int nratts, nbatts, nbdef; int i, j, nbNs, nbTotalDef, attval, nsIndex, maxAtts; int alloc = 0; int numNsErr = 0; @@ -9536,7 +8999,6 @@ xmlParseStartTag2(xmlParserCtxtPtr ctxt, const xmlChar **pref, if (RAW != '<') return(NULL); NEXT1;
- inputid = ctxt->input->id; nbatts = 0; nratts = 0; nbdef = 0; @@ -9545,7 +9007,7 @@ xmlParseStartTag2(xmlParserCtxtPtr ctxt, const xmlChar **pref, attval = 0;
if (xmlParserNsStartElement(ctxt->nsdb) < 0) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); return(NULL); }
@@ -9592,17 +9054,14 @@ xmlParseStartTag2(xmlParserCtxtPtr ctxt, const xmlChar **pref,
while (((RAW != '>') && ((RAW != '/') || (NXT(1) != '>')) && - (IS_BYTE_CHAR(RAW))) && (ctxt->instate != XML_PARSER_EOF)) { + (IS_BYTE_CHAR(RAW))) && (PARSER_STOPPED(ctxt) == 0)) { int len = -1;
hattname = xmlParseAttribute2(ctxt, prefix, localname, &haprefix, &attvalue, &len, &alloc); - if (hattname.name == NULL) { - xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR, - "xmlParseStartTag: problem parsing attributes\n"); + if (hattname.name == NULL) break; - } if (attvalue == NULL) goto next_attr; attname = hattname.name; @@ -9616,11 +9075,14 @@ xmlParseStartTag2(xmlParserCtxtPtr ctxt, const xmlChar **pref, huri = xmlDictLookupHashed(ctxt->dict, attvalue, len); uri = huri.name; if (uri == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); goto next_attr; } if (*uri != 0) { - parsedUri = xmlParseURI((const char *) uri); + if (xmlParseURISafe((const char *) uri, &parsedUri) < 0) { + xmlErrMemory(ctxt); + goto next_attr; + } if (parsedUri == NULL) { xmlNsErr(ctxt, XML_WAR_NS_URI, "xmlns: '%s' is not a valid URI\n", @@ -9660,7 +9122,7 @@ xmlParseStartTag2(xmlParserCtxtPtr ctxt, const xmlChar **pref, huri = xmlDictLookupHashed(ctxt->dict, attvalue, len); uri = huri.name; if (uri == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); goto next_attr; }
@@ -9703,7 +9165,10 @@ xmlParseStartTag2(xmlParserCtxtPtr ctxt, const xmlChar **pref, attname, NULL, NULL); goto next_attr; } else { - parsedUri = xmlParseURI((const char *) uri); + if (xmlParseURISafe((const char *) uri, &parsedUri) < 0) { + xmlErrMemory(ctxt); + goto next_attr; + } if (parsedUri == NULL) { xmlNsErr(ctxt, XML_WAR_NS_URI, "xmlns:%s: '%s' is not a valid URI\n", @@ -9765,8 +9230,6 @@ next_attr: }
GROW - if (ctxt->instate == XML_PARSER_EOF) - break; if ((RAW == '>') || (((RAW == '/') && (NXT(1) == '>')))) break; if (SKIP_BLANKS == 0) { @@ -9777,13 +9240,6 @@ next_attr: GROW; }
- if (ctxt->input->id != inputid) { - xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR, - "Unexpected change of input\n"); - localname = NULL; - goto done; - } - /* * Namespaces from default attributes */ @@ -9834,7 +9290,8 @@ next_attr: haprefix.name = aprefix; haprefix.hashValue = (size_t) atts[i+2]; nsIndex = xmlParserNsLookup(ctxt, &haprefix, NULL); - if (nsIndex == INT_MAX) { + + if ((nsIndex == INT_MAX) || (nsIndex < ctxt->nsdb->minNsIndex)) { xmlNsErr(ctxt, XML_NS_ERR_UNDEFINED_NAMESPACE, "Namespace prefix %s for %s on %s is not defined\n", aprefix, attname, localname); @@ -9863,7 +9320,7 @@ next_attr:
tmp = xmlRealloc(ctxt->attrHash, attrHashSize * sizeof(tmp[0])); if (tmp == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); goto done; }
@@ -9885,6 +9342,12 @@ next_attr: nameHashValue = ctxt->attallocs[j] | 0x80000000;
if (nsIndex == NS_INDEX_EMPTY) { + /* + * Prefix with empty namespace means an undeclared + * prefix which was already reported above. + */ + if (aprefix != NULL) + continue; nsuri = NULL; uriHashValue = URI_HASH_EMPTY; } else if (nsIndex == NS_INDEX_XML) { @@ -9953,7 +9416,8 @@ next_attr: uriHashValue = URI_HASH_XML; } else if (aprefix != NULL) { nsIndex = xmlParserNsLookup(ctxt, &attr->prefix, NULL); - if (nsIndex == INT_MAX) { + if ((nsIndex == INT_MAX) || + (nsIndex < ctxt->nsdb->minNsIndex)) { xmlNsErr(ctxt, XML_NS_ERR_UNDEFINED_NAMESPACE, "Namespace prefix %s for %s on %s is not " "defined\n", @@ -10141,8 +9605,6 @@ xmlParseEndTag2(xmlParserCtxtPtr ctxt, const xmlStartTag *tag) { * We should definitely be at the ending "S? '>'" part */ GROW; - if (ctxt->instate == XML_PARSER_EOF) - return; SKIP_BLANKS; if ((!IS_BYTE_CHAR(RAW)) || (RAW != '>')) { xmlFatalErr(ctxt, XML_ERR_GT_REQUIRED, NULL); @@ -10211,7 +9673,6 @@ xmlParseCDSect(xmlParserCtxtPtr ctxt) { return; SKIP(6);
- ctxt->instate = XML_PARSER_CDATA_SECTION; r = CUR_CHAR(rl); if (!IS_CHAR(r)) { xmlFatalErr(ctxt, XML_ERR_CDATA_NOT_FINISHED, NULL); @@ -10227,7 +9688,7 @@ xmlParseCDSect(xmlParserCtxtPtr ctxt) { cur = CUR_CHAR(l); buf = (xmlChar *) xmlMallocAtomic(size); if (buf == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); goto out; } while (IS_CHAR(cur) && @@ -10237,7 +9698,7 @@ xmlParseCDSect(xmlParserCtxtPtr ctxt) {
tmp = (xmlChar *) xmlRealloc(buf, size * 2); if (tmp == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); goto out; } buf = tmp; @@ -10257,10 +9718,6 @@ xmlParseCDSect(xmlParserCtxtPtr ctxt) { cur = CUR_CHAR(l); } buf[len] = 0; - if (ctxt->instate == XML_PARSER_EOF) { - xmlFree(buf); - return; - } if (cur != '>') { xmlFatalErrMsgStr(ctxt, XML_ERR_CDATA_NOT_FINISHED, "CData section not finished\n%.50s\n", buf); @@ -10279,8 +9736,6 @@ xmlParseCDSect(xmlParserCtxtPtr ctxt) { }
out: - if (ctxt->instate != XML_PARSER_EOF) - ctxt->instate = XML_PARSER_CONTENT; xmlFree(buf); }
@@ -10294,11 +9749,13 @@ out:
static void xmlParseContentInternal(xmlParserCtxtPtr ctxt) { - int nameNr = ctxt->nameNr; + int oldNameNr = ctxt->nameNr; + int oldSpaceNr = ctxt->spaceNr; + int oldNodeNr = ctxt->nodeNr;
GROW; while ((ctxt->input->cur < ctxt->input->end) && - (ctxt->instate != XML_PARSER_EOF)) { + (PARSER_STOPPED(ctxt) == 0)) { const xmlChar *cur = ctxt->input->cur;
/* @@ -10322,7 +9779,6 @@ xmlParseContentInternal(xmlParserCtxtPtr ctxt) { else if ((*cur == '<') && (NXT(1) == '!') && (NXT(2) == '-') && (NXT(3) == '-')) { xmlParseComment(ctxt); - ctxt->instate = XML_PARSER_CONTENT; }
/* @@ -10330,7 +9786,7 @@ xmlParseContentInternal(xmlParserCtxtPtr ctxt) { */ else if (*cur == '<') { if (NXT(1) == '/') { - if (ctxt->nameNr <= nameNr) + if (ctxt->nameNr <= oldNameNr) break; xmlParseElementEnd(ctxt); } else { @@ -10357,32 +9813,56 @@ xmlParseContentInternal(xmlParserCtxtPtr ctxt) { SHRINK; GROW; } + + if ((ctxt->nameNr > oldNameNr) && + (ctxt->input->cur >= ctxt->input->end) && + (ctxt->wellFormed)) { + const xmlChar *name = ctxt->nameTab[ctxt->nameNr - 1]; + int line = ctxt->pushTab[ctxt->nameNr - 1].line; + xmlFatalErrMsgStrIntStr(ctxt, XML_ERR_TAG_NOT_FINISHED, + "Premature end of data in tag %s line %d\n", + name, line, NULL); + } + + /* + * Clean up in error case + */ + + while (ctxt->nodeNr > oldNodeNr) + nodePop(ctxt); + + while (ctxt->nameNr > oldNameNr) { + xmlStartTag *tag = &ctxt->pushTab[ctxt->nameNr - 1]; + + if (tag->nsNr != 0) + xmlParserNsPop(ctxt, tag->nsNr); + + namePop(ctxt); + } + + while (ctxt->spaceNr > oldSpaceNr) + spacePop(ctxt); }
/** * xmlParseContent: * @ctxt: an XML parser context * - * Parse a content sequence. Stops at EOF or '</'. - * - * [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)* + * Parse XML element content. This is useful if you're only interested + * in custom SAX callbacks. If you want a node list, use + * xmlParseInNodeContext. */ - void xmlParseContent(xmlParserCtxtPtr ctxt) { - int nameNr = ctxt->nameNr; + if ((ctxt == NULL) || (ctxt->input == NULL)) + return; + + xmlCtxtInitializeLate(ctxt);
xmlParseContentInternal(ctxt);
- if ((ctxt->instate != XML_PARSER_EOF) && - (ctxt->errNo == XML_ERR_OK) && - (ctxt->nameNr > nameNr)) { - const xmlChar *name = ctxt->nameTab[ctxt->nameNr - 1]; - int line = ctxt->pushTab[ctxt->nameNr - 1].line; - xmlFatalErrMsgStrIntStr(ctxt, XML_ERR_TAG_NOT_FINISHED, - "Premature end of data in tag %s line %d\n", - name, line, NULL); - } + if (ctxt->input->cur < ctxt->input->end) + xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL); }
/** @@ -10407,11 +9887,9 @@ xmlParseElement(xmlParserCtxtPtr ctxt) { return;
xmlParseContentInternal(ctxt); - if (ctxt->instate == XML_PARSER_EOF) - return;
if (ctxt->input->cur >= ctxt->input->end) { - if (ctxt->errNo == XML_ERR_OK) { + if (ctxt->wellFormed) { const xmlChar *name = ctxt->nameTab[ctxt->nameNr - 1]; int line = ctxt->pushTab[ctxt->nameNr - 1].line; xmlFatalErrMsgStrIntStr(ctxt, XML_ERR_TAG_NOT_FINISHED, @@ -10435,6 +9913,7 @@ xmlParseElement(xmlParserCtxtPtr ctxt) { */ static int xmlParseElementStart(xmlParserCtxtPtr ctxt) { + int maxDepth = (ctxt->options & XML_PARSE_HUGE) ? 2048 : 256; const xmlChar *name; const xmlChar *prefix = NULL; const xmlChar *URI = NULL; @@ -10443,11 +9922,10 @@ xmlParseElementStart(xmlParserCtxtPtr ctxt) { xmlNodePtr cur; int nbNs = 0;
- if (((unsigned int) ctxt->nameNr > xmlParserMaxDepth) && - ((ctxt->options & XML_PARSE_HUGE) == 0)) { - xmlFatalErrMsgInt(ctxt, XML_ERR_INTERNAL_ERROR, - "Excessive depth in document: %d use XML_PARSE_HUGE option\n", - xmlParserMaxDepth); + if (ctxt->nameNr > maxDepth) { + xmlFatalErrMsgInt(ctxt, XML_ERR_RESOURCE_LIMIT, + "Excessive depth in document: %d use XML_PARSE_HUGE option\n", + ctxt->nameNr); xmlHaltParser(ctxt); return(-1); } @@ -10475,8 +9953,6 @@ xmlParseElementStart(xmlParserCtxtPtr ctxt) { else name = xmlParseStartTag(ctxt); #endif /* LIBXML_SAX1_ENABLED */ - if (ctxt->instate == XML_PARSER_EOF) - return(-1); if (name == NULL) { spacePop(ctxt); return(-1); @@ -10617,7 +10093,7 @@ xmlParseVersionNum(xmlParserCtxtPtr ctxt) {
buf = (xmlChar *) xmlMallocAtomic(size); if (buf == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); return(NULL); } cur = CUR; @@ -10643,7 +10119,7 @@ xmlParseVersionNum(xmlParserCtxtPtr ctxt) { tmp = (xmlChar *) xmlRealloc(buf, size); if (tmp == NULL) { xmlFree(buf); - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); return(NULL); } buf = tmp; @@ -10732,7 +10208,7 @@ xmlParseEncName(xmlParserCtxtPtr ctxt) { ((cur >= 'A') && (cur <= 'Z'))) { buf = (xmlChar *) xmlMallocAtomic(size); if (buf == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); return(NULL); }
@@ -10750,7 +10226,7 @@ xmlParseEncName(xmlParserCtxtPtr ctxt) { size *= 2; tmp = (xmlChar *) xmlRealloc(buf, size); if (tmp == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); xmlFree(buf); return(NULL); } @@ -10996,13 +10472,6 @@ xmlParseXMLDecl(xmlParserCtxtPtr ctxt) { xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, "Blank needed here\n"); } xmlParseEncodingDecl(ctxt); - if ((ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) || - (ctxt->instate == XML_PARSER_EOF)) { - /* - * The XML REC instructs us to stop parsing right here - */ - return; - }
/* * We may have the standalone status. @@ -11034,7 +10503,8 @@ xmlParseXMLDecl(xmlParserCtxtPtr ctxt) { int c;
xmlFatalErr(ctxt, XML_ERR_XMLDECL_NOT_FINISHED, NULL); - while ((c = CUR) != 0) { + while ((PARSER_STOPPED(ctxt) == 0) && + ((c = CUR) != 0)) { NEXT; if (c == '>') break; @@ -11055,7 +10525,7 @@ xmlParseXMLDecl(xmlParserCtxtPtr ctxt) {
void xmlParseMisc(xmlParserCtxtPtr ctxt) { - while (ctxt->instate != XML_PARSER_EOF) { + while (PARSER_STOPPED(ctxt) == 0) { SKIP_BLANKS; GROW; if ((RAW == '<') && (NXT(1) == '?')) { @@ -11068,25 +10538,52 @@ xmlParseMisc(xmlParserCtxtPtr ctxt) { } }
+static void +xmlFinishDocument(xmlParserCtxtPtr ctxt) { + xmlDocPtr doc; + + /* + * SAX: end of the document processing. + */ + if ((ctxt->sax) && (ctxt->sax->endDocument != NULL)) + ctxt->sax->endDocument(ctxt->userData); + + doc = ctxt->myDoc; + if (doc != NULL) { + if (ctxt->wellFormed) { + doc->properties |= XML_DOC_WELLFORMED; + if (ctxt->valid) + doc->properties |= XML_DOC_DTDVALID; + if (ctxt->nsWellFormed) + doc->properties |= XML_DOC_NSVALID; + } + + if (ctxt->options & XML_PARSE_OLD10) + doc->properties |= XML_DOC_OLD10; + + /* + * Remove locally kept entity definitions if the tree was not built + */ + if (xmlStrEqual(doc->version, SAX_COMPAT_MODE)) { + xmlFreeDoc(doc); + ctxt->myDoc = NULL; + } + } +} + /** * xmlParseDocument: * @ctxt: an XML parser context * - * parse an XML document (and build a tree if using the standard SAX - * interface). + * Parse an XML document and invoke the SAX handlers. This is useful + * if you're only interested in custom SAX callbacks. If you want a + * document tree, use xmlCtxtParseDocument. * - * [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. + * Returns 0, -1 in case of error. */
int xmlParseDocument(xmlParserCtxtPtr ctxt) { - xmlInitParser(); - if ((ctxt == NULL) || (ctxt->input == NULL)) return(-1);
@@ -11095,15 +10592,12 @@ xmlParseDocument(xmlParserCtxtPtr ctxt) { /* * SAX: detecting the level. */ - xmlDetectSAX2(ctxt); + xmlCtxtInitializeLate(ctxt);
- /* - * SAX: beginning of the document processing. - */ - if ((ctxt->sax) && (ctxt->sax->setDocumentLocator)) - ctxt->sax->setDocumentLocator(ctxt->userData, &xmlDefaultSAXLocator); - if (ctxt->instate == XML_PARSER_EOF) - return(-1); + if ((ctxt->sax) && (ctxt->sax->setDocumentLocator)) { + ctxt->sax->setDocumentLocator(ctxt->userData, + (xmlSAXLocator *) &xmlDefaultSAXLocator); + }
xmlDetectEncoding(ctxt);
@@ -11119,21 +10613,16 @@ xmlParseDocument(xmlParserCtxtPtr ctxt) { * Note that we will switch encoding on the fly. */ xmlParseXMLDecl(ctxt); - if ((ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) || - (ctxt->instate == XML_PARSER_EOF)) { - /* - * The XML REC instructs us to stop parsing right here - */ - return(-1); - } SKIP_BLANKS; } else { ctxt->version = xmlCharStrdup(XML_DEFAULT_VERSION); + if (ctxt->version == NULL) { + xmlErrMemory(ctxt); + return(-1); + } } if ((ctxt->sax) && (ctxt->sax->startDocument) && (!ctxt->disableSAX)) ctxt->sax->startDocument(ctxt->userData); - if (ctxt->instate == XML_PARSER_EOF) - return(-1); if ((ctxt->myDoc != NULL) && (ctxt->input != NULL) && (ctxt->input->buf != NULL) && (ctxt->input->buf->compressed >= 0)) { ctxt->myDoc->compression = ctxt->input->buf->compressed; @@ -11154,10 +10643,7 @@ xmlParseDocument(xmlParserCtxtPtr ctxt) { ctxt->inSubset = 1; xmlParseDocTypeDecl(ctxt); if (RAW == '[') { - ctxt->instate = XML_PARSER_DTD; xmlParseInternalSubset(ctxt); - if (ctxt->instate == XML_PARSER_EOF) - return(-1); }
/* @@ -11168,13 +10654,10 @@ xmlParseDocument(xmlParserCtxtPtr ctxt) { (!ctxt->disableSAX)) ctxt->sax->externalSubset(ctxt->userData, ctxt->intSubName, ctxt->extSubSystem, ctxt->extSubURI); - if (ctxt->instate == XML_PARSER_EOF) - return(-1); ctxt->inSubset = 0;
xmlCleanSpecialAttr(ctxt);
- ctxt->instate = XML_PARSER_PROLOG; xmlParseMisc(ctxt); }
@@ -11183,13 +10666,11 @@ xmlParseDocument(xmlParserCtxtPtr ctxt) { */ GROW; if (RAW != '<') { - xmlFatalErrMsg(ctxt, XML_ERR_DOCUMENT_EMPTY, - "Start tag expected, '<' not found\n"); + if (ctxt->wellFormed) + xmlFatalErrMsg(ctxt, XML_ERR_DOCUMENT_EMPTY, + "Start tag expected, '<' not found\n"); } else { - ctxt->instate = XML_PARSER_CONTENT; xmlParseElement(ctxt); - ctxt->instate = XML_PARSER_EPILOG; -
/* * The Misc part at the end @@ -11197,45 +10678,25 @@ xmlParseDocument(xmlParserCtxtPtr ctxt) { xmlParseMisc(ctxt);
if (ctxt->input->cur < ctxt->input->end) { - if (ctxt->errNo == XML_ERR_OK) + if (ctxt->wellFormed) xmlFatalErr(ctxt, XML_ERR_DOCUMENT_END, NULL); } else if ((ctxt->input->buf != NULL) && (ctxt->input->buf->encoder != NULL) && + (ctxt->input->buf->error == 0) && (!xmlBufIsEmpty(ctxt->input->buf->raw))) { xmlFatalErrMsg(ctxt, XML_ERR_INVALID_CHAR, "Truncated multi-byte sequence at EOF\n"); } - ctxt->instate = XML_PARSER_EOF; }
- /* - * SAX: end of the document processing. - */ - if ((ctxt->sax) && (ctxt->sax->endDocument != NULL)) - ctxt->sax->endDocument(ctxt->userData); - - /* - * 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; - } + ctxt->instate = XML_PARSER_EOF; + xmlFinishDocument(ctxt);
- if ((ctxt->wellFormed) && (ctxt->myDoc != NULL)) { - ctxt->myDoc->properties |= XML_DOC_WELLFORMED; - if (ctxt->valid) - ctxt->myDoc->properties |= XML_DOC_DTDVALID; - if (ctxt->nsWellFormed) - ctxt->myDoc->properties |= XML_DOC_NSVALID; - if (ctxt->options & XML_PARSE_OLD10) - ctxt->myDoc->properties |= XML_DOC_OLD10; - } if (! ctxt->wellFormed) { ctxt->valid = 0; return(-1); } + return(0); }
@@ -11258,13 +10719,12 @@ xmlParseExtParsedEnt(xmlParserCtxtPtr ctxt) { if ((ctxt == NULL) || (ctxt->input == NULL)) return(-1);
- xmlDetectSAX2(ctxt); + xmlCtxtInitializeLate(ctxt);
- /* - * SAX: beginning of the document processing. - */ - if ((ctxt->sax) && (ctxt->sax->setDocumentLocator)) - ctxt->sax->setDocumentLocator(ctxt->userData, &xmlDefaultSAXLocator); + if ((ctxt->sax) && (ctxt->sax->setDocumentLocator)) { + ctxt->sax->setDocumentLocator(ctxt->userData, + (xmlSAXLocator *) &xmlDefaultSAXLocator); + }
xmlDetectEncoding(ctxt);
@@ -11282,38 +10742,24 @@ xmlParseExtParsedEnt(xmlParserCtxtPtr ctxt) { * 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); - if (ctxt->instate == XML_PARSER_EOF) - return(-1);
/* * Doing validity checking on chunk doesn't make sense */ - ctxt->instate = XML_PARSER_CONTENT; + ctxt->options &= ~XML_PARSE_DTDVALID; ctxt->validate = 0; - ctxt->loadsubset = 0; ctxt->depth = 0;
- xmlParseContent(ctxt); - if (ctxt->instate == XML_PARSER_EOF) - return(-1); + xmlParseContentInternal(ctxt);
- if ((RAW == '<') && (NXT(1) == '/')) { + if (ctxt->input->cur < ctxt->input->end) 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. @@ -11681,10 +11127,7 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) { xmlParserShrink(ctxt); }
- while (ctxt->instate != XML_PARSER_EOF) { - if ((ctxt->errNo != XML_ERR_OK) && (ctxt->disableSAX == 1)) - return(0); - + while (ctxt->disableSAX == 0) { avail = ctxt->input->end - ctxt->input->cur; if (avail < 1) goto done; @@ -11710,8 +11153,6 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) { goto done;
xmlDetectEncoding(ctxt); - if (ctxt->instate == XML_PARSER_EOF) - goto done; ctxt->instate = XML_PARSER_XML_DECL; break;
@@ -11731,32 +11172,27 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) { (IS_BLANK_CH(ctxt->input->cur[5]))) { ret += 5; xmlParseXMLDecl(ctxt); - if (ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) { - /* - * The XML REC instructs us to stop parsing right - * here - */ - xmlHaltParser(ctxt); - return(0); - } } else { ctxt->version = xmlCharStrdup(XML_DEFAULT_VERSION); + if (ctxt->version == NULL) { + xmlErrMemory(ctxt); + break; + } } } else { ctxt->version = xmlCharStrdup(XML_DEFAULT_VERSION); if (ctxt->version == NULL) { - xmlErrMemory(ctxt, NULL); + xmlErrMemory(ctxt); break; } } - if ((ctxt->sax) && (ctxt->sax->setDocumentLocator)) + if ((ctxt->sax) && (ctxt->sax->setDocumentLocator)) { ctxt->sax->setDocumentLocator(ctxt->userData, - &xmlDefaultSAXLocator); + (xmlSAXLocator *) &xmlDefaultSAXLocator); + } if ((ctxt->sax) && (ctxt->sax->startDocument) && (!ctxt->disableSAX)) ctxt->sax->startDocument(ctxt->userData); - if (ctxt->instate == XML_PARSER_EOF) - goto done; ctxt->instate = XML_PARSER_MISC; break; case XML_PARSER_START_TAG: { @@ -11772,9 +11208,8 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) { if (cur != '<') { xmlFatalErrMsg(ctxt, XML_ERR_DOCUMENT_EMPTY, "Start tag expected, '<' not found"); - xmlHaltParser(ctxt); - if ((ctxt->sax) && (ctxt->sax->endDocument != NULL)) - ctxt->sax->endDocument(ctxt->userData); + ctxt->instate = XML_PARSER_EOF; + xmlFinishDocument(ctxt); goto done; } if ((!terminate) && (!xmlParseLookupGt(ctxt))) @@ -11793,13 +11228,10 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) { else name = xmlParseStartTag(ctxt); #endif /* LIBXML_SAX1_ENABLED */ - if (ctxt->instate == XML_PARSER_EOF) - goto done; if (name == NULL) { spacePop(ctxt); - xmlHaltParser(ctxt); - if ((ctxt->sax) && (ctxt->sax->endDocument != NULL)) - ctxt->sax->endDocument(ctxt->userData); + ctxt->instate = XML_PARSER_EOF; + xmlFinishDocument(ctxt); goto done; } #ifdef LIBXML_VALID_ENABLED @@ -11849,8 +11281,6 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) { xmlParserNsPop(ctxt, nbNs); }
- if (ctxt->instate == XML_PARSER_EOF) - goto done; if (ctxt->nameNr == 0) ctxt->instate = XML_PARSER_EPILOG; else @@ -11873,8 +11303,6 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) { (!xmlParseLookupString(ctxt, 2, "?>", 2))) goto done; xmlParsePI(ctxt); - if (ctxt->instate == XML_PARSER_EOF) - goto done; ctxt->instate = XML_PARSER_CONTENT; break; } else if (next == '!') { @@ -11890,8 +11318,6 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) { (!xmlParseLookupString(ctxt, 4, "-->", 3))) goto done; xmlParseComment(ctxt); - if (ctxt->instate == XML_PARSER_EOF) - goto done; ctxt->instate = XML_PARSER_CONTENT; break; } @@ -11952,8 +11378,6 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) { else xmlParseEndTag1(ctxt, 0); #endif /* LIBXML_SAX1_ENABLED */ - if (ctxt->instate == XML_PARSER_EOF) - goto done; if (ctxt->nameNr == 0) { ctxt->instate = XML_PARSER_EPILOG; } else { @@ -12005,8 +11429,6 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) { ctxt->sax->characters(ctxt->userData, ctxt->input->cur, tmp); } - if (ctxt->instate == XML_PARSER_EOF) - goto done; SKIPL(tmp); } else { int base = term - CUR_PTR; @@ -12040,8 +11462,6 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) { ctxt->sax->characters(ctxt->userData, ctxt->input->cur, base); } - if (ctxt->instate == XML_PARSER_EOF) - goto done; SKIPL(base + 3); ctxt->instate = XML_PARSER_CONTENT; } @@ -12063,8 +11483,6 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) { (!xmlParseLookupString(ctxt, 2, "?>", 2))) goto done; xmlParsePI(ctxt); - if (ctxt->instate == XML_PARSER_EOF) - goto done; break; } else if (next == '!') { if ((!terminate) && (avail < 3)) @@ -12078,8 +11496,6 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) { (!xmlParseLookupString(ctxt, 4, "-->", 3))) goto done; xmlParseComment(ctxt); - if (ctxt->instate == XML_PARSER_EOF) - goto done; break; } } else if (ctxt->instate == XML_PARSER_MISC) { @@ -12096,8 +11512,6 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) { goto done; ctxt->inSubset = 1; xmlParseDocTypeDecl(ctxt); - if (ctxt->instate == XML_PARSER_EOF) - goto done; if (RAW == '[') { ctxt->instate = XML_PARSER_DTD; } else { @@ -12115,8 +11529,6 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) { ctxt->extSubURI); ctxt->inSubset = 0; xmlCleanSpecialAttr(ctxt); - if (ctxt->instate == XML_PARSER_EOF) - goto done; ctxt->instate = XML_PARSER_PROLOG; } break; @@ -12129,8 +11541,7 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) { if (ctxt->errNo == XML_ERR_OK) xmlFatalErr(ctxt, XML_ERR_DOCUMENT_END, NULL); ctxt->instate = XML_PARSER_EOF; - if ((ctxt->sax) && (ctxt->sax->endDocument != NULL)) - ctxt->sax->endDocument(ctxt->userData); + xmlFinishDocument(ctxt); } else { ctxt->instate = XML_PARSER_START_TAG; } @@ -12139,8 +11550,6 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) { if ((!terminate) && (!xmlParseLookupInternalSubset(ctxt))) goto done; xmlParseInternalSubset(ctxt); - if (ctxt->instate == XML_PARSER_EOF) - goto done; ctxt->inSubset = 2; if ((ctxt->sax != NULL) && (!ctxt->disableSAX) && (ctxt->sax->externalSubset != NULL)) @@ -12148,13 +11557,11 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) { ctxt->extSubSystem, ctxt->extSubURI); ctxt->inSubset = 0; xmlCleanSpecialAttr(ctxt); - if (ctxt->instate == XML_PARSER_EOF) - goto done; ctxt->instate = XML_PARSER_PROLOG; break; } default: - xmlGenericError(xmlGenericErrorContext, + xmlFatalErrMsg(ctxt, XML_ERR_INTERNAL_ERROR, "PP: internal error\n"); ctxt->instate = XML_PARSER_EOF; break; @@ -12163,19 +11570,10 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) { done: return(ret); encoding_error: - if (ctxt->input->end - ctxt->input->cur < 4) { - __xmlErrEncoding(ctxt, XML_ERR_INVALID_CHAR, - "Input is not proper UTF-8, indicate encoding !\n", - NULL, NULL); - } else { - 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); + /* Only report the first error */ + if ((ctxt->input->flags & XML_INPUT_ENCODING_ERROR) == 0) { + xmlCtxtErrIO(ctxt, XML_ERR_INVALID_ENCODING, NULL); + ctxt->input->flags |= XML_INPUT_ENCODING_ERROR; } return(0); } @@ -12183,31 +11581,42 @@ encoding_error: /** * xmlParseChunk: * @ctxt: an XML parser context - * @chunk: an char array - * @size: the size in byte of the chunk + * @chunk: chunk of memory + * @size: size of chunk in bytes * @terminate: last chunk indicator * - * Parse a Chunk of memory + * Parse a chunk of memory in push parser mode. * - * Returns zero if no error, the xmlParserErrors otherwise. + * Assumes that the parser context was initialized with + * xmlCreatePushParserCtxt. + * + * The last chunk, which will often be empty, must be marked with + * the @terminate flag. With the default SAX callbacks, the resulting + * document will be available in ctxt->myDoc. This pointer will not + * be freed by the library. + * + * If the document isn't well-formed, ctxt->myDoc is set to NULL. + * The push parser doesn't support recovery mode. + * + * Returns an xmlParserErrors code (0 on success). */ int xmlParseChunk(xmlParserCtxtPtr ctxt, const char *chunk, int size, int terminate) { + size_t curBase; + size_t maxLength; int end_in_lf = 0;
- if (ctxt == NULL) - return(XML_ERR_INTERNAL_ERROR); - if ((ctxt->errNo != XML_ERR_OK) && (ctxt->disableSAX == 1)) + if ((ctxt == NULL) || (size < 0)) + return(XML_ERR_ARGUMENT); + if (ctxt->disableSAX != 0) return(ctxt->errNo); - if (ctxt->instate == XML_PARSER_EOF) - return(-1); if (ctxt->input == NULL) - return(-1); + return(XML_ERR_INTERNAL_ERROR);
- ctxt->progressive = 1; + ctxt->input->flags |= XML_INPUT_PROGRESSIVE; if (ctxt->instate == XML_PARSER_START) - xmlDetectSAX2(ctxt); + xmlCtxtInitializeLate(ctxt); if ((size > 0) && (chunk != NULL) && (!terminate) && (chunk[size - 1] == '\r')) { end_in_lf = 1; @@ -12215,31 +11624,32 @@ xmlParseChunk(xmlParserCtxtPtr ctxt, const char *chunk, int size, }
if ((size > 0) && (chunk != NULL) && (ctxt->input != NULL) && - (ctxt->input->buf != NULL) && (ctxt->instate != XML_PARSER_EOF)) { + (ctxt->input->buf != NULL)) { size_t pos = ctxt->input->cur - ctxt->input->base; int res;
res = xmlParserInputBufferPush(ctxt->input->buf, size, chunk); xmlBufUpdateInput(ctxt->input->buf->buffer, ctxt->input, pos); if (res < 0) { - xmlFatalErr(ctxt, ctxt->input->buf->error, NULL); + xmlCtxtErrIO(ctxt, ctxt->input->buf->error, NULL); xmlHaltParser(ctxt); return(ctxt->errNo); } }
xmlParseTryOrFinish(ctxt, terminate); - if (ctxt->instate == XML_PARSER_EOF) - return(ctxt->errNo);
- if ((ctxt->input != NULL) && - (((ctxt->input->end - ctxt->input->cur) > XML_MAX_LOOKUP_LIMIT) || - ((ctxt->input->cur - ctxt->input->base) > XML_MAX_LOOKUP_LIMIT)) && - ((ctxt->options & XML_PARSE_HUGE) == 0)) { - xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR, "Huge input lookup"); + curBase = ctxt->input->cur - ctxt->input->base; + maxLength = (ctxt->options & XML_PARSE_HUGE) ? + XML_MAX_HUGE_LENGTH : + XML_MAX_LOOKUP_LIMIT; + if (curBase > maxLength) { + xmlFatalErr(ctxt, XML_ERR_RESOURCE_LIMIT, + "Buffer size limit exceeded, try XML_PARSE_HUGE\n"); xmlHaltParser(ctxt); } - if ((ctxt->errNo != XML_ERR_OK) && (ctxt->disableSAX == 1)) + + if ((ctxt->errNo != XML_ERR_OK) && (ctxt->disableSAX != 0)) return(ctxt->errNo);
if ((end_in_lf == 1) && (ctxt->input != NULL) && @@ -12250,7 +11660,7 @@ xmlParseChunk(xmlParserCtxtPtr ctxt, const char *chunk, int size, res = xmlParserInputBufferPush(ctxt->input->buf, 1, "\r"); xmlBufUpdateInput(ctxt->input->buf->buffer, ctxt->input, pos); if (res < 0) { - xmlFatalErr(ctxt, ctxt->input->buf->error, NULL); + xmlCtxtErrIO(ctxt, ctxt->input->buf->error, NULL); xmlHaltParser(ctxt); return(ctxt->errNo); } @@ -12275,15 +11685,15 @@ xmlParseChunk(xmlParserCtxtPtr ctxt, const char *chunk, int size, } } else if ((ctxt->input->buf != NULL) && (ctxt->input->buf->encoder != NULL) && + (ctxt->input->buf->error == 0) && (!xmlBufIsEmpty(ctxt->input->buf->raw))) { xmlFatalErrMsg(ctxt, XML_ERR_INVALID_CHAR, "Truncated multi-byte sequence at EOF\n"); } if (ctxt->instate != XML_PARSER_EOF) { - if ((ctxt->sax) && (ctxt->sax->endDocument != NULL)) - ctxt->sax->endDocument(ctxt->userData); + ctxt->instate = XML_PARSER_EOF; + xmlFinishDocument(ctxt); } - ctxt->instate = XML_PARSER_EOF; } if (ctxt->wellFormed == 0) return((xmlParserErrors) ctxt->errNo); @@ -12299,81 +11709,42 @@ xmlParseChunk(xmlParserCtxtPtr ctxt, const char *chunk, int size,
/** * xmlCreatePushParserCtxt: - * @sax: a SAX handler - * @user_data: The user data returned on SAX callbacks - * @chunk: a pointer to an array of chars - * @size: number of chars in the array - * @filename: an optional file name or URI + * @sax: a SAX handler (optional) + * @user_data: user data for SAX callbacks (optional) + * @chunk: initial chunk (optional, deprecated) + * @size: size of initial chunk in bytes + * @filename: file name or URI (optional) * * 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. + * See xmlParseChunk. * - * Returns the new parser context or NULL + * Passing an initial chunk is useless and deprecated. + * + * @filename is used as base URI to fetch external entities and for + * error reports. + * + * Returns the new parser context or NULL in case of error. */
xmlParserCtxtPtr xmlCreatePushParserCtxt(xmlSAXHandlerPtr sax, void *user_data, const char *chunk, int size, const char *filename) { xmlParserCtxtPtr ctxt; - xmlParserInputPtr inputStream; - xmlParserInputBufferPtr buf; - - buf = xmlAllocParserInputBuffer(XML_CHAR_ENCODING_NONE); - if (buf == NULL) return(NULL); + xmlParserInputPtr input;
ctxt = xmlNewSAXParserCtxt(sax, user_data); - if (ctxt == NULL) { - xmlErrMemory(NULL, "creating parser: out of memory\n"); - xmlFreeParserInputBuffer(buf); + if (ctxt == NULL) return(NULL); - } + + ctxt->options &= ~XML_PARSE_NODICT; ctxt->dictNames = 1; - if (filename == NULL) { - ctxt->directory = NULL; - } else { - ctxt->directory = xmlParserGetDirectory(filename); - }
- inputStream = xmlNewInputStream(ctxt); - if (inputStream == NULL) { + input = xmlNewInputPush(ctxt, filename, chunk, size, NULL); + if (input == NULL) { xmlFreeParserCtxt(ctxt); - xmlFreeParserInputBuffer(buf); return(NULL); } - - if (filename == NULL) - inputStream->filename = NULL; - else { - inputStream->filename = (char *) - xmlCanonicPath((const xmlChar *) filename); - if (inputStream->filename == NULL) { - xmlFreeInputStream(inputStream); - xmlFreeParserCtxt(ctxt); - xmlFreeParserInputBuffer(buf); - return(NULL); - } - } - inputStream->buf = buf; - xmlBufResetInput(inputStream->buf->buffer, inputStream); - inputPush(ctxt, inputStream); - - if ((size != 0) && (chunk != NULL) && - (ctxt->input != NULL) && (ctxt->input->buf != NULL)) { - size_t pos = ctxt->input->cur - ctxt->input->base; - int res; - - res = xmlParserInputBufferPush(ctxt->input->buf, size, chunk); - xmlBufUpdateInput(ctxt->input->buf->buffer, ctxt->input, pos); - if (res < 0) { - xmlFatalErr(ctxt, ctxt->input->buf->error, NULL); - xmlHaltParser(ctxt); - } - } + inputPush(ctxt, input);
return(ctxt); } @@ -12390,17 +11761,18 @@ xmlStopParser(xmlParserCtxtPtr ctxt) { if (ctxt == NULL) return; xmlHaltParser(ctxt); - ctxt->errNo = XML_ERR_USER_STOP; + if (ctxt->errNo != XML_ERR_NO_MEMORY) + ctxt->errNo = XML_ERR_USER_STOP; }
/** * xmlCreateIOParserCtxt: - * @sax: a SAX handler - * @user_data: The user data returned on SAX callbacks + * @sax: a SAX handler (optional) + * @user_data: user data for SAX callbacks (optional) * @ioread: an I/O read function - * @ioclose: an I/O close function + * @ioclose: an I/O close function (optional) * @ioctx: an I/O handler - * @enc: the charset encoding if known + * @enc: the charset encoding if known (deprecated) * * Create a parser context for using the XML parser with an existing * I/O stream @@ -12409,33 +11781,24 @@ xmlStopParser(xmlParserCtxtPtr ctxt) { */ xmlParserCtxtPtr xmlCreateIOParserCtxt(xmlSAXHandlerPtr sax, void *user_data, - xmlInputReadCallback ioread, xmlInputCloseCallback ioclose, - void *ioctx, xmlCharEncoding enc) { + xmlInputReadCallback ioread, + xmlInputCloseCallback ioclose, + void *ioctx, xmlCharEncoding enc) { xmlParserCtxtPtr ctxt; - xmlParserInputPtr inputStream; - xmlParserInputBufferPtr buf; - - if (ioread == NULL) return(NULL); - - buf = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx, enc); - if (buf == NULL) { - if (ioclose != NULL) - ioclose(ioctx); - return (NULL); - } + xmlParserInputPtr input; + const char *encoding;
ctxt = xmlNewSAXParserCtxt(sax, user_data); - if (ctxt == NULL) { - xmlFreeParserInputBuffer(buf); + if (ctxt == NULL) return(NULL); - }
- inputStream = xmlNewIOInputStream(ctxt, buf, enc); - if (inputStream == NULL) { + encoding = xmlGetCharEncodingName(enc); + input = xmlNewInputIO(ctxt, NULL, ioread, ioclose, ioctx, encoding, 0); + if (input == NULL) { xmlFreeParserCtxt(ctxt); - return(NULL); + return (NULL); } - inputPush(ctxt, inputStream); + inputPush(ctxt, input);
return(ctxt); } @@ -12474,11 +11837,7 @@ xmlIOParseDTD(xmlSAXHandlerPtr sax, xmlParserInputBufferPtr input, xmlFreeParserInputBuffer(input); return(NULL); } - - /* We are loading a DTD */ - ctxt->options |= XML_PARSE_DTDLOAD; - - xmlDetectSAX2(ctxt); + xmlCtxtSetOptions(ctxt, XML_PARSE_DTDLOAD);
/* * generate a parser input from the I/O handler @@ -12505,18 +11864,15 @@ xmlIOParseDTD(xmlSAXHandlerPtr sax, xmlParserInputBufferPtr input, /* * let's parse that entity knowing it's an external subset. */ - ctxt->inSubset = 2; ctxt->myDoc = xmlNewDoc(BAD_CAST "1.0"); if (ctxt->myDoc == NULL) { - xmlErrMemory(ctxt, "New Doc failed"); + xmlErrMemory(ctxt); return(NULL); } ctxt->myDoc->properties = XML_DOC_INTERNAL; ctxt->myDoc->extSubset = xmlNewDtd(ctxt->myDoc, BAD_CAST "none", BAD_CAST "none", BAD_CAST "none");
- xmlDetectEncoding(ctxt); - xmlParseExternalSubset(ctxt, BAD_CAST "none", BAD_CAST "none");
if (ctxt->myDoc != NULL) { @@ -12571,9 +11927,7 @@ xmlSAXParseDTD(xmlSAXHandlerPtr sax, const xmlChar *ExternalID, if (ctxt == NULL) { return(NULL); } - - /* We are loading a DTD */ - ctxt->options |= XML_PARSE_DTDLOAD; + xmlCtxtSetOptions(ctxt, XML_PARSE_DTDLOAD);
/* * Canonicalise the system ID @@ -12618,16 +11972,20 @@ xmlSAXParseDTD(xmlSAXHandlerPtr sax, const xmlChar *ExternalID, /* * let's parse that entity knowing it's an external subset. */ - ctxt->inSubset = 2; ctxt->myDoc = xmlNewDoc(BAD_CAST "1.0"); if (ctxt->myDoc == NULL) { - xmlErrMemory(ctxt, "New Doc failed"); + xmlErrMemory(ctxt); xmlFreeParserCtxt(ctxt); return(NULL); } ctxt->myDoc->properties = XML_DOC_INTERNAL; ctxt->myDoc->extSubset = xmlNewDtd(ctxt->myDoc, BAD_CAST "none", ExternalID, SystemID); + if (ctxt->myDoc->extSubset == NULL) { + xmlFreeDoc(ctxt->myDoc); + xmlFreeParserCtxt(ctxt); + return(NULL); + } xmlParseExternalSubset(ctxt, ExternalID, SystemID);
if (ctxt->myDoc != NULL) { @@ -12678,258 +12036,255 @@ xmlParseDTD(const xmlChar *ExternalID, const xmlChar *SystemID) { * * ************************************************************************/
-/** - * xmlParseCtxtExternalEntity: - * @ctx: the existing parsing context - * @URL: the URL for the entity to load - * @ID: the System ID for the entity to load - * @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 - */ +static xmlNodePtr +xmlCtxtParseContent(xmlParserCtxtPtr ctxt, xmlParserInputPtr input, + int hasTextDecl, int buildTree) { + xmlNodePtr root = NULL; + xmlNodePtr list = NULL; + xmlChar *rootName = BAD_CAST "#root"; + int result;
-int -xmlParseCtxtExternalEntity(xmlParserCtxtPtr ctx, const xmlChar *URL, - const xmlChar *ID, xmlNodePtr *lst) { - void *userData; + if (buildTree) { + root = xmlNewDocNode(ctxt->myDoc, NULL, rootName, NULL); + if (root == NULL) { + xmlErrMemory(ctxt); + goto error; + } + }
- if (ctx == NULL) return(-1); - /* - * If the user provided their own SAX callbacks, then reuse the - * userData callback field, otherwise the expected setup in a - * DOM builder is to have userData == ctxt - */ - if (ctx->userData == ctx) - userData = NULL; - else - userData = ctx->userData; - return xmlParseExternalEntityPrivate(ctx->myDoc, ctx, ctx->sax, - userData, ctx->depth + 1, - URL, ID, lst); -} + if (xmlPushInput(ctxt, input) < 0) + goto error;
-/** - * xmlParseExternalEntityPrivate: - * @doc: the document the chunk pertains to - * @oldctxt: the previous parser context if available - * @sax: the SAX handler block (possibly NULL) - * @user_data: The user data returned on SAX callbacks (possibly NULL) - * @depth: Used for loop detection, use 0 - * @URL: the URL for the entity to load - * @ID: the System ID for the entity to load - * @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 - */ + nameNsPush(ctxt, rootName, NULL, NULL, 0, 0); + spacePush(ctxt, -1);
-static xmlParserErrors -xmlParseExternalEntityPrivate(xmlDocPtr doc, xmlParserCtxtPtr oldctxt, - xmlSAXHandlerPtr sax, - void *user_data, int depth, const xmlChar *URL, - const xmlChar *ID, xmlNodePtr *list) { - xmlParserCtxtPtr ctxt; - xmlDocPtr newDoc; - xmlNodePtr newRoot; - xmlParserErrors ret = XML_ERR_OK; + if (buildTree) + nodePush(ctxt, root);
- if (((depth > 40) && - ((oldctxt == NULL) || (oldctxt->options & XML_PARSE_HUGE) == 0)) || - (depth > 100)) { - xmlFatalErrMsg(oldctxt, XML_ERR_ENTITY_LOOP, - "Maximum entity nesting depth exceeded"); - return(XML_ERR_ENTITY_LOOP); + if (hasTextDecl) { + xmlDetectEncoding(ctxt); + + /* + * Parse a possible text declaration first + */ + if ((CMP5(CUR_PTR, '<', '?', 'x', 'm', 'l')) && + (IS_BLANK_CH(NXT(5)))) { + xmlParseTextDecl(ctxt); + /* + * An XML-1.0 document can't reference an entity not XML-1.0 + */ + if ((xmlStrEqual(ctxt->version, BAD_CAST "1.0")) && + (!xmlStrEqual(ctxt->input->version, BAD_CAST "1.0"))) { + xmlFatalErrMsg(ctxt, XML_ERR_VERSION_MISMATCH, + "Version mismatch between document and " + "entity\n"); + } + } }
- if (list != NULL) - *list = NULL; - if ((URL == NULL) && (ID == NULL)) - return(XML_ERR_INTERNAL_ERROR); - if (doc == NULL) - return(XML_ERR_INTERNAL_ERROR); + xmlParseContentInternal(ctxt);
- ctxt = xmlCreateEntityParserCtxtInternal(sax, user_data, URL, ID, NULL, - oldctxt); - if (ctxt == NULL) return(XML_WAR_UNDECLARED_ENTITY); - if (oldctxt != NULL) { - ctxt->nbErrors = oldctxt->nbErrors; - ctxt->nbWarnings = oldctxt->nbWarnings; - } - xmlDetectSAX2(ctxt); + if (ctxt->input->cur < ctxt->input->end) + xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL);
- newDoc = xmlNewDoc(BAD_CAST "1.0"); - if (newDoc == NULL) { - xmlFreeParserCtxt(ctxt); - return(XML_ERR_INTERNAL_ERROR); - } - newDoc->properties = XML_DOC_INTERNAL; - if (doc) { - newDoc->intSubset = doc->intSubset; - newDoc->extSubset = doc->extSubset; - if (doc->dict) { - newDoc->dict = doc->dict; - xmlDictReference(newDoc->dict); - } - if (doc->URL != NULL) { - newDoc->URL = xmlStrdup(doc->URL); + if ((ctxt->wellFormed) || + ((ctxt->recovery) && (ctxt->errNo != XML_ERR_NO_MEMORY))) { + if (root != NULL) { + xmlNodePtr cur; + + /* + * Return the newly created nodeset after unlinking it from + * its pseudo parent. + */ + cur = root->children; + list = cur; + while (cur != NULL) { + cur->parent = NULL; + cur = cur->next; + } + root->children = NULL; + root->last = NULL; } } - newRoot = xmlNewDocNode(newDoc, NULL, BAD_CAST "pseudoroot", NULL); - if (newRoot == NULL) { - if (sax != NULL) - xmlFreeParserCtxt(ctxt); - newDoc->intSubset = NULL; - newDoc->extSubset = NULL; - xmlFreeDoc(newDoc); - return(XML_ERR_INTERNAL_ERROR); - } - xmlAddChild((xmlNodePtr) newDoc, newRoot); - nodePush(ctxt, newDoc->children); - if (doc == NULL) { - ctxt->myDoc = newDoc; - } else { - ctxt->myDoc = doc; - newRoot->doc = doc; - }
- xmlDetectEncoding(ctxt); + /* + * Read the rest of the stream in case of errors. We want + * to account for the whole entity size. + */ + do { + ctxt->input->cur = ctxt->input->end; + xmlParserShrink(ctxt); + result = xmlParserGrow(ctxt); + } while (result > 0); + + if (buildTree) + nodePop(ctxt); + + namePop(ctxt); + spacePop(ctxt); + + /* xmlPopInput would free the stream */ + inputPop(ctxt); + +error: + xmlFreeNode(root); + + return(list); +} + +static void +xmlCtxtParseEntity(xmlParserCtxtPtr ctxt, xmlEntityPtr ent) { + xmlParserInputPtr input; + xmlNodePtr list; + unsigned long consumed; + int isExternal; + int buildTree; + int oldMinNsIndex; + int oldNodelen, oldNodemem; + + isExternal = (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY); + buildTree = (ctxt->node != NULL);
/* - * Parse a possible text declaration first + * Recursion check */ - if ((CMP5(CUR_PTR, '<', '?', 'x', 'm', 'l')) && (IS_BLANK_CH(NXT(5)))) { - xmlParseTextDecl(ctxt); - /* - * An XML-1.0 document can't reference an entity not XML-1.0 - */ - if ((xmlStrEqual(oldctxt->version, BAD_CAST "1.0")) && - (!xmlStrEqual(ctxt->input->version, BAD_CAST "1.0"))) { - xmlFatalErrMsg(ctxt, XML_ERR_VERSION_MISMATCH, - "Version mismatch between document and entity\n"); - } + if (ent->flags & XML_ENT_EXPANDING) { + xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL); + xmlHaltParser(ctxt); + goto error; }
- ctxt->instate = XML_PARSER_CONTENT; - ctxt->depth = depth; - if (oldctxt != NULL) { - ctxt->_private = oldctxt->_private; - ctxt->loadsubset = oldctxt->loadsubset; - ctxt->validate = oldctxt->validate; - ctxt->valid = oldctxt->valid; - ctxt->replaceEntities = oldctxt->replaceEntities; - if (oldctxt->validate) { - ctxt->vctxt.error = oldctxt->vctxt.error; - ctxt->vctxt.warning = oldctxt->vctxt.warning; - ctxt->vctxt.userData = oldctxt->vctxt.userData; - ctxt->vctxt.flags = oldctxt->vctxt.flags; + /* + * Load entity + */ + input = xmlNewEntityInputStream(ctxt, ent); + if (input == NULL) + goto error; + + /* + * When building a tree, we need to limit the scope of namespace + * declarations, so that entities don't reference xmlNs structs + * from the parent of a reference. + */ + oldMinNsIndex = ctxt->nsdb->minNsIndex; + if (buildTree) + ctxt->nsdb->minNsIndex = ctxt->nsNr; + + oldNodelen = ctxt->nodelen; + oldNodemem = ctxt->nodemem; + ctxt->nodelen = 0; + ctxt->nodemem = 0; + + /* + * Parse content + * + * This initiates a recursive call chain: + * + * - xmlCtxtParseContent + * - xmlParseContentInternal + * - xmlParseReference + * - xmlCtxtParseEntity + * + * The nesting depth is limited by the maximum number of inputs, + * see xmlPushInput. + * + * It's possible to make this non-recursive (minNsIndex must be + * stored in the input struct) at the expense of code readability. + */ + + ent->flags |= XML_ENT_EXPANDING; + + list = xmlCtxtParseContent(ctxt, input, isExternal, buildTree); + + ent->flags &= ~XML_ENT_EXPANDING; + + ctxt->nsdb->minNsIndex = oldMinNsIndex; + ctxt->nodelen = oldNodelen; + ctxt->nodemem = oldNodemem; + + /* + * Entity size accounting + */ + consumed = input->consumed; + xmlSaturatedAddSizeT(&consumed, input->end - input->base); + + if ((ent->flags & XML_ENT_CHECKED) == 0) + xmlSaturatedAdd(&ent->expandedSize, consumed); + + if ((ent->flags & XML_ENT_PARSED) == 0) { + if (isExternal) + xmlSaturatedAdd(&ctxt->sizeentities, consumed); + + ent->children = list; + + while (list != NULL) { + list->parent = (xmlNodePtr) ent; + + /* + * Downstream code like the nginx xslt module can set + * ctxt->myDoc->extSubset to a separate DTD, so the entity + * might have a different or a NULL document. + */ + if (list->doc != ent->doc) + xmlSetTreeDoc(list, ent->doc); + + if (list->next == NULL) + ent->last = list; + list = list->next; } - ctxt->external = oldctxt->external; - if (ctxt->dict) 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); - ctxt->dictNames = oldctxt->dictNames; - ctxt->attsDefault = oldctxt->attsDefault; - ctxt->attsSpecial = oldctxt->attsSpecial; - ctxt->linenumbers = oldctxt->linenumbers; - 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; } else { - /* - * Doing validity checking on chunk without context - * doesn't make sense - */ - ctxt->_private = NULL; - ctxt->validate = 0; - ctxt->external = 2; - ctxt->loadsubset = 0; + xmlFreeNodeList(list); }
- xmlParseContent(ctxt); + xmlFreeInputStream(input);
- 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); - } +error: + ent->flags |= XML_ENT_PARSED | XML_ENT_CHECKED; +}
- if (!ctxt->wellFormed) { - ret = (xmlParserErrors)ctxt->errNo; - if (oldctxt != NULL) { - oldctxt->errNo = ctxt->errNo; - oldctxt->wellFormed = 0; - xmlCopyError(&ctxt->lastError, &oldctxt->lastError); - } - } else { - if (list != NULL) { - xmlNodePtr cur; +/** + * xmlParseCtxtExternalEntity: + * @ctxt: the existing parsing context + * @URL: the URL for the entity to load + * @ID: the System ID for the entity to load + * @listOut: 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 + */
- /* - * 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; - } +int +xmlParseCtxtExternalEntity(xmlParserCtxtPtr ctxt, const xmlChar *URL, + const xmlChar *ID, xmlNodePtr *listOut) { + xmlParserInputPtr input; + xmlNodePtr list;
- /* - * Also record the size of the entity parsed - */ - if (ctxt->input != NULL && oldctxt != NULL) { - unsigned long consumed = ctxt->input->consumed; + if (listOut != NULL) + *listOut = NULL;
- xmlSaturatedAddSizeT(&consumed, ctxt->input->cur - ctxt->input->base); + if (ctxt == NULL) + return(XML_ERR_ARGUMENT);
- xmlSaturatedAdd(&oldctxt->sizeentities, consumed); - xmlSaturatedAdd(&oldctxt->sizeentities, ctxt->sizeentities); + input = xmlLoadExternalEntity((char *)URL, (char *)ID, ctxt); + if (input == NULL) + return(ctxt->errNo);
- xmlSaturatedAdd(&oldctxt->sizeentcopy, consumed); - xmlSaturatedAdd(&oldctxt->sizeentcopy, ctxt->sizeentcopy); - } + xmlCtxtInitializeLate(ctxt);
- if (oldctxt != NULL) { - ctxt->dict = NULL; - ctxt->attsDefault = NULL; - ctxt->attsSpecial = NULL; - oldctxt->nbErrors = ctxt->nbErrors; - oldctxt->nbWarnings = ctxt->nbWarnings; - oldctxt->validate = ctxt->validate; - oldctxt->valid = ctxt->valid; - 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; - xmlFreeParserCtxt(ctxt); - newDoc->intSubset = NULL; - newDoc->extSubset = NULL; - xmlFreeDoc(newDoc); + list = xmlCtxtParseContent(ctxt, input, /* hasTextDecl */ 1, 1); + if (listOut != NULL) + *listOut = list; + else + xmlFreeNodeList(list);
- return(ret); + xmlFreeInputStream(input); + return(ctxt->errNo); }
#ifdef LIBXML_SAX1_ENABLED @@ -12941,7 +12296,9 @@ xmlParseExternalEntityPrivate(xmlDocPtr doc, xmlParserCtxtPtr oldctxt, * @depth: Used for loop detection, use 0 * @URL: the URL for the entity to load * @ID: the System ID for the entity to load - * @lst: the return value for the set of parsed nodes + * @list: the return value for the set of parsed nodes + * + * DEPRECATED: Use xmlParseCtxtExternalEntity. * * Parse an external general entity * An external general parsed entity is well-formed if it matches the @@ -12955,9 +12312,26 @@ xmlParseExternalEntityPrivate(xmlDocPtr doc, xmlParserCtxtPtr oldctxt,
int xmlParseExternalEntity(xmlDocPtr doc, xmlSAXHandlerPtr sax, void *user_data, - int depth, const xmlChar *URL, const xmlChar *ID, xmlNodePtr *lst) { - return(xmlParseExternalEntityPrivate(doc, NULL, sax, user_data, depth, URL, - ID, lst)); + int depth, const xmlChar *URL, const xmlChar *ID, xmlNodePtr *list) { + xmlParserCtxtPtr ctxt; + int ret; + + if (list != NULL) + *list = NULL; + + if (doc == NULL) + return(XML_ERR_ARGUMENT); + + ctxt = xmlNewSAXParserCtxt(sax, user_data); + if (ctxt == NULL) + return(XML_ERR_NO_MEMORY); + + ctxt->depth = depth; + ctxt->myDoc = doc; + ret = xmlParseCtxtExternalEntity(ctxt, URL, ID, list); + + xmlFreeParserCtxt(ctxt); + return(ret); }
/** @@ -12988,229 +12362,6 @@ xmlParseBalancedChunkMemory(xmlDocPtr doc, xmlSAXHandlerPtr sax, } #endif /* LIBXML_SAX1_ENABLED */
-/** - * xmlParseBalancedChunkMemoryInternal: - * @oldctxt: the existing parsing context - * @string: the input string in UTF8 or ISO-Latin (zero terminated) - * @user_data: the user data field for the parser context - * @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; - xmlNodePtr newRoot; - xmlSAXHandlerPtr oldsax = NULL; - xmlNodePtr content = NULL; - xmlNodePtr last = NULL; - xmlParserErrors ret = XML_ERR_OK; - xmlHashedString hprefix, huri; - unsigned i; - - if (((oldctxt->depth > 40) && ((oldctxt->options & XML_PARSE_HUGE) == 0)) || - (oldctxt->depth > 100)) { - xmlFatalErrMsg(oldctxt, XML_ERR_ENTITY_LOOP, - "Maximum entity nesting depth exceeded"); - return(XML_ERR_ENTITY_LOOP); - } - - - if (lst != NULL) - *lst = NULL; - if (string == NULL) - return(XML_ERR_INTERNAL_ERROR); - - ctxt = xmlCreateDocParserCtxt(string); - if (ctxt == NULL) return(XML_WAR_UNDECLARED_ENTITY); - ctxt->nbErrors = oldctxt->nbErrors; - ctxt->nbWarnings = oldctxt->nbWarnings; - if (user_data != NULL) - ctxt->userData = user_data; - else - ctxt->userData = ctxt; - if (ctxt->dict != NULL) xmlDictFree(ctxt->dict); - ctxt->dict = oldctxt->dict; - ctxt->input_id = oldctxt->input_id; - 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); - - /* - * Propagate namespaces down the entity - * - * Making entities and namespaces work correctly requires additional - * changes, see xmlParseReference. - */ - - /* Default namespace */ - hprefix.name = NULL; - hprefix.hashValue = 0; - huri.name = xmlParserNsLookupUri(oldctxt, &hprefix); - huri.hashValue = 0; - if (huri.name != NULL) - xmlParserNsPush(ctxt, NULL, &huri, NULL, 0); - - for (i = 0; i < oldctxt->nsdb->hashSize; i++) { - xmlParserNsBucket *bucket = &oldctxt->nsdb->hash[i]; - const xmlChar **ns; - xmlParserNsExtra *extra; - unsigned nsIndex; - - if ((bucket->hashValue != 0) && - (bucket->index != INT_MAX)) { - nsIndex = bucket->index; - ns = &oldctxt->nsTab[nsIndex * 2]; - extra = &oldctxt->nsdb->extra[nsIndex]; - - hprefix.name = ns[0]; - hprefix.hashValue = bucket->hashValue; - huri.name = ns[1]; - huri.hashValue = extra->uriHashValue; - /* - * Don't copy SAX data to avoid a use-after-free with XML reader. - * This matches the pre-2.12 behavior. - */ - xmlParserNsPush(ctxt, &hprefix, &huri, NULL, 0); - } - } - - 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) { - ret = XML_ERR_INTERNAL_ERROR; - goto error; - } - newDoc->properties = XML_DOC_INTERNAL; - newDoc->dict = ctxt->dict; - xmlDictReference(newDoc->dict); - ctxt->myDoc = newDoc; - } else { - ctxt->myDoc = oldctxt->myDoc; - content = ctxt->myDoc->children; - last = ctxt->myDoc->last; - } - newRoot = xmlNewDocNode(ctxt->myDoc, NULL, BAD_CAST "pseudoroot", NULL); - if (newRoot == NULL) { - ret = XML_ERR_INTERNAL_ERROR; - goto error; - } - ctxt->myDoc->children = NULL; - ctxt->myDoc->last = NULL; - xmlAddChild((xmlNodePtr) ctxt->myDoc, newRoot); - nodePush(ctxt, ctxt->myDoc->children); - ctxt->instate = XML_PARSER_CONTENT; - ctxt->depth = oldctxt->depth; - - 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 ((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) { - ret = (xmlParserErrors)ctxt->errNo; - oldctxt->errNo = ctxt->errNo; - oldctxt->wellFormed = 0; - xmlCopyError(&ctxt->lastError, &oldctxt->lastError); - } 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) && - (cur->type == XML_ELEMENT_NODE)) { - 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->myDoc->last = last; - } - - /* - * Also record the size of the entity parsed - */ - if (ctxt->input != NULL && oldctxt != NULL) { - unsigned long consumed = ctxt->input->consumed; - - xmlSaturatedAddSizeT(&consumed, ctxt->input->cur - ctxt->input->base); - - xmlSaturatedAdd(&oldctxt->sizeentcopy, consumed); - xmlSaturatedAdd(&oldctxt->sizeentcopy, ctxt->sizeentcopy); - } - - oldctxt->nbErrors = ctxt->nbErrors; - oldctxt->nbWarnings = ctxt->nbWarnings; - -error: - ctxt->sax = oldsax; - ctxt->dict = NULL; - ctxt->attsDefault = NULL; - ctxt->attsSpecial = NULL; - xmlFreeParserCtxt(ctxt); - if (newDoc != NULL) { - xmlFreeDoc(newDoc); - } - - return(ret); -} - /** * xmlParseInNodeContext: * @node: the context node @@ -13244,7 +12395,7 @@ xmlParseInNodeContext(xmlNodePtr node, const char *data, int datalen, * check all input parameters, grab the document */ if ((lst == NULL) || (node == NULL) || (data == NULL) || (datalen < 0)) - return(XML_ERR_INTERNAL_ERROR); + return(XML_ERR_ARGUMENT); switch (node->type) { case XML_ELEMENT_NODE: case XML_ATTRIBUTE_NODE: @@ -13297,33 +12448,30 @@ xmlParseInNodeContext(xmlNodePtr node, const char *data, int datalen,
/* * 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 need a dictionary for xmlCtxtInitializeLate, so if there's no doc dict * we must wait until the last moment to free the original one. */ if (doc->dict != NULL) { if (ctxt->dict != NULL) xmlDictFree(ctxt->dict); ctxt->dict = doc->dict; - } else + } else { options |= XML_PARSE_NODICT; - - if (doc->encoding != NULL) { - xmlCharEncodingHandlerPtr hdlr; - - hdlr = xmlFindCharEncodingHandler((const char *) doc->encoding); - if (hdlr != NULL) { - xmlSwitchToEncoding(ctxt, hdlr); - } else { - return(XML_ERR_UNSUPPORTED_ENCODING); - } + ctxt->dictNames = 0; }
- xmlCtxtUseOptionsInternal(ctxt, options); - xmlDetectSAX2(ctxt); + if (doc->encoding != NULL) + xmlSwitchEncodingName(ctxt, (const char *) doc->encoding); + + xmlCtxtUseOptions(ctxt, options); + xmlCtxtInitializeLate(ctxt); ctxt->myDoc = doc; /* parsing in context, i.e. as within existing content */ ctxt->input_id = 2; - ctxt->instate = XML_PARSER_CONTENT; + + /* + * TODO: Use xmlCtxtParseContent + */
fake = xmlNewDocComment(node->doc, NULL); if (fake == NULL) { @@ -13367,26 +12515,18 @@ xmlParseInNodeContext(xmlNodePtr node, const char *data, int datalen, __htmlParseContent(ctxt); else #endif - xmlParseContent(ctxt); + xmlParseContentInternal(ctxt);
- xmlParserNsPop(ctxt, nsnr); - if ((RAW == '<') && (NXT(1) == '/')) { + if (ctxt->input->cur < ctxt->input->end) 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 { + xmlParserNsPop(ctxt, nsnr); + + if ((ctxt->wellFormed) || + ((ctxt->recovery) && (ctxt->errNo != XML_ERR_NO_MEMORY))) { ret = XML_ERR_OK; + } else { + ret = (xmlParserErrors) ctxt->errNo; }
/* @@ -13433,19 +12573,18 @@ xmlParseInNodeContext(xmlNodePtr node, const char *data, int datalen, * @user_data: The user data returned on SAX callbacks (possibly NULL) * @depth: Used for loop detection, use 0 * @string: the input string in UTF8 or ISO-Latin (zero terminated) - * @lst: the return value for the set of parsed nodes + * @listOut: the return value for the set of parsed nodes * @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 + * Returns 0 if the chunk is well balanced, or thehe 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, assuming the parsing succeeded to @@ -13453,142 +12592,49 @@ xmlParseInNodeContext(xmlNodePtr node, const char *data, int datalen, */ int xmlParseBalancedChunkMemoryRecover(xmlDocPtr doc, xmlSAXHandlerPtr sax, - void *user_data, int depth, const xmlChar *string, xmlNodePtr *lst, + void *user_data, int depth, const xmlChar *string, xmlNodePtr *listOut, int recover) { xmlParserCtxtPtr ctxt; - xmlDocPtr newDoc; - xmlSAXHandlerPtr oldsax = NULL; - xmlNodePtr content, newRoot; - int ret = 0; - - if (depth > 40) { - return(XML_ERR_ENTITY_LOOP); - } + xmlParserInputPtr input; + xmlNodePtr list; + int ret;
+ if (listOut != NULL) + *listOut = NULL;
- if (lst != NULL) - *lst = NULL; if (string == NULL) - return(-1); + return(XML_ERR_ARGUMENT);
- ctxt = xmlCreateDocParserCtxt(string); - 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); - } - newDoc->properties = XML_DOC_INTERNAL; - if ((doc != NULL) && (doc->dict != NULL)) { - xmlDictFree(ctxt->dict); - ctxt->dict = doc->dict; - xmlDictReference(ctxt->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 = 1; - newDoc->dict = ctxt->dict; - xmlDictReference(newDoc->dict); - } else { - xmlCtxtUseOptionsInternal(ctxt, XML_PARSE_NODICT); - } - /* doc == NULL is only supported for historic reasons */ - if (doc != NULL) { - newDoc->intSubset = doc->intSubset; - newDoc->extSubset = doc->extSubset; - } - newRoot = xmlNewDocNode(newDoc, NULL, BAD_CAST "pseudoroot", NULL); - if (newRoot == NULL) { - if (sax != NULL) - ctxt->sax = oldsax; - xmlFreeParserCtxt(ctxt); - newDoc->intSubset = NULL; - newDoc->extSubset = NULL; - xmlFreeDoc(newDoc); - return(-1); - } - xmlAddChild((xmlNodePtr) newDoc, newRoot); - nodePush(ctxt, newRoot); - /* doc == NULL is only supported for historic reasons */ - if (doc == NULL) { - ctxt->myDoc = newDoc; - } else { - ctxt->myDoc = newDoc; - /* Ensure that doc has XML spec namespace */ - xmlSearchNsByHref(doc, (xmlNodePtr)doc, XML_XML_NAMESPACE); - newDoc->oldNs = doc->oldNs; - } - ctxt->instate = XML_PARSER_CONTENT; - ctxt->input_id = 2; - ctxt->depth = depth; + ctxt = xmlNewSAXParserCtxt(sax, user_data); + if (ctxt == NULL) + return(XML_ERR_NO_MEMORY);
- /* - * Doing validity checking on chunk doesn't make sense - */ - ctxt->validate = 0; - ctxt->loadsubset = 0; - xmlDetectSAX2(ctxt); + xmlCtxtInitializeLate(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); + ctxt->depth = depth; + ctxt->myDoc = doc; + if (recover) { + ctxt->options |= XML_PARSE_RECOVER; + ctxt->recovery = 1; }
- if (!ctxt->wellFormed) { - if (ctxt->errNo == 0) - ret = 1; - else - ret = ctxt->errNo; - } else { - ret = 0; - } + input = xmlNewStringInputStream(ctxt, string); + if (input == NULL) + return(ctxt->errNo);
- if ((lst != NULL) && ((ret == 0) || (recover == 1))) { - xmlNodePtr cur; + list = xmlCtxtParseContent(ctxt, input, /* hasTextDecl */ 0, 1); + if (listOut != NULL) + *listOut = list; + else + xmlFreeNodeList(list);
- /* - * Return the newly created nodeset after unlinking it from - * they pseudo parent. - */ - cur = newDoc->children->children; - *lst = cur; - while (cur != NULL) { - xmlSetTreeDoc(cur, doc); - cur->parent = NULL; - cur = cur->next; - } - newDoc->children->children = NULL; - } + if (!ctxt->wellFormed) + ret = ctxt->errNo; + else + ret = XML_ERR_OK;
- if (sax != NULL) - ctxt->sax = oldsax; + xmlFreeInputStream(input); xmlFreeParserCtxt(ctxt); - newDoc->intSubset = NULL; - newDoc->extSubset = NULL; - /* This leaks the namespace list if doc == NULL */ - newDoc->oldNs = NULL; - xmlFreeDoc(newDoc); - return(ret); }
@@ -13620,23 +12666,24 @@ xmlSAXParseEntity(xmlSAXHandlerPtr sax, const char *filename) { return(NULL); } if (sax != NULL) { - if (ctxt->sax != NULL) - xmlFree(ctxt->sax); - ctxt->sax = sax; + if (sax->initialized == XML_SAX2_MAGIC) { + *ctxt->sax = *sax; + } else { + memset(ctxt->sax, 0, sizeof(*ctxt->sax)); + memcpy(ctxt->sax, sax, sizeof(xmlSAXHandlerV1)); + } ctxt->userData = NULL; }
xmlParseExtParsedEnt(ctxt);
- if (ctxt->wellFormed) + if (ctxt->wellFormed) { ret = ctxt->myDoc; - else { + } else { ret = NULL; xmlFreeDoc(ctxt->myDoc); - ctxt->myDoc = NULL; } - if (sax != NULL) - ctxt->sax = NULL; + xmlFreeParserCtxt(ctxt);
return(ret); @@ -13649,88 +12696,17 @@ xmlSAXParseEntity(xmlSAXHandlerPtr sax, const char *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 - */ - -xmlDocPtr -xmlParseEntity(const char *filename) { - return(xmlSAXParseEntity(NULL, filename)); -} -#endif /* LIBXML_SAX1_ENABLED */ - -/** - * xmlCreateEntityParserCtxtInternal: - * @URL: the entity URL - * @ID: the entity PUBLIC ID - * @base: a possible base for the target URI - * @pctx: parser context used to set options on new context - * - * 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 - */ -static xmlParserCtxtPtr -xmlCreateEntityParserCtxtInternal(xmlSAXHandlerPtr sax, void *userData, - const xmlChar *URL, const xmlChar *ID, const xmlChar *base, - xmlParserCtxtPtr pctx) { - xmlParserCtxtPtr ctxt; - xmlParserInputPtr inputStream; - char *directory = NULL; - xmlChar *uri; - - ctxt = xmlNewSAXParserCtxt(sax, userData); - if (ctxt == NULL) { - return(NULL); - } - - if (pctx != NULL) { - ctxt->options = pctx->options; - ctxt->_private = pctx->_private; - ctxt->input_id = pctx->input_id; - } - - /* Don't read from stdin. */ - if (xmlStrcmp(URL, BAD_CAST "-") == 0) - URL = BAD_CAST "./-"; - - uri = xmlBuildURI(URL, base); - - if (uri == NULL) { - inputStream = xmlLoadExternalEntity((char *)URL, (char *)ID, ctxt); - if (inputStream == NULL) { - xmlFreeParserCtxt(ctxt); - return(NULL); - } - - inputPush(ctxt, inputStream); - - if ((ctxt->directory == NULL) && (directory == NULL)) - directory = xmlParserGetDirectory((char *)URL); - if ((ctxt->directory == NULL) && (directory != NULL)) - ctxt->directory = directory; - } else { - inputStream = xmlLoadExternalEntity((char *)uri, (char *)ID, ctxt); - if (inputStream == NULL) { - xmlFree(uri); - xmlFreeParserCtxt(ctxt); - return(NULL); - } - - inputPush(ctxt, inputStream); + * + * This correspond to a "Well Balanced" chunk + * + * Returns the resulting document tree + */
- if ((ctxt->directory == NULL) && (directory == NULL)) - directory = xmlParserGetDirectory((char *)uri); - if ((ctxt->directory == NULL) && (directory != NULL)) - ctxt->directory = directory; - xmlFree(uri); - } - return(ctxt); +xmlDocPtr +xmlParseEntity(const char *filename) { + return(xmlSAXParseEntity(NULL, filename)); } +#endif /* LIBXML_SAX1_ENABLED */
/** * xmlCreateEntityParserCtxt: @@ -13738,6 +12714,8 @@ xmlCreateEntityParserCtxtInternal(xmlSAXHandlerPtr sax, void *userData, * @ID: the entity PUBLIC ID * @base: a possible base for the target URI * + * DEPRECATED: Don't use. + * * Create a parser context for an external entity * Automatic support for ZLIB/Compress compressed document is provided * by default if found at compile-time. @@ -13747,8 +12725,35 @@ xmlCreateEntityParserCtxtInternal(xmlSAXHandlerPtr sax, void *userData, xmlParserCtxtPtr xmlCreateEntityParserCtxt(const xmlChar *URL, const xmlChar *ID, const xmlChar *base) { - return xmlCreateEntityParserCtxtInternal(NULL, NULL, URL, ID, base, NULL); + xmlParserCtxtPtr ctxt; + xmlParserInputPtr input; + xmlChar *uri = NULL; + + ctxt = xmlNewParserCtxt(); + if (ctxt == NULL) + return(NULL); + + if (base != NULL) { + if (xmlBuildURISafe(URL, base, &uri) < 0) + goto error; + if (uri != NULL) + URL = uri; + } + + input = xmlLoadExternalEntity((char *)URL, (char *)ID, ctxt); + if (input == NULL) + goto error; + + if (inputPush(ctxt, input) < 0) + goto error; + + xmlFree(uri); + return(ctxt);
+error: + xmlFree(uri); + xmlFreeParserCtxt(ctxt); + return(NULL); }
/************************************************************************ @@ -13762,6 +12767,8 @@ xmlCreateEntityParserCtxt(const xmlChar *URL, const xmlChar *ID, * @filename: the filename or URL * @options: a combination of xmlParserOption * + * DEPRECATED: Use xmlNewParserCtxt and xmlCtxtReadFile. + * * 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 @@ -13772,30 +12779,21 @@ xmlParserCtxtPtr xmlCreateURLParserCtxt(const char *filename, int options) { xmlParserCtxtPtr ctxt; - xmlParserInputPtr inputStream; - char *directory = NULL; + xmlParserInputPtr input;
ctxt = xmlNewParserCtxt(); - if (ctxt == NULL) { - xmlErrMemory(NULL, "cannot allocate parser context"); + if (ctxt == NULL) return(NULL); - }
- if (options) - xmlCtxtUseOptionsInternal(ctxt, options); + xmlCtxtUseOptions(ctxt, options); ctxt->linenumbers = 1;
- inputStream = xmlLoadExternalEntity(filename, NULL, ctxt); - if (inputStream == NULL) { + input = xmlLoadExternalEntity(filename, NULL, ctxt); + if (input == NULL) { xmlFreeParserCtxt(ctxt); return(NULL); } - - inputPush(ctxt, inputStream); - if ((ctxt->directory == NULL) && (directory == NULL)) - directory = xmlParserGetDirectory(filename); - if ((ctxt->directory == NULL) && (directory != NULL)) - ctxt->directory = directory; + inputPush(ctxt, input);
return(ctxt); } @@ -13804,6 +12802,8 @@ xmlCreateURLParserCtxt(const char *filename, int options) * xmlCreateFileParserCtxt: * @filename: the filename * + * DEPRECATED: Use xmlNewParserCtxt and xmlCtxtReadFile. + * * Create a parser context for a file content. * Automatic support for ZLIB/Compress compressed document is provided * by default if found at compile-time. @@ -13843,48 +12843,28 @@ xmlSAXParseFileWithData(xmlSAXHandlerPtr sax, const char *filename, int recovery, void *data) { xmlDocPtr ret; xmlParserCtxtPtr ctxt; + xmlParserInputPtr input;
- xmlInitParser(); - - ctxt = xmlCreateFileParserCtxt(filename); - if (ctxt == NULL) { + ctxt = xmlNewSAXParserCtxt(sax, NULL); + if (ctxt == NULL) return(NULL); - } - if (sax != NULL) { - if (ctxt->sax != NULL) - xmlFree(ctxt->sax); - ctxt->sax = sax; - } - xmlDetectSAX2(ctxt); - if (data!=NULL) { + + if (data != NULL) ctxt->_private = data; - }
- if (ctxt->directory == NULL) - ctxt->directory = xmlParserGetDirectory(filename); + if (recovery) { + ctxt->options |= XML_PARSE_RECOVER; + ctxt->recovery = 1; + }
- ctxt->recovery = recovery; + if ((filename != NULL) && (filename[0] == '-') && (filename[1] == 0)) + input = xmlNewInputFd(ctxt, filename, STDIN_FILENO, NULL, 0); + else + input = xmlNewInputURL(ctxt, filename, NULL, NULL, 0);
- xmlParseDocument(ctxt); + ret = xmlCtxtParseDocument(ctxt, input);
- if ((ctxt->wellFormed) || recovery) { - ret = ctxt->myDoc; - if ((ret != NULL) && (ctxt->input->buf != NULL)) { - if (ctxt->input->buf->compressed > 0) - ret->compression = 9; - else - ret->compression = ctxt->input->buf->compressed; - } - } - else { - ret = NULL; - xmlFreeDoc(ctxt->myDoc); - ctxt->myDoc = NULL; - } - if (sax != NULL) - ctxt->sax = NULL; xmlFreeParserCtxt(ctxt); - return(ret); }
@@ -13988,19 +12968,11 @@ xmlSetupParserForBuffer(xmlParserCtxtPtr ctxt, const xmlChar* buffer, if ((ctxt == NULL) || (buffer == NULL)) return;
- input = xmlNewInputStream(ctxt); - if (input == NULL) { - xmlErrMemory(NULL, "parsing new buffer: out of memory\n"); - xmlClearParserCtxt(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)]; + + input = xmlNewInputString(ctxt, filename, (const char *) buffer, NULL, 0); + if (input == NULL) + return; inputPush(ctxt, input); }
@@ -14025,13 +12997,15 @@ xmlSAXUserParseFile(xmlSAXHandlerPtr sax, void *user_data,
ctxt = xmlCreateFileParserCtxt(filename); if (ctxt == NULL) return -1; - if (ctxt->sax != (xmlSAXHandlerPtr) &xmlDefaultSAXHandler) - xmlFree(ctxt->sax); - ctxt->sax = sax; - xmlDetectSAX2(ctxt); - - if (user_data != NULL) + if (sax != NULL) { + if (sax->initialized == XML_SAX2_MAGIC) { + *ctxt->sax = *sax; + } else { + memset(ctxt->sax, 0, sizeof(*ctxt->sax)); + memcpy(ctxt->sax, sax, sizeof(xmlSAXHandlerV1)); + } ctxt->userData = user_data; + }
xmlParseDocument(ctxt);
@@ -14043,8 +13017,6 @@ xmlSAXUserParseFile(xmlSAXHandlerPtr sax, void *user_data, else ret = -1; } - if (sax != NULL) - ctxt->sax = NULL; if (ctxt->myDoc != NULL) { xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL; @@ -14066,7 +13038,8 @@ xmlSAXUserParseFile(xmlSAXHandlerPtr sax, void *user_data, * @buffer: a pointer to a char array * @size: the size of the array * - * Create a parser context for an XML in-memory document. + * Create a parser context for an XML in-memory document. The input buffer + * must not contain a terminating null byte. * * Returns the new parser context or NULL */ @@ -14074,35 +13047,21 @@ xmlParserCtxtPtr xmlCreateMemoryParserCtxt(const char *buffer, int size) { xmlParserCtxtPtr ctxt; xmlParserInputPtr input; - xmlParserInputBufferPtr buf;
- if (buffer == NULL) - return(NULL); - if (size <= 0) + if (size < 0) return(NULL);
ctxt = xmlNewParserCtxt(); if (ctxt == NULL) return(NULL);
- buf = xmlParserInputBufferCreateMem(buffer, size, XML_CHAR_ENCODING_NONE); - if (buf == NULL) { - xmlFreeParserCtxt(ctxt); - return(NULL); - } - - input = xmlNewInputStream(ctxt); + input = xmlNewInputMemory(ctxt, NULL, buffer, size, NULL, 0); if (input == NULL) { - xmlFreeParserInputBuffer(buf); xmlFreeParserCtxt(ctxt); return(NULL); } - - input->filename = NULL; - input->buf = buf; - xmlBufResetInput(input->buf->buffer, input); - inputPush(ctxt, input); + return(ctxt); }
@@ -14130,38 +13089,32 @@ xmlCreateMemoryParserCtxt(const char *buffer, int size) {
xmlDocPtr xmlSAXParseMemoryWithData(xmlSAXHandlerPtr sax, const char *buffer, - int size, int recovery, void *data) { + int size, int recovery, void *data) { xmlDocPtr ret; xmlParserCtxtPtr ctxt; + xmlParserInputPtr input;
- xmlInitParser(); + if (size < 0) + return(NULL);
- 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 = xmlNewSAXParserCtxt(sax, NULL); + if (ctxt == NULL) + return(NULL); + + if (data != NULL) ctxt->_private=data; + + if (recovery) { + ctxt->options |= XML_PARSE_RECOVER; + ctxt->recovery = 1; }
- ctxt->recovery = recovery; + input = xmlNewInputMemory(ctxt, NULL, buffer, size, NULL, + XML_INPUT_BUF_STATIC);
- xmlParseDocument(ctxt); + ret = xmlCtxtParseDocument(ctxt, input);
- 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); }
@@ -14239,17 +13192,17 @@ int xmlSAXUserParseMemory(xmlSAXHandlerPtr sax, void *user_data, int ret = 0; xmlParserCtxtPtr ctxt;
- xmlInitParser(); - ctxt = xmlCreateMemoryParserCtxt(buffer, size); if (ctxt == NULL) return -1; - if (ctxt->sax != (xmlSAXHandlerPtr) &xmlDefaultSAXHandler) - xmlFree(ctxt->sax); - ctxt->sax = sax; - xmlDetectSAX2(ctxt); - - if (user_data != NULL) + if (sax != NULL) { + if (sax->initialized == XML_SAX2_MAGIC) { + *ctxt->sax = *sax; + } else { + memset(ctxt->sax, 0, sizeof(*ctxt->sax)); + memcpy(ctxt->sax, sax, sizeof(xmlSAXHandlerV1)); + } ctxt->userData = user_data; + }
xmlParseDocument(ctxt);
@@ -14261,8 +13214,6 @@ int xmlSAXUserParseMemory(xmlSAXHandlerPtr sax, void *user_data, else ret = -1; } - if (sax != NULL) - ctxt->sax = NULL; if (ctxt->myDoc != NULL) { xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL; @@ -14285,33 +13236,18 @@ xmlParserCtxtPtr xmlCreateDocParserCtxt(const xmlChar *str) { xmlParserCtxtPtr ctxt; xmlParserInputPtr input; - xmlParserInputBufferPtr buf; - - if (str == NULL) - return(NULL);
ctxt = xmlNewParserCtxt(); if (ctxt == NULL) return(NULL);
- buf = xmlParserInputBufferCreateString(str); - if (buf == NULL) { - xmlFreeParserCtxt(ctxt); - return(NULL); - } - - input = xmlNewInputStream(ctxt); + input = xmlNewInputString(ctxt, NULL, (const char *) str, NULL, 0); if (input == NULL) { - xmlFreeParserInputBuffer(buf); xmlFreeParserCtxt(ctxt); return(NULL); } - - input->filename = NULL; - input->buf = buf; - xmlBufResetInput(input->buf->buffer, input); - inputPush(ctxt, input); + return(ctxt); }
@@ -14348,7 +13284,6 @@ xmlSAXParseDoc(xmlSAXHandlerPtr sax, const xmlChar *cur, int recovery) { ctxt->sax = sax; ctxt->userData = NULL; } - xmlDetectSAX2(ctxt);
xmlParseDocument(ctxt); if ((ctxt->wellFormed) || recovery) ret = ctxt->myDoc; @@ -14381,47 +13316,6 @@ xmlParseDoc(const xmlChar *cur) { } #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: - * @ent : A valid entity - * @firstNode : A valid first node for children of entity - * @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: - * @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 */ - /************************************************************************ * * * New set (2.6.0) of simpler and more flexible APIs * @@ -14485,12 +13379,16 @@ xmlCtxtReset(xmlParserCtxtPtr ctxt) 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->directory != NULL) { + xmlFree(ctxt->directory); + ctxt->directory = NULL; + } + if (ctxt->myDoc != NULL) xmlFreeDoc(ctxt->myDoc); ctxt->myDoc = NULL; @@ -14499,9 +13397,7 @@ xmlCtxtReset(xmlParserCtxtPtr ctxt) 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; @@ -14558,208 +13454,258 @@ int xmlCtxtResetPush(xmlParserCtxtPtr ctxt, const char *chunk, int size, const char *filename, const char *encoding) { - xmlParserInputPtr inputStream; - xmlParserInputBufferPtr buf; + xmlParserInputPtr input;
if (ctxt == NULL) return(1);
- buf = xmlAllocParserInputBuffer(XML_CHAR_ENCODING_NONE); - if (buf == NULL) - return(1); - - if (ctxt == NULL) { - xmlFreeParserInputBuffer(buf); - return(1); - } - xmlCtxtReset(ctxt);
- if (filename == NULL) { - ctxt->directory = NULL; - } else { - ctxt->directory = xmlParserGetDirectory(filename); - } - - inputStream = xmlNewInputStream(ctxt); - if (inputStream == NULL) { - xmlFreeParserInputBuffer(buf); + input = xmlNewInputPush(ctxt, filename, chunk, size, encoding); + if (input == NULL) return(1); - } - - if (filename == NULL) - inputStream->filename = NULL; - else - inputStream->filename = (char *) - xmlCanonicPath((const xmlChar *) filename); - inputStream->buf = buf; - xmlBufResetInput(buf->buffer, inputStream); + inputPush(ctxt, input);
- inputPush(ctxt, inputStream); + return(0); +}
- if ((size > 0) && (chunk != NULL) && (ctxt->input != NULL) && - (ctxt->input->buf != NULL)) { - size_t pos = ctxt->input->cur - ctxt->input->base; - int res; +static int +xmlCtxtSetOptionsInternal(xmlParserCtxtPtr ctxt, int options, int keepMask) +{ + int allMask;
- res = xmlParserInputBufferPush(ctxt->input->buf, size, chunk); - xmlBufUpdateInput(ctxt->input->buf->buffer, ctxt->input, pos); - if (res < 0) { - xmlFatalErr(ctxt, ctxt->input->buf->error, NULL); - xmlHaltParser(ctxt); - return(1); - } - } + if (ctxt == NULL) + return(-1);
- if (encoding != NULL) { - xmlCharEncodingHandlerPtr hdlr; + /* + * XInclude options aren't handled by the parser. + * + * XML_PARSE_XINCLUDE + * XML_PARSE_NOXINCNODE + * XML_PARSE_NOBASEFIX + */ + allMask = XML_PARSE_RECOVER | + XML_PARSE_NOENT | + XML_PARSE_DTDLOAD | + XML_PARSE_DTDATTR | + XML_PARSE_DTDVALID | + XML_PARSE_NOERROR | + XML_PARSE_NOWARNING | + XML_PARSE_PEDANTIC | + XML_PARSE_NOBLANKS | +#ifdef LIBXML_SAX1_ENABLED + XML_PARSE_SAX1 | +#endif + XML_PARSE_NONET | + XML_PARSE_NODICT | + XML_PARSE_NSCLEAN | + XML_PARSE_NOCDATA | + XML_PARSE_COMPACT | + XML_PARSE_OLD10 | + XML_PARSE_HUGE | + XML_PARSE_OLDSAX | + XML_PARSE_IGNORE_ENC | + XML_PARSE_BIG_LINES | + XML_PARSE_NO_XXE; + + ctxt->options = (ctxt->options & keepMask) | (options & allMask); + + /* + * For some options, struct members are historically the source + * of truth. The values are initalized from global variables and + * old code could also modify them directly. Several older API + * functions that don't take an options argument rely on these + * deprecated mechanisms. + * + * Once public access to struct members and the globals are + * disabled, we can use the options bitmask as source of + * truth, making all these struct members obsolete. + * + * The XML_DETECT_IDS flags is misnamed. It simply enables + * loading of the external subset. + */ + ctxt->recovery = (options & XML_PARSE_RECOVER) ? 1 : 0; + ctxt->replaceEntities = (options & XML_PARSE_NOENT) ? 1 : 0; + ctxt->loadsubset = (options & XML_PARSE_DTDLOAD) ? XML_DETECT_IDS : 0; + ctxt->loadsubset |= (options & XML_PARSE_DTDATTR) ? XML_COMPLETE_ATTRS : 0; + ctxt->validate = (options & XML_PARSE_DTDVALID) ? 1 : 0; + ctxt->pedantic = (options & XML_PARSE_PEDANTIC) ? 1 : 0; + ctxt->keepBlanks = (options & XML_PARSE_NOBLANKS) ? 0 : 1; + ctxt->dictNames = (options & XML_PARSE_NODICT) ? 0 : 1;
- hdlr = xmlFindCharEncodingHandler(encoding); - if (hdlr != NULL) { - xmlSwitchToEncoding(ctxt, hdlr); - } else { - xmlFatalErrMsgStr(ctxt, XML_ERR_UNSUPPORTED_ENCODING, - "Unsupported encoding %s\n", BAD_CAST encoding); - } + /* + * Changing SAX callbacks is a bad idea. This should be fixed. + */ + if (options & XML_PARSE_NOBLANKS) { + ctxt->sax->ignorableWhitespace = xmlSAX2IgnorableWhitespace; + } + if (options & XML_PARSE_NOCDATA) { + ctxt->sax->cdataBlock = NULL; + } + if (options & XML_PARSE_HUGE) { + if (ctxt->dict != NULL) + xmlDictSetLimit(ctxt->dict, 0); }
- return(0); -} + ctxt->linenumbers = 1;
+ return(options & ~allMask); +}
/** - * xmlCtxtUseOptionsInternal: + * xmlCtxtSetOptions: * @ctxt: an XML parser context - * @options: a combination of xmlParserOption - * @encoding: the user provided encoding to use + * @options: a bitmask of xmlParserOption values + * + * Applies the options to the parser context. Unset options are + * cleared. + * + * Available since 2.13.0. With older versions, you can use + * xmlCtxtUseOptions. + * + * XML_PARSE_RECOVER + * + * Enable "recovery" mode which allows non-wellformed documents. + * How this mode behaves exactly is unspecified and may change + * without further notice. Use of this feature is DISCOURAGED. + * + * XML_PARSE_NOENT + * + * Despite the confusing name, this option enables substitution + * of entities. The resulting tree won't contain any entity + * reference nodes. + * + * This option also enables loading of external entities (both + * general and parameter entities) which is dangerous. If you + * process untrusted data, it's recommended to set the + * XML_PARSE_NO_XXE option to disable loading of external + * entities. + * + * XML_PARSE_DTDLOAD + * + * Enables loading of an external DTD and the loading and + * substitution of external parameter entities. Has no effect + * if XML_PARSE_NO_XXE is set. + * + * XML_PARSE_DTDATTR + * + * Adds default attributes from the DTD to the result document. + * + * Implies XML_PARSE_DTDLOAD, but loading of external content + * can be disabled with XML_PARSE_NO_XXE. + * + * XML_PARSE_DTDVALID + * + * This option enables DTD validation which requires to load + * external DTDs and external entities (both general and + * parameter entities) unless XML_PARSE_NO_XXE was set. + * + * XML_PARSE_NO_XXE + * + * Disables loading of external DTDs or entities. + * + * XML_PARSE_NOERROR + * + * Disable error and warning reports to the error handlers. + * Errors are still accessible with xmlCtxtGetLastError. + * + * XML_PARSE_NOWARNING + * + * Disable warning reports. + * + * XML_PARSE_PEDANTIC + * + * Enable some pedantic warnings. + * + * XML_PARSE_NOBLANKS + * + * Remove some text nodes containing only whitespace from the + * result document. Which nodes are removed depends on DTD + * element declarations or a conservative heuristic. The + * reindenting feature of the serialization code relies on this + * option to be set when parsing. Use of this option is + * DISCOURAGED. + * + * XML_PARSE_SAX1 + * + * Always invoke the deprecated SAX1 startElement and endElement + * handlers. This option is DEPRECATED. + * + * XML_PARSE_NONET + * + * Disable network access with the builtin HTTP and FTP clients. + * + * XML_PARSE_NODICT + * + * Create a document without interned strings, making all + * strings separate memory allocations. + * + * XML_PARSE_NSCLEAN + * + * Remove redundant namespace declarations from the result + * document. + * + * XML_PARSE_NOCDATA + * + * Output normal text nodes instead of CDATA nodes. + * + * XML_PARSE_COMPACT + * + * Store small strings directly in the node struct to save + * memory. + * + * XML_PARSE_OLD10 * - * Applies the options to the parser context + * Use old Name productions from before XML 1.0 Fifth Edition. + * This options is DEPRECATED. + * + * XML_PARSE_HUGE + * + * Relax some internal limits. + * + * Maximum size of text nodes, tags, comments, processing instructions, + * CDATA sections, entity values + * + * normal: 10M + * huge: 1B + * + * Maximum size of names, system literals, pubid literals + * + * normal: 50K + * huge: 10M + * + * Maximum nesting depth of elements + * + * normal: 256 + * huge: 2048 + * + * Maximum nesting depth of entities + * + * normal: 20 + * huge: 40 + * + * XML_PARSE_OLDSAX + * + * Enable an unspecified legacy mode for SAX parsers. This + * option is DEPRECATED. + * + * XML_PARSE_IGNORE_ENC + * + * Ignore the encoding in the XML declaration. This option is + * mostly unneeded these days. The only effect is to enforce + * UTF-8 decoding of ASCII-like data. + * + * XML_PARSE_BIG_LINES + * + * Enable reporting of line numbers larger than 65535. * * Returns 0 in case of success, the set of unknown or unimplemented options * in case of error. */ -static int -xmlCtxtUseOptionsInternal(xmlParserCtxtPtr ctxt, int options) +int +xmlCtxtSetOptions(xmlParserCtxtPtr ctxt, int options) { - if (ctxt == NULL) - return(-1); - if (options & XML_PARSE_RECOVER) { - ctxt->recovery = 1; - options -= XML_PARSE_RECOVER; - ctxt->options |= XML_PARSE_RECOVER; - } else - ctxt->recovery = 0; - if (options & XML_PARSE_DTDLOAD) { - ctxt->loadsubset = XML_DETECT_IDS; - options -= XML_PARSE_DTDLOAD; - ctxt->options |= XML_PARSE_DTDLOAD; - } else - ctxt->loadsubset = 0; - if (options & XML_PARSE_DTDATTR) { - ctxt->loadsubset |= XML_COMPLETE_ATTRS; - options -= XML_PARSE_DTDATTR; - ctxt->options |= XML_PARSE_DTDATTR; - } - if (options & XML_PARSE_NOENT) { - ctxt->replaceEntities = 1; - /* ctxt->loadsubset |= XML_DETECT_IDS; */ - options -= XML_PARSE_NOENT; - ctxt->options |= XML_PARSE_NOENT; - } else - ctxt->replaceEntities = 0; - if (options & XML_PARSE_PEDANTIC) { - ctxt->pedantic = 1; - options -= XML_PARSE_PEDANTIC; - ctxt->options |= XML_PARSE_PEDANTIC; - } else - ctxt->pedantic = 0; - if (options & XML_PARSE_NOBLANKS) { - ctxt->keepBlanks = 0; - ctxt->sax->ignorableWhitespace = xmlSAX2IgnorableWhitespace; - options -= XML_PARSE_NOBLANKS; - ctxt->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; - ctxt->options |= XML_PARSE_DTDVALID; - } else - ctxt->validate = 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; - } -#ifdef LIBXML_SAX1_ENABLED - if (options & XML_PARSE_SAX1) { - ctxt->sax->startElementNs = NULL; - ctxt->sax->endElementNs = NULL; - ctxt->sax->initialized = 1; - options -= XML_PARSE_SAX1; - ctxt->options |= XML_PARSE_SAX1; - } -#endif /* LIBXML_SAX1_ENABLED */ - if (options & XML_PARSE_NODICT) { - ctxt->dictNames = 0; - options -= XML_PARSE_NODICT; - ctxt->options |= XML_PARSE_NODICT; - } else { - ctxt->dictNames = 1; - } - if (options & XML_PARSE_NOCDATA) { - ctxt->sax->cdataBlock = NULL; - options -= XML_PARSE_NOCDATA; - ctxt->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; - } - if (options & XML_PARSE_COMPACT) { - ctxt->options |= XML_PARSE_COMPACT; - options -= XML_PARSE_COMPACT; - } - if (options & XML_PARSE_OLD10) { - ctxt->options |= XML_PARSE_OLD10; - options -= XML_PARSE_OLD10; - } - if (options & XML_PARSE_NOBASEFIX) { - ctxt->options |= XML_PARSE_NOBASEFIX; - options -= XML_PARSE_NOBASEFIX; - } - if (options & XML_PARSE_HUGE) { - ctxt->options |= XML_PARSE_HUGE; - options -= XML_PARSE_HUGE; - if (ctxt->dict != NULL) - xmlDictSetLimit(ctxt->dict, 0); - } - if (options & XML_PARSE_OLDSAX) { - ctxt->options |= XML_PARSE_OLDSAX; - options -= XML_PARSE_OLDSAX; - } - if (options & XML_PARSE_IGNORE_ENC) { - ctxt->options |= XML_PARSE_IGNORE_ENC; - options -= XML_PARSE_IGNORE_ENC; - } - if (options & XML_PARSE_BIG_LINES) { - ctxt->options |= XML_PARSE_BIG_LINES; - options -= XML_PARSE_BIG_LINES; - } - ctxt->linenumbers = 1; - return (options); + return(xmlCtxtSetOptionsInternal(ctxt, options, 0)); }
/** @@ -14767,7 +13713,22 @@ xmlCtxtUseOptionsInternal(xmlParserCtxtPtr ctxt, int options) * @ctxt: an XML parser context * @options: a combination of xmlParserOption * - * Applies the options to the parser context + * DEPRECATED: Use xmlCtxtSetOptions. + * + * Applies the options to the parser context. The following options + * are never cleared and can only be enabled: + * + * XML_PARSE_NOERROR + * XML_PARSE_NOWARNING + * XML_PARSE_NONET + * XML_PARSE_NSCLEAN + * XML_PARSE_NOCDATA + * XML_PARSE_COMPACT + * XML_PARSE_OLD10 + * XML_PARSE_HUGE + * XML_PARSE_OLDSAX + * XML_PARSE_IGNORE_ENC + * XML_PARSE_BIG_LINES * * Returns 0 in case of success, the set of unknown or unimplemented options * in case of error. @@ -14775,7 +13736,24 @@ xmlCtxtUseOptionsInternal(xmlParserCtxtPtr ctxt, int options) int xmlCtxtUseOptions(xmlParserCtxtPtr ctxt, int options) { - return(xmlCtxtUseOptionsInternal(ctxt, options)); + int keepMask; + + /* + * For historic reasons, some options can only be enabled. + */ + keepMask = XML_PARSE_NOERROR | + XML_PARSE_NOWARNING | + XML_PARSE_NONET | + XML_PARSE_NSCLEAN | + XML_PARSE_NOCDATA | + XML_PARSE_COMPACT | + XML_PARSE_OLD10 | + XML_PARSE_HUGE | + XML_PARSE_OLDSAX | + XML_PARSE_IGNORE_ENC | + XML_PARSE_BIG_LINES; + + return(xmlCtxtSetOptionsInternal(ctxt, options, keepMask)); }
/** @@ -14798,90 +13776,102 @@ xmlCtxtSetMaxAmplification(xmlParserCtxtPtr ctxt, unsigned maxAmpl) }
/** - * xmlDoRead: + * xmlCtxtParseDocument: * @ctxt: an XML parser context - * @URL: the base URL to use for the document - * @encoding: the document encoding, or NULL - * @options: a combination of xmlParserOption - * @reuse: keep the context for reuse + * @input: parser input * - * Common front-end for the xmlRead functions + * Parse an XML document and return the resulting document tree. + * Takes ownership of the input object. + * + * Available since 2.13.0. * * Returns the resulting document tree or NULL */ -static xmlDocPtr -xmlDoRead(xmlParserCtxtPtr ctxt, const char *URL, const char *encoding, - int options, int reuse) +xmlDocPtr +xmlCtxtParseDocument(xmlParserCtxtPtr ctxt, xmlParserInputPtr input) { - xmlDocPtr ret; + xmlDocPtr ret = NULL;
- xmlCtxtUseOptionsInternal(ctxt, options); - if (encoding != NULL) { - xmlCharEncodingHandlerPtr hdlr; + if ((ctxt == NULL) || (input == NULL)) + return(NULL);
- /* - * TODO: We should consider to set XML_PARSE_IGNORE_ENC if the - * caller provided an encoding. Otherwise, we might switch to - * the encoding from the XML declaration which is likely to - * break things. Also see xmlSwitchInputEncoding. - */ - hdlr = xmlFindCharEncodingHandler(encoding); - if (hdlr != NULL) - xmlSwitchToEncoding(ctxt, hdlr); + /* assert(ctxt->inputNr == 0); */ + while (ctxt->inputNr > 0) + xmlFreeInputStream(inputPop(ctxt)); + + if (inputPush(ctxt, input) < 0) { + xmlFreeInputStream(input); + return(NULL); } - 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) + + if ((ctxt->wellFormed) || + ((ctxt->recovery) && (ctxt->errNo != XML_ERR_NO_MEMORY))) { ret = ctxt->myDoc; - else { + } else { + if (ctxt->errNo == XML_ERR_OK) + xmlFatalErrMsg(ctxt, XML_ERR_INTERNAL_ERROR, "unknown error\n"); + ret = NULL; - if (ctxt->myDoc != NULL) { - xmlFreeDoc(ctxt->myDoc); - } + xmlFreeDoc(ctxt->myDoc); } ctxt->myDoc = NULL; - if (!reuse) { - xmlFreeParserCtxt(ctxt); - }
- return (ret); + /* assert(ctxt->inputNr == 1); */ + while (ctxt->inputNr > 0) + xmlFreeInputStream(inputPop(ctxt)); + + return(ret); }
/** * xmlReadDoc: * @cur: a pointer to a zero terminated string - * @URL: the base URL to use for the document - * @encoding: the document encoding, or NULL + * @URL: base URL (optional) + * @encoding: the document encoding (optional) * @options: a combination of xmlParserOption * - * parse an XML in-memory document and build a tree. + * Convenience function to parse an XML document from a + * zero-terminated string. + * + * See xmlCtxtReadDoc for details. * * Returns the resulting document tree */ xmlDocPtr -xmlReadDoc(const xmlChar * cur, const char *URL, const char *encoding, int options) +xmlReadDoc(const xmlChar *cur, const char *URL, const char *encoding, + int options) { xmlParserCtxtPtr ctxt; + xmlParserInputPtr input; + xmlDocPtr doc;
- if (cur == NULL) - return (NULL); - xmlInitParser(); - - ctxt = xmlCreateDocParserCtxt(cur); + ctxt = xmlNewParserCtxt(); if (ctxt == NULL) - return (NULL); - return (xmlDoRead(ctxt, URL, encoding, options, 0)); + return(NULL); + + xmlCtxtUseOptions(ctxt, options); + + input = xmlNewInputString(ctxt, URL, (const char *) cur, encoding, + XML_INPUT_BUF_STATIC); + + doc = xmlCtxtParseDocument(ctxt, input); + + xmlFreeParserCtxt(ctxt); + return(doc); }
/** * xmlReadFile: * @filename: a file or URL - * @encoding: the document encoding, or NULL + * @encoding: the document encoding (optional) * @options: a combination of xmlParserOption * - * parse an XML file from the filesystem or the network. + * Convenience function to parse an XML file from the filesystem, + * the network or a global user-define resource loader. + * + * See xmlCtxtReadFile for details. * * Returns the resulting document tree */ @@ -14889,48 +13879,86 @@ xmlDocPtr xmlReadFile(const char *filename, const char *encoding, int options) { xmlParserCtxtPtr ctxt; + xmlParserInputPtr input; + xmlDocPtr doc;
- xmlInitParser(); - ctxt = xmlCreateURLParserCtxt(filename, options); + ctxt = xmlNewParserCtxt(); if (ctxt == NULL) - return (NULL); - return (xmlDoRead(ctxt, NULL, encoding, options, 0)); + return(NULL); + + xmlCtxtUseOptions(ctxt, options); + + /* + * Backward compatibility for users of command line utilities like + * xmlstarlet expecting "-" to mean stdin. This is dangerous and + * should be removed at some point. + */ + if ((filename != NULL) && (filename[0] == '-') && (filename[1] == 0)) + input = xmlNewInputFd(ctxt, filename, STDIN_FILENO, encoding, + XML_INPUT_UNZIP); + else + input = xmlNewInputURL(ctxt, filename, NULL, encoding, 0); + + doc = xmlCtxtParseDocument(ctxt, input); + + xmlFreeParserCtxt(ctxt); + return(doc); }
/** * xmlReadMemory: * @buffer: a pointer to a char array * @size: the size of the array - * @URL: the base URL to use for the document - * @encoding: the document encoding, or NULL + * @url: base URL (optional) + * @encoding: the document encoding (optional) * @options: a combination of xmlParserOption * - * parse an XML in-memory document and build a tree. + * Parse an XML in-memory document and build a tree. The input buffer must + * not contain a terminating null byte. + * + * See xmlCtxtReadMemory for details. * * Returns the resulting document tree */ xmlDocPtr -xmlReadMemory(const char *buffer, int size, const char *URL, const char *encoding, int options) +xmlReadMemory(const char *buffer, int size, const char *url, + const char *encoding, int options) { xmlParserCtxtPtr ctxt; + xmlParserInputPtr input; + xmlDocPtr doc;
- xmlInitParser(); - ctxt = xmlCreateMemoryParserCtxt(buffer, size); + if (size < 0) + return(NULL); + + ctxt = xmlNewParserCtxt(); if (ctxt == NULL) - return (NULL); - return (xmlDoRead(ctxt, URL, encoding, options, 0)); + return(NULL); + + xmlCtxtUseOptions(ctxt, options); + + input = xmlNewInputMemory(ctxt, url, buffer, size, encoding, + XML_INPUT_BUF_STATIC); + + doc = xmlCtxtParseDocument(ctxt, input); + + xmlFreeParserCtxt(ctxt); + return(doc); }
/** * xmlReadFd: * @fd: an open file descriptor - * @URL: the base URL to use for the document - * @encoding: the document encoding, or NULL + * @URL: base URL (optional) + * @encoding: the document encoding (optional) * @options: a combination of xmlParserOption * - * parse an XML from a file descriptor and build a tree. + * Parse an XML from a file descriptor and build a tree. + * + * See xmlCtxtReadFd for details. + * * NOTE that the file descriptor will not be closed when the - * reader is closed or reset. + * context is freed or reset. * * Returns the resulting document tree */ @@ -14938,42 +13966,35 @@ xmlDocPtr xmlReadFd(int fd, const char *URL, const char *encoding, int options) { xmlParserCtxtPtr ctxt; - xmlParserInputBufferPtr input; - xmlParserInputPtr stream; - - if (fd < 0) - return (NULL); - xmlInitParser(); + xmlParserInputPtr input; + xmlDocPtr doc;
- 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)); + if (ctxt == NULL) + return(NULL); + + xmlCtxtUseOptions(ctxt, options); + + input = xmlNewInputFd(ctxt, URL, fd, encoding, 0); + + doc = xmlCtxtParseDocument(ctxt, input); + + xmlFreeParserCtxt(ctxt); + return(doc); }
/** * xmlReadIO: * @ioread: an I/O read function - * @ioclose: an I/O close function + * @ioclose: an I/O close function (optional) * @ioctx: an I/O handler - * @URL: the base URL to use for the document - * @encoding: the document encoding, or NULL + * @URL: base URL (optional) + * @encoding: the document encoding (optional) * @options: a combination of xmlParserOption * - * parse an XML document from I/O functions and source and build a tree. + * Parse an XML document from I/O functions and context and build a tree. + * + * See xmlCtxtReadIO for details. * * Returns the resulting document tree */ @@ -14982,45 +14003,37 @@ 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); - xmlInitParser(); + xmlParserInputPtr input; + xmlDocPtr doc;
- input = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx, - XML_CHAR_ENCODING_NONE); - if (input == NULL) { - if (ioclose != NULL) - ioclose(ioctx); - 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)); + if (ctxt == NULL) + return(NULL); + + xmlCtxtUseOptions(ctxt, options); + + input = xmlNewInputIO(ctxt, URL, ioread, ioclose, ioctx, encoding, 0); + + doc = xmlCtxtParseDocument(ctxt, input); + + xmlFreeParserCtxt(ctxt); + return(doc); }
/** * xmlCtxtReadDoc: * @ctxt: an XML parser context * @str: a pointer to a zero terminated string - * @URL: the base URL to use for the document - * @encoding: the document encoding, or NULL + * @URL: base URL (optional) + * @encoding: the document encoding (optional) * @options: a combination of xmlParserOption * - * parse an XML in-memory document and build a tree. - * This reuses the existing @ctxt parser context + * Parse an XML in-memory document and build a tree. + * + * @URL is used as base to resolve external entities and for error + * reporting. + * + * See xmlCtxtUseOptions for details. * * Returns the resulting document tree */ @@ -15028,41 +14041,29 @@ xmlDocPtr xmlCtxtReadDoc(xmlParserCtxtPtr ctxt, const xmlChar *str, const char *URL, const char *encoding, int options) { - xmlParserInputBufferPtr input; - xmlParserInputPtr stream; + xmlParserInputPtr input;
if (ctxt == NULL) - return (NULL); - if (str == NULL) - return (NULL); - xmlInitParser(); + return(NULL);
xmlCtxtReset(ctxt); + xmlCtxtUseOptions(ctxt, options);
- input = xmlParserInputBufferCreateString(str); - if (input == NULL) { - return(NULL); - } - - stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE); - if (stream == NULL) { - xmlFreeParserInputBuffer(input); - return(NULL); - } + input = xmlNewInputString(ctxt, URL, (const char *) str, encoding, + XML_INPUT_BUF_STATIC);
- inputPush(ctxt, stream); - return (xmlDoRead(ctxt, URL, encoding, options, 1)); + return(xmlCtxtParseDocument(ctxt, input)); }
/** * xmlCtxtReadFile: * @ctxt: an XML parser context * @filename: a file or URL - * @encoding: the document encoding, or NULL + * @encoding: the document encoding (optional) * @options: a combination of xmlParserOption * - * parse an XML file from the filesystem or the network. - * This reuses the existing @ctxt parser context + * Parse an XML file from the filesystem, the network or a user-defined + * resource loader. * * Returns the resulting document tree */ @@ -15070,22 +14071,17 @@ xmlDocPtr xmlCtxtReadFile(xmlParserCtxtPtr ctxt, const char *filename, const char *encoding, int options) { - xmlParserInputPtr stream; + xmlParserInputPtr input;
- if (filename == NULL) - return (NULL); if (ctxt == NULL) - return (NULL); - xmlInitParser(); + return(NULL);
xmlCtxtReset(ctxt); + xmlCtxtUseOptions(ctxt, options);
- stream = xmlLoadExternalEntity(filename, NULL, ctxt); - if (stream == NULL) { - return (NULL); - } - inputPush(ctxt, stream); - return (xmlDoRead(ctxt, NULL, encoding, options, 1)); + input = xmlNewInputURL(ctxt, filename, NULL, encoding, 0); + + return(xmlCtxtParseDocument(ctxt, input)); }
/** @@ -15093,12 +14089,17 @@ xmlCtxtReadFile(xmlParserCtxtPtr ctxt, const char *filename, * @ctxt: an XML parser context * @buffer: a pointer to a char array * @size: the size of the array - * @URL: the base URL to use for the document - * @encoding: the document encoding, or NULL + * @URL: base URL (optional) + * @encoding: the document encoding (optional) * @options: a combination of xmlParserOption * - * parse an XML in-memory document and build a tree. - * This reuses the existing @ctxt parser context + * Parse an XML in-memory document and build a tree. The input buffer must + * not contain a terminating null byte. + * + * @URL is used as base to resolve external entities and for error + * reporting. + * + * See xmlCtxtUseOptions for details. * * Returns the resulting document tree */ @@ -15106,45 +14107,37 @@ xmlDocPtr xmlCtxtReadMemory(xmlParserCtxtPtr ctxt, const char *buffer, int size, const char *URL, const char *encoding, int options) { - xmlParserInputBufferPtr input; - xmlParserInputPtr stream; + xmlParserInputPtr input;
- if (ctxt == NULL) - return (NULL); - if (buffer == NULL) - return (NULL); - xmlInitParser(); + if ((ctxt == NULL) || (size < 0)) + return(NULL);
xmlCtxtReset(ctxt); + xmlCtxtUseOptions(ctxt, options);
- input = xmlParserInputBufferCreateStatic(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); - } + input = xmlNewInputMemory(ctxt, URL, buffer, size, encoding, + XML_INPUT_BUF_STATIC);
- inputPush(ctxt, stream); - return (xmlDoRead(ctxt, URL, encoding, options, 1)); + return(xmlCtxtParseDocument(ctxt, input)); }
/** * xmlCtxtReadFd: * @ctxt: an XML parser context * @fd: an open file descriptor - * @URL: the base URL to use for the document - * @encoding: the document encoding, or NULL + * @URL: base URL (optional) + * @encoding: the document encoding (optional) * @options: a combination of xmlParserOption * - * parse an XML from a file descriptor and build a tree. - * This reuses the existing @ctxt parser context + * Parse an XML document from a file descriptor and build a tree. + * * NOTE that the file descriptor will not be closed when the - * reader is closed or reset. + * context is freed or reset. + * + * @URL is used as base to resolve external entities and for error + * reporting. + * + * See xmlCtxtUseOptions for details. * * Returns the resulting document tree */ @@ -15152,29 +14145,21 @@ xmlDocPtr xmlCtxtReadFd(xmlParserCtxtPtr ctxt, int fd, const char *URL, const char *encoding, int options) { - xmlParserInputBufferPtr input; - xmlParserInputPtr stream; + xmlParserInputPtr input; + int inputFlags;
- if (fd < 0) - return (NULL); if (ctxt == NULL) - return (NULL); - xmlInitParser(); + return(NULL);
xmlCtxtReset(ctxt); + xmlCtxtUseOptions(ctxt, options);
+ inputFlags = 0; + if (options & XML_PARSE_UNZIP) + inputFlags |= XML_INPUT_UNZIP; + input = xmlNewInputFd(ctxt, URL, fd, encoding, inputFlags);
- 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)); + return(xmlCtxtParseDocument(ctxt, input)); }
/** @@ -15190,6 +14175,11 @@ xmlCtxtReadFd(xmlParserCtxtPtr ctxt, int fd, * parse an XML document from I/O functions and source and build a tree. * This reuses the existing @ctxt parser context * + * @URL is used as base to resolve external entities and for error + * reporting. + * + * See xmlCtxtUseOptions for details. + * * Returns the resulting document tree */ xmlDocPtr @@ -15198,29 +14188,15 @@ xmlCtxtReadIO(xmlParserCtxtPtr ctxt, xmlInputReadCallback ioread, const char *URL, const char *encoding, int options) { - xmlParserInputBufferPtr input; - xmlParserInputPtr stream; + xmlParserInputPtr input;
- if (ioread == NULL) - return (NULL); if (ctxt == NULL) - return (NULL); - xmlInitParser(); + return(NULL);
xmlCtxtReset(ctxt); + xmlCtxtUseOptions(ctxt, options);
- input = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx, - XML_CHAR_ENCODING_NONE); - if (input == NULL) { - if (ioclose != NULL) - ioclose(ioctx); - 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)); + input = xmlNewInputIO(ctxt, URL, ioread, ioclose, ioctx, encoding, 0); + + return(xmlCtxtParseDocument(ctxt, input)); } diff --git a/libs/xml2/parserInternals.c b/libs/xml2/parserInternals.c index fca46c7feae..2db0105bc8e 100644 --- a/libs/xml2/parserInternals.c +++ b/libs/xml2/parserInternals.c @@ -35,6 +35,7 @@ #include <libxml/catalog.h> #endif #include <libxml/chvalid.h> +#include <libxml/nanohttp.h>
#define CUR(ctxt) ctxt->input->cur #define END(ctxt) ctxt->input->end @@ -45,6 +46,8 @@ #include "private/io.h" #include "private/parser.h"
+#define XML_MAX_ERRORS 100 + /* * XML_MAX_AMPLIFICATION_DEFAULT is the default maximum allowed amplification * factor of serialized output after entity expansion. @@ -60,7 +63,6 @@ * @version: the include version number * * check the compiled lib version against the include one. - * This can warn or immediately kill the application */ void xmlCheckVersion(int version) { @@ -69,15 +71,11 @@ xmlCheckVersion(int version) { xmlInitParser();
if ((myversion / 10000) != (version / 10000)) { - xmlGenericError(xmlGenericErrorContext, - "Fatal: program compiled against libxml %d using libxml %d\n", - (version / 10000), (myversion / 10000)); fprintf(stderr, "Fatal: program compiled against libxml %d using libxml %d\n", (version / 10000), (myversion / 10000)); - } - if ((myversion / 100) < (version / 100)) { - xmlGenericError(xmlGenericErrorContext, + } else if ((myversion / 100) < (version / 100)) { + fprintf(stderr, "Warning: program compiled against libxml %d using older %d\n", (version / 100), (myversion / 100)); } @@ -92,338 +90,290 @@ xmlCheckVersion(int version) {
/** - * xmlErrMemory: + * xmlCtxtSetErrorHandler: * @ctxt: an XML parser context - * @extra: extra information + * @handler: error handler + * @data: data for error handler + * + * Register a callback function that will be called on errors and + * warnings. If handler is NULL, the error handler will be deactivated. + * + * This is the recommended way to collect errors from the parser and + * takes precedence over all other error reporting mechanisms. + * These are (in order of precedence): + * + * - per-context structured handler (xmlCtxtSetErrorHandler) + * - per-context structured "serror" SAX handler + * - global structured handler (xmlSetStructuredErrorFunc) + * - per-context generic "error" and "warning" SAX handlers + * - global generic handler (xmlSetGenericErrorFunc) + * - print to stderr * - * Handle a redefinition of attribute error + * Available since 2.13.0. */ void -xmlErrMemory(xmlParserCtxtPtr ctxt, const char *extra) +xmlCtxtSetErrorHandler(xmlParserCtxtPtr ctxt, xmlStructuredErrorFunc handler, + void *data) { - if ((ctxt != NULL) && (ctxt->disableSAX != 0) && - (ctxt->instate == XML_PARSER_EOF)) - return; - if (ctxt != NULL) { - ctxt->errNo = XML_ERR_NO_MEMORY; - ctxt->instate = XML_PARSER_EOF; - ctxt->disableSAX = 1; - } - if (extra) - __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER, - XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra, - NULL, NULL, 0, 0, - "Memory allocation failed : %s\n", extra); - else - __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER, - XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL, - NULL, NULL, 0, 0, "Memory allocation failed\n"); + if (ctxt == NULL) + return; + ctxt->errorHandler = handler; + ctxt->errorCtxt = data; }
/** - * __xmlErrEncoding: + * xmlCtxtErrMemory: * @ctxt: an XML parser context - * @xmlerr: the error number - * @msg: the error message - * @str1: an string info - * @str2: an string info * - * Handle an encoding error + * Handle an out-of-memory error. + * + * Available since 2.13.0. */ void -__xmlErrEncoding(xmlParserCtxtPtr ctxt, xmlParserErrors xmlerr, - const char *msg, const xmlChar * str1, const xmlChar * str2) +xmlCtxtErrMemory(xmlParserCtxtPtr ctxt) { - if ((ctxt != NULL) && (ctxt->disableSAX != 0) && - (ctxt->instate == XML_PARSER_EOF)) - return; - if (ctxt != NULL) - ctxt->errNo = xmlerr; - __xmlRaiseError(NULL, NULL, NULL, - ctxt, NULL, XML_FROM_PARSER, xmlerr, XML_ERR_FATAL, - NULL, 0, (const char *) str1, (const char *) str2, - NULL, 0, 0, msg, str1, str2); - if (ctxt != NULL) { - ctxt->wellFormed = 0; - if (ctxt->recovery == 0) - ctxt->disableSAX = 1; + xmlStructuredErrorFunc schannel = NULL; + xmlGenericErrorFunc channel = NULL; + void *data; + + if (ctxt == NULL) + return; + + ctxt->errNo = XML_ERR_NO_MEMORY; + ctxt->instate = XML_PARSER_EOF; /* TODO: Remove after refactoring */ + ctxt->wellFormed = 0; + ctxt->disableSAX = 2; + + if (ctxt->errorHandler) { + schannel = ctxt->errorHandler; + data = ctxt->errorCtxt; + } else if ((ctxt->sax->initialized == XML_SAX2_MAGIC) && + (ctxt->sax->serror != NULL)) { + schannel = ctxt->sax->serror; + data = ctxt->userData; + } else { + channel = ctxt->sax->error; + data = ctxt->userData; } + + xmlRaiseMemoryError(schannel, channel, data, XML_FROM_PARSER, + &ctxt->lastError); }
/** - * xmlErrInternal: - * @ctxt: an XML parser context - * @msg: the error message - * @str: error information + * xmlCtxtErrIO: + * @ctxt: parser context + * @code: xmlParserErrors code + * @uri: filename or URI (optional) * - * Handle an internal error + * If filename is empty, use the one from context input if available. + * + * Report an IO error to the parser context. + */ +void +xmlCtxtErrIO(xmlParserCtxtPtr ctxt, int code, const char *uri) +{ + const char *errstr, *msg, *str1, *str2; + xmlErrorLevel level; + + if (ctxt == NULL) + return; + + /* + * Only report a warning if a file could not be found. This should + * only be done for external entities, but the external entity loader + * of xsltproc can try multiple paths and assumes that ENOENT doesn't + * raise an error and aborts parsing. + */ + if (((code == XML_IO_ENOENT) || + (code == XML_IO_NETWORK_ATTEMPT) || + (code == XML_IO_UNKNOWN))) { + if (ctxt->validate == 0) + level = XML_ERR_WARNING; + else + level = XML_ERR_ERROR; + } else { + level = XML_ERR_FATAL; + } + + errstr = xmlErrString(code); + + if (uri == NULL) { + msg = "%s\n"; + str1 = errstr; + str2 = NULL; + } else { + msg = "failed to load "%s": %s\n"; + str1 = uri; + str2 = errstr; + } + + xmlCtxtErr(ctxt, NULL, XML_FROM_IO, code, level, + (const xmlChar *) uri, NULL, NULL, 0, + msg, str1, str2); +} + +/** + * xmlCtxtVErr: + * @ctxt: a parser context + * @node: the current node or NULL + * @domain: the domain for the error + * @code: the code for the error + * @level: the xmlErrorLevel for the error + * @str1: extra string info + * @str2: extra string info + * @str3: extra string info + * @int1: extra int info + * @msg: the message to display/transmit + * @ap: extra parameters for the message display + * + * Raise a parser error. */ -static void LIBXML_ATTR_FORMAT(2,0) -xmlErrInternal(xmlParserCtxtPtr ctxt, const char *msg, const xmlChar * str) +void +xmlCtxtVErr(xmlParserCtxtPtr ctxt, xmlNodePtr node, xmlErrorDomain domain, + xmlParserErrors code, xmlErrorLevel level, + const xmlChar *str1, const xmlChar *str2, const xmlChar *str3, + int int1, const char *msg, va_list ap) { - if ((ctxt != NULL) && (ctxt->disableSAX != 0) && - (ctxt->instate == XML_PARSER_EOF)) + xmlStructuredErrorFunc schannel = NULL; + xmlGenericErrorFunc channel = NULL; + void *data = NULL; + const char *file = NULL; + int line = 0; + int col = 0; + int res; + + if (code == XML_ERR_NO_MEMORY) { + xmlCtxtErrMemory(ctxt); + return; + } + + if (PARSER_STOPPED(ctxt)) return; - if (ctxt != NULL) - ctxt->errNo = XML_ERR_INTERNAL_ERROR; - __xmlRaiseError(NULL, NULL, NULL, - ctxt, NULL, XML_FROM_PARSER, XML_ERR_INTERNAL_ERROR, - XML_ERR_FATAL, NULL, 0, (const char *) str, NULL, NULL, - 0, 0, msg, str); - if (ctxt != NULL) { + + if (level == XML_ERR_WARNING) { + if (ctxt->nbWarnings >= XML_MAX_ERRORS) + goto done; + ctxt->nbWarnings += 1; + } else { + /* Report at least one fatal error. */ + if ((ctxt->nbErrors >= XML_MAX_ERRORS) && + ((level < XML_ERR_FATAL) || (ctxt->wellFormed == 0))) + goto done; + ctxt->nbErrors += 1; + } + + if (((ctxt->options & XML_PARSE_NOERROR) == 0) && + ((level != XML_ERR_WARNING) || + ((ctxt->options & XML_PARSE_NOWARNING) == 0))) { + if (ctxt->errorHandler) { + schannel = ctxt->errorHandler; + data = ctxt->errorCtxt; + } else if ((ctxt->sax->initialized == XML_SAX2_MAGIC) && + (ctxt->sax->serror != NULL)) { + schannel = ctxt->sax->serror; + data = ctxt->userData; + } else if ((domain == XML_FROM_VALID) || (domain == XML_FROM_DTD)) { + if (level == XML_ERR_WARNING) + channel = ctxt->vctxt.warning; + else + channel = ctxt->vctxt.error; + data = ctxt->vctxt.userData; + } else { + if (level == XML_ERR_WARNING) + channel = ctxt->sax->warning; + else + channel = ctxt->sax->error; + data = ctxt->userData; + } + } + + if (ctxt->input != NULL) { + xmlParserInputPtr input = ctxt->input; + + if ((input->filename == NULL) && + (ctxt->inputNr > 1)) { + input = ctxt->inputTab[ctxt->inputNr - 2]; + } + file = input->filename; + line = input->line; + col = input->col; + } + + res = xmlVRaiseError(schannel, channel, data, ctxt, node, domain, code, + level, file, line, (const char *) str1, + (const char *) str2, (const char *) str3, int1, col, + msg, ap); + + if (res < 0) { + xmlCtxtErrMemory(ctxt); + return; + } + +done: + if (level >= XML_ERR_ERROR) + ctxt->errNo = code; + if (level == XML_ERR_FATAL) { ctxt->wellFormed = 0; if (ctxt->recovery == 0) ctxt->disableSAX = 1; } + + return; +} + +/** + * xmlCtxtErr: + * @ctxt: a parser context + * @node: the current node or NULL + * @domain: the domain for the error + * @code: the code for the error + * @level: the xmlErrorLevel for the error + * @str1: extra string info + * @str2: extra string info + * @str3: extra string info + * @int1: extra int info + * @msg: the message to display/transmit + * @...: extra parameters for the message display + * + * Raise a parser error. + */ +void +xmlCtxtErr(xmlParserCtxtPtr ctxt, xmlNodePtr node, xmlErrorDomain domain, + xmlParserErrors code, xmlErrorLevel level, + const xmlChar *str1, const xmlChar *str2, const xmlChar *str3, + int int1, const char *msg, ...) +{ + va_list ap; + + va_start(ap, msg); + xmlCtxtVErr(ctxt, node, domain, code, level, + str1, str2, str3, int1, msg, ap); + va_end(ap); }
/** * xmlFatalErr: * @ctxt: an XML parser context - * @error: the error number + * @code: the error number * @info: extra information string * * Handle a fatal parser error, i.e. violating Well-Formedness constraints */ void -xmlFatalErr(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *info) +xmlFatalErr(xmlParserCtxtPtr ctxt, xmlParserErrors code, const char *info) { const char *errmsg;
- 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"; - break; - case XML_ERR_INVALID_ENCODING: - errmsg = "Invalid bytes in character encoding"; - break; - case XML_IO_UNKNOWN: - errmsg = "I/O error"; - break; -#if 0 - case: - errmsg = ""; - break; -#endif - default: - errmsg = "Unregistered error message"; - } - if (ctxt != NULL) - ctxt->errNo = error; + errmsg = xmlErrString(code); + if (info == NULL) { - __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER, error, - XML_ERR_FATAL, NULL, 0, info, NULL, NULL, 0, 0, "%s\n", - errmsg); + xmlCtxtErr(ctxt, NULL, XML_FROM_PARSER, code, XML_ERR_FATAL, + NULL, NULL, NULL, 0, "%s\n", errmsg); } else { - __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER, error, - XML_ERR_FATAL, NULL, 0, info, NULL, NULL, 0, 0, "%s: %s\n", - errmsg, info); - } - if (ctxt != NULL) { - ctxt->wellFormed = 0; - if (ctxt->recovery == 0) - ctxt->disableSAX = 1; - } -} - -/** - * xmlErrEncodingInt: - * @ctxt: an XML parser context - * @error: the error number - * @msg: the error message - * @val: an integer value - * - * n encoding error - */ -static void LIBXML_ATTR_FORMAT(3,0) -xmlErrEncodingInt(xmlParserCtxtPtr ctxt, xmlParserErrors error, - const char *msg, int val) -{ - if ((ctxt != NULL) && (ctxt->disableSAX != 0) && - (ctxt->instate == XML_PARSER_EOF)) - return; - if (ctxt != NULL) - 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); - if (ctxt != NULL) { - ctxt->wellFormed = 0; - if (ctxt->recovery == 0) - ctxt->disableSAX = 1; + xmlCtxtErr(ctxt, NULL, XML_FROM_PARSER, code, XML_ERR_FATAL, + (const xmlChar *) info, NULL, NULL, 0, + "%s: %s\n", errmsg, info); } }
@@ -461,28 +411,8 @@ void xmlHaltParser(xmlParserCtxtPtr ctxt) { if (ctxt == NULL) return; - ctxt->instate = XML_PARSER_EOF; - ctxt->disableSAX = 1; - while (ctxt->inputNr > 1) - xmlFreeInputStream(inputPop(ctxt)); - if (ctxt->input != NULL) { - /* - * in case there was a specific allocation deallocate before - * overriding base - */ - if (ctxt->input->free != NULL) { - ctxt->input->free((xmlChar *) ctxt->input->base); - ctxt->input->free = NULL; - } - if (ctxt->input->buf != NULL) { - xmlFreeParserInputBuffer(ctxt->input->buf); - ctxt->input->buf = NULL; - } - ctxt->input->cur = BAD_CAST""; - ctxt->input->length = 0; - ctxt->input->base = ctxt->input->cur; - ctxt->input->end = ctxt->input->cur; - } + ctxt->instate = XML_PARSER_EOF; /* TODO: Remove after refactoring */ + ctxt->disableSAX = 2; }
/** @@ -511,14 +441,17 @@ int xmlParserGrow(xmlParserCtxtPtr ctxt) { xmlParserInputPtr in = ctxt->input; xmlParserInputBufferPtr buf = in->buf; - ptrdiff_t curEnd = in->end - in->cur; - ptrdiff_t curBase = in->cur - in->base; + size_t curEnd = in->end - in->cur; + size_t curBase = in->cur - in->base; + size_t maxLength = (ctxt->options & XML_PARSE_HUGE) ? + XML_MAX_HUGE_LENGTH : + XML_MAX_LOOKUP_LIMIT; int ret;
if (buf == NULL) return(0); /* Don't grow push parser buffer. */ - if ((ctxt->progressive) && (ctxt->inputNr <= 1)) + if (PARSER_PROGRESSIVE(ctxt)) return(0); /* Don't grow memory buffers. */ if ((buf->encoder == NULL) && (buf->readcallback == NULL)) @@ -526,10 +459,9 @@ xmlParserGrow(xmlParserCtxtPtr ctxt) { if (buf->error != 0) return(-1);
- if (((curEnd > XML_MAX_LOOKUP_LIMIT) || - (curBase > XML_MAX_LOOKUP_LIMIT)) && - ((ctxt->options & XML_PARSE_HUGE) == 0)) { - xmlErrMemory(ctxt, "Huge input lookup"); + if (curBase > maxLength) { + xmlFatalErr(ctxt, XML_ERR_RESOURCE_LIMIT, + "Buffer size limit exceeded, try XML_PARSE_HUGE\n"); xmlHaltParser(ctxt); return(-1); } @@ -541,10 +473,7 @@ xmlParserGrow(xmlParserCtxtPtr ctxt) { xmlBufUpdateInput(buf->buffer, in, curBase);
if (ret < 0) { - xmlFatalErr(ctxt, buf->error, NULL); - /* Buffer contents may be lost in case of memory errors. */ - if (buf->error == XML_ERR_NO_MEMORY) - xmlHaltParser(ctxt); + xmlCtxtErrIO(ctxt, buf->error, NULL); }
return(ret); @@ -612,7 +541,7 @@ xmlParserShrink(xmlParserCtxtPtr ctxt) { if (buf == NULL) return; /* Don't shrink pull parser memory buffers. */ - if (((ctxt->progressive == 0) || (ctxt->inputNr > 1)) && + if ((!PARSER_PROGRESSIVE(ctxt)) && (buf->encoder == NULL) && (buf->readcallback == NULL)) return; @@ -712,16 +641,14 @@ xmlNextChar(xmlParserCtxtPtr ctxt) size_t avail; int c;
- if ((ctxt == NULL) || (ctxt->instate == XML_PARSER_EOF) || - (ctxt->input == NULL)) + if ((ctxt == NULL) || (ctxt->input == NULL)) return;
avail = ctxt->input->end - ctxt->input->cur;
if (avail < INPUT_CHUNK) { xmlParserGrow(ctxt); - if ((ctxt->instate == XML_PARSER_EOF) || - (ctxt->input->cur >= ctxt->input->end)) + if (ctxt->input->cur >= ctxt->input->end) return; avail = ctxt->input->end - ctxt->input->cur; } @@ -788,21 +715,7 @@ xmlNextChar(xmlParserCtxtPtr ctxt) encoding_error: /* Only report the first error */ if ((ctxt->input->flags & XML_INPUT_ENCODING_ERROR) == 0) { - if ((ctxt == NULL) || (ctxt->input == NULL) || - (ctxt->input->end - ctxt->input->cur < 4)) { - __xmlErrEncoding(ctxt, XML_ERR_INVALID_CHAR, - "Input is not proper UTF-8, indicate encoding !\n", - NULL, NULL); - } else { - 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); - } + xmlCtxtErrIO(ctxt, XML_ERR_INVALID_ENCODING, NULL); ctxt->input->flags |= XML_INPUT_ENCODING_ERROR; } ctxt->input->cur++; @@ -836,15 +749,11 @@ xmlCurrentChar(xmlParserCtxtPtr ctxt, int *len) { int c;
if ((ctxt == NULL) || (len == NULL) || (ctxt->input == NULL)) return(0); - if (ctxt->instate == XML_PARSER_EOF) - return(0);
avail = ctxt->input->end - ctxt->input->cur;
if (avail < INPUT_CHUNK) { xmlParserGrow(ctxt); - if (ctxt->instate == XML_PARSER_EOF) - return(0); avail = ctxt->input->end - ctxt->input->cur; }
@@ -879,8 +788,8 @@ xmlCurrentChar(xmlParserCtxtPtr ctxt, int *len) { * TODO: Null bytes should be handled by callers, * but this can be tricky. */ - xmlErrEncodingInt(ctxt, XML_ERR_INVALID_CHAR, - "Char 0x0 out of allowed range\n", c); + xmlFatalErr(ctxt, XML_ERR_INVALID_CHAR, + "Char 0x0 out of allowed range\n"); } } else { *len = 1; @@ -942,20 +851,7 @@ xmlCurrentChar(xmlParserCtxtPtr ctxt, int *len) { encoding_error: /* Only report the first error */ if ((ctxt->input->flags & XML_INPUT_ENCODING_ERROR) == 0) { - if (ctxt->input->end - ctxt->input->cur < 4) { - __xmlErrEncoding(ctxt, XML_ERR_INVALID_CHAR, - "Input is not proper UTF-8, indicate encoding !\n", - NULL, NULL); - } else { - char buffer[150]; - - snprintf(&buffer[0], 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); - } + xmlCtxtErrIO(ctxt, XML_ERR_INVALID_ENCODING, NULL); ctxt->input->flags |= XML_INPUT_ENCODING_ERROR; } *len = 1; @@ -1029,9 +925,10 @@ xmlCopyCharMultiByte(xmlChar *out, int val) { else if (val < 0x10000) { *out++= (val >> 12) | 0xE0; bits= 6;} else if (val < 0x110000) { *out++= (val >> 18) | 0xF0; bits= 12; } else { - xmlErrEncodingInt(NULL, XML_ERR_INVALID_CHAR, - "Internal error, xmlCopyCharMultiByte 0x%X out of bound\n", - val); +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + fprintf(stderr, "xmlCopyCharMultiByte: codepoint out of range\n"); + abort(); +#endif return(0); } for ( ; bits >= 0; bits-= 6) @@ -1070,24 +967,30 @@ xmlCopyChar(int len ATTRIBUTE_UNUSED, xmlChar *out, int val) { * * ************************************************************************/
-static xmlCharEncodingHandlerPtr -xmlDetectEBCDIC(xmlParserInputPtr input) { +static int +xmlDetectEBCDIC(xmlParserInputPtr input, xmlCharEncodingHandlerPtr *hout) { xmlChar out[200]; xmlCharEncodingHandlerPtr handler; int inlen, outlen, res, i;
+ *hout = NULL; + /* * To detect the EBCDIC code page, we convert the first 200 bytes * to EBCDIC-US and try to find the encoding declaration. */ - handler = xmlGetCharEncodingHandler(XML_CHAR_ENCODING_EBCDIC); - if (handler == NULL) - return(NULL); + res = xmlLookupCharEncodingHandler(XML_CHAR_ENCODING_EBCDIC, &handler); + if (res != 0) + return(res); outlen = sizeof(out) - 1; inlen = input->end - input->cur; res = xmlEncInputChunk(handler, out, &outlen, input->cur, &inlen); + /* + * Return the EBCDIC handler if decoding failed. The error will + * be reported later. + */ if (res < 0) - return(handler); + goto done; out[outlen] = 0;
for (i = 0; i < outlen; i++) { @@ -1119,15 +1022,25 @@ xmlDetectEBCDIC(xmlParserInputPtr input) { break; out[i] = 0; xmlCharEncCloseFunc(handler); - return(xmlFindCharEncodingHandler((char *) out + start)); + res = xmlOpenCharEncodingHandler((char *) out + start, + /* output */ 0, &handler); + if (res != 0) + return(res); + *hout = handler; + return(0); } }
+done: /* - * ICU handlers are stateful, so we have to recreate them. + * Encoding handlers are stateful, so we have to recreate them. */ xmlCharEncCloseFunc(handler); - return(xmlGetCharEncodingHandler(XML_CHAR_ENCODING_EBCDIC)); + res = xmlLookupCharEncodingHandler(XML_CHAR_ENCODING_EBCDIC, &handler); + if (res != 0) + return(res); + *hout = handler; + return(0); }
/** @@ -1135,10 +1048,11 @@ xmlDetectEBCDIC(xmlParserInputPtr input) { * @ctxt: the parser context * @enc: the encoding value (number) * - * Use encoding specified by enum to decode input data. + * Use encoding specified by enum to decode input data. This overrides + * the encoding found in the XML declaration. * - * This function can be used to enforce the encoding of chunks passed - * to xmlParseChunk. + * This function can also be used to override the encoding of chunks + * passed to xmlParseChunk. * * Returns 0 in case of success, -1 otherwise */ @@ -1146,8 +1060,8 @@ int xmlSwitchEncoding(xmlParserCtxtPtr ctxt, xmlCharEncoding enc) { xmlCharEncodingHandlerPtr handler = NULL; - int check = 1; int ret; + int res;
if ((ctxt == NULL) || (ctxt->input == NULL)) return(-1); @@ -1156,28 +1070,20 @@ xmlSwitchEncoding(xmlParserCtxtPtr ctxt, xmlCharEncoding enc) case XML_CHAR_ENCODING_NONE: case XML_CHAR_ENCODING_UTF8: case XML_CHAR_ENCODING_ASCII: - check = 0; + res = 0; break; case XML_CHAR_ENCODING_EBCDIC: - handler = xmlDetectEBCDIC(ctxt->input); + res = xmlDetectEBCDIC(ctxt->input, &handler); break; default: - handler = xmlGetCharEncodingHandler(enc); + res = xmlLookupCharEncodingHandler(enc, &handler); break; }
- if ((check) && (handler == NULL)) { + if (res != 0) { const char *name = xmlGetCharEncodingName(enc);
- __xmlErrEncoding(ctxt, XML_ERR_UNSUPPORTED_ENCODING, - "encoding not supported: %s\n", - BAD_CAST (name ? name : "<null>"), NULL); - /* - * TODO: We could recover from errors in external entities - * if we didn't stop the parser. But most callers of this - * function don't check the return value. - */ - xmlStopParser(ctxt); + xmlFatalErr(ctxt, res, (name ? name : "<null>")); return(-1); }
@@ -1191,8 +1097,63 @@ xmlSwitchEncoding(xmlParserCtxtPtr ctxt, xmlCharEncoding enc) }
/** - * xmlSwitchInputEncoding: + * xmlSwitchEncodingName: + * @ctxt: the parser context, only for error reporting + * @input: the input strea, + * @encoding: the encoding name + * + * Available since 2.13.0. + * + * Returns 0 in case of success, -1 otherwise + */ +static int +xmlSwitchInputEncodingName(xmlParserCtxtPtr ctxt, xmlParserInputPtr input, + const char *encoding) { + xmlCharEncodingHandlerPtr handler; + int res; + + if (encoding == NULL) + return(-1); + + res = xmlOpenCharEncodingHandler(encoding, /* output */ 0, &handler); + if (res == XML_ERR_UNSUPPORTED_ENCODING) { + xmlWarningMsg(ctxt, XML_ERR_UNSUPPORTED_ENCODING, + "Unsupported encoding: %s\n", BAD_CAST encoding, NULL); + return(-1); + } else if (res != XML_ERR_OK) { + xmlFatalErr(ctxt, res, encoding); + return(-1); + } + + return(xmlSwitchInputEncoding(ctxt, input, handler)); +} + +/** + * xmlSwitchEncodingName: * @ctxt: the parser context + * @encoding: the encoding name + * + * Use specified encoding to decode input data. This overrides the + * encoding found in the XML declaration. + * + * This function can also be used to override the encoding of chunks + * passed to xmlParseChunk. + * + * Available since 2.13.0. + * + * Returns 0 in case of success, -1 otherwise + */ +int +xmlSwitchEncodingName(xmlParserCtxtPtr ctxt, const char *encoding) { + if (ctxt == NULL) + return(-1); + + return(xmlSwitchInputEncodingName(ctxt, ctxt->input, encoding)); +} + +/** + * xmlSwitchInputEncoding: + * @ctxt: the parser context, only for error reporting * @input: the input stream * @handler: the encoding handler * @@ -1250,8 +1211,15 @@ xmlSwitchInputEncoding(xmlParserCtxtPtr ctxt, xmlParserInputPtr input, * Is there already some content down the pipe to convert ? */ if (xmlBufIsEmpty(in->buffer) == 0) { + xmlBufPtr buf; size_t processed;
+ buf = xmlBufCreate(); + if (buf == NULL) { + xmlCtxtErrMemory(ctxt); + return(-1); + } + /* * Shrink the current input buffer. * Move it as the raw buffer and create a new input buffer @@ -1260,16 +1228,15 @@ xmlSwitchInputEncoding(xmlParserCtxtPtr ctxt, xmlParserInputPtr input, xmlBufShrink(in->buffer, processed); input->consumed += processed; in->raw = in->buffer; - in->buffer = xmlBufCreate(); + in->buffer = buf; in->rawconsumed = processed;
nbchars = xmlCharEncInput(in); xmlBufResetInput(in->buffer, input); - if (nbchars < 0) { - /* TODO: This could be an out of memory or an encoding error. */ - xmlErrInternal(ctxt, - "switching encoding: encoder error\n", - NULL); + if (nbchars == XML_ENC_ERR_MEMORY) { + xmlCtxtErrMemory(ctxt); + } else if (nbchars < 0) { + xmlCtxtErrIO(ctxt, in->error, NULL); xmlHaltParser(ctxt); return (-1); } @@ -1412,23 +1379,30 @@ xmlDetectEncoding(xmlParserCtxtPtr ctxt) { */ void xmlSetDeclaredEncoding(xmlParserCtxtPtr ctxt, xmlChar *encoding) { - if (ctxt->encoding != NULL) - xmlFree((xmlChar *) ctxt->encoding); - ctxt->encoding = encoding; - if (((ctxt->input->flags & XML_INPUT_HAS_ENCODING) == 0) && ((ctxt->options & XML_PARSE_IGNORE_ENC) == 0)) { xmlCharEncodingHandlerPtr handler; + int res; + + /* + * xmlSwitchInputEncodingName treats unsupported encodings as + * warnings, but we want it to be an error in an encoding + * declaration. + */ + res = xmlOpenCharEncodingHandler((const char *) encoding, + /* output */ 0, &handler); + if (res != XML_ERR_OK) { + xmlFatalErr(ctxt, res, (const char *) encoding); + xmlFree(encoding); + return; + }
- handler = xmlFindCharEncodingHandler((const char *) encoding); - if (handler == NULL) { - __xmlErrEncoding(ctxt, XML_ERR_UNSUPPORTED_ENCODING, - "Unsupported encoding: %s\n", - encoding, NULL); + res = xmlSwitchInputEncoding(ctxt, ctxt->input, handler); + if (res != XML_ERR_OK) { + xmlFree(encoding); return; }
- xmlSwitchToEncoding(ctxt, handler); ctxt->input->flags |= XML_INPUT_USES_ENC_DECL; } else if (ctxt->input->flags & XML_INPUT_AUTO_ENCODING) { static const char *allowedUTF8[] = { @@ -1474,9 +1448,17 @@ xmlSetDeclaredEncoding(xmlParserCtxtPtr ctxt, xmlChar *encoding) { "Encoding '%s' doesn't match " "auto-detected '%s'\n", encoding, BAD_CAST autoEnc); + xmlFree(encoding); + encoding = xmlStrdup(BAD_CAST autoEnc); + if (encoding == NULL) + xmlCtxtErrMemory(ctxt); } } } + + if (ctxt->encoding != NULL) + xmlFree((xmlChar *) ctxt->encoding); + ctxt->encoding = encoding; }
/** @@ -1520,7 +1502,6 @@ xmlFreeInputStream(xmlParserInputPtr input) { if (input == NULL) return;
if (input->filename != NULL) xmlFree((char *) input->filename); - if (input->directory != NULL) xmlFree((char *) input->directory); if (input->version != NULL) xmlFree((char *) input->version); if ((input->free != NULL) && (input->base != NULL)) input->free((xmlChar *) input->base); @@ -1543,7 +1524,7 @@ xmlNewInputStream(xmlParserCtxtPtr ctxt) {
input = (xmlParserInputPtr) xmlMalloc(sizeof(xmlParserInput)); if (input == NULL) { - xmlErrMemory(ctxt, "couldn't allocate a new input stream\n"); + xmlCtxtErrMemory(ctxt); return(NULL); } memset(input, 0, sizeof(xmlParserInput)); @@ -1557,7 +1538,7 @@ xmlNewInputStream(xmlParserCtxtPtr ctxt) { */ if (ctxt != NULL) { if (input->id >= INT_MAX) { - xmlErrMemory(ctxt, "Input ID overflow\n"); + xmlCtxtErrMemory(ctxt); return(NULL); } input->id = ctxt->input_id++; @@ -1567,146 +1548,509 @@ xmlNewInputStream(xmlParserCtxtPtr ctxt) { }
/** - * xmlNewIOInputStream: - * @ctxt: an XML parser context - * @input: an I/O Input - * @enc: the charset encoding if known + * xmlNewInputURL: + * @ctxt: parser context + * @url: filename or URL + * @publicId: publid ID from doctype (optional) + * @encoding: character encoding (optional) + * @flags: unused, pass 0 * - * Create a new input stream structure encapsulating the @input into - * a stream suitable for the parser. + * Creates a new parser input from the filesystem, the network or + * a user-defined resource loader. * - * Returns the new input stream or NULL + * Returns a new parser input. */ xmlParserInputPtr -xmlNewIOInputStream(xmlParserCtxtPtr ctxt, xmlParserInputBufferPtr input, - xmlCharEncoding enc) { - xmlParserInputPtr inputStream; +xmlNewInputURL(xmlParserCtxtPtr ctxt, const char *url, const char *publicId, + const char *encoding, int flags ATTRIBUTE_UNUSED) { + xmlParserInputPtr input;
- if (input == NULL) return(NULL); - if (xmlParserDebugEntities) - xmlGenericError(xmlGenericErrorContext, "new input from I/O\n"); - inputStream = xmlNewInputStream(ctxt); - if (inputStream == NULL) { + if ((ctxt == NULL) || (url == NULL)) return(NULL); - } - inputStream->filename = NULL; - inputStream->buf = input; - xmlBufResetInput(inputStream->buf->buffer, inputStream);
- if (enc != XML_CHAR_ENCODING_NONE) { - xmlSwitchEncoding(ctxt, enc); - } + input = xmlLoadExternalEntity(url, publicId, ctxt); + if (input == NULL) + return(NULL);
- return(inputStream); + if (encoding != NULL) + xmlSwitchInputEncodingName(ctxt, input, encoding); + + return(input); }
/** - * xmlNewEntityInputStream: - * @ctxt: an XML parser context - * @entity: an Entity pointer - * - * DEPRECATED: Internal function, do not use. + * xmlNewInputInternal: + * @ctxt: parser context + * @buf: parser input buffer + * @filename: filename or URL + * @encoding: character encoding (optional) * - * Create a new input stream based on an xmlEntityPtr + * Internal helper function. * - * Returns the new input stream or NULL + * Returns a new parser input. */ -xmlParserInputPtr -xmlNewEntityInputStream(xmlParserCtxtPtr ctxt, xmlEntityPtr entity) { +static xmlParserInputPtr +xmlNewInputInternal(xmlParserCtxtPtr ctxt, xmlParserInputBufferPtr buf, + const char *filename, const char *encoding) { xmlParserInputPtr input;
- if (entity == NULL) { - xmlErrInternal(ctxt, "xmlNewEntityInputStream entity = NULL\n", - NULL); + input = xmlNewInputStream(ctxt); + if (input == NULL) { + xmlFreeParserInputBuffer(buf); return(NULL); } - if (xmlParserDebugEntities) - xmlGenericError(xmlGenericErrorContext, - "new input from entity: %s\n", entity->name); - if (entity->content == NULL) { - switch (entity->etype) { - case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY: - xmlErrInternal(ctxt, "Cannot parse entity %s\n", - entity->name); - break; - case XML_EXTERNAL_GENERAL_PARSED_ENTITY: - case XML_EXTERNAL_PARAMETER_ENTITY: - input = xmlLoadExternalEntity((char *) entity->URI, - (char *) entity->ExternalID, ctxt); - if (input != NULL) - input->entity = entity; - return(input); - case XML_INTERNAL_GENERAL_ENTITY: - xmlErrInternal(ctxt, - "Internal entity %s without content !\n", - entity->name); - break; - case XML_INTERNAL_PARAMETER_ENTITY: - xmlErrInternal(ctxt, - "Internal parameter entity %s without content !\n", - entity->name); - break; - case XML_INTERNAL_PREDEFINED_ENTITY: - xmlErrInternal(ctxt, - "Predefined entity %s without content !\n", - entity->name); - break; - } + + input->buf = buf; + xmlBufResetInput(input->buf->buffer, input); + + if (filename != NULL) { + input->filename = xmlMemStrdup(filename); + if (input->filename == NULL) { + xmlCtxtErrMemory(ctxt); + xmlFreeInputStream(input); + return(NULL); + } + } + + if (encoding != NULL) + xmlSwitchInputEncodingName(ctxt, input, encoding); + + return(input); +} + +/** + * xmlNewInputMemory: + * @ctxt: parser context + * @url: base URL (optional) + * @mem: pointer to char array + * @size: size of array + * @encoding: character encoding (optional) + * @flags: optimization hints + * + * Creates a new parser input to read from a memory area. + * + * @url is used as base to resolve external entities and for + * error reporting. + * + * If the XML_INPUT_BUF_STATIC flag is set, the memory area must + * stay unchanged until parsing has finished. This can avoid + * temporary copies. + * + * If the XML_INPUT_BUF_ZERO_TERMINATED flag is set, the memory + * area must contain a zero byte after the buffer at position @size. + * This can avoid temporary copies. + * + * Returns a new parser input. + */ +xmlParserInputPtr +xmlNewInputMemory(xmlParserCtxtPtr ctxt, const char *url, + const void *mem, size_t size, + const char *encoding, int flags) { + xmlParserInputBufferPtr buf; + + if ((ctxt == NULL) || (mem == NULL)) return(NULL); + + buf = xmlNewInputBufferMemory(mem, size, flags, XML_CHAR_ENCODING_NONE); + if (buf == NULL) { + xmlCtxtErrMemory(ctxt); + return(NULL); } - input = xmlNewInputStream(ctxt); - if (input == NULL) { + + return(xmlNewInputInternal(ctxt, buf, url, encoding)); +} + +/** + * xmlNewInputString: + * @ctxt: parser context + * @url: base URL (optional) + * @str: zero-terminated string + * @encoding: character encoding (optional) + * @flags: optimization hints + * + * Creates a new parser input to read from a zero-terminated string. + * + * @url is used as base to resolve external entities and for + * error reporting. + * + * If the XML_INPUT_BUF_STATIC flag is set, the string must + * stay unchanged until parsing has finished. This can avoid + * temporary copies. + * + * Returns a new parser input. + */ +xmlParserInputPtr +xmlNewInputString(xmlParserCtxtPtr ctxt, const char *url, + const char *str, const char *encoding, int flags) { + xmlParserInputBufferPtr buf; + + if ((ctxt == NULL) || (str == NULL)) return(NULL); + + buf = xmlNewInputBufferString(str, flags); + if (buf == NULL) { + xmlCtxtErrMemory(ctxt); + return(NULL); } - if (entity->URI != NULL) - input->filename = (char *) xmlStrdup((xmlChar *) entity->URI); - input->base = entity->content; - if (entity->length == 0) - entity->length = xmlStrlen(entity->content); - input->cur = entity->content; - input->length = entity->length; - input->end = &entity->content[input->length]; - input->entity = entity; - return(input); + + return(xmlNewInputInternal(ctxt, buf, url, encoding)); }
/** - * xmlNewStringInputStream: - * @ctxt: an XML parser context - * @buffer: an memory buffer + * xmlNewInputFd: + * @ctxt: parser context + * @url: base URL (optional) + * @fd: file descriptor + * @encoding: character encoding (optional) + * @flags: unused, pass 0 * - * Create a new input stream based on a memory buffer. - * Returns the new input stream + * Creates a new parser input to read from a zero-terminated string. + * + * @url is used as base to resolve external entities and for + * error reporting. + * + * @fd is closed after parsing has finished. + * + * Returns a new parser input. */ xmlParserInputPtr -xmlNewStringInputStream(xmlParserCtxtPtr ctxt, const xmlChar *buffer) { - xmlParserInputPtr input; +xmlNewInputFd(xmlParserCtxtPtr ctxt, const char *url, + int fd, const char *encoding, int flags) { + xmlParserInputBufferPtr buf; + + if ((ctxt == NULL) || (fd < 0)) + return(NULL); + + buf = xmlAllocParserInputBuffer(XML_CHAR_ENCODING_NONE); + if (buf == NULL) { + xmlCtxtErrMemory(ctxt); + return(NULL); + } + + if (xmlInputFromFd(buf, fd, (flags & XML_INPUT_UNZIP) != 0) < 0) { + xmlFreeParserInputBuffer(buf); + return(NULL); + } + + return(xmlNewInputInternal(ctxt, buf, url, encoding)); +} + +/** + * xmlNewInputIO: + * @ctxt: parser context + * @url: base URL (optional) + * @ioRead: read callback + * @ioClose: close callback (optional) + * @ioCtxt: IO context + * @encoding: character encoding (optional) + * @flags: unused, pass 0 + * + * Creates a new parser input to read from input callbacks and + * cintext. + * + * @url is used as base to resolve external entities and for + * error reporting. + * + * @ioRead is called to read new data into a provided buffer. + * It must return the number of bytes written into the buffer + * ot a negative xmlParserErrors code on failure. + * + * @ioClose is called after parsing has finished. + * + * @ioCtxt is an opaque pointer passed to the callbacks. + * + * Returns a new parser input. + */ +xmlParserInputPtr +xmlNewInputIO(xmlParserCtxtPtr ctxt, const char *url, + xmlInputReadCallback ioRead, xmlInputCloseCallback ioClose, + void *ioCtxt, + const char *encoding, int flags ATTRIBUTE_UNUSED) { xmlParserInputBufferPtr buf;
- if (buffer == NULL) { - xmlErrInternal(ctxt, "xmlNewStringInputStream string = NULL\n", - NULL); + if ((ctxt == NULL) || (ioRead == NULL)) return(NULL); + + buf = xmlAllocParserInputBuffer(XML_CHAR_ENCODING_NONE); + if (buf == NULL) { + xmlCtxtErrMemory(ctxt); + if (ioClose != NULL) + ioClose(ioCtxt); + return(NULL); } - if (xmlParserDebugEntities) - xmlGenericError(xmlGenericErrorContext, - "new fixed input: %.30s\n", buffer); - buf = xmlParserInputBufferCreateString(buffer); + + buf->context = ioCtxt; + buf->readcallback = ioRead; + buf->closecallback = ioClose; + + return(xmlNewInputInternal(ctxt, buf, url, encoding)); +} + +/** + * xmlNewInputPush: + * @ctxt: parser context + * @url: base URL (optional) + * @chunk: pointer to char array + * @size: size of array + * @encoding: character encoding (optional) + * + * Creates a new parser input for a push parser. + * + * Returns a new parser input. + */ +xmlParserInputPtr +xmlNewInputPush(xmlParserCtxtPtr ctxt, const char *url, + const char *chunk, int size, const char *encoding) { + xmlParserInputBufferPtr buf; + xmlParserInputPtr input; + + buf = xmlAllocParserInputBuffer(XML_CHAR_ENCODING_NONE); if (buf == NULL) { - xmlErrMemory(ctxt, NULL); + xmlCtxtErrMemory(ctxt); return(NULL); } - input = xmlNewInputStream(ctxt); - if (input == NULL) { - xmlErrMemory(ctxt, "couldn't allocate a new input stream\n"); - xmlFreeParserInputBuffer(buf); + + input = xmlNewInputInternal(ctxt, buf, url, encoding); + if (input == NULL) return(NULL); + + input->flags |= XML_INPUT_PROGRESSIVE; + + if ((size > 0) && (chunk != NULL)) { + int res; + + res = xmlParserInputBufferPush(input->buf, size, chunk); + xmlBufResetInput(input->buf->buffer, input); + if (res < 0) { + xmlCtxtErrIO(ctxt, input->buf->error, NULL); + xmlFreeInputStream(input); + return(NULL); + } } - input->buf = buf; - xmlBufResetInput(input->buf->buffer, input); + + return(input); +} + +/** + * xmlNewIOInputStream: + * @ctxt: an XML parser context + * @buf: an input buffer + * @enc: the charset encoding if known + * + * Create a new input stream structure encapsulating the @input into + * a stream suitable for the parser. + * + * Returns the new input stream or NULL + */ +xmlParserInputPtr +xmlNewIOInputStream(xmlParserCtxtPtr ctxt, xmlParserInputBufferPtr buf, + xmlCharEncoding enc) { + const char *encoding; + + if (buf == NULL) + return(NULL); + + encoding = xmlGetCharEncodingName(enc); + return(xmlNewInputInternal(ctxt, buf, NULL, encoding)); +} + +/** + * xmlNewEntityInputStream: + * @ctxt: an XML parser context + * @ent: an Entity pointer + * + * DEPRECATED: Internal function, do not use. + * + * Create a new input stream based on an xmlEntityPtr + * + * Returns the new input stream or NULL + */ +xmlParserInputPtr +xmlNewEntityInputStream(xmlParserCtxtPtr ctxt, xmlEntityPtr ent) { + xmlParserInputPtr input; + + if ((ctxt == NULL) || (ent == NULL)) + return(NULL); + + if (ent->content != NULL) { + input = xmlNewInputString(ctxt, NULL, (const char *) ent->content, + NULL, XML_INPUT_BUF_STATIC); + } else if (ent->URI != NULL) { + input = xmlLoadExternalEntity((char *) ent->URI, + (char *) ent->ExternalID, ctxt); + } else { + return(NULL); + } + + if (input == NULL) + return(NULL); + + input->entity = ent; + return(input); }
+/** + * xmlNewStringInputStream: + * @ctxt: an XML parser context + * @buffer: an memory buffer + * + * Create a new input stream based on a memory buffer. + * + * Returns the new input stream + */ +xmlParserInputPtr +xmlNewStringInputStream(xmlParserCtxtPtr ctxt, const xmlChar *buffer) { + return(xmlNewInputString(ctxt, NULL, (const char *) buffer, NULL, 0)); +} + + +/**************************************************************** + * * + * External entities loading * + * * + ****************************************************************/ + +#ifdef LIBXML_CATALOG_ENABLED + +/** + * xmlResolveResourceFromCatalog: + * @URL: the URL for the entity to load + * @ID: the System ID for the entity to load + * @ctxt: the context in which the entity is called or NULL + * + * Resolves the URL and ID against the appropriate catalog. + * This function is used by xmlDefaultExternalEntityLoader and + * xmlNoNetExternalEntityLoader. + * + * Returns a new allocated URL, or NULL. + */ +static xmlChar * +xmlResolveResourceFromCatalog(const char *URL, const char *ID, + xmlParserCtxtPtr ctxt) { + xmlChar *resource = NULL; + xmlCatalogAllow pref; + + /* + * If the resource doesn't exists as a file, + * try to load it from the resource pointed in the catalogs + */ + pref = xmlCatalogGetDefaults(); + + if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) { + /* + * Do a local lookup + */ + if ((ctxt != NULL) && (ctxt->catalogs != NULL) && + ((pref == XML_CATA_ALLOW_ALL) || + (pref == XML_CATA_ALLOW_DOCUMENT))) { + resource = xmlCatalogLocalResolve(ctxt->catalogs, + (const xmlChar *)ID, + (const xmlChar *)URL); + } + /* + * Try a global lookup + */ + if ((resource == NULL) && + ((pref == XML_CATA_ALLOW_ALL) || + (pref == XML_CATA_ALLOW_GLOBAL))) { + resource = xmlCatalogResolve((const xmlChar *)ID, + (const xmlChar *)URL); + } + if ((resource == NULL) && (URL != NULL)) + resource = xmlStrdup((const xmlChar *) URL); + + /* + * TODO: do an URI lookup on the reference + */ + if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) { + xmlChar *tmp = NULL; + + if ((ctxt != NULL) && (ctxt->catalogs != NULL) && + ((pref == XML_CATA_ALLOW_ALL) || + (pref == XML_CATA_ALLOW_DOCUMENT))) { + tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource); + } + if ((tmp == NULL) && + ((pref == XML_CATA_ALLOW_ALL) || + (pref == XML_CATA_ALLOW_GLOBAL))) { + tmp = xmlCatalogResolveURI(resource); + } + + if (tmp != NULL) { + xmlFree(resource); + resource = tmp; + } + } + } + + return resource; +} + +#endif + +/** + * xmlCheckHTTPInput: + * @ctxt: an XML parser context + * @ret: an XML parser input + * + * DEPRECATED: Internal function, don't use. + * + * Check an input in case it was created from an HTTP stream, in that + * case it will handle encoding and update of the base URL in case of + * redirection. It also checks for HTTP errors in which case the input + * is cleanly freed up and an appropriate error is raised in context + * + * Returns the input or NULL in case of HTTP error. + */ +xmlParserInputPtr +xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) { + /* Avoid unused variable warning if features are disabled. */ + (void) ctxt; + +#ifdef LIBXML_HTTP_ENABLED + if ((ret != NULL) && (ret->buf != NULL) && + (ret->buf->readcallback == xmlIOHTTPRead) && + (ret->buf->context != NULL)) { + const char *encoding; + const char *redir; + const char *mime; + int code; + + code = xmlNanoHTTPReturnCode(ret->buf->context); + if (code >= 400) { + /* fatal error */ + if (ret->filename != NULL) + xmlCtxtErrIO(ctxt, XML_IO_LOAD_ERROR, ret->filename); + else + xmlCtxtErrIO(ctxt, XML_IO_LOAD_ERROR, "<null>"); + xmlFreeInputStream(ret); + ret = NULL; + } else { + + mime = xmlNanoHTTPMimeType(ret->buf->context); + if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) || + (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) { + encoding = xmlNanoHTTPEncoding(ret->buf->context); + if (encoding != NULL) + xmlSwitchEncodingName(ctxt, encoding); +#if 0 + } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) { +#endif + } + redir = xmlNanoHTTPRedir(ret->buf->context); + if (redir != NULL) { + if (ret->filename != NULL) + xmlFree((xmlChar *) ret->filename); + ret->filename = + (char *) xmlStrdup((const xmlChar *) redir); + } + } + } +#endif + return(ret); +} + /** * xmlNewInputFromFile: * @ctxt: an XML parser context @@ -1720,22 +2064,17 @@ xmlParserInputPtr xmlNewInputFromFile(xmlParserCtxtPtr ctxt, const char *filename) { xmlParserInputBufferPtr buf; xmlParserInputPtr inputStream; - char *directory = NULL; - xmlChar *URI = NULL; - - if (xmlParserDebugEntities) - xmlGenericError(xmlGenericErrorContext, - "new input from file: %s\n", filename); - if (ctxt == NULL) return(NULL); - buf = xmlParserInputBufferCreateFilename(filename, XML_CHAR_ENCODING_NONE); + const xmlChar *URI; + xmlChar *canonic; + int code; + + if ((ctxt == NULL) || (filename == NULL)) + return(NULL); + + code = xmlParserInputBufferCreateFilenameSafe(filename, + XML_CHAR_ENCODING_NONE, &buf); if (buf == NULL) { - if (filename == NULL) - __xmlLoaderErr(ctxt, - "failed to load external entity: NULL filename \n", - NULL); - else - __xmlLoaderErr(ctxt, "failed to load external entity "%s"\n", - (const char *) filename); + xmlCtxtErrIO(ctxt, code, filename); return(NULL); }
@@ -1751,21 +2090,189 @@ xmlNewInputFromFile(xmlParserCtxtPtr ctxt, const char *filename) { return(NULL);
if (inputStream->filename == NULL) - URI = xmlStrdup((xmlChar *) filename); + URI = (xmlChar *) filename; else - URI = xmlStrdup((xmlChar *) inputStream->filename); - directory = xmlParserGetDirectory((const char *) URI); - if (inputStream->filename != NULL) xmlFree((char *)inputStream->filename); - inputStream->filename = (char *) xmlCanonicPath((const xmlChar *) URI); - if (URI != NULL) xmlFree((char *) URI); - inputStream->directory = directory; + URI = (xmlChar *) inputStream->filename; + canonic = xmlCanonicPath(URI); + if (canonic == NULL) { + xmlCtxtErrMemory(ctxt); + xmlFreeInputStream(inputStream); + return(NULL); + } + if (inputStream->filename != NULL) + xmlFree((char *) inputStream->filename); + inputStream->filename = (char *) canonic;
xmlBufResetInput(inputStream->buf->buffer, inputStream); - if ((ctxt->directory == NULL) && (directory != NULL)) - ctxt->directory = (char *) xmlStrdup((const xmlChar *) directory); + return(inputStream); }
+/** + * xmlDefaultExternalEntityLoader: + * @URL: the URL for the entity to load + * @ID: the System ID for the entity to load + * @ctxt: the context in which the entity is called or NULL + * + * By default we don't load external entities, yet. + * + * Returns a new allocated xmlParserInputPtr, or NULL. + */ +static xmlParserInputPtr +xmlDefaultExternalEntityLoader(const char *URL, const char *ID, + xmlParserCtxtPtr ctxt) +{ + xmlParserInputPtr ret = NULL; + xmlChar *resource = NULL; + + if (URL == NULL) + return(NULL); + + if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) { + int options = ctxt->options; + + ctxt->options -= XML_PARSE_NONET; + ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt); + ctxt->options = options; + return(ret); + } +#ifdef LIBXML_CATALOG_ENABLED + resource = xmlResolveResourceFromCatalog(URL, ID, ctxt); +#endif + + if (resource == NULL) + resource = (xmlChar *) URL; + + ret = xmlNewInputFromFile(ctxt, (const char *) resource); + if ((resource != NULL) && (resource != (xmlChar *) URL)) + xmlFree(resource); + return (ret); +} + +/** + * xmlNoNetExternalEntityLoader: + * @URL: the URL for the entity to load + * @ID: the System ID for the entity to load + * @ctxt: the context in which the entity is called or NULL + * + * A specific entity loader disabling network accesses, though still + * allowing local catalog accesses for resolution. + * + * Returns a new allocated xmlParserInputPtr, or NULL. + */ +xmlParserInputPtr +xmlNoNetExternalEntityLoader(const char *URL, const char *ID, + xmlParserCtxtPtr ctxt) { + xmlParserInputPtr input = NULL; + xmlChar *resource = NULL; + +#ifdef LIBXML_CATALOG_ENABLED + resource = xmlResolveResourceFromCatalog(URL, ID, ctxt); +#endif + + if (resource == NULL) + resource = (xmlChar *) URL; + + if (resource != NULL) { + if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) || + (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) { + xmlCtxtErrIO(ctxt, XML_IO_NETWORK_ATTEMPT, + (const char *) resource); + /* + * Also forward the error directly to the global error + * handler, which the XML::LibXML test suite expects. + */ + __xmlIOErr(XML_FROM_IO, XML_IO_NETWORK_ATTEMPT, + (const char *) resource); + if (resource != (xmlChar *) URL) + xmlFree(resource); + return(NULL); + } + } + input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt); + if (resource != (xmlChar *) URL) + xmlFree(resource); + return(input); +} + +/* + * This global has to die eventually + */ +static xmlExternalEntityLoader +xmlCurrentExternalEntityLoader = xmlDefaultExternalEntityLoader; + +/** + * xmlSetExternalEntityLoader: + * @f: the new entity resolver function + * + * Changes the defaultexternal entity resolver function for the application + */ +void +xmlSetExternalEntityLoader(xmlExternalEntityLoader f) { + xmlCurrentExternalEntityLoader = f; +} + +/** + * xmlGetExternalEntityLoader: + * + * Get the default external entity resolver function for the application + * + * Returns the xmlExternalEntityLoader function pointer + */ +xmlExternalEntityLoader +xmlGetExternalEntityLoader(void) { + return(xmlCurrentExternalEntityLoader); +} + +/** + * xmlLoadExternalEntity: + * @URL: the URL for the entity to load + * @ID: the Public ID for the entity to load + * @ctxt: the context in which the entity is called or NULL + * + * @URL is a filename or URL. If if contains the substring "://", + * it is assumed to be a Legacy Extended IRI. Otherwise, it is + * treated as a filesystem path. + * + * @ID is an optional XML public ID, typically from a doctype + * declaration. It is used for catalog lookups. + * + * The following resource loaders will be called if they were + * registered (in order of precedence): + * + * - the global external entity loader set with + * xmlSetExternalEntityLoader + * - the per-thread xmlParserInputBufferCreateFilenameFunc set with + * xmlParserInputBufferCreateFilenameDefault + * - the default loader which will return + * - the result from a matching global input callback set with + * xmlRegisterInputCallbacks + * - a HTTP resource if support is compiled in. + * - a file opened from the filesystem, with automatic detection + * of compressed files if support is compiled in. + * + * Returns the xmlParserInputPtr or NULL + */ +xmlParserInputPtr +xmlLoadExternalEntity(const char *URL, const char *ID, + xmlParserCtxtPtr ctxt) { + char *canonicFilename; + xmlParserInputPtr ret; + + if (URL == NULL) + return(NULL); + + canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL); + if (canonicFilename == NULL) { + xmlCtxtErrMemory(ctxt); + return(NULL); + } + + ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt); + xmlFree(canonicFilename); + return(ret); +} + /************************************************************************ * * * Commodity functions to handle parser contexts * @@ -1789,27 +2296,19 @@ xmlInitSAXParserCtxt(xmlParserCtxtPtr ctxt, const xmlSAXHandler *sax, { xmlParserInputPtr input;
- if(ctxt==NULL) { - xmlErrInternal(NULL, "Got NULL parser context\n", NULL); + if (ctxt == NULL) return(-1); - } - - xmlInitParser();
if (ctxt->dict == NULL) ctxt->dict = xmlDictCreate(); - if (ctxt->dict == NULL) { - xmlErrMemory(NULL, "cannot initialize parser context\n"); + if (ctxt->dict == NULL) return(-1); - } xmlDictSetLimit(ctxt->dict, XML_MAX_DICTIONARY_LIMIT);
if (ctxt->sax == NULL) ctxt->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler)); - if (ctxt->sax == NULL) { - xmlErrMemory(NULL, "cannot initialize parser context\n"); + if (ctxt->sax == NULL) return(-1); - } if (sax == NULL) { memset(ctxt->sax, 0, sizeof(xmlSAXHandler)); xmlSAXVersion(ctxt->sax, 2); @@ -1832,13 +2331,8 @@ xmlInitSAXParserCtxt(xmlParserCtxtPtr ctxt, const xmlSAXHandler *sax, xmlMalloc(5 * sizeof(xmlParserInputPtr)); ctxt->inputMax = 5; } - if (ctxt->inputTab == NULL) { - xmlErrMemory(NULL, "cannot initialize parser context\n"); - ctxt->inputNr = 0; - ctxt->inputMax = 0; - ctxt->input = NULL; + if (ctxt->inputTab == NULL) return(-1); - } while ((input = inputPop(ctxt)) != NULL) { /* Non consuming */ xmlFreeInputStream(input); } @@ -1851,26 +2345,15 @@ xmlInitSAXParserCtxt(xmlParserCtxtPtr ctxt, const xmlSAXHandler *sax, ctxt->hasExternalSubset = 0; ctxt->hasPErefs = 0; ctxt->html = 0; - ctxt->external = 0; ctxt->instate = XML_PARSER_START; - ctxt->token = 0; - ctxt->directory = NULL;
/* Allocate the Node stack */ if (ctxt->nodeTab == NULL) { ctxt->nodeTab = (xmlNodePtr *) xmlMalloc(10 * sizeof(xmlNodePtr)); ctxt->nodeMax = 10; } - if (ctxt->nodeTab == NULL) { - xmlErrMemory(NULL, "cannot initialize parser context\n"); - ctxt->nodeNr = 0; - ctxt->nodeMax = 0; - ctxt->node = NULL; - ctxt->inputNr = 0; - ctxt->inputMax = 0; - ctxt->input = NULL; + if (ctxt->nodeTab == NULL) return(-1); - } ctxt->nodeNr = 0; ctxt->node = NULL;
@@ -1879,19 +2362,8 @@ xmlInitSAXParserCtxt(xmlParserCtxtPtr ctxt, const xmlSAXHandler *sax, ctxt->nameTab = (const xmlChar **) xmlMalloc(10 * sizeof(xmlChar *)); ctxt->nameMax = 10; } - if (ctxt->nameTab == NULL) { - xmlErrMemory(NULL, "cannot initialize parser context\n"); - ctxt->nodeNr = 0; - ctxt->nodeMax = 0; - ctxt->node = NULL; - ctxt->inputNr = 0; - ctxt->inputMax = 0; - ctxt->input = NULL; - ctxt->nameNr = 0; - ctxt->nameMax = 0; - ctxt->name = NULL; + if (ctxt->nameTab == NULL) return(-1); - } ctxt->nameNr = 0; ctxt->name = NULL;
@@ -1900,22 +2372,8 @@ xmlInitSAXParserCtxt(xmlParserCtxtPtr ctxt, const xmlSAXHandler *sax, ctxt->spaceTab = (int *) xmlMalloc(10 * sizeof(int)); ctxt->spaceMax = 10; } - if (ctxt->spaceTab == NULL) { - xmlErrMemory(NULL, "cannot initialize parser context\n"); - ctxt->nodeNr = 0; - ctxt->nodeMax = 0; - ctxt->node = NULL; - ctxt->inputNr = 0; - ctxt->inputMax = 0; - ctxt->input = NULL; - ctxt->nameNr = 0; - ctxt->nameMax = 0; - ctxt->name = NULL; - ctxt->spaceNr = 0; - ctxt->spaceMax = 0; - ctxt->space = NULL; + if (ctxt->spaceTab == NULL) return(-1); - } ctxt->spaceNr = 1; ctxt->spaceMax = 10; ctxt->spaceTab[0] = -1; @@ -1924,11 +2382,23 @@ xmlInitSAXParserCtxt(xmlParserCtxtPtr ctxt, const xmlSAXHandler *sax, ctxt->wellFormed = 1; ctxt->nsWellFormed = 1; ctxt->valid = 1; + + ctxt->options = XML_PARSE_NODICT; + + /* + * Initialize some parser options from deprecated global variables. + * Note that the "modern" API taking options arguments or + * xmlCtxtSetOptions will ignore these defaults. They're only + * relevant if old API functions like xmlParseFile are used. + */ ctxt->loadsubset = xmlLoadExtDtdDefaultValue; if (ctxt->loadsubset) { ctxt->options |= XML_PARSE_DTDLOAD; } ctxt->validate = xmlDoValidityCheckingDefaultValue; + if (ctxt->validate) { + ctxt->options |= XML_PARSE_DTDVALID; + } ctxt->pedantic = xmlPedanticParserDefaultValue; if (ctxt->pedantic) { ctxt->options |= XML_PARSE_PEDANTIC; @@ -1939,23 +2409,18 @@ xmlInitSAXParserCtxt(xmlParserCtxtPtr ctxt, const xmlSAXHandler *sax, ctxt->sax->ignorableWhitespace = xmlSAX2IgnorableWhitespace; ctxt->options |= XML_PARSE_NOBLANKS; } + ctxt->replaceEntities = xmlSubstituteEntitiesDefaultValue; + if (ctxt->replaceEntities) { + ctxt->options |= XML_PARSE_NOENT; + } + if (xmlGetWarningsDefaultValue == 0) + ctxt->options |= XML_PARSE_NOWARNING;
ctxt->vctxt.flags = XML_VCTXT_USE_PCTXT; ctxt->vctxt.userData = ctxt; ctxt->vctxt.error = xmlParserValidityError; ctxt->vctxt.warning = xmlParserValidityWarning; - if (ctxt->validate) { - if (xmlGetWarningsDefaultValue == 0) - ctxt->vctxt.warning = NULL; - else - ctxt->vctxt.warning = xmlParserValidityWarning; - ctxt->vctxt.nodeMax = 0; - ctxt->options |= XML_PARSE_DTDVALID; - } - ctxt->replaceEntities = xmlSubstituteEntitiesDefaultValue; - if (ctxt->replaceEntities) { - ctxt->options |= XML_PARSE_NOENT; - } + ctxt->record_info = 0; ctxt->checkIndex = 0; ctxt->inSubset = 0; @@ -1971,7 +2436,7 @@ xmlInitSAXParserCtxt(xmlParserCtxtPtr ctxt, const xmlSAXHandler *sax, if (ctxt->nsdb == NULL) { ctxt->nsdb = xmlParserNsCreate(); if (ctxt->nsdb == NULL) { - xmlErrMemory(ctxt, NULL); + xmlCtxtErrMemory(ctxt); return(-1); } } @@ -2031,7 +2496,7 @@ xmlFreeParserCtxt(xmlParserCtxtPtr ctxt) if (ctxt->sax != NULL) #endif /* LIBXML_SAX1_ENABLED */ xmlFree(ctxt->sax); - if (ctxt->directory != NULL) xmlFree((char *) ctxt->directory); + if (ctxt->directory != NULL) xmlFree(ctxt->directory); if (ctxt->vctxt.nodeTab != NULL) xmlFree(ctxt->vctxt.nodeTab); if (ctxt->atts != NULL) xmlFree((xmlChar * *)ctxt->atts); if (ctxt->dict != NULL) xmlDictFree(ctxt->dict); @@ -2107,6 +2572,10 @@ xmlNewParserCtxt(void) * Allocate and initialize a new SAX parser context. If userData is NULL, * the parser context will be passed as user data. * + * Available since 2.11.0. If you want support older versions, + * it's best to invoke xmlNewParserCtxt and set ctxt->sax with + * struct assignment. + * * Returns the xmlParserCtxtPtr or NULL if memory allocation failed. */
@@ -2115,11 +2584,11 @@ xmlNewSAXParserCtxt(const xmlSAXHandler *sax, void *userData) { xmlParserCtxtPtr ctxt;
+ xmlInitParser(); + ctxt = (xmlParserCtxtPtr) xmlMalloc(sizeof(xmlParserCtxt)); - if (ctxt == NULL) { - xmlErrMemory(NULL, "cannot allocate parser context\n"); + if (ctxt == NULL) return(NULL); - } memset(ctxt, 0, sizeof(xmlParserCtxt)); if (xmlInitSAXParserCtxt(ctxt, sax, userData) < 0) { xmlFreeParserCtxt(ctxt); @@ -2163,7 +2632,7 @@ xmlClearParserCtxt(xmlParserCtxtPtr ctxt) * Returns an xmlParserNodeInfo block pointer or NULL */ const xmlParserNodeInfo * -xmlParserFindNodeInfo(const xmlParserCtxtPtr ctx, const xmlNodePtr node) +xmlParserFindNodeInfo(xmlParserCtxtPtr ctx, xmlNodePtr node) { unsigned long pos;
@@ -2229,8 +2698,8 @@ xmlClearNodeInfoSeq(xmlParserNodeInfoSeqPtr seq) * Returns a long indicating the position of the record */ unsigned long -xmlParserFindNodeInfoIndex(const xmlParserNodeInfoSeqPtr seq, - const xmlNodePtr node) +xmlParserFindNodeInfoIndex(xmlParserNodeInfoSeqPtr seq, + xmlNodePtr node) { unsigned long upper, lower, middle; int found = 0; @@ -2271,7 +2740,7 @@ xmlParserFindNodeInfoIndex(const xmlParserNodeInfoSeqPtr seq, */ void xmlParserAddNodeInfo(xmlParserCtxtPtr ctxt, - const xmlParserNodeInfoPtr info) + xmlParserNodeInfoPtr info) { unsigned long pos;
@@ -2307,7 +2776,7 @@ xmlParserAddNodeInfo(xmlParserCtxtPtr ctxt, byte_size);
if (tmp_buffer == NULL) { - xmlErrMemory(ctxt, "failed to allocate buffer\n"); + xmlCtxtErrMemory(ctxt); return; } ctxt->node_seq.buffer = tmp_buffer; diff --git a/libs/xml2/pattern.c b/libs/xml2/pattern.c index b0f7f160141..e2ec22909e5 100644 --- a/libs/xml2/pattern.c +++ b/libs/xml2/pattern.c @@ -344,9 +344,8 @@ xmlFreePatParserContext(xmlPatParserContextPtr ctxt) { * Returns -1 in case of failure, 0 otherwise. */ static int -xmlPatternAdd(xmlPatParserContextPtr ctxt ATTRIBUTE_UNUSED, - xmlPatternPtr comp, - xmlPatOp op, xmlChar * value, xmlChar * value2) +xmlPatternAdd(xmlPatParserContextPtr ctxt, xmlPatternPtr comp, + xmlPatOp op, xmlChar * value, xmlChar * value2) { if (comp->nbStep >= comp->maxStep) { xmlStepOpPtr temp; @@ -355,6 +354,7 @@ xmlPatternAdd(xmlPatParserContextPtr ctxt ATTRIBUTE_UNUSED, if (temp == NULL) { ERROR(ctxt, NULL, NULL, "xmlPatternAdd: realloc failed\n"); + ctxt->error = -1; return (-1); } comp->steps = temp; @@ -697,10 +697,6 @@ rollback: * * ************************************************************************/
-#define TODO \ - xmlGenericError(xmlGenericErrorContext, \ - "Unimplemented block at %s:%d\n", \ - __FILE__, __LINE__); #define CUR (*ctxt->cur) #define SKIP(val) ctxt->cur += (val) #define NXT(val) ctxt->cur[(val)] @@ -717,14 +713,6 @@ rollback: #define PUSH(op, val, val2) \ if (xmlPatternAdd(ctxt, ctxt->comp, (op), (val), (val2))) goto error;
-#define XSLT_ERROR(X) \ - { xsltError(ctxt, __FILE__, __LINE__, X); \ - ctxt->error = (X); return; } - -#define XSLT_ERROR0(X) \ - { xsltError(ctxt, __FILE__, __LINE__, X); \ - ctxt->error = (X); return(0); } - #if 0 /** * xmlPatScanLiteral: @@ -869,6 +857,8 @@ xmlPatScanNCName(xmlPatParserContextPtr ctxt) { ret = (xmlChar *) xmlDictLookup(ctxt->dict, q, cur - q); else ret = xmlStrndup(q, cur - q); + if (ret == NULL) + ctxt->error = -1; CUR_PTR = cur; return(ret); } @@ -913,6 +903,8 @@ xmlCompileAttributeTest(xmlPatParserContextPtr ctxt) {
SKIP_BLANKS; name = xmlPatScanNCName(ctxt); + if (ctxt->error < 0) + return; if (name == NULL) { if (CUR == '*') { PUSH(XML_OP_ATTR, NULL, NULL); @@ -1032,6 +1024,8 @@ xmlCompileStepPattern(xmlPatParserContextPtr ctxt) { return; } name = xmlPatScanNCName(ctxt); + if (ctxt->error < 0) + return; if (name == NULL) { if (CUR == '*') { NEXT; @@ -1248,6 +1242,8 @@ xmlCompilePathPattern(xmlPatParserContextPtr ctxt) { if (CUR == '@') { NEXT; xmlCompileAttributeTest(ctxt); + if (ctxt->error != 0) + goto error; SKIP_BLANKS; /* TODO: check for incompleteness */ if (CUR != 0) { @@ -1788,7 +1784,7 @@ static int xmlStreamPushInternal(xmlStreamCtxtPtr stream, const xmlChar *name, const xmlChar *ns, int nodeType) { - int ret = 0, err = 0, final = 0, tmp, i, m, match, stepNr, desc; + int ret = 0, final = 0, tmp, i, m, match, stepNr, desc; xmlStreamCompPtr comp; xmlStreamStep step;
@@ -1819,10 +1815,8 @@ xmlStreamPushInternal(xmlStreamCtxtPtr stream, */ ret = 1; } else if (comp->steps[0].flags & XML_STREAM_STEP_ROOT) { - /* TODO: Do we need this ? */ - tmp = xmlStreamCtxtAddState(stream, 0, 0); - if (tmp < 0) - err++; + if (xmlStreamCtxtAddState(stream, 0, 0) < 0) + return(-1); } } } @@ -1977,9 +1971,9 @@ xmlStreamPushInternal(xmlStreamCtxtPtr stream, final = step.flags & XML_STREAM_STEP_FINAL; if (final) { ret = 1; - } else { - xmlStreamCtxtAddState(stream, stepNr + 1, - stream->level + 1); + } else if (xmlStreamCtxtAddState(stream, stepNr + 1, + stream->level + 1) < 0) { + return(-1); } if ((ret != 1) && (step.flags & XML_STREAM_STEP_IN_SET)) { /* @@ -2081,10 +2075,11 @@ compare: } final = step.flags & XML_STREAM_STEP_FINAL; if (match) { - if (final) + if (final) { ret = 1; - else - xmlStreamCtxtAddState(stream, 1, stream->level); + } else if (xmlStreamCtxtAddState(stream, 1, stream->level) < 0) { + return(-1); + } if ((ret != 1) && (step.flags & XML_STREAM_STEP_IN_SET)) { /* * Check if we have a special case like "foo//.", where @@ -2106,8 +2101,6 @@ stream_next: stream = stream->next; } /* while stream != NULL */
- if (err > 0) - ret = -1; return(ret); }
@@ -2259,28 +2252,37 @@ xmlStreamWantsAnyNode(xmlStreamCtxtPtr streamCtxt) ************************************************************************/
/** - * xmlPatterncompile: + * xmlPatternCompileSafe: * @pattern: the pattern to compile * @dict: an optional dictionary for interned strings * @flags: compilation flags, see xmlPatternFlags * @namespaces: the prefix definitions, array of [URI, prefix] or NULL + * @patternOut: output pattern * * Compile a pattern. * - * Returns the compiled form of the pattern or NULL in case of error + * Available since 2.13.0. + * + * Returns 0 on success, 1 on error, -1 if a memory allocation failed. */ -xmlPatternPtr -xmlPatterncompile(const xmlChar *pattern, xmlDict *dict, int flags, - const xmlChar **namespaces) { +int +xmlPatternCompileSafe(const xmlChar *pattern, xmlDict *dict, int flags, + const xmlChar **namespaces, xmlPatternPtr *patternOut) { xmlPatternPtr ret = NULL, cur; xmlPatParserContextPtr ctxt = NULL; const xmlChar *or, *start; xmlChar *tmp = NULL; int type = 0; int streamable = 1; + int error;
- if (pattern == NULL) - return(NULL); + if (patternOut == NULL) + return(1); + + if (pattern == NULL) { + error = 1; + goto error; + }
start = pattern; or = start; @@ -2296,9 +2298,15 @@ xmlPatterncompile(const xmlChar *pattern, xmlDict *dict, int flags, } or++; } - if (ctxt == NULL) goto error; + if (ctxt == NULL) { + error = -1; + goto error; + } cur = xmlNewPattern(); - if (cur == NULL) goto error; + if (cur == NULL) { + error = -1; + goto error; + } /* * Assign string dict. */ @@ -2319,8 +2327,10 @@ xmlPatterncompile(const xmlChar *pattern, xmlDict *dict, int flags, xmlCompileIDCXPathPath(ctxt); else xmlCompilePathPattern(ctxt); - if (ctxt->error != 0) + if (ctxt->error != 0) { + error = ctxt->error; goto error; + } xmlFreePatParserContext(ctxt); ctxt = NULL;
@@ -2336,9 +2346,13 @@ xmlPatterncompile(const xmlChar *pattern, xmlDict *dict, int flags, streamable = 0; } } - if (streamable) - xmlStreamCompile(cur); - if (xmlReversePattern(cur) < 0) + if (streamable) { + error = xmlStreamCompile(cur); + if (error != 0) + goto error; + } + error = xmlReversePattern(cur); + if (error != 0) goto error; if (tmp != NULL) { xmlFree(tmp); @@ -2357,12 +2371,33 @@ xmlPatterncompile(const xmlChar *pattern, xmlDict *dict, int flags, } }
- return(ret); + *patternOut = ret; + return(0); error: if (ctxt != NULL) xmlFreePatParserContext(ctxt); if (ret != NULL) xmlFreePattern(ret); if (tmp != NULL) xmlFree(tmp); - return(NULL); + *patternOut = NULL; + return(error); +} + +/** + * xmlPatterncompile: + * @pattern: the pattern to compile + * @dict: an optional dictionary for interned strings + * @flags: compilation flags, see xmlPatternFlags + * @namespaces: the prefix definitions, array of [URI, prefix] or NULL + * + * Compile a pattern. + * + * Returns the compiled form of the pattern or NULL in case of error + */ +xmlPatternPtr +xmlPatterncompile(const xmlChar *pattern, xmlDict *dict, int flags, + const xmlChar **namespaces) { + xmlPatternPtr ret; + xmlPatternCompileSafe(pattern, dict, flags, namespaces, &ret); + return(ret); }
/** diff --git a/libs/xml2/relaxng.c b/libs/xml2/relaxng.c index d7c407d1981..24c3e51056c 100644 --- a/libs/xml2/relaxng.c +++ b/libs/xml2/relaxng.c @@ -53,11 +53,6 @@ static const xmlChar *xmlRelaxNGNs = (const xmlChar *)
#define MAX_ERROR 5
-#define TODO \ - xmlGenericError(xmlGenericErrorContext, \ - "Unimplemented block at %s:%d\n", \ - __FILE__, __LINE__); - typedef struct _xmlRelaxNGSchema xmlRelaxNGSchema; typedef xmlRelaxNGSchema *xmlRelaxNGSchemaPtr;
@@ -415,7 +410,7 @@ struct _xmlRelaxNGDocument { * Handle a redefinition of attribute error */ static void -xmlRngPErrMemory(xmlRelaxNGParserCtxtPtr ctxt, const char *extra) +xmlRngPErrMemory(xmlRelaxNGParserCtxtPtr ctxt) { xmlStructuredErrorFunc schannel = NULL; xmlGenericErrorFunc channel = NULL; @@ -429,17 +424,8 @@ xmlRngPErrMemory(xmlRelaxNGParserCtxtPtr ctxt, const char *extra) data = ctxt->userData; ctxt->nbErrors++; } - if (extra) - __xmlRaiseError(schannel, channel, data, - NULL, NULL, XML_FROM_RELAXNGP, - XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra, - NULL, NULL, 0, 0, - "Memory allocation failed : %s\n", extra); - else - __xmlRaiseError(schannel, channel, data, - NULL, NULL, XML_FROM_RELAXNGP, - XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL, - NULL, NULL, 0, 0, "Memory allocation failed\n"); + + xmlRaiseMemoryError(schannel, channel, data, XML_FROM_RELAXNGP, NULL); }
/** @@ -450,7 +436,7 @@ xmlRngPErrMemory(xmlRelaxNGParserCtxtPtr ctxt, const char *extra) * Handle a redefinition of attribute error */ static void -xmlRngVErrMemory(xmlRelaxNGValidCtxtPtr ctxt, const char *extra) +xmlRngVErrMemory(xmlRelaxNGValidCtxtPtr ctxt) { xmlStructuredErrorFunc schannel = NULL; xmlGenericErrorFunc channel = NULL; @@ -464,17 +450,8 @@ xmlRngVErrMemory(xmlRelaxNGValidCtxtPtr ctxt, const char *extra) data = ctxt->userData; ctxt->nbErrors++; } - if (extra) - __xmlRaiseError(schannel, channel, data, - NULL, NULL, XML_FROM_RELAXNGV, - XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra, - NULL, NULL, 0, 0, - "Memory allocation failed : %s\n", extra); - else - __xmlRaiseError(schannel, channel, data, - NULL, NULL, XML_FROM_RELAXNGV, - XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL, - NULL, NULL, 0, 0, "Memory allocation failed\n"); + + xmlRaiseMemoryError(schannel, channel, data, XML_FROM_RELAXNGV, NULL); }
/** @@ -495,6 +472,7 @@ xmlRngPErr(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node, int error, xmlStructuredErrorFunc schannel = NULL; xmlGenericErrorFunc channel = NULL; void *data = NULL; + int res;
if (ctxt != NULL) { if (ctxt->serror != NULL) @@ -504,11 +482,18 @@ xmlRngPErr(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node, int error, data = ctxt->userData; ctxt->nbErrors++; } - __xmlRaiseError(schannel, channel, data, - NULL, node, XML_FROM_RELAXNGP, - error, XML_ERR_ERROR, NULL, 0, - (const char *) str1, (const char *) str2, NULL, 0, 0, - msg, str1, str2); + + if ((channel == NULL) && (schannel == NULL)) { + channel = xmlGenericError; + data = xmlGenericErrorContext; + } + + res = __xmlRaiseError(schannel, channel, data, NULL, node, + XML_FROM_RELAXNGP, error, XML_ERR_ERROR, NULL, 0, + (const char *) str1, (const char *) str2, NULL, 0, 0, + msg, str1, str2); + if (res < 0) + xmlRngPErrMemory(ctxt); }
/** @@ -529,6 +514,7 @@ xmlRngVErr(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node, int error, xmlStructuredErrorFunc schannel = NULL; xmlGenericErrorFunc channel = NULL; void *data = NULL; + int res;
if (ctxt != NULL) { if (ctxt->serror != NULL) @@ -538,11 +524,18 @@ xmlRngVErr(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node, int error, data = ctxt->userData; ctxt->nbErrors++; } - __xmlRaiseError(schannel, channel, data, - NULL, node, XML_FROM_RELAXNGV, - error, XML_ERR_ERROR, NULL, 0, - (const char *) str1, (const char *) str2, NULL, 0, 0, - msg, str1, str2); + + if ((channel == NULL) && (schannel == NULL)) { + channel = xmlGenericError; + data = xmlGenericErrorContext; + } + + res = __xmlRaiseError(schannel, channel, data, NULL, node, + XML_FROM_RELAXNGV, error, XML_ERR_ERROR, NULL, 0, + (const char *) str1, (const char *) str2, NULL, 0, 0, + msg, str1, str2); + if (res < 0) + xmlRngVErrMemory(ctxt); }
/************************************************************************ @@ -744,7 +737,7 @@ xmlRelaxNGNewRelaxNG(xmlRelaxNGParserCtxtPtr ctxt)
ret = (xmlRelaxNGPtr) xmlMalloc(sizeof(xmlRelaxNG)); if (ret == NULL) { - xmlRngPErrMemory(ctxt, NULL); + xmlRngPErrMemory(ctxt); return (NULL); } memset(ret, 0, sizeof(xmlRelaxNG)); @@ -823,7 +816,7 @@ xmlRelaxNGNewGrammar(xmlRelaxNGParserCtxtPtr ctxt)
ret = (xmlRelaxNGGrammarPtr) xmlMalloc(sizeof(xmlRelaxNGGrammar)); if (ret == NULL) { - xmlRngPErrMemory(ctxt, NULL); + xmlRngPErrMemory(ctxt); return (NULL); } memset(ret, 0, sizeof(xmlRelaxNGGrammar)); @@ -879,7 +872,7 @@ xmlRelaxNGNewDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) ctxt->defTab = (xmlRelaxNGDefinePtr *) xmlMalloc(ctxt->defMax * sizeof(xmlRelaxNGDefinePtr)); if (ctxt->defTab == NULL) { - xmlRngPErrMemory(ctxt, "allocating define\n"); + xmlRngPErrMemory(ctxt); return (NULL); } } else if (ctxt->defMax <= ctxt->defNr) { @@ -891,14 +884,14 @@ xmlRelaxNGNewDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) sizeof (xmlRelaxNGDefinePtr)); if (tmp == NULL) { - xmlRngPErrMemory(ctxt, "allocating define\n"); + xmlRngPErrMemory(ctxt); return (NULL); } ctxt->defTab = tmp; } ret = (xmlRelaxNGDefinePtr) xmlMalloc(sizeof(xmlRelaxNGDefine)); if (ret == NULL) { - xmlRngPErrMemory(ctxt, "allocating define\n"); + xmlRngPErrMemory(ctxt); return (NULL); } memset(ret, 0, sizeof(xmlRelaxNGDefine)); @@ -1004,7 +997,7 @@ xmlRelaxNGNewStates(xmlRelaxNGValidCtxtPtr ctxt, int size) 1) * sizeof(xmlRelaxNGValidStatePtr)); if (ret == NULL) { - xmlRngVErrMemory(ctxt, "allocating states\n"); + xmlRngVErrMemory(ctxt); return (NULL); } ret->nbState = 0; @@ -1013,7 +1006,7 @@ xmlRelaxNGNewStates(xmlRelaxNGValidCtxtPtr ctxt, int size) sizeof (xmlRelaxNGValidStatePtr)); if (ret->tabState == NULL) { - xmlRngVErrMemory(ctxt, "allocating states\n"); + xmlRngVErrMemory(ctxt); xmlFree(ret); return (NULL); } @@ -1049,7 +1042,7 @@ xmlRelaxNGAddStatesUniq(xmlRelaxNGValidCtxtPtr ctxt, sizeof (xmlRelaxNGValidStatePtr)); if (tmp == NULL) { - xmlRngVErrMemory(ctxt, "adding states\n"); + xmlRngVErrMemory(ctxt); return (-1); } states->tabState = tmp; @@ -1089,7 +1082,7 @@ xmlRelaxNGAddStates(xmlRelaxNGValidCtxtPtr ctxt, sizeof (xmlRelaxNGValidStatePtr)); if (tmp == NULL) { - xmlRngVErrMemory(ctxt, "adding states\n"); + xmlRngVErrMemory(ctxt); return (-1); } states->tabState = tmp; @@ -1124,7 +1117,7 @@ xmlRelaxNGFreeStates(xmlRelaxNGValidCtxtPtr ctxt, ctxt->freeStates = (xmlRelaxNGStatesPtr *) xmlMalloc(ctxt->freeStatesMax * sizeof(xmlRelaxNGStatesPtr)); if (ctxt->freeStates == NULL) { - xmlRngVErrMemory(ctxt, "storing states\n"); + xmlRngVErrMemory(ctxt); } } else if ((ctxt != NULL) && (ctxt->freeStatesNr >= ctxt->freeStatesMax)) { @@ -1135,7 +1128,7 @@ xmlRelaxNGFreeStates(xmlRelaxNGValidCtxtPtr ctxt, sizeof (xmlRelaxNGStatesPtr)); if (tmp == NULL) { - xmlRngVErrMemory(ctxt, "storing states\n"); + xmlRngVErrMemory(ctxt); xmlFree(states->tabState); xmlFree(states); return; @@ -1191,7 +1184,7 @@ xmlRelaxNGNewValidState(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node) (xmlRelaxNGValidStatePtr) xmlMalloc(sizeof(xmlRelaxNGValidState)); if (ret == NULL) { - xmlRngVErrMemory(ctxt, "allocating states\n"); + xmlRngVErrMemory(ctxt); return (NULL); } memset(ret, 0, sizeof(xmlRelaxNGValidState)); @@ -1215,7 +1208,7 @@ xmlRelaxNGNewValidState(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node) ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs * sizeof(xmlAttrPtr)); if (ret->attrs == NULL) { - xmlRngVErrMemory(ctxt, "allocating states\n"); + xmlRngVErrMemory(ctxt); return (ret); } } else if (ret->maxAttrs < nbAttrs) { @@ -1224,7 +1217,7 @@ xmlRelaxNGNewValidState(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node) tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, nbAttrs * sizeof(xmlAttrPtr)); if (tmp == NULL) { - xmlRngVErrMemory(ctxt, "allocating states\n"); + xmlRngVErrMemory(ctxt); return (ret); } ret->attrs = tmp; @@ -1273,7 +1266,7 @@ xmlRelaxNGCopyValidState(xmlRelaxNGValidCtxtPtr ctxt, (xmlRelaxNGValidStatePtr) xmlMalloc(sizeof(xmlRelaxNGValidState)); if (ret == NULL) { - xmlRngVErrMemory(ctxt, "allocating states\n"); + xmlRngVErrMemory(ctxt); return (NULL); } memset(ret, 0, sizeof(xmlRelaxNGValidState)); @@ -1289,7 +1282,7 @@ xmlRelaxNGCopyValidState(xmlRelaxNGValidCtxtPtr ctxt, ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs * sizeof(xmlAttrPtr)); if (ret->attrs == NULL) { - xmlRngVErrMemory(ctxt, "allocating states\n"); + xmlRngVErrMemory(ctxt); ret->nbAttrs = 0; return (ret); } @@ -1299,7 +1292,7 @@ xmlRelaxNGCopyValidState(xmlRelaxNGValidCtxtPtr ctxt, tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, state->maxAttrs * sizeof(xmlAttrPtr)); if (tmp == NULL) { - xmlRngVErrMemory(ctxt, "allocating states\n"); + xmlRngVErrMemory(ctxt); ret->nbAttrs = 0; return (ret); } @@ -1418,6 +1411,42 @@ xmlRelaxParserSetFlag(xmlRelaxNGParserCtxtPtr ctxt, int flags) static xmlDocPtr xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, xmlDocPtr doc);
+static xmlDoc * +xmlRelaxReadFile(xmlRelaxNGParserCtxtPtr ctxt, const char *filename) { + xmlParserCtxtPtr pctxt; + xmlDocPtr doc; + + pctxt = xmlNewParserCtxt(); + if (pctxt == NULL) { + xmlRngPErrMemory(ctxt); + return(NULL); + } + if (ctxt->serror != NULL) + xmlCtxtSetErrorHandler(pctxt, ctxt->serror, ctxt->userData); + doc = xmlCtxtReadFile(pctxt, filename, NULL, 0); + xmlFreeParserCtxt(pctxt); + + return(doc); +} + +static xmlDoc * +xmlRelaxReadMemory(xmlRelaxNGParserCtxtPtr ctxt, const char *buf, int size) { + xmlParserCtxtPtr pctxt; + xmlDocPtr doc; + + pctxt = xmlNewParserCtxt(); + if (pctxt == NULL) { + xmlRngPErrMemory(ctxt); + return(NULL); + } + if (ctxt->serror != NULL) + xmlCtxtSetErrorHandler(pctxt, ctxt->serror, ctxt->userData); + doc = xmlCtxtReadMemory(pctxt, buf, size, NULL, NULL, 0); + xmlFreeParserCtxt(pctxt); + + return(doc); +} + /** * xmlRelaxNGIncludePush: * @ctxt: the parser context @@ -1438,7 +1467,7 @@ xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt, (xmlRelaxNGIncludePtr *) xmlMalloc(ctxt->incMax * sizeof(ctxt->incTab[0])); if (ctxt->incTab == NULL) { - xmlRngPErrMemory(ctxt, "allocating include\n"); + xmlRngPErrMemory(ctxt); return (0); } } @@ -1449,7 +1478,7 @@ xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt, ctxt->incMax * sizeof(ctxt->incTab[0])); if (ctxt->incTab == NULL) { - xmlRngPErrMemory(ctxt, "allocating include\n"); + xmlRngPErrMemory(ctxt); return (0); } } @@ -1583,7 +1612,7 @@ xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar * URL, /* * load the document */ - doc = xmlReadFile((const char *) URL,NULL,0); + doc = xmlRelaxReadFile(ctxt, (const char *) URL); if (doc == NULL) { xmlRngPErr(ctxt, node, XML_RNGP_PARSE_ERROR, "xmlRelaxNG: could not load %s\n", URL, NULL); @@ -1595,7 +1624,7 @@ xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar * URL, */ ret = (xmlRelaxNGIncludePtr) xmlMalloc(sizeof(xmlRelaxNGInclude)); if (ret == NULL) { - xmlRngPErrMemory(ctxt, "allocating include\n"); + xmlRngPErrMemory(ctxt); xmlFreeDoc(doc); return (NULL); } @@ -1737,7 +1766,7 @@ xmlRelaxNGValidErrorPush(xmlRelaxNGValidCtxtPtr ctxt, sizeof (xmlRelaxNGValidError)); if (ctxt->errTab == NULL) { - xmlRngVErrMemory(ctxt, "pushing error\n"); + xmlRngVErrMemory(ctxt); return (0); } ctxt->err = NULL; @@ -1750,7 +1779,7 @@ xmlRelaxNGValidErrorPush(xmlRelaxNGValidCtxtPtr ctxt, sizeof (xmlRelaxNGValidError)); if (ctxt->errTab == NULL) { - xmlRngVErrMemory(ctxt, "pushing error\n"); + xmlRngVErrMemory(ctxt); return (0); } ctxt->err = &ctxt->errTab[ctxt->errNr - 1]; @@ -1832,7 +1861,7 @@ xmlRelaxNGDocumentPush(xmlRelaxNGParserCtxtPtr ctxt, (xmlRelaxNGDocumentPtr *) xmlMalloc(ctxt->docMax * sizeof(ctxt->docTab[0])); if (ctxt->docTab == NULL) { - xmlRngPErrMemory(ctxt, "adding document\n"); + xmlRngPErrMemory(ctxt); return (0); } } @@ -1843,7 +1872,7 @@ xmlRelaxNGDocumentPush(xmlRelaxNGParserCtxtPtr ctxt, ctxt->docMax * sizeof(ctxt->docTab[0])); if (ctxt->docTab == NULL) { - xmlRngPErrMemory(ctxt, "adding document\n"); + xmlRngPErrMemory(ctxt); return (0); } } @@ -1913,7 +1942,7 @@ xmlRelaxNGLoadExternalRef(xmlRelaxNGParserCtxtPtr ctxt, /* * load the document */ - doc = xmlReadFile((const char *) URL,NULL,0); + doc = xmlRelaxReadFile(ctxt, (const char *) URL); if (doc == NULL) { xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR, "xmlRelaxNG: could not load %s\n", URL, NULL); @@ -1925,8 +1954,7 @@ xmlRelaxNGLoadExternalRef(xmlRelaxNGParserCtxtPtr ctxt, */ ret = (xmlRelaxNGDocumentPtr) xmlMalloc(sizeof(xmlRelaxNGDocument)); if (ret == NULL) { - xmlRngPErr(ctxt, (xmlNodePtr) doc, XML_ERR_NO_MEMORY, - "xmlRelaxNG: allocate memory for doc %s\n", URL, NULL); + xmlRngPErrMemory(ctxt); xmlFreeDoc(doc); return (NULL); } @@ -2712,17 +2740,13 @@ xmlRelaxNGRegisterTypeLibrary(const xmlChar * namespace, void *data, if ((xmlRelaxNGRegisteredTypes == NULL) || (namespace == NULL) || (check == NULL) || (comp == NULL)) return (-1); - if (xmlHashLookup(xmlRelaxNGRegisteredTypes, namespace) != NULL) { - xmlGenericError(xmlGenericErrorContext, - "Relax-NG types library '%s' already registered\n", - namespace); + if (xmlHashLookup(xmlRelaxNGRegisteredTypes, namespace) != NULL) return (-1); - } lib = (xmlRelaxNGTypeLibraryPtr) xmlMalloc(sizeof(xmlRelaxNGTypeLibrary)); if (lib == NULL) { - xmlRngVErrMemory(NULL, "adding types library\n"); + xmlRngVErrMemory(NULL); return (-1); } memset(lib, 0, sizeof(xmlRelaxNGTypeLibrary)); @@ -2735,9 +2759,6 @@ xmlRelaxNGRegisterTypeLibrary(const xmlChar * namespace, void *data, lib->freef = freef; ret = xmlHashAddEntry(xmlRelaxNGRegisteredTypes, namespace, lib); if (ret < 0) { - xmlGenericError(xmlGenericErrorContext, - "Relax-NG types library failed to register '%s'\n", - namespace); xmlRelaxNGFreeTypeLibrary(lib, namespace); return (-1); } @@ -2757,11 +2778,8 @@ xmlRelaxNGInitTypes(void) if (xmlRelaxNGTypeInitialized != 0) return (0); xmlRelaxNGRegisteredTypes = xmlHashCreate(10); - if (xmlRelaxNGRegisteredTypes == NULL) { - xmlGenericError(xmlGenericErrorContext, - "Failed to allocate sh table for Relax-NG types\n"); + if (xmlRelaxNGRegisteredTypes == NULL) return (-1); - } xmlRelaxNGRegisterTypeLibrary(BAD_CAST "http://www.w3.org/2001/XMLSchema-datatypes", NULL, xmlRelaxNGSchemaTypeHave, @@ -3723,7 +3741,8 @@ xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1, else if (ret == 1) ret = 0; } else { - TODO ret = 0; + /* TODO */ + ret = 0; } if (ret == 0) return (ret); @@ -3754,7 +3773,8 @@ xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1, ret = 1; } } else { - TODO ret = 0; + /* TODO */ + ret = 0; }
return (ret); @@ -3911,7 +3931,7 @@ xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt, ret = (xmlRelaxNGDefinePtr *) xmlMalloc((max + 1) * sizeof(xmlRelaxNGDefinePtr)); if (ret == NULL) { - xmlRngPErrMemory(ctxt, "getting element list\n"); + xmlRngPErrMemory(ctxt); return (NULL); } } else if (max <= len) { @@ -3921,7 +3941,7 @@ xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt, temp = xmlRealloc(ret, (max + 1) * sizeof(xmlRelaxNGDefinePtr)); if (temp == NULL) { - xmlRngPErrMemory(ctxt, "getting element list\n"); + xmlRngPErrMemory(ctxt); xmlFree(ret); return (NULL); } @@ -4019,7 +4039,7 @@ xmlRelaxNGCheckChoiceDeterminism(xmlRelaxNGParserCtxtPtr ctxt, sizeof(xmlRelaxNGDefinePtr *)); if (list == NULL) { - xmlRngPErrMemory(ctxt, "building choice\n"); + xmlRngPErrMemory(ctxt); return; } i = 0; @@ -4156,7 +4176,7 @@ xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt, sizeof(xmlRelaxNGDefinePtr *)); if (list == NULL) { - xmlRngPErrMemory(ctxt, "building group\n"); + xmlRngPErrMemory(ctxt); return; } i = 0; @@ -4348,7 +4368,7 @@ xmlRelaxNGComputeInterleaves(void *payload, void *data, return;
error: - xmlRngPErrMemory(ctxt, "in interleave computation\n"); + xmlRngPErrMemory(ctxt); if (groups != NULL) { for (i = 0; i < nbgroups; i++) if (groups[i] != NULL) { @@ -4386,7 +4406,7 @@ xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) if (ctxt->interleaves == NULL) ctxt->interleaves = xmlHashCreate(10); if (ctxt->interleaves == NULL) { - xmlRngPErrMemory(ctxt, "create interleaves\n"); + xmlRngPErrMemory(ctxt); } else { char name[32];
@@ -5253,7 +5273,7 @@ xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node, if (tmp != NULL) { if (last == NULL) { last = tmp; - } else { + } else if (tmp != ret) { last->next = tmp; last = tmp; } @@ -6617,13 +6637,11 @@ xmlRelaxNGNewParserCtxt(const char *URL) ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt)); if (ret == NULL) { - xmlRngPErrMemory(NULL, "building parser\n"); + xmlRngPErrMemory(NULL); return (NULL); } memset(ret, 0, sizeof(xmlRelaxNGParserCtxt)); ret->URL = xmlStrdup((const xmlChar *) URL); - ret->error = xmlGenericError; - ret->userData = xmlGenericErrorContext; return (ret); }
@@ -6648,14 +6666,12 @@ xmlRelaxNGNewMemParserCtxt(const char *buffer, int size) ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt)); if (ret == NULL) { - xmlRngPErrMemory(NULL, "building parser\n"); + xmlRngPErrMemory(NULL); return (NULL); } memset(ret, 0, sizeof(xmlRelaxNGParserCtxt)); ret->buffer = buffer; ret->size = size; - ret->error = xmlGenericError; - ret->userData = xmlGenericErrorContext; return (ret); }
@@ -6684,7 +6700,7 @@ xmlRelaxNGNewDocParserCtxt(xmlDocPtr doc) ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt)); if (ret == NULL) { - xmlRngPErrMemory(NULL, "building parser\n"); + xmlRngPErrMemory(NULL); xmlFreeDoc(copy); return (NULL); } @@ -7366,7 +7382,7 @@ xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt) * First step is to parse the input document into an DOM/Infoset */ if (ctxt->URL != NULL) { - doc = xmlReadFile((const char *) ctxt->URL,NULL,0); + doc = xmlRelaxReadFile(ctxt, (const char *) ctxt->URL); if (doc == NULL) { xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR, "xmlRelaxNGParse: could not load %s\n", ctxt->URL, @@ -7374,7 +7390,7 @@ xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt) return (NULL); } } else if (ctxt->buffer != NULL) { - doc = xmlReadMemory(ctxt->buffer, ctxt->size,NULL,NULL,0); + doc = xmlRelaxReadMemory(ctxt, ctxt->buffer, ctxt->size); if (doc == NULL) { xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR, "xmlRelaxNGParse: could not parse schemas\n", NULL, @@ -7485,6 +7501,8 @@ xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt) * @warn: the warning callback * @ctx: contextual data for the callbacks * + * DEPRECATED: Use xmlRelaxNGSetParserStructuredErrors. + * * Set the callback functions used to handle errors for a validation context */ void @@ -7679,11 +7697,13 @@ xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define) break; case XML_RELAXNG_DATATYPE: case XML_RELAXNG_VALUE: - TODO break; + /* TODO */ + break; case XML_RELAXNG_START: case XML_RELAXNG_EXCEPT: case XML_RELAXNG_PARAM: - TODO break; + /* TODO */ + break; case XML_RELAXNG_NOOP: xmlRelaxNGDumpDefines(output, define->content); break; @@ -7951,7 +7971,7 @@ xmlRelaxNGElemPush(xmlRelaxNGValidCtxtPtr ctxt, xmlRegExecCtxtPtr exec) sizeof (xmlRegExecCtxtPtr)); if (ctxt->elemTab == NULL) { - xmlRngVErrMemory(ctxt, "validating\n"); + xmlRngVErrMemory(ctxt); return (-1); } } @@ -7962,7 +7982,7 @@ xmlRelaxNGElemPush(xmlRelaxNGValidCtxtPtr ctxt, xmlRegExecCtxtPtr exec) sizeof (xmlRegExecCtxtPtr)); if (ctxt->elemTab == NULL) { - xmlRngVErrMemory(ctxt, "validating\n"); + xmlRngVErrMemory(ctxt); return (-1); } } @@ -8033,13 +8053,7 @@ xmlRelaxNGValidateProgressiveCallback(xmlRegExecCtxtPtr exec ctxt->pstate = -1; return; } - if ((ctxt == NULL) || (define == NULL)) { - fprintf(stderr, "callback on %s missing info\n", token); - if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK)) - ctxt->errNo = XML_RELAXNG_ERR_INTERNAL; - ctxt->pstate = -1; - return; - } else if (define->type != XML_RELAXNG_ELEMENT) { + if (define->type != XML_RELAXNG_ELEMENT) { fprintf(stderr, "callback on %s define is not element\n", token); if (ctxt->errNo == XML_RELAXNG_OK) ctxt->errNo = XML_RELAXNG_ERR_INTERNAL; @@ -8382,7 +8396,7 @@ xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar * str)
ret = (xmlChar *) xmlMallocAtomic(len + 1); if (ret == NULL) { - xmlRngVErrMemory(ctxt, "validating\n"); + xmlRngVErrMemory(ctxt); return (NULL); } p = ret; @@ -8793,7 +8807,8 @@ xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt, } break; default: - TODO ret = -1; + /* TODO */ + ret = -1; } return (ret); } @@ -8881,7 +8896,9 @@ xmlRelaxNGAttributeMatch(xmlRelaxNGValidCtxtPtr ctxt, } return (0); } else { - TODO} + /* TODO */ + return (0); + } return (1); }
@@ -9133,13 +9150,13 @@ xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt, */ list = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr)); if (list == NULL) { - xmlRngVErrMemory(ctxt, "validating\n"); + xmlRngVErrMemory(ctxt); return (-1); } memset(list, 0, nbgroups * sizeof(xmlNodePtr)); lasts = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr)); if (lasts == NULL) { - xmlRngVErrMemory(ctxt, "validating\n"); + xmlRngVErrMemory(ctxt); return (-1); } memset(lasts, 0, nbgroups * sizeof(xmlNodePtr)); @@ -9516,7 +9533,8 @@ xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt, ctxt->flags = oldflags; } } else { - TODO ret = -1; + /* TODO */ + ret = -1; } return (ret); } @@ -10226,7 +10244,7 @@ xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt, if (content == NULL) { content = xmlStrdup(BAD_CAST ""); if (content == NULL) { - xmlRngVErrMemory(ctxt, "validating\n"); + xmlRngVErrMemory(ctxt); ret = -1; break; } @@ -10269,7 +10287,7 @@ xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt, if (content == NULL) { content = xmlStrdup(BAD_CAST ""); if (content == NULL) { - xmlRngVErrMemory(ctxt, "validating\n"); + xmlRngVErrMemory(ctxt); ret = -1; break; } @@ -10320,7 +10338,7 @@ xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt, if (content == NULL) { content = xmlStrdup(BAD_CAST ""); if (content == NULL) { - xmlRngVErrMemory(ctxt, "validating\n"); + xmlRngVErrMemory(ctxt); ret = -1; break; } @@ -10344,7 +10362,8 @@ xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt, } case XML_RELAXNG_EXCEPT: case XML_RELAXNG_PARAM: - TODO ret = -1; + /* TODO */ + ret = -1; break; } ctxt->depth--; @@ -10371,7 +10390,8 @@ xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt, * We should NOT have both ctxt->state and ctxt->states */ if ((ctxt->state != NULL) && (ctxt->states != NULL)) { - TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state); + /* TODO */ + xmlRelaxNGFreeValidState(ctxt, ctxt->state); ctxt->state = NULL; }
@@ -10383,7 +10403,8 @@ xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt, } ret = xmlRelaxNGValidateState(ctxt, define); if ((ctxt->state != NULL) && (ctxt->states != NULL)) { - TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state); + /* TODO */ + xmlRelaxNGFreeValidState(ctxt, ctxt->state); ctxt->state = NULL; } if ((ctxt->states != NULL) && (ctxt->states->nbState == 1)) { @@ -10408,7 +10429,8 @@ xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt, * We should NOT have both ctxt->state and ctxt->states */ if ((ctxt->state != NULL) && (ctxt->states != NULL)) { - TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state); + /* TODO */ + xmlRelaxNGFreeValidState(ctxt, ctxt->state); ctxt->state = NULL; } if (ret == 0) { @@ -10474,7 +10496,8 @@ xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt, } } if ((ctxt->state != NULL) && (ctxt->states != NULL)) { - TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state); + /* TODO */ + xmlRelaxNGFreeValidState(ctxt, ctxt->state); ctxt->state = NULL; } return (ret); @@ -10552,9 +10575,16 @@ xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc)
memset(&vctxt, 0, sizeof(xmlValidCtxt)); vctxt.valid = 1; - vctxt.error = ctxt->error; - vctxt.warning = ctxt->warning; - vctxt.userData = ctxt->userData; + + if (ctxt->error == NULL) { + vctxt.error = xmlGenericError; + vctxt.warning = xmlGenericError; + vctxt.userData = xmlGenericErrorContext; + } else { + vctxt.error = ctxt->error; + vctxt.warning = ctxt->warning; + vctxt.userData = ctxt->userData; + }
if (xmlValidateDocumentFinal(&vctxt, doc) != 1) ret = -1; @@ -10641,13 +10671,11 @@ xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema)
ret = (xmlRelaxNGValidCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGValidCtxt)); if (ret == NULL) { - xmlRngVErrMemory(NULL, "building context\n"); + xmlRngVErrMemory(NULL); return (NULL); } memset(ret, 0, sizeof(xmlRelaxNGValidCtxt)); ret->schema = schema; - ret->error = xmlGenericError; - ret->userData = xmlGenericErrorContext; ret->errNr = 0; ret->errMax = 0; ret->err = NULL; @@ -10710,6 +10738,8 @@ xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt) * @warn: the warning function * @ctx: the functions context * + * DEPRECATED: Use xmlRelaxNGSetValidStructuredErrors. + * * Set the error and warning callback information */ void diff --git a/libs/xml2/threads.c b/libs/xml2/threads.c index 82c794b53eb..3d4abfa744b 100644 --- a/libs/xml2/threads.c +++ b/libs/xml2/threads.c @@ -30,6 +30,7 @@ #include "private/dict.h" #include "private/enc.h" #include "private/globals.h" +#include "private/io.h" #include "private/memory.h" #include "private/threads.h" #include "private/xpath.h" @@ -498,9 +499,8 @@ xmlGlobalInitMutexLock(void) { if (global_init_lock == NULL) { cs = malloc(sizeof(CRITICAL_SECTION)); if (cs == NULL) { - xmlGenericError(xmlGenericErrorContext, - "xmlGlobalInitMutexLock: out of memory\n"); - return; + fprintf(stderr, "libxml2: xmlInitParser: out of memory\n"); + abort(); } InitializeCriticalSection(cs);
@@ -583,19 +583,15 @@ xmlInitParser(void) { atexit(xmlCleanupParser); #endif
- xmlInitMemoryInternal(); /* Should come second */ + xmlInitRandom(); /* Required by xmlInitGlobalsInternal */ + xmlInitMemoryInternal(); xmlInitGlobalsInternal(); - xmlInitRandom(); xmlInitDictInternal(); xmlInitEncodingInternal(); #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) xmlInitXPathInternal(); #endif - - xmlRegisterDefaultInputCallbacks(); -#ifdef LIBXML_OUTPUT_ENABLED - xmlRegisterDefaultOutputCallbacks(); -#endif /* LIBXML_OUTPUT_ENABLED */ + xmlInitIOCallbacks();
xmlParserInnerInitialized = 1; } @@ -644,11 +640,6 @@ xmlCleanupParser(void) {
/* These functions should never call xmlFree. */
- xmlCleanupInputCallbacks(); -#ifdef LIBXML_OUTPUT_ENABLED - xmlCleanupOutputCallbacks(); -#endif - xmlCleanupDictInternal(); xmlCleanupRandom(); xmlCleanupGlobalsInternal(); diff --git a/libs/xml2/tree.c b/libs/xml2/tree.c index 9f261407dcc..11b0a4a04a6 100644 --- a/libs/xml2/tree.c +++ b/libs/xml2/tree.c @@ -55,58 +55,23 @@ int __xmlRegisterCallbacks = 0; * * ************************************************************************/
+static xmlNodePtr +xmlNewEntityRef(xmlDocPtr doc, xmlChar *name); + static xmlNsPtr -xmlNewReconciledNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns); +xmlNewReconciledNs(xmlNodePtr tree, xmlNsPtr ns); + +static xmlAttrPtr +xmlGetPropNodeInternal(const xmlNode *node, const xmlChar *name, + const xmlChar *nsName, int useDTD);
static xmlChar* xmlGetPropNodeValueInternal(const xmlAttr *prop);
-/************************************************************************ - * * - * Tree memory error handler * - * * - ************************************************************************/ -/** - * xmlTreeErrMemory: - * @extra: extra information - * - * Handle an out of memory condition - */ static void -xmlTreeErrMemory(const char *extra) -{ - __xmlSimpleError(XML_FROM_TREE, XML_ERR_NO_MEMORY, NULL, NULL, extra); -} +xmlBufGetChildContent(xmlBufPtr buf, const xmlNode *tree);
-/** - * xmlTreeErr: - * @code: the error number - * @extra: extra information - * - * Handle an out of memory condition - */ static void -xmlTreeErr(int code, xmlNodePtr node, const char *extra) -{ - const char *msg = NULL; - - switch(code) { - case XML_TREE_INVALID_HEX: - msg = "invalid hexadecimal character value\n"; - break; - case XML_TREE_INVALID_DEC: - msg = "invalid decimal character value\n"; - break; - case XML_TREE_UNTERMINATED_ENTITY: - msg = "unterminated entity reference %15s\n"; - break; - case XML_TREE_NOT_UTF8: - msg = "string is not in UTF-8\n"; - break; - default: - msg = "unexpected error number\n"; - } - __xmlSimpleError(XML_FROM_TREE, code, node, msg, extra); -} +xmlUnlinkNodeInternal(xmlNodePtr cur);
/************************************************************************ * * @@ -122,20 +87,6 @@ const xmlChar xmlStringTextNoenc[] = const xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
static int xmlCompressMode = 0; -static int xmlCheckDTD = 1; - -#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) { \ - xmlNodePtr ulccur = (n)->children; \ - if (ulccur == NULL) { \ - (n)->last = NULL; \ - } else { \ - while (ulccur->next != NULL) { \ - ulccur->parent = (n); \ - ulccur = ulccur->next; \ - } \ - ulccur->parent = (n); \ - (n)->last = ulccur; \ -}}
#define IS_STR_XML(str) ((str != NULL) && (str[0] == 'x') && \ (str[1] == 'm') && (str[2] == 'l') && (str[3] == 0)) @@ -222,15 +173,19 @@ xmlBuildQName(const xmlChar *ncname, const xmlChar *prefix, if (ncname == NULL) return(NULL); if (prefix == NULL) return((xmlChar *) ncname);
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + /* Make allocation more likely */ + if (len > 8) + len = 8; +#endif + lenn = strlen((char *) ncname); lenp = strlen((char *) prefix);
if ((memory == NULL) || (len < lenn + lenp + 2)) { ret = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2); - if (ret == NULL) { - xmlTreeErrMemory("building QName"); + if (ret == NULL) return(NULL); - } } else { ret = memory; } @@ -246,6 +201,8 @@ xmlBuildQName(const xmlChar *ncname, const xmlChar *prefix, * @name: the full QName * @prefix: a xmlChar ** * + * DEPRECATED: This function doesn't report malloc failures. + * * parse an XML qualified name string * * [NS 5] QName ::= (Prefix ':')? LocalPart @@ -267,13 +224,6 @@ xmlSplitQName2(const xmlChar *name, xmlChar **prefix) { *prefix = NULL; if (name == NULL) return(NULL);
-#ifndef XML_XML_NAMESPACE - /* xml: prefix is not really a namespace */ - if ((name[0] == 'x') && (name[1] == 'm') && - (name[2] == 'l') && (name[3] == ':')) - return(NULL); -#endif - /* nasty but valid */ if (name[0] == ':') return(NULL); @@ -285,17 +235,14 @@ xmlSplitQName2(const xmlChar *name, xmlChar **prefix) { while ((name[len] != 0) && (name[len] != ':')) len++;
- if (name[len] == 0) + if ((name[len] == 0) || (name[len+1] == 0)) return(NULL);
*prefix = xmlStrndup(name, len); - if (*prefix == NULL) { - xmlTreeErrMemory("QName split"); + if (*prefix == NULL) return(NULL); - } ret = xmlStrdup(&name[len + 1]); if (ret == NULL) { - xmlTreeErrMemory("QName split"); if (*prefix != NULL) { xmlFree(*prefix); *prefix = NULL; @@ -336,7 +283,7 @@ xmlSplitQName3(const xmlChar *name, int *len) { while ((name[l] != 0) && (name[l] != ':')) l++;
- if (name[l] == 0) + if ((name[l] == 0) || (name[l+1] == 0)) return(NULL);
*len = l; @@ -344,6 +291,53 @@ xmlSplitQName3(const xmlChar *name, int *len) { return(&name[l+1]); }
+/** + * xmlSplitQName4: + * @name: the full QName + * @prefixPtr: pointer to resulting prefix + * + * Parse a QName. The return value points to the start of the local + * name in the input string. If the QName has a prefix, it will be + * allocated and stored in @prefixPtr. This string must be freed by + * the caller. If there's no prefix, @prefixPtr is set to NULL. + * + * Returns the local name or NULL if a memory allocation failed. + */ +const xmlChar * +xmlSplitQName4(const xmlChar *name, xmlChar **prefixPtr) { + xmlChar *prefix; + int l = 0; + + if ((name == NULL) || (prefixPtr == NULL)) + return(NULL); + + *prefixPtr = NULL; + + /* nasty but valid */ + if (name[0] == ':') + return(name); + + /* + * we are not trying to validate but just to cut, and yes it will + * work even if this is as set of UTF-8 encoded chars + */ + while ((name[l] != 0) && (name[l] != ':')) + l++; + + /* + * TODO: What about names with multiple colons? + */ + if ((name[l] == 0) || (name[l+1] == 0)) + return(name); + + prefix = xmlStrndup(name, l); + if (prefix == NULL) + return(NULL); + + *prefixPtr = prefix; + return(&name[l+1]); +} + /************************************************************************ * * * Check Name, NCName and QName strings * @@ -708,19 +702,21 @@ xmlGetBufferAllocationScheme(void) {
/** * xmlNewNs: - * @node: the element carrying the namespace + * @node: the element carrying the namespace (optional) * @href: the URI associated - * @prefix: the prefix for the namespace + * @prefix: the prefix for the namespace (optional) * - * Creation of a new Namespace. This function will refuse to create - * a namespace with a similar prefix than an existing one present on this - * node. - * Note that for a default namespace, @prefix should be NULL. + * Create a new namespace. For a default namespace, @prefix should be + * NULL. The namespace URI in @href is not checked. You should make sure + * to pass a valid URI. * - * We use href==NULL in the case of an element creation where the namespace - * was not defined. + * If @node is provided, it must be an element node. The namespace will + * be appended to the node's namespace declarations. It is an error if + * the node already has a definition for the prefix or default + * namespace. * - * Returns a new namespace pointer or NULL + * Returns a new namespace pointer or NULL if arguments are invalid, + * the prefix is already in use or a memory allocation failed. */ xmlNsPtr xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) { @@ -729,35 +725,25 @@ xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) { if ((node != NULL) && (node->type != XML_ELEMENT_NODE)) return(NULL);
- if ((prefix != NULL) && (xmlStrEqual(prefix, BAD_CAST "xml"))) { - /* xml namespace is predefined, no need to add it */ - if (xmlStrEqual(href, XML_XML_NAMESPACE)) - return(NULL); - - /* - * Problem, this is an attempt to bind xml prefix to a wrong - * namespace, which breaks - * Namespace constraint: Reserved Prefixes and Namespace Names - * from XML namespace. But documents authors may not care in - * their context so let's proceed. - */ - } - /* * Allocate a new Namespace and fill the fields. */ cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); - if (cur == NULL) { - xmlTreeErrMemory("building namespace"); + if (cur == NULL) return(NULL); - } memset(cur, 0, sizeof(xmlNs)); cur->type = XML_LOCAL_NAMESPACE;
- if (href != NULL) + if (href != NULL) { cur->href = xmlStrdup(href); - if (prefix != NULL) + if (cur->href == NULL) + goto error; + } + if (prefix != NULL) { cur->prefix = xmlStrdup(prefix); + if (cur->prefix == NULL) + goto error; + }
/* * Add it at the end to preserve parsing order ... @@ -769,31 +755,32 @@ xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) { } else { xmlNsPtr prev = node->nsDef;
- if (((prev->prefix == NULL) && (cur->prefix == NULL)) || - (xmlStrEqual(prev->prefix, cur->prefix))) { - xmlFreeNs(cur); - return(NULL); - } + if ((xmlStrEqual(prev->prefix, cur->prefix)) && + (prev->href != NULL)) + goto error; while (prev->next != NULL) { prev = prev->next; - if (((prev->prefix == NULL) && (cur->prefix == NULL)) || - (xmlStrEqual(prev->prefix, cur->prefix))) { - xmlFreeNs(cur); - return(NULL); - } + if ((xmlStrEqual(prev->prefix, cur->prefix)) && + (prev->href != NULL)) + goto error; } prev->next = cur; } } return(cur); + +error: + xmlFreeNs(cur); + return(NULL); }
/** * xmlSetNs: * @node: a node in the document - * @ns: a namespace pointer + * @ns: a namespace pointer (optional) * - * Associate a namespace to a node, a posteriori. + * Set the namespace of an element or attribute node. Passing a NULL + * namespace unsets the namespace. */ void xmlSetNs(xmlNodePtr node, xmlNsPtr ns) { @@ -809,7 +796,7 @@ xmlSetNs(xmlNodePtr node, xmlNsPtr ns) { * xmlFreeNs: * @cur: the namespace pointer * - * Free up the structures associated to a namespace + * Free an xmlNs object. */ void xmlFreeNs(xmlNsPtr cur) { @@ -825,7 +812,7 @@ xmlFreeNs(xmlNsPtr cur) { * xmlFreeNsList: * @cur: the first namespace pointer * - * Free up all the structures associated to the chained namespaces. + * Free a list of xmlNs objects. */ void xmlFreeNsList(xmlNsPtr cur) { @@ -842,15 +829,21 @@ xmlFreeNsList(xmlNsPtr cur) {
/** * xmlNewDtd: - * @doc: the document pointer - * @name: the DTD name - * @ExternalID: the external ID - * @SystemID: the system ID + * @doc: the document pointer (optional) + * @name: the DTD name (optional) + * @ExternalID: the external ID (optional) + * @SystemID: the system ID (optional) + * + * Create a DTD node. * - * Creation of a new DTD for the external subset. To create an - * internal subset, use xmlCreateIntSubset(). + * If a document is provided, it is an error if it already has an + * external subset. If the document has no external subset, it + * will be set to the created DTD. * - * Returns a pointer to the new DTD structure + * To create an internal subset, use xmlCreateIntSubset(). + * + * Returns a pointer to the new DTD object or NULL if arguments are + * invalid or a memory allocation failed. */ xmlDtdPtr xmlNewDtd(xmlDocPtr doc, const xmlChar *name, @@ -865,19 +858,26 @@ xmlNewDtd(xmlDocPtr doc, const xmlChar *name, * Allocate a new DTD and fill the fields. */ cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd)); - if (cur == NULL) { - xmlTreeErrMemory("building DTD"); + if (cur == NULL) return(NULL); - } memset(cur, 0 , sizeof(xmlDtd)); cur->type = XML_DTD_NODE;
- if (name != NULL) + if (name != NULL) { cur->name = xmlStrdup(name); - if (ExternalID != NULL) + if (cur->name == NULL) + goto error; + } + if (ExternalID != NULL) { cur->ExternalID = xmlStrdup(ExternalID); - if (SystemID != NULL) + if (cur->ExternalID == NULL) + goto error; + } + if (SystemID != NULL) { cur->SystemID = xmlStrdup(SystemID); + if (cur->SystemID == NULL) + goto error; + } if (doc != NULL) doc->extSubset = cur; cur->doc = doc; @@ -885,16 +885,20 @@ xmlNewDtd(xmlDocPtr doc, const xmlChar *name, if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) xmlRegisterNodeDefaultValue((xmlNodePtr)cur); return(cur); + +error: + xmlFreeDtd(cur); + return(NULL); }
/** * xmlGetIntSubset: * @doc: the document pointer * - * Get the internal subset of a document - * Returns a pointer to the DTD structure or NULL if not found + * Get the internal subset of a document. + * + * Returns a pointer to the DTD object or NULL if not found. */ - xmlDtdPtr xmlGetIntSubset(const xmlDoc *doc) { xmlNodePtr cur; @@ -912,63 +916,55 @@ xmlGetIntSubset(const xmlDoc *doc) {
/** * xmlCreateIntSubset: - * @doc: the document pointer - * @name: the DTD name - * @ExternalID: the external (PUBLIC) ID - * @SystemID: the system ID + * @doc: the document pointer (optional) + * @name: the DTD name (optional) + * @ExternalID: the external (PUBLIC) ID (optional) + * @SystemID: the system ID (optional) * - * Create the internal subset of a document - * Returns a pointer to the new DTD structure + * Create a DTD node. + * + * If a document is provided and it already has an internal subset, + * the existing DTD object is returned without creating a new object. + * If the document has no internal subset, it will be set to the + * created DTD. + * + * Returns a pointer to the new or existing DTD object or NULL if + * arguments are invalid or a memory allocation failed. */ xmlDtdPtr xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name, const xmlChar *ExternalID, const xmlChar *SystemID) { xmlDtdPtr cur;
- if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) { - return(NULL); + if (doc != NULL) { + cur = xmlGetIntSubset(doc); + if (cur != NULL) + return(cur); }
/* * Allocate a new DTD and fill the fields. */ cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd)); - if (cur == NULL) { - xmlTreeErrMemory("building internal subset"); + if (cur == NULL) return(NULL); - } memset(cur, 0, sizeof(xmlDtd)); cur->type = XML_DTD_NODE;
if (name != NULL) { cur->name = xmlStrdup(name); - if (cur->name == NULL) { - xmlTreeErrMemory("building internal subset"); - xmlFree(cur); - return(NULL); - } + if (cur->name == NULL) + goto error; } if (ExternalID != NULL) { cur->ExternalID = xmlStrdup(ExternalID); - if (cur->ExternalID == NULL) { - xmlTreeErrMemory("building internal subset"); - if (cur->name != NULL) - xmlFree((char *)cur->name); - xmlFree(cur); - return(NULL); - } + if (cur->ExternalID == NULL) + goto error; } if (SystemID != NULL) { cur->SystemID = xmlStrdup(SystemID); - if (cur->SystemID == NULL) { - xmlTreeErrMemory("building internal subset"); - if (cur->name != NULL) - xmlFree((char *)cur->name); - if (cur->ExternalID != NULL) - xmlFree((char *)cur->ExternalID); - xmlFree(cur); - return(NULL); - } + if (cur->SystemID == NULL) + goto error; } if (doc != NULL) { doc->intSubset = cur; @@ -1012,6 +1008,10 @@ xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name, if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) xmlRegisterNodeDefaultValue((xmlNodePtr)cur); return(cur); + +error: + xmlFreeDtd(cur); + return(NULL); }
/** @@ -1026,42 +1026,6 @@ xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name, (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \ xmlFree((char *)(str));
- -/** - * DICT_COPY: - * @str: a string - * - * Copy a string using a "dict" dictionary in the current scope, - * if available. - */ -#define DICT_COPY(str, cpy) \ - if (str) { \ - if (dict) { \ - if (xmlDictOwns(dict, (const xmlChar *)(str))) \ - cpy = (xmlChar *) (str); \ - else \ - cpy = (xmlChar *) xmlDictLookup((dict), (const xmlChar *)(str), -1); \ - } else \ - cpy = xmlStrdup((const xmlChar *)(str)); } - -/** - * DICT_CONST_COPY: - * @str: a string - * - * Copy a string using a "dict" dictionary in the current scope, - * if available. - */ -#define DICT_CONST_COPY(str, cpy) \ - if (str) { \ - if (dict) { \ - if (xmlDictOwns(dict, (const xmlChar *)(str))) \ - cpy = (const xmlChar *) (str); \ - else \ - cpy = xmlDictLookup((dict), (const xmlChar *)(str), -1); \ - } else \ - cpy = (const xmlChar *) xmlStrdup((const xmlChar *)(str)); } - - /** * xmlFreeDtd: * @cur: the DTD structure to free up @@ -1089,11 +1053,10 @@ xmlFreeDtd(xmlDtdPtr cur) { */ while (c != NULL) { next = c->next; - if ((c->type != XML_NOTATION_NODE) && - (c->type != XML_ELEMENT_DECL) && + if ((c->type != XML_ELEMENT_DECL) && (c->type != XML_ATTRIBUTE_DECL) && (c->type != XML_ENTITY_DECL)) { - xmlUnlinkNode(c); + xmlUnlinkNodeInternal(c); xmlFreeNode(c); } c = next; @@ -1120,11 +1083,11 @@ xmlFreeDtd(xmlDtdPtr cur) {
/** * xmlNewDoc: - * @version: xmlChar string giving the version of XML "1.0" + * @version: XML version string like "1.0" (optional) * - * Creates a new XML document + * Creates a new XML document. If version is NULL, "1.0" is used. * - * Returns a new document + * Returns a new document or NULL if a memory allocation failed. */ xmlDocPtr xmlNewDoc(const xmlChar *version) { @@ -1137,16 +1100,13 @@ xmlNewDoc(const xmlChar *version) { * Allocate a new document and fill the fields. */ cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc)); - if (cur == NULL) { - xmlTreeErrMemory("building doc"); + if (cur == NULL) return(NULL); - } memset(cur, 0, sizeof(xmlDoc)); cur->type = XML_DOCUMENT_NODE;
cur->version = xmlStrdup(version); if (cur->version == NULL) { - xmlTreeErrMemory("building doc"); xmlFree(cur); return(NULL); } @@ -1171,7 +1131,7 @@ xmlNewDoc(const xmlChar *version) { * xmlFreeDoc: * @cur: pointer to the document * - * Free up all the structures used by a document, tree included. + * Free a document including all children and associated DTDs. */ void xmlFreeDoc(xmlDocPtr cur) { @@ -1182,7 +1142,7 @@ xmlFreeDoc(xmlDocPtr cur) { return; }
- if (cur != NULL) dict = cur->dict; + dict = cur->dict;
if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue)) xmlDeregisterNodeDefaultValue((xmlNodePtr)cur); @@ -1199,12 +1159,12 @@ xmlFreeDoc(xmlDocPtr cur) { if (intSubset == extSubset) extSubset = NULL; if (extSubset != NULL) { - xmlUnlinkNode((xmlNodePtr) cur->extSubset); + xmlUnlinkNodeInternal((xmlNodePtr) cur->extSubset); cur->extSubset = NULL; xmlFreeDtd(extSubset); } if (intSubset != NULL) { - xmlUnlinkNode((xmlNodePtr) cur->intSubset); + xmlUnlinkNodeInternal((xmlNodePtr) cur->intSubset); cur->intSubset = NULL; xmlFreeDtd(intSubset); } @@ -1221,38 +1181,52 @@ xmlFreeDoc(xmlDocPtr cur) { }
/** - * xmlStringLenGetNodeList: - * @doc: the document - * @value: the value of the text - * @len: the length of the string value + * xmlNodeParseContentInternal: + * @doc: a document (optional) + * @parent: an element or attribute (optional) + * @value: an attribute value + * @len: maximum length of the attribute value + * @listPtr: pointer to the resulting node list (optional) + * + * See xmlNodeParseContent. * - * Parse the value string and build the node list associated. Should - * produce a flat tree with only TEXTs and ENTITY_REFs. - * Returns a pointer to the first child + * Returns 0 on success, -1 if a memory allocation failed. */ -xmlNodePtr -xmlStringLenGetNodeList(const xmlDoc *doc, const xmlChar *value, int len) { - xmlNodePtr ret = NULL, last = NULL; +static int +xmlNodeParseContentInternal(const xmlDoc *doc, xmlNodePtr parent, + const xmlChar *value, int len, + xmlNodePtr *listPtr) { + xmlNodePtr head = NULL, last = NULL; xmlNodePtr node; - xmlChar *val; - const xmlChar *cur, *end; + xmlChar *val = NULL; + const xmlChar *cur; const xmlChar *q; xmlEntityPtr ent; xmlBufPtr buf; + int remaining; + + if (listPtr != NULL) + *listPtr = NULL; + + if (len < 0) + remaining = INT_MAX; + else + remaining = len; + + if ((value == NULL) || (value[0] == 0)) + goto done;
- if (value == NULL) return(NULL); cur = value; - end = cur + len;
- buf = xmlBufCreateSize(0); - if (buf == NULL) return(NULL); + buf = xmlBufCreateSize(64); + if (buf == NULL) + return(-1); xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT);
q = cur; - while ((cur < end) && (*cur != 0)) { + while ((remaining > 0) && (*cur != 0)) { if (cur[0] == '&') { int charval = 0; - xmlChar tmp;
/* * Save the current text. @@ -1260,25 +1234,15 @@ xmlStringLenGetNodeList(const xmlDoc *doc, const xmlChar *value, int len) { if (cur != q) { if (xmlBufAdd(buf, q, cur - q)) goto out; + q = cur; } - q = cur; - if ((cur + 2 < end) && (cur[1] == '#') && (cur[2] == 'x')) { + + if ((remaining > 2) && (cur[1] == '#') && (cur[2] == 'x')) { + int tmp = 0; + cur += 3; - if (cur < end) - tmp = *cur; - else - tmp = 0; - while (tmp != ';') { /* Non input consuming loop */ - /* - * If you find an integer overflow here when fuzzing, - * the bug is probably elsewhere. This function should - * only receive entities that were already validated by - * the parser, typically by xmlParseAttValueComplex - * calling xmlStringDecodeEntities. - * - * So it's better *not* to check for overflow to - * potentially discover new bugs. - */ + remaining -= 3; + while ((remaining > 0) && ((tmp = *cur) != ';')) { if ((tmp >= '0') && (tmp <= '9')) charval = charval * 16 + (tmp - '0'); else if ((tmp >= 'a') && (tmp <= 'f')) @@ -1286,142 +1250,147 @@ xmlStringLenGetNodeList(const xmlDoc *doc, const xmlChar *value, int len) { else if ((tmp >= 'A') && (tmp <= 'F')) charval = charval * 16 + (tmp - 'A') + 10; else { - xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc, - NULL); charval = 0; break; } + if (charval > 0x110000) + charval = 0x110000; cur++; - if (cur < end) - tmp = *cur; - else - tmp = 0; + remaining--; } - if (tmp == ';') + if (tmp == ';') { cur++; + remaining--; + } q = cur; - } else if ((cur + 1 < end) && (cur[1] == '#')) { + } else if ((remaining > 1) && (cur[1] == '#')) { + int tmp = 0; + cur += 2; - if (cur < end) - tmp = *cur; - else - tmp = 0; - while (tmp != ';') { /* Non input consuming loops */ - /* Don't check for integer overflow, see above. */ + remaining -= 2; + while ((remaining > 0) && ((tmp = *cur) != ';')) { if ((tmp >= '0') && (tmp <= '9')) charval = charval * 10 + (tmp - '0'); else { - xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc, - NULL); charval = 0; break; } + if (charval > 0x110000) + charval = 0x110000; cur++; - if (cur < end) - tmp = *cur; - else - tmp = 0; + remaining--; } - if (tmp == ';') + if (tmp == ';') { cur++; + remaining--; + } q = cur; } else { /* * Read the entity string */ cur++; + remaining--; q = cur; - while ((cur < end) && (*cur != 0) && (*cur != ';')) cur++; - if ((cur >= end) || (*cur == 0)) { - xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY, (xmlNodePtr) doc, - (const char *) q); - goto out; - } + while ((remaining > 0) && (*cur != 0) && (*cur != ';')) { + cur++; + remaining--; + } + if ((remaining <= 0) || (*cur == 0)) + break; if (cur != q) { - /* - * Predefined entities don't generate nodes - */ val = xmlStrndup(q, cur - q); + if (val == NULL) + goto out; ent = xmlGetDocEntity(doc, val); if ((ent != NULL) && (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) { - + /* + * Predefined entities don't generate nodes + */ if (xmlBufCat(buf, ent->content)) goto out; - } else { /* * Flush buffer so far */ if (!xmlBufIsEmpty(buf)) { node = xmlNewDocText(doc, NULL); - if (node == NULL) { - if (val != NULL) xmlFree(val); + if (node == NULL) goto out; - } node->content = xmlBufDetach(buf); + node->parent = parent;
if (last == NULL) { - last = ret = node; + head = node; } else { - last = xmlAddNextSibling(last, node); + last->next = node; + node->prev = last; } + last = node; + } + + if ((ent != NULL) && + ((ent->flags & XML_ENT_PARSED) == 0) && + ((ent->flags & XML_ENT_EXPANDING) == 0) && + (ent->content != NULL)) { + int res; + + ent->flags |= XML_ENT_EXPANDING; + res = xmlNodeParseContentInternal(doc, + (xmlNodePtr) ent, ent->content, -1, NULL); + ent->flags &= ~XML_ENT_EXPANDING; + if (res < 0) + goto out; + ent->flags |= XML_ENT_PARSED; }
/* * Create a new REFERENCE_REF node */ - node = xmlNewReference(doc, val); - if (node == NULL) { - if (val != NULL) xmlFree(val); + node = xmlNewEntityRef((xmlDocPtr) doc, val); + val = NULL; + if (node == NULL) goto out; - } - else if ((ent != NULL) && - ((ent->flags & XML_ENT_PARSED) == 0) && - ((ent->flags & XML_ENT_EXPANDING) == 0)) { - xmlNodePtr temp; - - /* - * The entity should have been checked already, - * but set the flag anyway to avoid recursion. - */ - ent->flags |= XML_ENT_EXPANDING; - ent->children = xmlStringGetNodeList(doc, - (const xmlChar*)node->content); - ent->owner = 1; - ent->flags &= ~XML_ENT_EXPANDING; - ent->flags |= XML_ENT_PARSED; - temp = ent->children; - while (temp) { - temp->parent = (xmlNodePtr)ent; - ent->last = temp; - temp = temp->next; - } - } + node->parent = parent; + node->last = (xmlNodePtr) ent; + if (ent != NULL) { + node->children = (xmlNodePtr) ent; + node->content = ent->content; + } + if (last == NULL) { - last = ret = node; + head = node; } else { - last = xmlAddNextSibling(last, node); + last->next = node; + node->prev = last; } + last = node; } xmlFree(val); + val = NULL; } cur++; + remaining--; q = cur; } if (charval != 0) { xmlChar buffer[10]; int l;
+ if (charval >= 0x110000) + charval = 0xFFFD; /* replacement character */ + l = xmlCopyCharMultiByte(buffer, charval); buffer[l] = 0;
if (xmlBufCat(buf, buffer)) goto out; - charval = 0; } - } else + } else { cur++; + remaining--; + } }
if (cur != q) { @@ -1434,398 +1403,258 @@ xmlStringLenGetNodeList(const xmlDoc *doc, const xmlChar *value, int len) {
if (!xmlBufIsEmpty(buf)) { node = xmlNewDocText(doc, NULL); - if (node == NULL) goto out; + if (node == NULL) + goto out; + node->parent = parent; node->content = xmlBufDetach(buf);
if (last == NULL) { - ret = node; + head = node; } else { - xmlAddNextSibling(last, node); + last->next = node; + node->prev = last; } - } else if (ret == NULL) { - ret = xmlNewDocText(doc, BAD_CAST ""); + last = node; + } else if (head == NULL) { + head = xmlNewDocText(doc, BAD_CAST ""); + if (head == NULL) + goto out; + head->parent = parent; + last = head; + } + + xmlBufFree(buf); + +done: + if (parent != NULL) { + if (parent->children != NULL) + xmlFreeNodeList(parent->children); + parent->children = head; + parent->last = last; }
+ if (listPtr != NULL) + *listPtr = head; + + return(0); + out: xmlBufFree(buf); + if (val != NULL) + xmlFree(val); + if (head != NULL) + xmlFreeNodeList(head); + return(-1); +} + +/** + * xmlNodeParseContent: + * @node: an element or attribute + * @content: text content with XML references + * @len: maximum length of content + * + * Parse content and replace the node's children with the resulting + * node list. + * + * @content is expected to be a valid XML attribute value possibly + * containing character and entity references. Syntax errors + * and references to undeclared entities are ignored silently. + * Only references are handled, nested elements, comments or PIs are + * not. + * + * Returns 0 on success, -1 if a memory allocation failed. + */ +int +xmlNodeParseContent(xmlNodePtr node, const xmlChar *content, int len) { + return(xmlNodeParseContentInternal(node->doc, node, content, len, NULL)); +} + +/** + * xmlStringLenGetNodeList: + * @doc: a document (optional) + * @value: an attribute value + * @len: maximum length of the attribute value + * + * DEPRECATED: Use xmlNodeSetContentLen. + * + * See xmlStringGetNodeList. + * + * Returns a pointer to the first child or NULL if a memory + * allocation failed. + */ +xmlNodePtr +xmlStringLenGetNodeList(const xmlDoc *doc, const xmlChar *value, int len) { + xmlNodePtr ret; + + xmlNodeParseContentInternal(doc, NULL, value, len, &ret); return(ret); }
/** * xmlStringGetNodeList: - * @doc: the document - * @value: the value of the attribute + * @doc: a document (optional) + * @value: an attribute value + * + * DEPRECATED: Use xmlNodeSetContent. + * + * Parse an attribute value and build a node list containing only + * text and entity reference nodes. The resulting nodes will be + * associated with the document if provided. The document is also + * used to look up entities. + * + * The input is not validated. Syntax errors or references to + * undeclared entities will be ignored silently with unspecified + * results. * - * Parse the value string and build the node list associated. Should - * produce a flat tree with only TEXTs and ENTITY_REFs. - * Returns a pointer to the first child + * Returns a pointer to the first child or NULL if a memory + * allocation failed. */ xmlNodePtr xmlStringGetNodeList(const xmlDoc *doc, const xmlChar *value) { - xmlNodePtr ret = NULL, head = NULL, last = NULL; - xmlNodePtr node; - xmlChar *val = NULL; - const xmlChar *cur = value; - const xmlChar *q; - xmlEntityPtr ent; + xmlNodePtr ret; + + xmlNodeParseContentInternal(doc, NULL, value, -1, &ret); + return(ret); +} + +/** + * xmlNodeListGetStringInternal: + * @doc: a document (optional) + * @node: a node list + * @escMode: escape mode (0 = no, 1 = elem, 2 = attr, 3 = raw) + * + * Returns a pointer to the string. + */ +static xmlChar * +xmlNodeListGetStringInternal(xmlDocPtr doc, const xmlNode *node, int escMode) { xmlBufPtr buf; + xmlChar *ret;
- if (value == NULL) return(NULL); + if (node == NULL) + return(xmlStrdup(BAD_CAST ""));
- buf = xmlBufCreateSize(0); - if (buf == NULL) return(NULL); - xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT); + if ((escMode == 0) && + ((node->type == XML_TEXT_NODE) || + (node->type == XML_CDATA_SECTION_NODE)) && + (node->next == NULL)) { + if (node->content == NULL) + return(xmlStrdup(BAD_CAST "")); + return(xmlStrdup(node->content)); + }
- q = cur; - while (*cur != 0) { - if (cur[0] == '&') { - int charval = 0; - xmlChar tmp; + buf = xmlBufCreateSize(64); + if (buf == NULL) + return(NULL);
- /* - * Save the current text. - */ - if (cur != q) { - if (xmlBufAdd(buf, q, cur - q)) - goto out; - } - q = cur; - if ((cur[1] == '#') && (cur[2] == 'x')) { - cur += 3; - tmp = *cur; - while (tmp != ';') { /* Non input consuming loop */ - /* Don't check for integer overflow, see above. */ - if ((tmp >= '0') && (tmp <= '9')) - charval = charval * 16 + (tmp - '0'); - else if ((tmp >= 'a') && (tmp <= 'f')) - charval = charval * 16 + (tmp - 'a') + 10; - else if ((tmp >= 'A') && (tmp <= 'F')) - charval = charval * 16 + (tmp - 'A') + 10; - else { - xmlTreeErr(XML_TREE_INVALID_HEX, (xmlNodePtr) doc, - NULL); - charval = 0; - break; - } - cur++; - tmp = *cur; - } - if (tmp == ';') - cur++; - q = cur; - } else if (cur[1] == '#') { - cur += 2; - tmp = *cur; - while (tmp != ';') { /* Non input consuming loops */ - /* Don't check for integer overflow, see above. */ - if ((tmp >= '0') && (tmp <= '9')) - charval = charval * 10 + (tmp - '0'); - else { - xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc, - NULL); - charval = 0; - break; - } - cur++; - tmp = *cur; - } - if (tmp == ';') - cur++; - q = cur; - } else { - /* - * Read the entity string - */ - cur++; - q = cur; - while ((*cur != 0) && (*cur != ';')) cur++; - if (*cur == 0) { - xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY, - (xmlNodePtr) doc, (const char *) q); - goto out; - } - if (cur != q) { - /* - * Predefined entities don't generate nodes - */ - val = xmlStrndup(q, cur - q); - ent = xmlGetDocEntity(doc, val); - if ((ent != NULL) && - (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) { - - if (xmlBufCat(buf, ent->content)) - goto out; - - } else { - /* - * Flush buffer so far - */ - if (!xmlBufIsEmpty(buf)) { - node = xmlNewDocText(doc, NULL); - if (node == NULL) - goto out; - node->content = xmlBufDetach(buf); - - if (last == NULL) { - last = head = node; - } else { - last = xmlAddNextSibling(last, node); - } - } - - /* - * Create a new REFERENCE_REF node - */ - node = xmlNewReference(doc, val); - if (node == NULL) - goto out; - if ((ent != NULL) && - ((ent->flags & XML_ENT_PARSED) == 0) && - ((ent->flags & XML_ENT_EXPANDING) == 0)) { - xmlNodePtr temp; - - /* - * The entity should have been checked already, - * but set the flag anyway to avoid recursion. - */ - ent->flags |= XML_ENT_EXPANDING; - ent->children = xmlStringGetNodeList(doc, - (const xmlChar*)node->content); - ent->owner = 1; - ent->flags &= ~XML_ENT_EXPANDING; - ent->flags |= XML_ENT_PARSED; - temp = ent->children; - while (temp) { - temp->parent = (xmlNodePtr)ent; - ent->last = temp; - temp = temp->next; - } - } - if (last == NULL) { - last = head = node; - } else { - last = xmlAddNextSibling(last, node); - } - } - xmlFree(val); - val = NULL; - } - cur++; - q = cur; - } - if (charval != 0) { - xmlChar buffer[10]; - int len; - - len = xmlCopyCharMultiByte(buffer, charval); - buffer[len] = 0; - - if (xmlBufCat(buf, buffer)) - goto out; - charval = 0; - } - } else - cur++; - } - if ((cur != q) || (head == NULL)) { - /* - * Handle the last piece of text. - */ - xmlBufAdd(buf, q, cur - q); - } - - if (!xmlBufIsEmpty(buf)) { - node = xmlNewDocText(doc, NULL); - if (node == NULL) - goto out; - node->content = xmlBufDetach(buf); + while (node != NULL) { + if ((node->type == XML_TEXT_NODE) || + (node->type == XML_CDATA_SECTION_NODE)) { + if (node->content != NULL) { + if (escMode == 0) { + xmlBufCat(buf, node->content); + } else { + xmlChar *encoded; + + if (escMode == 1) + encoded = xmlEncodeEntitiesReentrant(doc, + node->content); + else if (escMode == 2) + encoded = xmlEncodeAttributeEntities(doc, + node->content); + else + encoded = xmlEncodeSpecialChars(doc, node->content); + if (encoded == NULL) + goto error; + xmlBufCat(buf, encoded); + xmlFree(encoded); + } + } + } else if (node->type == XML_ENTITY_REF_NODE) { + if (escMode == 0) { + xmlBufGetNodeContent(buf, node); + } else { + xmlBufAdd(buf, BAD_CAST "&", 1); + xmlBufCat(buf, node->name); + xmlBufAdd(buf, BAD_CAST ";", 1); + } + }
- if (last == NULL) { - head = node; - } else { - xmlAddNextSibling(last, node); - } + node = node->next; }
- ret = head; - head = NULL; - -out: + ret = xmlBufDetach(buf); xmlBufFree(buf); - if (val != NULL) xmlFree(val); - if (head != NULL) xmlFreeNodeList(head); return(ret); + +error: + xmlBufFree(buf); + return(NULL); }
/** * xmlNodeListGetString: - * @doc: the document - * @list: a Node list - * @inLine: should we replace entity contents or show their external form + * @doc: a document (optional) + * @list: a node list of attribute children + * @inLine: whether entity references are substituted + * + * Serializes attribute children (text and entity reference nodes) + * into a string. * - * Build the string equivalent to the text contained in the Node list - * made of TEXTs and ENTITY_REFs + * If @inLine is true, entity references will be substituted. + * Otherwise, entity references will be kept and special characters + * like '&' as well as non-ASCII chars will be escaped. See + * xmlNodeListGetRawString for an alternative option. * - * Returns a pointer to the string copy, the caller must free it with xmlFree(). + * Returns a string or NULL if a memory allocation failed. */ xmlChar * xmlNodeListGetString(xmlDocPtr doc, const xmlNode *list, int inLine) { - const xmlNode *node = list; - xmlChar *ret = NULL; - xmlEntityPtr ent; - int attr; + int escMode;
+ /* backward compatibility */ if (list == NULL) - return (NULL); - if ((list->parent != NULL) && (list->parent->type == XML_ATTRIBUTE_NODE)) - attr = 1; - else - attr = 0; - - while (node != NULL) { - if ((node->type == XML_TEXT_NODE) || - (node->type == XML_CDATA_SECTION_NODE)) { - if (inLine) { - ret = xmlStrcat(ret, node->content); - } else { - xmlChar *buffer; + return(NULL);
- if (attr) - buffer = xmlEncodeAttributeEntities(doc, node->content); - else - buffer = xmlEncodeEntitiesReentrant(doc, node->content); - if (buffer != NULL) { - ret = xmlStrcat(ret, buffer); - xmlFree(buffer); - } - } - } else if (node->type == XML_ENTITY_REF_NODE) { - if (inLine) { - ent = xmlGetDocEntity(doc, node->name); - if (ent != NULL) { - xmlChar *buffer; - - /* an entity content can be any "well balanced chunk", - * i.e. the result of the content [43] production: - * http://www.w3.org/TR/REC-xml#NT-content. - * So it can contain text, CDATA section or nested - * entity reference nodes (among others). - * -> we recursive call xmlNodeListGetString() - * which handles these types */ - buffer = xmlNodeListGetString(doc, ent->children, 1); - if (buffer != NULL) { - ret = xmlStrcat(ret, buffer); - xmlFree(buffer); - } - } else { - ret = xmlStrcat(ret, node->content); - } - } else { - xmlChar buf[2]; - - buf[0] = '&'; - buf[1] = 0; - ret = xmlStrncat(ret, buf, 1); - ret = xmlStrcat(ret, node->name); - buf[0] = ';'; - buf[1] = 0; - ret = xmlStrncat(ret, buf, 1); - } - } -#if 0 - else { - xmlGenericError(xmlGenericErrorContext, - "xmlGetNodeListString : invalid node type %d\n", - node->type); - } -#endif - node = node->next; + if (inLine) { + escMode = 0; + } else { + if ((list->parent != NULL) && + (list->parent->type == XML_ATTRIBUTE_NODE)) + escMode = 2; + else + escMode = 1; } - return (ret); + + return(xmlNodeListGetStringInternal(doc, list, escMode)); }
#ifdef LIBXML_TREE_ENABLED /** * xmlNodeListGetRawString: - * @doc: the document - * @list: a Node list - * @inLine: should we replace entity contents or show their external form + * @doc: a document (optional) + * @list: a node list of attribute children + * @inLine: whether entity references are substituted * - * Builds the string equivalent to the text contained in the Node list - * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString() - * this function doesn't do any character encoding handling. + * Serializes attribute children (text and entity reference nodes) + * into a string. * - * Returns a pointer to the string copy, the caller must free it with xmlFree(). + * If @inLine is true, entity references will be substituted. + * Otherwise, entity references will be kept and special characters + * like '&' will be escaped. + * + * Returns a string or NULL if a memory allocation failed. */ xmlChar * xmlNodeListGetRawString(const xmlDoc *doc, const xmlNode *list, int inLine) { - const xmlNode *node = list; - xmlChar *ret = NULL; - xmlEntityPtr ent; + int escMode = inLine ? 0 : 3;
+ /* backward compatibility */ if (list == NULL) - return (NULL); - - while (node != NULL) { - if ((node->type == XML_TEXT_NODE) || - (node->type == XML_CDATA_SECTION_NODE)) { - if (inLine) { - ret = xmlStrcat(ret, node->content); - } else { - xmlChar *buffer; + return(NULL);
- buffer = xmlEncodeSpecialChars(doc, node->content); - if (buffer != NULL) { - ret = xmlStrcat(ret, buffer); - xmlFree(buffer); - } - } - } else if (node->type == XML_ENTITY_REF_NODE) { - if (inLine) { - ent = xmlGetDocEntity(doc, node->name); - if (ent != NULL) { - xmlChar *buffer; - - /* an entity content can be any "well balanced chunk", - * i.e. the result of the content [43] production: - * http://www.w3.org/TR/REC-xml#NT-content. - * So it can contain text, CDATA section or nested - * entity reference nodes (among others). - * -> we recursive call xmlNodeListGetRawString() - * which handles these types */ - buffer = - xmlNodeListGetRawString(doc, ent->children, 1); - if (buffer != NULL) { - ret = xmlStrcat(ret, buffer); - xmlFree(buffer); - } - } else { - ret = xmlStrcat(ret, node->content); - } - } else { - xmlChar buf[2]; - - buf[0] = '&'; - buf[1] = 0; - ret = xmlStrncat(ret, buf, 1); - ret = xmlStrcat(ret, node->name); - buf[0] = ';'; - buf[1] = 0; - ret = xmlStrncat(ret, buf, 1); - } - } -#if 0 - else { - xmlGenericError(xmlGenericErrorContext, - "xmlGetNodeListString : invalid node type %d\n", - node->type); - } -#endif - node = node->next; - } - return (ret); + return(xmlNodeListGetStringInternal((xmlDocPtr) doc, list, escMode)); } #endif /* LIBXML_TREE_ENABLED */
@@ -1855,7 +1684,6 @@ xmlNewPropInternal(xmlNodePtr node, xmlNsPtr ns, (node->doc->dict == NULL) || (!(xmlDictOwns(node->doc->dict, name))))) xmlFree((xmlChar *) name); - xmlTreeErrMemory("building attribute"); return (NULL); } memset(cur, 0, sizeof(xmlAttr)); @@ -1873,6 +1701,8 @@ xmlNewPropInternal(xmlNodePtr node, xmlNsPtr ns, cur->name = (xmlChar *) xmlDictLookup(doc->dict, name, -1); else cur->name = xmlStrdup(name); + if (cur->name == NULL) + goto error; } else cur->name = name;
@@ -1880,6 +1710,8 @@ xmlNewPropInternal(xmlNodePtr node, xmlNsPtr ns, xmlNodePtr tmp;
cur->children = xmlNewDocText(doc, value); + if (cur->children == NULL) + goto error; cur->last = NULL; tmp = cur->children; while (tmp != NULL) { @@ -1888,6 +1720,15 @@ xmlNewPropInternal(xmlNodePtr node, xmlNsPtr ns, cur->last = tmp; tmp = tmp->next; } + + if (doc != NULL) { + int res = xmlIsID(doc, node, cur); + + if (res < 0) + goto error; + if ((res == 1) && (xmlAddIDSafe(cur, value) < 0)) + goto error; + } }
/* @@ -1906,25 +1747,33 @@ xmlNewPropInternal(xmlNodePtr node, xmlNsPtr ns, } }
- if ((value != NULL) && (node != NULL) && - (xmlIsID(node->doc, node, cur) == 1)) - xmlAddID(NULL, node->doc, value, cur); - if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) xmlRegisterNodeDefaultValue((xmlNodePtr) cur); return (cur); + +error: + xmlFreeProp(cur); + return(NULL); }
#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \ defined(LIBXML_SCHEMAS_ENABLED) /** * xmlNewProp: - * @node: the holding node + * @node: the parent node (optional) * @name: the name of the attribute - * @value: the value of the attribute + * @value: the value of the attribute (optional) + * + * Create an attribute node. * - * Create a new property carried by a node. - * Returns a pointer to the attribute + * If provided, @value should be a raw, unescaped string. + * + * If @node is provided, the created attribute will be appended without + * checking for duplicate names. It is an error if @node is not an + * element. + * + * Returns a pointer to the attribute or NULL if arguments are invalid + * or a memory allocation failed. */ xmlAttrPtr xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) { @@ -1939,13 +1788,21 @@ xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
/** * xmlNewNsProp: - * @node: the holding node - * @ns: the namespace - * @name: the name of the attribute - * @value: the value of the attribute + * @node: the parent node (optional) + * @ns: the namespace (optional) + * @name: the local name of the attribute + * @value: the value of the attribute (optional) + * + * Create an attribute object. * - * Create a new property tagged with a namespace and carried by a node. - * Returns a pointer to the attribute + * If provided, @value should be a raw, unescaped string. + * + * If @node is provided, the created attribute will be appended without + * checking for duplicate names. It is an error if @node is not an + * element. + * + * Returns a pointer to the attribute or NULL if arguments are invalid + * or a memory allocation failed. */ xmlAttrPtr xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name, @@ -1960,13 +1817,17 @@ xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
/** * xmlNewNsPropEatName: - * @node: the holding node - * @ns: the namespace - * @name: the name of the attribute - * @value: the value of the attribute + * @node: the parent node (optional) + * @ns: the namespace (optional) + * @name: the local name of the attribute + * @value: the value of the attribute (optional) + * + * Like xmlNewNsProp, but the @name string will be used directly + * without making a copy. Takes ownership of @name which will also + * be freed on error. * - * Create a new property tagged with a namespace and carried by a node. - * Returns a pointer to the attribute + * Returns a pointer to the attribute or NULL if arguments are invalid + * or a memory allocation failed. */ xmlAttrPtr xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name, @@ -1981,17 +1842,19 @@ xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name,
/** * xmlNewDocProp: - * @doc: the document + * @doc: the target document (optional) * @name: the name of the attribute - * @value: the value of the attribute + * @value: attribute value with XML references (optional) + * + * Create an attribute object. * - * Create a new property carried by a document. - * NOTE: @value is supposed to be a piece of XML CDATA, so it allows entity - * references, but XML special chars need to be escaped first by using - * xmlEncodeEntitiesReentrant(). Use xmlNewProp() if you don't need - * entities support. + * If provided, @value is expected to be a valid XML attribute value + * possibly containing character and entity references. Syntax errors + * and references to undeclared entities are ignored silently. + * If you want to pass a raw string, see xmlNewProp. * - * Returns a pointer to the attribute + * Returns a pointer to the attribute or NULL if arguments are invalid + * or a memory allocation failed. */ xmlAttrPtr xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) { @@ -2005,10 +1868,8 @@ xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) { * Allocate a new property and fill the fields. */ cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr)); - if (cur == NULL) { - xmlTreeErrMemory("building attribute"); + if (cur == NULL) return(NULL); - } memset(cur, 0, sizeof(xmlAttr)); cur->type = XML_ATTRIBUTE_NODE;
@@ -2016,32 +1877,28 @@ xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) { cur->name = xmlDictLookup(doc->dict, name, -1); else cur->name = xmlStrdup(name); + if (cur->name == NULL) + goto error; cur->doc = doc; if (value != NULL) { - xmlNodePtr tmp; - - cur->children = xmlStringGetNodeList(doc, value); - cur->last = NULL; - - tmp = cur->children; - while (tmp != NULL) { - tmp->parent = (xmlNodePtr) cur; - if (tmp->next == NULL) - cur->last = tmp; - tmp = tmp->next; - } + if (xmlNodeParseContent((xmlNodePtr) cur, value, -1) < 0) + goto error; }
if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) xmlRegisterNodeDefaultValue((xmlNodePtr)cur); return(cur); + +error: + xmlFreeProp(cur); + return(NULL); }
/** * xmlFreePropList: - * @cur: the first property in the list + * @cur: the first attribute in the list * - * Free a property and all its siblings, all the children are freed too. + * Free an attribute list including all children. */ void xmlFreePropList(xmlAttrPtr cur) { @@ -2058,7 +1915,7 @@ xmlFreePropList(xmlAttrPtr cur) { * xmlFreeProp: * @cur: an attribute * - * Free one attribute, all the content is freed too + * Free an attribute including all children. */ void xmlFreeProp(xmlAttrPtr cur) { @@ -2083,10 +1940,14 @@ xmlFreeProp(xmlAttrPtr cur) { * xmlRemoveProp: * @cur: an attribute * - * Unlink and free one attribute, all the content is freed too - * Note this doesn't work for namespace definition attributes + * Unlink and free an attribute including all children. + * + * Note this doesn't work for namespace declarations. * - * Returns 0 if success and -1 in case of error. + * The attribute must have a non-NULL parent pointer. + * + * Returns 0 on success or -1 if the attribute was not found or + * arguments are invalid. */ int xmlRemoveProp(xmlAttrPtr cur) { @@ -2120,12 +1981,14 @@ xmlRemoveProp(xmlAttrPtr cur) {
/** * xmlNewDocPI: - * @doc: the target document - * @name: the processing instruction name - * @content: the PI content + * @doc: the target document (optional) + * @name: the processing instruction target + * @content: the PI content (optional) * - * Creation of a processing instruction element. - * Returns a pointer to the new node object. + * Create a processing instruction object. + * + * Returns a pointer to the new node object or NULL if arguments are + * invalid or a memory allocation failed. */ xmlNodePtr xmlNewDocPI(xmlDocPtr doc, const xmlChar *name, const xmlChar *content) { @@ -2139,37 +2002,44 @@ xmlNewDocPI(xmlDocPtr doc, const xmlChar *name, const xmlChar *content) { * Allocate a new node and fill the fields. */ cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); - if (cur == NULL) { - xmlTreeErrMemory("building PI"); + if (cur == NULL) return(NULL); - } memset(cur, 0, sizeof(xmlNode)); cur->type = XML_PI_NODE; + cur->doc = doc;
if ((doc != NULL) && (doc->dict != NULL)) cur->name = xmlDictLookup(doc->dict, name, -1); else cur->name = xmlStrdup(name); + if (cur->name == NULL) + goto error; if (content != NULL) { cur->content = xmlStrdup(content); + if (cur->content == NULL) + goto error; } - cur->doc = doc;
if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) xmlRegisterNodeDefaultValue((xmlNodePtr)cur); return(cur); + +error: + xmlFreeNode(cur); + return(NULL); }
/** * xmlNewPI: - * @name: the processing instruction name - * @content: the PI content + * @name: the processing instruction target + * @content: the PI content (optional) * - * Creation of a processing instruction element. + * Create a processing instruction node. * * Use of this function is DISCOURAGED in favor of xmlNewDocPI. * - * Returns a pointer to the new node object. + * Returns a pointer to the new node object or NULL if arguments are + * invalid or a memory allocation failed. */ xmlNodePtr xmlNewPI(const xmlChar *name, const xmlChar *content) { @@ -2178,116 +2048,122 @@ xmlNewPI(const xmlChar *name, const xmlChar *content) {
/** * xmlNewNode: - * @ns: namespace if any + * @ns: namespace (optional) * @name: the node name * - * Creation of a new node element. @ns is optional (NULL). + * Create an element node. * * Use of this function is DISCOURAGED in favor of xmlNewDocNode. * - * Returns a pointer to the new node object. Uses xmlStrdup() to make - * copy of @name. + * Returns a pointer to the new node object or NULL if arguments are + * invalid or a memory allocation failed. */ xmlNodePtr xmlNewNode(xmlNsPtr ns, const xmlChar *name) { - xmlNodePtr cur; - - if (name == NULL) { - return(NULL); - } - - /* - * Allocate a new node and fill the fields. - */ - cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); - if (cur == NULL) { - xmlTreeErrMemory("building node"); - return(NULL); - } - memset(cur, 0, sizeof(xmlNode)); - cur->type = XML_ELEMENT_NODE; - - cur->name = xmlStrdup(name); - cur->ns = ns; - - if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) - xmlRegisterNodeDefaultValue(cur); - return(cur); + return(xmlNewDocNode(NULL, ns, name, NULL)); }
/** * xmlNewNodeEatName: - * @ns: namespace if any + * @ns: namespace (optional) * @name: the node name * - * Creation of a new node element. @ns is optional (NULL). + * Create an element node. * * Use of this function is DISCOURAGED in favor of xmlNewDocNodeEatName. * - * Returns a pointer to the new node object, with pointer @name as - * new node's name. Use xmlNewNode() if a copy of @name string is - * is needed as new node's name. + * Like xmlNewNode, but the @name string will be used directly + * without making a copy. Takes ownership of @name which will also + * be freed on error. + * + * Returns a pointer to the new node object or NULL if arguments are + * invalid or a memory allocation failed. */ xmlNodePtr xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) { - xmlNodePtr cur; + return(xmlNewDocNodeEatName(NULL, ns, name, NULL)); +}
- if (name == NULL) { - return(NULL); - } +static xmlNodePtr +xmlNewElem(xmlDocPtr doc, xmlNsPtr ns, const xmlChar *name, + const xmlChar *content) { + xmlNodePtr cur;
- /* - * Allocate a new node and fill the fields. - */ cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); - if (cur == NULL) { - xmlTreeErrMemory("building node"); - /* we can't check here that name comes from the doc dictionary */ + if (cur == NULL) return(NULL); - } memset(cur, 0, sizeof(xmlNode)); - cur->type = XML_ELEMENT_NODE;
- cur->name = name; + cur->type = XML_ELEMENT_NODE; + cur->doc = doc; + cur->name = name; cur->ns = ns;
+ if (content != NULL) { + if (xmlNodeParseContent(cur, content, -1) < 0) { + /* Don't free name on error */ + xmlFree(cur); + return(NULL); + } + } + if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) xmlRegisterNodeDefaultValue((xmlNodePtr)cur); + return(cur); }
/** * xmlNewDocNode: - * @doc: the document - * @ns: namespace if any + * @doc: the target document + * @ns: namespace (optional) * @name: the node name - * @content: the XML text content if any + * @content: text content with XML references (optional) + * + * Create an element node. * - * Creation of a new node element within a document. @ns and @content - * are optional (NULL). - * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities - * references, but XML special chars need to be escaped first by using - * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't - * need entities support. + * If provided, @content is expected to be a valid XML attribute value + * possibly containing character and entity references. Syntax errors + * and references to undeclared entities are ignored silently. + * Only references are handled, nested elements, comments or PIs are + * not. See xmlNewDocRawNode for an alternative. * - * Returns a pointer to the new node object. + * General notes on object creation: + * + * Each node and all its children are associated with the same + * document. The document should be provided when creating nodes to + * avoid a performance penalty when adding the node to a document + * tree. Note that a document only owns nodes reachable from the root + * node. Unlinked subtrees must be freed manually. + * + * Returns a pointer to the new node object or NULL if arguments are + * invalid or a memory allocation failed. */ xmlNodePtr xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns, const xmlChar *name, const xmlChar *content) { xmlNodePtr cur; + xmlChar *copy;
- if ((doc != NULL) && (doc->dict != NULL)) - cur = xmlNewNodeEatName(ns, (xmlChar *) - xmlDictLookup(doc->dict, name, -1)); - else - cur = xmlNewNode(ns, name); - if (cur != NULL) { - cur->doc = doc; - if (content != NULL) { - cur->children = xmlStringGetNodeList(doc, content); - UPDATE_LAST_CHILD_AND_PARENT(cur) - } + if (name == NULL) + return(NULL); + + if ((doc != NULL) && (doc->dict != NULL)) { + const xmlChar *dictName = xmlDictLookup(doc->dict, name, -1); + + if (dictName == NULL) + return(NULL); + return(xmlNewElem(doc, ns, dictName, content)); + } + + copy = xmlStrdup(name); + if (copy == NULL) + return(NULL); + + cur = xmlNewElem(doc, ns, copy, content); + if (cur == NULL) { + xmlFree(copy); + return(NULL); }
return(cur); @@ -2295,54 +2171,55 @@ xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
/** * xmlNewDocNodeEatName: - * @doc: the document - * @ns: namespace if any + * @doc: the target document + * @ns: namespace (optional) * @name: the node name - * @content: the XML text content if any + * @content: text content with XML references (optional) + * + * Create an element node. * - * Creation of a new node element within a document. @ns and @content - * are optional (NULL). - * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities - * references, but XML special chars need to be escaped first by using - * xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't - * need entities support. + * Like xmlNewDocNode, but the @name string will be used directly + * without making a copy. Takes ownership of @name which will also + * be freed on error. * - * Returns a pointer to the new node object. + * Returns a pointer to the new node object or NULL if arguments are + * invalid or a memory allocation failed. */ xmlNodePtr xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns, - xmlChar *name, const xmlChar *content) { + xmlChar *name, const xmlChar *content) { xmlNodePtr cur;
- cur = xmlNewNodeEatName(ns, name); - if (cur != NULL) { - cur->doc = doc; - if (content != NULL) { - cur->children = xmlStringGetNodeList(doc, content); - UPDATE_LAST_CHILD_AND_PARENT(cur) - } - } else { - /* if name don't come from the doc dictionary free it here */ - if ((name != NULL) && - ((doc == NULL) || (doc->dict == NULL) || - (!(xmlDictOwns(doc->dict, name))))) - xmlFree(name); + if (name == NULL) + return(NULL); + + cur = xmlNewElem(doc, ns, name, content); + if (cur == NULL) { + /* if name doesn't come from the doc dictionary free it here */ + if ((doc == NULL) || + (doc->dict == NULL) || + (!xmlDictOwns(doc->dict, name))) + xmlFree(name); + return(NULL); } + return(cur); }
#ifdef LIBXML_TREE_ENABLED /** * xmlNewDocRawNode: - * @doc: the document - * @ns: namespace if any + * @doc: the target document + * @ns: namespace (optional) * @name: the node name - * @content: the text content if any + * @content: raw text content (optional) + * + * Create an element node. * - * Creation of a new node element within a document. @ns and @content - * are optional (NULL). + * If provided, @value should be a raw, unescaped string. * - * Returns a pointer to the new node object. + * Returns a pointer to the new node object or NULL if arguments are + * invalid or a memory allocation failed. */ xmlNodePtr xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns, @@ -2353,8 +2230,17 @@ xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns, if (cur != NULL) { cur->doc = doc; if (content != NULL) { - cur->children = xmlNewDocText(doc, content); - UPDATE_LAST_CHILD_AND_PARENT(cur) + xmlNodePtr text; + + text = xmlNewDocText(doc, content); + if (text == NULL) { + xmlFreeNode(cur); + return(NULL); + } + + cur->children = text; + cur->last = text; + text->parent = cur; } } return(cur); @@ -2362,10 +2248,12 @@ xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
/** * xmlNewDocFragment: - * @doc: the document owning the fragment + * @doc: the target document (optional) * - * Creation of a new Fragment node. - * Returns a pointer to the new node object. + * Create a document fragment node. + * + * Returns a pointer to the new node object or NULL if a memory + * allocation failed. */ xmlNodePtr xmlNewDocFragment(xmlDocPtr doc) { @@ -2375,10 +2263,8 @@ xmlNewDocFragment(xmlDocPtr doc) { * Allocate a new DocumentFragment node and fill the fields. */ cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); - if (cur == NULL) { - xmlTreeErrMemory("building fragment"); + if (cur == NULL) return(NULL); - } memset(cur, 0, sizeof(xmlNode)); cur->type = XML_DOCUMENT_FRAG_NODE;
@@ -2392,13 +2278,14 @@ xmlNewDocFragment(xmlDocPtr doc) {
/** * xmlNewText: - * @content: the text content + * @content: raw text content (optional) * - * Creation of a new text node. + * Create a text node. * * Use of this function is DISCOURAGED in favor of xmlNewDocText. * - * Returns a pointer to the new node object. + * Returns a pointer to the new node object or NULL if a memory + * allocation failed. */ xmlNodePtr xmlNewText(const xmlChar *content) { @@ -2408,83 +2295,77 @@ xmlNewText(const xmlChar *content) { * Allocate a new node and fill the fields. */ cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); - if (cur == NULL) { - xmlTreeErrMemory("building text"); + if (cur == NULL) return(NULL); - } memset(cur, 0, sizeof(xmlNode)); cur->type = XML_TEXT_NODE;
cur->name = xmlStringText; if (content != NULL) { cur->content = xmlStrdup(content); + if (cur->content == NULL) + goto error; }
if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) xmlRegisterNodeDefaultValue(cur); return(cur); + +error: + xmlFreeNode(cur); + return(NULL); }
#ifdef LIBXML_TREE_ENABLED /** * xmlNewTextChild: * @parent: the parent node - * @ns: a namespace if any + * @ns: a namespace (optional) * @name: the name of the child - * @content: the text content of the child if any. + * @content: raw text content of the child (optional) + * + * Create a new child element and append it to a parent element. + * + * If @ns is NULL, the newly created element inherits the namespace + * of the parent. * - * Creation of a new child element, added at the end of @parent children list. - * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly - * created element inherits the namespace of @parent. If @content is non NULL, - * a child TEXT node will be created containing the string @content. - * NOTE: Use xmlNewChild() if @content will contain entities that need to be - * preserved. Use this function, xmlNewTextChild(), if you need to ensure that - * reserved XML chars that might appear in @content, such as the ampersand, - * greater-than or less-than signs, are automatically replaced by their XML - * escaped entity representations. + * If @content is provided, a text node will be added to the child + * element, see xmlNewDocRawNode. * - * Returns a pointer to the new node object. + * Returns a pointer to the new node object or NULL if arguments + * are invalid or a memory allocation failed. */ xmlNodePtr xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns, const xmlChar *name, const xmlChar *content) { xmlNodePtr cur, prev;
- if (parent == NULL) { + if ((parent == NULL) || (name == NULL)) return(NULL); - }
- if (name == NULL) { - return(NULL); - } + switch (parent->type) { + case XML_DOCUMENT_NODE: + case XML_HTML_DOCUMENT_NODE: + case XML_DOCUMENT_FRAG_NODE: + break;
- /* - * Allocate a new node - */ - if (parent->type == XML_ELEMENT_NODE) { - if (ns == NULL) - cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content); - else - cur = xmlNewDocRawNode(parent->doc, ns, name, content); - } else if ((parent->type == XML_DOCUMENT_NODE) || - (parent->type == XML_HTML_DOCUMENT_NODE)) { - if (ns == NULL) - cur = xmlNewDocRawNode((xmlDocPtr) parent, NULL, name, content); - else - cur = xmlNewDocRawNode((xmlDocPtr) parent, ns, name, content); - } else if (parent->type == XML_DOCUMENT_FRAG_NODE) { - cur = xmlNewDocRawNode( parent->doc, ns, name, content); - } else { - return(NULL); + case XML_ELEMENT_NODE: + if (ns == NULL) + ns = parent->ns; + break; + + default: + return(NULL); } - if (cur == NULL) return(NULL); + + cur = xmlNewDocRawNode(parent->doc, ns, name, content); + if (cur == NULL) + return(NULL);
/* * add the new element at the end of the children list. */ - cur->type = XML_ELEMENT_NODE; cur->parent = parent; - cur->doc = parent->doc; if (parent->children == NULL) { parent->children = cur; parent->last = cur; @@ -2500,55 +2381,92 @@ xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns, #endif /* LIBXML_TREE_ENABLED */
/** - * xmlNewCharRef: - * @doc: the document - * @name: the char ref string, starting with # or "&# ... ;" + * xmlNewEntityRef: + * @doc: the target document (optional) + * @name: the entity name * - * Creation of a new character reference node. - * Returns a pointer to the new node object. + * Create an empty entity reference node. This function doesn't attempt + * to look up the entity in @doc. + * + * @name is consumed. + * + * Returns a pointer to the new node object or NULL if arguments are + * invalid or a memory allocation failed. */ -xmlNodePtr -xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) { +static xmlNodePtr +xmlNewEntityRef(xmlDocPtr doc, xmlChar *name) { xmlNodePtr cur;
- if (name == NULL) - return(NULL); - /* * Allocate a new node and fill the fields. */ cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); if (cur == NULL) { - xmlTreeErrMemory("building character reference"); + xmlFree(name); return(NULL); } memset(cur, 0, sizeof(xmlNode)); cur->type = XML_ENTITY_REF_NODE; - cur->doc = doc; + cur->name = name; + + if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) + xmlRegisterNodeDefaultValue(cur); + + return(cur); +} + +/** + * xmlNewCharRef: + * @doc: the target document (optional) + * @name: the entity name + * + * This function is MISNAMED. It doesn't create a character reference + * but an entity reference. + * + * Create an empty entity reference node. This function doesn't attempt + * to look up the entity in @doc. + * + * Entity names like '&entity;' are handled as well. + * + * Returns a pointer to the new node object or NULL if arguments are + * invalid or a memory allocation failed. + */ +xmlNodePtr +xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) { + xmlChar *copy; + + if (name == NULL) + return(NULL); + if (name[0] == '&') { int len; name++; len = xmlStrlen(name); if (name[len - 1] == ';') - cur->name = xmlStrndup(name, len - 1); + copy = xmlStrndup(name, len - 1); else - cur->name = xmlStrndup(name, len); + copy = xmlStrndup(name, len); } else - cur->name = xmlStrdup(name); + copy = xmlStrdup(name); + if (copy == NULL) + return(NULL);
- if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) - xmlRegisterNodeDefaultValue(cur); - return(cur); + return(xmlNewEntityRef(doc, copy)); }
/** * xmlNewReference: - * @doc: the document - * @name: the reference name, or the reference string with & and ; + * @doc: the target document (optional) + * @name: the entity name + * + * Create a new entity reference node, linking the result with the + * entity in @doc if found. * - * Creation of a new reference node. - * Returns a pointer to the new node object. + * Entity names like '&entity;' are handled as well. + * + * Returns a pointer to the new node object or NULL if arguments are + * invalid or a memory allocation failed. */ xmlNodePtr xmlNewReference(const xmlDoc *doc, const xmlChar *name) { @@ -2562,10 +2480,8 @@ xmlNewReference(const xmlDoc *doc, const xmlChar *name) { * Allocate a new node and fill the fields. */ cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); - if (cur == NULL) { - xmlTreeErrMemory("building reference"); + if (cur == NULL) return(NULL); - } memset(cur, 0, sizeof(xmlNode)); cur->type = XML_ENTITY_REF_NODE;
@@ -2580,6 +2496,8 @@ xmlNewReference(const xmlDoc *doc, const xmlChar *name) { cur->name = xmlStrndup(name, len); } else cur->name = xmlStrdup(name); + if (cur->name == NULL) + goto error;
ent = xmlGetDocEntity(doc, cur->name); if (ent != NULL) { @@ -2596,15 +2514,21 @@ xmlNewReference(const xmlDoc *doc, const xmlChar *name) { if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) xmlRegisterNodeDefaultValue(cur); return(cur); + +error: + xmlFreeNode(cur); + return(NULL); }
/** * xmlNewDocText: - * @doc: the document - * @content: the text content + * @doc: the target document + * @content: raw text content (optional) * - * Creation of a new text node within a document. - * Returns a pointer to the new node object. + * Create a new text node. + * + * Returns a pointer to the new node object or NULL if a memory + * allocation failed. */ xmlNodePtr xmlNewDocText(const xmlDoc *doc, const xmlChar *content) { @@ -2617,13 +2541,13 @@ xmlNewDocText(const xmlDoc *doc, const xmlChar *content) {
/** * xmlNewTextLen: - * @content: the text content - * @len: the text len. + * @content: raw text content (optional) + * @len: size of text content * * Use of this function is DISCOURAGED in favor of xmlNewDocTextLen. * - * Creation of a new text node with an extra parameter for the content's length - * Returns a pointer to the new node object. + * Returns a pointer to the new node object or NULL if a memory + * allocation failed. */ xmlNodePtr xmlNewTextLen(const xmlChar *content, int len) { @@ -2633,16 +2557,18 @@ xmlNewTextLen(const xmlChar *content, int len) { * Allocate a new node and fill the fields. */ cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); - if (cur == NULL) { - xmlTreeErrMemory("building text"); + if (cur == NULL) return(NULL); - } memset(cur, 0, sizeof(xmlNode)); cur->type = XML_TEXT_NODE;
cur->name = xmlStringText; if (content != NULL) { cur->content = xmlStrndup(content, len); + if (cur->content == NULL) { + xmlFreeNode(cur); + return(NULL); + } }
if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) @@ -2652,13 +2578,14 @@ xmlNewTextLen(const xmlChar *content, int len) {
/** * xmlNewDocTextLen: - * @doc: the document - * @content: the text content - * @len: the text len. + * @doc: the target document + * @content: raw text content (optional) + * @len: size of text content + * + * Create a new text node. * - * Creation of a new text node with an extra content length parameter. The - * text node pertain to a given document. - * Returns a pointer to the new node object. + * Returns a pointer to the new node object or NULL if a memory + * allocation failed. */ xmlNodePtr xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) { @@ -2671,12 +2598,14 @@ xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
/** * xmlNewComment: - * @content: the comment content + * @content: the comment content (optional) * * Use of this function is DISCOURAGED in favor of xmlNewDocComment. * - * Creation of a new node containing a comment. - * Returns a pointer to the new node object. + * Create a comment node. + * + * Returns a pointer to the new node object or NULL if a memory + * allocation failed. */ xmlNodePtr xmlNewComment(const xmlChar *content) { @@ -2686,31 +2615,37 @@ xmlNewComment(const xmlChar *content) { * Allocate a new node and fill the fields. */ cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); - if (cur == NULL) { - xmlTreeErrMemory("building comment"); + if (cur == NULL) return(NULL); - } memset(cur, 0, sizeof(xmlNode)); cur->type = XML_COMMENT_NODE;
cur->name = xmlStringComment; if (content != NULL) { cur->content = xmlStrdup(content); + if (cur->content == NULL) + goto error; }
if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) xmlRegisterNodeDefaultValue(cur); return(cur); + +error: + xmlFreeNode(cur); + return(NULL); }
/** * xmlNewCDataBlock: - * @doc: the document - * @content: the CDATA block content content - * @len: the length of the block + * @doc: the target document (optional) + * @content: raw text content (optional) + * @len: size of text content + * + * Create a CDATA section node. * - * Creation of a new node containing a CDATA block. - * Returns a pointer to the new node object. + * Returns a pointer to the new node object or NULL if a memory + * allocation failed. */ xmlNodePtr xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) { @@ -2720,16 +2655,18 @@ xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) { * Allocate a new node and fill the fields. */ cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); - if (cur == NULL) { - xmlTreeErrMemory("building CDATA"); + if (cur == NULL) return(NULL); - } memset(cur, 0, sizeof(xmlNode)); cur->type = XML_CDATA_SECTION_NODE; cur->doc = doc;
if (content != NULL) { cur->content = xmlStrndup(content, len); + if (cur->content == NULL) { + xmlFree(cur); + return(NULL); + } }
if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) @@ -2742,8 +2679,10 @@ xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) { * @doc: the document * @content: the comment content * - * Creation of a new node containing a comment within a document. - * Returns a pointer to the new node object. + * Create a comment node. + * + * Returns a pointer to the new node object or NULL if a memory + * allocation failed. */ xmlNodePtr xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) { @@ -2754,164 +2693,293 @@ xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) { return(cur); }
-static const xmlChar *_copyStringForNewDictIfNeeded(xmlDictPtr oldDict, xmlDictPtr newDict, const xmlChar *oldValue) { - const xmlChar *newValue = oldValue; - if (oldValue) { - int oldDictOwnsOldValue = oldDict && (xmlDictOwns(oldDict, oldValue) == 1); - if (oldDictOwnsOldValue) { +static void +xmlRemoveEntity(xmlEntityPtr ent) { + xmlDocPtr doc = ent->doc; + xmlDtdPtr intSubset, extSubset; + + if (doc == NULL) + return; + intSubset = doc->intSubset; + extSubset = doc->extSubset; + + if ((ent->etype == XML_INTERNAL_GENERAL_ENTITY) || + (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY) || + (ent->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY)) { + if (intSubset != NULL) { + if (xmlHashLookup(intSubset->entities, ent->name) == ent) + xmlHashRemoveEntry(intSubset->entities, ent->name, NULL); + } + if (extSubset != NULL) { + if (xmlHashLookup(extSubset->entities, ent->name) == ent) + xmlHashRemoveEntry(extSubset->entities, ent->name, NULL); + } + } else if ((ent->etype == XML_INTERNAL_PARAMETER_ENTITY) || + (ent->etype == XML_EXTERNAL_PARAMETER_ENTITY)) { + if (intSubset != NULL) { + if (xmlHashLookup(intSubset->pentities, ent->name) == ent) + xmlHashRemoveEntry(intSubset->entities, ent->name, NULL); + } + if (extSubset != NULL) { + if (xmlHashLookup(extSubset->pentities, ent->name) == ent) + xmlHashRemoveEntry(extSubset->entities, ent->name, NULL); + } + } +} + +static int +xmlNodeSetDoc(xmlNodePtr node, xmlDocPtr doc) { + xmlDocPtr oldDoc; + xmlDictPtr oldDict, newDict; + int ret = 0; + + /* + * Remove name and content from old dictionary + */ + + oldDoc = node->doc; + oldDict = oldDoc ? oldDoc->dict : NULL; + newDict = doc ? doc->dict : NULL; + + if ((oldDict != NULL) && (oldDict != newDict)) { + if ((node->name != NULL) && + ((node->type == XML_ELEMENT_NODE) || + (node->type == XML_ATTRIBUTE_NODE) || + (node->type == XML_PI_NODE) || + (node->type == XML_ENTITY_REF_NODE)) && + (xmlDictOwns(oldDict, node->name))) { if (newDict) - newValue = xmlDictLookup(newDict, oldValue, -1); + node->name = xmlDictLookup(newDict, node->name, -1); else - newValue = xmlStrdup(oldValue); + node->name = xmlStrdup(node->name); + if (node->name == NULL) + ret = -1; + } + + if ((node->content != NULL) && + ((node->type == XML_TEXT_NODE) || + (node->type == XML_CDATA_SECTION_NODE)) && + (xmlDictOwns(oldDict, node->content))) { + node->content = xmlStrdup(node->content); + if (node->content == NULL) + ret = -1; + } + } + + switch (node->type) { + case XML_ATTRIBUTE_NODE: { + xmlAttrPtr attr = (xmlAttrPtr) node; + + /* + * Handle IDs + * + * TODO: ID attributes should also be added to the new + * document, but it's not clear how to handle clashes. + */ + if (attr->atype == XML_ATTRIBUTE_ID) + xmlRemoveID(oldDoc, attr); + + break; } + + case XML_ENTITY_REF_NODE: + /* + * Handle entity references + */ + node->children = NULL; + node->last = NULL; + node->content = NULL; + + if ((doc != NULL) && + ((doc->intSubset != NULL) || (doc->extSubset != NULL))) { + xmlEntityPtr ent; + + /* + * Assign new entity node if available + */ + ent = xmlGetDocEntity(doc, node->name); + if (ent != NULL) { + node->children = (xmlNodePtr) ent; + node->last = (xmlNodePtr) ent; + node->content = ent->content; + } + } + + break; + + case XML_DTD_NODE: + if (oldDoc != NULL) { + if (oldDoc->intSubset == (xmlDtdPtr) node) + oldDoc->intSubset = NULL; + if (oldDoc->extSubset == (xmlDtdPtr) node) + oldDoc->extSubset = NULL; + } + + break; + + case XML_ENTITY_DECL: + xmlRemoveEntity((xmlEntityPtr) node); + break; + + /* + * TODO: + * - Remove element decls from doc->elements + * - Remove attribtue decls form doc->attributes + */ + + default: + break; } - return newValue; + + /* + * Set new document + */ + node->doc = doc; + + return(ret); }
/** * xmlSetTreeDoc: - * @tree: the top element - * @doc: the document + * @tree: root of a subtree + * @doc: new document + * + * This is an internal function which shouldn't be used. It is + * invoked by functions like xmlAddChild, xmlAddSibling or + * xmlReplaceNode. @tree must be the root node of an unlinked + * subtree. + * + * Associate all nodes in a tree with a new document. + * + * Also copy strings from the old document's dictionary and + * remove ID attributes from the old ID table. * - * update all nodes under the tree to point to the right document + * Returns 0 on success. If a memory allocation fails, returns -1. + * The whole tree will be updated on failure but some strings + * may be lost. */ -void +int xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) { - xmlAttrPtr prop; + int ret = 0;
if ((tree == NULL) || (tree->type == XML_NAMESPACE_DECL)) - return; - if (tree->doc != doc) { - xmlDictPtr oldTreeDict = tree->doc ? tree->doc->dict : NULL; - xmlDictPtr newDict = doc ? doc->dict : NULL; - - if(tree->type == XML_ELEMENT_NODE) { - prop = tree->properties; - while (prop != NULL) { - if (prop->atype == XML_ATTRIBUTE_ID) { - xmlRemoveID(tree->doc, prop); - } + return(0); + if (tree->doc == doc) + return(0);
- if (prop->doc != doc) { - xmlDictPtr oldPropDict = prop->doc ? prop->doc->dict : NULL; - prop->name = _copyStringForNewDictIfNeeded(oldPropDict, newDict, prop->name); - prop->doc = doc; - } - xmlSetListDoc(prop->children, doc); + if (tree->type == XML_ELEMENT_NODE) { + xmlAttrPtr prop = tree->properties;
- /* - * TODO: ID attributes should be also added to the new - * document, but this breaks things like xmlReplaceNode. - * The underlying problem is that xmlRemoveID is only called - * if a node is destroyed, not if it's unlinked. - */ -#if 0 - if (xmlIsID(doc, tree, prop)) { - xmlChar *idVal = xmlNodeListGetString(doc, prop->children, - 1); - xmlAddID(NULL, doc, idVal, prop); - } -#endif + while (prop != NULL) { + if (prop->children != NULL) { + if (xmlSetListDoc(prop->children, doc) < 0) + ret = -1; + }
- prop = prop->next; - } - } - if (tree->type == XML_ENTITY_REF_NODE) { - /* - * Clear 'children' which points to the entity declaration - * from the original document. - */ - tree->children = NULL; - } else if (tree->children != NULL) { - xmlSetListDoc(tree->children, doc); + if (xmlNodeSetDoc((xmlNodePtr) prop, doc) < 0) + ret = -1; + + prop = prop->next; } + }
- tree->name = _copyStringForNewDictIfNeeded(oldTreeDict, newDict, tree->name); - tree->content = (xmlChar *)_copyStringForNewDictIfNeeded(oldTreeDict, NULL, tree->content); - /* FIXME: tree->ns should be updated as in xmlStaticCopyNode(). */ - tree->doc = doc; + if ((tree->children != NULL) && + (tree->type != XML_ENTITY_REF_NODE)) { + if (xmlSetListDoc(tree->children, doc) < 0) + ret = -1; } + + if (xmlNodeSetDoc(tree, doc) < 0) + ret = -1; + + return(ret); }
/** * xmlSetListDoc: - * @list: the first element - * @doc: the document + * @list: a node list + * @doc: new document + * + * Associate all subtrees in @list with a new document. * - * update all nodes in the list to point to the right document + * Internal function, see xmlSetTreeDoc. + * + * Returns 0 on success. If a memory allocation fails, returns -1. + * All subtrees will be updated on failure but some strings + * may be lost. */ -void +int xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) { xmlNodePtr cur; + int ret = 0;
if ((list == NULL) || (list->type == XML_NAMESPACE_DECL)) - return; + return(0); + cur = list; while (cur != NULL) { - if (cur->doc != doc) - xmlSetTreeDoc(cur, doc); + if (cur->doc != doc) { + if (xmlSetTreeDoc(cur, doc) < 0) + ret = -1; + } cur = cur->next; } + + return(ret); }
#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) /** * xmlNewChild: * @parent: the parent node - * @ns: a namespace if any + * @ns: a namespace (optional) * @name: the name of the child - * @content: the XML content of the child if any. + * @content: text content with XML references (optional) * - * Creation of a new child element, added at the end of @parent children list. - * @ns and @content parameters are optional (NULL). If @ns is NULL, the newly - * created element inherits the namespace of @parent. If @content is non NULL, - * a child list containing the TEXTs and ENTITY_REFs node will be created. - * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity - * references. XML special chars must be escaped first by using - * xmlEncodeEntitiesReentrant(), or xmlNewTextChild() should be used. + * Create a new child element and append it to a parent element. * - * Returns a pointer to the new node object. + * If @ns is NULL, the newly created element inherits the namespace + * of the parent. + * + * If provided, @content is expected to be a valid XML attribute + * value possibly containing character and entity references. Text + * and entity reference node will be added to the child element, + * see xmlNewDocNode. + * + * Returns a pointer to the new node object or NULL if arguments + * are invalid or a memory allocation failed. */ xmlNodePtr xmlNewChild(xmlNodePtr parent, xmlNsPtr ns, const xmlChar *name, const xmlChar *content) { xmlNodePtr cur, prev;
- if (parent == NULL) { + if ((parent == NULL) || (name == NULL)) return(NULL); - }
- if (name == NULL) { - return(NULL); - } + switch (parent->type) { + case XML_DOCUMENT_NODE: + case XML_HTML_DOCUMENT_NODE: + case XML_DOCUMENT_FRAG_NODE: + break;
- /* - * Allocate a new node - */ - if (parent->type == XML_ELEMENT_NODE) { - if (ns == NULL) - cur = xmlNewDocNode(parent->doc, parent->ns, name, content); - else - cur = xmlNewDocNode(parent->doc, ns, name, content); - } else if ((parent->type == XML_DOCUMENT_NODE) || - (parent->type == XML_HTML_DOCUMENT_NODE)) { - if (ns == NULL) - cur = xmlNewDocNode((xmlDocPtr) parent, NULL, name, content); - else - cur = xmlNewDocNode((xmlDocPtr) parent, ns, name, content); - } else if (parent->type == XML_DOCUMENT_FRAG_NODE) { - cur = xmlNewDocNode( parent->doc, ns, name, content); - } else { - return(NULL); + case XML_ELEMENT_NODE: + if (ns == NULL) + ns = parent->ns; + break; + + default: + return(NULL); } - if (cur == NULL) return(NULL); + + cur = xmlNewDocNode(parent->doc, ns, name, content); + if (cur == NULL) + return(NULL);
/* * add the new element at the end of the children list. */ - cur->type = XML_ELEMENT_NODE; cur->parent = parent; - cur->doc = parent->doc; if (parent->children == NULL) { parent->children = cur; parent->last = cur; @@ -2926,261 +2994,274 @@ xmlNewChild(xmlNodePtr parent, xmlNsPtr ns, } #endif /* LIBXML_TREE_ENABLED */
-/** - * xmlAddPropSibling: - * @prev: the attribute to which @prop is added after - * @cur: the base attribute passed to calling function - * @prop: the new attribute - * - * Add a new attribute after @prev using @cur as base attribute. - * When inserting before @cur, @prev is passed as @cur->prev. - * When inserting after @cur, @prev is passed as @cur. - * If an existing attribute is found it is destroyed prior to adding @prop. - * - * See the note regarding namespaces in xmlAddChild. - * - * Returns the attribute being inserted or NULL in case of error. - */ +static void +xmlTextSetContent(xmlNodePtr text, xmlChar *content) { + if ((text->content != NULL) && + (text->content != (xmlChar *) &text->properties)) { + xmlDocPtr doc = text->doc; + + if ((doc == NULL) || + (doc->dict == NULL) || + (!xmlDictOwns(doc->dict, text->content))) + xmlFree(text->content); + } + + text->content = content; + text->properties = NULL; +} + +static int +xmlTextAddContent(xmlNodePtr text, const xmlChar *content, int len) { + xmlChar *merged; + + if (content == NULL) + return(0); + + merged = xmlStrncatNew(text->content, content, len); + if (merged == NULL) + return(-1); + + xmlTextSetContent(text, merged); + return(0); +} + static xmlNodePtr -xmlAddPropSibling(xmlNodePtr prev, xmlNodePtr cur, xmlNodePtr prop) { - xmlAttrPtr attr; +xmlInsertProp(xmlDocPtr doc, xmlNodePtr cur, xmlNodePtr parent, + xmlNodePtr prev, xmlNodePtr next) { + xmlAttrPtr attr;
- if ((cur == NULL) || (cur->type != XML_ATTRIBUTE_NODE) || - (prop == NULL) || (prop->type != XML_ATTRIBUTE_NODE) || - ((prev != NULL) && (prev->type != XML_ATTRIBUTE_NODE))) - return(NULL); + if (((prev != NULL) && (prev->type != XML_ATTRIBUTE_NODE)) || + ((next != NULL) && (next->type != XML_ATTRIBUTE_NODE))) + return(NULL);
- /* check if an attribute with the same name exists */ - if (prop->ns == NULL) - attr = xmlHasNsProp(cur->parent, prop->name, NULL); - else - attr = xmlHasNsProp(cur->parent, prop->name, prop->ns->href); + /* check if an attribute with the same name exists */ + attr = xmlGetPropNodeInternal(parent, cur->name, + cur->ns ? cur->ns->href : NULL, 0);
- if (prop->doc != cur->doc) { - xmlSetTreeDoc(prop, cur->doc); - } - prop->parent = cur->parent; - prop->prev = prev; - if (prev != NULL) { - prop->next = prev->next; - prev->next = prop; - if (prop->next) - prop->next->prev = prop; - } else { - prop->next = cur; - cur->prev = prop; + xmlUnlinkNodeInternal(cur); + + if (cur->doc != doc) { + if (xmlSetTreeDoc(cur, doc) < 0) + return(NULL); + } + + cur->parent = parent; + cur->prev = prev; + cur->next = next; + + if (prev == NULL) { + if (parent != NULL) + parent->properties = (xmlAttrPtr) cur; + } else { + prev->next = cur; + } + if (next != NULL) { + next->prev = cur; + } + + if ((attr != NULL) && (attr != (xmlAttrPtr) cur)) { + /* different instance, destroy it (attributes must be unique) */ + xmlRemoveProp((xmlAttrPtr) attr); + } + + return cur; +} + +static xmlNodePtr +xmlInsertNode(xmlDocPtr doc, xmlNodePtr cur, xmlNodePtr parent, + xmlNodePtr prev, xmlNodePtr next, int coalesce) { + xmlNodePtr oldParent; + + if (cur->type == XML_ATTRIBUTE_NODE) + return xmlInsertProp(doc, cur, parent, prev, next); + + /* + * Coalesce text nodes + */ + if ((coalesce) && (cur->type == XML_TEXT_NODE)) { + if ((prev != NULL) && (prev->type == XML_TEXT_NODE) && + (prev->name == cur->name)) { + if (xmlTextAddContent(prev, cur->content, -1) < 0) + return(NULL); + xmlUnlinkNodeInternal(cur); + xmlFreeNode(cur); + return(prev); } - if (prop->prev == NULL && prop->parent != NULL) - prop->parent->properties = (xmlAttrPtr) prop; - if ((attr != NULL) && (attr->type != XML_ATTRIBUTE_DECL)) { - /* different instance, destroy it (attributes must be unique) */ - xmlRemoveProp((xmlAttrPtr) attr); + + if ((next != NULL) && (next->type == XML_TEXT_NODE) && + (next->name == cur->name)) { + if (cur->content != NULL) { + xmlChar *merged; + + merged = xmlStrncatNew(cur->content, next->content, -1); + if (merged == NULL) + return(NULL); + xmlTextSetContent(next, merged); + } + + xmlUnlinkNodeInternal(cur); + xmlFreeNode(cur); + return(next); } - return prop; + } + + /* Unlink */ + oldParent = cur->parent; + if (oldParent != NULL) { + if (oldParent->children == cur) + oldParent->children = cur->next; + if (oldParent->last == cur) + oldParent->last = cur->prev; + } + if (cur->next != NULL) + cur->next->prev = cur->prev; + if (cur->prev != NULL) + cur->prev->next = cur->next; + + if (cur->doc != doc) { + if (xmlSetTreeDoc(cur, doc) < 0) { + /* + * We shouldn't make any modifications to the inserted + * tree if a memory allocation fails, but that's hard to + * implement. The tree has been moved to the target + * document now but some contents are corrupted. + * Unlinking is the best we can do. + */ + cur->parent = NULL; + cur->prev = NULL; + cur->next = NULL; + return(NULL); + } + } + + cur->parent = parent; + cur->prev = prev; + cur->next = next; + + if (prev == NULL) { + if (parent != NULL) + parent->children = cur; + } else { + prev->next = cur; + } + if (next == NULL) { + if (parent != NULL) + parent->last = cur; + } else { + next->prev = cur; + } + + return(cur); }
/** * xmlAddNextSibling: - * @cur: the child node - * @elem: the new node + * @prev: the target node + * @cur: the new node * - * Add a new node @elem as the next sibling of @cur - * If the new node was already inserted in a document it is - * first unlinked from its existing context. - * As a result of text merging @elem may be freed. - * If the new node is ATTRIBUTE, it is added into properties instead of children. - * If there is an attribute with equal name, it is first destroyed. + * Unlinks @cur and inserts it as next sibling after @prev. * - * See the note regarding namespaces in xmlAddChild. + * Unlike xmlAddChild this function does not merge text nodes. * - * Returns the new node or NULL in case of error. + * If @cur is an attribute node, it is inserted after attribute + * @prev. If the attribute list contains an attribute with a name + * matching @cur, the old attribute is destroyed. + * + * See the notes in xmlAddChild. + * + * Returns @cur or a sibling if @cur was merged. Returns NULL + * if arguments are invalid or a memory allocation failed. */ xmlNodePtr -xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) { - if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) { - return(NULL); - } - if ((elem == NULL) || (elem->type == XML_NAMESPACE_DECL)) { - return(NULL); - } - - if (cur == elem) { +xmlAddNextSibling(xmlNodePtr prev, xmlNodePtr cur) { + if ((prev == NULL) || (prev->type == XML_NAMESPACE_DECL) || + (cur == NULL) || (cur->type == XML_NAMESPACE_DECL) || + (cur == prev)) return(NULL); - } - - xmlUnlinkNode(elem);
- if (elem->type == XML_TEXT_NODE) { - if (cur->type == XML_TEXT_NODE) { - xmlNodeAddContent(cur, elem->content); - xmlFreeNode(elem); - return(cur); - } - if ((cur->next != NULL) && (cur->next->type == XML_TEXT_NODE) && - (cur->name == cur->next->name)) { - xmlChar *tmp; - - tmp = xmlStrdup(elem->content); - tmp = xmlStrcat(tmp, cur->next->content); - xmlNodeSetContent(cur->next, tmp); - xmlFree(tmp); - xmlFreeNode(elem); - return(cur->next); - } - } else if (elem->type == XML_ATTRIBUTE_NODE) { - return xmlAddPropSibling(cur, cur, elem); - } + if (cur == prev->next) + return(cur);
- if (elem->doc != cur->doc) { - xmlSetTreeDoc(elem, cur->doc); - } - elem->parent = cur->parent; - elem->prev = cur; - elem->next = cur->next; - cur->next = elem; - if (elem->next != NULL) - elem->next->prev = elem; - if ((elem->parent != NULL) && (elem->parent->last == cur)) - elem->parent->last = elem; - return(elem); + return(xmlInsertNode(prev->doc, cur, prev->parent, prev, prev->next, 0)); }
#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_HTML_ENABLED) || \ defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) /** * xmlAddPrevSibling: - * @cur: the child node - * @elem: the new node + * @next: the target node + * @cur: the new node + * + * Unlinks @cur and inserts it as previous sibling before @next. * - * Add a new node @elem as the previous sibling of @cur - * merging adjacent TEXT nodes (@elem may be freed) - * If the new node was already inserted in a document it is - * first unlinked from its existing context. - * If the new node is ATTRIBUTE, it is added into properties instead of children. - * If there is an attribute with equal name, it is first destroyed. + * Unlike xmlAddChild this function does not merge text nodes. * - * See the note regarding namespaces in xmlAddChild. + * If @cur is an attribute node, it is inserted before attribute + * @next. If the attribute list contains an attribute with a name + * matching @cur, the old attribute is destroyed. * - * Returns the new node or NULL in case of error. + * See the notes in xmlAddChild. + * + * Returns @cur or a sibling if @cur was merged. Returns NULL + * if arguments are invalid or a memory allocation failed. */ xmlNodePtr -xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) { - if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) { - return(NULL); - } - if ((elem == NULL) || (elem->type == XML_NAMESPACE_DECL)) { +xmlAddPrevSibling(xmlNodePtr next, xmlNodePtr cur) { + if ((next == NULL) || (next->type == XML_NAMESPACE_DECL) || + (cur == NULL) || (cur->type == XML_NAMESPACE_DECL) || + (cur == next)) return(NULL); - } - - if (cur == elem) { - return(NULL); - }
- xmlUnlinkNode(elem); + if (cur == next->prev) + return(cur);
- if (elem->type == XML_TEXT_NODE) { - if (cur->type == XML_TEXT_NODE) { - xmlChar *tmp; - - tmp = xmlStrdup(elem->content); - tmp = xmlStrcat(tmp, cur->content); - xmlNodeSetContent(cur, tmp); - xmlFree(tmp); - xmlFreeNode(elem); - return(cur); - } - if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE) && - (cur->name == cur->prev->name)) { - xmlNodeAddContent(cur->prev, elem->content); - xmlFreeNode(elem); - return(cur->prev); - } - } else if (elem->type == XML_ATTRIBUTE_NODE) { - return xmlAddPropSibling(cur->prev, cur, elem); - } - - if (elem->doc != cur->doc) { - xmlSetTreeDoc(elem, cur->doc); - } - elem->parent = cur->parent; - elem->next = cur; - elem->prev = cur->prev; - cur->prev = elem; - if (elem->prev != NULL) - elem->prev->next = elem; - if ((elem->parent != NULL) && (elem->parent->children == cur)) { - elem->parent->children = elem; - } - return(elem); + return(xmlInsertNode(next->doc, cur, next->parent, next->prev, next, 0)); } #endif /* LIBXML_TREE_ENABLED */
/** * xmlAddSibling: - * @cur: the child node - * @elem: the new node + * @node: the target node + * @cur: the new node * - * Add a new element @elem to the list of siblings of @cur - * merging adjacent TEXT nodes (@elem may be freed) - * If the new element was already inserted in a document it is - * first unlinked from its existing context. + * Unlinks @cur and inserts it as last sibling of @node. * - * See the note regarding namespaces in xmlAddChild. + * If @cur is a text node, it may be merged with an adjacent text + * node and freed. In this case the text node containing the merged + * content is returned. * - * Returns the new element or NULL in case of error. + * If @cur is an attribute node, it is appended to the attribute + * list containing @node. If the attribute list contains an attribute + * with a name matching @cur, the old attribute is destroyed. + * + * See the notes in xmlAddChild. + * + * Returns @cur or a sibling if @cur was merged. Returns NULL + * if arguments are invalid or a memory allocation failed. */ xmlNodePtr -xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) { - xmlNodePtr parent; - - if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) { - return(NULL); - } - - if ((elem == NULL) || (elem->type == XML_NAMESPACE_DECL)) { - return(NULL); - } - - if (cur == elem) { +xmlAddSibling(xmlNodePtr node, xmlNodePtr cur) { + if ((node == NULL) || (node->type == XML_NAMESPACE_DECL) || + (cur == NULL) || (cur->type == XML_NAMESPACE_DECL) || + (cur == node)) return(NULL); - }
/* * Constant time is we can rely on the ->parent->last to find * the last sibling. */ - if ((cur->type != XML_ATTRIBUTE_NODE) && (cur->parent != NULL) && - (cur->parent->children != NULL) && - (cur->parent->last != NULL) && - (cur->parent->last->next == NULL)) { - cur = cur->parent->last; + if ((node->type != XML_ATTRIBUTE_NODE) && (node->parent != NULL)) { + if (node->parent->last != NULL) + node = node->parent->last; } else { - while (cur->next != NULL) cur = cur->next; - } - - xmlUnlinkNode(elem); - - if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE) && - (cur->name == elem->name)) { - xmlNodeAddContent(cur, elem->content); - xmlFreeNode(elem); - return(cur); - } else if (elem->type == XML_ATTRIBUTE_NODE) { - return xmlAddPropSibling(cur, cur, elem); + while (node->next != NULL) + node = node->next; }
- if (elem->doc != cur->doc) { - xmlSetTreeDoc(elem, cur->doc); - } - parent = cur->parent; - elem->prev = cur; - elem->next = NULL; - elem->parent = parent; - cur->next = elem; - if (parent != NULL) - parent->last = elem; + if (cur == node) + return(cur);
- return(elem); + return(xmlInsertNode(node->doc, cur, node->parent, node, NULL, 1)); }
/** @@ -3188,16 +3269,17 @@ xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) { * @parent: the parent node * @cur: the first node in the list * - * Add a list of node at the end of the child list of the parent - * merging adjacent TEXT nodes (@cur may be freed) + * Append a node list to another node. * - * See the note regarding namespaces in xmlAddChild. + * See xmlAddChild. * * Returns the last child or NULL in case of error. */ xmlNodePtr xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) { + xmlNodePtr iter; xmlNodePtr prev; + int oom;
if ((parent == NULL) || (parent->type == XML_NAMESPACE_DECL)) { return(NULL); @@ -3207,9 +3289,15 @@ xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) { return(NULL); }
- if ((cur->doc != NULL) && (parent->doc != NULL) && - (cur->doc != parent->doc)) { + oom = 0; + for (iter = cur; iter != NULL; iter = iter->next) { + if (iter->doc != parent->doc) { + if (xmlSetTreeDoc(iter, parent->doc) < 0) + oom = 1; + } } + if (oom) + return(NULL);
/* * add the first element at the end of the children list. @@ -3218,40 +3306,36 @@ xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) { if (parent->children == NULL) { parent->children = cur; } else { + prev = parent->last; + /* * If cur and parent->last both are TEXT nodes, then merge them. */ if ((cur->type == XML_TEXT_NODE) && - (parent->last->type == XML_TEXT_NODE) && - (cur->name == parent->last->name)) { - xmlNodeAddContent(parent->last, cur->content); + (prev->type == XML_TEXT_NODE) && + (cur->name == prev->name)) { + xmlNodePtr next; + + if (xmlTextAddContent(prev, cur->content, -1) < 0) + return(NULL); + next = cur->next; + xmlFreeNode(cur); /* * if it's the only child, nothing more to be done. */ - if (cur->next == NULL) { - xmlFreeNode(cur); - return(parent->last); - } - prev = cur; - cur = cur->next; - xmlFreeNode(prev); + if (next == NULL) + return(prev); + cur = next; } - prev = parent->last; + prev->next = cur; cur->prev = prev; } while (cur->next != NULL) { cur->parent = parent; - if (cur->doc != parent->doc) { - xmlSetTreeDoc(cur, parent->doc); - } cur = cur->next; } cur->parent = parent; - /* the parent may not be linked to a doc ! */ - if (cur->doc != parent->doc) { - xmlSetTreeDoc(cur, parent->doc); - } parent->last = cur;
return(cur); @@ -3262,130 +3346,87 @@ xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) { * @parent: the parent node * @cur: the child node * - * Add a new node to @parent, at the end of the child (or property) list - * merging adjacent TEXT nodes (in which case @cur is freed) - * If the new node is ATTRIBUTE, it is added into properties instead of children. - * If there is an attribute with equal name, it is first destroyed. + * Unlink @cur and append it to the children of @parent. * - * All tree manipulation functions can safely move nodes within a document. - * But when moving nodes from one document to another, references to - * namespaces in element or attribute nodes are NOT fixed. In this case, - * you MUST call xmlReconciliateNs after the move operation to avoid - * memory errors. + * If @cur is a text node, it may be merged with an adjacent text + * node and freed. In this case the text node containing the merged + * content is returned. * - * Returns the child or NULL in case of error. + * If @cur is an attribute node, it is appended to the attributes of + * @parent. If the attribute list contains an attribute with a name + * matching @elem, the old attribute is destroyed. + * + * General notes: + * + * Move operations like xmlAddChild can cause element or attribute + * nodes to reference namespaces that aren't declared in one of + * their ancestors. This can lead to use-after-free errors if the + * elements containing the declarations are freed later, especially + * when moving nodes from one document to another. You should + * consider calling xmlReconciliateNs after a move operation to + * normalize namespaces. Another option is to call + * xmlDOMWrapAdoptNode with the target parent before moving a node. + * + * For the most part, move operations don't check whether the + * resulting tree structure is valid. Users must make sure that + * parent nodes only receive children of valid types. Inserted + * child nodes must never be an ancestor of the parent node to + * avoid cycles in the tree structure. In general, only + * document, document fragments, elements and attributes + * should be used as parent nodes. + * + * When moving a node between documents and a memory allocation + * fails, the node's content will be corrupted and it will be + * unlinked. In this case, the node must be freed manually. + * + * Moving DTDs between documents isn't supported. + * + * Returns @elem or a sibling if @elem was merged. Returns NULL + * if arguments are invalid or a memory allocation failed. */ xmlNodePtr xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) { xmlNodePtr prev;
- if ((parent == NULL) || (parent->type == XML_NAMESPACE_DECL)) { - return(NULL); - } - - if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) { - return(NULL); - } - - if (parent == cur) { - return(NULL); - } - /* - * If cur is a TEXT node, merge its content with adjacent TEXT nodes - * cur is then freed. - */ - if (cur->type == XML_TEXT_NODE) { - if ((parent->type == XML_TEXT_NODE) && - (parent->content != NULL) && - (parent->name == cur->name)) { - xmlNodeAddContent(parent, cur->content); - xmlFreeNode(cur); - return(parent); - } - if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) && - (parent->last->name == cur->name) && - (parent->last != cur)) { - xmlNodeAddContent(parent->last, cur->content); - xmlFreeNode(cur); - return(parent->last); - } - } + if ((parent == NULL) || (parent->type == XML_NAMESPACE_DECL) || + (cur == NULL) || (cur->type == XML_NAMESPACE_DECL) || + (parent == cur)) + return(NULL);
/* - * add the new element at the end of the children list. + * If parent is a text node, call xmlTextAddContent. This + * undocumented quirk should probably be removed. */ - prev = cur->parent; - cur->parent = parent; - if (cur->doc != parent->doc) { - xmlSetTreeDoc(cur, parent->doc); + if (parent->type == XML_TEXT_NODE) { + if (xmlTextAddContent(parent, cur->content, -1) < 0) + return(NULL); + xmlFreeNode(cur); + return(parent); } - /* this check prevents a loop on tree-traversions if a developer - * tries to add a node to its parent multiple times - */ - if (prev == parent) - return(cur);
- /* - * Coalescing - */ - if ((parent->type == XML_TEXT_NODE) && - (parent->content != NULL) && - (parent != cur)) { - xmlNodeAddContent(parent, cur->content); - xmlFreeNode(cur); - return(parent); - } if (cur->type == XML_ATTRIBUTE_NODE) { - if (parent->type != XML_ELEMENT_NODE) - return(NULL); - if (parent->properties != NULL) { - /* check if an attribute with the same name exists */ - xmlAttrPtr lastattr; - - if (cur->ns == NULL) - lastattr = xmlHasNsProp(parent, cur->name, NULL); - else - lastattr = xmlHasNsProp(parent, cur->name, cur->ns->href); - if ((lastattr != NULL) && (lastattr != (xmlAttrPtr) cur) && (lastattr->type != XML_ATTRIBUTE_DECL)) { - /* different instance, destroy it (attributes must be unique) */ - xmlUnlinkNode((xmlNodePtr) lastattr); - xmlFreeProp(lastattr); - } - if (lastattr == (xmlAttrPtr) cur) - return(cur); - - } - if (parent->properties == NULL) { - parent->properties = (xmlAttrPtr) cur; - } else { - /* find the end */ - xmlAttrPtr lastattr = parent->properties; - while (lastattr->next != NULL) { - lastattr = lastattr->next; - } - lastattr->next = (xmlAttrPtr) cur; - ((xmlAttrPtr) cur)->prev = lastattr; - } + prev = (xmlNodePtr) parent->properties; + if (prev != NULL) { + while (prev->next != NULL) + prev = prev->next; + } } else { - if (parent->children == NULL) { - parent->children = cur; - parent->last = cur; - } else { - prev = parent->last; - prev->next = cur; - cur->prev = prev; - parent->last = cur; - } + prev = parent->last; } - return(cur); + + if (cur == prev) + return(cur); + + return(xmlInsertNode(parent->doc, cur, parent, prev, NULL, 1)); }
/** * xmlGetLastChild: * @parent: the parent node * - * Search the last child of a node. - * Returns the last child or NULL if none. + * Find the last child of a node. + * + * Returns the last child or NULL if parent has no children. */ xmlNodePtr xmlGetLastChild(const xmlNode *parent) { @@ -3404,13 +3445,12 @@ xmlGetLastChild(const xmlNode *parent) { * xmlChildElementCount: * @parent: the parent node * - * Finds the current number of child nodes of that element which are - * element nodes. - * Note the handling of entities references is different than in - * the W3C DOM element traversal spec since we don't have back reference - * from entities content to entities references. + * Count the number of child nodes which are elements. * - * Returns the count of element child or 0 if not available + * Note that entity references are not expanded. + * + * Returns the number of element children or 0 if arguments are + * invalid. */ unsigned long xmlChildElementCount(xmlNodePtr parent) { @@ -3421,10 +3461,10 @@ xmlChildElementCount(xmlNodePtr parent) { return(0); switch (parent->type) { case XML_ELEMENT_NODE: - case XML_ENTITY_NODE: case XML_DOCUMENT_NODE: case XML_DOCUMENT_FRAG_NODE: case XML_HTML_DOCUMENT_NODE: + case XML_ENTITY_DECL: cur = parent->children; break; default: @@ -3442,12 +3482,11 @@ xmlChildElementCount(xmlNodePtr parent) { * xmlFirstElementChild: * @parent: the parent node * - * Finds the first child node of that element which is a Element node - * Note the handling of entities references is different than in - * the W3C DOM element traversal spec since we don't have back reference - * from entities content to entities references. + * Find the first child node which is an element. * - * Returns the first element child or NULL if not available + * Note that entity references are not expanded. + * + * Returns the first element or NULL if parent has no children. */ xmlNodePtr xmlFirstElementChild(xmlNodePtr parent) { @@ -3457,10 +3496,10 @@ xmlFirstElementChild(xmlNodePtr parent) { return(NULL); switch (parent->type) { case XML_ELEMENT_NODE: - case XML_ENTITY_NODE: case XML_DOCUMENT_NODE: case XML_DOCUMENT_FRAG_NODE: case XML_HTML_DOCUMENT_NODE: + case XML_ENTITY_DECL: cur = parent->children; break; default: @@ -3478,12 +3517,11 @@ xmlFirstElementChild(xmlNodePtr parent) { * xmlLastElementChild: * @parent: the parent node * - * Finds the last child node of that element which is a Element node - * Note the handling of entities references is different than in - * the W3C DOM element traversal spec since we don't have back reference - * from entities content to entities references. + * Find the last child node which is an element. * - * Returns the last element child or NULL if not available + * Note that entity references are not expanded. + * + * Returns the last element or NULL if parent has no children. */ xmlNodePtr xmlLastElementChild(xmlNodePtr parent) { @@ -3493,10 +3531,10 @@ xmlLastElementChild(xmlNodePtr parent) { return(NULL); switch (parent->type) { case XML_ELEMENT_NODE: - case XML_ENTITY_NODE: case XML_DOCUMENT_NODE: case XML_DOCUMENT_FRAG_NODE: case XML_HTML_DOCUMENT_NODE: + case XML_ENTITY_DECL: cur = parent->last; break; default: @@ -3514,13 +3552,11 @@ xmlLastElementChild(xmlNodePtr parent) { * xmlPreviousElementSibling: * @node: the current node * - * Finds the first closest previous sibling of the node which is an - * element node. - * Note the handling of entities references is different than in - * the W3C DOM element traversal spec since we don't have back reference - * from entities content to entities references. + * Find the closest preceding sibling which is a element. * - * Returns the previous element sibling or NULL if not available + * Note that entity references are not expanded. + * + * Returns the sibling or NULL if no sibling was found. */ xmlNodePtr xmlPreviousElementSibling(xmlNodePtr node) { @@ -3531,7 +3567,6 @@ xmlPreviousElementSibling(xmlNodePtr node) { case XML_TEXT_NODE: case XML_CDATA_SECTION_NODE: case XML_ENTITY_REF_NODE: - case XML_ENTITY_NODE: case XML_PI_NODE: case XML_COMMENT_NODE: case XML_XINCLUDE_START: @@ -3553,13 +3588,11 @@ xmlPreviousElementSibling(xmlNodePtr node) { * xmlNextElementSibling: * @node: the current node * - * Finds the first closest next sibling of the node which is an - * element node. - * Note the handling of entities references is different than in - * the W3C DOM element traversal spec since we don't have back reference - * from entities content to entities references. + * Find the closest following sibling which is a element. + * + * Note that entity references are not expanded. * - * Returns the next element sibling or NULL if not available + * Returns the sibling or NULL if no sibling was found. */ xmlNodePtr xmlNextElementSibling(xmlNodePtr node) { @@ -3570,7 +3603,6 @@ xmlNextElementSibling(xmlNodePtr node) { case XML_TEXT_NODE: case XML_CDATA_SECTION_NODE: case XML_ENTITY_REF_NODE: - case XML_ENTITY_NODE: case XML_PI_NODE: case XML_COMMENT_NODE: case XML_DTD_NODE: @@ -3595,8 +3627,7 @@ xmlNextElementSibling(xmlNodePtr node) { * xmlFreeNodeList: * @cur: the first node in the list * - * Free a node and all its siblings, this is a recursive behaviour, all - * the children are freed too. + * Free a node list including all children. */ void xmlFreeNodeList(xmlNodePtr cur) { @@ -3626,8 +3657,14 @@ xmlFreeNodeList(xmlNodePtr cur) { if ((cur->type == XML_DOCUMENT_NODE) || (cur->type == XML_HTML_DOCUMENT_NODE)) { xmlFreeDoc((xmlDocPtr) cur); - } else if (cur->type != XML_DTD_NODE) { - + } else if (cur->type == XML_DTD_NODE) { + /* + * TODO: We should consider freeing the DTD if it isn't + * referenced from doc->intSubset or doc->extSubset. + */ + cur->prev = NULL; + cur->next = NULL; + } else { if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue)) xmlDeregisterNodeDefaultValue(cur);
@@ -3678,8 +3715,10 @@ xmlFreeNodeList(xmlNodePtr cur) { * xmlFreeNode: * @cur: the node * - * Free a node, this is a recursive behaviour, all the children are freed too. - * This doesn't unlink the child from the list, use xmlUnlinkNode() first. + * Free a node including all the children. + * + * This doesn't unlink the node from the tree. Call xmlUnlinkNode first + * unless @cur is a root node. */ void xmlFreeNode(xmlNodePtr cur) { @@ -3700,17 +3739,16 @@ xmlFreeNode(xmlNodePtr cur) { xmlFreeProp((xmlAttrPtr) cur); return; } + if (cur->type == XML_ENTITY_DECL) { + xmlFreeEntity((xmlEntityPtr) cur); + return; + }
if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue)) xmlDeregisterNodeDefaultValue(cur);
if (cur->doc != NULL) dict = cur->doc->dict;
- if (cur->type == XML_ENTITY_DECL) { - xmlEntityPtr ent = (xmlEntityPtr) cur; - DICT_FREE(ent->SystemID); - DICT_FREE(ent->ExternalID); - } if ((cur->children != NULL) && (cur->type != XML_ENTITY_REF_NODE)) xmlFreeNodeList(cur->children); @@ -3742,54 +3780,16 @@ xmlFreeNode(xmlNodePtr cur) { }
/** - * xmlUnlinkNode: + * xmlUnlinkNodeInternal: * @cur: the node * - * Unlink a node from it's current context, the node is not freed - * If one need to free the node, use xmlFreeNode() routine after the - * unlink to discard it. - * Note that namespace nodes can't be unlinked as they do not have - * pointer to their parent. + * Unlink a node from its tree. + * + * This function only unlinks the node from the tree. It doesn't + * clear references to DTD nodes. */ -void -xmlUnlinkNode(xmlNodePtr cur) { - if (cur == NULL) { - return; - } - if (cur->type == XML_NAMESPACE_DECL) - return; - if (cur->type == XML_DTD_NODE) { - xmlDocPtr doc; - doc = cur->doc; - if (doc != NULL) { - if (doc->intSubset == (xmlDtdPtr) cur) - doc->intSubset = NULL; - if (doc->extSubset == (xmlDtdPtr) cur) - doc->extSubset = NULL; - } - } - if (cur->type == XML_ENTITY_DECL) { - xmlDocPtr doc; - doc = cur->doc; - if (doc != NULL) { - if (doc->intSubset != NULL) { - if (xmlHashLookup(doc->intSubset->entities, cur->name) == cur) - xmlHashRemoveEntry(doc->intSubset->entities, cur->name, - NULL); - if (xmlHashLookup(doc->intSubset->pentities, cur->name) == cur) - xmlHashRemoveEntry(doc->intSubset->pentities, cur->name, - NULL); - } - if (doc->extSubset != NULL) { - if (xmlHashLookup(doc->extSubset->entities, cur->name) == cur) - xmlHashRemoveEntry(doc->extSubset->entities, cur->name, - NULL); - if (xmlHashLookup(doc->extSubset->pentities, cur->name) == cur) - xmlHashRemoveEntry(doc->extSubset->pentities, cur->name, - NULL); - } - } - } +static void +xmlUnlinkNodeInternal(xmlNodePtr cur) { if (cur->parent != NULL) { xmlNodePtr parent; parent = cur->parent; @@ -3804,26 +3804,67 @@ xmlUnlinkNode(xmlNodePtr cur) { } cur->parent = NULL; } + if (cur->next != NULL) cur->next->prev = cur->prev; if (cur->prev != NULL) cur->prev->next = cur->next; - cur->next = cur->prev = NULL; + cur->next = NULL; + cur->prev = NULL; +} + +/** + * xmlUnlinkNode: + * @cur: the node + * + * Unlink a node from its tree. + * + * The node is not freed. Unless it is reinserted, it must be managed + * manually and freed eventually by calling xmlFreeNode. + */ +void +xmlUnlinkNode(xmlNodePtr cur) { + if (cur == NULL) + return; + + if (cur->type == XML_NAMESPACE_DECL) + return; + + if (cur->type == XML_DTD_NODE) { + xmlDocPtr doc = cur->doc; + + if (doc != NULL) { + if (doc->intSubset == (xmlDtdPtr) cur) + doc->intSubset = NULL; + if (doc->extSubset == (xmlDtdPtr) cur) + doc->extSubset = NULL; + } + } + + if (cur->type == XML_ENTITY_DECL) + xmlRemoveEntity((xmlEntityPtr) cur); + + xmlUnlinkNodeInternal(cur); }
#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED) /** * xmlReplaceNode: * @old: the old node - * @cur: the node + * @cur: the node (optional) + * + * Unlink the old node. If @cur is provided, it is unlinked and + * inserted in place of @old. * - * Unlink the old node from its current context, prune the new one - * at the same place. If @cur was already inserted in a document it is - * first unlinked from its existing context. + * It is an error if @old has no parent. * - * See the note regarding namespaces in xmlAddChild. + * Unlike xmlAddChild, this function doesn't merge text nodes or + * delete duplicate attributes. * - * Returns the @old node + * See the notes in xmlAddChild. + * + * Returns @old or NULL if arguments are invalid or a memory + * allocation failed. */ xmlNodePtr xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) { @@ -3833,20 +3874,19 @@ xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) { return(NULL); } if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) { + /* Don't call xmlUnlinkNodeInternal to handle DTDs. */ xmlUnlinkNode(old); return(old); } - if (cur == old) { - return(old); - } if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) { return(old); } if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) { return(old); } - xmlUnlinkNode(cur); - xmlSetTreeDoc(cur, old->doc); + xmlUnlinkNodeInternal(cur); + if (xmlSetTreeDoc(cur, old->doc) < 0) + return(NULL); cur->parent = old->parent; cur->next = old->next; if (cur->next != NULL) @@ -3881,9 +3921,10 @@ xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) { * xmlCopyNamespace: * @cur: the namespace * - * Do a copy of the namespace. + * Copy a namespace. * - * Returns: a new #xmlNsPtr, or NULL in case of error. + * Returns the copied namespace or NULL if a memory allocation + * failed. */ xmlNsPtr xmlCopyNamespace(xmlNsPtr cur) { @@ -3904,9 +3945,10 @@ xmlCopyNamespace(xmlNsPtr cur) { * xmlCopyNamespaceList: * @cur: the first namespace * - * Do a copy of an namespace list. + * Copy a namespace list. * - * Returns: a new #xmlNsPtr, or NULL in case of error. + * Returns the head of the copied list or NULL if a memory + * allocation failed. */ xmlNsPtr xmlCopyNamespaceList(xmlNsPtr cur) { @@ -3932,7 +3974,7 @@ xmlCopyNamespaceList(xmlNsPtr cur) {
static xmlAttrPtr xmlCopyPropInternal(xmlDocPtr doc, xmlNodePtr target, xmlAttrPtr cur) { - xmlAttrPtr ret; + xmlAttrPtr ret = NULL;
if (cur == NULL) return(NULL); if ((target != NULL) && (target->type != XML_ELEMENT_NODE)) @@ -3952,15 +3994,20 @@ xmlCopyPropInternal(xmlDocPtr doc, xmlNodePtr target, xmlAttrPtr cur) {
if ((cur->ns != NULL) && (target != NULL)) { xmlNsPtr ns; + int res;
- ns = xmlSearchNs(target->doc, target, cur->ns->prefix); + res = xmlSearchNsSafe(target, cur->ns->prefix, &ns); + if (res < 0) + goto error; if (ns == NULL) { /* * Humm, we are copying an element whose namespace is defined * out of the new tree scope. Search it in the original tree * and add it at the top of the new tree */ - ns = xmlSearchNs(cur->doc, cur->parent, cur->ns->prefix); + res = xmlSearchNsSafe(cur->parent, cur->ns->prefix, &ns); + if (res < 0) + goto error; if (ns != NULL) { xmlNodePtr root = target; xmlNodePtr pred = NULL; @@ -3974,6 +4021,8 @@ xmlCopyPropInternal(xmlDocPtr doc, xmlNodePtr target, xmlAttrPtr cur) { root = pred; } ret->ns = xmlNewNs(root, ns->href, ns->prefix); + if (ret->ns == NULL) + goto error; } } else { /* @@ -3989,7 +4038,9 @@ xmlCopyPropInternal(xmlDocPtr doc, xmlNodePtr target, xmlAttrPtr cur) { * we are in trouble: we need a new reconciled namespace. * This is expensive */ - ret->ns = xmlNewReconciledNs(target->doc, target, cur->ns); + ret->ns = xmlNewReconciledNs(target, cur->ns); + if (ret->ns == NULL) + goto error; } }
@@ -4000,6 +4051,8 @@ xmlCopyPropInternal(xmlDocPtr doc, xmlNodePtr target, xmlAttrPtr cur) { xmlNodePtr tmp;
ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret); + if (ret->children == NULL) + goto error; ret->last = NULL; tmp = ret->children; while (tmp != NULL) { @@ -4012,20 +4065,31 @@ xmlCopyPropInternal(xmlDocPtr doc, xmlNodePtr target, xmlAttrPtr cur) { /* * Try to handle IDs */ - if ((target!= NULL) && (cur!= NULL) && + if ((target != NULL) && (cur != NULL) && (target->doc != NULL) && (cur->doc != NULL) && - (cur->doc->ids != NULL) && (cur->parent != NULL)) { - if (xmlIsID(cur->doc, cur->parent, cur)) { + (cur->parent != NULL) && + (cur->children != NULL)) { + int res = xmlIsID(cur->doc, cur->parent, cur); + + if (res < 0) + goto error; + if (res != 0) { xmlChar *id;
- id = xmlNodeListGetString(cur->doc, cur->children, 1); - if (id != NULL) { - xmlAddID(NULL, target->doc, id, ret); - xmlFree(id); - } + id = xmlNodeGetContent((xmlNodePtr) cur); + if (id == NULL) + goto error; + res = xmlAddIDSafe(ret, id); + xmlFree(id); + if (res < 0) + goto error; } } return(ret); + +error: + xmlFreeProp(ret); + return(NULL); }
/** @@ -4033,9 +4097,14 @@ xmlCopyPropInternal(xmlDocPtr doc, xmlNodePtr target, xmlAttrPtr cur) { * @target: the element where the attribute will be grafted * @cur: the attribute * - * Do a copy of the attribute. + * Create a copy of the attribute. This function sets the parent + * pointer of the copy to @target but doesn't set the attribute on + * the target element. Users should consider to set the attribute + * by calling xmlAddChild afterwards or reset the parent pointer to + * NULL. * - * Returns: a new #xmlAttrPtr, or NULL in case of error. + * Returns the copied attribute or NULL if a memory allocation + * failed. */ xmlAttrPtr xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) { @@ -4047,9 +4116,12 @@ xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) { * @target: the element where the attributes will be grafted * @cur: the first attribute * - * Do a copy of an attribute list. + * Create a copy of an attribute list. This function sets the + * parent pointers of the copied attributes to @target but doesn't + * set the attributes on the target element. * - * Returns: a new #xmlAttrPtr, or NULL in case of error. + * Returns the head of the copied list or NULL if a memory + * allocation failed. */ xmlAttrPtr xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) { @@ -4095,6 +4167,17 @@ xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) { * namespace info, but don't recurse on children. */
+/** + * xmlStaticCopyNode: + * @node: source node + * @doc: target document + * @parent: target parent + * @extended: flags + * + * Copy a node. + * + * Returns the copy or NULL if a memory allocation failed. + */ xmlNodePtr xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent, int extended) { @@ -4107,7 +4190,6 @@ xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent, case XML_ELEMENT_NODE: case XML_DOCUMENT_FRAG_NODE: case XML_ENTITY_REF_NODE: - case XML_ENTITY_NODE: case XML_PI_NODE: case XML_COMMENT_NODE: case XML_XINCLUDE_START: @@ -4123,12 +4205,7 @@ xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent, #ifdef LIBXML_TREE_ENABLED return((xmlNodePtr) xmlCopyDoc((xmlDocPtr) node, extended)); #endif /* LIBXML_TREE_ENABLED */ - case XML_DOCUMENT_TYPE_NODE: - case XML_NOTATION_NODE: - case XML_DTD_NODE: - case XML_ELEMENT_DECL: - case XML_ATTRIBUTE_DECL: - case XML_ENTITY_DECL: + default: return(NULL); }
@@ -4136,10 +4213,8 @@ xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent, * Allocate a new node and fill the fields. */ ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); - if (ret == NULL) { - xmlTreeErrMemory("copying node"); + if (ret == NULL) return(NULL); - } memset(ret, 0, sizeof(xmlNode)); ret->type = node->type;
@@ -4156,6 +4231,8 @@ xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent, ret->name = xmlDictLookup(doc->dict, node->name, -1); else ret->name = xmlStrdup(node->name); + if (ret->name == NULL) + goto error; } if ((node->type != XML_ELEMENT_NODE) && (node->content != NULL) && @@ -4163,45 +4240,29 @@ xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent, (node->type != XML_XINCLUDE_END) && (node->type != XML_XINCLUDE_START)) { ret->content = xmlStrdup(node->content); + if (ret->content == NULL) + goto error; }else{ if (node->type == XML_ELEMENT_NODE) ret->line = node->line; } - if (parent != NULL) { - xmlNodePtr tmp; - - /* - * this is a tricky part for the node register thing: - * in case ret does get coalesced in xmlAddChild - * the deregister-node callback is called; so we register ret now already - */ - if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) - xmlRegisterNodeDefaultValue((xmlNodePtr)ret); - - /* - * Note that since ret->parent is already set, xmlAddChild will - * return early and not actually insert the node. It will only - * coalesce text nodes and unnecessarily call xmlSetTreeDoc. - * Assuming that the subtree to be copied always has its text - * nodes coalesced, the somewhat confusing call to xmlAddChild - * could be removed. - */ - tmp = xmlAddChild(parent, ret); - /* node could have coalesced */ - if (tmp != ret) - return(tmp); - }
if (!extended) goto out; if (((node->type == XML_ELEMENT_NODE) || - (node->type == XML_XINCLUDE_START)) && (node->nsDef != NULL)) + (node->type == XML_XINCLUDE_START)) && (node->nsDef != NULL)) { ret->nsDef = xmlCopyNamespaceList(node->nsDef); + if (ret->nsDef == NULL) + goto error; + }
- if (node->ns != NULL) { - xmlNsPtr ns; + if ((node->type == XML_ELEMENT_NODE) && (node->ns != NULL)) { + xmlNsPtr ns = NULL; + int res;
- ns = xmlSearchNs(doc, ret, node->ns->prefix); + res = xmlSearchNsSafe(ret, node->ns->prefix, &ns); + if (res < 0) + goto error; if (ns == NULL) { /* * Humm, we are copying an element whose namespace is defined @@ -4211,15 +4272,19 @@ xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent, * TODO: Searching the original tree seems unnecessary. We * already have a namespace URI. */ - ns = xmlSearchNs(node->doc, node, node->ns->prefix); + res = xmlSearchNsSafe(node, node->ns->prefix, &ns); + if (res < 0) + goto error; if (ns != NULL) { xmlNodePtr root = ret;
while (root->parent != NULL) root = root->parent; ret->ns = xmlNewNs(root, ns->href, ns->prefix); } else { - ret->ns = xmlNewReconciledNs(doc, ret, node->ns); + ret->ns = xmlNewReconciledNs(ret, node->ns); } + if (ret->ns == NULL) + goto error; } else { /* * reference the existing namespace definition in our own tree. @@ -4227,9 +4292,11 @@ xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent, ret->ns = ns; } } - if (((node->type == XML_ELEMENT_NODE) || - (node->type == XML_XINCLUDE_START)) && (node->properties != NULL)) + if ((node->type == XML_ELEMENT_NODE) && (node->properties != NULL)) { ret->properties = xmlCopyPropList(ret, node->properties); + if (ret->properties == NULL) + goto error; + } if (node->type == XML_ENTITY_REF_NODE) { if ((doc == NULL) || (node->doc != doc)) { /* @@ -4250,10 +4317,8 @@ xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent, insert = ret; while (cur != NULL) { xmlNodePtr copy = xmlStaticCopyNode(cur, doc, insert, 2); - if (copy == NULL) { - xmlFreeNode(ret); - return(NULL); - } + if (copy == NULL) + goto error;
/* Check for coalesced text nodes */ if (insert->last != copy) { @@ -4290,13 +4355,27 @@ xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent, }
out: - /* if parent != NULL we already registered the node above */ - if ((parent == NULL) && - ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))) + if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) xmlRegisterNodeDefaultValue((xmlNodePtr)ret); return(ret); + +error: + xmlFreeNode(ret); + return(NULL); }
+/** + * xmlStaticCopyNodeList: + * @node: node to copy + * @doc: target document + * @parent: target node (optional) + * + * Copy a node list. If @parent is provided, sets the parent pointer + * of the copied nodes, but doesn't update the children and last + * pointer of @parent. + * + * Returns a the copy or NULL in case of error. + */ xmlNodePtr xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) { xmlNodePtr ret = NULL; @@ -4305,23 +4384,44 @@ xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) { int linkedSubset = 0;
while (node != NULL) { + xmlNodePtr next = node->next; + #ifdef LIBXML_TREE_ENABLED if (node->type == XML_DTD_NODE ) { if (doc == NULL) { - node = node->next; + node = next; continue; } if ((doc->intSubset == NULL) && (newSubset == NULL)) { q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node ); if (q == NULL) goto error; - q->doc = doc; + /* Can't fail on DTD */ + xmlSetTreeDoc(q, doc); q->parent = parent; newSubset = (xmlDtdPtr) q; - xmlAddChild(parent, q); } else { + /* + * We don't allow multiple internal subsets in a document, + * so we move the DTD instead of creating a copy. + */ linkedSubset = 1; q = (xmlNodePtr) doc->intSubset; - xmlAddChild(parent, q); + /* Unlink */ + if (q->prev == NULL) { + if (q->parent != NULL) + q->parent->children = q->next; + } else { + q->prev->next = q->next; + } + if (q->next == NULL) { + if (q->parent != NULL) + q->parent->last = q->prev; + } else { + q->next->prev = q->prev; + } + q->parent = parent; + q->next = NULL; + q->prev = NULL; } } else #endif /* LIBXML_TREE_ENABLED */ @@ -4336,15 +4436,19 @@ xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) { q->prev = p; p = q; } - node = node->next; + node = next; } if ((doc != NULL) && (newSubset != NULL)) doc->intSubset = newSubset; return(ret); error: - if (linkedSubset != 0) - xmlUnlinkNode((xmlNodePtr) doc->intSubset); xmlFreeNodeList(ret); + if (newSubset != NULL) + xmlFreeDtd(newSubset); + if (linkedSubset != 0) { + doc->intSubset->next = NULL; + doc->intSubset->prev = NULL; + } return(NULL); }
@@ -4355,9 +4459,11 @@ error: * when applicable) * if 2 copy properties and namespaces (when applicable) * - * Do a copy of the node. + * Copy a node. + * + * Use of this function is DISCOURAGED in favor of xmlDocCopyNode. * - * Returns: a new #xmlNodePtr, or NULL in case of error. + * Returns the copied node or NULL if a memory allocation failed. */ xmlNodePtr xmlCopyNode(xmlNodePtr node, int extended) { @@ -4375,9 +4481,9 @@ xmlCopyNode(xmlNodePtr node, int extended) { * when applicable) * if 2 copy properties and namespaces (when applicable) * - * Do a copy of the node to a given document. + * Copy a node into another document. * - * Returns: a new #xmlNodePtr, or NULL in case of error. + * Returns the copied node or NULL if a memory allocation failed. */ xmlNodePtr xmlDocCopyNode(xmlNodePtr node, xmlDocPtr doc, int extended) { @@ -4392,9 +4498,10 @@ xmlDocCopyNode(xmlNodePtr node, xmlDocPtr doc, int extended) { * @doc: the target document * @node: the first node in the list. * - * Do a recursive copy of the node list. + * Copy a node list and all children into a new document. * - * Returns: a new #xmlNodePtr, or NULL in case of error. + * Returns the head of the copied list or NULL if a memory + * allocation failed. */ xmlNodePtr xmlDocCopyNodeList(xmlDocPtr doc, xmlNodePtr node) { xmlNodePtr ret = xmlStaticCopyNodeList(node, doc, NULL); @@ -4405,10 +4512,12 @@ xmlNodePtr xmlDocCopyNodeList(xmlDocPtr doc, xmlNodePtr node) { * xmlCopyNodeList: * @node: the first node in the list. * - * Do a recursive copy of the node list. - * Use xmlDocCopyNodeList() if possible to ensure string interning. + * Copy a node list and all children. * - * Returns: a new #xmlNodePtr, or NULL in case of error. + * Use of this function is DISCOURAGED in favor of xmlDocCopyNodeList. + * + * Returns the head of the copied list or NULL if a memory + * allocation failed. */ xmlNodePtr xmlCopyNodeList(xmlNodePtr node) { xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL); @@ -4418,11 +4527,11 @@ xmlNodePtr xmlCopyNodeList(xmlNodePtr node) { #if defined(LIBXML_TREE_ENABLED) /** * xmlCopyDtd: - * @dtd: the dtd + * @dtd: the DTD * - * Do a copy of the dtd. + * Copy a DTD. * - * Returns: a new #xmlDtdPtr, or NULL in case of error. + * Returns the copied DTD or NULL if a memory allocation failed. */ xmlDtdPtr xmlCopyDtd(xmlDtdPtr dtd) { @@ -4432,21 +4541,36 @@ xmlCopyDtd(xmlDtdPtr dtd) { if (dtd == NULL) return(NULL); ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID); if (ret == NULL) return(NULL); - if (dtd->entities != NULL) + if (dtd->entities != NULL) { ret->entities = (void *) xmlCopyEntitiesTable( (xmlEntitiesTablePtr) dtd->entities); - if (dtd->notations != NULL) + if (ret->entities == NULL) + goto error; + } + if (dtd->notations != NULL) { ret->notations = (void *) xmlCopyNotationTable( (xmlNotationTablePtr) dtd->notations); - if (dtd->elements != NULL) + if (ret->notations == NULL) + goto error; + } + if (dtd->elements != NULL) { ret->elements = (void *) xmlCopyElementTable( (xmlElementTablePtr) dtd->elements); - if (dtd->attributes != NULL) + if (ret->elements == NULL) + goto error; + } + if (dtd->attributes != NULL) { ret->attributes = (void *) xmlCopyAttributeTable( (xmlAttributeTablePtr) dtd->attributes); - if (dtd->pentities != NULL) + if (ret->attributes == NULL) + goto error; + } + if (dtd->pentities != NULL) { ret->pentities = (void *) xmlCopyEntitiesTable( (xmlEntitiesTablePtr) dtd->pentities); + if (ret->pentities == NULL) + goto error; + }
cur = dtd->children; while (cur != NULL) { @@ -4478,6 +4602,8 @@ xmlCopyDtd(xmlDtdPtr dtd) { xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix); } else if (cur->type == XML_COMMENT_NODE) { q = xmlCopyNode(cur, 0); + if (q == NULL) + goto error; }
if (q == NULL) { @@ -4499,6 +4625,10 @@ xmlCopyDtd(xmlDtdPtr dtd) { }
return(ret); + +error: + xmlFreeDtd(ret); + return(NULL); } #endif
@@ -4508,10 +4638,11 @@ xmlCopyDtd(xmlDtdPtr dtd) { * @doc: the document * @recursive: if not zero do a recursive copy. * - * Do a copy of the document info. If recursive, the content tree will + * Copy a document. If recursive, the content tree will * be copied too as well as DTD, namespaces and entities. * - * Returns: a new #xmlDocPtr, or NULL in case of error. + * Returns the copied document or NULL if a memory allocation + * failed. */ xmlDocPtr xmlCopyDoc(xmlDocPtr doc, int recursive) { @@ -4521,12 +4652,21 @@ xmlCopyDoc(xmlDocPtr doc, int recursive) { ret = xmlNewDoc(doc->version); if (ret == NULL) return(NULL); ret->type = doc->type; - if (doc->name != NULL) + if (doc->name != NULL) { ret->name = xmlMemStrdup(doc->name); - if (doc->encoding != NULL) + if (ret->name == NULL) + goto error; + } + if (doc->encoding != NULL) { ret->encoding = xmlStrdup(doc->encoding); - if (doc->URL != NULL) + if (ret->encoding == NULL) + goto error; + } + if (doc->URL != NULL) { ret->URL = xmlStrdup(doc->URL); + if (ret->URL == NULL) + goto error; + } ret->charset = doc->charset; ret->compression = doc->compression; ret->standalone = doc->standalone; @@ -4537,21 +4677,24 @@ xmlCopyDoc(xmlDocPtr doc, int recursive) { #ifdef LIBXML_TREE_ENABLED if (doc->intSubset != NULL) { ret->intSubset = xmlCopyDtd(doc->intSubset); - if (ret->intSubset == NULL) { - xmlFreeDoc(ret); - return(NULL); - } + if (ret->intSubset == NULL) + goto error; + /* Can't fail on DTD */ xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret); - ret->intSubset->parent = ret; } #endif - if (doc->oldNs != NULL) + if (doc->oldNs != NULL) { ret->oldNs = xmlCopyNamespaceList(doc->oldNs); + if (ret->oldNs == NULL) + goto error; + } if (doc->children != NULL) { xmlNodePtr tmp;
ret->children = xmlStaticCopyNodeList(doc->children, ret, (xmlNodePtr)ret); + if (ret->children == NULL) + goto error; ret->last = NULL; tmp = ret->children; while (tmp != NULL) { @@ -4561,6 +4704,10 @@ xmlCopyDoc(xmlDocPtr doc, int recursive) { } } return(ret); + +error: + xmlFreeDoc(ret); + return(NULL); } #endif /* LIBXML_TREE_ENABLED */
@@ -4663,13 +4810,10 @@ xmlGetNodePath(const xmlNode *node)
buf_len = 500; buffer = (xmlChar *) xmlMallocAtomic(buf_len); - if (buffer == NULL) { - xmlTreeErrMemory("getting node path"); + if (buffer == NULL) return (NULL); - } buf = (xmlChar *) xmlMallocAtomic(buf_len); if (buf == NULL) { - xmlTreeErrMemory("getting node path"); xmlFree(buffer); return (NULL); } @@ -4856,7 +5000,6 @@ xmlGetNodePath(const xmlNode *node) 2 * buf_len + xmlStrlen(buffer) + sizeof(nametemp) + 20; temp = (xmlChar *) xmlRealloc(buffer, buf_len); if (temp == NULL) { - xmlTreeErrMemory("getting node path"); xmlFree(buf); xmlFree(buffer); return (NULL); @@ -4864,7 +5007,6 @@ xmlGetNodePath(const xmlNode *node) buffer = temp; temp = (xmlChar *) xmlRealloc(buf, buf_len); if (temp == NULL) { - xmlTreeErrMemory("getting node path"); xmlFree(buf); xmlFree(buffer); return (NULL); @@ -4892,7 +5034,7 @@ xmlGetNodePath(const xmlNode *node) * Get the root element of the document (doc->children is a list * containing possibly comments, PIs, etc ...). * - * Returns the #xmlNodePtr for the root or NULL + * Returns the root element or NULL if no element was found. */ xmlNodePtr xmlDocGetRootElement(const xmlDoc *doc) { @@ -4918,7 +5060,10 @@ xmlDocGetRootElement(const xmlDoc *doc) { * Set the root element of the document (doc->children is a list * containing possibly comments, PIs, etc ...). * - * Returns the old root element if any was found, NULL if root was NULL + * @root must be an element node. It is unlinked before insertion. + * + * Returns the unlinked old root element or NULL if the document + * didn't have a root element or a memory allocation failed. */ xmlNodePtr xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) { @@ -4927,15 +5072,18 @@ xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) { if (doc == NULL) return(NULL); if ((root == NULL) || (root->type == XML_NAMESPACE_DECL)) return(NULL); - xmlUnlinkNode(root); - xmlSetTreeDoc(root, doc); - root->parent = (xmlNodePtr) doc; old = doc->children; while (old != NULL) { if (old->type == XML_ELEMENT_NODE) break; old = old->next; } + if (old == root) + return(old); + xmlUnlinkNodeInternal(root); + if (xmlSetTreeDoc(root, doc) < 0) + return(NULL); + root->parent = (xmlNodePtr) doc; if (old == NULL) { if (doc->children == NULL) { doc->children = root; @@ -4958,40 +5106,27 @@ xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) { * * Set the language of a node, i.e. the values of the xml:lang * attribute. + * + * Return 0 on success, 1 if arguments are invalid, -1 if a + * memory allocation failed. */ -void +int xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) { xmlNsPtr ns; + xmlAttrPtr attr; + int res;
- if (cur == NULL) return; - switch(cur->type) { - case XML_TEXT_NODE: - case XML_CDATA_SECTION_NODE: - case XML_COMMENT_NODE: - case XML_DOCUMENT_NODE: - case XML_DOCUMENT_TYPE_NODE: - case XML_DOCUMENT_FRAG_NODE: - case XML_NOTATION_NODE: - case XML_HTML_DOCUMENT_NODE: - case XML_DTD_NODE: - case XML_ELEMENT_DECL: - case XML_ATTRIBUTE_DECL: - case XML_ENTITY_DECL: - case XML_PI_NODE: - case XML_ENTITY_REF_NODE: - case XML_ENTITY_NODE: - case XML_NAMESPACE_DECL: - case XML_XINCLUDE_START: - case XML_XINCLUDE_END: - return; - case XML_ELEMENT_NODE: - case XML_ATTRIBUTE_NODE: - break; - } - ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE); - if (ns == NULL) - return; - xmlSetNsProp(cur, ns, BAD_CAST "lang", lang); + if ((cur == NULL) || (cur->type != XML_ELEMENT_NODE)) + return(1); + + res = xmlSearchNsByHrefSafe(cur, XML_XML_NAMESPACE, &ns); + if (res != 0) + return(res); + attr = xmlSetNsProp(cur, ns, BAD_CAST "lang", lang); + if (attr == NULL) + return(-1); + + return(0); } #endif /* LIBXML_TREE_ENABLED */
@@ -5008,15 +5143,22 @@ xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) { xmlChar * xmlNodeGetLang(const xmlNode *cur) { xmlChar *lang; + int res;
if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) return(NULL); + while (cur != NULL) { - lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE); + res = xmlNodeGetAttrValue(cur, BAD_CAST "lang", XML_XML_NAMESPACE, + &lang); + if (res < 0) + return(NULL); if (lang != NULL) return(lang); + cur = cur->parent; } + return(NULL); }
@@ -5029,47 +5171,34 @@ xmlNodeGetLang(const xmlNode *cur) { * * Set (or reset) the space preserving behaviour of a node, i.e. the * value of the xml:space attribute. + * + * Return 0 on success, 1 if arguments are invalid, -1 if a + * memory allocation failed. */ -void +int xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) { xmlNsPtr ns; + xmlAttrPtr attr; + const char *string; + int res;
- if (cur == NULL) return; - switch(cur->type) { - case XML_TEXT_NODE: - case XML_CDATA_SECTION_NODE: - case XML_COMMENT_NODE: - case XML_DOCUMENT_NODE: - case XML_DOCUMENT_TYPE_NODE: - case XML_DOCUMENT_FRAG_NODE: - case XML_NOTATION_NODE: - case XML_HTML_DOCUMENT_NODE: - case XML_DTD_NODE: - case XML_ELEMENT_DECL: - case XML_ATTRIBUTE_DECL: - case XML_ENTITY_DECL: - case XML_PI_NODE: - case XML_ENTITY_REF_NODE: - case XML_ENTITY_NODE: - case XML_NAMESPACE_DECL: - case XML_XINCLUDE_START: - case XML_XINCLUDE_END: - return; - case XML_ELEMENT_NODE: - case XML_ATTRIBUTE_NODE: - break; - } - ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE); - if (ns == NULL) - return; - switch (val) { - case 0: - xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "default"); - break; - case 1: - xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST "preserve"); - break; - } + if ((cur == NULL) || (cur->type != XML_ELEMENT_NODE)) + return(1); + + res = xmlSearchNsByHrefSafe(cur, XML_XML_NAMESPACE, &ns); + if (res != 0) + return(res); + + if (val == 0) + string = "default"; + else + string = "preserve"; + + attr = xmlSetNsProp(cur, ns, BAD_CAST "space", BAD_CAST string); + if (attr == NULL) + return(-1); + + return(0); } #endif /* LIBXML_TREE_ENABLED */
@@ -5086,11 +5215,16 @@ xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) { int xmlNodeGetSpacePreserve(const xmlNode *cur) { xmlChar *space; + int res;
if ((cur == NULL) || (cur->type != XML_ELEMENT_NODE)) return(-1); + while (cur != NULL) { - space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE); + res = xmlNodeGetAttrValue(cur, BAD_CAST "space", XML_XML_NAMESPACE, + &space); + if (res < 0) + return(-1); if (space != NULL) { if (xmlStrEqual(space, BAD_CAST "preserve")) { xmlFree(space); @@ -5102,8 +5236,10 @@ xmlNodeGetSpacePreserve(const xmlNode *cur) { } xmlFree(space); } + cur = cur->parent; } + return(-1); }
@@ -5119,51 +5255,39 @@ void xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) { xmlDocPtr doc; xmlDictPtr dict; - const xmlChar *freeme = NULL; + const xmlChar *copy; + const xmlChar *oldName;
if (cur == NULL) return; if (name == NULL) return; switch(cur->type) { - case XML_TEXT_NODE: - case XML_CDATA_SECTION_NODE: - case XML_COMMENT_NODE: - case XML_DOCUMENT_TYPE_NODE: - case XML_DOCUMENT_FRAG_NODE: - case XML_NOTATION_NODE: - case XML_HTML_DOCUMENT_NODE: - case XML_NAMESPACE_DECL: - case XML_XINCLUDE_START: - case XML_XINCLUDE_END: - return; case XML_ELEMENT_NODE: case XML_ATTRIBUTE_NODE: case XML_PI_NODE: case XML_ENTITY_REF_NODE: - case XML_ENTITY_NODE: - case XML_DTD_NODE: - case XML_DOCUMENT_NODE: - case XML_ELEMENT_DECL: - case XML_ATTRIBUTE_DECL: - case XML_ENTITY_DECL: break; + default: + return; } + doc = cur->doc; if (doc != NULL) dict = doc->dict; else dict = NULL; - if (dict != NULL) { - if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name))) - freeme = cur->name; - cur->name = xmlDictLookup(dict, name, -1); - } else { - if (cur->name != NULL) - freeme = cur->name; - cur->name = xmlStrdup(name); - }
- if (freeme) - xmlFree((xmlChar *) freeme); + if (dict != NULL) + copy = xmlDictLookup(dict, name, -1); + else + copy = xmlStrdup(name); + if (copy == NULL) + return; + + oldName = cur->name; + cur->name = copy; + if ((oldName != NULL) && + ((dict == NULL) || (!xmlDictOwns(dict, oldName)))) + xmlFree((xmlChar *) oldName); } #endif
@@ -5175,31 +5299,17 @@ xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) { * * Set (or reset) the base URI of a node, i.e. the value of the * xml:base attribute. + * + * Returns 0 on success, -1 on error. */ -void +int xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) { xmlNsPtr ns; xmlChar* fixed;
- if (cur == NULL) return; + if (cur == NULL) + return(-1); switch(cur->type) { - case XML_TEXT_NODE: - case XML_CDATA_SECTION_NODE: - case XML_COMMENT_NODE: - case XML_DOCUMENT_TYPE_NODE: - case XML_DOCUMENT_FRAG_NODE: - case XML_NOTATION_NODE: - case XML_DTD_NODE: - case XML_ELEMENT_DECL: - case XML_ATTRIBUTE_DECL: - case XML_ENTITY_DECL: - case XML_PI_NODE: - case XML_ENTITY_REF_NODE: - case XML_ENTITY_NODE: - case XML_NAMESPACE_DECL: - case XML_XINCLUDE_START: - case XML_XINCLUDE_END: - return; case XML_ELEMENT_NODE: case XML_ATTRIBUTE_NODE: break; @@ -5209,31 +5319,40 @@ xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) {
if (doc->URL != NULL) xmlFree((xmlChar *) doc->URL); - if (uri == NULL) + if (uri == NULL) { doc->URL = NULL; - else + } else { doc->URL = xmlPathToURI(uri); - return; + if (doc->URL == NULL) + return(-1); + } + return(0); } + default: + return(-1); }
- ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE); + xmlSearchNsByHrefSafe(cur, XML_XML_NAMESPACE, &ns); if (ns == NULL) - return; + return(-1); fixed = xmlPathToURI(uri); - if (fixed != NULL) { - xmlSetNsProp(cur, ns, BAD_CAST "base", fixed); - xmlFree(fixed); - } else { - xmlSetNsProp(cur, ns, BAD_CAST "base", uri); + if (fixed == NULL) + return(-1); + if (xmlSetNsProp(cur, ns, BAD_CAST "base", fixed) == NULL) { + xmlFree(fixed); + return(-1); } + xmlFree(fixed); + + return(0); } #endif /* LIBXML_TREE_ENABLED */
/** - * xmlNodeGetBase: + * xmlNodeGetBaseSafe: * @doc: the document the node pertains to * @cur: the node being checked + * @baseOut: pointer to base * * Searches for the BASE URL. The code should work on both XML * and HTML document even if base mechanisms are completely different. @@ -5244,19 +5363,27 @@ xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) { * However it does not return the document base (5.1.3), use * doc->URL in this case * - * Returns a pointer to the base URL, or NULL if not found - * It's up to the caller to free the memory with xmlFree(). + * Available since 2.13.0. + * + * Return 0 in case of success, 1 if a URI or argument is invalid, -1 if a + * memory allocation failed. */ -xmlChar * -xmlNodeGetBase(const xmlDoc *doc, const xmlNode *cur) { - xmlChar *oldbase = NULL; +int +xmlNodeGetBaseSafe(const xmlDoc *doc, const xmlNode *cur, xmlChar **baseOut) { + xmlChar *ret = NULL; xmlChar *base, *newbase; + int res;
+ if (baseOut == NULL) + return(1); + *baseOut = NULL; if ((cur == NULL) && (doc == NULL)) - return(NULL); + return(1); if ((cur != NULL) && (cur->type == XML_NAMESPACE_DECL)) - return(NULL); - if (doc == NULL) doc = cur->doc; + return(1); + if (doc == NULL) + doc = cur->doc; + if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) { cur = doc->children; while ((cur != NULL) && (cur->name != NULL)) { @@ -5273,50 +5400,91 @@ xmlNodeGetBase(const xmlDoc *doc, const xmlNode *cur) { continue; } if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) { - return(xmlGetProp(cur, BAD_CAST "href")); + if (xmlNodeGetAttrValue(cur, BAD_CAST "href", NULL, &ret) < 0) + return(-1); + if (ret == NULL) + return(1); + goto found; } cur = cur->next; } - return(NULL); + return(0); } + while (cur != NULL) { if (cur->type == XML_ENTITY_DECL) { xmlEntityPtr ent = (xmlEntityPtr) cur; - return(xmlStrdup(ent->URI)); + + if (ent->URI == NULL) + break; + xmlFree(ret); + ret = xmlStrdup(ent->URI); + if (ret == NULL) + return(-1); + goto found; } if (cur->type == XML_ELEMENT_NODE) { - base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE); + if (xmlNodeGetAttrValue(cur, BAD_CAST "base", XML_XML_NAMESPACE, + &base) < 0) { + xmlFree(ret); + return(-1); + } if (base != NULL) { - if (oldbase != NULL) { - newbase = xmlBuildURI(oldbase, base); - if (newbase != NULL) { - xmlFree(oldbase); - xmlFree(base); - oldbase = newbase; - } else { - xmlFree(oldbase); - xmlFree(base); - return(NULL); - } + if (ret != NULL) { + res = xmlBuildURISafe(ret, base, &newbase); + xmlFree(ret); + xmlFree(base); + if (res != 0) + return(res); + ret = newbase; } else { - oldbase = base; + ret = base; } - if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) || - (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) || - (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4))) - return(oldbase); + if ((!xmlStrncmp(ret, BAD_CAST "http://", 7)) || + (!xmlStrncmp(ret, BAD_CAST "ftp://", 6)) || + (!xmlStrncmp(ret, BAD_CAST "urn:", 4))) + goto found; } } cur = cur->parent; } + if ((doc != NULL) && (doc->URL != NULL)) { - if (oldbase == NULL) - return(xmlStrdup(doc->URL)); - newbase = xmlBuildURI(oldbase, doc->URL); - xmlFree(oldbase); - return(newbase); + if (ret == NULL) { + ret = xmlStrdup(doc->URL); + if (ret == NULL) + return(-1); + } else { + res = xmlBuildURISafe(ret, doc->URL, &newbase); + xmlFree(ret); + if (res != 0) + return(res); + ret = newbase; + } } - return(oldbase); + +found: + *baseOut = ret; + return(0); +} + +/** + * xmlNodeGetBase: + * @doc: the document the node pertains to + * @cur: the node being checked + * + * See xmlNodeGetBaseSafe. This function doesn't allow to distinguish + * memory allocation failures from a non-existing base. + * + * Returns a pointer to the base URL, or NULL if not found + * It's up to the caller to free the memory with xmlFree(). + */ +xmlChar * +xmlNodeGetBase(const xmlDoc *doc, const xmlNode *cur) { + xmlChar *base; + + xmlNodeGetBaseSafe(doc, cur, &base); + return(base); }
/** @@ -5347,6 +5515,69 @@ xmlNodeBufGetContent(xmlBufferPtr buffer, const xmlNode *cur) return(0); }
+static void +xmlBufGetEntityRefContent(xmlBufPtr buf, const xmlNode *ref) { + xmlEntityPtr ent; + + if (ref->children != NULL) { + ent = (xmlEntityPtr) ref->children; + } else { + /* lookup entity declaration */ + ent = xmlGetDocEntity(ref->doc, ref->name); + if (ent == NULL) + return; + } + + /* + * The parser should always expand predefined entities but it's + * possible to create references to predefined entities using + * the tree API. + */ + if (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY) { + xmlBufCat(buf, ent->content); + return; + } + + if (ent->flags & XML_ENT_EXPANDING) + return; + + ent->flags |= XML_ENT_EXPANDING; + xmlBufGetChildContent(buf, (xmlNodePtr) ent); + ent->flags &= ~XML_ENT_EXPANDING; +} + +static void +xmlBufGetChildContent(xmlBufPtr buf, const xmlNode *tree) { + const xmlNode *cur = tree->children; + + while (cur != NULL) { + switch (cur->type) { + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: + xmlBufCat(buf, cur->content); + break; + + case XML_ENTITY_REF_NODE: + xmlBufGetEntityRefContent(buf, cur); + break; + + default: + if (cur->children != NULL) { + cur = cur->children; + continue; + } + break; + } + + while (cur->next == NULL) { + cur = cur->parent; + if (cur == tree) + return; + } + cur = cur->next; + } +} + /** * xmlBufGetNodeContent: * @buf: a buffer xmlBufPtr @@ -5363,127 +5594,38 @@ xmlNodeBufGetContent(xmlBufferPtr buffer, const xmlNode *cur) int xmlBufGetNodeContent(xmlBufPtr buf, const xmlNode *cur) { - if ((cur == NULL) || (buf == NULL)) return(-1); + if ((cur == NULL) || (buf == NULL)) + return(-1); + switch (cur->type) { - case XML_CDATA_SECTION_NODE: - case XML_TEXT_NODE: - xmlBufCat(buf, cur->content); - break; + case XML_DOCUMENT_NODE: + case XML_HTML_DOCUMENT_NODE: case XML_DOCUMENT_FRAG_NODE: - case XML_ELEMENT_NODE:{ - const xmlNode *tmp = cur; - - while (tmp != NULL) { - switch (tmp->type) { - case XML_CDATA_SECTION_NODE: - case XML_TEXT_NODE: - if (tmp->content != NULL) - xmlBufCat(buf, tmp->content); - break; - case XML_ENTITY_REF_NODE: - xmlBufGetNodeContent(buf, tmp); - break; - default: - break; - } - /* - * Skip to next node - */ - if (tmp->children != NULL) { - if (tmp->children->type != XML_ENTITY_DECL) { - tmp = tmp->children; - continue; - } - } - if (tmp == cur) - break; - - if (tmp->next != NULL) { - tmp = tmp->next; - continue; - } - - do { - tmp = tmp->parent; - if (tmp == NULL) - break; - if (tmp == cur) { - tmp = NULL; - break; - } - if (tmp->next != NULL) { - tmp = tmp->next; - break; - } - } while (tmp != NULL); - } - break; - } - case XML_ATTRIBUTE_NODE:{ - xmlAttrPtr attr = (xmlAttrPtr) cur; - xmlNodePtr tmp = attr->children; + case XML_ELEMENT_NODE: + case XML_ATTRIBUTE_NODE: + case XML_ENTITY_DECL: + xmlBufGetChildContent(buf, cur); + break;
- while (tmp != NULL) { - if (tmp->type == XML_TEXT_NODE) - xmlBufCat(buf, tmp->content); - else - xmlBufGetNodeContent(buf, tmp); - tmp = tmp->next; - } - break; - } + case XML_CDATA_SECTION_NODE: + case XML_TEXT_NODE: case XML_COMMENT_NODE: case XML_PI_NODE: xmlBufCat(buf, cur->content); break; - case XML_ENTITY_REF_NODE:{ - xmlEntityPtr ent; - xmlNodePtr tmp;
- /* lookup entity declaration */ - ent = xmlGetDocEntity(cur->doc, cur->name); - if (ent == NULL) - return(-1); - - /* an entity content can be any "well balanced chunk", - * i.e. the result of the content [43] production: - * http://www.w3.org/TR/REC-xml#NT-content - * -> we iterate through child nodes and recursive call - * xmlNodeGetContent() which handles all possible node types */ - tmp = ent->children; - while (tmp) { - xmlBufGetNodeContent(buf, tmp); - tmp = tmp->next; - } - break; - } - case XML_ENTITY_NODE: - case XML_DOCUMENT_TYPE_NODE: - case XML_NOTATION_NODE: - case XML_DTD_NODE: - case XML_XINCLUDE_START: - case XML_XINCLUDE_END: + case XML_ENTITY_REF_NODE: + xmlBufGetEntityRefContent(buf, cur); break; - case XML_DOCUMENT_NODE: - case XML_HTML_DOCUMENT_NODE: - cur = cur->children; - while (cur!= NULL) { - if ((cur->type == XML_ELEMENT_NODE) || - (cur->type == XML_TEXT_NODE) || - (cur->type == XML_CDATA_SECTION_NODE)) { - xmlBufGetNodeContent(buf, cur); - } - cur = cur->next; - } - break; + case XML_NAMESPACE_DECL: xmlBufCat(buf, ((xmlNsPtr) cur)->href); break; - case XML_ELEMENT_DECL: - case XML_ATTRIBUTE_DECL: - case XML_ENTITY_DECL: + + default: break; } + return(0); }
@@ -5501,163 +5643,131 @@ xmlBufGetNodeContent(xmlBufPtr buf, const xmlNode *cur) xmlChar * xmlNodeGetContent(const xmlNode *cur) { + xmlBufPtr buf; + xmlChar *ret; + if (cur == NULL) return (NULL); + switch (cur->type) { + case XML_DOCUMENT_NODE: + case XML_HTML_DOCUMENT_NODE: + case XML_ENTITY_REF_NODE: + break; + case XML_DOCUMENT_FRAG_NODE: - case XML_ELEMENT_NODE:{ - xmlBufPtr buf; - xmlChar *ret; - - buf = xmlBufCreateSize(64); - if (buf == NULL) - return (NULL); - xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT); - xmlBufGetNodeContent(buf, cur); - ret = xmlBufDetach(buf); - xmlBufFree(buf); - return (ret); - } + case XML_ELEMENT_NODE: case XML_ATTRIBUTE_NODE: - return(xmlGetPropNodeValueInternal((xmlAttrPtr) cur)); - case XML_COMMENT_NODE: - case XML_PI_NODE: - if (cur->content != NULL) - return (xmlStrdup(cur->content)); - return (NULL); - case XML_ENTITY_REF_NODE:{ - xmlEntityPtr ent; - xmlBufPtr buf; - xmlChar *ret; - - /* lookup entity declaration */ - ent = xmlGetDocEntity(cur->doc, cur->name); - if (ent == NULL) - return (NULL); - - buf = xmlBufCreate(); - if (buf == NULL) - return (NULL); - xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT); - - xmlBufGetNodeContent(buf, cur); - - ret = xmlBufDetach(buf); - xmlBufFree(buf); - return (ret); + case XML_ENTITY_DECL: { + xmlNodePtr children = cur->children; + + if (children == NULL) + return(xmlStrdup(BAD_CAST "")); + + /* Optimization for single text children */ + if (((children->type == XML_TEXT_NODE) || + (children->type == XML_CDATA_SECTION_NODE)) && + (children->next == NULL)) { + if (children->content == NULL) + return(xmlStrdup(BAD_CAST "")); + return(xmlStrdup(children->content)); } - case XML_ENTITY_NODE: - case XML_DOCUMENT_TYPE_NODE: - case XML_NOTATION_NODE: - case XML_DTD_NODE: - case XML_XINCLUDE_START: - case XML_XINCLUDE_END: - return (NULL); - case XML_DOCUMENT_NODE: - case XML_HTML_DOCUMENT_NODE: { - xmlBufPtr buf; - xmlChar *ret; - - buf = xmlBufCreate(); - if (buf == NULL) - return (NULL); - xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT);
- xmlBufGetNodeContent(buf, (xmlNodePtr) cur); - - ret = xmlBufDetach(buf); - xmlBufFree(buf); - return (ret); - } - case XML_NAMESPACE_DECL: { - xmlChar *tmp; + break; + }
- tmp = xmlStrdup(((xmlNsPtr) cur)->href); - return (tmp); - } - case XML_ELEMENT_DECL: - /* TODO !!! */ - return (NULL); - case XML_ATTRIBUTE_DECL: - /* TODO !!! */ - return (NULL); - case XML_ENTITY_DECL: - /* TODO !!! */ - return (NULL); case XML_CDATA_SECTION_NODE: case XML_TEXT_NODE: + case XML_COMMENT_NODE: + case XML_PI_NODE: if (cur->content != NULL) - return (xmlStrdup(cur->content)); - return (NULL); + return(xmlStrdup(cur->content)); + else + return(xmlStrdup(BAD_CAST "")); + + case XML_NAMESPACE_DECL: + return(xmlStrdup(((xmlNsPtr) cur)->href)); + + default: + return(NULL); } - return (NULL); + + buf = xmlBufCreateSize(64); + if (buf == NULL) + return (NULL); + xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT); + xmlBufGetNodeContent(buf, cur); + ret = xmlBufDetach(buf); + xmlBufFree(buf); + + return(ret); }
-/** - * xmlNodeSetContent: - * @cur: the node being modified - * @content: the new value of the content - * - * Replace the content of a node. - * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity - * references, but XML special chars need to be escaped first by using - * xmlEncodeEntitiesReentrant() resp. xmlEncodeSpecialChars(). - */ -void -xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) { +static int +xmlNodeSetContentInternal(xmlNodePtr cur, const xmlChar *content, int len) { if (cur == NULL) { - return; + return(1); } switch (cur->type) { case XML_DOCUMENT_FRAG_NODE: case XML_ELEMENT_NODE: case XML_ATTRIBUTE_NODE: - if (cur->children != NULL) xmlFreeNodeList(cur->children); - cur->children = xmlStringGetNodeList(cur->doc, content); - UPDATE_LAST_CHILD_AND_PARENT(cur) + if (xmlNodeParseContent(cur, content, len) < 0) + return(-1); break; + case XML_TEXT_NODE: case XML_CDATA_SECTION_NODE: - case XML_ENTITY_REF_NODE: - case XML_ENTITY_NODE: case XML_PI_NODE: - case XML_COMMENT_NODE: - if ((cur->content != NULL) && - (cur->content != (xmlChar *) &(cur->properties))) { - if (!((cur->doc != NULL) && (cur->doc->dict != NULL) && - (xmlDictOwns(cur->doc->dict, cur->content)))) - xmlFree(cur->content); - } - if (cur->children != NULL) xmlFreeNodeList(cur->children); - cur->last = cur->children = NULL; + case XML_COMMENT_NODE: { + xmlChar *copy = NULL; + if (content != NULL) { - cur->content = xmlStrdup(content); - } else - cur->content = NULL; - cur->properties = NULL; - break; - case XML_DOCUMENT_NODE: - case XML_HTML_DOCUMENT_NODE: - case XML_DOCUMENT_TYPE_NODE: - case XML_XINCLUDE_START: - case XML_XINCLUDE_END: - break; - case XML_NOTATION_NODE: - break; - case XML_DTD_NODE: - break; - case XML_NAMESPACE_DECL: - break; - case XML_ELEMENT_DECL: - /* TODO !!! */ - break; - case XML_ATTRIBUTE_DECL: - /* TODO !!! */ - break; - case XML_ENTITY_DECL: - /* TODO !!! */ + if (len < 0) + copy = xmlStrdup(content); + else + copy = xmlStrndup(content, len); + if (copy == NULL) + return(-1); + } + + xmlTextSetContent(cur, copy); break; + } + + default: + break; } + + return(0); +} + +/** + * xmlNodeSetContent: + * @cur: the node being modified + * @content: the new value of the content + * + * Replace the text content of a node. + * + * Sets the raw text content of text, CDATA, comment or PI nodes. + * + * For element and attribute nodes, removes all children and + * replaces them by parsing @content which is expected to be a + * valid XML attribute value possibly containing character and + * entity references. Syntax errors and references to undeclared + * entities are ignored silently. Unfortunately, there isn't an + * API to pass raw content directly. An inefficient work-around + * is to escape the content with xmlEncodeSpecialChars before + * passing it. A better trick is clearing the old content + * with xmlNodeSetContent(node, NULL) first and then calling + * xmlNodeAddContent(node, content). Unlike this function, + * xmlNodeAddContent accepts raw text. + * + * Returns 0 on success, 1 on error, -1 if a memory allocation failed. + */ +int +xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) { + return(xmlNodeSetContentInternal(cur, content, -1)); }
#ifdef LIBXML_TREE_ENABLED @@ -5667,63 +5777,13 @@ xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) { * @content: the new value of the content * @len: the size of @content * - * Replace the content of a node. - * NOTE: @content is supposed to be a piece of XML CDATA, so it allows entity - * references, but XML special chars need to be escaped first by using - * xmlEncodeEntitiesReentrant() resp. xmlEncodeSpecialChars(). + * See xmlNodeSetContent. + * + * Returns 0 on success, 1 on error, -1 if a memory allocation failed. */ -void +int xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) { - if (cur == NULL) { - return; - } - switch (cur->type) { - case XML_DOCUMENT_FRAG_NODE: - case XML_ELEMENT_NODE: - case XML_ATTRIBUTE_NODE: - if (cur->children != NULL) xmlFreeNodeList(cur->children); - cur->children = xmlStringLenGetNodeList(cur->doc, content, len); - UPDATE_LAST_CHILD_AND_PARENT(cur) - break; - case XML_TEXT_NODE: - case XML_CDATA_SECTION_NODE: - case XML_ENTITY_REF_NODE: - case XML_ENTITY_NODE: - case XML_PI_NODE: - case XML_COMMENT_NODE: - case XML_NOTATION_NODE: - if ((cur->content != NULL) && - (cur->content != (xmlChar *) &(cur->properties))) { - if (!((cur->doc != NULL) && (cur->doc->dict != NULL) && - (xmlDictOwns(cur->doc->dict, cur->content)))) - xmlFree(cur->content); - } - if (cur->children != NULL) xmlFreeNodeList(cur->children); - cur->children = cur->last = NULL; - if (content != NULL) { - cur->content = xmlStrndup(content, len); - } else - cur->content = NULL; - cur->properties = NULL; - break; - case XML_DOCUMENT_NODE: - case XML_DTD_NODE: - case XML_HTML_DOCUMENT_NODE: - case XML_DOCUMENT_TYPE_NODE: - case XML_NAMESPACE_DECL: - case XML_XINCLUDE_START: - case XML_XINCLUDE_END: - break; - case XML_ELEMENT_DECL: - /* TODO !!! */ - break; - case XML_ATTRIBUTE_DECL: - /* TODO !!! */ - break; - case XML_ENTITY_DECL: - /* TODO !!! */ - break; - } + return(xmlNodeSetContentInternal(cur, content, len)); } #endif /* LIBXML_TREE_ENABLED */
@@ -5737,63 +5797,43 @@ xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) { * NOTE: In contrast to xmlNodeSetContentLen(), @content is supposed to be * raw text, so unescaped XML special chars are allowed, entity * references are not supported. + * + * Returns 0 on success, 1 on error, -1 if a memory allocation failed. */ -void +int xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) { - if (cur == NULL) { - return; - } - if (len <= 0) return; + if (cur == NULL) + return(1); + if ((content == NULL) || (len <= 0)) + return(0); + switch (cur->type) { case XML_DOCUMENT_FRAG_NODE: case XML_ELEMENT_NODE: { - xmlNodePtr last, newNode, tmp; + xmlNodePtr newNode, tmp;
- last = cur->last; newNode = xmlNewDocTextLen(cur->doc, content, len); - if (newNode != NULL) { - tmp = xmlAddChild(cur, newNode); - if (tmp != newNode) - return; - if ((last != NULL) && (last->next == newNode)) { - xmlTextMerge(last, newNode); - } - } + if (newNode == NULL) + return(-1); + tmp = xmlAddChild(cur, newNode); + if (tmp == NULL) { + xmlFreeNode(newNode); + return(-1); + } break; } case XML_ATTRIBUTE_NODE: break; case XML_TEXT_NODE: case XML_CDATA_SECTION_NODE: - case XML_ENTITY_REF_NODE: - case XML_ENTITY_NODE: - case XML_PI_NODE: - case XML_COMMENT_NODE: - case XML_NOTATION_NODE: - if (content != NULL) { - if ((cur->content == (xmlChar *) &(cur->properties)) || - ((cur->doc != NULL) && (cur->doc->dict != NULL) && - xmlDictOwns(cur->doc->dict, cur->content))) { - cur->content = xmlStrncatNew(cur->content, content, len); - cur->properties = NULL; - } else { - cur->content = xmlStrncat(cur->content, content, len); - } - } - break; - case XML_DOCUMENT_NODE: - case XML_DTD_NODE: - case XML_HTML_DOCUMENT_NODE: - case XML_DOCUMENT_TYPE_NODE: - case XML_NAMESPACE_DECL: - case XML_XINCLUDE_START: - case XML_XINCLUDE_END: - break; - case XML_ELEMENT_DECL: - case XML_ATTRIBUTE_DECL: - case XML_ENTITY_DECL: - break; + case XML_PI_NODE: + case XML_COMMENT_NODE: + return(xmlTextAddContent(cur, content, len)); + default: + break; } + + return(0); }
/** @@ -5805,17 +5845,12 @@ xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) { * NOTE: In contrast to xmlNodeSetContent(), @content is supposed to be * raw text, so unescaped XML special chars are allowed, entity * references are not supported. + * + * Returns 0 on success, 1 on error, -1 if a memory allocation failed. */ -void +int xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) { - int len; - - if (cur == NULL) { - return; - } - if (content == NULL) return; - len = xmlStrlen(content); - xmlNodeAddContentLen(cur, content, len); + return(xmlNodeAddContentLen(cur, content, xmlStrlen(content))); }
/** @@ -5823,53 +5858,72 @@ xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) { * @first: the first text node * @second: the second text node being merged * - * Merge two text nodes into one - * Returns the first text node augmented + * Merge the second text node into the first. If @first is NULL, + * @second is returned. Otherwise, the second node is unlinked and + * freed. + * + * Returns the first text node augmented or NULL in case of error. */ xmlNodePtr xmlTextMerge(xmlNodePtr first, xmlNodePtr second) { - if (first == NULL) return(second); - if (second == NULL) return(first); - if (first->type != XML_TEXT_NODE) return(first); - if (second->type != XML_TEXT_NODE) return(first); - if (second->name != first->name) - return(first); - xmlNodeAddContent(first, second->content); - xmlUnlinkNode(second); + if (first == NULL) + return(second); + if (second == NULL) + return(first); + + if ((first->type != XML_TEXT_NODE) || + (second->type != XML_TEXT_NODE) || + (first == second) || + (first->name != second->name)) + return(NULL); + + if (xmlTextAddContent(first, second->content, -1) < 0) + return(NULL); + + xmlUnlinkNodeInternal(second); xmlFreeNode(second); return(first); }
#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) /** - * xmlGetNsList: + * xmlGetNsListSafe: * @doc: the document * @node: the current node + * @out: the returned namespace array + * + * Find all in-scope namespaces of a node. @out returns a NULL + * terminated array of namespace pointers that must be freed by + * the caller. * - * Search all the namespace applying to a given element. - * Returns an NULL terminated array of all the #xmlNsPtr found - * that need to be freed by the caller or NULL if no - * namespace if defined + * Available since 2.13.0. + * + * Returns 0 on success, 1 if no namespaces were found, -1 if a + * memory allocation failed. */ -xmlNsPtr * -xmlGetNsList(const xmlDoc *doc ATTRIBUTE_UNUSED, const xmlNode *node) +int +xmlGetNsListSafe(const xmlDoc *doc ATTRIBUTE_UNUSED, const xmlNode *node, + xmlNsPtr **out) { xmlNsPtr cur; - xmlNsPtr *ret = NULL; + xmlNsPtr *namespaces = NULL; int nbns = 0; int maxns = 0; int i;
+ if (out == NULL) + return(1); + *out = NULL; if ((node == NULL) || (node->type == XML_NAMESPACE_DECL)) - return(NULL); + return(1);
while (node != NULL) { if (node->type == XML_ELEMENT_NODE) { cur = node->nsDef; while (cur != NULL) { for (i = 0; i < nbns; i++) { - if ((cur->prefix == ret[i]->prefix) || - (xmlStrEqual(cur->prefix, ret[i]->prefix))) + if ((cur->prefix == namespaces[i]->prefix) || + (xmlStrEqual(cur->prefix, namespaces[i]->prefix))) break; } if (i >= nbns) { @@ -5877,18 +5931,17 @@ xmlGetNsList(const xmlDoc *doc ATTRIBUTE_UNUSED, const xmlNode *node) xmlNsPtr *tmp;
maxns = maxns ? maxns * 2 : 10; - tmp = (xmlNsPtr *) xmlRealloc(ret, + tmp = (xmlNsPtr *) xmlRealloc(namespaces, (maxns + 1) * sizeof(xmlNsPtr)); if (tmp == NULL) { - xmlTreeErrMemory("getting namespace list"); - xmlFree(ret); - return (NULL); + xmlFree(namespaces); + return(-1); } - ret = tmp; + namespaces = tmp; } - ret[nbns++] = cur; - ret[nbns] = NULL; + namespaces[nbns++] = cur; + namespaces[nbns] = NULL; }
cur = cur->next; @@ -5896,40 +5949,161 @@ xmlGetNsList(const xmlDoc *doc ATTRIBUTE_UNUSED, const xmlNode *node) } node = node->parent; } - return (ret); + + *out = namespaces; + return((namespaces == NULL) ? 1 : 0); +} + +/** + * xmlGetNsList: + * @doc: the document + * @node: the current node + * + * Find all in-scope namespaces of a node. + * + * Use xmlGetNsListSafe for better error reporting. + * + * Returns a NULL terminated array of namespace pointers that must + * be freed by the caller or NULL if no namespaces were found or + * a memory allocation failed. + */ +xmlNsPtr * +xmlGetNsList(const xmlDoc *doc, const xmlNode *node) +{ + xmlNsPtr *ret; + + xmlGetNsListSafe(doc, node, &ret); + return(ret); } #endif /* LIBXML_TREE_ENABLED */
+static xmlNsPtr +xmlNewXmlNs(void) { + xmlNsPtr ns; + + ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); + if (ns == NULL) + return(NULL); + memset(ns, 0, sizeof(xmlNs)); + ns->type = XML_LOCAL_NAMESPACE; + ns->href = xmlStrdup(XML_XML_NAMESPACE); + if (ns->href == NULL) { + xmlFreeNs(ns); + return(NULL); + } + ns->prefix = xmlStrdup(BAD_CAST "xml"); + if (ns->prefix == NULL) { + xmlFreeNs(ns); + return(NULL); + } + + return(ns); +} + /* * xmlTreeEnsureXMLDecl: * @doc: the doc * * Ensures that there is an XML namespace declaration on the doc. * -* Returns the XML ns-struct or NULL on API and internal errors. +* Returns the XML ns-struct or NULL if a memory allocation failed. */ static xmlNsPtr xmlTreeEnsureXMLDecl(xmlDocPtr doc) { - if (doc == NULL) - return (NULL); - if (doc->oldNs != NULL) - return (doc->oldNs); - { - xmlNsPtr ns; - ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); - if (ns == NULL) { - xmlTreeErrMemory( - "allocating the XML namespace"); - return (NULL); - } - memset(ns, 0, sizeof(xmlNs)); - ns->type = XML_LOCAL_NAMESPACE; - ns->href = xmlStrdup(XML_XML_NAMESPACE); - ns->prefix = xmlStrdup((const xmlChar *)"xml"); - doc->oldNs = ns; + xmlNsPtr ns; + + ns = doc->oldNs; + if (ns != NULL) return (ns); + + ns = xmlNewXmlNs(); + doc->oldNs = ns; + + return(ns); +} + +/** + * xmlSearchNsSafe: + * @node: a node + * @prefix: a namespace prefix + * @out: pointer to resulting namespace + * + * Search a namespace with @prefix in scope of @node. + * + * Returns 0 on success, -1 if a memory allocation failed, 1 on + * other errors. + */ +int +xmlSearchNsSafe(xmlNodePtr node, const xmlChar *prefix, + xmlNsPtr *out) { + xmlNsPtr cur; + xmlDocPtr doc; + xmlNodePtr orig = node; + xmlNodePtr parent; + + if (out == NULL) + return(1); + *out = NULL; + if ((node == NULL) || (node->type == XML_NAMESPACE_DECL)) + return(1); + + doc = node->doc; + + if ((doc != NULL) && (IS_STR_XML(prefix))) { + cur = xmlTreeEnsureXMLDecl(doc); + if (cur == NULL) + return(-1); + *out = cur; + return(0); + } + + while (node->type != XML_ELEMENT_NODE) { + node = node->parent; + if (node == NULL) + return(0); + } + + parent = node; + + while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) { + cur = node->nsDef; + while (cur != NULL) { + if ((xmlStrEqual(cur->prefix, prefix)) && + (cur->href != NULL)) { + *out = cur; + return(0); + } + cur = cur->next; + } + if (orig != node) { + cur = node->ns; + if ((cur != NULL) && + (xmlStrEqual(cur->prefix, prefix)) && + (cur->href != NULL)) { + *out = cur; + return(0); + } + } + + node = node->parent; + } + + /* + * The XML-1.0 namespace is normally held on the document + * element. In this case exceptionally create it on the + * node element. + */ + if ((doc == NULL) && (IS_STR_XML(prefix))) { + cur = xmlNewXmlNs(); + if (cur == NULL) + return(-1); + cur->next = parent->nsDef; + parent->nsDef = cur; + *out = cur; } + + return(0); }
/** @@ -5946,82 +6120,17 @@ xmlTreeEnsureXMLDecl(xmlDocPtr doc) * the namespace within those you will be in troubles !!! A warning * is generated to cover this case. * - * Returns the namespace pointer or NULL. + * Returns the namespace pointer or NULL if no namespace was found or + * a memory allocation failed. Allocations can only fail if the "xml" + * namespace is queried. */ xmlNsPtr -xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) { - +xmlSearchNs(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node, + const xmlChar *nameSpace) { xmlNsPtr cur; - const xmlNode *orig = node;
- if ((node == NULL) || (node->type == XML_NAMESPACE_DECL)) return(NULL); - if ((nameSpace != NULL) && - (xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) { - if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) { - /* - * The XML-1.0 namespace is normally held on the root - * element. In this case exceptionally create it on the - * node element. - */ - cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); - if (cur == NULL) { - xmlTreeErrMemory("searching namespace"); - return(NULL); - } - memset(cur, 0, sizeof(xmlNs)); - cur->type = XML_LOCAL_NAMESPACE; - cur->href = xmlStrdup(XML_XML_NAMESPACE); - cur->prefix = xmlStrdup((const xmlChar *)"xml"); - cur->next = node->nsDef; - node->nsDef = cur; - return(cur); - } - if (doc == NULL) { - doc = node->doc; - if (doc == NULL) - return(NULL); - } - /* - * Return the XML namespace declaration held by the doc. - */ - if (doc->oldNs == NULL) - return(xmlTreeEnsureXMLDecl(doc)); - else - return(doc->oldNs); - } - while (node != NULL) { - if ((node->type == XML_ENTITY_REF_NODE) || - (node->type == XML_ENTITY_NODE) || - (node->type == XML_ENTITY_DECL)) - return(NULL); - if (node->type == XML_ELEMENT_NODE) { - cur = node->nsDef; - while (cur != NULL) { - if ((cur->prefix == NULL) && (nameSpace == NULL) && - (cur->href != NULL)) - return(cur); - if ((cur->prefix != NULL) && (nameSpace != NULL) && - (cur->href != NULL) && - (xmlStrEqual(cur->prefix, nameSpace))) - return(cur); - cur = cur->next; - } - if (orig != node) { - cur = node->ns; - if (cur != NULL) { - if ((cur->prefix == NULL) && (nameSpace == NULL) && - (cur->href != NULL)) - return(cur); - if ((cur->prefix != NULL) && (nameSpace != NULL) && - (cur->href != NULL) && - (xmlStrEqual(cur->prefix, nameSpace))) - return(cur); - } - } - } - node = node->parent; - } - return(NULL); + xmlSearchNsSafe(node, nameSpace, &cur); + return(cur); }
/** @@ -6044,7 +6153,6 @@ xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node,
while ((node != NULL) && (node != ancestor)) { if ((node->type == XML_ENTITY_REF_NODE) || - (node->type == XML_ENTITY_NODE) || (node->type == XML_ENTITY_DECL)) return (-1); if (node->type == XML_ELEMENT_NODE) { @@ -6068,92 +6176,117 @@ xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node, }
/** - * xmlSearchNsByHref: - * @doc: the document - * @node: the current node - * @href: the namespace value + * xmlSearchNsByHrefSafe: + * @node: a node + * @href: a namespace URI + * @out: pointer to resulting namespace * - * Search a Ns aliasing a given URI. Recurse on the parents until it finds - * the defined namespace or return NULL otherwise. - * Returns the namespace pointer or NULL. + * Search a namespace matching @URI in scope of @node. + * + * Returns 0 on success, -1 if a memory allocation failed, 1 on + * other errors. */ -xmlNsPtr -xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href) -{ +int +xmlSearchNsByHrefSafe(xmlNodePtr node, const xmlChar *href, + xmlNsPtr *out) { xmlNsPtr cur; + xmlDocPtr doc; xmlNodePtr orig = node; + xmlNodePtr parent; int is_attr;
- if ((node == NULL) || (node->type == XML_NAMESPACE_DECL) || (href == NULL)) - return (NULL); - if (xmlStrEqual(href, XML_XML_NAMESPACE)) { - /* - * Only the document can hold the XML spec namespace. - */ - if ((doc == NULL) && (node->type == XML_ELEMENT_NODE)) { - /* - * The XML-1.0 namespace is normally held on the root - * element. In this case exceptionally create it on the - * node element. - */ - cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); - if (cur == NULL) { - xmlTreeErrMemory("searching namespace"); - return (NULL); - } - memset(cur, 0, sizeof(xmlNs)); - cur->type = XML_LOCAL_NAMESPACE; - cur->href = xmlStrdup(XML_XML_NAMESPACE); - cur->prefix = xmlStrdup((const xmlChar *) "xml"); - cur->next = node->nsDef; - node->nsDef = cur; - return (cur); - } - if (doc == NULL) { - doc = node->doc; - if (doc == NULL) - return(NULL); - } - /* - * Return the XML namespace declaration held by the doc. - */ - if (doc->oldNs == NULL) - return(xmlTreeEnsureXMLDecl(doc)); - else - return(doc->oldNs); + if (out == NULL) + return(1); + *out = NULL; + if ((node == NULL) || (node->type == XML_NAMESPACE_DECL)) + return(1); + + doc = node->doc; + + if ((doc != NULL) && (xmlStrEqual(href, XML_XML_NAMESPACE))) { + cur = xmlTreeEnsureXMLDecl(doc); + if (cur == NULL) + return(-1); + *out = cur; + return(0); } + is_attr = (node->type == XML_ATTRIBUTE_NODE); - while (node != NULL) { - if ((node->type == XML_ENTITY_REF_NODE) || - (node->type == XML_ENTITY_NODE) || - (node->type == XML_ENTITY_DECL)) - return (NULL); - if (node->type == XML_ELEMENT_NODE) { - cur = node->nsDef; - while (cur != NULL) { - if ((cur->href != NULL) && (href != NULL) && - (xmlStrEqual(cur->href, href))) { - if (((!is_attr) || (cur->prefix != NULL)) && - (xmlNsInScope(doc, orig, node, cur->prefix) == 1)) - return (cur); + + while (node->type != XML_ELEMENT_NODE) { + node = node->parent; + if (node == NULL) + return(0); + } + + parent = node; + + while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) { + cur = node->nsDef; + while (cur != NULL) { + if (xmlStrEqual(cur->href, href)) { + if (((!is_attr) || (cur->prefix != NULL)) && + (xmlNsInScope(doc, orig, node, cur->prefix) == 1)) { + *out = cur; + return(0); } - cur = cur->next; } - if (orig != node) { - cur = node->ns; - if (cur != NULL) { - if ((cur->href != NULL) && (href != NULL) && - (xmlStrEqual(cur->href, href))) { - if (((!is_attr) || (cur->prefix != NULL)) && - (xmlNsInScope(doc, orig, node, cur->prefix) == 1)) - return (cur); + cur = cur->next; + } + if (orig != node) { + cur = node->ns; + if (cur != NULL) { + if (xmlStrEqual(cur->href, href)) { + if (((!is_attr) || (cur->prefix != NULL)) && + (xmlNsInScope(doc, orig, node, + cur->prefix) == 1)) { + *out = cur; + return(0); } } } } + node = node->parent; } - return (NULL); + + /* + * The XML-1.0 namespace is normally held on the document + * element. In this case exceptionally create it on the + * node element. + */ + if ((doc == NULL) && (xmlStrEqual(href, XML_XML_NAMESPACE))) { + cur = xmlNewXmlNs(); + if (cur == NULL) + return(-1); + cur->next = parent->nsDef; + parent->nsDef = cur; + *out = cur; + } + + return(0); +} + +/** + * xmlSearchNsByHref: + * @doc: the document + * @node: the current node + * @href: the namespace value + * + * Search a Ns aliasing a given URI. Recurse on the parents until it finds + * the defined namespace or return NULL otherwise. + * + * Returns the namespace pointer or NULL if no namespace was found or + * a memory allocation failed. Allocations can only fail if the "xml" + * namespace is queried. + */ +xmlNsPtr +xmlSearchNsByHref(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node, + const xmlChar * href) { + xmlNsPtr cur; + + xmlSearchNsByHrefSafe(node, href, &cur); + return(cur); }
/** @@ -6170,10 +6303,11 @@ xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href) * Returns the (new) namespace definition or NULL in case of error */ static xmlNsPtr -xmlNewReconciledNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) { +xmlNewReconciledNs(xmlNodePtr tree, xmlNsPtr ns) { xmlNsPtr def; xmlChar prefix[50]; int counter = 1; + int res;
if ((tree == NULL) || (tree->type != XML_ELEMENT_NODE)) { return(NULL); @@ -6184,7 +6318,9 @@ xmlNewReconciledNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) { /* * Search an existing namespace definition inherited. */ - def = xmlSearchNsByHref(doc, tree, ns->href); + res = xmlSearchNsByHrefSafe(tree, ns->href, &def); + if (res < 0) + return(NULL); if (def != NULL) return(def);
@@ -6197,7 +6333,9 @@ xmlNewReconciledNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) { else snprintf((char *) prefix, sizeof(prefix), "%.20s", (char *)ns->prefix);
- def = xmlSearchNs(doc, tree, prefix); + res = xmlSearchNsSafe(tree, prefix, &def); + if (res < 0) + return(NULL); while (def != NULL) { if (counter > 1000) return(NULL); if (ns->prefix == NULL) @@ -6205,7 +6343,9 @@ xmlNewReconciledNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) { else snprintf((char *) prefix, sizeof(prefix), "%.20s%d", (char *)ns->prefix, counter++); - def = xmlSearchNs(doc, tree, prefix); + res = xmlSearchNsSafe(tree, prefix, &def); + if (res < 0) + return(NULL); }
/* @@ -6216,6 +6356,12 @@ xmlNewReconciledNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) { }
#ifdef LIBXML_TREE_ENABLED + +typedef struct { + xmlNsPtr oldNs; + xmlNsPtr newNs; +} xmlNsCache; + /** * xmlReconciliateNs: * @doc: the document @@ -6228,12 +6374,12 @@ xmlNewReconciledNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) { * as possible the function try to reuse the existing namespaces found in * the new environment. If not possible the new namespaces are redeclared * on @tree at the top of the given subtree. - * Returns the number of namespace declarations created or -1 in case of error. + * + * Returns 0 on success or -1 in case of error. */ int xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) { - xmlNsPtr *oldNs = NULL; - xmlNsPtr *newNs = NULL; + xmlNsCache *cache = NULL; int sizeCache = 0; int nbCache = 0;
@@ -6243,35 +6389,15 @@ xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) { int ret = 0, i;
if ((node == NULL) || (node->type != XML_ELEMENT_NODE)) return(-1); - if ((doc == NULL) || (doc->type != XML_DOCUMENT_NODE)) return(-1); if (node->doc != doc) return(-1); while (node != NULL) { /* * Reconciliate the node namespace */ if (node->ns != NULL) { - /* - * initialize the cache if needed - */ - if (sizeCache == 0) { - sizeCache = 10; - oldNs = (xmlNsPtr *) xmlMalloc(sizeCache * - sizeof(xmlNsPtr)); - if (oldNs == NULL) { - xmlTreeErrMemory("fixing namespaces"); - return(-1); - } - newNs = (xmlNsPtr *) xmlMalloc(sizeCache * - sizeof(xmlNsPtr)); - if (newNs == NULL) { - xmlTreeErrMemory("fixing namespaces"); - xmlFree(oldNs); - return(-1); - } - } - for (i = 0;i < nbCache;i++) { - if (oldNs[i] == node->ns) { - node->ns = newNs[i]; + for (i = 0; i < nbCache; i++) { + if (cache[i].oldNs == node->ns) { + node->ns = cache[i].newNs; break; } } @@ -6279,32 +6405,31 @@ xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) { /* * OK we need to recreate a new namespace definition */ - n = xmlNewReconciledNs(doc, tree, node->ns); - if (n != NULL) { /* :-( what if else ??? */ + n = xmlNewReconciledNs(tree, node->ns); + if (n == NULL) { + ret = -1; + } else { /* * check if we need to grow the cache buffers. */ if (sizeCache <= nbCache) { - sizeCache *= 2; - oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache * - sizeof(xmlNsPtr)); - if (oldNs == NULL) { - xmlTreeErrMemory("fixing namespaces"); - xmlFree(newNs); - return(-1); - } - newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache * - sizeof(xmlNsPtr)); - if (newNs == NULL) { - xmlTreeErrMemory("fixing namespaces"); - xmlFree(oldNs); - return(-1); - } + xmlNsCache *tmp; + size_t newSize = sizeCache ? sizeCache * 2 : 10; + + tmp = xmlRealloc(cache, newSize * sizeof(tmp[0])); + if (tmp == NULL) { + ret = -1; + } else { + cache = tmp; + sizeCache = newSize; + } } - newNs[nbCache] = n; - oldNs[nbCache++] = node->ns; - node->ns = n; + if (nbCache < sizeCache) { + cache[nbCache].newNs = n; + cache[nbCache++].oldNs = node->ns; + } } + node->ns = n; } } /* @@ -6314,28 +6439,9 @@ xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) { attr = node->properties; while (attr != NULL) { if (attr->ns != NULL) { - /* - * initialize the cache if needed - */ - if (sizeCache == 0) { - sizeCache = 10; - oldNs = (xmlNsPtr *) xmlMalloc(sizeCache * - sizeof(xmlNsPtr)); - if (oldNs == NULL) { - xmlTreeErrMemory("fixing namespaces"); - return(-1); - } - newNs = (xmlNsPtr *) xmlMalloc(sizeCache * - sizeof(xmlNsPtr)); - if (newNs == NULL) { - xmlTreeErrMemory("fixing namespaces"); - xmlFree(oldNs); - return(-1); - } - } - for (i = 0;i < nbCache;i++) { - if (oldNs[i] == attr->ns) { - attr->ns = newNs[i]; + for (i = 0; i < nbCache; i++) { + if (cache[i].oldNs == attr->ns) { + attr->ns = cache[i].newNs; break; } } @@ -6343,32 +6449,33 @@ xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) { /* * OK we need to recreate a new namespace definition */ - n = xmlNewReconciledNs(doc, tree, attr->ns); - if (n != NULL) { /* :-( what if else ??? */ + n = xmlNewReconciledNs(tree, attr->ns); + if (n == NULL) { + ret = -1; + } else { /* * check if we need to grow the cache buffers. */ if (sizeCache <= nbCache) { - sizeCache *= 2; - oldNs = (xmlNsPtr *) xmlRealloc(oldNs, - sizeCache * sizeof(xmlNsPtr)); - if (oldNs == NULL) { - xmlTreeErrMemory("fixing namespaces"); - xmlFree(newNs); - return(-1); - } - newNs = (xmlNsPtr *) xmlRealloc(newNs, - sizeCache * sizeof(xmlNsPtr)); - if (newNs == NULL) { - xmlTreeErrMemory("fixing namespaces"); - xmlFree(oldNs); - return(-1); - } + xmlNsCache *tmp; + size_t newSize = sizeCache ? + sizeCache * 2 : 10; + + tmp = xmlRealloc(cache, + newSize * sizeof(tmp[0])); + if (tmp == NULL) { + ret = -1; + } else { + cache = tmp; + sizeCache = newSize; + } + } + if (nbCache < sizeCache) { + cache[nbCache].newNs = n; + cache[nbCache++].oldNs = attr->ns; } - newNs[nbCache] = n; - oldNs[nbCache++] = attr->ns; - attr->ns = n; } + attr->ns = n; } } attr = attr->next; @@ -6404,10 +6511,8 @@ xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) { } else break; } - if (oldNs != NULL) - xmlFree(oldNs); - if (newNs != NULL) - xmlFree(newNs); + if (cache != NULL) + xmlFree(cache); return(ret); } #endif /* LIBXML_TREE_ENABLED */ @@ -6469,7 +6574,11 @@ xmlGetPropNodeInternal(const xmlNode *node, const xmlChar *name, */ if ((node->ns != NULL) && (node->ns->prefix != NULL)) { tmpstr = xmlStrdup(node->ns->prefix); + if (tmpstr == NULL) + return(NULL); tmpstr = xmlStrcat(tmpstr, BAD_CAST ":"); + if (tmpstr == NULL) + return(NULL); tmpstr = xmlStrcat(tmpstr, node->name); if (tmpstr == NULL) return(NULL); @@ -6545,28 +6654,7 @@ xmlGetPropNodeValueInternal(const xmlAttr *prop) if (prop == NULL) return(NULL); if (prop->type == XML_ATTRIBUTE_NODE) { - /* - * Note that we return at least the empty string. - * TODO: Do we really always want that? - */ - if (prop->children != NULL) { - if ((prop->children->next == NULL) && - ((prop->children->type == XML_TEXT_NODE) || - (prop->children->type == XML_CDATA_SECTION_NODE))) - { - /* - * Optimization for the common case: only 1 text node. - */ - return(xmlStrdup(prop->children->content)); - } else { - xmlChar *ret; - - ret = xmlNodeListGetString(prop->doc, prop->children, 1); - if (ret != NULL) - return(ret); - } - } - return(xmlStrdup((xmlChar *)"")); + return(xmlNodeGetContent((xmlNodePtr) prop)); } else if (prop->type == XML_ATTRIBUTE_DECL) { return(xmlStrdup(((xmlAttributePtr)prop)->defaultValue)); } @@ -6580,10 +6668,11 @@ xmlGetPropNodeValueInternal(const xmlAttr *prop) * * Search an attribute associated to a node * This function also looks in DTD attribute declaration for #FIXED or - * default declaration values unless DTD use has been turned off. + * default declaration values. * * Returns the attribute or the attribute declaration or NULL if - * neither was found. + * neither was found. Also returns NULL if a memory allocation failed + * making this function unreliable. */ xmlAttrPtr xmlHasProp(const xmlNode *node, const xmlChar *name) { @@ -6602,7 +6691,6 @@ xmlHasProp(const xmlNode *node, const xmlChar *name) { } prop = prop->next; } - if (!xmlCheckDTD) return(NULL);
/* * Check if there is a default declaration in the internal @@ -6634,16 +6722,53 @@ xmlHasProp(const xmlNode *node, const xmlChar *name) { * This attribute has to be anchored in the namespace specified. * This does the entity substitution. * This function looks in DTD attribute declaration for #FIXED or - * default declaration values unless DTD use has been turned off. + * default declaration values. * Note that a namespace of NULL indicates to use the default namespace. * - * Returns the attribute or the attribute declaration or NULL - * if neither was found. + * Returns the attribute or the attribute declaration or NULL if + * neither was found. Also returns NULL if a memory allocation failed + * making this function unreliable. */ xmlAttrPtr xmlHasNsProp(const xmlNode *node, const xmlChar *name, const xmlChar *nameSpace) {
- return(xmlGetPropNodeInternal(node, name, nameSpace, xmlCheckDTD)); + return(xmlGetPropNodeInternal(node, name, nameSpace, 1)); +} + +/** + * xmlNodeGetAttrValue: + * @node: the node + * @name: the attribute name + * @nsUri: the URI of the namespace + * @out: the returned string + * + * Search and get the value of an attribute associated to a node + * This attribute has to be anchored in the namespace specified. + * This does the entity substitution. The returned value must be + * freed by the caller. + * + * Available since 2.13.0. + * + * Returns 0 on success, 1 if no attribute was found, -1 if a + * memory allocation failed. + */ +int +xmlNodeGetAttrValue(const xmlNode *node, const xmlChar *name, + const xmlChar *nsUri, xmlChar **out) { + xmlAttrPtr prop; + + if (out == NULL) + return(1); + *out = NULL; + + prop = xmlGetPropNodeInternal(node, name, nsUri, 0); + if (prop == NULL) + return(1); + + *out = xmlGetPropNodeValueInternal(prop); + if (*out == NULL) + return(-1); + return(0); }
/** @@ -6654,13 +6779,17 @@ xmlHasNsProp(const xmlNode *node, const xmlChar *name, const xmlChar *nameSpace) * Search and get the value of an attribute associated to a node * This does the entity substitution. * This function looks in DTD attribute declaration for #FIXED or - * default declaration values unless DTD use has been turned off. - * NOTE: this function acts independently of namespaces associated + * default declaration values. + * + * NOTE: This function acts independently of namespaces associated * to the attribute. Use xmlGetNsProp() or xmlGetNoNsProp() * for namespace aware processing. * - * Returns the attribute value or NULL if not found. - * It's up to the caller to free the memory with xmlFree(). + * NOTE: This function doesn't allow to distinguish malloc failures from + * missing attributes. It's more robust to use xmlNodeGetAttrValue. + * + * Returns the attribute value or NULL if not found or a memory allocation + * failed. It's up to the caller to free the memory with xmlFree(). */ xmlChar * xmlGetProp(const xmlNode *node, const xmlChar *name) { @@ -6680,18 +6809,21 @@ xmlGetProp(const xmlNode *node, const xmlChar *name) { * Search and get the value of an attribute associated to a node * This does the entity substitution. * This function looks in DTD attribute declaration for #FIXED or - * default declaration values unless DTD use has been turned off. + * default declaration values. * This function is similar to xmlGetProp except it will accept only * an attribute in no namespace. * - * Returns the attribute value or NULL if not found. - * It's up to the caller to free the memory with xmlFree(). + * NOTE: This function doesn't allow to distinguish malloc failures from + * missing attributes. It's more robust to use xmlNodeGetAttrValue. + * + * Returns the attribute value or NULL if not found or a memory allocation + * failed. It's up to the caller to free the memory with xmlFree(). */ xmlChar * xmlGetNoNsProp(const xmlNode *node, const xmlChar *name) { xmlAttrPtr prop;
- prop = xmlGetPropNodeInternal(node, name, NULL, xmlCheckDTD); + prop = xmlGetPropNodeInternal(node, name, NULL, 1); if (prop == NULL) return(NULL); return(xmlGetPropNodeValueInternal(prop)); @@ -6707,16 +6839,19 @@ xmlGetNoNsProp(const xmlNode *node, const xmlChar *name) { * This attribute has to be anchored in the namespace specified. * This does the entity substitution. * This function looks in DTD attribute declaration for #FIXED or - * default declaration values unless DTD use has been turned off. + * default declaration values. * - * Returns the attribute value or NULL if not found. - * It's up to the caller to free the memory with xmlFree(). + * NOTE: This function doesn't allow to distinguish malloc failures from + * missing attributes. It's more robust to use xmlNodeGetAttrValue. + * + * Returns the attribute value or NULL if not found or a memory allocation + * failed. It's up to the caller to free the memory with xmlFree(). */ xmlChar * xmlGetNsProp(const xmlNode *node, const xmlChar *name, const xmlChar *nameSpace) { xmlAttrPtr prop;
- prop = xmlGetPropNodeInternal(node, name, nameSpace, xmlCheckDTD); + prop = xmlGetPropNodeInternal(node, name, nameSpace, 1); if (prop == NULL) return(NULL); return(xmlGetPropNodeValueInternal(prop)); @@ -6739,7 +6874,7 @@ xmlUnsetProp(xmlNodePtr node, const xmlChar *name) { prop = xmlGetPropNodeInternal(node, name, NULL, 0); if (prop == NULL) return(-1); - xmlUnlinkNode((xmlNodePtr) prop); + xmlUnlinkNodeInternal((xmlNodePtr) prop); xmlFreeProp(prop); return(0); } @@ -6757,10 +6892,11 @@ int xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) { xmlAttrPtr prop;
- prop = xmlGetPropNodeInternal(node, name, (ns != NULL) ? ns->href : NULL, 0); + prop = xmlGetPropNodeInternal(node, name, + (ns != NULL) ? ns->href : NULL, 0); if (prop == NULL) return(-1); - xmlUnlinkNode((xmlNodePtr) prop); + xmlUnlinkNodeInternal((xmlNodePtr) prop); xmlFreeProp(prop); return(0); } @@ -6783,8 +6919,10 @@ xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) { */ xmlAttrPtr xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) { - int len; - const xmlChar *nqname; + xmlNsPtr ns = NULL; + const xmlChar *localname; + xmlChar *prefix; + int res;
if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE)) return(NULL); @@ -6792,16 +6930,19 @@ xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) { /* * handle QNames */ - nqname = xmlSplitQName3(name, &len); - if (nqname != NULL) { - xmlNsPtr ns; - xmlChar *prefix = xmlStrndup(name, len); - ns = xmlSearchNs(node->doc, node, prefix); - if (prefix != NULL) - xmlFree(prefix); - if (ns != NULL) - return(xmlSetNsProp(node, ns, nqname, value)); + localname = xmlSplitQName4(name, &prefix); + if (localname == NULL) + return(NULL); + + if (prefix != NULL) { + res = xmlSearchNsSafe(node, prefix, &ns); + xmlFree(prefix); + if (res < 0) + return(NULL); + if (ns != NULL) + return(xmlSetNsProp(node, ns, localname, value)); } + return(xmlSetNsProp(node, NULL, name, value)); }
@@ -6825,11 +6966,22 @@ xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
if (ns && (ns->href == NULL)) return(NULL); - prop = xmlGetPropNodeInternal(node, name, (ns != NULL) ? ns->href : NULL, 0); + if (name == NULL) + return(NULL); + prop = xmlGetPropNodeInternal(node, name, + (ns != NULL) ? ns->href : NULL, 0); if (prop != NULL) { + xmlNodePtr children = NULL; + /* * Modify the attribute's value. */ + if (value != NULL) { + children = xmlNewDocText(node->doc, value); + if (children == NULL) + return(NULL); + } + if (prop->atype == XML_ATTRIBUTE_ID) { xmlRemoveID(node->doc, prop); prop->atype = XML_ATTRIBUTE_ID; @@ -6842,7 +6994,7 @@ xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name, if (value != NULL) { xmlNodePtr tmp;
- prop->children = xmlNewDocText(node->doc, value); + prop->children = children; prop->last = NULL; tmp = prop->children; while (tmp != NULL) { @@ -6852,8 +7004,10 @@ xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name, tmp = tmp->next; } } - if (prop->atype == XML_ATTRIBUTE_ID) - xmlAddID(NULL, node->doc, value, prop); + if ((prop->atype == XML_ATTRIBUTE_ID) && + (xmlAddIDSafe(prop, value) < 0)) { + return(NULL); + } return(prop); } /* @@ -6912,33 +7066,25 @@ xmlIsBlankNode(const xmlNode *node) { * @content: the content * @len: @content length * - * Concat the given string at the end of the existing node content + * Concat the given string at the end of the existing node content. + * + * If @len is -1, the string length will be calculated. * * Returns -1 in case of error, 0 otherwise */
int xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) { - if (node == NULL) return(-1); + if (node == NULL) + return(-1);
if ((node->type != XML_TEXT_NODE) && (node->type != XML_CDATA_SECTION_NODE) && (node->type != XML_COMMENT_NODE) && - (node->type != XML_PI_NODE)) { + (node->type != XML_PI_NODE)) return(-1); - } - /* need to check if content is currently in the dictionary */ - if ((node->content == (xmlChar *) &(node->properties)) || - ((node->doc != NULL) && (node->doc->dict != NULL) && - xmlDictOwns(node->doc->dict, node->content))) { - node->content = xmlStrncatNew(node->content, content, len); - } else { - node->content = xmlStrncat(node->content, content, len); - } - node->properties = NULL; - if (node->content == NULL) - return(-1); - return(0); + + return(xmlTextAddContent(node, content, len)); }
/************************************************************************ @@ -6958,16 +7104,13 @@ xmlBufferCreate(void) { xmlBufferPtr ret;
ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer)); - if (ret == NULL) { - xmlTreeErrMemory("creating buffer"); + if (ret == NULL) return(NULL); - } ret->use = 0; ret->size = xmlDefaultBufferSize; ret->alloc = xmlBufferAllocScheme; ret->content = (xmlChar *) xmlMallocAtomic(ret->size); if (ret->content == NULL) { - xmlTreeErrMemory("creating buffer"); xmlFree(ret); return(NULL); } @@ -6990,17 +7133,14 @@ xmlBufferCreateSize(size_t size) { if (size >= UINT_MAX) return(NULL); ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer)); - if (ret == NULL) { - xmlTreeErrMemory("creating buffer"); + if (ret == NULL) return(NULL); - } ret->use = 0; ret->alloc = xmlBufferAllocScheme; ret->size = (size ? size + 1 : 0); /* +1 for ending null */ if (ret->size){ ret->content = (xmlChar *) xmlMallocAtomic(ret->size); if (ret->content == NULL) { - xmlTreeErrMemory("creating buffer"); xmlFree(ret); return(NULL); } @@ -7178,10 +7318,8 @@ xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
if (len < buf->size - buf->use) return(0); - if (len >= UINT_MAX - buf->use) { - xmlTreeErrMemory("growing buffer past UINT_MAX"); + if (len >= UINT_MAX - buf->use) return(-1); - }
if (buf->size > (size_t) len) { size = buf->size > UINT_MAX / 2 ? UINT_MAX : buf->size * 2; @@ -7194,18 +7332,14 @@ xmlBufferGrow(xmlBufferPtr buf, unsigned int len) { size_t start_buf = buf->content - buf->contentIO;
newbuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + size); - if (newbuf == NULL) { - xmlTreeErrMemory("growing buffer"); + if (newbuf == NULL) return(-1); - } buf->contentIO = newbuf; buf->content = newbuf + start_buf; } else { newbuf = (xmlChar *) xmlRealloc(buf->content, size); - if (newbuf == NULL) { - xmlTreeErrMemory("growing buffer"); + if (newbuf == NULL) return(-1); - } buf->content = newbuf; } buf->size = size; @@ -7295,10 +7429,8 @@ xmlBufferResize(xmlBufferPtr buf, unsigned int size) if (size < buf->size) return 1;
- if (size > UINT_MAX - 10) { - xmlTreeErrMemory("growing buffer past UINT_MAX"); + if (size > UINT_MAX - 10) return 0; - }
/* figure out new size */ switch (buf->alloc){ @@ -7306,19 +7438,17 @@ xmlBufferResize(xmlBufferPtr buf, unsigned int size) case XML_BUFFER_ALLOC_DOUBLEIT: /*take care of empty case*/ if (buf->size == 0) - newSize = (size > UINT_MAX - 10 ? UINT_MAX : size + 10); + newSize = size + 10; else newSize = buf->size; while (size > newSize) { - if (newSize > UINT_MAX / 2) { - xmlTreeErrMemory("growing buffer"); + if (newSize > UINT_MAX / 2) return 0; - } newSize *= 2; } break; case XML_BUFFER_ALLOC_EXACT: - newSize = (size > UINT_MAX - 10 ? UINT_MAX : size + 10); + newSize = size + 10; break; case XML_BUFFER_ALLOC_HYBRID: if (buf->use < BASE_BUFFER_SIZE) @@ -7326,17 +7456,15 @@ xmlBufferResize(xmlBufferPtr buf, unsigned int size) else { newSize = buf->size; while (size > newSize) { - if (newSize > UINT_MAX / 2) { - xmlTreeErrMemory("growing buffer"); + if (newSize > UINT_MAX / 2) return 0; - } newSize *= 2; } } break;
default: - newSize = (size > UINT_MAX - 10 ? UINT_MAX : size + 10); + newSize = size + 10; break; }
@@ -7351,10 +7479,8 @@ xmlBufferResize(xmlBufferPtr buf, unsigned int size) buf->size += start_buf; } else { rebuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + newSize); - if (rebuf == NULL) { - xmlTreeErrMemory("growing buffer"); + if (rebuf == NULL) return 0; - } buf->contentIO = rebuf; buf->content = rebuf + start_buf; } @@ -7378,10 +7504,8 @@ xmlBufferResize(xmlBufferPtr buf, unsigned int size) rebuf[buf->use] = 0; } } - if (rebuf == NULL) { - xmlTreeErrMemory("growing buffer"); + if (rebuf == NULL) return 0; - } buf->content = rebuf; } buf->size = newSize; @@ -7421,15 +7545,11 @@ xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
/* Note that both buf->size and buf->use can be zero here. */ if ((unsigned) len >= buf->size - buf->use) { - if ((unsigned) len >= UINT_MAX - buf->use) { - xmlTreeErrMemory("growing buffer past UINT_MAX"); + if ((unsigned) len >= UINT_MAX - buf->use) return XML_ERR_NO_MEMORY; - } needSize = buf->use + len + 1; - if (!xmlBufferResize(buf, needSize)){ - xmlTreeErrMemory("growing buffer"); + if (!xmlBufferResize(buf, needSize)) return XML_ERR_NO_MEMORY; - } }
memmove(&buf->content[buf->use], str, len); @@ -7486,15 +7606,11 @@ xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) { } /* Note that both buf->size and buf->use can be zero here. */ if ((unsigned) len >= buf->size - buf->use) { - if ((unsigned) len >= UINT_MAX - buf->use) { - xmlTreeErrMemory("growing buffer past UINT_MAX"); + if ((unsigned) len >= UINT_MAX - buf->use) return(-1); - } needSize = buf->use + len + 1; - if (!xmlBufferResize(buf, needSize)){ - xmlTreeErrMemory("growing buffer"); - return XML_ERR_NO_MEMORY; - } + if (!xmlBufferResize(buf, needSize)) + return(-1); }
memmove(&buf->content[len], &buf->content[0], buf->use); @@ -7647,6 +7763,8 @@ xmlSetDocCompressMode (xmlDocPtr doc, int mode) { /** * xmlGetCompressMode: * + * DEPRECATED: Use xmlGetDocCompressMode + * * get the default compression mode used, ZLIB based. * Returns 0 (uncompressed) to 9 (max compression) */ @@ -7660,6 +7778,8 @@ xmlGetCompressMode(void) * xmlSetCompressMode: * @mode: the compression ratio * + * DEPRECATED: Use xmlSetDocCompressMode + * * set the default compression mode used, ZLIB based * Correct values: 0 (uncompressed) to 9 (max compression) */ @@ -7767,10 +7887,8 @@ xmlDOMWrapNsMapAddItem(xmlNsMapPtr *nsmap, int position, * Create the ns-map. */ map = (xmlNsMapPtr) xmlMalloc(sizeof(struct xmlNsMap)); - if (map == NULL) { - xmlTreeErrMemory("allocating namespace map"); - return (NULL); - } + if (map == NULL) + return(NULL); memset(map, 0, sizeof(struct xmlNsMap)); *nsmap = map; } @@ -7787,10 +7905,8 @@ xmlDOMWrapNsMapAddItem(xmlNsMapPtr *nsmap, int position, * Create a new item. */ ret = (xmlNsMapItemPtr) xmlMalloc(sizeof(struct xmlNsMapItem)); - if (ret == NULL) { - xmlTreeErrMemory("allocating namespace map item"); - return (NULL); - } + if (ret == NULL) + return(NULL); memset(ret, 0, sizeof(struct xmlNsMapItem)); }
@@ -7882,10 +7998,8 @@ xmlDOMWrapNewCtxt(void) xmlDOMWrapCtxtPtr ret;
ret = xmlMalloc(sizeof(xmlDOMWrapCtxt)); - if (ret == NULL) { - xmlTreeErrMemory("allocating DOM-wrapper context"); + if (ret == NULL) return (NULL); - } memset(ret, 0, sizeof(xmlDOMWrapCtxt)); return (ret); } @@ -8001,39 +8115,6 @@ xmlDOMWrapNSNormGatherInScopeNs(xmlNsMapPtr *map, return (0); }
-/* -* XML_TREE_ADOPT_STR: If we have a dest-dict, put @str in the dict; -* otherwise copy it, when it was in the source-dict. -*/ -#define XML_TREE_ADOPT_STR(str) \ - if (adoptStr && (str != NULL)) { \ - if (destDoc->dict) { \ - const xmlChar *old = str; \ - str = xmlDictLookup(destDoc->dict, str, -1); \ - if ((sourceDoc == NULL) || (sourceDoc->dict == NULL) || \ - (!xmlDictOwns(sourceDoc->dict, old))) \ - xmlFree((char *)old); \ - } else if ((sourceDoc) && (sourceDoc->dict) && \ - xmlDictOwns(sourceDoc->dict, str)) { \ - str = BAD_CAST xmlStrdup(str); \ - } \ - } - -/* -* XML_TREE_ADOPT_STR_2: If @str was in the source-dict, then -* put it in dest-dict or copy it. -*/ -#define XML_TREE_ADOPT_STR_2(str) \ - if (adoptStr && (str != NULL) && (sourceDoc != NULL) && \ - (sourceDoc->dict != NULL) && \ - xmlDictOwns(sourceDoc->dict, cur->content)) { \ - if (destDoc->dict) \ - cur->content = (xmlChar *) \ - xmlDictLookup(destDoc->dict, cur->content, -1); \ - else \ - cur->content = xmlStrdup(BAD_CAST cur->content); \ - } - /* * xmlDOMWrapNSNormAddNsMapItem2: * @@ -8045,23 +8126,18 @@ static int xmlDOMWrapNSNormAddNsMapItem2(xmlNsPtr **list, int *size, int *number, xmlNsPtr oldNs, xmlNsPtr newNs) { - if (*list == NULL) { - *list = (xmlNsPtr *) xmlMalloc(6 * sizeof(xmlNsPtr)); - if (*list == NULL) { - xmlTreeErrMemory("alloc ns map item"); - return(-1); - } - *size = 3; - *number = 0; - } else if ((*number) >= (*size)) { - *size *= 2; - *list = (xmlNsPtr *) xmlRealloc(*list, - (*size) * 2 * sizeof(xmlNsPtr)); - if (*list == NULL) { - xmlTreeErrMemory("realloc ns map item"); - return(-1); - } + if (*number >= *size) { + xmlNsPtr *tmp; + size_t newSize; + + newSize = *size ? *size * 2 : 3; + tmp = xmlRealloc(*list, newSize * 2 * sizeof(tmp[0])); + if (tmp == NULL) + return(-1); + *list = tmp; + *size = newSize; } + (*list)[2 * (*number)] = oldNs; (*list)[2 * (*number) +1] = newNs; (*number)++; @@ -8090,7 +8166,7 @@ xmlDOMWrapRemoveNode(xmlDOMWrapCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr node, int options ATTRIBUTE_UNUSED) { xmlNsPtr *list = NULL; - int sizeList, nbList, i, j; + int sizeList = 0, nbList = 0, ret = 0, i, j; xmlNsPtr ns;
if ((node == NULL) || (doc == NULL) || (node->doc != doc)) @@ -8106,7 +8182,7 @@ xmlDOMWrapRemoveNode(xmlDOMWrapCtxtPtr ctxt, xmlDocPtr doc, case XML_ENTITY_REF_NODE: case XML_PI_NODE: case XML_COMMENT_NODE: - xmlUnlinkNode(node); + xmlUnlinkNodeInternal(node); return (0); case XML_ELEMENT_NODE: case XML_ATTRIBUTE_NODE: @@ -8114,7 +8190,7 @@ xmlDOMWrapRemoveNode(xmlDOMWrapCtxtPtr ctxt, xmlDocPtr doc, default: return (1); } - xmlUnlinkNode(node); + xmlUnlinkNodeInternal(node); /* * Save out-of-scope ns-references in doc->oldNs. */ @@ -8126,7 +8202,7 @@ xmlDOMWrapRemoveNode(xmlDOMWrapCtxtPtr ctxt, xmlDocPtr doc, do { if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList, &nbList, ns, ns) == -1) - goto internal_error; + ret = -1; ns = ns->next; } while (ns != NULL); } @@ -8156,7 +8232,7 @@ xmlDOMWrapRemoveNode(xmlDOMWrapCtxtPtr ctxt, xmlDocPtr doc, ns = xmlDOMWrapStoreNs(doc, node->ns->href, node->ns->prefix); if (ns == NULL) - goto internal_error; + ret = -1; } if (ns != NULL) { /* @@ -8164,7 +8240,7 @@ xmlDOMWrapRemoveNode(xmlDOMWrapCtxtPtr ctxt, xmlDocPtr doc, */ if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList, &nbList, node->ns, ns) == -1) - goto internal_error; + ret = -1; } node->ns = ns; } @@ -8189,19 +8265,22 @@ next_sibling: if (node->next != NULL) node = node->next; else { + int type = node->type; + node = node->parent; - goto next_sibling; + if ((type == XML_ATTRIBUTE_NODE) && + (node != NULL) && + (node->children != NULL)) { + node = node->children; + } else { + goto next_sibling; + } } } while (node != NULL);
if (list != NULL) xmlFree(list); - return (0); - -internal_error: - if (list != NULL) - xmlFree(list); - return (-1); + return (ret); }
/* @@ -8299,8 +8378,7 @@ xmlSearchNsByNamespaceStrict(xmlDocPtr doc, xmlNodePtr node, out = prev; prev = cur; } - } else if ((cur->type == XML_ENTITY_NODE) || - (cur->type == XML_ENTITY_DECL)) + } else if (cur->type == XML_ENTITY_DECL) return (0); cur = cur->parent; } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur)); @@ -8362,8 +8440,7 @@ xmlSearchNsByPrefixStrict(xmlDocPtr doc, xmlNodePtr node, ns = ns->next; } while (ns != NULL); } - } else if ((cur->type == XML_ENTITY_NODE) || - (cur->type == XML_ENTITY_DECL)) + } else if (cur->type == XML_ENTITY_DECL) return (0); cur = cur->parent; } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur)); @@ -8547,7 +8624,6 @@ xmlDOMWrapNSNormAcquireNormalizedNs(xmlDocPtr doc, */ if (xmlDOMWrapNsMapAddItem(nsMap, -1, ns, tmpns, XML_TREE_NSMAP_DOC) == NULL) { - xmlFreeNs(tmpns); return (-1); } *retNs = tmpns; @@ -8577,7 +8653,6 @@ xmlDOMWrapNSNormAcquireNormalizedNs(xmlDocPtr doc, } } if (xmlDOMWrapNsMapAddItem(nsMap, -1, ns, tmpns, depth) == NULL) { - xmlFreeNs(tmpns); return (-1); } *retNs = tmpns; @@ -8622,7 +8697,7 @@ xmlDOMWrapReconcileNamespaces(xmlDOMWrapCtxtPtr ctxt ATTRIBUTE_UNUSED, int optRemoveRedundantNS = ((xmlDOMReconcileNSOptions) options & XML_DOM_RECONNS_REMOVEREDUND) ? 1 : 0; xmlNsPtr *listRedund = NULL; - int sizeRedund = 0, nbRedund = 0, ret, i, j; + int sizeRedund = 0, nbRedund = 0, ret = 0, i, j;
if ((elem == NULL) || (elem->doc == NULL) || (elem->type != XML_ELEMENT_NODE)) @@ -8651,7 +8726,7 @@ xmlDOMWrapReconcileNamespaces(xmlDOMWrapCtxtPtr ctxt ATTRIBUTE_UNUSED, */ if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, elem->parent) == -1) - goto internal_error; + ret = -1; } parnsdone = 1; } @@ -8673,16 +8748,18 @@ xmlDOMWrapReconcileNamespaces(xmlDOMWrapCtxtPtr ctxt ATTRIBUTE_UNUSED, * Add it to the list of redundant ns-decls. */ if (xmlDOMWrapNSNormAddNsMapItem2(&listRedund, - &sizeRedund, &nbRedund, ns, mi->newNs) == -1) - goto internal_error; - /* - * Remove the ns-decl from the element-node. - */ - if (prevns) - prevns->next = ns->next; - else - cur->nsDef = ns->next; - goto next_ns_decl; + &sizeRedund, &nbRedund, ns, mi->newNs) == -1) { + ret = -1; + } else { + /* + * Remove the ns-decl from the element-node. + */ + if (prevns) + prevns->next = ns->next; + else + cur->nsDef = ns->next; + goto next_ns_decl; + } } } } @@ -8712,7 +8789,7 @@ xmlDOMWrapReconcileNamespaces(xmlDOMWrapCtxtPtr ctxt ATTRIBUTE_UNUSED, */ if (xmlDOMWrapNsMapAddItem(&nsMap, -1, ns, ns, depth) == NULL) - goto internal_error; + ret = -1;
prevns = ns; next_ns_decl: @@ -8732,7 +8809,7 @@ next_ns_decl: ((xmlNodePtr) elem->parent->doc != elem->parent)) { if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, elem->parent) == -1) - goto internal_error; + ret = -1; } parnsdone = 1; } @@ -8771,7 +8848,7 @@ next_ns_decl: &nsMap, depth, ancestorsOnly, (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1) - goto internal_error; + ret = -1; cur->ns = ns;
ns_end: @@ -8831,11 +8908,6 @@ next_sibling: } } while (cur != NULL);
- ret = 0; - goto exit; -internal_error: - ret = -1; -exit: if (listRedund) { for (i = 0, j = 0; i < nbRedund; i++, j += 2) { xmlFreeNs(listRedund[j]); @@ -8871,7 +8943,7 @@ exit: */ static int xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt, - xmlDocPtr sourceDoc, + xmlDocPtr sourceDoc ATTRIBUTE_UNUSED, xmlNodePtr node, xmlDocPtr destDoc, xmlNodePtr destParent, @@ -8882,21 +8954,12 @@ xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt, xmlNsMapPtr nsMap = NULL; xmlNsMapItemPtr mi; xmlNsPtr ns = NULL; - int depth = -1, adoptStr = 1; + int depth = -1; /* gather @parent's ns-decls. */ int parnsdone; /* @ancestorsOnly should be set per option. */ int ancestorsOnly = 0;
- /* - * Optimize string adoption for equal or none dicts. - */ - if ((sourceDoc != NULL) && - (sourceDoc->dict == destDoc->dict)) - adoptStr = 0; - else - adoptStr = 1; - /* * Get the ns-map from the context if available. */ @@ -8916,40 +8979,21 @@ xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt, parnsdone = 0;
cur = node; - if ((cur != NULL) && (cur->type == XML_NAMESPACE_DECL)) - goto internal_error;
while (cur != NULL) { - /* - * Paranoid source-doc sanity check. - */ - if (cur->doc != sourceDoc) { - /* - * We'll assume XIncluded nodes if the doc differs. - * TODO: Do we need to reconciliate XIncluded nodes? - * This here skips XIncluded nodes and tries to handle - * broken sequences. - */ - if (cur->next == NULL) - goto leave_node; - do { - cur = cur->next; - if ((cur->type == XML_XINCLUDE_END) || - (cur->doc == node->doc)) - break; - } while (cur->next != NULL); + if (cur->doc != destDoc) { + if (xmlNodeSetDoc(cur, destDoc) < 0) + ret = -1; + }
- if (cur->doc != node->doc) - goto leave_node; - } - cur->doc = destDoc; switch (cur->type) { case XML_XINCLUDE_START: case XML_XINCLUDE_END: /* * TODO */ - return (-1); + ret = -1; + goto leave_node; case XML_ELEMENT_NODE: curElem = cur; depth++; @@ -8970,14 +9014,12 @@ xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt, */ if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, destParent) == -1) - goto internal_error; + ret = -1; parnsdone = 1; } for (ns = cur->nsDef; ns != NULL; ns = ns->next) { /* * NOTE: ns->prefix and ns->href are never in the dict. - * XML_TREE_ADOPT_STR(ns->prefix) - * XML_TREE_ADOPT_STR(ns->href) */ /* * Does it shadow any ns-decl? @@ -8999,7 +9041,7 @@ xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt, */ if (xmlDOMWrapNsMapAddItem(&nsMap, -1, ns, ns, depth) == NULL) - goto internal_error; + ret = -1; } } /* Falls through. */ @@ -9011,7 +9053,7 @@ xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt, if (! parnsdone) { if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, destParent) == -1) - goto internal_error; + ret = -1; parnsdone = 1; } /* @@ -9045,7 +9087,7 @@ xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt, */ if (xmlDOMWrapNsMapAddItem(&nsMap, -1, cur->ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL) - goto internal_error; + ret = -1; cur->ns = ns; } else { /* @@ -9059,15 +9101,11 @@ xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt, ancestorsOnly, /* ns-decls must be prefixed for attributes. */ (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1) - goto internal_error; + ret = -1; cur->ns = ns; } + ns_end: - /* - * Further node properties. - * TODO: Is this all? - */ - XML_TREE_ADOPT_STR(cur->name) if (cur->type == XML_ELEMENT_NODE) { cur->psvi = NULL; cur->line = 0; @@ -9082,55 +9120,16 @@ ns_end: cur = (xmlNodePtr) cur->properties; continue; } - } else { - /* - * Attributes. - */ - if ((sourceDoc != NULL) && - (((xmlAttrPtr) cur)->atype == XML_ATTRIBUTE_ID)) - { - xmlRemoveID(sourceDoc, (xmlAttrPtr) cur); - } - ((xmlAttrPtr) cur)->atype = 0; - ((xmlAttrPtr) cur)->psvi = NULL; } break; case XML_TEXT_NODE: case XML_CDATA_SECTION_NODE: - /* - * This puts the content in the dest dict, only if - * it was previously in the source dict. - */ - XML_TREE_ADOPT_STR_2(cur->content) - goto leave_node; - case XML_ENTITY_REF_NODE: - /* - * Remove reference to the entity-node. - */ - cur->content = NULL; - cur->children = NULL; - cur->last = NULL; - if ((destDoc->intSubset) || (destDoc->extSubset)) { - xmlEntityPtr ent; - /* - * Assign new entity-node if available. - */ - ent = xmlGetDocEntity(destDoc, cur->name); - if (ent != NULL) { - cur->content = ent->content; - cur->children = (xmlNodePtr) ent; - cur->last = (xmlNodePtr) ent; - } - } - goto leave_node; case XML_PI_NODE: - XML_TREE_ADOPT_STR(cur->name) - XML_TREE_ADOPT_STR_2(cur->content) - break; case XML_COMMENT_NODE: - break; + case XML_ENTITY_REF_NODE: + goto leave_node; default: - goto internal_error; + ret = -1; } /* * Walk the tree. @@ -9181,12 +9180,6 @@ leave_node: } }
- goto exit; - -internal_error: - ret = -1; - -exit: /* * Cleanup. */ @@ -9248,7 +9241,7 @@ xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt, int options ATTRIBUTE_UNUSED) { int ret = 0; - xmlNodePtr cur, curElem = NULL; + xmlNodePtr cur, cloneElem = NULL; xmlNsMapPtr nsMap = NULL; xmlNsMapItemPtr mi; xmlNsPtr ns; @@ -9266,7 +9259,8 @@ xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt, xmlNsPtr cloneNs = NULL, *cloneNsDefSlot = NULL; xmlDictPtr dict; /* The destination dict */
- if ((node == NULL) || (resNode == NULL) || (destDoc == NULL)) + if ((node == NULL) || (resNode == NULL) || (destDoc == NULL) || + ((destParent != NULL) && (destParent->doc != destDoc))) return(-1); /* * TODO: Initially we support only element-nodes. @@ -9298,9 +9292,6 @@ xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt, *resNode = NULL;
cur = node; - if ((cur != NULL) && (cur->type == XML_NAMESPACE_DECL)) - return(-1); - while (cur != NULL) { if (cur->doc != sourceDoc) { /* @@ -9328,15 +9319,12 @@ xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt, case XML_PI_NODE: case XML_DOCUMENT_FRAG_NODE: case XML_ENTITY_REF_NODE: - case XML_ENTITY_NODE: /* * Nodes of xmlNode structure. */ clone = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); - if (clone == NULL) { - xmlTreeErrMemory("xmlDOMWrapCloneNode(): allocating a node"); + if (clone == NULL) goto internal_error; - } memset(clone, 0, sizeof(xmlNode)); /* * Set hierarchical links. @@ -9348,6 +9336,7 @@ xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt, clone->prev = prevClone; } else parentClone->children = clone; + parentClone->last = clone; } else resultClone = clone;
@@ -9358,10 +9347,8 @@ xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt, */ /* Use xmlRealloc to avoid -Warray-bounds warning */ clone = (xmlNodePtr) xmlRealloc(NULL, sizeof(xmlAttr)); - if (clone == NULL) { - xmlTreeErrMemory("xmlDOMWrapCloneNode(): allocating an attr-node"); + if (clone == NULL) goto internal_error; - } memset(clone, 0, sizeof(xmlAttr)); /* * Set hierarchical links. @@ -9402,7 +9389,12 @@ xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt, else if (cur->name == xmlStringComment) clone->name = xmlStringComment; else if (cur->name != NULL) { - DICT_CONST_COPY(cur->name, clone->name); + if (dict != NULL) + clone->name = xmlDictLookup(dict, cur->name, -1); + else + clone->name = xmlStrdup(cur->name); + if (clone->name == NULL) + goto internal_error; }
switch (cur->type) { @@ -9413,7 +9405,7 @@ xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt, */ return (-1); case XML_ELEMENT_NODE: - curElem = cur; + cloneElem = clone; depth++; /* * Namespace declarations. @@ -9439,18 +9431,25 @@ xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt, * Create a new xmlNs. */ cloneNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); - if (cloneNs == NULL) { - xmlTreeErrMemory("xmlDOMWrapCloneNode(): " - "allocating namespace"); - return(-1); - } + if (cloneNs == NULL) + goto internal_error; memset(cloneNs, 0, sizeof(xmlNs)); cloneNs->type = XML_LOCAL_NAMESPACE;
- if (ns->href != NULL) + if (ns->href != NULL) { cloneNs->href = xmlStrdup(ns->href); - if (ns->prefix != NULL) + if (cloneNs->href == NULL) { + xmlFreeNs(cloneNs); + goto internal_error; + } + } + if (ns->prefix != NULL) { cloneNs->prefix = xmlStrdup(ns->prefix); + if (cloneNs->prefix == NULL) { + xmlFreeNs(cloneNs); + goto internal_error; + } + }
*cloneNsDefSlot = cloneNs; cloneNsDefSlot = &(cloneNs->next); @@ -9496,15 +9495,18 @@ xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt, /* IDs will be processed further down. */ /* cur->ns will be processed further down. */ break; + case XML_PI_NODE: + case XML_COMMENT_NODE: case XML_TEXT_NODE: case XML_CDATA_SECTION_NODE: /* * Note that this will also cover the values of attributes. */ - DICT_COPY(cur->content, clone->content); - goto leave_node; - case XML_ENTITY_NODE: - /* TODO: What to do here? */ + if (cur->content != NULL) { + clone->content = xmlStrdup(cur->content); + if (clone->content == NULL) + goto internal_error; + } goto leave_node; case XML_ENTITY_REF_NODE: if (sourceDoc != destDoc) { @@ -9530,12 +9532,6 @@ xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt, clone->last = cur->last; } goto leave_node; - case XML_PI_NODE: - DICT_COPY(cur->content, clone->content); - goto leave_node; - case XML_COMMENT_NODE: - DICT_COPY(cur->content, clone->content); - goto leave_node; default: goto internal_error; } @@ -9595,8 +9591,8 @@ xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt, * Acquire a normalized ns-decl and add it to the map. */ if (xmlDOMWrapNSNormAcquireNormalizedNs(destDoc, - /* ns-decls on curElem or on destDoc->oldNs */ - destParent ? curElem : NULL, + /* ns-decls on cloneElem or on destDoc->oldNs */ + destParent ? cloneElem : NULL, cur->ns, &ns, &nsMap, depth, /* if we need to search only in the ancestor-axis */ @@ -9617,19 +9613,22 @@ end_ns_reference: if ((clone->type == XML_ATTRIBUTE_NODE) && (clone->parent != NULL)) { - if (xmlIsID(destDoc, clone->parent, (xmlAttrPtr) clone)) { + int res;
+ res = xmlIsID(destDoc, clone->parent, (xmlAttrPtr) clone); + if (res < 0) + goto internal_error; + if (res == 1) { xmlChar *idVal;
- idVal = xmlNodeListGetString(cur->doc, cur->children, 1); - if (idVal != NULL) { - if (xmlAddID(NULL, destDoc, idVal, (xmlAttrPtr) cur) == NULL) { - /* TODO: error message. */ - xmlFree(idVal); - goto internal_error; - } - xmlFree(idVal); - } + idVal = xmlNodeGetContent(cur); + if (idVal == NULL) + goto internal_error; + if (xmlAddIDSafe((xmlAttrPtr) cur, idVal) < 0) { + xmlFree(idVal); + goto internal_error; + } + xmlFree(idVal); } } /* @@ -9694,11 +9693,6 @@ leave_node: prevClone = clone; cur = cur->next; } else if (cur->type != XML_ATTRIBUTE_NODE) { - /* - * Set clone->last. - */ - if (clone->parent != NULL) - clone->parent->last = clone; clone = clone->parent; if (clone != NULL) parentClone = clone->parent; @@ -9767,19 +9761,22 @@ exit: */ static int xmlDOMWrapAdoptAttr(xmlDOMWrapCtxtPtr ctxt, - xmlDocPtr sourceDoc, + xmlDocPtr sourceDoc ATTRIBUTE_UNUSED, xmlAttrPtr attr, xmlDocPtr destDoc, xmlNodePtr destParent, int options ATTRIBUTE_UNUSED) { - xmlNodePtr cur; - int adoptStr = 1; + int ret = 0;
if ((attr == NULL) || (destDoc == NULL)) return (-1);
- attr->doc = destDoc; + if (attr->doc != destDoc) { + if (xmlSetTreeDoc((xmlNodePtr) attr, destDoc) < 0) + ret = -1; + } + if (attr->ns != NULL) { xmlNsPtr ns = NULL;
@@ -9800,75 +9797,18 @@ xmlDOMWrapAdoptAttr(xmlDOMWrapCtxtPtr ctxt, */ if (xmlSearchNsByNamespaceStrict(destDoc, destParent, attr->ns->href, &ns, 1) == -1) - goto internal_error; + ret = -1; if (ns == NULL) { ns = xmlDOMWrapNSNormDeclareNsForced(destDoc, destParent, attr->ns->href, attr->ns->prefix, 1); } } if (ns == NULL) - goto internal_error; + ret = -1; attr->ns = ns; }
- XML_TREE_ADOPT_STR(attr->name); - attr->atype = 0; - attr->psvi = NULL; - /* - * Walk content. - */ - if (attr->children == NULL) - return (0); - cur = attr->children; - if ((cur != NULL) && (cur->type == XML_NAMESPACE_DECL)) - goto internal_error; - while (cur != NULL) { - cur->doc = destDoc; - switch (cur->type) { - case XML_TEXT_NODE: - case XML_CDATA_SECTION_NODE: - XML_TREE_ADOPT_STR_2(cur->content) - break; - case XML_ENTITY_REF_NODE: - /* - * Remove reference to the entity-node. - */ - cur->content = NULL; - cur->children = NULL; - cur->last = NULL; - if ((destDoc->intSubset) || (destDoc->extSubset)) { - xmlEntityPtr ent; - /* - * Assign new entity-node if available. - */ - ent = xmlGetDocEntity(destDoc, cur->name); - if (ent != NULL) { - cur->content = ent->content; - cur->children = (xmlNodePtr) ent; - cur->last = (xmlNodePtr) ent; - } - } - break; - default: - break; - } - if (cur->children != NULL) { - cur = cur->children; - continue; - } -next_sibling: - if (cur == (xmlNodePtr) attr) - break; - if (cur->next != NULL) - cur = cur->next; - else { - cur = cur->parent; - goto next_sibling; - } - } - return (0); -internal_error: - return (-1); + return (ret); }
/* @@ -9906,6 +9846,8 @@ xmlDOMWrapAdoptNode(xmlDOMWrapCtxtPtr ctxt, xmlNodePtr destParent, int options) { + int ret = 0; + if ((node == NULL) || (node->type == XML_NAMESPACE_DECL) || (destDoc == NULL) || ((destParent != NULL) && (destParent->doc != destDoc))) @@ -9913,17 +9855,18 @@ xmlDOMWrapAdoptNode(xmlDOMWrapCtxtPtr ctxt, /* * Check node->doc sanity. */ - if ((node->doc != NULL) && (sourceDoc != NULL) && - (node->doc != sourceDoc)) { - /* - * Might be an XIncluded node. - */ + if (sourceDoc == NULL) { + sourceDoc = node->doc; + } else if (node->doc != sourceDoc) { return (-1); } - if (sourceDoc == NULL) - sourceDoc = node->doc; + + /* + * TODO: Shouldn't this be allowed? + */ if (sourceDoc == destDoc) return (-1); + switch (node->type) { case XML_ELEMENT_NODE: case XML_ATTRIBUTE_NODE: @@ -9943,7 +9886,7 @@ xmlDOMWrapAdoptNode(xmlDOMWrapCtxtPtr ctxt, * Unlink only if @node was not already added to @destParent. */ if ((node->parent != NULL) && (destParent != node->parent)) - xmlUnlinkNode(node); + xmlUnlinkNodeInternal(node);
if (node->type == XML_ELEMENT_NODE) { return (xmlDOMWrapAdoptBranch(ctxt, sourceDoc, node, @@ -9952,52 +9895,12 @@ xmlDOMWrapAdoptNode(xmlDOMWrapCtxtPtr ctxt, return (xmlDOMWrapAdoptAttr(ctxt, sourceDoc, (xmlAttrPtr) node, destDoc, destParent, options)); } else { - xmlNodePtr cur = node; - int adoptStr = 1; - - cur->doc = destDoc; - /* - * Optimize string adoption. - */ - if ((sourceDoc != NULL) && - (sourceDoc->dict == destDoc->dict)) - adoptStr = 0; - switch (node->type) { - case XML_TEXT_NODE: - case XML_CDATA_SECTION_NODE: - XML_TREE_ADOPT_STR_2(node->content) - break; - case XML_ENTITY_REF_NODE: - /* - * Remove reference to the entity-node. - */ - node->content = NULL; - node->children = NULL; - node->last = NULL; - if ((destDoc->intSubset) || (destDoc->extSubset)) { - xmlEntityPtr ent; - /* - * Assign new entity-node if available. - */ - ent = xmlGetDocEntity(destDoc, node->name); - if (ent != NULL) { - node->content = ent->content; - node->children = (xmlNodePtr) ent; - node->last = (xmlNodePtr) ent; - } - } - XML_TREE_ADOPT_STR(node->name) - break; - case XML_PI_NODE: { - XML_TREE_ADOPT_STR(node->name) - XML_TREE_ADOPT_STR_2(node->content) - break; - } - default: - break; - } + if (node->doc != destDoc) { + if (xmlNodeSetDoc(node, destDoc) < 0) + ret = -1; + } } - return (0); + return (ret); }
/************************************************************************ @@ -10055,6 +9958,8 @@ xmlIsXHTML(const xmlChar *systemID, const xmlChar *publicID) { * xmlRegisterNodeDefault: * @func: function pointer to the new RegisterNodeFunc * + * DEPRECATED: don't use + * * Registers a callback for node creation * * Returns the old value of the registration function @@ -10073,6 +9978,8 @@ xmlRegisterNodeDefault(xmlRegisterNodeFunc func) * xmlDeregisterNodeDefault: * @func: function pointer to the new DeregisterNodeFunc * + * DEPRECATED: don't use + * * Registers a callback for node destruction * * Returns the previous value of the deregistration function diff --git a/libs/xml2/uri.c b/libs/xml2/uri.c index 03b5a31aa60..d5fa3ea9b92 100644 --- a/libs/xml2/uri.c +++ b/libs/xml2/uri.c @@ -37,23 +37,6 @@ #define PORT_EMPTY 0 #define PORT_EMPTY_SERVER -1
-static void -xmlURIErrMemory(const char *extra) -{ - if (extra) - __xmlRaiseError(NULL, NULL, NULL, - NULL, NULL, XML_FROM_URI, - XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, - extra, NULL, NULL, 0, 0, - "Memory allocation failed : %s\n", extra); - else - __xmlRaiseError(NULL, NULL, NULL, - NULL, NULL, XML_FROM_URI, - XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, - NULL, NULL, NULL, 0, 0, - "Memory allocation failed\n"); -} - static void xmlCleanURI(xmlURIPtr uri);
/* @@ -68,7 +51,6 @@ static void xmlCleanURI(xmlURIPtr uri); * "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" | * "u" | "v" | "w" | "x" | "y" | "z" */ - #define IS_LOWALPHA(x) (((x) >= 'a') && ((x) <= 'z'))
/* @@ -89,7 +71,6 @@ static void xmlCleanURI(xmlURIPtr uri); /* * alphanum = alpha | digit */ - #define IS_ALPHANUM(x) (IS_ALPHA(x) || IS_DIGIT(x))
/* @@ -103,16 +84,15 @@ static void xmlCleanURI(xmlURIPtr uri); /* * unwise = "{" | "}" | "|" | "" | "^" | "`" */ - #define IS_UNWISE(p) \ (((*(p) == '{')) || ((*(p) == '}')) || ((*(p) == '|')) || \ ((*(p) == '\')) || ((*(p) == '^')) || ((*(p) == '[')) || \ ((*(p) == ']')) || ((*(p) == '`'))) + /* * reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | "," | * "[" | "]" */ - #define IS_RESERVED(x) (((x) == ';') || ((x) == '/') || ((x) == '?') || \ ((x) == ':') || ((x) == '@') || ((x) == '&') || ((x) == '=') || \ ((x) == '+') || ((x) == '$') || ((x) == ',') || ((x) == '[') || \ @@ -121,13 +101,11 @@ static void xmlCleanURI(xmlURIPtr uri); /* * unreserved = alphanum | mark */ - #define IS_UNRESERVED(x) (IS_ALPHANUM(x) || IS_MARK(x))
/* * Skip to next pointer char, handle escaped sequences */ - #define NEXT(p) ((*p == '%')? p += 3 : p++)
/* @@ -139,7 +117,6 @@ static void xmlCleanURI(xmlURIPtr uri); * * path = [ abs_path | opaque_part ] */ - #define STRNDUP(s, n) (char *) xmlStrndup((const xmlChar *)(s), (n))
/************************************************************************ @@ -181,7 +158,7 @@ static void xmlCleanURI(xmlURIPtr uri); /* * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" */ -#define ISA_UNRESERVED(p) \ +#define ISA_STRICTLY_UNRESERVED(p) \ ((ISA_ALPHA(p)) || (ISA_DIGIT(p)) || ((*(p) == '-')) || \ ((*(p) == '.')) || ((*(p) == '_')) || ((*(p) == '~')))
@@ -194,10 +171,47 @@ static void xmlCleanURI(xmlURIPtr uri); /* * pchar = unreserved / pct-encoded / sub-delims / ":" / "@" */ -#define ISA_PCHAR(p) \ - (ISA_UNRESERVED(p) || ISA_PCT_ENCODED(p) || ISA_SUB_DELIM(p) || \ +#define ISA_PCHAR(u, p) \ + (ISA_UNRESERVED(u, p) || ISA_PCT_ENCODED(p) || ISA_SUB_DELIM(p) || \ ((*(p) == ':')) || ((*(p) == '@')))
+/* + * From https://www.w3.org/TR/leiri/ + * + * " " / "<" / ">" / '"' / "{" / "}" / "|" + * / "" / "^" / "`" / %x0-1F / %x7F-D7FF + * / %xE000-FFFD / %x10000-10FFFF + */ +#define ISA_UCSCHAR(p) \ + ((*(p) <= 0x20) || (*(p) >= 0x7F) || (*(p) == '<') || (*(p) == '>') || \ + (*(p) == '"') || (*(p) == '{') || (*(p) == '}') || (*(p) == '|') || \ + (*(p) == '\') || (*(p) == '^') || (*(p) == '`')) + +#define ISA_UNRESERVED(u, p) (xmlIsUnreserved(u, p)) + +#define XML_URI_ALLOW_UNWISE 1 +#define XML_URI_NO_UNESCAPE 2 +#define XML_URI_ALLOW_UCSCHAR 4 + +static int +xmlIsUnreserved(xmlURIPtr uri, const char *cur) { + if (uri == NULL) + return(0); + + if (ISA_STRICTLY_UNRESERVED(cur)) + return(1); + + if (uri->cleanup & XML_URI_ALLOW_UNWISE) { + if (IS_UNWISE(cur)) + return(1); + } else if (uri->cleanup & XML_URI_ALLOW_UCSCHAR) { + if (ISA_UCSCHAR(cur)) + return(1); + } + + return(0); +} + /** * xmlParse3986Scheme: * @uri: pointer to an URI structure @@ -213,18 +227,26 @@ static int xmlParse3986Scheme(xmlURIPtr uri, const char **str) { const char *cur;
- if (str == NULL) - return(-1); - cur = *str; if (!ISA_ALPHA(cur)) - return(2); + return(1); cur++; + +#if defined(_WIN32) || defined(__CYGWIN__) + /* + * Don't treat Windows drive letters as scheme. + */ + if (*cur == ':') + return(1); +#endif + while (ISA_ALPHA(cur) || ISA_DIGIT(cur) || (*cur == '+') || (*cur == '-') || (*cur == '.')) cur++; if (uri != NULL) { if (uri->scheme != NULL) xmlFree(uri->scheme); uri->scheme = STRNDUP(*str, cur - *str); + if (uri->scheme == NULL) + return(-1); } *str = cur; return(0); @@ -250,22 +272,20 @@ xmlParse3986Fragment(xmlURIPtr uri, const char **str) { const char *cur;
- if (str == NULL) - return (-1); - cur = *str;
- while ((ISA_PCHAR(cur)) || (*cur == '/') || (*cur == '?') || - (*cur == '[') || (*cur == ']') || - ((uri != NULL) && (uri->cleanup & 1) && (IS_UNWISE(cur)))) + while ((ISA_PCHAR(uri, cur)) || (*cur == '/') || (*cur == '?') || + (*cur == '[') || (*cur == ']')) NEXT(cur); if (uri != NULL) { if (uri->fragment != NULL) xmlFree(uri->fragment); - if (uri->cleanup & 2) + if (uri->cleanup & XML_URI_NO_UNESCAPE) uri->fragment = STRNDUP(*str, cur - *str); else uri->fragment = xmlURIUnescapeString(*str, cur - *str, NULL); + if (uri->fragment == NULL) + return (-1); } *str = cur; return (0); @@ -287,21 +307,19 @@ xmlParse3986Query(xmlURIPtr uri, const char **str) { const char *cur;
- if (str == NULL) - return (-1); - cur = *str;
- while ((ISA_PCHAR(cur)) || (*cur == '/') || (*cur == '?') || - ((uri != NULL) && (uri->cleanup & 1) && (IS_UNWISE(cur)))) + while ((ISA_PCHAR(uri, cur)) || (*cur == '/') || (*cur == '?')) NEXT(cur); if (uri != NULL) { if (uri->query != NULL) xmlFree(uri->query); - if (uri->cleanup & 2) + if (uri->cleanup & XML_URI_NO_UNESCAPE) uri->query = STRNDUP(*str, cur - *str); else uri->query = xmlURIUnescapeString(*str, cur - *str, NULL); + if (uri->query == NULL) + return (-1);
/* Save the raw bytes of the query as well. * See: http://mail.gnome.org/archives/xml/2007-April/thread.html#00114 @@ -309,6 +327,8 @@ xmlParse3986Query(xmlURIPtr uri, const char **str) if (uri->query_raw != NULL) xmlFree (uri->query_raw); uri->query_raw = STRNDUP (*str, cur - *str); + if (uri->query_raw == NULL) + return (-1); } *str = cur; return (0); @@ -371,16 +391,18 @@ xmlParse3986Userinfo(xmlURIPtr uri, const char **str) const char *cur;
cur = *str; - while (ISA_UNRESERVED(cur) || ISA_PCT_ENCODED(cur) || + while (ISA_UNRESERVED(uri, cur) || ISA_PCT_ENCODED(cur) || ISA_SUB_DELIM(cur) || (*cur == ':')) NEXT(cur); if (*cur == '@') { if (uri != NULL) { if (uri->user != NULL) xmlFree(uri->user); - if (uri->cleanup & 2) + if (uri->cleanup & XML_URI_NO_UNESCAPE) uri->user = STRNDUP(*str, cur - *str); else uri->user = xmlURIUnescapeString(*str, cur - *str, NULL); + if (uri->user == NULL) + return(-1); } *str = cur; return(0); @@ -485,7 +507,8 @@ not_ipv4: /* * then this should be a hostname which can be empty */ - while (ISA_UNRESERVED(cur) || ISA_PCT_ENCODED(cur) || ISA_SUB_DELIM(cur)) + while (ISA_UNRESERVED(uri, cur) || + ISA_PCT_ENCODED(cur) || ISA_SUB_DELIM(cur)) NEXT(cur); found: if (uri != NULL) { @@ -493,10 +516,12 @@ found: uri->authority = NULL; if (uri->server != NULL) xmlFree(uri->server); if (cur != host) { - if (uri->cleanup & 2) + if (uri->cleanup & XML_URI_NO_UNESCAPE) uri->server = STRNDUP(host, cur - host); else uri->server = xmlURIUnescapeString(host, cur - host, NULL); + if (uri->server == NULL) + return(-1); } else uri->server = NULL; } @@ -527,6 +552,8 @@ xmlParse3986Authority(xmlURIPtr uri, const char **str) * try to parse an userinfo and check for the trailing @ */ ret = xmlParse3986Userinfo(uri, &cur); + if (ret < 0) + return(ret); if ((ret != 0) || (*cur != '@')) cur = *str; else @@ -559,17 +586,27 @@ xmlParse3986Authority(xmlURIPtr uri, const char **str) * Returns 0 or the error code */ static int -xmlParse3986Segment(const char **str, char forbid, int empty) +xmlParse3986Segment(xmlURIPtr uri, const char **str, char forbid, int empty) { const char *cur;
cur = *str; - if (!ISA_PCHAR(cur)) { + if (!ISA_PCHAR(uri, cur) || (*cur == forbid)) { if (empty) return(0); return(1); } - while (ISA_PCHAR(cur) && (*cur != forbid)) + NEXT(cur); + +#if defined(_WIN32) || defined(__CYGWIN__) + /* + * Allow Windows drive letters. + */ + if ((forbid == ':') && (*cur == forbid)) + NEXT(cur); +#endif + + while (ISA_PCHAR(uri, cur) && (*cur != forbid)) NEXT(cur); *str = cur; return (0); @@ -597,16 +634,18 @@ xmlParse3986PathAbEmpty(xmlURIPtr uri, const char **str)
while (*cur == '/') { cur++; - ret = xmlParse3986Segment(&cur, 0, 1); + ret = xmlParse3986Segment(uri, &cur, 0, 1); if (ret != 0) return(ret); } if (uri != NULL) { if (uri->path != NULL) xmlFree(uri->path); if (*str != cur) { - if (uri->cleanup & 2) + if (uri->cleanup & XML_URI_NO_UNESCAPE) uri->path = STRNDUP(*str, cur - *str); else uri->path = xmlURIUnescapeString(*str, cur - *str, NULL); + if (uri->path == NULL) + return (-1); } else { uri->path = NULL; } @@ -638,21 +677,23 @@ xmlParse3986PathAbsolute(xmlURIPtr uri, const char **str) if (*cur != '/') return(1); cur++; - ret = xmlParse3986Segment(&cur, 0, 0); + ret = xmlParse3986Segment(uri, &cur, 0, 0); if (ret == 0) { while (*cur == '/') { cur++; - ret = xmlParse3986Segment(&cur, 0, 1); + ret = xmlParse3986Segment(uri, &cur, 0, 1); if (ret != 0) return(ret); } } if (uri != NULL) { if (uri->path != NULL) xmlFree(uri->path); if (cur != *str) { - if (uri->cleanup & 2) + if (uri->cleanup & XML_URI_NO_UNESCAPE) uri->path = STRNDUP(*str, cur - *str); else uri->path = xmlURIUnescapeString(*str, cur - *str, NULL); + if (uri->path == NULL) + return (-1); } else { uri->path = NULL; } @@ -681,20 +722,22 @@ xmlParse3986PathRootless(xmlURIPtr uri, const char **str)
cur = *str;
- ret = xmlParse3986Segment(&cur, 0, 0); + ret = xmlParse3986Segment(uri, &cur, 0, 0); if (ret != 0) return(ret); while (*cur == '/') { cur++; - ret = xmlParse3986Segment(&cur, 0, 1); + ret = xmlParse3986Segment(uri, &cur, 0, 1); if (ret != 0) return(ret); } if (uri != NULL) { if (uri->path != NULL) xmlFree(uri->path); if (cur != *str) { - if (uri->cleanup & 2) + if (uri->cleanup & XML_URI_NO_UNESCAPE) uri->path = STRNDUP(*str, cur - *str); else uri->path = xmlURIUnescapeString(*str, cur - *str, NULL); + if (uri->path == NULL) + return (-1); } else { uri->path = NULL; } @@ -723,20 +766,22 @@ xmlParse3986PathNoScheme(xmlURIPtr uri, const char **str)
cur = *str;
- ret = xmlParse3986Segment(&cur, ':', 0); + ret = xmlParse3986Segment(uri, &cur, ':', 0); if (ret != 0) return(ret); while (*cur == '/') { cur++; - ret = xmlParse3986Segment(&cur, 0, 1); + ret = xmlParse3986Segment(uri, &cur, 0, 1); if (ret != 0) return(ret); } if (uri != NULL) { if (uri->path != NULL) xmlFree(uri->path); if (cur != *str) { - if (uri->cleanup & 2) + if (uri->cleanup & XML_URI_NO_UNESCAPE) uri->path = STRNDUP(*str, cur - *str); else uri->path = xmlURIUnescapeString(*str, cur - *str, NULL); + if (uri->path == NULL) + return (-1); } else { uri->path = NULL; } @@ -784,7 +829,7 @@ xmlParse3986HierPart(xmlURIPtr uri, const char **str) } else if (*cur == '/') { ret = xmlParse3986PathAbsolute(uri, &cur); if (ret != 0) return(ret); - } else if (ISA_PCHAR(cur)) { + } else if (ISA_PCHAR(uri, cur)) { ret = xmlParse3986PathRootless(uri, &cur); if (ret != 0) return(ret); } else { @@ -827,7 +872,7 @@ xmlParse3986RelativeRef(xmlURIPtr uri, const char *str) { } else if (*str == '/') { ret = xmlParse3986PathAbsolute(uri, &str); if (ret != 0) return(ret); - } else if (ISA_PCHAR(str)) { + } else if (ISA_PCHAR(uri, str)) { ret = xmlParse3986PathNoScheme(uri, &str); if (ret != 0) return(ret); } else { @@ -922,6 +967,8 @@ xmlParse3986URIReference(xmlURIPtr uri, const char *str) { * it fails. */ ret = xmlParse3986URI(uri, str); + if (ret < 0) + return(ret); if (ret != 0) { xmlCleanURI(uri); ret = xmlParse3986RelativeRef(uri, str); @@ -934,30 +981,58 @@ xmlParse3986URIReference(xmlURIPtr uri, const char *str) { }
/** - * xmlParseURI: + * xmlParseURISafe: * @str: the URI string to analyze + * @uriOut: optional pointer to parsed URI * * Parse an URI based on RFC 3986 * * URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ] * - * Returns a newly built xmlURIPtr or NULL in case of error + * Available since 2.13.0. + * + * Returns 0 on success, an error code (typically 1) if the URI is invalid + * or -1 if a memory allocation failed. */ -xmlURIPtr -xmlParseURI(const char *str) { +int +xmlParseURISafe(const char *str, xmlURIPtr *uriOut) { xmlURIPtr uri; int ret;
+ if (uriOut == NULL) + return(1); + *uriOut = NULL; if (str == NULL) - return(NULL); + return(1); + uri = xmlCreateURI(); - if (uri != NULL) { - ret = xmlParse3986URIReference(uri, str); - if (ret) { - xmlFreeURI(uri); - return(NULL); - } + if (uri == NULL) + return(-1); + + ret = xmlParse3986URIReference(uri, str); + if (ret) { + xmlFreeURI(uri); + return(ret); } + + *uriOut = uri; + return(0); +} + +/** + * xmlParseURI: + * @str: the URI string to analyze + * + * Parse an URI based on RFC 3986 + * + * URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ] + * + * Returns a newly built xmlURIPtr or NULL in case of error + */ +xmlURIPtr +xmlParseURI(const char *str) { + xmlURIPtr uri; + xmlParseURISafe(str, &uri); return(uri); }
@@ -999,7 +1074,7 @@ xmlParseURIRaw(const char *str, int raw) { uri = xmlCreateURI(); if (uri != NULL) { if (raw) { - uri->cleanup |= 2; + uri->cleanup |= XML_URI_NO_UNESCAPE; } ret = xmlParseURIReference(uri, str); if (ret) { @@ -1028,10 +1103,8 @@ xmlCreateURI(void) { xmlURIPtr ret;
ret = (xmlURIPtr) xmlMalloc(sizeof(xmlURI)); - if (ret == NULL) { - xmlURIErrMemory("creating URI structure\n"); + if (ret == NULL) return(NULL); - } memset(ret, 0, sizeof(xmlURI)); ret->port = PORT_EMPTY; return(ret); @@ -1048,16 +1121,12 @@ xmlSaveUriRealloc(xmlChar *ret, int *max) { xmlChar *temp; int tmp;
- if (*max > MAX_URI_LENGTH) { - xmlURIErrMemory("reaching arbitrary MAX_URI_LENGTH limit\n"); + if (*max > MAX_URI_LENGTH) return(NULL); - } tmp = *max * 2; temp = (xmlChar *) xmlRealloc(ret, (tmp + 1)); - if (temp == NULL) { - xmlURIErrMemory("saving URI\n"); + if (temp == NULL) return(NULL); - } *max = tmp; return(temp); } @@ -1083,10 +1152,8 @@ xmlSaveUri(xmlURIPtr uri) {
max = 80; ret = (xmlChar *) xmlMallocAtomic(max + 1); - if (ret == NULL) { - xmlURIErrMemory("saving URI\n"); + if (ret == NULL) return(NULL); - } len = 0;
if (uri->scheme != NULL) { @@ -1414,195 +1481,136 @@ xmlFreeURI(xmlURIPtr uri) { * * ************************************************************************/
+static int +xmlIsPathSeparator(int c, int isFile) { + (void) isFile; + + if (c == '/') + return(1); + +#if defined(_WIN32) || defined(__CYGWIN__) + if (isFile && (c == '\')) + return(1); +#endif + + return(0); +} + /** - * xmlNormalizeURIPath: + * xmlNormalizePath: * @path: pointer to the path string + * @isFile: true for filesystem paths, false for URIs * - * Applies the 5 normalization steps to a path string--that is, RFC 2396 - * Section 5.2, steps 6.c through 6.g. - * - * Normalization occurs directly on the string, no new allocation is done + * Normalize a filesystem path or URI. * * Returns 0 or an error code */ -int -xmlNormalizeURIPath(char *path) { +static int +xmlNormalizePath(char *path, int isFile) { char *cur, *out; + int numSeg = 0;
if (path == NULL) return(-1);
- /* Skip all initial "/" chars. We want to get to the beginning of the - * first non-empty segment. - */ cur = path; - while (cur[0] == '/') - ++cur; - if (cur[0] == '\0') - return(0); + out = path;
- /* Keep everything we've seen so far. */ - out = cur; + if (*cur == 0) + return(0);
- /* - * Analyze each segment in sequence for cases (c) and (d). - */ - while (cur[0] != '\0') { - /* - * c) All occurrences of "./", where "." is a complete path segment, - * are removed from the buffer string. - */ - if ((cur[0] == '.') && (cur[1] == '/')) { - cur += 2; - /* '//' normalization should be done at this point too */ - while (cur[0] == '/') - cur++; - continue; - } - - /* - * d) If the buffer string ends with "." as a complete path segment, - * that "." is removed. - */ - if ((cur[0] == '.') && (cur[1] == '\0')) - break; - - /* Otherwise keep the segment. */ - while (cur[0] != '/') { - if (cur[0] == '\0') - goto done_cd; - (out++)[0] = (cur++)[0]; - } - /* normalize // */ - while ((cur[0] == '/') && (cur[1] == '/')) - cur++; - - (out++)[0] = (cur++)[0]; + if (xmlIsPathSeparator(*cur, isFile)) { + cur++; + *out++ = '/'; } - done_cd: - out[0] = '\0'; - - /* Reset to the beginning of the first segment for the next sequence. */ - cur = path; - while (cur[0] == '/') - ++cur; - if (cur[0] == '\0') - return(0); - - /* - * Analyze each segment in sequence for cases (e) and (f). - * - * e) All occurrences of "<segment>/../", where <segment> is a - * complete path segment not equal to "..", are removed from the - * buffer string. Removal of these path segments is performed - * iteratively, removing the leftmost matching pattern on each - * iteration, until no matching pattern remains. - * - * f) If the buffer string ends with "<segment>/..", where <segment> - * is a complete path segment not equal to "..", that - * "<segment>/.." is removed. - * - * To satisfy the "iterative" clause in (e), we need to collapse the - * string every time we find something that needs to be removed. Thus, - * we don't need to keep two pointers into the string: we only need a - * "current position" pointer. - */ - while (1) { - char *segp, *tmp; - - /* At the beginning of each iteration of this loop, "cur" points to - * the first character of the segment we want to examine. - */ - - /* Find the end of the current segment. */ - segp = cur; - while ((segp[0] != '/') && (segp[0] != '\0')) - ++segp; - - /* If this is the last segment, we're done (we need at least two - * segments to meet the criteria for the (e) and (f) cases). - */ - if (segp[0] == '\0') - break;
- /* If the first segment is "..", or if the next segment _isn't_ "..", - * keep this segment and try the next one. + while (*cur != 0) { + /* + * At this point, out is either empty or ends with a separator. + * Collapse multiple separators first. */ - ++segp; - if (((cur[0] == '.') && (cur[1] == '.') && (segp == cur+3)) - || ((segp[0] != '.') || (segp[1] != '.') - || ((segp[2] != '/') && (segp[2] != '\0')))) { - cur = segp; - continue; + while (xmlIsPathSeparator(*cur, isFile)) { +#if defined(_WIN32) || defined(__CYGWIN__) + /* Allow two separators at start of path */ + if ((isFile) && (out == path + 1)) + *out++ = '/'; +#endif + cur++; }
- /* If we get here, remove this segment and the next one and back up - * to the previous segment (if there is one), to implement the - * "iteratively" clause. It's pretty much impossible to back up - * while maintaining two pointers into the buffer, so just compact - * the whole buffer now. - */ + if (*cur == '.') { + if (cur[1] == 0) { + /* Ignore "." at end of path */ + break; + } else if (xmlIsPathSeparator(cur[1], isFile)) { + /* Skip "./" */ + cur += 2; + continue; + } else if ((cur[1] == '.') && + ((cur[2] == 0) || xmlIsPathSeparator(cur[2], isFile))) { + if (numSeg > 0) { + /* Handle ".." by removing last segment */ + do { + out--; + } while ((out > path) && + !xmlIsPathSeparator(out[-1], isFile)); + numSeg--; + + if (cur[2] == 0) + break; + cur += 3; + continue; + } else if (out[0] == '/') { + /* Ignore extraneous ".." in absolute paths */ + if (cur[2] == 0) + break; + cur += 3; + continue; + } else { + /* Keep "../" at start of relative path */ + numSeg--; + } + } + }
- /* If this is the end of the buffer, we're done. */ - if (segp[2] == '\0') { - cur[0] = '\0'; - break; + /* Copy segment */ + while ((*cur != 0) && !xmlIsPathSeparator(*cur, isFile)) { + *out++ = *cur++; } - /* Valgrind complained, strcpy(cur, segp + 3); */ - /* string will overlap, do not use strcpy */ - tmp = cur; - segp += 3; - while ((*tmp++ = *segp++) != 0) - ; - - /* If there are no previous segments, then keep going from here. */ - segp = cur; - while ((segp > path) && ((--segp)[0] == '/')) - ; - if (segp == path) - continue; - - /* "segp" is pointing to the end of a previous segment; find it's - * start. We need to back up to the previous segment and start - * over with that to handle things like "foo/bar/../..". If we - * don't do this, then on the first pass we'll remove the "bar/..", - * but be pointing at the second ".." so we won't realize we can also - * remove the "foo/..". - */ - cur = segp; - while ((cur > path) && (cur[-1] != '/')) - --cur; - } - out[0] = '\0';
- /* - * g) If the resulting buffer string still begins with one or more - * complete path segments of "..", then the reference is - * considered to be in error. Implementations may handle this - * error by retaining these components in the resolved path (i.e., - * treating them as part of the final URI), by removing them from - * the resolved path (i.e., discarding relative levels above the - * root), or by avoiding traversal of the reference. - * - * We discard them from the final path. - */ - if (path[0] == '/') { - cur = path; - while ((cur[0] == '/') && (cur[1] == '.') && (cur[2] == '.') - && ((cur[3] == '/') || (cur[3] == '\0'))) - cur += 3; + /* Copy separator */ + if (*cur != 0) { + cur++; + *out++ = '/'; + }
- if (cur != path) { - out = path; - while (cur[0] != '\0') - (out++)[0] = (cur++)[0]; - out[0] = 0; - } + numSeg++; }
+ /* Keep "." if output is empty and it's a file */ + if ((isFile) && (out <= path)) + *out++ = '.'; + *out = 0; + return(0); }
+/** + * xmlNormalizeURIPath: + * @path: pointer to the path string + * + * Applies the 5 normalization steps to a path string--that is, RFC 2396 + * Section 5.2, steps 6.c through 6.g. + * + * Normalization occurs directly on the string, no new allocation is done + * + * Returns 0 or an error code + */ +int +xmlNormalizeURIPath(char *path) { + return(xmlNormalizePath(path, 0)); +} + static int is_hex(char c) { if (((c >= '0') && (c <= '9')) || ((c >= 'a') && (c <= 'f')) || @@ -1637,10 +1645,8 @@ xmlURIUnescapeString(const char *str, int len, char *target) {
if (target == NULL) { ret = (char *) xmlMallocAtomic(len + 1); - if (ret == NULL) { - xmlURIErrMemory("unescaping URI value\n"); + if (ret == NULL) return(NULL); - } } else ret = target; in = str; @@ -1680,8 +1686,9 @@ xmlURIUnescapeString(const char *str, int len, char *target) { * @str: string to escape * @list: exception list string of chars not to escape * - * This routine escapes a string to hex, ignoring reserved characters - * (a-z, A-Z, 0-9, "@-_.!~*'()") and the characters in the exception list. + * This routine escapes a string to hex, ignoring unreserved characters + * a-z, A-Z, 0-9, "-._~", a few sub-delims "!*'()", the gen-delim "@" + * (why?) and the characters in the exception list. * * Returns a new escaped string or NULL in case of error. */ @@ -1697,25 +1704,24 @@ xmlURIEscapeStr(const xmlChar *str, const xmlChar *list) { if (str[0] == 0) return(xmlStrdup(str)); len = xmlStrlen(str); - if (!(len > 0)) return(NULL);
len += 20; ret = (xmlChar *) xmlMallocAtomic(len); - if (ret == NULL) { - xmlURIErrMemory("escaping URI value\n"); + if (ret == NULL) return(NULL); - } in = (const xmlChar *) str; out = 0; while(*in != 0) { if (len - out <= 3) { - temp = xmlSaveUriRealloc(ret, &len); + if (len > INT_MAX / 2) + return(NULL); + temp = xmlRealloc(ret, len * 2); if (temp == NULL) { - xmlURIErrMemory("escaping URI value\n"); xmlFree(ret); return(NULL); } ret = temp; + len *= 2; }
ch = *in; @@ -1773,7 +1779,7 @@ xmlURIEscape(const xmlChar * str) /* * Allow escaping errors in the unescaped form */ - uri->cleanup = 1; + uri->cleanup = XML_URI_ALLOW_UNWISE; ret2 = xmlParseURIReference(uri, (const char *)str); if (ret2) { xmlFreeURI(uri); @@ -1787,7 +1793,6 @@ xmlURIEscape(const xmlChar * str) ret = NULL;
#define NULLCHK(p) if(!p) { \ - xmlURIErrMemory("escaping URI value\n"); \ xmlFreeURI(uri); \ xmlFree(ret); \ return NULL; } \ @@ -1883,10 +1888,132 @@ xmlURIEscape(const xmlChar * str) * * ************************************************************************/
+static int +xmlIsAbsolutePath(const xmlChar *path) { + int c = path[0]; + + if (xmlIsPathSeparator(c, 1)) + return(1); + +#if defined(_WIN32) || defined(__CYGWIN__) + if ((((c >= 'A') && (c <= 'Z')) || + ((c >= 'a') && (c <= 'z'))) && + (path[1] == ':')) + return(1); +#endif + + return(0); +} + /** - * xmlBuildURI: + * xmlResolvePath: + * @ref: the filesystem path + * @base: the base value + * @out: pointer to result URI + * + * Resolves a filesystem path from a base path. + * + * Returns 0 on success, -1 if a memory allocation failed or an error + * code if URI or base are invalid. + */ +static int +xmlResolvePath(const xmlChar *escRef, const xmlChar *base, xmlChar **out) { + const xmlChar *fragment; + xmlChar *tmp = NULL; + xmlChar *ref = NULL; + xmlChar *result = NULL; + int ret = -1; + int i; + + if (out == NULL) + return(1); + *out = NULL; + + if ((escRef == NULL) || (escRef[0] == 0)) { + if ((base == NULL) || (base[0] == 0)) + return(1); + ref = xmlStrdup(base); + if (ref == NULL) + goto err_memory; + *out = ref; + return(0); + } + + /* + * If a URI is resolved, we can assume it is a valid URI and not + * a filesystem path. This means we have to unescape the part + * before the fragment. + */ + fragment = xmlStrchr(escRef, '#'); + if (fragment != NULL) { + tmp = xmlStrndup(escRef, fragment - escRef); + if (tmp == NULL) + goto err_memory; + escRef = tmp; + } + + ref = (xmlChar *) xmlURIUnescapeString((char *) escRef, -1, NULL); + if (ref == NULL) + goto err_memory; + + if ((base == NULL) || (base[0] == 0)) + goto done; + + if (xmlIsAbsolutePath(ref)) + goto done; + + /* + * Remove last segment from base + */ + i = xmlStrlen(base); + while ((i > 0) && !xmlIsPathSeparator(base[i-1], 1)) + i--; + + /* + * Concatenate base and ref + */ + if (i > 0) { + int refLen = xmlStrlen(ref); + + result = xmlMalloc(i + refLen + 1); + if (result == NULL) + goto err_memory; + + memcpy(result, base, i); + memcpy(result + i, ref, refLen + 1); + } + + /* + * Normalize + */ + xmlNormalizePath((char *) result, 1); + +done: + if (result == NULL) { + result = ref; + ref = NULL; + } + + if (fragment != NULL) { + result = xmlStrcat(result, fragment); + if (result == NULL) + goto err_memory; + } + + *out = result; + ret = 0; + +err_memory: + xmlFree(tmp); + xmlFree(ref); + return(ret); +} + +/** + * xmlBuildURISafe: * @URI: the URI instance found in the document * @base: the base value + * @valPtr: pointer to result URI * * Computes he final URI of the reference done by checking that * the given URI is valid, and building the final URI using the @@ -1895,17 +2022,34 @@ xmlURIEscape(const xmlChar * str) * * 5.2. Resolving Relative References to Absolute Form * - * Returns a new URI string (to be freed by the caller) or NULL in case - * of error. + * Available since 2.13.0. + * + * Returns 0 on success, -1 if a memory allocation failed or an error + * code if URI or base are invalid. */ -xmlChar * -xmlBuildURI(const xmlChar *URI, const xmlChar *base) { +int +xmlBuildURISafe(const xmlChar *URI, const xmlChar *base, xmlChar **valPtr) { xmlChar *val = NULL; int ret, len, indx, cur, out; xmlURIPtr ref = NULL; xmlURIPtr bas = NULL; xmlURIPtr res = NULL;
+ if (valPtr == NULL) + return(1); + *valPtr = NULL; + + if (URI == NULL) + return(1); + + if (base == NULL) { + val = xmlStrdup(URI); + if (val == NULL) + return(-1); + *valPtr = val; + return(0); + } + /* * 1) The URI reference is parsed into the potential four components and * fragment identifier, as described in Section 4.3. @@ -1914,18 +2058,10 @@ xmlBuildURI(const xmlChar *URI, const xmlChar *base) { * as a reference to "." rather than as a synonym for the current * URI. Should we do that here? */ - if (URI == NULL) - ret = -1; - else { - if (*URI) { - ref = xmlCreateURI(); - if (ref == NULL) - goto done; - ret = xmlParseURIReference(ref, (const char *) URI); - } - else - ret = 0; - } + if (URI[0] != 0) + ret = xmlParseURISafe((const char *) URI, &ref); + else + ret = 0; if (ret != 0) goto done; if ((ref != NULL) && (ref->scheme != NULL)) { @@ -1933,19 +2069,47 @@ xmlBuildURI(const xmlChar *URI, const xmlChar *base) { * The URI is absolute don't modify. */ val = xmlStrdup(URI); + if (val == NULL) + ret = -1; goto done; } - if (base == NULL) - ret = -1; - else { - bas = xmlCreateURI(); - if (bas == NULL) - goto done; - ret = xmlParseURIReference(bas, (const char *) base); + + /* + * If base has no scheme or authority, it is assumed to be a + * filesystem path. + */ + if (xmlStrstr(base, BAD_CAST "://") == NULL) { + xmlFreeURI(ref); + return(xmlResolvePath(URI, base, valPtr)); + } + +#if defined(_WIN32) || defined(__CYGWIN__) + /* + * Resolve paths with a Windows drive letter as filesystem path + * even if base has a scheme. + */ + if ((ref != NULL) && (ref->path != NULL)) { + int c = ref->path[0]; + + if ((((c >= 'A') && (c <= 'Z')) || + ((c >= 'a') && (c <= 'z'))) && + (ref->path[1] == ':')) { + xmlFreeURI(ref); + return(xmlResolvePath(URI, base, valPtr)); + } } +#endif + + ret = xmlParseURISafe((const char *) base, &bas); + if (ret < 0) + goto done; if (ret != 0) { - if (ref) + if (ref) { + ret = 0; val = xmlSaveUri(ref); + if (val == NULL) + ret = -1; + } goto done; } if (ref == NULL) { @@ -1957,6 +2121,8 @@ xmlBuildURI(const xmlChar *URI, const xmlChar *base) { bas->fragment = NULL; } val = xmlSaveUri(bas); + if (val == NULL) + ret = -1; goto done; }
@@ -1972,35 +2138,62 @@ xmlBuildURI(const xmlChar *URI, const xmlChar *base) { * defined while still treating this as a reference to the current * document. */ + ret = -1; res = xmlCreateURI(); if (res == NULL) goto done; if ((ref->scheme == NULL) && (ref->path == NULL) && ((ref->authority == NULL) && (ref->server == NULL) && (ref->port == PORT_EMPTY))) { - if (bas->scheme != NULL) + if (bas->scheme != NULL) { res->scheme = xmlMemStrdup(bas->scheme); - if (bas->authority != NULL) + if (res->scheme == NULL) + goto done; + } + if (bas->authority != NULL) { res->authority = xmlMemStrdup(bas->authority); - else { - if (bas->server != NULL) + if (res->authority == NULL) + goto done; + } else { + if (bas->server != NULL) { res->server = xmlMemStrdup(bas->server); - if (bas->user != NULL) + if (res->server == NULL) + goto done; + } + if (bas->user != NULL) { res->user = xmlMemStrdup(bas->user); + if (res->user == NULL) + goto done; + } res->port = bas->port; } - if (bas->path != NULL) + if (bas->path != NULL) { res->path = xmlMemStrdup(bas->path); - if (ref->query_raw != NULL) + if (res->path == NULL) + goto done; + } + if (ref->query_raw != NULL) { res->query_raw = xmlMemStrdup (ref->query_raw); - else if (ref->query != NULL) + if (res->query_raw == NULL) + goto done; + } else if (ref->query != NULL) { res->query = xmlMemStrdup(ref->query); - else if (bas->query_raw != NULL) + if (res->query == NULL) + goto done; + } else if (bas->query_raw != NULL) { res->query_raw = xmlMemStrdup(bas->query_raw); - else if (bas->query != NULL) + if (res->query_raw == NULL) + goto done; + } else if (bas->query != NULL) { res->query = xmlMemStrdup(bas->query); - if (ref->fragment != NULL) + if (res->query == NULL) + goto done; + } + if (ref->fragment != NULL) { res->fragment = xmlMemStrdup(ref->fragment); + if (res->fragment == NULL) + goto done; + } goto step_7; }
@@ -2012,17 +2205,30 @@ xmlBuildURI(const xmlChar *URI, const xmlChar *base) { */ if (ref->scheme != NULL) { val = xmlSaveUri(ref); + if (val != NULL) + ret = 0; goto done; } - if (bas->scheme != NULL) + if (bas->scheme != NULL) { res->scheme = xmlMemStrdup(bas->scheme); + if (res->scheme == NULL) + goto done; + }
- if (ref->query_raw != NULL) + if (ref->query_raw != NULL) { res->query_raw = xmlMemStrdup(ref->query_raw); - else if (ref->query != NULL) + if (res->query_raw == NULL) + goto done; + } else if (ref->query != NULL) { res->query = xmlMemStrdup(ref->query); - if (ref->fragment != NULL) + if (res->query == NULL) + goto done; + } + if (ref->fragment != NULL) { res->fragment = xmlMemStrdup(ref->fragment); + if (res->fragment == NULL) + goto done; + }
/* * 4) If the authority component is defined, then the reference is a @@ -2033,26 +2239,45 @@ xmlBuildURI(const xmlChar *URI, const xmlChar *base) { */ if ((ref->authority != NULL) || (ref->server != NULL) || (ref->port != PORT_EMPTY)) { - if (ref->authority != NULL) + if (ref->authority != NULL) { res->authority = xmlMemStrdup(ref->authority); - else { - if (ref->server != NULL) + if (res->authority == NULL) + goto done; + } else { + if (ref->server != NULL) { res->server = xmlMemStrdup(ref->server); - if (ref->user != NULL) + if (res->server == NULL) + goto done; + } + if (ref->user != NULL) { res->user = xmlMemStrdup(ref->user); + if (res->user == NULL) + goto done; + } res->port = ref->port; } - if (ref->path != NULL) + if (ref->path != NULL) { res->path = xmlMemStrdup(ref->path); + if (res->path == NULL) + goto done; + } goto step_7; } - if (bas->authority != NULL) + if (bas->authority != NULL) { res->authority = xmlMemStrdup(bas->authority); - else if ((bas->server != NULL) || (bas->port != PORT_EMPTY)) { - if (bas->server != NULL) + if (res->authority == NULL) + goto done; + } else if ((bas->server != NULL) || (bas->port != PORT_EMPTY)) { + if (bas->server != NULL) { res->server = xmlMemStrdup(bas->server); - if (bas->user != NULL) + if (res->server == NULL) + goto done; + } + if (bas->user != NULL) { res->user = xmlMemStrdup(bas->user); + if (res->user == NULL) + goto done; + } res->port = bas->port; }
@@ -2062,6 +2287,8 @@ xmlBuildURI(const xmlChar *URI, const xmlChar *base) { */ if ((ref->path != NULL) && (ref->path[0] == '/')) { res->path = xmlMemStrdup(ref->path); + if (res->path == NULL) + goto done; goto step_7; }
@@ -2080,10 +2307,8 @@ xmlBuildURI(const xmlChar *URI, const xmlChar *base) { if (bas->path != NULL) len += strlen(bas->path); res->path = (char *) xmlMallocAtomic(len); - if (res->path == NULL) { - xmlURIErrMemory("resolving URI against base\n"); + if (res->path == NULL) goto done; - } res->path[0] = 0;
/* @@ -2139,6 +2364,8 @@ step_7: * reference. */ val = xmlSaveUri(res); + if (val != NULL) + ret = 0;
done: if (ref != NULL) @@ -2147,13 +2374,161 @@ done: xmlFreeURI(bas); if (res != NULL) xmlFreeURI(res); - return(val); + *valPtr = val; + return(ret); }
/** - * xmlBuildRelativeURI: + * xmlBuildURI: + * @URI: the URI instance found in the document + * @base: the base value + * + * Computes he final URI of the reference done by checking that + * the given URI is valid, and building the final URI using the + * base URI. This is processed according to section 5.2 of the + * RFC 2396 + * + * 5.2. Resolving Relative References to Absolute Form + * + * Returns a new URI string (to be freed by the caller) or NULL in case + * of error. + */ +xmlChar * +xmlBuildURI(const xmlChar *URI, const xmlChar *base) { + xmlChar *out; + + xmlBuildURISafe(URI, base, &out); + return(out); +} + +static int +xmlParseUriOrPath(const char *str, xmlURIPtr *out, int *drive) { + xmlURIPtr uri; + char *buf = NULL; + int ret; + + *out = NULL; + *drive = 0; + + uri = xmlCreateURI(); + if (uri == NULL) { + ret = -1; + goto done; + } + + if (xmlStrstr(BAD_CAST str, BAD_CAST "://") == NULL) { + const char *path; + size_t pathSize; + int prependSlash = 0; + + buf = xmlMemStrdup(str); + if (buf == NULL) { + ret = -1; + goto done; + } + xmlNormalizePath(buf, /* isFile */ 1); + + path = buf; + + if (xmlIsAbsolutePath(BAD_CAST buf)) { +#if defined(_WIN32) || defined(__CYGWIN__) + const char *server = NULL; + int isFileScheme = 0; +#endif + +#if defined(_WIN32) || defined(__CYGWIN__) + if (strncmp(buf, "//?/UNC/", 8) == 0) { + server = buf + 8; + isFileScheme = 1; + } else if (strncmp(buf, "//?/", 4) == 0) { + path = buf + 3; + isFileScheme = 1; + } else if (strncmp(buf, "//", 2) == 0) { + server = buf + 2; + isFileScheme = 1; + } + + if (server != NULL) { + const char *end = strchr(server, '/'); + + if (end == NULL) { + uri->server = xmlMemStrdup(server); + path = "/"; + } else { + uri->server = (char *) xmlStrndup(BAD_CAST server, + end - server); + path = end; + } + if (uri->server == NULL) { + ret = -1; + goto done; + } + } + + if ((((path[0] >= 'A') && (path[0] <= 'Z')) || + ((path[0] >= 'a') && (path[0] <= 'z'))) && + (path[1] == ':')) { + prependSlash = 1; + isFileScheme = 1; + } + + if (isFileScheme) { + uri->scheme = xmlMemStrdup("file"); + if (uri->scheme == NULL) { + ret = -1; + goto done; + } + + if (uri->server == NULL) + uri->port = PORT_EMPTY_SERVER; + } +#endif + } + + pathSize = strlen(path); + uri->path = xmlMalloc(pathSize + prependSlash + 1); + if (uri->path == NULL) { + ret = -1; + goto done; + } + if (prependSlash) { + uri->path[0] = '/'; + memcpy(uri->path + 1, path, pathSize + 1); + } else { + memcpy(uri->path, path, pathSize + 1); + } + } else { + ret = xmlParseURIReference(uri, str); + if (ret != 0) + goto done; + + xmlNormalizePath(uri->path, /* isFile */ 0); + } + +#if defined(_WIN32) || defined(__CYGWIN__) + if ((uri->path[0] == '/') && + (((uri->path[1] >= 'A') && (uri->path[1] <= 'Z')) || + ((uri->path[1] >= 'a') && (uri->path[1] <= 'z'))) && + (uri->path[2] == ':')) + *drive = uri->path[1]; +#endif + + *out = uri; + uri = NULL; + ret = 0; + +done: + xmlFreeURI(uri); + xmlFree(buf); + + return(ret); +} + +/** + * xmlBuildRelativeURISafe: * @URI: the URI reference under consideration * @base: the base value + * @valPtr: pointer to result URI * * Expresses the URI of the reference in terms relative to the * base. Some examples of this operation include: @@ -2179,106 +2554,112 @@ done: * since this routine (for reasonable efficiency) assumes URI has * already been through some validation. * - * Returns a new URI string (to be freed by the caller) or NULL in case - * error. + * Available since 2.13.0. + * + * Returns 0 on success, -1 if a memory allocation failed or an error + * code if URI or base are invalid. */ -xmlChar * -xmlBuildRelativeURI (const xmlChar * URI, const xmlChar * base) +int +xmlBuildRelativeURISafe(const xmlChar * URI, const xmlChar * base, + xmlChar **valPtr) { xmlChar *val = NULL; - int ret; + int ret = 0; int ix; int nbslash = 0; int len; xmlURIPtr ref = NULL; xmlURIPtr bas = NULL; - xmlChar *bptr, *uptr, *vptr; + const xmlChar *bptr, *uptr, *rptr; + xmlChar *vptr; int remove_path = 0; + int refDrive, baseDrive;
+ if (valPtr == NULL) + return(1); + *valPtr = NULL; if ((URI == NULL) || (*URI == 0)) - return NULL; + return(1);
- /* - * First parse URI into a standard form - */ - ref = xmlCreateURI (); - if (ref == NULL) - return NULL; - /* If URI not already in "relative" form */ - if (URI[0] != '.') { - ret = xmlParseURIReference (ref, (const char *) URI); - if (ret != 0) - goto done; /* Error in URI, return NULL */ - } else - ref->path = (char *)xmlStrdup(URI); + ret = xmlParseUriOrPath((char *) URI, &ref, &refDrive); + if (ret < 0) + goto done; + if (ret != 0) { + /* Return URI if URI is invalid */ + ret = 0; + val = xmlStrdup(URI); + if (val == NULL) + ret = -1; + goto done; + }
- /* - * Next parse base into the same standard form - */ - if ((base == NULL) || (*base == 0)) { - val = xmlStrdup (URI); - goto done; + /* Return URI if base is empty */ + if ((base == NULL) || (*base == 0)) + goto done; + + ret = xmlParseUriOrPath((char *) base, &bas, &baseDrive); + if (ret < 0) + goto done; + if (ret != 0) { + /* Return URI if base is invalid */ + ret = 0; + goto done; } - bas = xmlCreateURI (); - if (bas == NULL) - goto done; - if (base[0] != '.') { - ret = xmlParseURIReference (bas, (const char *) base); - if (ret != 0) - goto done; /* Error in base, return NULL */ - } else - bas->path = (char *)xmlStrdup(base);
/* * If the scheme / server on the URI differs from the base, * just return the URI */ - if ((ref->scheme != NULL) && - ((bas->scheme == NULL) || - (xmlStrcmp ((xmlChar *)bas->scheme, (xmlChar *)ref->scheme)) || - (xmlStrcmp ((xmlChar *)bas->server, (xmlChar *)ref->server)) || - (bas->port != ref->port))) { - val = xmlStrdup (URI); + if ((xmlStrcmp ((xmlChar *)bas->scheme, (xmlChar *)ref->scheme)) || + (xmlStrcmp ((xmlChar *)bas->server, (xmlChar *)ref->server)) || + (bas->port != ref->port) || + (baseDrive != refDrive)) { goto done; } if (xmlStrEqual((xmlChar *)bas->path, (xmlChar *)ref->path)) { val = xmlStrdup(BAD_CAST ""); + if (val == NULL) + ret = -1; goto done; } if (bas->path == NULL) { val = xmlStrdup((xmlChar *)ref->path); - goto done; + if (val == NULL) { + ret = -1; + goto done; + } + goto escape; } if (ref->path == NULL) { ref->path = (char *) "/"; remove_path = 1; }
+ bptr = (xmlChar *) bas->path; + rptr = (xmlChar *) ref->path; + /* - * At this point (at last!) we can compare the two paths - * - * First we take care of the special case where either of the - * two path components may be missing (bug 316224) + * Return URI if URI and base aren't both absolute or relative. + */ + if ((bptr[0] == '/') != (rptr[0] == '/')) + goto done; + + /* + * At this point we can compare the two paths */ - bptr = (xmlChar *)bas->path; { - xmlChar *rptr = (xmlChar *) ref->path; int pos = 0;
/* * Next we compare the two strings and find where they first differ */ - if ((*rptr == '.') && (rptr[1] == '/')) - rptr += 2; - if ((*bptr == '.') && (bptr[1] == '/')) - bptr += 2; - else if ((*bptr == '/') && (*rptr != '/')) - bptr++; while ((bptr[pos] == rptr[pos]) && (bptr[pos] != 0)) pos++;
if (bptr[pos] == rptr[pos]) { val = xmlStrdup(BAD_CAST ""); + if (val == NULL) + ret = -1; goto done; /* (I can't imagine why anyone would do this) */ }
@@ -2306,6 +2687,8 @@ xmlBuildRelativeURI (const xmlChar * URI, const xmlChar * base) */ if (nbslash == 0 && !uptr[0]) { val = xmlStrdup(BAD_CAST "./"); + if (val == NULL) + ret = -1; goto done; }
@@ -2313,9 +2696,12 @@ xmlBuildRelativeURI (const xmlChar * URI, const xmlChar * base) }
if (nbslash == 0) { - if (uptr != NULL) + if (uptr != NULL) { /* exception characters from xmlSaveUri */ val = xmlURIEscapeStr(uptr, BAD_CAST "/;&=+$,"); + if (val == NULL) + ret = -1; + } goto done; }
@@ -2326,7 +2712,7 @@ xmlBuildRelativeURI (const xmlChar * URI, const xmlChar * base) */ val = (xmlChar *) xmlMalloc (len + 3 * nbslash); if (val == NULL) { - xmlURIErrMemory("building relative URI\n"); + ret = -1; goto done; } vptr = val; @@ -2354,13 +2740,24 @@ xmlBuildRelativeURI (const xmlChar * URI, const xmlChar * base) vptr[len - 1] = 0; }
+escape: /* escape the freshly-built path */ vptr = val; - /* exception characters from xmlSaveUri */ + /* exception characters from xmlSaveUri */ val = xmlURIEscapeStr(vptr, BAD_CAST "/;&=+$,"); + if (val == NULL) + ret = -1; + else + ret = 0; xmlFree(vptr);
done: + if ((ret == 0) && (val == NULL)) { + val = xmlSaveUri(ref); + if (val == NULL) + ret = -1; + } + /* * Free the working variables */ @@ -2370,153 +2767,75 @@ done: xmlFreeURI (ref); if (bas != NULL) xmlFreeURI (bas); + if (ret != 0) { + xmlFree(val); + val = NULL; + }
- return val; + *valPtr = val; + return(ret); +} + +/* + * xmlBuildRelativeURI: + * @URI: the URI reference under consideration + * @base: the base value + * + * See xmlBuildRelativeURISafe. + * + * Returns a new URI string (to be freed by the caller) or NULL in case + * error. + */ +xmlChar * +xmlBuildRelativeURI(const xmlChar * URI, const xmlChar * base) +{ + xmlChar *val; + + xmlBuildRelativeURISafe(URI, base, &val); + return(val); }
/** * xmlCanonicPath: * @path: the resource locator in a filesystem notation * - * Constructs a canonic path from the specified path. + * Prepares a path. + * + * If the path contains the substring "://", it is considered a + * Legacy Extended IRI. Characters which aren't allowed in URIs are + * escaped. + * + * Otherwise, the path is considered a filesystem path which is + * copied without modification. * - * Returns a new canonic path, or a duplicate of the path parameter if the - * construction fails. The caller is responsible for freeing the memory occupied + * The caller is responsible for freeing the memory occupied * by the returned string. If there is insufficient memory available, or the * argument is NULL, the function returns NULL. + * + * Returns the escaped path. */ -#define IS_WINDOWS_PATH(p) \ - ((p != NULL) && \ - (((p[0] >= 'a') && (p[0] <= 'z')) || \ - ((p[0] >= 'A') && (p[0] <= 'Z'))) && \ - (p[1] == ':') && ((p[2] == '/') || (p[2] == '\'))) xmlChar * xmlCanonicPath(const xmlChar *path) { -/* - * For Windows implementations, additional work needs to be done to - * replace backslashes in pathnames with "forward slashes" - */ -#if defined(_WIN32) - int len = 0; - char *p = NULL; -#endif - xmlURIPtr uri; xmlChar *ret; - const xmlChar *absuri;
if (path == NULL) return(NULL);
-#if defined(_WIN32) - /* - * We must not change the backslashes to slashes if the the path - * starts with \?\ - * Those paths can be up to 32k characters long. - * Was added specifically for OpenOffice, those paths can't be converted - * to URIs anyway. - */ - if ((path[0] == '\') && (path[1] == '\') && (path[2] == '?') && - (path[3] == '\') ) - return xmlStrdup((const xmlChar *) path); -#endif - - /* sanitize filename starting with // so it can be used as URI */ - if ((path[0] == '/') && (path[1] == '/') && (path[2] != '/')) - path++; - - if ((uri = xmlParseURI((const char *) path)) != NULL) { - xmlFreeURI(uri); - return xmlStrdup(path); - } - /* Check if this is an "absolute uri" */ - absuri = xmlStrstr(path, BAD_CAST "://"); - if (absuri != NULL) { - int l, j; - unsigned char c; - xmlChar *escURI; - - /* - * this looks like an URI where some parts have not been - * escaped leading to a parsing problem. Check that the first - * part matches a protocol. - */ - l = absuri - path; - /* Bypass if first part (part before the '://') is > 20 chars */ - if ((l <= 0) || (l > 20)) - goto path_processing; - /* Bypass if any non-alpha characters are present in first part */ - for (j = 0;j < l;j++) { - c = path[j]; - if (!(((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')))) - goto path_processing; - } - - /* Escape all except the characters specified in the supplied path */ - escURI = xmlURIEscapeStr(path, BAD_CAST ":/?_.#&;="); - if (escURI != NULL) { - /* Try parsing the escaped path */ - uri = xmlParseURI((const char *) escURI); - /* If successful, return the escaped string */ - if (uri != NULL) { - xmlFreeURI(uri); - return escURI; - } - xmlFree(escURI); - } - } - -path_processing: -/* For Windows implementations, replace backslashes with 'forward slashes' */ -#if defined(_WIN32) - /* - * Create a URI structure - */ - uri = xmlCreateURI(); - if (uri == NULL) { /* Guard against 'out of memory' */ - return(NULL); - } - - len = xmlStrlen(path); - if ((len > 2) && IS_WINDOWS_PATH(path)) { - /* make the scheme 'file' */ - uri->scheme = (char *) xmlStrdup(BAD_CAST "file"); - /* allocate space for leading '/' + path + string terminator */ - uri->path = xmlMallocAtomic(len + 2); - if (uri->path == NULL) { - xmlFreeURI(uri); /* Guard against 'out of memory' */ - return(NULL); - } - /* Put in leading '/' plus path */ - uri->path[0] = '/'; - p = uri->path + 1; - strncpy(p, (char *) path, len + 1); - } else { - uri->path = (char *) xmlStrdup(path); - if (uri->path == NULL) { - xmlFreeURI(uri); - return(NULL); - } - p = uri->path; - } - /* Now change all occurrences of '' to '/' */ - while (*p != '\0') { - if (*p == '\') - *p = '/'; - p++; - } - - if (uri->scheme == NULL) { - ret = xmlStrdup((const xmlChar *) uri->path); + if (xmlStrstr(path, BAD_CAST "://") != NULL) { + /* + * Escape all characters except reserved, unreserved and the + * percent sign. + * + * xmlURIEscapeStr already keeps unreserved characters, so we + * pass gen-delims, sub-delims and "%" to ignore. + */ + ret = xmlURIEscapeStr(path, BAD_CAST ":/?#[]@!$&()*+,;='%"); } else { - ret = xmlSaveUri(uri); + ret = xmlStrdup((const xmlChar *) path); }
- xmlFreeURI(uri); -#else - ret = xmlStrdup((const xmlChar *) path); -#endif return(ret); }
@@ -2534,41 +2853,5 @@ path_processing: xmlChar * xmlPathToURI(const xmlChar *path) { - xmlURIPtr uri; - xmlURI temp; - xmlChar *ret, *cal; - - if (path == NULL) - return(NULL); - - if ((uri = xmlParseURI((const char *) path)) != NULL) { - xmlFreeURI(uri); - return xmlStrdup(path); - } - cal = xmlCanonicPath(path); - if (cal == NULL) - return(NULL); -#if defined(_WIN32) - /* xmlCanonicPath can return an URI on Windows (is that the intended behaviour?) - If 'cal' is a valid URI already then we are done here, as continuing would make - it invalid. */ - if ((uri = xmlParseURI((const char *) cal)) != NULL) { - xmlFreeURI(uri); - return cal; - } - /* 'cal' can contain a relative path with backslashes. If that is processed - by xmlSaveURI, they will be escaped and the external entity loader machinery - will fail. So convert them to slashes. Misuse 'ret' for walking. */ - ret = cal; - while (*ret != '\0') { - if (*ret == '\') - *ret = '/'; - ret++; - } -#endif - memset(&temp, 0, sizeof(temp)); - temp.path = (char *) cal; - ret = xmlSaveUri(&temp); - xmlFree(cal); - return(ret); + return(xmlCanonicPath(path)); } diff --git a/libs/xml2/valid.c b/libs/xml2/valid.c index ea3a65faac8..f6767f9ab11 100644 --- a/libs/xml2/valid.c +++ b/libs/xml2/valid.c @@ -21,18 +21,16 @@ #include <libxml/parserInternals.h> #include <libxml/xmlerror.h> #include <libxml/list.h> +#include <libxml/xmlsave.h>
#include "private/error.h" #include "private/parser.h" +#include "private/regexp.h" +#include "private/save.h" +#include "private/tree.h"
static xmlElementPtr -xmlGetDtdElementDesc2(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name, - int create); - -#define TODO \ - xmlGenericError(xmlGenericErrorContext, \ - "Unimplemented block at %s:%d\n", \ - __FILE__, __LINE__); +xmlGetDtdElementDesc2(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name);
#ifdef LIBXML_VALID_ENABLED static int @@ -53,31 +51,56 @@ xmlValidateAttributeValueInternal(xmlDocPtr doc, xmlAttributeType type, * Handle an out of memory error */ static void -xmlVErrMemory(xmlValidCtxtPtr ctxt, const char *extra) +xmlVErrMemory(xmlValidCtxtPtr ctxt) { - xmlGenericErrorFunc channel = NULL; + if (ctxt != NULL) { + if (ctxt->flags & XML_VCTXT_USE_PCTXT) { + xmlCtxtErrMemory(ctxt->userData); + } else { + xmlRaiseMemoryError(NULL, ctxt->error, ctxt->userData, + XML_FROM_VALID, NULL); + } + } else { + xmlRaiseMemoryError(NULL, NULL, NULL, XML_FROM_VALID, NULL); + } +} + +static void +xmlDoErrValid(xmlValidCtxtPtr ctxt, xmlNodePtr node, + xmlParserErrors code, int level, + const xmlChar *str1, const xmlChar *str2, const xmlChar *str3, + int int1, + const char *msg, ...) { xmlParserCtxtPtr pctxt = NULL; - void *data = NULL; + va_list ap;
- if (ctxt != NULL) { - channel = ctxt->error; - data = ctxt->userData; - /* Look up flag to detect if it is part of a parsing - context */ - if (ctxt->flags & XML_VCTXT_USE_PCTXT) { - pctxt = ctxt->userData; - } + if (ctxt == NULL) + return; + if (ctxt->flags & XML_VCTXT_USE_PCTXT) + pctxt = ctxt->userData; + + va_start(ap, msg); + if (pctxt != NULL) { + xmlCtxtVErr(pctxt, node, XML_FROM_VALID, code, level, + str1, str2, str3, int1, msg, ap); + } else { + xmlGenericErrorFunc channel = NULL; + void *data = NULL; + int res; + + if (ctxt != NULL) { + channel = ctxt->error; + data = ctxt->userData; + } + res = xmlVRaiseError(NULL, channel, data, NULL, node, + XML_FROM_VALID, code, level, NULL, 0, + (const char *) str1, (const char *) str2, + (const char *) str2, int1, 0, + msg, ap); + if (res < 0) + xmlVErrMemory(ctxt); } - if (extra) - __xmlRaiseError(NULL, channel, data, - pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY, - XML_ERR_FATAL, NULL, 0, extra, NULL, NULL, 0, 0, - "Memory allocation failed : %s\n", extra); - else - __xmlRaiseError(NULL, channel, data, - pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY, - XML_ERR_FATAL, NULL, 0, NULL, NULL, NULL, 0, 0, - "Memory allocation failed\n"); + va_end(ap); }
/** @@ -92,29 +115,8 @@ static void LIBXML_ATTR_FORMAT(3,0) xmlErrValid(xmlValidCtxtPtr ctxt, xmlParserErrors error, const char *msg, const char *extra) { - xmlGenericErrorFunc channel = NULL; - xmlParserCtxtPtr pctxt = NULL; - void *data = NULL; - - if (ctxt != NULL) { - channel = ctxt->error; - data = ctxt->userData; - /* Look up flag to detect if it is part of a parsing - context */ - if (ctxt->flags & XML_VCTXT_USE_PCTXT) { - pctxt = ctxt->userData; - } - } - if (extra) - __xmlRaiseError(NULL, channel, data, - pctxt, NULL, XML_FROM_VALID, error, - XML_ERR_ERROR, NULL, 0, extra, NULL, NULL, 0, 0, - msg, extra); - else - __xmlRaiseError(NULL, channel, data, - pctxt, NULL, XML_FROM_VALID, error, - XML_ERR_ERROR, NULL, 0, NULL, NULL, NULL, 0, 0, - "%s", msg); + xmlDoErrValid(ctxt, NULL, error, XML_ERR_ERROR, (const xmlChar *) extra, + NULL, NULL, 0, msg, extra); }
#if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) @@ -135,25 +137,8 @@ xmlErrValidNode(xmlValidCtxtPtr ctxt, const char *msg, const xmlChar * str1, const xmlChar * str2, const xmlChar * str3) { - xmlStructuredErrorFunc schannel = NULL; - xmlGenericErrorFunc channel = NULL; - xmlParserCtxtPtr pctxt = NULL; - void *data = NULL; - - if (ctxt != NULL) { - channel = ctxt->error; - data = ctxt->userData; - /* Look up flag to detect if it is part of a parsing - context */ - if (ctxt->flags & XML_VCTXT_USE_PCTXT) { - pctxt = ctxt->userData; - } - } - __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error, - XML_ERR_ERROR, NULL, 0, - (const char *) str1, - (const char *) str2, - (const char *) str3, 0, 0, msg, str1, str2, str3); + xmlDoErrValid(ctxt, node, error, XML_ERR_ERROR, str1, str2, str3, 0, + msg, str1, str2, str3); } #endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
@@ -175,25 +160,8 @@ xmlErrValidNodeNr(xmlValidCtxtPtr ctxt, const char *msg, const xmlChar * str1, int int2, const xmlChar * str3) { - xmlStructuredErrorFunc schannel = NULL; - xmlGenericErrorFunc channel = NULL; - xmlParserCtxtPtr pctxt = NULL; - void *data = NULL; - - if (ctxt != NULL) { - channel = ctxt->error; - data = ctxt->userData; - /* Look up flag to detect if it is part of a parsing - context */ - if (ctxt->flags & XML_VCTXT_USE_PCTXT) { - pctxt = ctxt->userData; - } - } - __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error, - XML_ERR_ERROR, NULL, 0, - (const char *) str1, - (const char *) str3, - NULL, int2, 0, msg, str1, int2, str3); + xmlDoErrValid(ctxt, node, error, XML_ERR_ERROR, str1, str3, NULL, int2, + msg, str1, int2, str3); }
/** @@ -213,25 +181,8 @@ xmlErrValidWarning(xmlValidCtxtPtr ctxt, const char *msg, const xmlChar * str1, const xmlChar * str2, const xmlChar * str3) { - xmlStructuredErrorFunc schannel = NULL; - xmlGenericErrorFunc channel = NULL; - xmlParserCtxtPtr pctxt = NULL; - void *data = NULL; - - if (ctxt != NULL) { - channel = ctxt->warning; - data = ctxt->userData; - /* Look up flag to detect if it is part of a parsing - context */ - if (ctxt->flags & XML_VCTXT_USE_PCTXT) { - pctxt = ctxt->userData; - } - } - __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error, - XML_ERR_WARNING, NULL, 0, - (const char *) str1, - (const char *) str2, - (const char *) str3, 0, 0, msg, str1, str2, str3); + xmlDoErrValid(ctxt, node, error, XML_ERR_WARNING, str1, str2, str3, 0, + msg, str1, str2, str3); }
@@ -260,7 +211,7 @@ vstateVPush(xmlValidCtxtPtr ctxt, xmlElementPtr elemDecl, xmlNodePtr node) { ctxt->vstateTab = (xmlValidState *) xmlMalloc(ctxt->vstateMax * sizeof(ctxt->vstateTab[0])); if (ctxt->vstateTab == NULL) { - xmlVErrMemory(ctxt, "malloc failed"); + xmlVErrMemory(ctxt); return(-1); } } @@ -271,7 +222,7 @@ vstateVPush(xmlValidCtxtPtr ctxt, xmlElementPtr elemDecl, xmlNodePtr node) { tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab, 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0])); if (tmp == NULL) { - xmlVErrMemory(ctxt, "realloc failed"); + xmlVErrMemory(ctxt); return(-1); } ctxt->vstateMax *= 2; @@ -286,6 +237,10 @@ vstateVPush(xmlValidCtxtPtr ctxt, xmlElementPtr elemDecl, xmlNodePtr node) { if (elemDecl->contModel != NULL) { ctxt->vstateTab[ctxt->vstateNr].exec = xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL); + if (ctxt->vstateTab[ctxt->vstateNr].exec == NULL) { + xmlVErrMemory(ctxt); + return(-1); + } } else { ctxt->vstateTab[ctxt->vstateNr].exec = NULL; xmlErrValidNode(ctxt, (xmlNodePtr) elemDecl, @@ -367,7 +322,7 @@ vstateVPush(xmlValidCtxtPtr ctxt, xmlElementContentPtr cont, ctxt->vstateTab = (xmlValidState *) xmlMalloc( ctxt->vstateMax * sizeof(ctxt->vstateTab[0])); if (ctxt->vstateTab == NULL) { - xmlVErrMemory(ctxt, "malloc failed"); + xmlVErrMemory(ctxt); return(-1); } } @@ -377,7 +332,7 @@ vstateVPush(xmlValidCtxtPtr ctxt, xmlElementContentPtr cont, tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab, 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0])); if (tmp == NULL) { - xmlVErrMemory(ctxt, "malloc failed"); + xmlVErrMemory(ctxt); return(-1); } ctxt->vstateMax *= 2; @@ -425,7 +380,7 @@ nodeVPush(xmlValidCtxtPtr ctxt, xmlNodePtr value) (xmlNodePtr *) xmlMalloc(ctxt->nodeMax * sizeof(ctxt->nodeTab[0])); if (ctxt->nodeTab == NULL) { - xmlVErrMemory(ctxt, "malloc failed"); + xmlVErrMemory(ctxt); ctxt->nodeMax = 0; return (0); } @@ -435,7 +390,7 @@ nodeVPush(xmlValidCtxtPtr ctxt, xmlNodePtr value) tmp = (xmlNodePtr *) xmlRealloc(ctxt->nodeTab, ctxt->nodeMax * 2 * sizeof(ctxt->nodeTab[0])); if (tmp == NULL) { - xmlVErrMemory(ctxt, "realloc failed"); + xmlVErrMemory(ctxt); return (0); } ctxt->nodeMax *= 2; @@ -512,7 +467,7 @@ xmlValidBuildAContentModel(xmlElementContentPtr content,
fullname = xmlBuildQName(content->name, content->prefix, fn, 50); if (fullname == NULL) { - xmlVErrMemory(ctxt, "Building content model"); + xmlVErrMemory(ctxt); return(0); }
@@ -557,11 +512,13 @@ xmlValidBuildAContentModel(xmlElementContentPtr content, oldstate = ctxt->state; } do { - xmlValidBuildAContentModel(content->c1, ctxt, name); + if (xmlValidBuildAContentModel(content->c1, ctxt, name) == 0) + return(0); content = content->c2; } while ((content->type == XML_ELEMENT_CONTENT_SEQ) && (content->ocur == XML_ELEMENT_CONTENT_ONCE)); - xmlValidBuildAContentModel(content, ctxt, name); + if (xmlValidBuildAContentModel(content, ctxt, name) == 0) + return(0); oldend = ctxt->state; ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL); switch (ocur) { @@ -599,13 +556,15 @@ xmlValidBuildAContentModel(xmlElementContentPtr content, */ do { ctxt->state = oldstate; - xmlValidBuildAContentModel(content->c1, ctxt, name); + if (xmlValidBuildAContentModel(content->c1, ctxt, name) == 0) + return(0); xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend); content = content->c2; } while ((content->type == XML_ELEMENT_CONTENT_OR) && (content->ocur == XML_ELEMENT_CONTENT_ONCE)); ctxt->state = oldstate; - xmlValidBuildAContentModel(content, ctxt, name); + if (xmlValidBuildAContentModel(content, ctxt, name) == 0) + return(0); xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend); ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL); switch (ocur) { @@ -637,6 +596,8 @@ xmlValidBuildAContentModel(xmlElementContentPtr content, * @ctxt: a validation context * @elem: an element declaration node * + * DEPRECATED: Internal function, don't use. + * * (Re)Build the automata associated to the content model of this * element * @@ -644,6 +605,7 @@ xmlValidBuildAContentModel(xmlElementContentPtr content, */ int xmlValidBuildContentModel(xmlValidCtxtPtr ctxt, xmlElementPtr elem) { + int ret = 0;
if ((ctxt == NULL) || (elem == NULL)) return(0); @@ -662,16 +624,18 @@ xmlValidBuildContentModel(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
ctxt->am = xmlNewAutomata(); if (ctxt->am == NULL) { - xmlErrValidNode(ctxt, (xmlNodePtr) elem, - XML_ERR_INTERNAL_ERROR, - "Cannot create automata for element %s\n", - elem->name, NULL, NULL); + xmlVErrMemory(ctxt); return(0); } ctxt->state = xmlAutomataGetInitState(ctxt->am); - xmlValidBuildAContentModel(elem->content, ctxt, elem->name); + if (xmlValidBuildAContentModel(elem->content, ctxt, elem->name) == 0) + goto done; xmlAutomataSetFinalState(ctxt->am, ctxt->state); elem->contModel = xmlAutomataCompile(ctxt->am); + if (elem->contModel == NULL) { + xmlVErrMemory(ctxt); + goto done; + } if (xmlRegexpIsDeterminist(elem->contModel) != 1) { char expr[5000]; expr[0] = 0; @@ -681,15 +645,16 @@ xmlValidBuildContentModel(xmlValidCtxtPtr ctxt, xmlElementPtr elem) { "Content model of %s is not deterministic: %s\n", elem->name, BAD_CAST expr, NULL); ctxt->valid = 0; - ctxt->state = NULL; - xmlFreeAutomata(ctxt->am); - ctxt->am = NULL; - return(0); + goto done; } + + ret = 1; + +done: ctxt->state = NULL; xmlFreeAutomata(ctxt->am); ctxt->am = NULL; - return(1); + return(ret); }
#endif /* LIBXML_REGEXP_ENABLED */ @@ -710,10 +675,8 @@ xmlValidBuildContentModel(xmlValidCtxtPtr ctxt, xmlElementPtr elem) { xmlValidCtxtPtr xmlNewValidCtxt(void) { xmlValidCtxtPtr ret;
- if ((ret = xmlMalloc(sizeof (xmlValidCtxt))) == NULL) { - xmlVErrMemory(NULL, "malloc failed"); + if ((ret = xmlMalloc(sizeof (xmlValidCtxt))) == NULL) return (NULL); - }
(void) memset(ret, 0, sizeof (xmlValidCtxt));
@@ -782,10 +745,8 @@ xmlNewDocElementContent(xmlDocPtr doc, const xmlChar *name, return(NULL); } ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent)); - if (ret == NULL) { - xmlVErrMemory(NULL, "malloc failed"); + if (ret == NULL) return(NULL); - } memset(ret, 0, sizeof(xmlElementContent)); ret->type = type; ret->ocur = XML_ELEMENT_CONTENT_ONCE; @@ -807,9 +768,17 @@ xmlNewDocElementContent(xmlDocPtr doc, const xmlChar *name, ret->prefix = xmlDictLookup(dict, name, l); ret->name = xmlDictLookup(dict, tmp, -1); } + if (ret->prefix == NULL) + goto error; } + if (ret->name == NULL) + goto error; } return(ret); + +error: + xmlFreeDocElementContent(doc, ret); + return(NULL); }
/** @@ -847,10 +816,8 @@ xmlCopyDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) { dict = doc->dict;
ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent)); - if (ret == NULL) { - xmlVErrMemory(NULL, "malloc failed"); + if (ret == NULL) return(NULL); - } memset(ret, 0, sizeof(xmlElementContent)); ret->type = cur->type; ret->ocur = cur->ocur; @@ -859,6 +826,8 @@ xmlCopyDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) { ret->name = xmlDictLookup(dict, cur->name, -1); else ret->name = xmlStrdup(cur->name); + if (ret->name == NULL) + goto error; }
if (cur->prefix != NULL) { @@ -866,20 +835,22 @@ xmlCopyDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) { ret->prefix = xmlDictLookup(dict, cur->prefix, -1); else ret->prefix = xmlStrdup(cur->prefix); + if (ret->prefix == NULL) + goto error; } - if (cur->c1 != NULL) + if (cur->c1 != NULL) { ret->c1 = xmlCopyDocElementContent(doc, cur->c1); - if (ret->c1 != NULL) + if (ret->c1 == NULL) + goto error; ret->c1->parent = ret; + } if (cur->c2 != NULL) { prev = ret; cur = cur->c2; while (cur != NULL) { tmp = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent)); - if (tmp == NULL) { - xmlVErrMemory(NULL, "malloc failed"); - return(ret); - } + if (tmp == NULL) + goto error; memset(tmp, 0, sizeof(xmlElementContent)); tmp->type = cur->type; tmp->ocur = cur->ocur; @@ -890,6 +861,8 @@ xmlCopyDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) { tmp->name = xmlDictLookup(dict, cur->name, -1); else tmp->name = xmlStrdup(cur->name); + if (tmp->name == NULL) + goto error; }
if (cur->prefix != NULL) { @@ -897,16 +870,24 @@ xmlCopyDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) { tmp->prefix = xmlDictLookup(dict, cur->prefix, -1); else tmp->prefix = xmlStrdup(cur->prefix); + if (tmp->prefix == NULL) + goto error; } - if (cur->c1 != NULL) + if (cur->c1 != NULL) { tmp->c1 = xmlCopyDocElementContent(doc,cur->c1); - if (tmp->c1 != NULL) + if (tmp->c1 == NULL) + goto error; tmp->c1->parent = tmp; + } prev = tmp; cur = cur->c2; } } return(ret); + +error: + xmlFreeElementContent(ret); + return(NULL); }
/** @@ -1002,105 +983,6 @@ xmlFreeElementContent(xmlElementContentPtr cur) { }
#ifdef LIBXML_OUTPUT_ENABLED -/** - * xmlDumpElementOccur: - * @buf: An XML buffer - * @cur: An element table - * - * Dump the occurrence operator of an element. - */ -static void -xmlDumpElementOccur(xmlBufferPtr buf, xmlElementContentPtr cur) { - switch (cur->ocur) { - case XML_ELEMENT_CONTENT_ONCE: - break; - case XML_ELEMENT_CONTENT_OPT: - xmlBufferWriteChar(buf, "?"); - break; - case XML_ELEMENT_CONTENT_MULT: - xmlBufferWriteChar(buf, "*"); - break; - case XML_ELEMENT_CONTENT_PLUS: - xmlBufferWriteChar(buf, "+"); - break; - } -} - -/** - * xmlDumpElementContent: - * @buf: An XML buffer - * @content: An element table - * - * This will dump the content of the element table as an XML DTD definition - */ -static void -xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content) { - xmlElementContentPtr cur; - - if (content == NULL) return; - - xmlBufferWriteChar(buf, "("); - cur = content; - - do { - if (cur == NULL) return; - - switch (cur->type) { - case XML_ELEMENT_CONTENT_PCDATA: - xmlBufferWriteChar(buf, "#PCDATA"); - break; - case XML_ELEMENT_CONTENT_ELEMENT: - if (cur->prefix != NULL) { - xmlBufferWriteCHAR(buf, cur->prefix); - xmlBufferWriteChar(buf, ":"); - } - xmlBufferWriteCHAR(buf, cur->name); - break; - case XML_ELEMENT_CONTENT_SEQ: - case XML_ELEMENT_CONTENT_OR: - if ((cur != content) && - (cur->parent != NULL) && - ((cur->type != cur->parent->type) || - (cur->ocur != XML_ELEMENT_CONTENT_ONCE))) - xmlBufferWriteChar(buf, "("); - cur = cur->c1; - continue; - default: - xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, - "Internal: ELEMENT cur corrupted invalid type\n", - NULL); - } - - while (cur != content) { - xmlElementContentPtr parent = cur->parent; - - if (parent == NULL) return; - - if (((cur->type == XML_ELEMENT_CONTENT_OR) || - (cur->type == XML_ELEMENT_CONTENT_SEQ)) && - ((cur->type != parent->type) || - (cur->ocur != XML_ELEMENT_CONTENT_ONCE))) - xmlBufferWriteChar(buf, ")"); - xmlDumpElementOccur(buf, cur); - - if (cur == parent->c1) { - if (parent->type == XML_ELEMENT_CONTENT_SEQ) - xmlBufferWriteChar(buf, " , "); - else if (parent->type == XML_ELEMENT_CONTENT_OR) - xmlBufferWriteChar(buf, " | "); - - cur = parent->c2; - break; - } - - cur = parent; - } - } while (cur != content); - - xmlBufferWriteChar(buf, ")"); - xmlDumpElementOccur(buf, content); -} - /** * xmlSprintfElementContent: * @buf: an output buffer @@ -1267,7 +1149,8 @@ xmlAddElementDecl(xmlValidCtxtPtr ctxt, xmlElementPtr ret; xmlElementTablePtr table; xmlAttributePtr oldAttributes = NULL; - xmlChar *ns, *uqname; + const xmlChar *localName; + xmlChar *prefix = NULL;
if (dtd == NULL) { return(NULL); @@ -1279,7 +1162,7 @@ xmlAddElementDecl(xmlValidCtxtPtr ctxt, switch (type) { case XML_ELEMENT_TYPE_EMPTY: if (content != NULL) { - xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, + xmlErrValid(ctxt, XML_DTD_CONTENT_ERROR, "xmlAddElementDecl: content != NULL for EMPTY\n", NULL); return(NULL); @@ -1287,7 +1170,7 @@ xmlAddElementDecl(xmlValidCtxtPtr ctxt, break; case XML_ELEMENT_TYPE_ANY: if (content != NULL) { - xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, + xmlErrValid(ctxt, XML_DTD_CONTENT_ERROR, "xmlAddElementDecl: content != NULL for ANY\n", NULL); return(NULL); @@ -1295,7 +1178,7 @@ xmlAddElementDecl(xmlValidCtxtPtr ctxt, break; case XML_ELEMENT_TYPE_MIXED: if (content == NULL) { - xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, + xmlErrValid(ctxt, XML_DTD_CONTENT_ERROR, "xmlAddElementDecl: content == NULL for MIXED\n", NULL); return(NULL); @@ -1303,25 +1186,24 @@ xmlAddElementDecl(xmlValidCtxtPtr ctxt, break; case XML_ELEMENT_TYPE_ELEMENT: if (content == NULL) { - xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, + xmlErrValid(ctxt, XML_DTD_CONTENT_ERROR, "xmlAddElementDecl: content == NULL for ELEMENT\n", NULL); return(NULL); } break; default: - xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, - "Internal: ELEMENT decl corrupted invalid type\n", - NULL); + xmlErrValid(ctxt, XML_ERR_ARGUMENT, + "xmlAddElementDecl: invalid type\n", NULL); return(NULL); }
/* * check if name is a QName */ - uqname = xmlSplitQName2(name, &ns); - if (uqname != NULL) - name = uqname; + localName = xmlSplitQName4(name, &prefix); + if (localName == NULL) + goto mem_error;
/* * Create the Element table if needed. @@ -1333,28 +1215,22 @@ xmlAddElementDecl(xmlValidCtxtPtr ctxt, if (dtd->doc != NULL) dict = dtd->doc->dict; table = xmlHashCreateDict(0, dict); + if (table == NULL) + goto mem_error; dtd->elements = (void *) table; } - if (table == NULL) { - xmlVErrMemory(ctxt, - "xmlAddElementDecl: Table creation failed!\n"); - if (uqname != NULL) - xmlFree(uqname); - if (ns != NULL) - xmlFree(ns); - return(NULL); - }
/* * lookup old attributes inserted on an undefined element in the * internal subset. */ if ((dtd->doc != NULL) && (dtd->doc->intSubset != NULL)) { - ret = xmlHashLookup2(dtd->doc->intSubset->elements, name, ns); + ret = xmlHashLookup2(dtd->doc->intSubset->elements, localName, prefix); if ((ret != NULL) && (ret->etype == XML_ELEMENT_TYPE_UNDEFINED)) { oldAttributes = ret->attributes; ret->attributes = NULL; - xmlHashRemoveEntry2(dtd->doc->intSubset->elements, name, ns, NULL); + xmlHashRemoveEntry2(dtd->doc->intSubset->elements, localName, prefix, + NULL); xmlFreeElement(ret); } } @@ -1363,7 +1239,7 @@ xmlAddElementDecl(xmlValidCtxtPtr ctxt, * The element may already be present if one of its attribute * was registered first */ - ret = xmlHashLookup2(table, name, ns); + ret = xmlHashLookup2(table, localName, prefix); if (ret != NULL) { if (ret->etype != XML_ELEMENT_TYPE_UNDEFINED) { #ifdef LIBXML_VALID_ENABLED @@ -1374,61 +1250,42 @@ xmlAddElementDecl(xmlValidCtxtPtr ctxt, "Redefinition of element %s\n", name, NULL, NULL); #endif /* LIBXML_VALID_ENABLED */ - if (uqname != NULL) - xmlFree(uqname); - if (ns != NULL) - xmlFree(ns); + if (prefix != NULL) + xmlFree(prefix); return(NULL); } - if (ns != NULL) { - xmlFree(ns); - ns = NULL; + if (prefix != NULL) { + xmlFree(prefix); + prefix = NULL; } } else { + int res; + ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement)); - if (ret == NULL) { - xmlVErrMemory(ctxt, "malloc failed"); - if (uqname != NULL) - xmlFree(uqname); - if (ns != NULL) - xmlFree(ns); - return(NULL); - } + if (ret == NULL) + goto mem_error; memset(ret, 0, sizeof(xmlElement)); ret->type = XML_ELEMENT_DECL;
/* * fill the structure. */ - ret->name = xmlStrdup(name); + ret->name = xmlStrdup(localName); if (ret->name == NULL) { - xmlVErrMemory(ctxt, "malloc failed"); - if (uqname != NULL) - xmlFree(uqname); - if (ns != NULL) - xmlFree(ns); xmlFree(ret); - return(NULL); + goto mem_error; } - ret->prefix = ns; + ret->prefix = prefix; + prefix = NULL;
/* * Validity Check: * Insertion must not fail */ - if (xmlHashAddEntry2(table, name, ns, ret)) { -#ifdef LIBXML_VALID_ENABLED - /* - * The element is already defined in this DTD. - */ - xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED, - "Redefinition of element %s\n", - name, NULL, NULL); -#endif /* LIBXML_VALID_ENABLED */ + res = xmlHashAdd2(table, localName, ret->prefix, ret); + if (res <= 0) { xmlFreeElement(ret); - if (uqname != NULL) - xmlFree(uqname); - return(NULL); + goto mem_error; } /* * For new element, may have attributes from earlier @@ -1446,12 +1303,15 @@ xmlAddElementDecl(xmlValidCtxtPtr ctxt, * and flag it by setting a special parent value * so the parser doesn't unallocate it. */ - if ((ctxt != NULL) && (ctxt->flags & XML_VCTXT_USE_PCTXT)) { - ret->content = content; - if (content != NULL) - content->parent = (xmlElementContentPtr) 1; - } else { - ret->content = xmlCopyDocElementContent(dtd->doc, content); + if (content != NULL) { + if ((ctxt != NULL) && (ctxt->flags & XML_VCTXT_USE_PCTXT)) { + ret->content = content; + content->parent = (xmlElementContentPtr) 1; + } else if (content != NULL){ + ret->content = xmlCopyDocElementContent(dtd->doc, content); + if (ret->content == NULL) + goto mem_error; + } }
/* @@ -1466,9 +1326,15 @@ xmlAddElementDecl(xmlValidCtxtPtr ctxt, ret->prev = dtd->last; dtd->last = (xmlNodePtr) ret; } - if (uqname != NULL) - xmlFree(uqname); + if (prefix != NULL) + xmlFree(prefix); return(ret); + +mem_error: + xmlVErrMemory(ctxt); + if (prefix != NULL) + xmlFree(prefix); + return(NULL); }
static void @@ -1502,25 +1368,33 @@ xmlCopyElement(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) { xmlElementPtr cur;
cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement)); - if (cur == NULL) { - xmlVErrMemory(NULL, "malloc failed"); + if (cur == NULL) return(NULL); - } memset(cur, 0, sizeof(xmlElement)); cur->type = XML_ELEMENT_DECL; cur->etype = elem->etype; - if (elem->name != NULL) + if (elem->name != NULL) { cur->name = xmlStrdup(elem->name); - else - cur->name = NULL; - if (elem->prefix != NULL) + if (cur->name == NULL) + goto error; + } + if (elem->prefix != NULL) { cur->prefix = xmlStrdup(elem->prefix); - else - cur->prefix = NULL; - cur->content = xmlCopyElementContent(elem->content); + if (cur->prefix == NULL) + goto error; + } + if (elem->content != NULL) { + cur->content = xmlCopyElementContent(elem->content); + if (cur->content == NULL) + goto error; + } /* TODO : rebuild the attribute list on the copy */ cur->attributes = NULL; return(cur); + +error: + xmlFreeElement(cur); + return(NULL); }
/** @@ -1533,7 +1407,7 @@ xmlCopyElement(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) { */ xmlElementTablePtr xmlCopyElementTable(xmlElementTablePtr table) { - return((xmlElementTablePtr) xmlHashCopy(table, xmlCopyElement)); + return(xmlHashCopySafe(table, xmlCopyElement, xmlFreeElementTableEntry)); } #endif /* LIBXML_TREE_ENABLED */
@@ -1543,59 +1417,22 @@ xmlCopyElementTable(xmlElementTablePtr table) { * @buf: the XML buffer output * @elem: An element table * + * DEPRECATED: Use xmlSaveTree. + * * This will dump the content of the element declaration as an XML * DTD definition */ void xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) { + xmlSaveCtxtPtr save; + if ((buf == NULL) || (elem == NULL)) return; - switch (elem->etype) { - case XML_ELEMENT_TYPE_EMPTY: - xmlBufferWriteChar(buf, "<!ELEMENT "); - if (elem->prefix != NULL) { - xmlBufferWriteCHAR(buf, elem->prefix); - xmlBufferWriteChar(buf, ":"); - } - xmlBufferWriteCHAR(buf, elem->name); - xmlBufferWriteChar(buf, " EMPTY>\n"); - break; - case XML_ELEMENT_TYPE_ANY: - xmlBufferWriteChar(buf, "<!ELEMENT "); - if (elem->prefix != NULL) { - xmlBufferWriteCHAR(buf, elem->prefix); - xmlBufferWriteChar(buf, ":"); - } - xmlBufferWriteCHAR(buf, elem->name); - xmlBufferWriteChar(buf, " ANY>\n"); - break; - case XML_ELEMENT_TYPE_MIXED: - xmlBufferWriteChar(buf, "<!ELEMENT "); - if (elem->prefix != NULL) { - xmlBufferWriteCHAR(buf, elem->prefix); - xmlBufferWriteChar(buf, ":"); - } - xmlBufferWriteCHAR(buf, elem->name); - xmlBufferWriteChar(buf, " "); - xmlDumpElementContent(buf, elem->content); - xmlBufferWriteChar(buf, ">\n"); - break; - case XML_ELEMENT_TYPE_ELEMENT: - xmlBufferWriteChar(buf, "<!ELEMENT "); - if (elem->prefix != NULL) { - xmlBufferWriteCHAR(buf, elem->prefix); - xmlBufferWriteChar(buf, ":"); - } - xmlBufferWriteCHAR(buf, elem->name); - xmlBufferWriteChar(buf, " "); - xmlDumpElementContent(buf, elem->content); - xmlBufferWriteChar(buf, ">\n"); - break; - default: - xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, - "Internal: ELEMENT struct corrupted invalid type\n", - NULL); - } + + save = xmlSaveToBuffer(buf, NULL, 0); + xmlSaveTree(save, (xmlNodePtr) elem); + if (xmlSaveFinish(save) != XML_ERR_OK) + xmlFree(xmlBufferDetach(buf)); }
/** @@ -1607,9 +1444,9 @@ xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) { * the arguments. */ static void -xmlDumpElementDeclScan(void *elem, void *buf, +xmlDumpElementDeclScan(void *elem, void *save, const xmlChar *name ATTRIBUTE_UNUSED) { - xmlDumpElementDecl((xmlBufferPtr) buf, (xmlElementPtr) elem); + xmlSaveTree(save, elem); }
/** @@ -1617,13 +1454,21 @@ xmlDumpElementDeclScan(void *elem, void *buf, * @buf: the XML buffer output * @table: An element table * + * DEPRECATED: Don't use. + * * This will dump the content of the element table as an XML DTD definition */ void xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) { + xmlSaveCtxtPtr save; + if ((buf == NULL) || (table == NULL)) return; - xmlHashScan(table, xmlDumpElementDeclScan, buf); + + save = xmlSaveToBuffer(buf, NULL, 0); + xmlHashScan(table, xmlDumpElementDeclScan, save); + if (xmlSaveFinish(save) != XML_ERR_OK) + xmlFree(xmlBufferDetach(buf)); } #endif /* LIBXML_OUTPUT_ENABLED */
@@ -1641,14 +1486,18 @@ xmlCreateEnumeration(const xmlChar *name) { xmlEnumerationPtr ret;
ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration)); - if (ret == NULL) { - xmlVErrMemory(NULL, "malloc failed"); + if (ret == NULL) return(NULL); - } memset(ret, 0, sizeof(xmlEnumeration));
- if (name != NULL) + if (name != NULL) { ret->name = xmlStrdup(name); + if (ret->name == NULL) { + xmlFree(ret); + return(NULL); + } + } + return(ret); }
@@ -1660,12 +1509,14 @@ xmlCreateEnumeration(const xmlChar *name) { */ void xmlFreeEnumeration(xmlEnumerationPtr cur) { - if (cur == NULL) return; + while (cur != NULL) { + xmlEnumerationPtr next = cur->next;
- if (cur->next != NULL) xmlFreeEnumeration(cur->next); + xmlFree((xmlChar *) cur->name); + xmlFree(cur);
- if (cur->name != NULL) xmlFree((xmlChar *) cur->name); - xmlFree(cur); + cur = next; + } }
#ifdef LIBXML_TREE_ENABLED @@ -1680,41 +1531,30 @@ xmlFreeEnumeration(xmlEnumerationPtr cur) { */ xmlEnumerationPtr xmlCopyEnumeration(xmlEnumerationPtr cur) { - xmlEnumerationPtr ret; + xmlEnumerationPtr ret = NULL; + xmlEnumerationPtr last = NULL;
- if (cur == NULL) return(NULL); - ret = xmlCreateEnumeration((xmlChar *) cur->name); - if (ret == NULL) return(NULL); - - if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next); - else ret->next = NULL; + while (cur != NULL) { + xmlEnumerationPtr copy = xmlCreateEnumeration(cur->name);
- return(ret); -} -#endif /* LIBXML_TREE_ENABLED */ + if (copy == NULL) { + xmlFreeEnumeration(ret); + return(NULL); + }
-#ifdef LIBXML_OUTPUT_ENABLED -/** - * xmlDumpEnumeration: - * @buf: the XML buffer output - * @enum: An enumeration - * - * This will dump the content of the enumeration - */ -static void -xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) { - if ((buf == NULL) || (cur == NULL)) - return; + if (ret == NULL) { + ret = last = copy; + } else { + last->next = copy; + last = copy; + }
- xmlBufferWriteCHAR(buf, cur->name); - if (cur->next == NULL) - xmlBufferWriteChar(buf, ")"); - else { - xmlBufferWriteChar(buf, " | "); - xmlDumpEnumeration(buf, cur->next); + cur = cur->next; } + + return(ret); } -#endif /* LIBXML_OUTPUT_ENABLED */ +#endif /* LIBXML_TREE_ENABLED */
#ifdef LIBXML_VALID_ENABLED /** @@ -1814,10 +1654,11 @@ xmlAddAttributeDecl(xmlValidCtxtPtr ctxt, const xmlChar *name, const xmlChar *ns, xmlAttributeType type, xmlAttributeDefault def, const xmlChar *defaultValue, xmlEnumerationPtr tree) { - xmlAttributePtr ret; + xmlAttributePtr ret = NULL; xmlAttributeTablePtr table; xmlElementPtr elemDef; xmlDictPtr dict = NULL; + int res;
if (dtd == NULL) { xmlFreeEnumeration(tree); @@ -1860,9 +1701,8 @@ xmlAddAttributeDecl(xmlValidCtxtPtr ctxt, case XML_ATTRIBUTE_NOTATION: break; default: - xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, - "Internal: ATTRIBUTE struct corrupted invalid type\n", - NULL); + xmlErrValid(ctxt, XML_ERR_ARGUMENT, + "xmlAddAttributeDecl: invalid type\n", NULL); xmlFreeEnumeration(tree); return(NULL); } @@ -1899,20 +1739,12 @@ xmlAddAttributeDecl(xmlValidCtxtPtr ctxt, table = xmlHashCreateDict(0, dict); dtd->attributes = (void *) table; } - if (table == NULL) { - xmlVErrMemory(ctxt, - "xmlAddAttributeDecl: Table creation failed!\n"); - xmlFreeEnumeration(tree); - return(NULL); - } - + if (table == NULL) + goto mem_error;
ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute)); - if (ret == NULL) { - xmlVErrMemory(ctxt, "malloc failed"); - xmlFreeEnumeration(tree); - return(NULL); - } + if (ret == NULL) + goto mem_error; memset(ret, 0, sizeof(xmlAttribute)); ret->type = XML_ATTRIBUTE_DECL;
@@ -1928,34 +1760,53 @@ xmlAddAttributeDecl(xmlValidCtxtPtr ctxt, ret->doc = dtd->doc; if (dict) { ret->name = xmlDictLookup(dict, name, -1); - ret->prefix = xmlDictLookup(dict, ns, -1); ret->elem = xmlDictLookup(dict, elem, -1); } else { ret->name = xmlStrdup(name); - ret->prefix = xmlStrdup(ns); ret->elem = xmlStrdup(elem); } + if ((ret->name == NULL) || (ret->elem == NULL)) + goto mem_error; + if (ns != NULL) { + if (dict) + ret->prefix = xmlDictLookup(dict, ns, -1); + else + ret->prefix = xmlStrdup(ns); + if (ret->prefix == NULL) + goto mem_error; + } ret->def = def; ret->tree = tree; + tree = NULL; if (defaultValue != NULL) { if (dict) ret->defaultValue = xmlDictLookup(dict, defaultValue, -1); else ret->defaultValue = xmlStrdup(defaultValue); + if (ret->defaultValue == NULL) + goto mem_error; }
+ elemDef = xmlGetDtdElementDesc2(ctxt, dtd, elem); + if (elemDef == NULL) + goto mem_error; + /* * Validity Check: * Search the DTD for previous declarations of the ATTLIST */ - if (xmlHashAddEntry3(table, ret->name, ret->prefix, ret->elem, ret) < 0) { + res = xmlHashAdd3(table, ret->name, ret->prefix, ret->elem, ret); + if (res <= 0) { + if (res < 0) + goto mem_error; #ifdef LIBXML_VALID_ENABLED - /* - * The attribute is already defined in this DTD. - */ - xmlErrValidWarning(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_REDEFINED, - "Attribute %s of element %s: already defined\n", - name, elem, NULL); + /* + * The attribute is already defined in this DTD. + */ + xmlErrValidWarning(ctxt, (xmlNodePtr) dtd, + XML_DTD_ATTRIBUTE_REDEFINED, + "Attribute %s of element %s: already defined\n", + name, elem, NULL); #endif /* LIBXML_VALID_ENABLED */ xmlFreeAttribute(ret); return(NULL); @@ -1965,48 +1816,44 @@ xmlAddAttributeDecl(xmlValidCtxtPtr ctxt, * Validity Check: * Multiple ID per element */ - elemDef = xmlGetDtdElementDesc2(ctxt, dtd, elem, 1); - if (elemDef != NULL) { - #ifdef LIBXML_VALID_ENABLED - if ((type == XML_ATTRIBUTE_ID) && - (xmlScanIDAttributeDecl(NULL, elemDef, 1) != 0)) { - xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_MULTIPLE_ID, - "Element %s has too may ID attributes defined : %s\n", - elem, name, NULL); - if (ctxt != NULL) - ctxt->valid = 0; - } + if ((type == XML_ATTRIBUTE_ID) && + (xmlScanIDAttributeDecl(ctxt, elemDef, 1) != 0)) { + xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_MULTIPLE_ID, + "Element %s has too may ID attributes defined : %s\n", + elem, name, NULL); + if (ctxt != NULL) + ctxt->valid = 0; + } #endif /* LIBXML_VALID_ENABLED */
- /* - * Insert namespace default def first they need to be - * processed first. - */ - if ((xmlStrEqual(ret->name, BAD_CAST "xmlns")) || - ((ret->prefix != NULL && - (xmlStrEqual(ret->prefix, BAD_CAST "xmlns"))))) { - ret->nexth = elemDef->attributes; - elemDef->attributes = ret; - } else { - xmlAttributePtr tmp = elemDef->attributes; + /* + * Insert namespace default def first they need to be + * processed first. + */ + if ((xmlStrEqual(ret->name, BAD_CAST "xmlns")) || + ((ret->prefix != NULL && + (xmlStrEqual(ret->prefix, BAD_CAST "xmlns"))))) { + ret->nexth = elemDef->attributes; + elemDef->attributes = ret; + } else { + xmlAttributePtr tmp = elemDef->attributes;
- while ((tmp != NULL) && - ((xmlStrEqual(tmp->name, BAD_CAST "xmlns")) || - ((ret->prefix != NULL && - (xmlStrEqual(ret->prefix, BAD_CAST "xmlns")))))) { - if (tmp->nexth == NULL) - break; - tmp = tmp->nexth; - } - if (tmp != NULL) { - ret->nexth = tmp->nexth; - tmp->nexth = ret; - } else { - ret->nexth = elemDef->attributes; - elemDef->attributes = ret; - } - } + while ((tmp != NULL) && + ((xmlStrEqual(tmp->name, BAD_CAST "xmlns")) || + ((ret->prefix != NULL && + (xmlStrEqual(ret->prefix, BAD_CAST "xmlns")))))) { + if (tmp->nexth == NULL) + break; + tmp = tmp->nexth; + } + if (tmp != NULL) { + ret->nexth = tmp->nexth; + tmp->nexth = ret; + } else { + ret->nexth = elemDef->attributes; + elemDef->attributes = ret; + } }
/* @@ -2021,6 +1868,12 @@ xmlAddAttributeDecl(xmlValidCtxtPtr ctxt, dtd->last = (xmlNodePtr) ret; } return(ret); + +mem_error: + xmlVErrMemory(ctxt); + xmlFreeEnumeration(tree); + xmlFreeAttribute(ret); + return(NULL); }
static void @@ -2054,24 +1907,42 @@ xmlCopyAttribute(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) { xmlAttributePtr cur;
cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute)); - if (cur == NULL) { - xmlVErrMemory(NULL, "malloc failed"); + if (cur == NULL) return(NULL); - } memset(cur, 0, sizeof(xmlAttribute)); cur->type = XML_ATTRIBUTE_DECL; cur->atype = attr->atype; cur->def = attr->def; - cur->tree = xmlCopyEnumeration(attr->tree); - if (attr->elem != NULL) + if (attr->tree != NULL) { + cur->tree = xmlCopyEnumeration(attr->tree); + if (cur->tree == NULL) + goto error; + } + if (attr->elem != NULL) { cur->elem = xmlStrdup(attr->elem); - if (attr->name != NULL) + if (cur->elem == NULL) + goto error; + } + if (attr->name != NULL) { cur->name = xmlStrdup(attr->name); - if (attr->prefix != NULL) + if (cur->name == NULL) + goto error; + } + if (attr->prefix != NULL) { cur->prefix = xmlStrdup(attr->prefix); - if (attr->defaultValue != NULL) + if (cur->prefix == NULL) + goto error; + } + if (attr->defaultValue != NULL) { cur->defaultValue = xmlStrdup(attr->defaultValue); + if (cur->defaultValue == NULL) + goto error; + } return(cur); + +error: + xmlFreeAttribute(cur); + return(NULL); }
/** @@ -2084,7 +1955,8 @@ xmlCopyAttribute(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) { */ xmlAttributeTablePtr xmlCopyAttributeTable(xmlAttributeTablePtr table) { - return((xmlAttributeTablePtr) xmlHashCopy(table, xmlCopyAttribute)); + return(xmlHashCopySafe(table, xmlCopyAttribute, + xmlFreeAttributeTableEntry)); } #endif /* LIBXML_TREE_ENABLED */
@@ -2094,81 +1966,22 @@ xmlCopyAttributeTable(xmlAttributeTablePtr table) { * @buf: the XML buffer output * @attr: An attribute declaration * + * DEPRECATED: Use xmlSaveTree. + * * This will dump the content of the attribute declaration as an XML * DTD definition */ void xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) { + xmlSaveCtxtPtr save; + if ((buf == NULL) || (attr == NULL)) return; - xmlBufferWriteChar(buf, "<!ATTLIST "); - xmlBufferWriteCHAR(buf, attr->elem); - xmlBufferWriteChar(buf, " "); - if (attr->prefix != NULL) { - xmlBufferWriteCHAR(buf, attr->prefix); - xmlBufferWriteChar(buf, ":"); - } - xmlBufferWriteCHAR(buf, attr->name); - switch (attr->atype) { - case XML_ATTRIBUTE_CDATA: - xmlBufferWriteChar(buf, " CDATA"); - break; - case XML_ATTRIBUTE_ID: - xmlBufferWriteChar(buf, " ID"); - break; - case XML_ATTRIBUTE_IDREF: - xmlBufferWriteChar(buf, " IDREF"); - break; - case XML_ATTRIBUTE_IDREFS: - xmlBufferWriteChar(buf, " IDREFS"); - break; - case XML_ATTRIBUTE_ENTITY: - xmlBufferWriteChar(buf, " ENTITY"); - break; - case XML_ATTRIBUTE_ENTITIES: - xmlBufferWriteChar(buf, " ENTITIES"); - break; - case XML_ATTRIBUTE_NMTOKEN: - xmlBufferWriteChar(buf, " NMTOKEN"); - break; - case XML_ATTRIBUTE_NMTOKENS: - xmlBufferWriteChar(buf, " NMTOKENS"); - break; - case XML_ATTRIBUTE_ENUMERATION: - xmlBufferWriteChar(buf, " ("); - xmlDumpEnumeration(buf, attr->tree); - break; - case XML_ATTRIBUTE_NOTATION: - xmlBufferWriteChar(buf, " NOTATION ("); - xmlDumpEnumeration(buf, attr->tree); - break; - default: - xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, - "Internal: ATTRIBUTE struct corrupted invalid type\n", - NULL); - } - switch (attr->def) { - case XML_ATTRIBUTE_NONE: - break; - case XML_ATTRIBUTE_REQUIRED: - xmlBufferWriteChar(buf, " #REQUIRED"); - break; - case XML_ATTRIBUTE_IMPLIED: - xmlBufferWriteChar(buf, " #IMPLIED"); - break; - case XML_ATTRIBUTE_FIXED: - xmlBufferWriteChar(buf, " #FIXED"); - break; - default: - xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, - "Internal: ATTRIBUTE struct corrupted invalid def\n", - NULL); - } - if (attr->defaultValue != NULL) { - xmlBufferWriteChar(buf, " "); - xmlBufferWriteQuotedString(buf, attr->defaultValue); - } - xmlBufferWriteChar(buf, ">\n"); + + save = xmlSaveToBuffer(buf, NULL, 0); + xmlSaveTree(save, (xmlNodePtr) attr); + if (xmlSaveFinish(save) != XML_ERR_OK) + xmlFree(xmlBufferDetach(buf)); }
/** @@ -2179,9 +1992,9 @@ xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) { * This is used with the hash scan function - just reverses arguments */ static void -xmlDumpAttributeDeclScan(void *attr, void *buf, +xmlDumpAttributeDeclScan(void *attr, void *save, const xmlChar *name ATTRIBUTE_UNUSED) { - xmlDumpAttributeDecl((xmlBufferPtr) buf, (xmlAttributePtr) attr); + xmlSaveTree(save, attr); }
/** @@ -2189,13 +2002,21 @@ xmlDumpAttributeDeclScan(void *attr, void *buf, * @buf: the XML buffer output * @table: An attribute table * + * DEPRECATED: Don't use. + * * This will dump the content of the attribute table as an XML DTD definition */ void xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) { + xmlSaveCtxtPtr save; + if ((buf == NULL) || (table == NULL)) return; - xmlHashScan(table, xmlDumpAttributeDeclScan, buf); + + save = xmlSaveToBuffer(buf, NULL, 0); + xmlHashScan(table, xmlDumpAttributeDeclScan, save); + if (xmlSaveFinish(save) != XML_ERR_OK) + xmlFree(xmlBufferDetach(buf)); } #endif /* LIBXML_OUTPUT_ENABLED */
@@ -2239,8 +2060,9 @@ xmlNotationPtr xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name, const xmlChar *PublicID, const xmlChar *SystemID) { - xmlNotationPtr ret; + xmlNotationPtr ret = NULL; xmlNotationTablePtr table; + int res;
if (dtd == NULL) { return(NULL); @@ -2262,43 +2084,54 @@ xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, dict = dtd->doc->dict;
dtd->notations = table = xmlHashCreateDict(0, dict); - } - if (table == NULL) { - xmlVErrMemory(ctxt, - "xmlAddNotationDecl: Table creation failed!\n"); - return(NULL); + if (table == NULL) + goto mem_error; }
ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation)); - if (ret == NULL) { - xmlVErrMemory(ctxt, "malloc failed"); - return(NULL); - } + if (ret == NULL) + goto mem_error; memset(ret, 0, sizeof(xmlNotation));
/* * fill the structure. */ ret->name = xmlStrdup(name); - if (SystemID != NULL) + if (ret->name == NULL) + goto mem_error; + if (SystemID != NULL) { ret->SystemID = xmlStrdup(SystemID); - if (PublicID != NULL) + if (ret->SystemID == NULL) + goto mem_error; + } + if (PublicID != NULL) { ret->PublicID = xmlStrdup(PublicID); + if (ret->PublicID == NULL) + goto mem_error; + }
/* * Validity Check: * Check the DTD for previous declarations of the ATTLIST */ - if (xmlHashAddEntry(table, name, ret)) { + res = xmlHashAdd(table, name, ret); + if (res <= 0) { + if (res < 0) + goto mem_error; #ifdef LIBXML_VALID_ENABLED - xmlErrValid(NULL, XML_DTD_NOTATION_REDEFINED, - "xmlAddNotationDecl: %s already defined\n", - (const char *) name); + xmlErrValid(ctxt, XML_DTD_NOTATION_REDEFINED, + "xmlAddNotationDecl: %s already defined\n", + (const char *) name); #endif /* LIBXML_VALID_ENABLED */ xmlFreeNotation(ret); return(NULL); } return(ret); + +mem_error: + xmlVErrMemory(ctxt); + xmlFreeNotation(ret); + return(NULL); }
static void @@ -2332,23 +2165,29 @@ xmlCopyNotation(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) { xmlNotationPtr cur;
cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation)); - if (cur == NULL) { - xmlVErrMemory(NULL, "malloc failed"); + if (cur == NULL) return(NULL); - } - if (nota->name != NULL) + memset(cur, 0, sizeof(*cur)); + if (nota->name != NULL) { cur->name = xmlStrdup(nota->name); - else - cur->name = NULL; - if (nota->PublicID != NULL) + if (cur->name == NULL) + goto error; + } + if (nota->PublicID != NULL) { cur->PublicID = xmlStrdup(nota->PublicID); - else - cur->PublicID = NULL; - if (nota->SystemID != NULL) + if (cur->PublicID == NULL) + goto error; + } + if (nota->SystemID != NULL) { cur->SystemID = xmlStrdup(nota->SystemID); - else - cur->SystemID = NULL; + if (cur->SystemID == NULL) + goto error; + } return(cur); + +error: + xmlFreeNotation(cur); + return(NULL); }
/** @@ -2361,7 +2200,7 @@ xmlCopyNotation(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) { */ xmlNotationTablePtr xmlCopyNotationTable(xmlNotationTablePtr table) { - return((xmlNotationTablePtr) xmlHashCopy(table, xmlCopyNotation)); + return(xmlHashCopySafe(table, xmlCopyNotation, xmlFreeNotationTableEntry)); } #endif /* LIBXML_TREE_ENABLED */
@@ -2371,39 +2210,21 @@ xmlCopyNotationTable(xmlNotationTablePtr table) { * @buf: the XML buffer output * @nota: A notation declaration * + * DEPRECATED: Don't use. + * * This will dump the content the notation declaration as an XML DTD definition */ void xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) { + xmlSaveCtxtPtr save; + if ((buf == NULL) || (nota == NULL)) return; - xmlBufferWriteChar(buf, "<!NOTATION "); - xmlBufferWriteCHAR(buf, nota->name); - if (nota->PublicID != NULL) { - xmlBufferWriteChar(buf, " PUBLIC "); - xmlBufferWriteQuotedString(buf, nota->PublicID); - if (nota->SystemID != NULL) { - xmlBufferWriteChar(buf, " "); - xmlBufferWriteQuotedString(buf, nota->SystemID); - } - } else { - xmlBufferWriteChar(buf, " SYSTEM "); - xmlBufferWriteQuotedString(buf, nota->SystemID); - } - xmlBufferWriteChar(buf, " >\n"); -}
-/** - * xmlDumpNotationDeclScan: - * @nota: A notation declaration - * @buf: the XML buffer output - * - * This is called with the hash scan function, and just reverses args - */ -static void -xmlDumpNotationDeclScan(void *nota, void *buf, - const xmlChar *name ATTRIBUTE_UNUSED) { - xmlDumpNotationDecl((xmlBufferPtr) buf, (xmlNotationPtr) nota); + save = xmlSaveToBuffer(buf, NULL, 0); + xmlSaveNotationDecl(save, nota); + if (xmlSaveFinish(save) != XML_ERR_OK) + xmlFree(xmlBufferDetach(buf)); }
/** @@ -2411,13 +2232,21 @@ xmlDumpNotationDeclScan(void *nota, void *buf, * @buf: the XML buffer output * @table: A notation table * + * DEPRECATED: Don't use. + * * This will dump the content of the notation table as an XML DTD definition */ void xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) { + xmlSaveCtxtPtr save; + if ((buf == NULL) || (table == NULL)) return; - xmlHashScan(table, xmlDumpNotationDeclScan, buf); + + save = xmlSaveToBuffer(buf, NULL, 0); + xmlSaveNotationTable(save, table); + if (xmlSaveFinish(save) != XML_ERR_OK) + xmlFree(xmlBufferDetach(buf)); } #endif /* LIBXML_OUTPUT_ENABLED */
@@ -2438,35 +2267,6 @@ xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) { (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \ xmlFree((char *)(str));
-/** - * xmlValidNormalizeString: - * @str: a string - * - * Normalize a string in-place. - */ -static void -xmlValidNormalizeString(xmlChar *str) { - xmlChar *dst; - const xmlChar *src; - - if (str == NULL) - return; - src = str; - dst = str; - - while (*src == 0x20) src++; - while (*src != 0) { - if (*src == 0x20) { - while (*src == 0x20) src++; - if (*src != 0) - *dst++ = 0x20; - } else { - *dst++ = *src++; - } - } - *dst = 0; -} - static int xmlIsStreaming(xmlValidCtxtPtr ctxt) { xmlParserCtxtPtr pctxt; @@ -2498,36 +2298,43 @@ xmlFreeID(xmlIDPtr id) { DICT_FREE(id->value) if (id->name != NULL) DICT_FREE(id->name) + if (id->attr != NULL) { + id->attr->id = NULL; + id->attr->atype = 0; + } + xmlFree(id); }
/** - * xmlAddID: - * @ctxt: the validation context - * @doc: pointer to the document - * @value: the value name + * xmlAddIDInternal: * @attr: the attribute holding the ID + * @value: the attribute (ID) value + * @idPtr: pointer to resulting ID * * Register a new id declaration * - * Returns NULL if not, otherwise the new xmlIDPtr + * Returns 1 on success, 0 if the ID already exists, -1 if a memory + * allocation fails. */ -xmlIDPtr -xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value, - xmlAttrPtr attr) { - xmlIDPtr ret; +static int +xmlAddIDInternal(xmlAttrPtr attr, const xmlChar *value, xmlIDPtr *idPtr) { + xmlDocPtr doc; + xmlIDPtr id; xmlIDTablePtr table; + int ret;
- if (doc == NULL) { - return(NULL); - } - if ((value == NULL) || (value[0] == 0)) { - return(NULL); - } - if (attr == NULL) { - return(NULL); - } + if (idPtr != NULL) + *idPtr = NULL; + if ((value == NULL) || (value[0] == 0)) + return(0); + if (attr == NULL) + return(0); + + doc = attr->doc; + if (doc == NULL) + return(0);
/* * Create the ID table if needed. @@ -2535,57 +2342,105 @@ xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value, table = (xmlIDTablePtr) doc->ids; if (table == NULL) { doc->ids = table = xmlHashCreateDict(0, doc->dict); - } - if (table == NULL) { - xmlVErrMemory(ctxt, - "xmlAddID: Table creation failed!\n"); - return(NULL); + if (table == NULL) + return(-1); + } else { + id = xmlHashLookup(table, value); + if (id != NULL) + return(0); }
- ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID)); - if (ret == NULL) { - xmlVErrMemory(ctxt, "malloc failed"); - return(NULL); - } + id = (xmlIDPtr) xmlMalloc(sizeof(xmlID)); + if (id == NULL) + return(-1); + memset(id, 0, sizeof(*id));
/* * fill the structure. */ - ret->value = xmlStrdup(value); - ret->doc = doc; - if (xmlIsStreaming(ctxt)) { - /* - * Operating in streaming mode, attr is gonna disappear - */ - if (doc->dict != NULL) - ret->name = xmlDictLookup(doc->dict, attr->name, -1); - else - ret->name = xmlStrdup(attr->name); - ret->attr = NULL; - } else { - ret->attr = attr; - ret->name = NULL; + id->doc = doc; + id->value = xmlStrdup(value); + if (id->value == NULL) { + xmlFreeID(id); + return(-1); } - ret->lineno = xmlGetLineNo(attr->parent);
- if (xmlHashAddEntry(table, value, ret) < 0) { -#ifdef LIBXML_VALID_ENABLED - /* - * The id is already defined in this DTD. - */ - if (ctxt != NULL) { - xmlErrValidNode(ctxt, attr->parent, XML_DTD_ID_REDEFINED, - "ID %s already defined\n", value, NULL, NULL); - } -#endif /* LIBXML_VALID_ENABLED */ - xmlFreeID(ret); - return(NULL); + if (attr->id != NULL) + xmlRemoveID(doc, attr); + + if (xmlHashAddEntry(table, value, id) < 0) { + xmlFreeID(id); + return(-1); } - if (attr != NULL) - attr->atype = XML_ATTRIBUTE_ID; + + ret = 1; + if (idPtr != NULL) + *idPtr = id; + + id->attr = attr; + id->lineno = xmlGetLineNo(attr->parent); + attr->atype = XML_ATTRIBUTE_ID; + attr->id = id; + return(ret); }
+/** + * xmlAddIDSafe: + * @attr: the attribute holding the ID + * @value: the attribute (ID) value + * + * Register a new id declaration + * + * Available since 2.13.0. + * + * Returns 1 on success, 0 if the ID already exists, -1 if a memory + * allocation fails. + */ +int +xmlAddIDSafe(xmlAttrPtr attr, const xmlChar *value) { + return(xmlAddIDInternal(attr, value, NULL)); +} + +/** + * xmlAddID: + * @ctxt: the validation context + * @doc: pointer to the document + * @value: the value name + * @attr: the attribute holding the ID + * + * Register a new id declaration + * + * Returns NULL if not, otherwise the new xmlIDPtr + */ +xmlIDPtr +xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value, + xmlAttrPtr attr) { + xmlIDPtr id; + int res; + + if ((attr == NULL) || (doc != attr->doc)) + return(NULL); + + res = xmlAddIDInternal(attr, value, &id); + if (res < 0) { + xmlVErrMemory(ctxt); + } +#ifdef LIBXML_VALID_ENABLED + else if (res == 0) { + if (ctxt != NULL) { + /* + * The id is already defined in this DTD. + */ + xmlErrValidNode(ctxt, attr->parent, XML_DTD_ID_REDEFINED, + "ID %s already defined\n", value, NULL, NULL); + } + } +#endif /* LIBXML_VALID_ENABLED */ + + return(id); +} + static void xmlFreeIDTableEntry(void *id, const xmlChar *name ATTRIBUTE_UNUSED) { xmlFreeID((xmlIDPtr) id); @@ -2613,57 +2468,67 @@ xmlFreeIDTable(xmlIDTablePtr table) { * of HTML documents parsed with the HTML parser, then ID detection is * done systematically. * - * Returns 0 or 1 depending on the lookup result + * Returns 0 or 1 depending on the lookup result or -1 if a memory allocation + * failed. */ int xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) { - if ((attr == NULL) || (attr->name == NULL)) return(0); - if ((attr->ns != NULL) && (attr->ns->prefix != NULL) && - (!strcmp((char *) attr->name, "id")) && - (!strcmp((char *) attr->ns->prefix, "xml"))) - return(1); - if (doc == NULL) return(0); - if ((doc->intSubset == NULL) && (doc->extSubset == NULL) && - (doc->type != XML_HTML_DOCUMENT_NODE)) { - return(0); - } else if (doc->type == XML_HTML_DOCUMENT_NODE) { - if ((xmlStrEqual(BAD_CAST "id", attr->name)) || - ((xmlStrEqual(BAD_CAST "name", attr->name)) && - ((elem == NULL) || (xmlStrEqual(elem->name, BAD_CAST "a"))))) + if ((attr == NULL) || (attr->name == NULL)) + return(0); + + if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) { + if (xmlStrEqual(BAD_CAST "id", attr->name)) + return(1); + + if ((elem == NULL) || (elem->type != XML_ELEMENT_NODE)) + return(0); + + if ((xmlStrEqual(BAD_CAST "name", attr->name)) && + (xmlStrEqual(elem->name, BAD_CAST "a"))) return(1); - return(0); - } else if (elem == NULL) { - return(0); } else { xmlAttributePtr attrDecl = NULL; + xmlChar felem[50]; + xmlChar *fullelemname; + const xmlChar *aprefix; + + if ((attr->ns != NULL) && (attr->ns->prefix != NULL) && + (!strcmp((char *) attr->name, "id")) && + (!strcmp((char *) attr->ns->prefix, "xml"))) + return(1); + + if ((doc == NULL) || + ((doc->intSubset == NULL) && (doc->extSubset == NULL))) + return(0);
- xmlChar felem[50], fattr[50]; - xmlChar *fullelemname, *fullattrname; + if ((elem == NULL) || + (elem->type != XML_ELEMENT_NODE) || + (elem->name == NULL)) + return(0);
fullelemname = (elem->ns != NULL && elem->ns->prefix != NULL) ? xmlBuildQName(elem->name, elem->ns->prefix, felem, 50) : (xmlChar *)elem->name; + if (fullelemname == NULL) + return(-1);
- fullattrname = (attr->ns != NULL && attr->ns->prefix != NULL) ? - xmlBuildQName(attr->name, attr->ns->prefix, fattr, 50) : - (xmlChar *)attr->name; + aprefix = (attr->ns != NULL) ? attr->ns->prefix : NULL;
- if (fullelemname != NULL && fullattrname != NULL) { - attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullelemname, - fullattrname); + if (fullelemname != NULL) { + attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullelemname, + attr->name, aprefix); if ((attrDecl == NULL) && (doc->extSubset != NULL)) - attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullelemname, - fullattrname); + attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullelemname, + attr->name, aprefix); }
- if ((fullattrname != fattr) && (fullattrname != attr->name)) - xmlFree(fullattrname); if ((fullelemname != felem) && (fullelemname != elem->name)) xmlFree(fullelemname);
if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID)) return(1); } + return(0); }
@@ -2679,30 +2544,17 @@ xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) { int xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) { xmlIDTablePtr table; - xmlIDPtr id; - xmlChar *ID;
if (doc == NULL) return(-1); - if (attr == NULL) return(-1); + if ((attr == NULL) || (attr->id == NULL)) return(-1);
table = (xmlIDTablePtr) doc->ids; if (table == NULL) return(-1);
- ID = xmlNodeListGetString(doc, attr->children, 1); - if (ID == NULL) - return(-1); - xmlValidNormalizeString(ID); - - id = xmlHashLookup(table, ID); - if (id == NULL || id->attr != attr) { - xmlFree(ID); + if (xmlHashRemoveEntry(table, attr->id->value, xmlFreeIDTableEntry) < 0) return(-1); - }
- xmlHashRemoveEntry(table, ID, xmlFreeIDTableEntry); - xmlFree(ID); - attr->atype = 0; return(0); }
@@ -2847,7 +2699,7 @@ xmlDummyCompare(const void *data0 ATTRIBUTE_UNUSED, xmlRefPtr xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value, xmlAttrPtr attr) { - xmlRefPtr ret; + xmlRefPtr ret = NULL; xmlRefTablePtr table; xmlListPtr ref_list;
@@ -2867,28 +2719,28 @@ xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value, table = (xmlRefTablePtr) doc->refs; if (table == NULL) { doc->refs = table = xmlHashCreateDict(0, doc->dict); - } - if (table == NULL) { - xmlVErrMemory(ctxt, - "xmlAddRef: Table creation failed!\n"); - return(NULL); + if (table == NULL) + goto failed; }
ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef)); - if (ret == NULL) { - xmlVErrMemory(ctxt, "malloc failed"); - return(NULL); - } + if (ret == NULL) + goto failed; + memset(ret, 0, sizeof(*ret));
/* * fill the structure. */ ret->value = xmlStrdup(value); + if (ret->value == NULL) + goto failed; if (xmlIsStreaming(ctxt)) { /* * Operating in streaming mode, attr is gonna disappear */ ret->name = xmlStrdup(attr->name); + if (ret->name == NULL) + goto failed; ret->attr = NULL; } else { ret->name = NULL; @@ -2904,28 +2756,22 @@ xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value, */
if (NULL == (ref_list = xmlHashLookup(table, value))) { - if (NULL == (ref_list = xmlListCreate(xmlFreeRef, xmlDummyCompare))) { - xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, - "xmlAddRef: Reference list creation failed!\n", - NULL); + int res; + + if (NULL == (ref_list = xmlListCreate(xmlFreeRef, xmlDummyCompare))) goto failed; - } - if (xmlHashAddEntry(table, value, ref_list) < 0) { + res = xmlHashAdd(table, value, ref_list); + if (res <= 0) { xmlListDelete(ref_list); - xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, - "xmlAddRef: Reference list insertion failed!\n", - NULL); goto failed; } } - if (xmlListAppend(ref_list, ret) != 0) { - xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, - "xmlAddRef: Reference list insertion failed!\n", - NULL); + if (xmlListAppend(ref_list, ret) != 0) goto failed; - } return(ret); + failed: + xmlVErrMemory(ctxt); if (ret != NULL) { if (ret->value != NULL) xmlFree((char *)ret->value); @@ -2979,12 +2825,15 @@ xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) { return(0); } else { xmlAttributePtr attrDecl; + const xmlChar *aprefix;
if (elem == NULL) return(0); - attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name); + aprefix = (attr->ns != NULL) ? attr->ns->prefix : NULL; + attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name, attr->name, + aprefix); if ((attrDecl == NULL) && (doc->extSubset != NULL)) - attrDecl = xmlGetDtdAttrDesc(doc->extSubset, - elem->name, attr->name); + attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name, attr->name, + aprefix);
if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_IDREF || @@ -3047,7 +2896,7 @@ xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
/*If the list is empty then remove the list entry in the hash */ if (xmlListEmpty(ref_list)) - xmlHashUpdateEntry(table, ID, NULL, xmlFreeRefTableEntry); + xmlHashRemoveEntry(table, ID, xmlFreeRefTableEntry); xmlFree(ID); return(0); } @@ -3095,6 +2944,8 @@ xmlGetRefs(xmlDocPtr doc, const xmlChar *ID) { * * Search the DTD for the description of this element * + * NOTE: A NULL return value can also mean that a memory allocation failed. + * * returns the xmlElementPtr if found or NULL */
@@ -3102,21 +2953,26 @@ xmlElementPtr xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) { xmlElementTablePtr table; xmlElementPtr cur; - xmlChar *uqname = NULL, *prefix = NULL; + const xmlChar *localname; + xmlChar *prefix; + + if ((dtd == NULL) || (dtd->elements == NULL) || + (name == NULL)) + return(NULL);
- if ((dtd == NULL) || (name == NULL)) return(NULL); - if (dtd->elements == NULL) - return(NULL); table = (xmlElementTablePtr) dtd->elements; + if (table == NULL) + return(NULL);
- uqname = xmlSplitQName2(name, &prefix); - if (uqname != NULL) - name = uqname; - cur = xmlHashLookup2(table, name, prefix); - if (prefix != NULL) xmlFree(prefix); - if (uqname != NULL) xmlFree(uqname); + localname = xmlSplitQName4(name, &prefix); + if (localname == NULL) + return(NULL); + cur = xmlHashLookup2(table, localname, prefix); + if (prefix != NULL) + xmlFree(prefix); return(cur); } + /** * xmlGetDtdElementDesc2: * @dtd: a pointer to the DtD to search @@ -3129,66 +2985,64 @@ xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) { */
static xmlElementPtr -xmlGetDtdElementDesc2(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name, - int create) { +xmlGetDtdElementDesc2(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name) { xmlElementTablePtr table; - xmlElementPtr cur; - xmlChar *uqname = NULL, *prefix = NULL; + xmlElementPtr cur = NULL; + const xmlChar *localName; + xmlChar *prefix = NULL;
if (dtd == NULL) return(NULL); + + /* + * Create the Element table if needed. + */ if (dtd->elements == NULL) { xmlDictPtr dict = NULL;
if (dtd->doc != NULL) dict = dtd->doc->dict;
- if (!create) - return(NULL); - /* - * Create the Element table if needed. - */ - table = (xmlElementTablePtr) dtd->elements; - if (table == NULL) { - table = xmlHashCreateDict(0, dict); - dtd->elements = (void *) table; - } - if (table == NULL) { - xmlVErrMemory(ctxt, "element table allocation failed"); - return(NULL); - } + dtd->elements = xmlHashCreateDict(0, dict); + if (dtd->elements == NULL) + goto mem_error; } table = (xmlElementTablePtr) dtd->elements;
- uqname = xmlSplitQName2(name, &prefix); - if (uqname != NULL) - name = uqname; - cur = xmlHashLookup2(table, name, prefix); - if ((cur == NULL) && (create)) { + localName = xmlSplitQName4(name, &prefix); + if (localName == NULL) + goto mem_error; + cur = xmlHashLookup2(table, localName, prefix); + if (cur == NULL) { cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement)); - if (cur == NULL) { - xmlVErrMemory(ctxt, "malloc failed"); - goto error; - } + if (cur == NULL) + goto mem_error; memset(cur, 0, sizeof(xmlElement)); cur->type = XML_ELEMENT_DECL; + cur->doc = dtd->doc;
/* * fill the structure. */ - cur->name = xmlStrdup(name); - cur->prefix = xmlStrdup(prefix); + cur->name = xmlStrdup(localName); + if (cur->name == NULL) + goto mem_error; + cur->prefix = prefix; + prefix = NULL; cur->etype = XML_ELEMENT_TYPE_UNDEFINED;
- if (xmlHashAddEntry2(table, name, prefix, cur) < 0) { - xmlVErrMemory(ctxt, "adding entry failed"); - xmlFreeElement(cur); - cur = NULL; - } + if (xmlHashAdd2(table, localName, cur->prefix, cur) <= 0) + goto mem_error; } -error: - if (prefix != NULL) xmlFree(prefix); - if (uqname != NULL) xmlFree(uqname); + + if (prefix != NULL) + xmlFree(prefix); return(cur); + +mem_error: + xmlVErrMemory(ctxt); + xmlFree(prefix); + xmlFreeElement(cur); + return(NULL); }
/** @@ -3230,23 +3084,23 @@ xmlAttributePtr xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) { xmlAttributeTablePtr table; xmlAttributePtr cur; - xmlChar *uqname = NULL, *prefix = NULL; + const xmlChar *localname; + xmlChar *prefix = NULL;
- if (dtd == NULL) return(NULL); - if (dtd->attributes == NULL) return(NULL); + if ((dtd == NULL) || (dtd->attributes == NULL) || + (elem == NULL) || (name == NULL)) + return(NULL);
table = (xmlAttributeTablePtr) dtd->attributes; if (table == NULL) return(NULL);
- uqname = xmlSplitQName2(name, &prefix); - - if (uqname != NULL) { - cur = xmlHashLookup3(table, uqname, prefix, elem); - if (prefix != NULL) xmlFree(prefix); - if (uqname != NULL) xmlFree(uqname); - } else - cur = xmlHashLookup3(table, name, NULL, elem); + localname = xmlSplitQName4(name, &prefix); + if (localname == NULL) + return(NULL); + cur = xmlHashLookup3(table, localname, prefix, elem); + if (prefix != NULL) + xmlFree(prefix); return(cur); }
@@ -3303,6 +3157,8 @@ xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) { * @doc: the document * @notationName: the notation name to check * + * DEPRECATED: Internal function, don't use. + * * Validate that the given name match a notation declaration. * - [ VC: Notation Declared ] * @@ -3370,6 +3226,35 @@ xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
#ifdef LIBXML_VALID_ENABLED
+/** + * xmlValidNormalizeString: + * @str: a string + * + * Normalize a string in-place. + */ +static void +xmlValidNormalizeString(xmlChar *str) { + xmlChar *dst; + const xmlChar *src; + + if (str == NULL) + return; + src = str; + dst = str; + + while (*src == 0x20) src++; + while (*src != 0) { + if (*src == 0x20) { + while (*src == 0x20) src++; + if (*src != 0) + *dst++ = 0x20; + } else { + *dst++ = *src++; + } + } + *dst = 0; +} + static int xmlIsDocNameStartChar(xmlDocPtr doc, int c) { if ((doc == NULL) || (doc->properties & XML_DOC_OLD10) == 0) { @@ -3689,6 +3574,8 @@ xmlValidateNmtokensValue(const xmlChar *value) { * @doc: a document instance * @nota: a notation definition * + * DEPRECATED: Internal function, don't use. + * * Try to validate a single notation definition * basically it does the following checks as described by the * XML-1.0 recommendation: @@ -3745,6 +3632,8 @@ xmlValidateAttributeValueInternal(xmlDocPtr doc, xmlAttributeType type, * @type: an attribute type * @value: an attribute value * + * DEPRECATED: Internal function, don't use. + * * Validate that the given attribute value match the proper production * * [ VC: ID ] @@ -3840,8 +3729,10 @@ xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlEntityPtr ent;
dup = xmlStrdup(value); - if (dup == NULL) + if (dup == NULL) { + xmlVErrMemory(ctxt); return(0); + } cur = dup; while (*cur != 0) { nam = cur; @@ -3899,6 +3790,8 @@ xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc, * @value: the attribute value * @ctxt: the validation context or NULL * + * DEPRECATED: Internal function, don't use. + * * Does the validation related extra step of the normalization of attribute * values: * @@ -3919,6 +3812,8 @@ xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem, const xmlChar *name, const xmlChar *value) { xmlChar *ret; xmlAttributePtr attrDecl = NULL; + const xmlChar *localName; + xmlChar *prefix = NULL; int extsubset = 0;
if (doc == NULL) return(NULL); @@ -3926,38 +3821,47 @@ xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc, if (name == NULL) return(NULL); if (value == NULL) return(NULL);
- if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) { - xmlChar fn[50]; - xmlChar *fullname; + localName = xmlSplitQName4(name, &prefix); + if (localName == NULL) + goto mem_error;
- fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50); - if (fullname == NULL) - return(NULL); - attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name); + if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) { + xmlChar buf[50]; + xmlChar *elemname; + + elemname = xmlBuildQName(elem->name, elem->ns->prefix, buf, 50); + if (elemname == NULL) + goto mem_error; + if (doc->intSubset != NULL) + attrDecl = xmlHashLookup3(doc->intSubset->attributes, localName, + prefix, elemname); if ((attrDecl == NULL) && (doc->extSubset != NULL)) { - attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name); + attrDecl = xmlHashLookup3(doc->extSubset->attributes, localName, + prefix, elemname); if (attrDecl != NULL) extsubset = 1; } - if ((fullname != fn) && (fullname != elem->name)) - xmlFree(fullname); + if ((elemname != buf) && (elemname != elem->name)) + xmlFree(elemname); } if ((attrDecl == NULL) && (doc->intSubset != NULL)) - attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name); + attrDecl = xmlHashLookup3(doc->intSubset->attributes, localName, + prefix, elem->name); if ((attrDecl == NULL) && (doc->extSubset != NULL)) { - attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name); + attrDecl = xmlHashLookup3(doc->extSubset->attributes, localName, + prefix, elem->name); if (attrDecl != NULL) extsubset = 1; }
if (attrDecl == NULL) - return(NULL); + goto done; if (attrDecl->atype == XML_ATTRIBUTE_CDATA) - return(NULL); + goto done;
ret = xmlStrdup(value); if (ret == NULL) - return(NULL); + goto mem_error; xmlValidNormalizeString(ret); if ((doc->standalone) && (extsubset == 1) && (!xmlStrEqual(value, ret))) { xmlErrValidNode(ctxt, elem, XML_DTD_NOT_STANDALONE, @@ -3965,7 +3869,16 @@ xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc, name, elem->name, NULL); ctxt->valid = 0; } + + xmlFree(prefix); return(ret); + +mem_error: + xmlVErrMemory(ctxt); + +done: + xmlFree(prefix); + return(NULL); }
/** @@ -3975,6 +3888,8 @@ xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc, * @name: the attribute name * @value: the attribute value * + * DEPRECATED: Internal function, don't use. + * * Does the validation related extra step of the normalization of attribute * values: * @@ -4038,6 +3953,8 @@ xmlValidateAttributeIdCallback(void *payload, void *data, * @doc: a document instance * @attr: an attribute definition * + * DEPRECATED: Internal function, don't use. + * * Try to validate a single attribute definition * basically it does the following checks as described by the * XML-1.0 recommendation: @@ -4083,13 +4000,23 @@ xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
/* One ID per Element Type */ if (attr->atype == XML_ATTRIBUTE_ID) { + xmlElementPtr elem = NULL; + const xmlChar *elemLocalName; + xmlChar *elemPrefix; int nbId;
+ elemLocalName = xmlSplitQName4(attr->elem, &elemPrefix); + if (elemLocalName == NULL) { + xmlVErrMemory(ctxt); + return(0); + } + /* the trick is that we parse DtD as their own internal subset */ - xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset, - attr->elem); + if (doc->intSubset != NULL) + elem = xmlHashLookup2(doc->intSubset->elements, + elemLocalName, elemPrefix); if (elem != NULL) { - nbId = xmlScanIDAttributeDecl(NULL, elem, 0); + nbId = xmlScanIDAttributeDecl(ctxt, elem, 0); } else { xmlAttributeTablePtr table;
@@ -4109,22 +4036,28 @@ xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET, "Element %s has %d ID attribute defined in the internal subset : %s\n", attr->elem, nbId, attr->name); + ret = 0; } else if (doc->extSubset != NULL) { int extId = 0; - elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem); + elem = xmlHashLookup2(doc->extSubset->elements, + elemLocalName, elemPrefix); if (elem != NULL) { - extId = xmlScanIDAttributeDecl(NULL, elem, 0); + extId = xmlScanIDAttributeDecl(ctxt, elem, 0); } if (extId > 1) { xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET, "Element %s has %d ID attribute defined in the external subset : %s\n", attr->elem, extId, attr->name); + ret = 0; } else if (extId + nbId > 1) { xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET, "Element %s has ID attributes defined in the internal and external subset : %s\n", attr->elem, attr->name, NULL); + ret = 0; } } + + xmlFree(elemPrefix); }
/* Validity Constraint: Enumeration */ @@ -4151,6 +4084,8 @@ xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc, * @doc: a document instance * @elem: an element definition * + * DEPRECATED: Internal function, don't use. + * * Try to validate a single element definition * basically it does the following checks as described by the * XML-1.0 recommendation: @@ -4166,6 +4101,8 @@ xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlElementPtr elem) { int ret = 1; xmlElementPtr tst; + const xmlChar *localName; + xmlChar *prefix;
CHECK_DTD;
@@ -4229,32 +4166,47 @@ xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc, } }
+ localName = xmlSplitQName4(elem->name, &prefix); + if (localName == NULL) { + xmlVErrMemory(ctxt); + return(0); + } + /* VC: Unique Element Type Declaration */ - tst = xmlGetDtdElementDesc(doc->intSubset, elem->name); - if ((tst != NULL ) && (tst != elem) && - ((tst->prefix == elem->prefix) || - (xmlStrEqual(tst->prefix, elem->prefix))) && - (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) { - xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED, - "Redefinition of element %s\n", - elem->name, NULL, NULL); - ret = 0; + if (doc->intSubset != NULL) { + tst = xmlHashLookup2(doc->intSubset->elements, localName, prefix); + + if ((tst != NULL ) && (tst != elem) && + ((tst->prefix == elem->prefix) || + (xmlStrEqual(tst->prefix, elem->prefix))) && + (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) { + xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED, + "Redefinition of element %s\n", + elem->name, NULL, NULL); + ret = 0; + } } - tst = xmlGetDtdElementDesc(doc->extSubset, elem->name); - if ((tst != NULL ) && (tst != elem) && - ((tst->prefix == elem->prefix) || - (xmlStrEqual(tst->prefix, elem->prefix))) && - (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) { - xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED, - "Redefinition of element %s\n", - elem->name, NULL, NULL); - ret = 0; + if (doc->extSubset != NULL) { + tst = xmlHashLookup2(doc->extSubset->elements, localName, prefix); + + if ((tst != NULL ) && (tst != elem) && + ((tst->prefix == elem->prefix) || + (xmlStrEqual(tst->prefix, elem->prefix))) && + (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) { + xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED, + "Redefinition of element %s\n", + elem->name, NULL, NULL); + ret = 0; + } } + /* One ID per Element Type * already done when registering the attribute if (xmlScanIDAttributeDecl(ctxt, elem) > 1) { ret = 0; } */ + + xmlFree(prefix); return(ret); }
@@ -4266,6 +4218,8 @@ xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc, * @attr: an attribute instance * @value: the attribute value (without entities processing) * + * DEPRECATED: Internal function, don't use. + * * Try to validate a single attribute for an element * basically it does the following checks as described by the * XML-1.0 recommendation: @@ -4288,6 +4242,7 @@ xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value) { xmlAttributePtr attrDecl = NULL; + const xmlChar *aprefix; int val; int ret = 1;
@@ -4295,42 +4250,31 @@ xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc, if ((elem == NULL) || (elem->name == NULL)) return(0); if ((attr == NULL) || (attr->name == NULL)) return(0);
+ aprefix = (attr->ns != NULL) ? attr->ns->prefix : NULL; + if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) { xmlChar fn[50]; xmlChar *fullname;
fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50); - if (fullname == NULL) + if (fullname == NULL) { + xmlVErrMemory(ctxt); return(0); - if (attr->ns != NULL) { - attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname, - attr->name, attr->ns->prefix); - if ((attrDecl == NULL) && (doc->extSubset != NULL)) - attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname, - attr->name, attr->ns->prefix); - } else { - attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, attr->name); - if ((attrDecl == NULL) && (doc->extSubset != NULL)) - attrDecl = xmlGetDtdAttrDesc(doc->extSubset, - fullname, attr->name); - } + } + attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname, + attr->name, aprefix); + if ((attrDecl == NULL) && (doc->extSubset != NULL)) + attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname, + attr->name, aprefix); if ((fullname != fn) && (fullname != elem->name)) xmlFree(fullname); } if (attrDecl == NULL) { - if (attr->ns != NULL) { - attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name, - attr->name, attr->ns->prefix); - if ((attrDecl == NULL) && (doc->extSubset != NULL)) - attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name, - attr->name, attr->ns->prefix); - } else { - attrDecl = xmlGetDtdAttrDesc(doc->intSubset, - elem->name, attr->name); - if ((attrDecl == NULL) && (doc->extSubset != NULL)) - attrDecl = xmlGetDtdAttrDesc(doc->extSubset, - elem->name, attr->name); - } + attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name, + attr->name, aprefix); + if ((attrDecl == NULL) && (doc->extSubset != NULL)) + attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name, + attr->name, aprefix); }
@@ -4341,6 +4285,8 @@ xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc, attr->name, elem->name, NULL); return(0); } + if (attr->atype == XML_ATTRIBUTE_ID) + xmlRemoveID(doc, attr); attr->atype = attrDecl->atype;
val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value); @@ -4443,6 +4389,8 @@ xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc, * @ns: an namespace declaration instance * @value: the attribute value (without entities processing) * + * DEPRECATED: Internal function, don't use. + * * Try to validate a single namespace declaration for an element * basically it does the following checks as described by the * XML-1.0 recommendation: @@ -4478,7 +4426,7 @@ xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) {
fullname = xmlBuildQName(elem->name, prefix, fn, 50); if (fullname == NULL) { - xmlVErrMemory(ctxt, "Validating namespace"); + xmlVErrMemory(ctxt); return(0); } if (ns->prefix != NULL) { @@ -4488,11 +4436,11 @@ xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) { attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname, ns->prefix, BAD_CAST "xmlns"); } else { - attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, - BAD_CAST "xmlns"); + attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname, + BAD_CAST "xmlns", NULL); if ((attrDecl == NULL) && (doc->extSubset != NULL)) - attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, - BAD_CAST "xmlns"); + attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname, + BAD_CAST "xmlns", NULL); } if ((fullname != fn) && (fullname != elem->name)) xmlFree(fullname); @@ -4505,11 +4453,11 @@ xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) { attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name, ns->prefix, BAD_CAST "xmlns"); } else { - attrDecl = xmlGetDtdAttrDesc(doc->intSubset, - elem->name, BAD_CAST "xmlns"); + attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name, + BAD_CAST "xmlns", NULL); if ((attrDecl == NULL) && (doc->extSubset != NULL)) - attrDecl = xmlGetDtdAttrDesc(doc->extSubset, - elem->name, BAD_CAST "xmlns"); + attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name, + BAD_CAST "xmlns", NULL); } }
@@ -5159,67 +5107,74 @@ xmlValidateElementContent(xmlValidCtxtPtr ctxt, xmlNodePtr child, ctxt->nodeNr = 0; ctxt->nodeTab = NULL; exec = xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL); - if (exec != NULL) { - cur = child; - while (cur != NULL) { - switch (cur->type) { - case XML_ENTITY_REF_NODE: - /* - * Push the current node to be able to roll back - * and process within the entity - */ - if ((cur->children != NULL) && - (cur->children->children != NULL)) { - nodeVPush(ctxt, cur); - cur = cur->children->children; - continue; - } - break; - case XML_TEXT_NODE: - if (xmlIsBlankNode(cur)) - break; - ret = 0; - goto fail; - case XML_CDATA_SECTION_NODE: - /* TODO */ - ret = 0; - goto fail; - case XML_ELEMENT_NODE: - if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) { - xmlChar fn[50]; - xmlChar *fullname; - - fullname = xmlBuildQName(cur->name, - cur->ns->prefix, fn, 50); - if (fullname == NULL) { - ret = -1; - goto fail; - } - ret = xmlRegExecPushString(exec, fullname, NULL); - if ((fullname != fn) && (fullname != cur->name)) - xmlFree(fullname); - } else { - ret = xmlRegExecPushString(exec, cur->name, NULL); - } - break; - default: - break; - } - /* - * Switch to next element - */ - cur = cur->next; - while (cur == NULL) { - cur = nodeVPop(ctxt); - if (cur == NULL) - break; - cur = cur->next; - } - } - ret = xmlRegExecPushString(exec, NULL, NULL); + if (exec == NULL) { + xmlVErrMemory(ctxt); + return(-1); + } + cur = child; + while (cur != NULL) { + switch (cur->type) { + case XML_ENTITY_REF_NODE: + /* + * Push the current node to be able to roll back + * and process within the entity + */ + if ((cur->children != NULL) && + (cur->children->children != NULL)) { + nodeVPush(ctxt, cur); + cur = cur->children->children; + continue; + } + break; + case XML_TEXT_NODE: + if (xmlIsBlankNode(cur)) + break; + ret = 0; + goto fail; + case XML_CDATA_SECTION_NODE: + /* TODO */ + ret = 0; + goto fail; + case XML_ELEMENT_NODE: + if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) { + xmlChar fn[50]; + xmlChar *fullname; + + fullname = xmlBuildQName(cur->name, + cur->ns->prefix, fn, 50); + if (fullname == NULL) { + xmlVErrMemory(ctxt); + ret = -1; + goto fail; + } + ret = xmlRegExecPushString(exec, fullname, NULL); + if ((fullname != fn) && (fullname != cur->name)) + xmlFree(fullname); + } else { + ret = xmlRegExecPushString(exec, cur->name, NULL); + } + break; + default: + break; + } + if (ret == XML_REGEXP_OUT_OF_MEMORY) + xmlVErrMemory(ctxt); + /* + * Switch to next element + */ + cur = cur->next; + while (cur == NULL) { + cur = nodeVPop(ctxt); + if (cur == NULL) + break; + cur = cur->next; + } + } + ret = xmlRegExecPushString(exec, NULL, NULL); + if (ret == XML_REGEXP_OUT_OF_MEMORY) + xmlVErrMemory(ctxt); fail: - xmlRegFreeExecCtxt(exec); - } + xmlRegFreeExecCtxt(exec); } #else /* LIBXML_REGEXP_ENABLED */ /* @@ -5229,7 +5184,7 @@ fail: ctxt->vstateTab = (xmlValidState *) xmlMalloc( ctxt->vstateMax * sizeof(ctxt->vstateTab[0])); if (ctxt->vstateTab == NULL) { - xmlVErrMemory(ctxt, "malloc failed"); + xmlVErrMemory(ctxt); return(-1); } /* @@ -5288,7 +5243,7 @@ fail: */ tmp = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); if (tmp == NULL) { - xmlVErrMemory(ctxt, "malloc failed"); + xmlVErrMemory(ctxt); xmlFreeNodeList(repl); ret = -1; goto done; @@ -5588,9 +5543,9 @@ xmlValidGetElemDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc, * full QName but in that case being flexible makes sense. */ if (elemDecl == NULL) { - elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name); + elemDecl = xmlGetDtdQElementDesc(doc->intSubset, elem->name, NULL); if ((elemDecl == NULL) && (doc->extSubset != NULL)) { - elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name); + elemDecl = xmlGetDtdQElementDesc(doc->extSubset, elem->name, NULL); if ((elemDecl != NULL) && (extsubset != NULL)) *extsubset = 1; } @@ -5612,6 +5567,8 @@ xmlValidGetElemDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc, * @elem: an element instance * @qname: the qualified name as appearing in the serialization * + * DEPRECATED: Internal function, don't use. + * * Push a new element start on the validation stack. * * returns 1 if no validation problem was found or 0 otherwise @@ -5680,6 +5637,10 @@ xmlValidatePushElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, */ if (state->exec != NULL) { ret = xmlRegExecPushString(state->exec, qname, NULL); + if (ret == XML_REGEXP_OUT_OF_MEMORY) { + xmlVErrMemory(ctxt); + return(0); + } if (ret < 0) { xmlErrValidNode(ctxt, state->node, XML_DTD_CONTENT_MODEL, @@ -5705,6 +5666,8 @@ xmlValidatePushElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, * @data: some character data read * @len: the length of the data * + * DEPRECATED: Internal function, don't use. + * * check the CData parsed for validation in the current stack * * returns 1 if no validation problem was found or 0 otherwise @@ -5778,6 +5741,8 @@ done: * @elem: an element instance * @qname: the qualified name as appearing in the serialization * + * DEPRECATED: Internal function, don't use. + * * Pop the element end from the validation stack. * * returns 1 if no validation problem was found or 0 otherwise @@ -5805,8 +5770,11 @@ xmlValidatePopElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc ATTRIBUTE_UNUSED, if (state->exec != NULL) { ret = xmlRegExecPushString(state->exec, NULL, NULL); if (ret <= 0) { - xmlErrValidNode(ctxt, state->node, - XML_DTD_CONTENT_MODEL, + if (ret == XML_REGEXP_OUT_OF_MEMORY) + xmlVErrMemory(ctxt); + else + xmlErrValidNode(ctxt, state->node, + XML_DTD_CONTENT_MODEL, "Element %s content does not follow the DTD, Expecting more children\n", state->node->name, NULL,NULL); ret = 0; @@ -5832,6 +5800,8 @@ xmlValidatePopElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc ATTRIBUTE_UNUSED, * @doc: a document instance * @elem: an element instance * + * DEPRECATED: Internal function, don't use. + * * Try to validate a single element and it's attributes, * basically it does the following checks as described by the * XML-1.0 recommendation: @@ -5859,61 +5829,19 @@ xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
if (elem == NULL) return(0); switch (elem->type) { - case XML_ATTRIBUTE_NODE: - xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, - "Attribute element not expected\n", NULL, NULL ,NULL); - return(0); case XML_TEXT_NODE: - if (elem->children != NULL) { - xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, - "Text element has children !\n", - NULL,NULL,NULL); - return(0); - } - if (elem->ns != NULL) { - xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, - "Text element has namespace !\n", - NULL,NULL,NULL); - return(0); - } - if (elem->content == NULL) { - xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, - "Text element has no content !\n", - NULL,NULL,NULL); - return(0); - } - return(1); - case XML_XINCLUDE_START: - case XML_XINCLUDE_END: - return(1); case XML_CDATA_SECTION_NODE: case XML_ENTITY_REF_NODE: case XML_PI_NODE: case XML_COMMENT_NODE: + case XML_XINCLUDE_START: + case XML_XINCLUDE_END: return(1); - case XML_ENTITY_NODE: - xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, - "Entity element not expected\n", NULL, NULL ,NULL); - return(0); - case XML_NOTATION_NODE: - xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, - "Notation element not expected\n", NULL, NULL ,NULL); - return(0); - case XML_DOCUMENT_NODE: - case XML_DOCUMENT_TYPE_NODE: - case XML_DOCUMENT_FRAG_NODE: - xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, - "Document element not expected\n", NULL, NULL ,NULL); - return(0); - case XML_HTML_DOCUMENT_NODE: - xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, - "HTML Document not expected\n", NULL, NULL ,NULL); - return(0); case XML_ELEMENT_NODE: break; default: xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, - "unknown element type\n", NULL, NULL ,NULL); + "unexpected element type\n", NULL, NULL ,NULL); return(0); }
@@ -5971,8 +5899,10 @@ xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
fullname = xmlBuildQName(child->name, child->ns->prefix, fn, 50); - if (fullname == NULL) + if (fullname == NULL) { + xmlVErrMemory(ctxt); return(0); + } cont = elemDecl->content; while (cont != NULL) { if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) { @@ -6036,7 +5966,8 @@ child_ok: */ child = elem->children; while (child != NULL) { - if (child->type == XML_TEXT_NODE) { + if ((child->type == XML_TEXT_NODE) && + (child->content != NULL)) { const xmlChar *content = child->content;
while (IS_BLANK_CH(*content)) @@ -6057,7 +5988,7 @@ child_ok: cont = elemDecl->content; tmp = xmlValidateElementContent(ctxt, child, elemDecl, 1, elem); if (tmp <= 0) - ret = tmp; + ret = 0; break; } } /* not continuous */ @@ -6199,6 +6130,8 @@ found: * @ctxt: the validation context * @doc: a document instance * + * DEPRECATED: Internal function, don't use. + * * Try to validate a the root element * basically it does the following check as described by the * XML-1.0 recommendation: @@ -6238,7 +6171,7 @@ xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
fullname = xmlBuildQName(root->name, root->ns->prefix, fn, 50); if (fullname == NULL) { - xmlVErrMemory(ctxt, NULL); + xmlVErrMemory(ctxt); return(0); } ret = xmlStrEqual(doc->intSubset->name, fullname); @@ -6291,10 +6224,17 @@ xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr root) { if (elem->type == XML_ELEMENT_NODE) { attr = elem->properties; while (attr != NULL) { - value = xmlNodeListGetString(doc, attr->children, 0); - ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value); - if (value != NULL) + if (attr->children == NULL) + value = xmlStrdup(BAD_CAST ""); + else + value = xmlNodeListGetString(doc, attr->children, 0); + if (value == NULL) { + xmlVErrMemory(ctxt); + ret = 0; + } else { + ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value); xmlFree((char *)value); + } attr= attr->next; }
@@ -6353,7 +6293,7 @@ xmlValidateRef(xmlRefPtr ref, xmlValidCtxtPtr ctxt,
dup = xmlStrdup(name); if (dup == NULL) { - ctxt->valid = 0; + xmlVErrMemory(ctxt); return; } cur = dup; @@ -6388,7 +6328,7 @@ xmlValidateRef(xmlRefPtr ref, xmlValidCtxtPtr ctxt,
dup = xmlStrdup(name); if (dup == NULL) { - xmlVErrMemory(ctxt, "IDREFS split"); + xmlVErrMemory(ctxt); ctxt->valid = 0; return; } @@ -6456,6 +6396,8 @@ xmlValidateCheckRefCallback(void *payload, void *data, const xmlChar *name) { * @ctxt: the validation context * @doc: a document instance * + * DEPRECATED: Internal function, don't use. + * * Does the final step for the document validation once all the * incremental validation steps have been completed * @@ -6469,7 +6411,8 @@ xmlValidateCheckRefCallback(void *payload, void *data, const xmlChar *name) { int xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) { xmlRefTablePtr table; - unsigned int save; + xmlParserCtxtPtr pctxt = NULL; + xmlParserInputPtr oldInput = NULL;
if (ctxt == NULL) return(0); @@ -6479,10 +6422,6 @@ xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) { return(0); }
- /* trick to get correct line id report */ - save = ctxt->flags; - ctxt->flags &= ~XML_VCTXT_USE_PCTXT; - /* * Check all the NOTATION/NOTATIONS attributes */ @@ -6492,12 +6431,24 @@ xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) { /* * Check all the IDREF/IDREFS attributes definition for validity */ + + /* + * Don't print line numbers. + */ + if (ctxt->flags & XML_VCTXT_USE_PCTXT) { + pctxt = ctxt->userData; + oldInput = pctxt->input; + pctxt->input = NULL; + } + table = (xmlRefTablePtr) doc->refs; ctxt->doc = doc; ctxt->valid = 1; xmlHashScan(table, xmlValidateCheckRefCallback, ctxt);
- ctxt->flags = save; + if (ctxt->flags & XML_VCTXT_USE_PCTXT) + pctxt->input = oldInput; + return(ctxt->valid); }
@@ -6523,31 +6474,42 @@ xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) { xmlDtdPtr oldExt, oldInt; xmlNodePtr root;
- if (dtd == NULL) return(0); - if (doc == NULL) return(0); + if (dtd == NULL) + return(0); + if (doc == NULL) + return(0); + oldExt = doc->extSubset; oldInt = doc->intSubset; doc->extSubset = dtd; doc->intSubset = NULL; - ret = xmlValidateRoot(ctxt, doc); - if (ret == 0) { - doc->extSubset = oldExt; - doc->intSubset = oldInt; - return(ret); - } if (doc->ids != NULL) { - xmlFreeIDTable(doc->ids); - doc->ids = NULL; + xmlFreeIDTable(doc->ids); + doc->ids = NULL; } if (doc->refs != NULL) { - xmlFreeRefTable(doc->refs); - doc->refs = NULL; + xmlFreeRefTable(doc->refs); + doc->refs = NULL; } - root = xmlDocGetRootElement(doc); - ret = xmlValidateElement(ctxt, doc, root); - ret &= xmlValidateDocumentFinal(ctxt, doc); + + ret = xmlValidateRoot(ctxt, doc); + if (ret != 0) { + root = xmlDocGetRootElement(doc); + ret = xmlValidateElement(ctxt, doc, root); + ret &= xmlValidateDocumentFinal(ctxt, doc); + } + doc->extSubset = oldExt; doc->intSubset = oldInt; + if (doc->ids != NULL) { + xmlFreeIDTable(doc->ids); + doc->ids = NULL; + } + if (doc->refs != NULL) { + xmlFreeRefTable(doc->refs); + doc->refs = NULL; + } + return(ret); }
@@ -6614,6 +6576,9 @@ xmlValidateAttributeCallback(void *payload, void *data, } } if (cur->atype == XML_ATTRIBUTE_NOTATION) { + const xmlChar *elemLocalName; + xmlChar *elemPrefix; + doc = cur->doc; if (cur->elem == NULL) { xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, @@ -6622,13 +6587,25 @@ xmlValidateAttributeCallback(void *payload, void *data, return; }
- if (doc != NULL) - elem = xmlGetDtdElementDesc(doc->intSubset, cur->elem); - if ((elem == NULL) && (doc != NULL)) - elem = xmlGetDtdElementDesc(doc->extSubset, cur->elem); + elemLocalName = xmlSplitQName4(cur->elem, &elemPrefix); + if (elemLocalName == NULL) { + xmlVErrMemory(ctxt); + return; + } + + if ((doc != NULL) && (doc->intSubset != NULL)) + elem = xmlHashLookup2(doc->intSubset->elements, + elemLocalName, elemPrefix); + if ((elem == NULL) && (doc != NULL) && (doc->extSubset != NULL)) + elem = xmlHashLookup2(doc->extSubset->elements, + elemLocalName, elemPrefix); if ((elem == NULL) && (cur->parent != NULL) && (cur->parent->type == XML_DTD_NODE)) - elem = xmlGetDtdElementDesc((xmlDtdPtr) cur->parent, cur->elem); + elem = xmlHashLookup2(((xmlDtdPtr) cur->parent)->elements, + elemLocalName, elemPrefix); + + xmlFree(elemPrefix); + if (elem == NULL) { xmlErrValidNode(ctxt, NULL, XML_DTD_UNKNOWN_ELEM, "attribute %s: could not find decl for element %s\n", @@ -6649,6 +6626,8 @@ xmlValidateAttributeCallback(void *payload, void *data, * @ctxt: the validation context * @doc: a document instance * + * DEPRECATED: Internal function, don't use. + * * Does the final step for the dtds validation once all the * subsets have been parsed * diff --git a/libs/xml2/xinclude.c b/libs/xml2/xinclude.c index b6581558d93..6c1e3ace64f 100644 --- a/libs/xml2/xinclude.c +++ b/libs/xml2/xinclude.c @@ -49,11 +49,11 @@ typedef xmlXIncludeRef *xmlXIncludeRefPtr; struct _xmlXIncludeRef { xmlChar *URI; /* the fully resolved resource URL */ xmlChar *fragment; /* the fragment in the URI */ + xmlChar *base; /* base URI of xi:include element */ xmlNodePtr elem; /* the xi:include element */ xmlNodePtr inc; /* the included copy */ int xml; /* xml or txt */ int fallback; /* fallback was loaded */ - int emptyFb; /* flag to show fallback empty */ int expanding; /* flag to detect inclusion loops */ int replace; /* should the node be replaced? */ }; @@ -89,9 +89,9 @@ struct _xmlXIncludeCtxt {
int nbErrors; /* the number of errors detected */ int fatalErr; /* abort processing */ + int errNo; /* error code */ int legacy; /* using XINCLUDE_OLD_NS */ int parseFlags; /* the flags used for parsing XML documents */ - xmlChar * base; /* the current xml:base */
void *_private; /* application data */
@@ -100,6 +100,11 @@ struct _xmlXIncludeCtxt { #endif int depth; /* recursion depth */ int isStream; /* streaming mode */ + + xmlXPathContextPtr xpctxt; + + xmlStructuredErrorFunc errorHandler; + void *errorCtxt; };
static xmlXIncludeRefPtr @@ -125,15 +130,14 @@ xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlNodePtr tree); * Handle an out of memory condition */ static void -xmlXIncludeErrMemory(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node, - const char *extra) +xmlXIncludeErrMemory(xmlXIncludeCtxtPtr ctxt) { - if (ctxt != NULL) - ctxt->nbErrors++; - __xmlRaiseError(NULL, NULL, NULL, ctxt, node, XML_FROM_XINCLUDE, - XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0, - extra, NULL, NULL, 0, 0, - "Memory allocation failed : %s\n", extra); + ctxt->errNo = XML_ERR_NO_MEMORY; + ctxt->fatalErr = 1; + ctxt->nbErrors++; + + xmlRaiseMemoryError(ctxt->errorHandler, NULL, ctxt->errorCtxt, + XML_FROM_XINCLUDE, NULL); }
/** @@ -149,34 +153,34 @@ static void LIBXML_ATTR_FORMAT(4,0) xmlXIncludeErr(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node, int error, const char *msg, const xmlChar *extra) { - if (ctxt != NULL) - ctxt->nbErrors++; - __xmlRaiseError(NULL, NULL, NULL, ctxt, node, XML_FROM_XINCLUDE, - error, XML_ERR_ERROR, NULL, 0, - (const char *) extra, NULL, NULL, 0, 0, - msg, (const char *) extra); -} + xmlStructuredErrorFunc schannel = NULL; + xmlGenericErrorFunc channel = NULL; + void *data = NULL; + int res;
-#if 0 -/** - * xmlXIncludeWarn: - * @ctxt: the XInclude context - * @node: the context node - * @msg: the error message - * @extra: extra information - * - * Emit an XInclude warning. - */ -static void LIBXML_ATTR_FORMAT(4,0) -xmlXIncludeWarn(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node, int error, - const char *msg, const xmlChar *extra) -{ - __xmlRaiseError(NULL, NULL, NULL, ctxt, node, XML_FROM_XINCLUDE, - error, XML_ERR_WARNING, NULL, 0, - (const char *) extra, NULL, NULL, 0, 0, - msg, (const char *) extra); + if (ctxt->fatalErr != 0) + return; + ctxt->nbErrors++; + + schannel = ctxt->errorHandler; + data = ctxt->errorCtxt; + + if (schannel == NULL) { + channel = xmlGenericError; + data = xmlGenericErrorContext; + } + + res = __xmlRaiseError(schannel, channel, data, ctxt, node, + XML_FROM_XINCLUDE, error, XML_ERR_ERROR, + NULL, 0, (const char *) extra, NULL, NULL, 0, 0, + msg, (const char *) extra); + if (res < 0) { + ctxt->errNo = XML_ERR_NO_MEMORY; + ctxt->fatalErr = 1; + } else { + ctxt->errNo = error; + } } -#endif
/** * xmlXIncludeGetProp: @@ -193,15 +197,20 @@ xmlXIncludeGetProp(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur, const xmlChar *name) { xmlChar *ret;
- ret = xmlGetNsProp(cur, XINCLUDE_NS, name); + if (xmlNodeGetAttrValue(cur, name, XINCLUDE_NS, &ret) < 0) + xmlXIncludeErrMemory(ctxt); if (ret != NULL) return(ret); + if (ctxt->legacy != 0) { - ret = xmlGetNsProp(cur, XINCLUDE_OLD_NS, name); - if (ret != NULL) - return(ret); + if (xmlNodeGetAttrValue(cur, name, XINCLUDE_OLD_NS, &ret) < 0) + xmlXIncludeErrMemory(ctxt); + if (ret != NULL) + return(ret); } - ret = xmlGetProp(cur, name); + + if (xmlNodeGetAttrValue(cur, name, NULL, &ret) < 0) + xmlXIncludeErrMemory(ctxt); return(ret); } /** @@ -218,60 +227,11 @@ xmlXIncludeFreeRef(xmlXIncludeRefPtr ref) { xmlFree(ref->URI); if (ref->fragment != NULL) xmlFree(ref->fragment); + if (ref->base != NULL) + xmlFree(ref->base); xmlFree(ref); }
-/** - * xmlXIncludeNewRef: - * @ctxt: the XInclude context - * @URI: the resource URI - * @elem: the xi:include element - * - * Creates a new reference within an XInclude context - * - * Returns the new set - */ -static xmlXIncludeRefPtr -xmlXIncludeNewRef(xmlXIncludeCtxtPtr ctxt, const xmlChar *URI, - xmlNodePtr elem) { - xmlXIncludeRefPtr ret; - - ret = (xmlXIncludeRefPtr) xmlMalloc(sizeof(xmlXIncludeRef)); - if (ret == NULL) { - xmlXIncludeErrMemory(ctxt, elem, "growing XInclude context"); - return(NULL); - } - memset(ret, 0, sizeof(xmlXIncludeRef)); - if (URI == NULL) - ret->URI = NULL; - else - ret->URI = xmlStrdup(URI); - ret->fragment = NULL; - ret->elem = elem; - ret->xml = 0; - ret->inc = NULL; - if (ctxt->incNr >= ctxt->incMax) { - xmlXIncludeRefPtr *tmp; -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - size_t newSize = ctxt->incMax ? ctxt->incMax * 2 : 1; -#else - size_t newSize = ctxt->incMax ? ctxt->incMax * 2 : 4; -#endif - - tmp = (xmlXIncludeRefPtr *) xmlRealloc(ctxt->incTab, - newSize * sizeof(ctxt->incTab[0])); - if (tmp == NULL) { - xmlXIncludeErrMemory(ctxt, elem, "growing XInclude context"); - xmlXIncludeFreeRef(ret); - return(NULL); - } - ctxt->incTab = tmp; - ctxt->incMax = newSize; - } - ctxt->incTab[ctxt->incNr++] = ret; - return(ret); -} - /** * xmlXIncludeNewContext: * @doc: an XML Document @@ -287,11 +247,8 @@ xmlXIncludeNewContext(xmlDocPtr doc) { if (doc == NULL) return(NULL); ret = (xmlXIncludeCtxtPtr) xmlMalloc(sizeof(xmlXIncludeCtxt)); - if (ret == NULL) { - xmlXIncludeErrMemory(NULL, (xmlNodePtr) doc, - "creating XInclude context"); + if (ret == NULL) return(NULL); - } memset(ret, 0, sizeof(xmlXIncludeCtxt)); ret->doc = doc; ret->incNr = 0; @@ -333,9 +290,8 @@ xmlXIncludeFreeContext(xmlXIncludeCtxtPtr ctxt) { } xmlFree(ctxt->txtTab); } - if (ctxt->base != NULL) { - xmlFree(ctxt->base); - } + if (ctxt->xpctxt != NULL) + xmlXPathFreeContext(ctxt->xpctxt); xmlFree(ctxt); }
@@ -348,7 +304,7 @@ xmlXIncludeFreeContext(xmlXIncludeCtxtPtr ctxt) { */ static xmlDocPtr xmlXIncludeParseFile(xmlXIncludeCtxtPtr ctxt, const char *URL) { - xmlDocPtr ret; + xmlDocPtr ret = NULL; xmlParserCtxtPtr pctxt; xmlParserInputPtr inputStream;
@@ -356,9 +312,11 @@ xmlXIncludeParseFile(xmlXIncludeCtxtPtr ctxt, const char *URL) {
pctxt = xmlNewParserCtxt(); if (pctxt == NULL) { - xmlXIncludeErrMemory(ctxt, NULL, "cannot allocate parser context"); + xmlXIncludeErrMemory(ctxt); return(NULL); } + if (ctxt->errorHandler != NULL) + xmlCtxtSetErrorHandler(pctxt, ctxt->errorHandler, ctxt->errorCtxt);
/* * pass in the application data to the parser context. @@ -376,25 +334,18 @@ xmlXIncludeParseFile(xmlXIncludeCtxtPtr ctxt, const char *URL) { xmlDictReference(pctxt->dict); }
+ /* + * We set DTDLOAD to make sure that ID attributes declared in + * external DTDs are detected. + */ xmlCtxtUseOptions(pctxt, ctxt->parseFlags | XML_PARSE_DTDLOAD);
- /* Don't read from stdin. */ - if ((URL != NULL) && (strcmp(URL, "-") == 0)) - URL = "./-"; - inputStream = xmlLoadExternalEntity(URL, NULL, pctxt); - if (inputStream == NULL) { - xmlFreeParserCtxt(pctxt); - return(NULL); - } + if (inputStream == NULL) + goto error;
inputPush(pctxt, inputStream);
- if (pctxt->directory == NULL) - pctxt->directory = xmlParserGetDirectory(URL); - - pctxt->loadsubset |= XML_DETECT_IDS; - xmlParseDocument(pctxt);
if (pctxt->wellFormed) { @@ -406,6 +357,10 @@ xmlXIncludeParseFile(xmlXIncludeCtxtPtr ctxt, const char *URL) { xmlFreeDoc(pctxt->myDoc); pctxt->myDoc = NULL; } + +error: + if (pctxt->errNo == XML_ERR_NO_MEMORY) + xmlXIncludeErrMemory(ctxt); xmlFreeParserCtxt(pctxt);
return(ret); @@ -420,17 +375,17 @@ xmlXIncludeParseFile(xmlXIncludeCtxtPtr ctxt, const char *URL) { */ static xmlXIncludeRefPtr xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur) { - xmlXIncludeRefPtr ref; - xmlURIPtr uri; - xmlChar *URL; + xmlXIncludeRefPtr ref = NULL; + xmlXIncludeRefPtr ret = NULL; + xmlURIPtr uri = NULL; + xmlChar *href = NULL; + xmlChar *parse = NULL; xmlChar *fragment = NULL; - xmlChar *href; - xmlChar *parse; - xmlChar *base; - xmlChar *URI; + xmlChar *base = NULL; + xmlChar *tmp; int xml = 1; int local = 0; - + int res;
if (ctxt == NULL) return(NULL); @@ -440,12 +395,24 @@ xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur) { /* * read the attributes */ + + fragment = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE_XPOINTER); + href = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_HREF); if (href == NULL) { + if (fragment == NULL) { + xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_NO_HREF, + "href or xpointer must be present\n", parse); + goto error; + } + href = xmlStrdup(BAD_CAST ""); /* @@@@ href is now optional */ - if (href == NULL) - return(NULL); + if (href == NULL) { + xmlXIncludeErrMemory(ctxt); + goto error; + } } + parse = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE); if (parse != NULL) { if (xmlStrEqual(parse, XINCLUDE_PARSE_XML)) @@ -455,61 +422,21 @@ xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur) { else { xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_PARSE_VALUE, "invalid value %s for 'parse'\n", parse); - if (href != NULL) - xmlFree(href); - if (parse != NULL) - xmlFree(parse); - return(NULL); + goto error; } }
- /* - * compute the URI - */ - base = xmlNodeGetBase(ctxt->doc, cur); - if (base == NULL) { - URI = xmlBuildURI(href, ctxt->doc->URL); - } else { - URI = xmlBuildURI(href, base); - } - if (URI == NULL) { - xmlChar *escbase; - xmlChar *eschref; - /* - * Some escaping may be needed - */ - escbase = xmlURIEscape(base); - eschref = xmlURIEscape(href); - URI = xmlBuildURI(eschref, escbase); - if (escbase != NULL) - xmlFree(escbase); - if (eschref != NULL) - xmlFree(eschref); - } - if (parse != NULL) - xmlFree(parse); - if (href != NULL) - xmlFree(href); - if (base != NULL) - xmlFree(base); - if (URI == NULL) { - xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI, - "failed build URL\n", NULL); - return(NULL); - } - fragment = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE_XPOINTER); - /* * Check the URL and remove any fragment identifier */ - uri = xmlParseURI((const char *)URI); + res = xmlParseURISafe((const char *)href, &uri); if (uri == NULL) { - xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI, - "invalid value URI %s\n", URI); - if (fragment != NULL) - xmlFree(fragment); - xmlFree(URI); - return(NULL); + if (res < 0) + xmlXIncludeErrMemory(ctxt); + else + xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI, + "invalid value href %s\n", href); + goto error; }
if (uri->fragment != NULL) { @@ -522,29 +449,46 @@ xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur) { } else { xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_FRAGMENT_ID, "Invalid fragment identifier in URI %s use the xpointer attribute\n", - URI); - if (fragment != NULL) - xmlFree(fragment); - xmlFreeURI(uri); - xmlFree(URI); - return(NULL); + href); + goto error; } uri->fragment = NULL; } - URL = xmlSaveUri(uri); - xmlFreeURI(uri); - if (URL == NULL) { - xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI, - "invalid value URI %s\n", URI); - if (fragment != NULL) - xmlFree(fragment); - xmlFree(URI); - return(NULL); + tmp = xmlSaveUri(uri); + if (tmp == NULL) { + xmlXIncludeErrMemory(ctxt); + goto error; } - xmlFree(URI); + xmlFree(href); + href = tmp;
- if (xmlStrEqual(URL, ctxt->doc->URL)) - local = 1; + /* + * Resolve URI + */ + + if (xmlNodeGetBaseSafe(ctxt->doc, cur, &base) < 0) { + xmlXIncludeErrMemory(ctxt); + goto error; + } + + if (href[0] != 0) { + if (xmlBuildURISafe(href, base, &tmp) < 0) { + xmlXIncludeErrMemory(ctxt); + goto error; + } + if (tmp == NULL) { + xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI, + "failed build URL\n", NULL); + goto error; + } + xmlFree(href); + href = tmp; + + if (xmlStrEqual(href, ctxt->doc->URL)) + local = 1; + } else { + local = 1; + }
/* * If local and xml then we need a fragment @@ -553,21 +497,72 @@ xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur) { ((fragment == NULL) || (fragment[0] == 0))) { xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_RECURSION, "detected a local recursion with no xpointer in %s\n", - URL); - xmlFree(URL); - xmlFree(fragment); - return(NULL); + href); + goto error; }
- ref = xmlXIncludeNewRef(ctxt, URL, cur); - xmlFree(URL); + ref = (xmlXIncludeRefPtr) xmlMalloc(sizeof(xmlXIncludeRef)); if (ref == NULL) { - xmlFree(fragment); - return(NULL); + xmlXIncludeErrMemory(ctxt); + goto error; } - ref->fragment = fragment; + memset(ref, 0, sizeof(xmlXIncludeRef)); + + ref->elem = cur; ref->xml = xml; - return(ref); + ref->URI = href; + href = NULL; + ref->fragment = fragment; + fragment = NULL; + + /* + * xml:base fixup + */ + if (((ctxt->parseFlags & XML_PARSE_NOBASEFIX) == 0) && + (cur->doc != NULL) && + ((cur->doc->parseFlags & XML_PARSE_NOBASEFIX) == 0)) { + if (base != NULL) { + ref->base = base; + base = NULL; + } else { + ref->base = xmlStrdup(BAD_CAST ""); + if (ref->base == NULL) { + xmlXIncludeErrMemory(ctxt); + goto error; + } + } + } + + if (ctxt->incNr >= ctxt->incMax) { + xmlXIncludeRefPtr *table; +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + size_t newSize = ctxt->incMax ? ctxt->incMax * 2 : 1; +#else + size_t newSize = ctxt->incMax ? ctxt->incMax * 2 : 4; +#endif + + table = (xmlXIncludeRefPtr *) xmlRealloc(ctxt->incTab, + newSize * sizeof(ctxt->incTab[0])); + if (table == NULL) { + xmlXIncludeErrMemory(ctxt); + goto error; + } + ctxt->incTab = table; + ctxt->incMax = newSize; + } + ctxt->incTab[ctxt->incNr++] = ref; + + ret = ref; + ref = NULL; + +error: + xmlXIncludeFreeRef(ref); + xmlFreeURI(uri); + xmlFree(href); + xmlFree(parse); + xmlFree(fragment); + xmlFree(base); + return(ret); }
/** @@ -579,8 +574,7 @@ xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur) { * The XInclude recursive nature is handled at this point. */ static void -xmlXIncludeRecurseDoc(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, - const xmlURL url ATTRIBUTE_UNUSED) { +xmlXIncludeRecurseDoc(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc) { xmlDocPtr oldDoc; xmlXIncludeRefPtr *oldIncTab; int oldIncMax, oldIncNr, oldIsStream; @@ -618,6 +612,56 @@ xmlXIncludeRecurseDoc(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, * * ************************************************************************/
+static void +xmlXIncludeBaseFixup(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur, xmlNodePtr copy, + const xmlChar *targetBase) { + xmlChar *base = NULL; + xmlChar *relBase = NULL; + xmlNs ns; + int res; + + if (cur->type != XML_ELEMENT_NODE) + return; + + if (xmlNodeGetBaseSafe(cur->doc, cur, &base) < 0) + xmlXIncludeErrMemory(ctxt); + + if ((base != NULL) && !xmlStrEqual(base, targetBase)) { + if (xmlBuildRelativeURISafe(base, targetBase, &relBase) < 0) { + xmlXIncludeErrMemory(ctxt); + goto done; + } + if (relBase == NULL) { + xmlXIncludeErr(ctxt, cur, + XML_XINCLUDE_HREF_URI, + "Building relative URI failed: %s\n", + base); + goto done; + } + + /* + * If the new base doesn't contain a slash, it can be omitted. + */ + if (xmlStrchr(relBase, '/') != NULL) { + res = xmlNodeSetBase(copy, relBase); + if (res < 0) + xmlXIncludeErrMemory(ctxt); + goto done; + } + } + + /* + * Delete existing xml:base if bases are equal + */ + memset(&ns, 0, sizeof(ns)); + ns.href = XML_XML_NAMESPACE; + xmlUnsetNsProp(copy, &ns, BAD_CAST "base"); + +done: + xmlFree(base); + xmlFree(relBase); +} + /** * xmlXIncludeCopyNode: * @ctxt: the XInclude context @@ -630,11 +674,13 @@ xmlXIncludeRecurseDoc(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, */ static xmlNodePtr xmlXIncludeCopyNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr elem, - int copyChildren) { + int copyChildren, const xmlChar *targetBase) { xmlNodePtr result = NULL; xmlNodePtr insertParent = NULL; xmlNodePtr insertLast = NULL; xmlNodePtr cur; + xmlNodePtr item; + int depth = 0;
if (copyChildren) { cur = elem->children; @@ -663,22 +709,33 @@ xmlXIncludeCopyNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr elem, /* * TODO: Insert XML_XINCLUDE_START and XML_XINCLUDE_END nodes */ - if (ref->inc != NULL) { - copy = xmlStaticCopyNodeList(ref->inc, ctxt->doc, - insertParent); - if (copy == NULL) + for (item = ref->inc; item != NULL; item = item->next) { + copy = xmlStaticCopyNode(item, ctxt->doc, insertParent, 1); + if (copy == NULL) { + xmlXIncludeErrMemory(ctxt); goto error; + } + + if (result == NULL) + result = copy; + if (insertLast != NULL) { + insertLast->next = copy; + copy->prev = insertLast; + } else if (insertParent != NULL) { + insertParent->children = copy; + } + insertLast = copy; + + if ((depth == 0) && (targetBase != NULL)) + xmlXIncludeBaseFixup(ctxt, item, copy, targetBase); } } else { copy = xmlStaticCopyNode(cur, ctxt->doc, insertParent, 2); - if (copy == NULL) + if (copy == NULL) { + xmlXIncludeErrMemory(ctxt); goto error; + }
- recurse = (cur->type != XML_ENTITY_REF_NODE) && - (cur->children != NULL); - } - - if (copy != NULL) { if (result == NULL) result = copy; if (insertLast != NULL) { @@ -688,15 +745,19 @@ xmlXIncludeCopyNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr elem, insertParent->children = copy; } insertLast = copy; - while (insertLast->next != NULL) { - insertLast = insertLast->next; - } + + if ((depth == 0) && (targetBase != NULL)) + xmlXIncludeBaseFixup(ctxt, cur, copy, targetBase); + + recurse = (cur->type != XML_ENTITY_REF_NODE) && + (cur->children != NULL); }
if (recurse) { cur = cur->children; insertParent = insertLast; insertLast = NULL; + depth += 1; continue; }
@@ -711,6 +772,7 @@ xmlXIncludeCopyNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr elem, return(result); insertLast = insertParent; insertParent = insertParent->parent; + depth -= 1; }
cur = cur->next; @@ -959,6 +1021,7 @@ xmlXIncludeCopyRange(xmlXIncludeCtxtPtr ctxt, xmlXPathObjectPtr range) { } #endif /* LIBXML_XPTR_LOCS_ENABLED */
+#ifdef LIBXML_XPTR_ENABLED /** * xmlXIncludeCopyXPointer: * @ctxt: the XInclude context @@ -971,7 +1034,8 @@ xmlXIncludeCopyRange(xmlXIncludeCtxtPtr ctxt, xmlXPathObjectPtr range) { * the caller has to free the node tree. */ static xmlNodePtr -xmlXIncludeCopyXPointer(xmlXIncludeCtxtPtr ctxt, xmlXPathObjectPtr obj) { +xmlXIncludeCopyXPointer(xmlXIncludeCtxtPtr ctxt, xmlXPathObjectPtr obj, + const xmlChar *targetBase) { xmlNodePtr list = NULL, last = NULL, copy; int i;
@@ -981,7 +1045,7 @@ xmlXIncludeCopyXPointer(xmlXIncludeCtxtPtr ctxt, xmlXPathObjectPtr obj) { case XPATH_NODESET: { xmlNodeSetPtr set = obj->nodesetval; if (set == NULL) - return(NULL); + break; for (i = 0;i < set->nodeNr;i++) { xmlNodePtr node;
@@ -995,11 +1059,11 @@ xmlXIncludeCopyXPointer(xmlXIncludeCtxtPtr ctxt, xmlXPathObjectPtr obj) { if (node == NULL) { xmlXIncludeErr(ctxt, set->nodeTab[i], XML_ERR_INTERNAL_ERROR, - "document without root\n", NULL); + "document without root\n", NULL); continue; } break; - case XML_TEXT_NODE: + case XML_TEXT_NODE: case XML_CDATA_SECTION_NODE: case XML_ELEMENT_NODE: case XML_PI_NODE: @@ -1019,7 +1083,7 @@ xmlXIncludeCopyXPointer(xmlXIncludeCtxtPtr ctxt, xmlXPathObjectPtr obj) { * xmlXIncludeCopyNode is only required for the initial * document. */ - copy = xmlXIncludeCopyNode(ctxt, node, 0); + copy = xmlXIncludeCopyNode(ctxt, node, 0, targetBase); if (copy == NULL) { xmlFreeNodeList(list); return(NULL); @@ -1044,10 +1108,12 @@ xmlXIncludeCopyXPointer(xmlXIncludeCtxtPtr ctxt, xmlXPathObjectPtr obj) { for (i = 0;i < set->locNr;i++) { if (last == NULL) list = last = xmlXIncludeCopyXPointer(ctxt, - set->locTab[i]); + set->locTab[i], + targetBase); else xmlAddNextSibling(last, - xmlXIncludeCopyXPointer(ctxt, set->locTab[i])); + xmlXIncludeCopyXPointer(ctxt, set->locTab[i], + targetBase)); if (last != NULL) { while (last->next != NULL) last = last->next; @@ -1066,6 +1132,8 @@ xmlXIncludeCopyXPointer(xmlXIncludeCtxtPtr ctxt, xmlXPathObjectPtr obj) { } return(list); } +#endif + /************************************************************************ * * * XInclude I/O handling * @@ -1112,32 +1180,36 @@ xmlXIncludeMergeEntity(void *payload, void *vdata, case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY: break; } - ret = xmlAddDocEntity(doc, ent->name, ent->etype, ent->ExternalID, - ent->SystemID, ent->content); - if (ret != NULL) { - if (ent->URI != NULL) + prev = xmlGetDocEntity(doc, ent->name); + if (prev == NULL) { + ret = xmlAddDocEntity(doc, ent->name, ent->etype, ent->ExternalID, + ent->SystemID, ent->content); + if (ret == NULL) { + xmlXIncludeErrMemory(ctxt); + return; + } + if (ent->URI != NULL) { ret->URI = xmlStrdup(ent->URI); + if (ret->URI == 0) + xmlXIncludeErrMemory(ctxt); + } } else { - prev = xmlGetDocEntity(doc, ent->name); - if (prev != NULL) { - if (ent->etype != prev->etype) - goto error; - - if ((ent->SystemID != NULL) && (prev->SystemID != NULL)) { - if (!xmlStrEqual(ent->SystemID, prev->SystemID)) - goto error; - } else if ((ent->ExternalID != NULL) && - (prev->ExternalID != NULL)) { - if (!xmlStrEqual(ent->ExternalID, prev->ExternalID)) - goto error; - } else if ((ent->content != NULL) && (prev->content != NULL)) { - if (!xmlStrEqual(ent->content, prev->content)) - goto error; - } else { - goto error; - } + if (ent->etype != prev->etype) + goto error;
- } + if ((ent->SystemID != NULL) && (prev->SystemID != NULL)) { + if (!xmlStrEqual(ent->SystemID, prev->SystemID)) + goto error; + } else if ((ent->ExternalID != NULL) && + (prev->ExternalID != NULL)) { + if (!xmlStrEqual(ent->ExternalID, prev->ExternalID)) + goto error; + } else if ((ent->content != NULL) && (prev->content != NULL)) { + if (!xmlStrEqual(ent->content, prev->content)) + goto error; + } else { + goto error; + } } return; error: @@ -1184,8 +1256,10 @@ xmlXIncludeMergeEntities(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, if (cur == NULL) return(-1); target = xmlCreateIntSubset(doc, cur->name, NULL, NULL); - if (target == NULL) + if (target == NULL) { + xmlXIncludeErrMemory(ctxt); return(-1); + } }
source = from->intSubset; @@ -1228,13 +1302,11 @@ xmlXIncludeMergeEntities(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, * Returns 0 in case of success, -1 in case of failure */ static int -xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, - xmlXIncludeRefPtr ref) { +xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, xmlXIncludeRefPtr ref) { xmlXIncludeDocPtr cache; xmlDocPtr doc; - xmlURIPtr uri; - xmlChar *URL = NULL; - xmlChar *fragment = NULL; + const xmlChar *url = ref->URI; + const xmlChar *fragment = ref->fragment; int i = 0; int ret = -1; int cacheNr; @@ -1242,37 +1314,12 @@ xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int saveFlags; #endif
- /* - * Check the URL and remove any fragment identifier - */ - uri = xmlParseURI((const char *)url); - if (uri == NULL) { - xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_HREF_URI, - "invalid value URI %s\n", url); - goto error; - } - if (uri->fragment != NULL) { - fragment = (xmlChar *) uri->fragment; - uri->fragment = NULL; - } - if (ref->fragment != NULL) { - if (fragment != NULL) xmlFree(fragment); - fragment = xmlStrdup(ref->fragment); - } - URL = xmlSaveUri(uri); - xmlFreeURI(uri); - if (URL == NULL) { - xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_HREF_URI, - "invalid value URI %s\n", url); - goto error; - } - /* * Handling of references to the local document are done * directly through ctxt->doc. */ - if ((URL[0] == 0) || (URL[0] == '#') || - ((ctxt->doc != NULL) && (xmlStrEqual(URL, ctxt->doc->URL)))) { + if ((url[0] == 0) || (url[0] == '#') || + ((ctxt->doc != NULL) && (xmlStrEqual(url, ctxt->doc->URL)))) { doc = ctxt->doc; goto loaded; } @@ -1281,7 +1328,7 @@ xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, * Prevent reloading the document twice. */ for (i = 0; i < ctxt->urlNr; i++) { - if (xmlStrEqual(URL, ctxt->urlTab[i].url)) { + if (xmlStrEqual(url, ctxt->urlTab[i].url)) { if (ctxt->urlTab[i].expanding) { xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_RECURSION, "inclusion loop detected\n", NULL); @@ -1309,7 +1356,7 @@ xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, } #endif
- doc = xmlXIncludeParseFile(ctxt, (const char *)URL); + doc = xmlXIncludeParseFile(ctxt, (const char *)url); #ifdef LIBXML_XPTR_ENABLED ctxt->parseFlags = saveFlags; #endif @@ -1325,19 +1372,23 @@ xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url,
tmp = xmlRealloc(ctxt->urlTab, sizeof(xmlXIncludeDoc) * newSize); if (tmp == NULL) { - xmlXIncludeErrMemory(ctxt, ref->elem, - "growing XInclude URL table"); + xmlXIncludeErrMemory(ctxt); xmlFreeDoc(doc); goto error; } ctxt->urlMax = newSize; ctxt->urlTab = tmp; } - cacheNr = ctxt->urlNr++; - cache = &ctxt->urlTab[cacheNr]; + cache = &ctxt->urlTab[ctxt->urlNr]; cache->doc = doc; - cache->url = xmlStrdup(URL); + cache->url = xmlStrdup(url); + if (cache->url == NULL) { + xmlXIncludeErrMemory(ctxt); + xmlFreeDoc(doc); + goto error; + } cache->expanding = 0; + cacheNr = ctxt->urlNr++;
if (doc == NULL) goto error; @@ -1347,10 +1398,8 @@ xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, * To check for this, we compare the URL with that of the doc * and change it if they disagree (bug 146988). */ - if (!xmlStrEqual(URL, doc->URL)) { - xmlFree(URL); - URL = xmlStrdup(doc->URL); - } + if ((doc->URL != NULL) && (!xmlStrEqual(url, doc->URL))) + url = doc->URL;
/* * Make sure we have all entities fixed up @@ -1371,17 +1420,30 @@ xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, } */ cache->expanding = 1; - xmlXIncludeRecurseDoc(ctxt, doc, URL); + xmlXIncludeRecurseDoc(ctxt, doc); /* urlTab might be reallocated. */ cache = &ctxt->urlTab[cacheNr]; cache->expanding = 0;
loaded: if (fragment == NULL) { - /* - * Add the top children list as the replacement copy. - */ - ref->inc = xmlDocCopyNode(xmlDocGetRootElement(doc), ctxt->doc, 1); + xmlNodePtr root; + + root = xmlDocGetRootElement(doc); + if (root == NULL) { + xmlXIncludeErr(ctxt, ref->elem, XML_ERR_INTERNAL_ERROR, + "document without root\n", NULL); + goto error; + } + + ref->inc = xmlDocCopyNode(root, ctxt->doc, 1); + if (ref->inc == NULL) { + xmlXIncludeErrMemory(ctxt); + goto error; + } + + if (ref->base != NULL) + xmlXIncludeBaseFixup(ctxt, root, ref->inc, ref->base); } #ifdef LIBXML_XPTR_ENABLED else { @@ -1390,7 +1452,6 @@ loaded: * as the replacement copy. */ xmlXPathObjectPtr xptr; - xmlXPathContextPtr xptrctxt; xmlNodeSetPtr set;
if (ctxt->isStream && doc == ctxt->doc) { @@ -1400,20 +1461,33 @@ loaded: goto error; }
- xptrctxt = xmlXPtrNewContext(doc, NULL, NULL); - if (xptrctxt == NULL) { - xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_XPTR_FAILED, - "could not create XPointer context\n", NULL); - goto error; - } - xptr = xmlXPtrEval(fragment, xptrctxt); - if (xptr == NULL) { - xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_XPTR_FAILED, - "XPointer evaluation failed: #%s\n", - fragment); - xmlXPathFreeContext(xptrctxt); + if (ctxt->xpctxt == NULL) { + ctxt->xpctxt = xmlXPtrNewContext(doc, NULL, NULL); + if (ctxt->xpctxt == NULL) { + xmlXIncludeErrMemory(ctxt); + goto error; + } + if (ctxt->errorHandler != NULL) + xmlXPathSetErrorHandler(ctxt->xpctxt, ctxt->errorHandler, + ctxt->errorCtxt); +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + ctxt->xpctxt->opLimit = 100000; +#endif + } else { + ctxt->xpctxt->doc = doc; + } + xptr = xmlXPtrEval(fragment, ctxt->xpctxt); + if (ctxt->xpctxt->lastError.code != XML_ERR_OK) { + if (ctxt->xpctxt->lastError.code == XML_ERR_NO_MEMORY) + xmlXIncludeErrMemory(ctxt); + else + xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_XPTR_FAILED, + "XPointer evaluation failed: #%s\n", + fragment); goto error; } + if (xptr == NULL) + goto done; switch (xptr->type) { case XPATH_UNDEFINED: case XPATH_BOOLEAN: @@ -1428,15 +1502,9 @@ loaded: "XPointer is not a range: #%s\n", fragment); xmlXPathFreeObject(xptr); - xmlXPathFreeContext(xptrctxt); goto error; case XPATH_NODESET: - if ((xptr->nodesetval == NULL) || - (xptr->nodesetval->nodeNr <= 0)) { - xmlXPathFreeObject(xptr); - xmlXPathFreeContext(xptrctxt); - goto error; - } + break;
#ifdef LIBXML_XPTR_LOCS_ENABLED case XPATH_RANGE: @@ -1494,106 +1562,21 @@ loaded: } } } - ref->inc = xmlXIncludeCopyXPointer(ctxt, xptr); + ref->inc = xmlXIncludeCopyXPointer(ctxt, xptr, ref->base); xmlXPathFreeObject(xptr); - xmlXPathFreeContext(xptrctxt); } #endif
- /* - * Do the xml:base fixup if needed - */ - if ((doc != NULL) && (URL != NULL) && - (!(ctxt->parseFlags & XML_PARSE_NOBASEFIX)) && - (!(doc->parseFlags & XML_PARSE_NOBASEFIX))) { - xmlNodePtr node; - xmlChar *base; - xmlChar *curBase; - - /* - * The base is only adjusted if "necessary", i.e. if the xinclude node - * has a base specified, or the URL is relative - */ - base = xmlGetNsProp(ref->elem, BAD_CAST "base", XML_XML_NAMESPACE); - if (base == NULL) { - /* - * No xml:base on the xinclude node, so we check whether the - * URI base is different than (relative to) the context base - */ - curBase = xmlBuildRelativeURI(URL, ctxt->base); - if (curBase == NULL) { /* Error return */ - xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_HREF_URI, - "trying to build relative URI from %s\n", URL); - } else { - /* If the URI doesn't contain a slash, it's not relative */ - if (!xmlStrchr(curBase, '/')) - xmlFree(curBase); - else - base = curBase; - } - } - if (base != NULL) { /* Adjustment may be needed */ - node = ref->inc; - while (node != NULL) { - /* Only work on element nodes */ - if (node->type == XML_ELEMENT_NODE) { - curBase = xmlNodeGetBase(node->doc, node); - /* If no current base, set it */ - if (curBase == NULL) { - xmlNodeSetBase(node, base); - } else { - /* - * If the current base is the same as the - * URL of the document, then reset it to be - * the specified xml:base or the relative URI - */ - if (xmlStrEqual(curBase, node->doc->URL)) { - xmlNodeSetBase(node, base); - } else { - /* - * If the element already has an xml:base - * set, then relativise it if necessary - */ - xmlChar *xmlBase; - xmlBase = xmlGetNsProp(node, - BAD_CAST "base", - XML_XML_NAMESPACE); - if (xmlBase != NULL) { - xmlChar *relBase; - relBase = xmlBuildURI(xmlBase, base); - if (relBase == NULL) { /* error */ - xmlXIncludeErr(ctxt, - ref->elem, - XML_XINCLUDE_HREF_URI, - "trying to rebuild base from %s\n", - xmlBase); - } else { - xmlNodeSetBase(node, relBase); - xmlFree(relBase); - } - xmlFree(xmlBase); - } - } - xmlFree(curBase); - } - } - node = node->next; - } - xmlFree(base); - } - } +done: ret = 0;
error: - xmlFree(URL); - xmlFree(fragment); return(ret); }
/** * xmlXIncludeLoadTxt: * @ctxt: the XInclude context - * @url: the associated URL * @ref: an XMLXincludeRefPtr * * Load the content, and store the result in the XInclude context @@ -1601,53 +1584,25 @@ error: * Returns 0 in case of success, -1 in case of failure */ static int -xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, - xmlXIncludeRefPtr ref) { +xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, xmlXIncludeRefPtr ref) { xmlParserInputBufferPtr buf; xmlNodePtr node = NULL; - xmlURIPtr uri = NULL; - xmlChar *URL = NULL; + const xmlChar *url = ref->URI; int i; int ret = -1; xmlChar *encoding = NULL; - xmlCharEncoding enc = (xmlCharEncoding) 0; + xmlCharEncodingHandlerPtr handler = NULL; xmlParserCtxtPtr pctxt = NULL; xmlParserInputPtr inputStream = NULL; int len; + int res; const xmlChar *content;
- - /* Don't read from stdin. */ - if (xmlStrcmp(url, BAD_CAST "-") == 0) - url = BAD_CAST "./-"; - - /* - * Check the URL and remove any fragment identifier - */ - uri = xmlParseURI((const char *)url); - if (uri == NULL) { - xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_HREF_URI, - "invalid value URI %s\n", url); - goto error; - } - if (uri->fragment != NULL) { - xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_TEXT_FRAGMENT, - "fragment identifier forbidden for text: %s\n", - (const xmlChar *) uri->fragment); - goto error; - } - URL = xmlSaveUri(uri); - if (URL == NULL) { - xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_HREF_URI, - "invalid value URI %s\n", url); - goto error; - } - /* * Handling of references to the local document are done * directly through ctxt->doc. */ - if (URL[0] == 0) { + if (url[0] == 0) { xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_TEXT_DOCUMENT, "text serialization of document not available\n", NULL); goto error; @@ -1657,8 +1612,10 @@ xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, * Prevent reloading the document twice. */ for (i = 0; i < ctxt->txtNr; i++) { - if (xmlStrEqual(URL, ctxt->txtTab[i].url)) { + if (xmlStrEqual(url, ctxt->txtTab[i].url)) { node = xmlNewDocText(ctxt->doc, ctxt->txtTab[i].text); + if (node == NULL) + xmlXIncludeErrMemory(ctxt); goto loaded; } } @@ -1667,47 +1624,77 @@ xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, * Try to get the encoding if available */ if (ref->elem != NULL) { - encoding = xmlGetProp(ref->elem, XINCLUDE_PARSE_ENCODING); + encoding = xmlXIncludeGetProp(ctxt, ref->elem, XINCLUDE_PARSE_ENCODING); } if (encoding != NULL) { - /* - * TODO: we should not have to remap to the xmlCharEncoding - * predefined set, a better interface than - * xmlParserInputBufferCreateFilename should allow any - * encoding supported by iconv - */ - enc = xmlParseCharEncoding((const char *) encoding); - if (enc == XML_CHAR_ENCODING_ERROR) { - xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_UNKNOWN_ENCODING, - "encoding %s not supported\n", encoding); - goto error; - } + res = xmlOpenCharEncodingHandler((const char *) encoding, + /* output */ 0, &handler); + + if (res != 0) { + if (res == XML_ERR_NO_MEMORY) { + xmlXIncludeErrMemory(ctxt); + } else if (res == XML_ERR_UNSUPPORTED_ENCODING) { + xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_UNKNOWN_ENCODING, + "encoding %s not supported\n", encoding); + goto error; + } else { + xmlXIncludeErr(ctxt, ref->elem, res, + "unexpected error from iconv or ICU\n", NULL); + goto error; + } + } }
/* * Load it. */ pctxt = xmlNewParserCtxt(); - inputStream = xmlLoadExternalEntity((const char*)URL, NULL, pctxt); - if(inputStream == NULL) + if (pctxt == NULL) { + xmlXIncludeErrMemory(ctxt); + goto error; + } + if (ctxt->errorHandler != NULL) + xmlCtxtSetErrorHandler(pctxt, ctxt->errorHandler, ctxt->errorCtxt); + inputStream = xmlLoadExternalEntity((const char*)url, NULL, pctxt); + if (inputStream == NULL) { + /* + * ENOENT only produces a warning which isn't reflected in errNo. + */ + if (pctxt->errNo == XML_ERR_NO_MEMORY) + xmlXIncludeErrMemory(ctxt); + else if ((pctxt->errNo != XML_ERR_OK) && + (pctxt->errNo != XML_IO_ENOENT) && + (pctxt->errNo != XML_IO_UNKNOWN)) + xmlXIncludeErr(ctxt, NULL, pctxt->errNo, "load error", NULL); goto error; + } buf = inputStream->buf; if (buf == NULL) goto error; if (buf->encoder) xmlCharEncCloseFunc(buf->encoder); - buf->encoder = xmlGetCharEncodingHandler(enc); + buf->encoder = handler; + handler = NULL; + node = xmlNewDocText(ctxt->doc, NULL); if (node == NULL) { - xmlXIncludeErrMemory(ctxt, ref->elem, NULL); + xmlXIncludeErrMemory(ctxt); goto error; }
/* * Scan all chars from the resource and add the to the node */ - while (xmlParserInputBufferRead(buf, 4096) > 0) - ; + do { + res = xmlParserInputBufferRead(buf, 4096); + } while (res > 0); + if (res < 0) { + if (buf->error == XML_ERR_NO_MEMORY) + xmlXIncludeErrMemory(ctxt); + else + xmlXIncludeErr(ctxt, NULL, buf->error, "read error", NULL); + goto error; + }
content = xmlBufContent(buf->buffer); len = xmlBufLength(buf->buffer); @@ -1719,14 +1706,15 @@ xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, cur = xmlGetUTF8Char(&content[i], &l); if ((cur < 0) || (!IS_CHAR(cur))) { xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_INVALID_CHAR, - "%s contains invalid char\n", URL); + "%s contains invalid char\n", url); goto error; }
i += l; }
- xmlNodeAddContentLen(node, content, len); + if (xmlNodeAddContentLen(node, content, len) < 0) + xmlXIncludeErrMemory(ctxt);
if (ctxt->txtNr >= ctxt->txtMax) { xmlXIncludeTxt *tmp; @@ -1738,15 +1726,24 @@ xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url,
tmp = xmlRealloc(ctxt->txtTab, sizeof(xmlXIncludeTxt) * newSize); if (tmp == NULL) { - xmlXIncludeErrMemory(ctxt, ref->elem, - "growing XInclude text table"); + xmlXIncludeErrMemory(ctxt); goto error; } ctxt->txtMax = newSize; ctxt->txtTab = tmp; } ctxt->txtTab[ctxt->txtNr].text = xmlStrdup(node->content); - ctxt->txtTab[ctxt->txtNr].url = xmlStrdup(URL); + if ((node->content != NULL) && + (ctxt->txtTab[ctxt->txtNr].text == NULL)) { + xmlXIncludeErrMemory(ctxt); + goto error; + } + ctxt->txtTab[ctxt->txtNr].url = xmlStrdup(url); + if (ctxt->txtTab[ctxt->txtNr].url == NULL) { + xmlXIncludeErrMemory(ctxt); + xmlFree(ctxt->txtTab[ctxt->txtNr].text); + goto error; + } ctxt->txtNr++;
loaded: @@ -1761,9 +1758,8 @@ error: xmlFreeNode(node); xmlFreeInputStream(inputStream); xmlFreeParserCtxt(pctxt); + xmlCharEncCloseFunc(handler); xmlFree(encoding); - xmlFreeURI(uri); - xmlFree(URL); return(ret); }
@@ -1793,14 +1789,11 @@ xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, * (Bug 129969), so we re-process the fallback just in case */ oldNbErrors = ctxt->nbErrors; - ref->inc = xmlXIncludeCopyNode(ctxt, fallback, 1); + ref->inc = xmlXIncludeCopyNode(ctxt, fallback, 1, ref->base); if (ctxt->nbErrors > oldNbErrors) ret = -1; - else if (ref->inc == NULL) - ref->emptyFb = 1; } else { ref->inc = NULL; - ref->emptyFb = 1; /* flag empty callback */ } ref->fallback = 1; return(ret); @@ -1896,12 +1889,6 @@ xmlXIncludeExpandNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) { static int xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, xmlXIncludeRefPtr ref) { xmlNodePtr cur; - xmlChar *href; - xmlChar *parse; - xmlChar *base; - xmlChar *oldBase; - xmlChar *URI; - int xml = 1; /* default Issue 64 */ int ret;
if ((ctxt == NULL) || (ref == NULL)) @@ -1910,85 +1897,13 @@ xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, xmlXIncludeRefPtr ref) { if (cur == NULL) return(-1);
- /* - * read the attributes - */ - href = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_HREF); - if (href == NULL) { - href = xmlStrdup(BAD_CAST ""); /* @@@@ href is now optional */ - if (href == NULL) - return(-1); - } - parse = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE); - if (parse != NULL) { - if (xmlStrEqual(parse, XINCLUDE_PARSE_XML)) - xml = 1; - else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT)) - xml = 0; - else { - xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_PARSE_VALUE, - "invalid value %s for 'parse'\n", parse); - if (href != NULL) - xmlFree(href); - if (parse != NULL) - xmlFree(parse); - return(-1); - } - } - - /* - * compute the URI - */ - base = xmlNodeGetBase(ctxt->doc, cur); - if (base == NULL) { - URI = xmlBuildURI(href, ctxt->doc->URL); - } else { - URI = xmlBuildURI(href, base); - } - if (URI == NULL) { - xmlChar *escbase; - xmlChar *eschref; - /* - * Some escaping may be needed - */ - escbase = xmlURIEscape(base); - eschref = xmlURIEscape(href); - URI = xmlBuildURI(eschref, escbase); - if (escbase != NULL) - xmlFree(escbase); - if (eschref != NULL) - xmlFree(eschref); - } - if (URI == NULL) { - xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI, - "failed build URL\n", NULL); - if (parse != NULL) - xmlFree(parse); - if (href != NULL) - xmlFree(href); - if (base != NULL) - xmlFree(base); - return(-1); - } - - /* - * Save the base for this include (saving the current one) - */ - oldBase = ctxt->base; - ctxt->base = base; - - if (xml) { - ret = xmlXIncludeLoadDoc(ctxt, URI, ref); + if (ref->xml) { + ret = xmlXIncludeLoadDoc(ctxt, ref); /* xmlXIncludeGetFragment(ctxt, cur, URI); */ } else { - ret = xmlXIncludeLoadTxt(ctxt, URI, ref); + ret = xmlXIncludeLoadTxt(ctxt, ref); }
- /* - * Restore the original base before checking for fallback - */ - ctxt->base = oldBase; - if (ret < 0) { xmlNodePtr children;
@@ -2011,20 +1926,9 @@ xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, xmlXIncludeRefPtr ref) { if (ret < 0) { xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_NO_FALLBACK, "could not load %s, and no fallback was found\n", - URI); + ref->URI); }
- /* - * Cleanup - */ - if (URI != NULL) - xmlFree(URI); - if (parse != NULL) - xmlFree(parse); - if (href != NULL) - xmlFree(href); - if (base != NULL) - xmlFree(base); return(0); }
@@ -2049,7 +1953,6 @@ xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, xmlXIncludeRefPtr ref) {
list = ref->inc; ref->inc = NULL; - ref->emptyFb = 0;
/* * Check against the risk of generating a multi-rooted document @@ -2076,16 +1979,19 @@ xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, xmlXIncludeRefPtr ref) { if (ctxt->parseFlags & XML_PARSE_NOXINCNODE) { /* * Add the list of nodes + * + * TODO: Coalesce text nodes unless we are streaming mode. */ while (list != NULL) { end = list; list = list->next;
- xmlAddPrevSibling(cur, end); + if (xmlAddPrevSibling(cur, end) == NULL) { + xmlUnlinkNode(end); + xmlFreeNode(end); + goto err_memory; + } } - /* - * FIXME: xmlUnlinkNode doesn't coalesce text nodes. - */ xmlUnlinkNode(cur); xmlFreeNode(cur); } else { @@ -2105,14 +2011,13 @@ xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, xmlXIncludeRefPtr ref) { xmlFreeNode(child); } end = xmlNewDocNode(cur->doc, cur->ns, cur->name, NULL); - if (end == NULL) { - xmlXIncludeErr(ctxt, ref->elem, XML_XINCLUDE_BUILD_FAILED, - "failed to build node\n", NULL); - xmlFreeNodeList(list); - return(-1); - } + if (end == NULL) + goto err_memory; end->type = XML_XINCLUDE_END; - xmlAddNextSibling(cur, end); + if (xmlAddNextSibling(cur, end) == NULL) { + xmlFreeNode(end); + goto err_memory; + }
/* * Add the list of nodes @@ -2121,12 +2026,21 @@ xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, xmlXIncludeRefPtr ref) { cur = list; list = list->next;
- xmlAddPrevSibling(end, cur); + if (xmlAddPrevSibling(end, cur) == NULL) { + xmlUnlinkNode(cur); + xmlFreeNode(cur); + goto err_memory; + } } }
return(0); + +err_memory: + xmlXIncludeErrMemory(ctxt); + xmlFreeNodeList(list); + return(-1); }
/** @@ -2222,11 +2136,6 @@ xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlNodePtr tree) { int ret = 0; int i, start;
- if ((tree == NULL) || (tree->type == XML_NAMESPACE_DECL)) - return(-1); - if (ctxt == NULL) - return(-1); - /* * First phase: lookup the elements in the document */ @@ -2263,10 +2172,7 @@ xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlNodePtr tree) { */ for (i = start; i < ctxt->incNr; i++) { if (ctxt->incTab[i]->replace != 0) { - if ((ctxt->incTab[i]->inc != NULL) || - (ctxt->incTab[i]->emptyFb != 0)) { /* (empty fallback) */ - xmlXIncludeIncludeNode(ctxt, ctxt->incTab[i]); - } + xmlXIncludeIncludeNode(ctxt, ctxt->incTab[i]); ctxt->incTab[i]->replace = 0; } else { /* @@ -2296,6 +2202,61 @@ xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlNodePtr tree) { return(ret); }
+/** + * xmlXIncludeDoProcessRoot: + * @ctxt: the XInclude processing context + * @tree: the top of the tree to process + * + * Implement the XInclude substitution on the XML document @doc + * + * Returns 0 if no substitution were done, -1 if some processing failed + * or the number of substitutions done. + */ +static int +xmlXIncludeDoProcessRoot(xmlXIncludeCtxtPtr ctxt, xmlNodePtr tree) { + if ((tree == NULL) || (tree->type == XML_NAMESPACE_DECL)) + return(-1); + if (ctxt == NULL) + return(-1); + + return(xmlXIncludeDoProcess(ctxt, tree)); +} + +/** + * xmlXIncludeGetLastError: + * @ctxt: an XInclude processing context + * + * Available since 2.13.0. + * + * Returns the last error code. + */ +int +xmlXIncludeGetLastError(xmlXIncludeCtxtPtr ctxt) { + if (ctxt == NULL) + return(XML_ERR_ARGUMENT); + return(ctxt->errNo); +} + +/** + * xmlXIncludeSetErrorHandler: + * @ctxt: an XInclude processing context + * @handler: error handler + * @data: user data which will be passed to the handler + * + * Register a callback function that will be called on errors and + * warnings. If handler is NULL, the error handler will be deactivated. + * + * Available since 2.13.0. + */ +void +xmlXIncludeSetErrorHandler(xmlXIncludeCtxtPtr ctxt, + xmlStructuredErrorFunc handler, void *data) { + if (ctxt == NULL) + return; + ctxt->errorHandler = handler; + ctxt->errorCtxt = data; +} + /** * xmlXIncludeSetFlags: * @ctxt: an XInclude processing context @@ -2356,9 +2317,8 @@ xmlXIncludeProcessTreeFlagsData(xmlNodePtr tree, int flags, void *data) { if (ctxt == NULL) return(-1); ctxt->_private = data; - ctxt->base = xmlStrdup((xmlChar *)tree->doc->URL); xmlXIncludeSetFlags(ctxt, flags); - ret = xmlXIncludeDoProcess(ctxt, tree); + ret = xmlXIncludeDoProcessRoot(ctxt, tree); if ((ret >= 0) && (ctxt->nbErrors > 0)) ret = -1;
@@ -2440,9 +2400,8 @@ xmlXIncludeProcessTreeFlags(xmlNodePtr tree, int flags) { ctxt = xmlXIncludeNewContext(tree->doc); if (ctxt == NULL) return(-1); - ctxt->base = xmlNodeGetBase(tree->doc, tree); xmlXIncludeSetFlags(ctxt, flags); - ret = xmlXIncludeDoProcess(ctxt, tree); + ret = xmlXIncludeDoProcessRoot(ctxt, tree); if ((ret >= 0) && (ctxt->nbErrors > 0)) ret = -1;
@@ -2482,7 +2441,7 @@ xmlXIncludeProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) { if ((node == NULL) || (node->type == XML_NAMESPACE_DECL) || (node->doc == NULL) || (ctxt == NULL)) return(-1); - ret = xmlXIncludeDoProcess(ctxt, node); + ret = xmlXIncludeDoProcessRoot(ctxt, node); if ((ret >= 0) && (ctxt->nbErrors > 0)) ret = -1; return(ret); diff --git a/libs/xml2/xmlIO.c b/libs/xml2/xmlIO.c index b601be6a209..6aea1b04e4d 100644 --- a/libs/xml2/xmlIO.c +++ b/libs/xml2/xmlIO.c @@ -4,8 +4,6 @@ * See Copyright for the status of this software. * * daniel@veillard.com - * - * 14 Nov 2000 ht - for VMS, truncated name of long functions to under 32 char */
#define IN_LIBXML @@ -38,22 +36,8 @@ #include <direct.h> #endif
-#ifndef S_ISDIR -# ifdef _S_ISDIR -# define S_ISDIR(x) _S_ISDIR(x) -# elif defined(S_IFDIR) -# ifdef S_IFMT -# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) -# elif defined(_S_IFMT) -# define S_ISDIR(m) (((m) & _S_IFMT) == S_IFDIR) -# endif -# endif -#endif - #include <libxml/xmlIO.h> #include <libxml/xmlmemory.h> -#include <libxml/parser.h> -#include <libxml/parserInternals.h> #include <libxml/uri.h> #include <libxml/nanohttp.h> #include <libxml/nanoftp.h> @@ -72,6 +56,22 @@
#define MINLEN 4000
+#ifndef STDOUT_FILENO + #define STDOUT_FILENO 1 +#endif + +#ifndef S_ISDIR +# ifdef _S_ISDIR +# define S_ISDIR(x) _S_ISDIR(x) +# elif defined(S_IFDIR) +# ifdef S_IFMT +# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +# elif defined(_S_IFMT) +# define S_ISDIR(m) (((m) & _S_IFMT) == S_IFDIR) +# endif +# endif +#endif + /* * Input I/O callback sets */ @@ -82,11 +82,14 @@ typedef struct _xmlInputCallback { xmlInputCloseCallback closecallback; } xmlInputCallback;
-#define MAX_INPUT_CALLBACK 15 +/* This dummy function only marks default IO in the callback table */ +static int +xmlIODefaultMatch(const char *filename); + +#define MAX_INPUT_CALLBACK 10
static xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK]; -static int xmlInputCallbackNr = 0; -static int xmlInputCallbackInitialized = 0; +static int xmlInputCallbackNr;
#ifdef LIBXML_OUTPUT_ENABLED /* @@ -99,112 +102,18 @@ typedef struct _xmlOutputCallback { xmlOutputCloseCallback closecallback; } xmlOutputCallback;
-#define MAX_OUTPUT_CALLBACK 15 +#define MAX_OUTPUT_CALLBACK 10
static xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK]; -static int xmlOutputCallbackNr = 0; -static int xmlOutputCallbackInitialized = 0; +static int xmlOutputCallbackNr; #endif /* LIBXML_OUTPUT_ENABLED */
/************************************************************************ * * - * Tree memory error handler * + * Error handling * * * ************************************************************************/
-static const char* const IOerr[] = { - "Unknown IO error", /* UNKNOWN */ - "Permission denied", /* EACCES */ - "Resource temporarily unavailable",/* EAGAIN */ - "Bad file descriptor", /* EBADF */ - "Bad message", /* EBADMSG */ - "Resource busy", /* EBUSY */ - "Operation canceled", /* ECANCELED */ - "No child processes", /* ECHILD */ - "Resource deadlock avoided",/* EDEADLK */ - "Domain error", /* EDOM */ - "File exists", /* EEXIST */ - "Bad address", /* EFAULT */ - "File too large", /* EFBIG */ - "Operation in progress", /* EINPROGRESS */ - "Interrupted function call",/* EINTR */ - "Invalid argument", /* EINVAL */ - "Input/output error", /* EIO */ - "Is a directory", /* EISDIR */ - "Too many open files", /* EMFILE */ - "Too many links", /* EMLINK */ - "Inappropriate message buffer length",/* EMSGSIZE */ - "Filename too long", /* ENAMETOOLONG */ - "Too many open files in system",/* ENFILE */ - "No such device", /* ENODEV */ - "No such file or directory",/* ENOENT */ - "Exec format error", /* ENOEXEC */ - "No locks available", /* ENOLCK */ - "Not enough space", /* ENOMEM */ - "No space left on device", /* ENOSPC */ - "Function not implemented", /* ENOSYS */ - "Not a directory", /* ENOTDIR */ - "Directory not empty", /* ENOTEMPTY */ - "Not supported", /* ENOTSUP */ - "Inappropriate I/O control operation",/* ENOTTY */ - "No such device or address",/* ENXIO */ - "Operation not permitted", /* EPERM */ - "Broken pipe", /* EPIPE */ - "Result too large", /* ERANGE */ - "Read-only file system", /* EROFS */ - "Invalid seek", /* ESPIPE */ - "No such process", /* ESRCH */ - "Operation timed out", /* ETIMEDOUT */ - "Improper link", /* EXDEV */ - "Attempt to load network entity %s", /* XML_IO_NETWORK_ATTEMPT */ - "encoder error", /* XML_IO_ENCODER */ - "flush error", - "write error", - "no input", - "buffer full", - "loading error", - "not a socket", /* ENOTSOCK */ - "already connected", /* EISCONN */ - "connection refused", /* ECONNREFUSED */ - "unreachable network", /* ENETUNREACH */ - "address in use", /* EADDRINUSE */ - "already in use", /* EALREADY */ - "unknown address family", /* EAFNOSUPPORT */ -}; - -#if defined(_WIN32) -/** - * __xmlIOWin32UTF8ToWChar: - * @u8String: uft-8 string - * - * Convert a string from utf-8 to wchar (WINDOWS ONLY!) - */ -static wchar_t * -__xmlIOWin32UTF8ToWChar(const char *u8String) -{ - wchar_t *wString = NULL; - - if (u8String) { - int wLen = - MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, u8String, - -1, NULL, 0); - if (wLen) { - wString = xmlMalloc(wLen * sizeof(wchar_t)); - if (wString) { - if (MultiByteToWideChar - (CP_UTF8, 0, u8String, -1, wString, wLen) == 0) { - xmlFree(wString); - wString = NULL; - } - } - } - } - - return wString; -} -#endif - -#if defined(LIBXML_HTTP_ENABLED) && defined(LIBXML_OUTPUT_ENABLED) /** * xmlIOErrMemory: * @extra: extra information @@ -212,11 +121,10 @@ __xmlIOWin32UTF8ToWChar(const char *u8String) * Handle an out of memory condition */ static void -xmlIOErrMemory(const char *extra) +xmlIOErrMemory(void) { - __xmlSimpleError(XML_FROM_IO, XML_ERR_NO_MEMORY, NULL, NULL, extra); + xmlRaiseMemoryError(NULL, NULL, NULL, XML_FROM_IO, NULL); } -#endif
/** * __xmlIOErr: @@ -226,13 +134,17 @@ xmlIOErrMemory(const char *extra) * * Handle an I/O error */ -void +int __xmlIOErr(int domain, int code, const char *extra) { - unsigned int idx; + xmlStructuredErrorFunc schannel = NULL; + xmlGenericErrorFunc channel = NULL; + void *data = NULL; + const char *fmt, *arg1, *arg2; + int res;
if (code == 0) { - if (errno == 0) code = 0; + if (errno == 0) code = XML_IO_UNKNOWN; #ifdef EACCES else if (errno == EACCES) code = XML_IO_EACCES; #endif @@ -388,189 +300,49 @@ __xmlIOErr(int domain, int code, const char *extra) #endif else code = XML_IO_UNKNOWN; } - idx = 0; - if (code >= XML_IO_UNKNOWN) idx = code - XML_IO_UNKNOWN; - if (idx >= (sizeof(IOerr) / sizeof(IOerr[0]))) idx = 0; - - __xmlSimpleError(domain, code, NULL, IOerr[idx], extra); -} - -/** - * xmlIOErr: - * @code: the error number - * @extra: extra information - * - * Handle an I/O error - */ -static void -xmlIOErr(int code, const char *extra) -{ - __xmlIOErr(XML_FROM_IO, code, extra); -}
-/** - * __xmlLoaderErr: - * @ctx: the parser context - * @extra: extra information - * - * Handle a resource access error - */ -void -__xmlLoaderErr(void *ctx, const char *msg, const char *filename) -{ - xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; - xmlStructuredErrorFunc schannel = NULL; - xmlGenericErrorFunc channel = NULL; - void *data = NULL; - xmlErrorLevel level = XML_ERR_ERROR; - - if ((ctxt != NULL) && (ctxt->disableSAX != 0) && - (ctxt->instate == XML_PARSER_EOF)) - return; - if ((ctxt != NULL) && (ctxt->sax != NULL)) { - if (ctxt->validate) { - channel = ctxt->sax->error; - level = XML_ERR_ERROR; - } else { - channel = ctxt->sax->warning; - level = XML_ERR_WARNING; - } - if (ctxt->sax->initialized == XML_SAX2_MAGIC) - schannel = ctxt->sax->serror; - data = ctxt->userData; + if (xmlStructuredError) { + schannel = xmlStructuredError; + data = xmlStructuredErrorContext; + } else { + channel = xmlGenericError; + data = xmlGenericErrorContext; } - __xmlRaiseError(schannel, channel, data, ctxt, NULL, XML_FROM_IO, - XML_IO_LOAD_ERROR, level, NULL, 0, - filename, NULL, NULL, 0, 0, - msg, filename); - -}
-/************************************************************************ - * * - * Tree memory error handler * - * * - ************************************************************************/ -/** - * xmlNormalizeWindowsPath: - * @path: the input file path - * - * This function is obsolete. Please see xmlURIFromPath in uri.c for - * a better solution. - * - * Returns a canonicalized version of the path - */ -xmlChar * -xmlNormalizeWindowsPath(const xmlChar *path) -{ - return xmlCanonicPath(path); -} - -/** - * xmlCleanupInputCallbacks: - * - * clears the entire input callback table. this includes the - * compiled-in I/O. - */ -void -xmlCleanupInputCallbacks(void) -{ - int i; - - if (!xmlInputCallbackInitialized) - return; - - for (i = xmlInputCallbackNr - 1; i >= 0; i--) { - xmlInputCallbackTable[i].matchcallback = NULL; - xmlInputCallbackTable[i].opencallback = NULL; - xmlInputCallbackTable[i].readcallback = NULL; - xmlInputCallbackTable[i].closecallback = NULL; + if (extra != NULL) { + fmt = "%s: %s"; + } else { + fmt = "%s"; }
- xmlInputCallbackNr = 0; - xmlInputCallbackInitialized = 0; -} - -/** - * xmlPopInputCallbacks: - * - * Clear the top input callback from the input stack. this includes the - * compiled-in I/O. - * - * Returns the number of input callback registered or -1 in case of error. - */ -int -xmlPopInputCallbacks(void) -{ - if (!xmlInputCallbackInitialized) - return(-1); - - if (xmlInputCallbackNr <= 0) - return(-1); - - xmlInputCallbackNr--; - xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = NULL; - xmlInputCallbackTable[xmlInputCallbackNr].opencallback = NULL; - xmlInputCallbackTable[xmlInputCallbackNr].readcallback = NULL; - xmlInputCallbackTable[xmlInputCallbackNr].closecallback = NULL; - - return(xmlInputCallbackNr); -} - -#ifdef LIBXML_OUTPUT_ENABLED -/** - * xmlCleanupOutputCallbacks: - * - * clears the entire output callback table. this includes the - * compiled-in I/O callbacks. - */ -void -xmlCleanupOutputCallbacks(void) -{ - int i; - - if (!xmlOutputCallbackInitialized) - return; + arg1 = xmlErrString(code); + arg2 = extra;
- for (i = xmlOutputCallbackNr - 1; i >= 0; i--) { - xmlOutputCallbackTable[i].matchcallback = NULL; - xmlOutputCallbackTable[i].opencallback = NULL; - xmlOutputCallbackTable[i].writecallback = NULL; - xmlOutputCallbackTable[i].closecallback = NULL; + res = __xmlRaiseError(schannel, channel, data, NULL, NULL, + domain, code, XML_ERR_ERROR, NULL, 0, + extra, NULL, NULL, 0, 0, + fmt, arg1, arg2); + if (res < 0) { + xmlIOErrMemory(); + return(XML_ERR_NO_MEMORY); }
- xmlOutputCallbackNr = 0; - xmlOutputCallbackInitialized = 0; + return(code); }
/** - * xmlPopOutputCallbacks: - * - * Remove the top output callbacks from the output stack. This includes the - * compiled-in I/O. + * xmlIOErr: + * @code: the error number + * @extra: extra information * - * Returns the number of output callback registered or -1 in case of error. + * Handle an I/O error */ -int -xmlPopOutputCallbacks(void) +static int +xmlIOErr(int code, const char *extra) { - if (!xmlOutputCallbackInitialized) - return(-1); - - if (xmlOutputCallbackNr <= 0) - return(-1); - - xmlOutputCallbackNr--; - xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = NULL; - xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = NULL; - xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = NULL; - xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = NULL; - - return(xmlOutputCallbackNr); + return(__xmlIOErr(XML_FROM_IO, code, extra)); }
-#endif /* LIBXML_OUTPUT_ENABLED */ - /************************************************************************ * * * Standard I/O for file accesses * @@ -580,92 +352,65 @@ xmlPopOutputCallbacks(void) #if defined(_WIN32)
/** - * xmlWrapOpenUtf8: - * @path: the path in utf-8 encoding - * @mode: type of access (0 - read, 1 - write) - * - * function opens the file specified by @path + * __xmlIOWin32UTF8ToWChar: + * @u8String: uft-8 string * + * Convert a string from utf-8 to wchar (WINDOWS ONLY!) */ -static FILE* -xmlWrapOpenUtf8(const char *path,int mode) -{ - FILE *fd = NULL; - wchar_t *wPath; - - wPath = __xmlIOWin32UTF8ToWChar(path); - if(wPath) - { - fd = _wfopen(wPath, mode ? L"wb" : L"rb"); - xmlFree(wPath); - } - /* maybe path in native encoding */ - if(fd == NULL) - fd = fopen(path, mode ? "wb" : "rb"); - - return fd; -} - -#ifdef LIBXML_ZLIB_ENABLED -static gzFile -xmlWrapGzOpenUtf8(const char *path, const char *mode) +static wchar_t * +__xmlIOWin32UTF8ToWChar(const char *u8String) { - gzFile fd; - wchar_t *wPath; + wchar_t *wString = NULL; + int i;
- fd = gzopen (path, mode); - if (fd) - return fd; + if (u8String) { + int wLen = + MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, u8String, + -1, NULL, 0); + if (wLen) { + wString = xmlMalloc(wLen * sizeof(wchar_t)); + if (wString) { + if (MultiByteToWideChar + (CP_UTF8, 0, u8String, -1, wString, wLen) == 0) { + xmlFree(wString); + wString = NULL; + } + }
- wPath = __xmlIOWin32UTF8ToWChar(path); - if(wPath) - { - int d, m = (strstr(mode, "r") ? O_RDONLY : O_RDWR); -#ifdef _O_BINARY - m |= (strstr(mode, "b") ? _O_BINARY : 0); -#endif - d = _wopen(wPath, m); - if (d >= 0) - fd = gzdopen(d, mode); - xmlFree(wPath); + /* + * Convert to backward slash + */ + for (i = 0; wString[i] != 0; i++) { + if (wString[i] == '/') + wString[i] = '\'; + } + } }
- return fd; + return wString; } + #endif
/** - * xmlWrapStatUtf8: - * @path: the path in utf-8 encoding - * @info: structure that stores results + * xmlNormalizeWindowsPath: + * @path: the input file path * - * function obtains information about the file or directory + * DEPRECATED: This never really worked. * + * Returns a copy of path. */ -static int -xmlWrapStatUtf8(const char *path, struct _stat *info) { - int retval = -1; - wchar_t *wPath; - - wPath = __xmlIOWin32UTF8ToWChar(path); - if (wPath) { - retval = _wstat(wPath, info); - xmlFree(wPath); - } - /* maybe path in native encoding */ - if(retval < 0) - retval = _stat(path, info); - return retval; +xmlChar * +xmlNormalizeWindowsPath(const xmlChar *path) +{ + return xmlStrdup(path); }
-#endif - /** * xmlCheckFilename: * @path: the path to check * - * function checks to see if @path is a valid source - * (file, socket...) for XML. + * DEPRECATED: Internal function, don't use. * * if stat is not available on the target machine, * returns 1. if stat fails, returns 0 (if calling @@ -673,9 +418,8 @@ xmlWrapStatUtf8(const char *path, struct _stat *info) { * if stat succeeds and the file is a directory, * returns 2. otherwise returns 1. */ - int -xmlCheckFilename (const char *path) +xmlCheckFilename(const char *path) { #ifdef HAVE_STAT #if defined(_WIN32) @@ -683,50 +427,183 @@ xmlCheckFilename (const char *path) #else struct stat stat_buffer; #endif + int res; #endif + if (path == NULL) return(0);
#ifdef HAVE_STAT #if defined(_WIN32) - /* - * On Windows stat and wstat do not work with long pathname, - * which start with '\?' - */ - if ((path[0] == '\') && (path[1] == '\') && (path[2] == '?') && - (path[3] == '\') ) - return 1; + { + wchar_t *wpath;
- if (xmlWrapStatUtf8(path, &stat_buffer) == -1) - return 0; + /* + * On Windows stat and wstat do not work with long pathname, + * which start with '\?' + */ + if ((path[0] == '\') && (path[1] == '\') && (path[2] == '?') && + (path[3] == '\') ) + return 1; + + wpath = __xmlIOWin32UTF8ToWChar(path); + if (wpath == NULL) + return(0); + res = _wstat(wpath, &stat_buffer); + xmlFree(wpath); + } #else - if (stat(path, &stat_buffer) == -1) - return 0; + res = stat(path, &stat_buffer); #endif + + if (res < 0) + return 0; + #ifdef S_ISDIR if (S_ISDIR(stat_buffer.st_mode)) return 2; #endif #endif /* HAVE_STAT */ + return 1; }
-/** - * xmlFdRead: - * @context: the I/O context - * @buffer: where to drop data - * @len: number of bytes to read - * - * Read @len bytes to @buffer from the I/O channel. - * - * Returns the number of bytes written +static int +xmlConvertUriToPath(const char *uri, char **out) { + const char *escaped; + char *unescaped; + + *out = NULL; + + if (!xmlStrncasecmp(BAD_CAST uri, BAD_CAST "file://localhost/", 17)) { + escaped = &uri[16]; + } else if (!xmlStrncasecmp(BAD_CAST uri, BAD_CAST "file:///", 8)) { + escaped = &uri[7]; + } else if (!xmlStrncasecmp(BAD_CAST uri, BAD_CAST "file:/", 6)) { + /* lots of generators seems to lazy to read RFC 1738 */ + escaped = &uri[5]; + } else { + return(1); + } + +#ifdef _WIN32 + /* Ignore slash like in file:///C:/file.txt */ + escaped += 1; +#endif + + unescaped = xmlURIUnescapeString(escaped, 0, NULL); + if (unescaped == NULL) + return(-1); + + *out = unescaped; + return(0); +} + +/** + * xmlFdOpen: + * @filename: the URI for matching + * @out: pointer to resulting context + * + * Returns an xmlParserErrors code */ static int -xmlFdRead (void * context, char * buffer, int len) { +xmlFdOpen(const char *filename, int write, int *out) { + char *fromUri = NULL; + int flags; + int fd; int ret;
- ret = read((int) (ptrdiff_t) context, &buffer[0], len); - if (ret < 0) xmlIOErr(0, "read()"); + *out = -1; + if (filename == NULL) + return(XML_ERR_ARGUMENT); + + if (xmlConvertUriToPath(filename, &fromUri) < 0) + return(XML_ERR_NO_MEMORY); + + if (fromUri != NULL) + filename = fromUri; + +#if defined(_WIN32) + { + wchar_t *wpath; + + wpath = __xmlIOWin32UTF8ToWChar(filename); + if (wpath == NULL) { + xmlFree(fromUri); + return(XML_ERR_NO_MEMORY); + } + if (write) + flags = _O_WRONLY | _O_CREAT | _O_TRUNC; + else + flags = _O_RDONLY; + fd = _wopen(wpath, flags | _O_BINARY, 0666); + xmlFree(wpath); + } +#else + if (write) + flags = O_WRONLY | O_CREAT | O_TRUNC; + else + flags = O_RDONLY; + fd = open(filename, flags, 0666); +#endif /* WIN32 */ + + if (fd < 0) { + /* + * Windows and possibly other platforms return EINVAL + * for invalid filenames. + */ + if ((errno == ENOENT) || (errno == EINVAL)) { + ret = XML_IO_ENOENT; + } else { + /* + * This error won't be forwarded to the parser context + * which will report it a second time. + */ + ret = xmlIOErr(0, filename); + } + } else { + *out = fd; + ret = XML_ERR_OK; + } + + xmlFree(fromUri); + return(ret); +} + +/** + * xmlFdRead: + * @context: the I/O context + * @buffer: where to drop data + * @len: number of bytes to read + * + * Read @len bytes to @buffer from the I/O channel. + * + * Returns the number of bytes read + */ +static int +xmlFdRead(void *context, char *buffer, int len) { + int fd = (int) (ptrdiff_t) context; + int ret = 0; + int bytes; + + while (len > 0) { + bytes = read(fd, buffer, len); + if (bytes < 0) { + /* + * If we already got some bytes, return them without + * raising an error. + */ + if (ret > 0) + break; + return(-xmlIOErr(0, "read()")); + } + if (bytes == 0) + break; + ret += bytes; + buffer += bytes; + len -= bytes; + } + return(ret); }
@@ -742,13 +619,20 @@ xmlFdRead (void * context, char * buffer, int len) { * Returns the number of bytes written */ static int -xmlFdWrite (void * context, const char * buffer, int len) { +xmlFdWrite(void *context, const char *buffer, int len) { + int fd = (int) (ptrdiff_t) context; int ret = 0; + int bytes;
- if (len > 0) { - ret = write((int) (ptrdiff_t) context, &buffer[0], len); - if (ret < 0) xmlIOErr(0, "write()"); + while (len > 0) { + bytes = write(fd, buffer, len); + if (bytes < 0) + return(-xmlIOErr(0, "write()")); + ret += bytes; + buffer += bytes; + len -= bytes; } + return(ret); } #endif /* LIBXML_OUTPUT_ENABLED */ @@ -764,16 +648,19 @@ xmlFdWrite (void * context, const char * buffer, int len) { static int xmlFdClose (void * context) { int ret; + ret = close((int) (ptrdiff_t) context); - if (ret < 0) xmlIOErr(0, "close()"); - return(ret); + if (ret < 0) + return(xmlIOErr(0, "close()")); + + return(XML_ERR_OK); }
/** * xmlFileMatch: * @filename: the URI for matching * - * input from FILE * + * DEPRECATED: Internal function, don't use. * * Returns 1 if matches, 0 otherwise */ @@ -783,139 +670,82 @@ xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) { }
/** - * xmlFileOpen_real: + * xmlFileOpenSafe: * @filename: the URI for matching + * @out: pointer to resulting context * - * input from FILE *, supports compressed input - * if @filename is " " then the standard input is used + * input from FILE * * * Returns an I/O context or NULL in case of error */ -static void * -xmlFileOpen_real (const char *filename) { - const char *path = filename; +static int +xmlFileOpenSafe(const char *filename, int write, void **out) { + char *fromUri = NULL; FILE *fd; + int ret = XML_ERR_OK;
+ *out = NULL; if (filename == NULL) - return(NULL); - - if (!strcmp(filename, "-")) { - fd = stdin; - return((void *) fd); - } + return(XML_ERR_ARGUMENT);
- if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) { -#if defined (_WIN32) - path = &filename[17]; -#else - path = &filename[16]; -#endif - } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) { -#if defined (_WIN32) - path = &filename[8]; -#else - path = &filename[7]; -#endif - } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:/", 6)) { - /* lots of generators seems to lazy to read RFC 1738 */ -#if defined (_WIN32) - path = &filename[6]; -#else - path = &filename[5]; -#endif - } + if (xmlConvertUriToPath(filename, &fromUri) < 0) + return(XML_ERR_NO_MEMORY);
- /* Do not check DDNAME on zOS ! */ -#if !defined(__MVS__) - if (!xmlCheckFilename(path)) - return(NULL); -#endif + if (fromUri != NULL) + filename = fromUri;
#if defined(_WIN32) - fd = xmlWrapOpenUtf8(path, 0); + { + wchar_t *wpath; + + wpath = __xmlIOWin32UTF8ToWChar(filename); + if (wpath == NULL) { + xmlFree(fromUri); + return(XML_ERR_NO_MEMORY); + } + fd = _wfopen(wpath, write ? L"wb" : L"rb"); + xmlFree(wpath); + } #else - fd = fopen(path, "rb"); + fd = fopen(filename, write ? "wb" : "rb"); #endif /* WIN32 */ - if (fd == NULL) xmlIOErr(0, path); - return((void *) fd); -}
-/** - * xmlFileOpen: - * @filename: the URI for matching - * - * Wrapper around xmlFileOpen_real that try it with an unescaped - * version of @filename, if this fails fallback to @filename - * - * Returns a handler or NULL in case or failure - */ -void * -xmlFileOpen (const char *filename) { - char *unescaped; - void *retval; - - retval = xmlFileOpen_real(filename); - if (retval == NULL) { - unescaped = xmlURIUnescapeString(filename, 0, NULL); - if (unescaped != NULL) { - retval = xmlFileOpen_real(unescaped); - xmlFree(unescaped); - } + if (fd == NULL) { + /* + * Windows and possibly other platforms return EINVAL + * for invalid filenames. + */ + if ((errno == ENOENT) || (errno == EINVAL)) { + ret = XML_IO_ENOENT; + } else { + /* + * This error won't be forwarded to the parser context + * which will report it a second time. + */ + ret = xmlIOErr(0, filename); + } }
- return retval; + *out = fd; + xmlFree(fromUri); + return(ret); }
-#ifdef LIBXML_OUTPUT_ENABLED /** - * xmlFileOpenW: + * xmlFileOpen: * @filename: the URI for matching * - * output to from FILE *, - * if @filename is "-" then the standard output is used + * DEPRECATED: Internal function, don't use. * - * Returns an I/O context or NULL in case of error + * Returns an IO context or NULL in case or failure */ -static void * -xmlFileOpenW (const char *filename) { - const char *path = NULL; - FILE *fd; - - if (!strcmp(filename, "-")) { - fd = stdout; - return((void *) fd); - } - - if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) -#if defined (_WIN32) - path = &filename[17]; -#else - path = &filename[16]; -#endif - else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) { -#if defined (_WIN32) - path = &filename[8]; -#else - path = &filename[7]; -#endif - } else - path = filename; - - if (path == NULL) - return(NULL); - -#if defined(_WIN32) - fd = xmlWrapOpenUtf8(path, 1); -#elif(__MVS__) - fd = fopen(path, "w"); -#else - fd = fopen(path, "wb"); -#endif /* WIN32 */ +void * +xmlFileOpen(const char *filename) { + void *context;
- if (fd == NULL) xmlIOErr(0, path); - return((void *) fd); + xmlFileOpenSafe(filename, 0, &context); + return(context); } -#endif /* LIBXML_OUTPUT_ENABLED */
/** * xmlFileRead: @@ -923,18 +753,30 @@ xmlFileOpenW (const char *filename) { * @buffer: where to drop data * @len: number of bytes to write * - * Read @len bytes to @buffer from the I/O channel. + * DEPRECATED: Internal function, don't use. * - * Returns the number of bytes written or < 0 in case of failure + * Returns the number of bytes read or < 0 in case of failure */ int -xmlFileRead (void * context, char * buffer, int len) { - int ret; +xmlFileRead(void * context, char * buffer, int len) { + FILE *file = context; + size_t bytes; + if ((context == NULL) || (buffer == NULL)) return(-1); - ret = fread(&buffer[0], 1, len, (FILE *) context); - if (ret < 0) xmlIOErr(0, "fread()"); - return(ret); + + /* + * The C standard doesn't mandate that fread sets errno, only + * POSIX does. The Windows documentation isn't really clear. + * Set errno to zero which will be reported as unknown error + * if fread fails without setting errno. + */ + errno = 0; + bytes = fread(buffer, 1, len, file); + if ((bytes < (size_t) len) && (ferror(file))) + return(-xmlIOErr(0, "fread()")); + + return(bytes); }
#ifdef LIBXML_OUTPUT_ENABLED @@ -949,66 +791,65 @@ xmlFileRead (void * context, char * buffer, int len) { * Returns the number of bytes written */ static int -xmlFileWrite (void * context, const char * buffer, int len) { - int items; +xmlFileWrite(void *context, const char *buffer, int len) { + FILE *file = context; + size_t bytes;
if ((context == NULL) || (buffer == NULL)) return(-1); - items = fwrite(&buffer[0], len, 1, (FILE *) context); - if ((items == 0) && (ferror((FILE *) context))) { - xmlIOErr(0, "fwrite()"); - return(-1); - } - return(items * len); + + errno = 0; + bytes = fwrite(buffer, 1, len, file); + if (bytes < (size_t) len) + return(-xmlIOErr(0, "fwrite()")); + + return(len); } #endif /* LIBXML_OUTPUT_ENABLED */
/** - * xmlFileClose: + * xmlFileFlush: * @context: the I/O context * - * Close an I/O channel - * - * Returns 0 or -1 in case of error + * Flush an I/O channel */ -int -xmlFileClose (void * context) { - FILE *fil; - int ret; +static int +xmlFileFlush (void * context) { + FILE *file = context;
- if (context == NULL) + if (file == NULL) return(-1); - fil = (FILE *) context; - if ((fil == stdout) || (fil == stderr)) { - ret = fflush(fil); - if (ret < 0) - xmlIOErr(0, "fflush()"); - return(0); - } - if (fil == stdin) - return(0); - ret = ( fclose((FILE *) context) == EOF ) ? -1 : 0; - if (ret < 0) - xmlIOErr(0, "fclose()"); - return(ret); + + if (fflush(file) != 0) + return(xmlIOErr(0, "fflush()")); + + return(XML_ERR_OK); }
/** - * xmlFileFlush: + * xmlFileClose: * @context: the I/O context * - * Flush an I/O channel + * DEPRECATED: Internal function, don't use. + * + * Returns 0 or -1 an error code case of error */ -static int -xmlFileFlush (void * context) { - int ret; +int +xmlFileClose (void * context) { + FILE *file = context;
if (context == NULL) return(-1); - ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0; - if (ret < 0) - xmlIOErr(0, "fflush()"); - return(ret); + + if (file == stdin) + return(0); + if ((file == stdout) || (file == stderr)) + return(xmlFileFlush(file)); + + if (fclose(file) != 0) + return(xmlIOErr(0, "fclose()")); + + return(0); }
#ifdef LIBXML_OUTPUT_ENABLED @@ -1020,7 +861,8 @@ xmlFileFlush (void * context) { * * Write @len bytes from @buffer to the xml buffer * - * Returns the number of bytes written + * Returns the number of bytes written or a negative xmlParserErrors + * value. */ static int xmlBufferWrite (void * context, const char * buffer, int len) { @@ -1028,7 +870,7 @@ xmlBufferWrite (void * context, const char * buffer, int len) {
ret = xmlBufferAdd((xmlBufferPtr) context, (const xmlChar *) buffer, len); if (ret != 0) - return(-1); + return(-XML_ERR_NO_MEMORY); return(len); } #endif @@ -1039,148 +881,6 @@ xmlBufferWrite (void * context, const char * buffer, int len) { * I/O for compressed file accesses * * * ************************************************************************/ -/** - * xmlGzfileMatch: - * @filename: the URI for matching - * - * input from compressed file test - * - * Returns 1 if matches, 0 otherwise - */ -static int -xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) { - return(1); -} - -/** - * xmlGzfileOpen_real: - * @filename: the URI for matching - * - * input from compressed file open - * if @filename is " " then the standard input is used - * - * Returns an I/O context or NULL in case of error - */ -static void * -xmlGzfileOpen_real (const char *filename) { - const char *path = NULL; - gzFile fd; - - if (!strcmp(filename, "-")) { - int duped_fd = dup(fileno(stdin)); - fd = gzdopen(duped_fd, "rb"); - if (fd == Z_NULL && duped_fd >= 0) { - close(duped_fd); /* gzdOpen() does not close on failure */ - } - - return((void *) fd); - } - - if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) -#if defined (_WIN32) - path = &filename[17]; -#else - path = &filename[16]; -#endif - else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) { -#if defined (_WIN32) - path = &filename[8]; -#else - path = &filename[7]; -#endif - } else - path = filename; - - if (path == NULL) - return(NULL); - if (!xmlCheckFilename(path)) - return(NULL); - -#if defined(_WIN32) - fd = xmlWrapGzOpenUtf8(path, "rb"); -#else - fd = gzopen(path, "rb"); -#endif - return((void *) fd); -} - -/** - * xmlGzfileOpen: - * @filename: the URI for matching - * - * Wrapper around xmlGzfileOpen_real if the open fails, it will - * try to unescape @filename - */ -static void * -xmlGzfileOpen (const char *filename) { - char *unescaped; - void *retval; - - retval = xmlGzfileOpen_real(filename); - if (retval == NULL) { - unescaped = xmlURIUnescapeString(filename, 0, NULL); - if (unescaped != NULL) { - retval = xmlGzfileOpen_real(unescaped); - } - xmlFree(unescaped); - } - return retval; -} - -#ifdef LIBXML_OUTPUT_ENABLED -/** - * xmlGzfileOpenW: - * @filename: the URI for matching - * @compression: the compression factor (0 - 9 included) - * - * input from compressed file open - * if @filename is " " then the standard input is used - * - * Returns an I/O context or NULL in case of error - */ -static void * -xmlGzfileOpenW (const char *filename, int compression) { - const char *path = NULL; - char mode[15]; - gzFile fd; - - snprintf(mode, sizeof(mode), "wb%d", compression); - if (!strcmp(filename, "-")) { - int duped_fd = dup(fileno(stdout)); - fd = gzdopen(duped_fd, "rb"); - if (fd == Z_NULL && duped_fd >= 0) { - close(duped_fd); /* gzdOpen() does not close on failure */ - } - - return((void *) fd); - } - - if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) -#if defined (_WIN32) - path = &filename[17]; -#else - path = &filename[16]; -#endif - else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) { -#if defined (_WIN32) - path = &filename[8]; -#else - path = &filename[7]; -#endif - } else - path = filename; - - if (path == NULL) - return(NULL); - -#if defined(_WIN32) - fd = xmlWrapGzOpenUtf8(path, mode); -#else - fd = gzopen(path, mode); -#endif - return((void *) fd); -} -#endif /* LIBXML_OUTPUT_ENABLED */
/** * xmlGzfileRead: @@ -1238,103 +938,29 @@ xmlGzfileClose (void * context) { } #endif /* LIBXML_ZLIB_ENABLED */
-#ifdef LIBXML_LZMA_ENABLED /************************************************************************ * * * I/O for compressed file accesses * * * ************************************************************************/ + +#ifdef LIBXML_LZMA_ENABLED + #include "private/xzlib.h" + /** - * xmlXzfileMatch: - * @filename: the URI for matching + * xmlXzfileRead: + * @context: the I/O context + * @buffer: where to drop data + * @len: number of bytes to write * - * input from compressed file test + * Read @len bytes to @buffer from the compressed I/O channel. * - * Returns 1 if matches, 0 otherwise + * Returns the number of bytes written */ static int -xmlXzfileMatch (const char *filename ATTRIBUTE_UNUSED) { - return(1); -} - -/** - * xmlXzFileOpen_real: - * @filename: the URI for matching - * - * input from compressed file open - * if @filename is " " then the standard input is used - * - * Returns an I/O context or NULL in case of error - */ -static void * -xmlXzfileOpen_real (const char *filename) { - const char *path = NULL; - xzFile fd; - - if (!strcmp(filename, "-")) { - fd = __libxml2_xzdopen(dup(fileno(stdin)), "rb"); - return((void *) fd); - } - - if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) { - path = &filename[16]; - } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) { - path = &filename[7]; - } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:/", 6)) { - /* lots of generators seems to lazy to read RFC 1738 */ - path = &filename[5]; - } else - path = filename; - - if (path == NULL) - return(NULL); - if (!xmlCheckFilename(path)) - return(NULL); - - fd = __libxml2_xzopen(path, "rb"); - return((void *) fd); -} - -/** - * xmlXzfileOpen: - * @filename: the URI for matching - * - * Wrapper around xmlXzfileOpen_real that try it with an unescaped - * version of @filename, if this fails fallback to @filename - * - * Returns a handler or NULL in case or failure - */ -static void * -xmlXzfileOpen (const char *filename) { - char *unescaped; - void *retval; - - retval = xmlXzfileOpen_real(filename); - if (retval == NULL) { - unescaped = xmlURIUnescapeString(filename, 0, NULL); - if (unescaped != NULL) { - retval = xmlXzfileOpen_real(unescaped); - } - xmlFree(unescaped); - } - - return retval; -} - -/** - * xmlXzfileRead: - * @context: the I/O context - * @buffer: where to drop data - * @len: number of bytes to write - * - * Read @len bytes to @buffer from the compressed I/O channel. - * - * Returns the number of bytes written - */ -static int -xmlXzfileRead (void * context, char * buffer, int len) { - int ret; +xmlXzfileRead (void * context, char * buffer, int len) { + int ret;
ret = __libxml2_xzread((xzFile) context, &buffer[0], len); if (ret < 0) xmlIOErr(0, "xzread()"); @@ -1357,371 +983,19 @@ xmlXzfileClose (void * context) { } #endif /* LIBXML_LZMA_ENABLED */
-#ifdef LIBXML_HTTP_ENABLED /************************************************************************ * * * I/O for HTTP file accesses * * * ************************************************************************/
-#ifdef LIBXML_OUTPUT_ENABLED -typedef struct xmlIOHTTPWriteCtxt_ -{ - int compression; - - char * uri; - - void * doc_buff; - -} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr; - -#ifdef LIBXML_ZLIB_ENABLED - -#define DFLT_WBITS ( -15 ) -#define DFLT_MEM_LVL ( 8 ) -#define GZ_MAGIC1 ( 0x1f ) -#define GZ_MAGIC2 ( 0x8b ) -#define LXML_ZLIB_OS_CODE ( 0x03 ) -#define INIT_HTTP_BUFF_SIZE ( 32768 ) -#define DFLT_ZLIB_RATIO ( 5 ) - -/* -** Data structure and functions to work with sending compressed data -** via HTTP. -*/ - -typedef struct xmlZMemBuff_ -{ - unsigned long size; - unsigned long crc; - - unsigned char * zbuff; - z_stream zctrl; - -} xmlZMemBuff, *xmlZMemBuffPtr; - -/** - * append_reverse_ulong - * @buff: Compressed memory buffer - * @data: Unsigned long to append - * - * Append a unsigned long in reverse byte order to the end of the - * memory buffer. - */ -static void -append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) { - - int idx; - - if ( buff == NULL ) - return; - - /* - ** This is plagiarized from putLong in gzio.c (zlib source) where - ** the number "4" is hardcoded. If zlib is ever patched to - ** support 64 bit file sizes, this code would need to be patched - ** as well. - */ - - for ( idx = 0; idx < 4; idx++ ) { - *buff->zctrl.next_out = ( data & 0xff ); - data >>= 8; - buff->zctrl.next_out++; - } - - return; -} - -/** - * - * xmlFreeZMemBuff - * @buff: The memory buffer context to clear - * - * Release all the resources associated with the compressed memory buffer. - */ -static void -xmlFreeZMemBuff( xmlZMemBuffPtr buff ) { - - if ( buff == NULL ) - return; - - xmlFree( buff->zbuff ); - deflateEnd( &buff->zctrl ); - - xmlFree( buff ); - return; -} - -/** - * xmlCreateZMemBuff - *@compression: Compression value to use - * - * Create a memory buffer to hold the compressed XML document. The - * compressed document in memory will end up being identical to what - * would be created if gzopen/gzwrite/gzclose were being used to - * write the document to disk. The code for the header/trailer data to - * the compression is plagiarized from the zlib source files. - */ -static void * -xmlCreateZMemBuff( int compression ) { - - int z_err; - int hdr_lgth; - xmlZMemBuffPtr buff = NULL; - - if ( ( compression < 1 ) || ( compression > 9 ) ) - return ( NULL ); - - /* Create the control and data areas */ - - buff = xmlMalloc( sizeof( xmlZMemBuff ) ); - if ( buff == NULL ) { - xmlIOErrMemory("creating buffer context"); - return ( NULL ); - } - - (void)memset( buff, 0, sizeof( xmlZMemBuff ) ); - buff->size = INIT_HTTP_BUFF_SIZE; - buff->zbuff = xmlMalloc( buff->size ); - if ( buff->zbuff == NULL ) { - xmlFreeZMemBuff( buff ); - xmlIOErrMemory("creating buffer"); - return ( NULL ); - } - - z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED, - DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY ); - if ( z_err != Z_OK ) { - xmlChar msg[500]; - xmlFreeZMemBuff( buff ); - buff = NULL; - xmlStrPrintf(msg, 500, - "xmlCreateZMemBuff: %s %d\n", - "Error initializing compression context. ZLIB error:", - z_err ); - xmlIOErr(XML_IO_WRITE, (const char *) msg); - return ( NULL ); - } - - /* Set the header data. The CRC will be needed for the trailer */ - buff->crc = crc32( 0L, NULL, 0 ); - hdr_lgth = snprintf( (char *)buff->zbuff, buff->size, - "%c%c%c%c%c%c%c%c%c%c", - GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED, - 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE ); - buff->zctrl.next_out = buff->zbuff + hdr_lgth; - buff->zctrl.avail_out = buff->size - hdr_lgth; - - return ( buff ); -} - -/** - * xmlZMemBuffExtend - * @buff: Buffer used to compress and consolidate data. - * @ext_amt: Number of bytes to extend the buffer. - * - * Extend the internal buffer used to store the compressed data by the - * specified amount. - * - * Returns 0 on success or -1 on failure to extend the buffer. On failure - * the original buffer still exists at the original size. - */ -static int -xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) { - - int rc = -1; - size_t new_size; - size_t cur_used; - - unsigned char * tmp_ptr = NULL; - - if ( buff == NULL ) - return ( -1 ); - - else if ( ext_amt == 0 ) - return ( 0 ); - - cur_used = buff->zctrl.next_out - buff->zbuff; - new_size = buff->size + ext_amt; - - tmp_ptr = xmlRealloc( buff->zbuff, new_size ); - if ( tmp_ptr != NULL ) { - rc = 0; - buff->size = new_size; - buff->zbuff = tmp_ptr; - buff->zctrl.next_out = tmp_ptr + cur_used; - buff->zctrl.avail_out = new_size - cur_used; - } - else { - xmlChar msg[500]; - xmlStrPrintf(msg, 500, - "xmlZMemBuffExtend: %s %lu bytes.\n", - "Allocation failure extending output buffer to", - (unsigned long) new_size ); - xmlIOErr(XML_IO_WRITE, (const char *) msg); - } - - return ( rc ); -} - -/** - * xmlZMemBuffAppend - * @buff: Buffer used to compress and consolidate data - * @src: Uncompressed source content to append to buffer - * @len: Length of source data to append to buffer - * - * Compress and append data to the internal buffer. The data buffer - * will be expanded if needed to store the additional data. - * - * Returns the number of bytes appended to the buffer or -1 on error. - */ -static int -xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) { - - int z_err; - size_t min_accept; - - if ( ( buff == NULL ) || ( src == NULL ) ) - return ( -1 ); - - buff->zctrl.avail_in = len; - buff->zctrl.next_in = (unsigned char *)src; - while ( buff->zctrl.avail_in > 0 ) { - /* - ** Extend the buffer prior to deflate call if a reasonable amount - ** of output buffer space is not available. - */ - min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO; - if ( buff->zctrl.avail_out <= min_accept ) { - if ( xmlZMemBuffExtend( buff, buff->size ) == -1 ) - return ( -1 ); - } - - z_err = deflate( &buff->zctrl, Z_NO_FLUSH ); - if ( z_err != Z_OK ) { - xmlChar msg[500]; - xmlStrPrintf(msg, 500, - "xmlZMemBuffAppend: %s %d %s - %d", - "Compression error while appending", - len, "bytes to buffer. ZLIB error", z_err ); - xmlIOErr(XML_IO_WRITE, (const char *) msg); - return ( -1 ); - } - } - - buff->crc = crc32( buff->crc, (unsigned char *)src, len ); - - return ( len ); -} - -/** - * xmlZMemBuffGetContent - * @buff: Compressed memory content buffer - * @data_ref: Pointer reference to point to compressed content - * - * Flushes the compression buffers, appends gzip file trailers and - * returns the compressed content and length of the compressed data. - * NOTE: The gzip trailer code here is plagiarized from zlib source. - * - * Returns the length of the compressed data or -1 on error. - */ -static int -xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) { - - int zlgth = -1; - int z_err; - - if ( ( buff == NULL ) || ( data_ref == NULL ) ) - return ( -1 ); - - /* Need to loop until compression output buffers are flushed */ - - do - { - z_err = deflate( &buff->zctrl, Z_FINISH ); - if ( z_err == Z_OK ) { - /* In this case Z_OK means more buffer space needed */ - - if ( xmlZMemBuffExtend( buff, buff->size ) == -1 ) - return ( -1 ); - } - } - while ( z_err == Z_OK ); - - /* If the compression state is not Z_STREAM_END, some error occurred */ - - if ( z_err == Z_STREAM_END ) { - - /* Need to append the gzip data trailer */ - - if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) { - if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 ) - return ( -1 ); - } - - /* - ** For whatever reason, the CRC and length data are pushed out - ** in reverse byte order. So a memcpy can't be used here. - */ - - append_reverse_ulong( buff, buff->crc ); - append_reverse_ulong( buff, buff->zctrl.total_in ); - - zlgth = buff->zctrl.next_out - buff->zbuff; - *data_ref = (char *)buff->zbuff; - } - - else { - xmlChar msg[500]; - xmlStrPrintf(msg, 500, - "xmlZMemBuffGetContent: %s - %d\n", - "Error flushing zlib buffers. Error code", z_err ); - xmlIOErr(XML_IO_WRITE, (const char *) msg); - } - - return ( zlgth ); -} -#endif /* LIBXML_OUTPUT_ENABLED */ -#endif /* LIBXML_ZLIB_ENABLED */ - -#ifdef LIBXML_OUTPUT_ENABLED -/** - * xmlFreeHTTPWriteCtxt - * @ctxt: Context to cleanup - * - * Free allocated memory and reclaim system resources. - * - * No return value. - */ -static void -xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt ) -{ - if ( ctxt->uri != NULL ) - xmlFree( ctxt->uri ); - - if ( ctxt->doc_buff != NULL ) { - -#ifdef LIBXML_ZLIB_ENABLED - if ( ctxt->compression > 0 ) { - xmlFreeZMemBuff( ctxt->doc_buff ); - } - else -#endif - { - xmlOutputBufferClose( ctxt->doc_buff ); - } - } - - xmlFree( ctxt ); - return; -} -#endif /* LIBXML_OUTPUT_ENABLED */ - - +#ifdef LIBXML_HTTP_ENABLED /** * xmlIOHTTPMatch: * @filename: the URI for matching * + * DEPRECATED: Internal function, don't use. + * * check if the URI matches an HTTP one * * Returns 1 if matches, 0 otherwise @@ -1737,6 +1011,8 @@ xmlIOHTTPMatch (const char *filename) { * xmlIOHTTPOpen: * @filename: the URI for matching * + * DEPRECATED: Internal function, don't use. + * * open an HTTP I/O channel * * Returns an I/O context or NULL in case of error @@ -1752,78 +1028,15 @@ xmlIOHTTPOpen (const char *filename) { * @post_uri: The destination URI for the document * @compression: The compression desired for the document. * - * Open a temporary buffer to collect the document for a subsequent HTTP POST - * request. Non-static as is called from the output buffer creation routine. + * DEPRECATED: Support for HTTP POST has been removed. * - * Returns an I/O context or NULL in case of error. + * Returns NULL. */ - void * -xmlIOHTTPOpenW(const char *post_uri, int compression ATTRIBUTE_UNUSED) +xmlIOHTTPOpenW(const char *post_uri ATTRIBUTE_UNUSED, + int compression ATTRIBUTE_UNUSED) { - - xmlIOHTTPWriteCtxtPtr ctxt = NULL; - - if (post_uri == NULL) - return (NULL); - - ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt)); - if (ctxt == NULL) { - xmlIOErrMemory("creating HTTP output context"); - return (NULL); - } - - (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt)); - - ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri); - if (ctxt->uri == NULL) { - xmlIOErrMemory("copying URI"); - xmlFreeHTTPWriteCtxt(ctxt); - return (NULL); - } - - /* - * ** Since the document length is required for an HTTP post, - * ** need to put the document into a buffer. A memory buffer - * ** is being used to avoid pushing the data to disk and back. - */ - -#ifdef LIBXML_ZLIB_ENABLED - if ((compression > 0) && (compression <= 9)) { - - ctxt->compression = compression; - ctxt->doc_buff = xmlCreateZMemBuff(compression); - } else -#endif - { - /* Any character conversions should have been done before this */ - - ctxt->doc_buff = xmlAllocOutputBufferInternal(NULL); - } - - if (ctxt->doc_buff == NULL) { - xmlFreeHTTPWriteCtxt(ctxt); - ctxt = NULL; - } - - return (ctxt); -} -#endif /* LIBXML_OUTPUT_ENABLED */ - -#ifdef LIBXML_OUTPUT_ENABLED -/** - * xmlIOHTTPDfltOpenW - * @post_uri: The destination URI for this document. - * - * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent - * HTTP post command. This function should generally not be used as - * the open callback is short circuited in xmlOutputBufferCreateFile. - * - * Returns a pointer to the new IO context. - */ -static void * -xmlIOHTTPDfltOpenW( const char * post_uri ) { - return ( xmlIOHTTPOpenW( post_uri, 0 ) ); + return(NULL); } #endif /* LIBXML_OUTPUT_ENABLED */
@@ -1833,6 +1046,8 @@ xmlIOHTTPDfltOpenW( const char * post_uri ) { * @buffer: where to drop data * @len: number of bytes to write * + * DEPRECATED: Internal function, don't use. + * * Read @len bytes to @buffer from the I/O channel. * * Returns the number of bytes written @@ -1843,59 +1058,12 @@ xmlIOHTTPRead(void * context, char * buffer, int len) { return(xmlNanoHTTPRead(context, &buffer[0], len)); }
-#ifdef LIBXML_OUTPUT_ENABLED -/** - * xmlIOHTTPWrite - * @context: previously opened writing context - * @buffer: data to output to temporary buffer - * @len: bytes to output - * - * Collect data from memory buffer into a temporary file for later - * processing. - * - * Returns number of bytes written. - */ - -static int -xmlIOHTTPWrite( void * context, const char * buffer, int len ) { - - xmlIOHTTPWriteCtxtPtr ctxt = context; - - if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) ) - return ( -1 ); - - if ( len > 0 ) { - - /* Use gzwrite or fwrite as previously setup in the open call */ - -#ifdef LIBXML_ZLIB_ENABLED - if ( ctxt->compression > 0 ) - len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len ); - - else -#endif - len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer ); - - if ( len < 0 ) { - xmlChar msg[500]; - xmlStrPrintf(msg, 500, - "xmlIOHTTPWrite: %s\n%s '%s'.\n", - "Error appending to internal buffer.", - "Error sending document to URI", - ctxt->uri ); - xmlIOErr(XML_IO_WRITE, (const char *) msg); - } - } - - return ( len ); -} -#endif /* LIBXML_OUTPUT_ENABLED */ - - /** * xmlIOHTTPClose: * @context: the I/O context * + * DEPRECATED: Internal function, don't use. + * * Close an HTTP I/O channel * * Returns 0 @@ -1905,119 +1073,6 @@ xmlIOHTTPClose (void * context) { xmlNanoHTTPClose(context); return 0; } - -#ifdef LIBXML_OUTPUT_ENABLED -/** - * xmlIOHTTCloseWrite - * @context: The I/O context - * @http_mthd: The HTTP method to be used when sending the data - * - * Close the transmit HTTP I/O channel and actually send the data. - */ -static int -xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) { - - int close_rc = -1; - int http_rtn = 0; - int content_lgth = 0; - xmlIOHTTPWriteCtxtPtr ctxt = context; - - char * http_content = NULL; - char * content_encoding = NULL; - char * content_type = (char *) "text/xml"; - void * http_ctxt = NULL; - - if ( ( ctxt == NULL ) || ( http_mthd == NULL ) ) - return ( -1 ); - - /* Retrieve the content from the appropriate buffer */ - -#ifdef LIBXML_ZLIB_ENABLED - - if ( ctxt->compression > 0 ) { - content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content ); - content_encoding = (char *) "Content-Encoding: gzip"; - } - else -#endif - { - /* Pull the data out of the memory output buffer */ - - xmlOutputBufferPtr dctxt = ctxt->doc_buff; - http_content = (char *) xmlBufContent(dctxt->buffer); - content_lgth = xmlBufUse(dctxt->buffer); - } - - if ( http_content == NULL ) { - xmlChar msg[500]; - xmlStrPrintf(msg, 500, - "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n", - "Error retrieving content.\nUnable to", - http_mthd, "data to URI", ctxt->uri ); - xmlIOErr(XML_IO_WRITE, (const char *) msg); - } - - else { - - http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content, - &content_type, content_encoding, - content_lgth ); - - if ( http_ctxt != NULL ) { - - http_rtn = xmlNanoHTTPReturnCode( http_ctxt ); - if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) ) - close_rc = 0; - else { - xmlChar msg[500]; - xmlStrPrintf(msg, 500, - "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n", - http_mthd, content_lgth, - "bytes to URI", ctxt->uri, - "failed. HTTP return code:", http_rtn ); - xmlIOErr(XML_IO_WRITE, (const char *) msg); - } - - xmlNanoHTTPClose( http_ctxt ); - xmlFree( content_type ); - } - } - - /* Final cleanups */ - - xmlFreeHTTPWriteCtxt( ctxt ); - - return ( close_rc ); -} - -/** - * xmlIOHTTPClosePut - * - * @context: The I/O context - * - * Close the transmit HTTP I/O channel and actually send data using a PUT - * HTTP method. - */ -static int -xmlIOHTTPClosePut( void * ctxt ) { - return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) ); -} - - -/** - * xmlIOHTTPClosePost - * - * @context: The I/O context - * - * Close the transmit HTTP I/O channel and actually send data using a POST - * HTTP method. - */ -static int -xmlIOHTTPClosePost( void * ctxt ) { - return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) ); -} -#endif /* LIBXML_OUTPUT_ENABLED */ - #endif /* LIBXML_HTTP_ENABLED */
#ifdef LIBXML_FTP_ENABLED @@ -2030,6 +1085,8 @@ xmlIOHTTPClosePost( void * ctxt ) { * xmlIOFTPMatch: * @filename: the URI for matching * + * DEPRECATED: Internal function, don't use. + * * check if the URI matches an FTP one * * Returns 1 if matches, 0 otherwise @@ -2045,6 +1102,8 @@ xmlIOFTPMatch (const char *filename) { * xmlIOFTPOpen: * @filename: the URI for matching * + * DEPRECATED: Internal function, don't use. + * * open an FTP I/O channel * * Returns an I/O context or NULL in case of error @@ -2060,6 +1119,8 @@ xmlIOFTPOpen (const char *filename) { * @buffer: where to drop data * @len: number of bytes to write * + * DEPRECATED: Internal function, don't use. + * * Read @len bytes to @buffer from the I/O channel. * * Returns the number of bytes written @@ -2074,6 +1135,8 @@ xmlIOFTPRead(void * context, char * buffer, int len) { * xmlIOFTPClose: * @context: the I/O context * + * DEPRECATED: Internal function, don't use. + * * Close an FTP I/O channel * * Returns 0 @@ -2084,161 +1147,229 @@ xmlIOFTPClose (void * context) { } #endif /* LIBXML_FTP_ENABLED */
+/************************************************************************ + * * + * Input/output buffers * + * * + ************************************************************************/
-/** - * xmlRegisterInputCallbacks: - * @matchFunc: the xmlInputMatchCallback - * @openFunc: the xmlInputOpenCallback - * @readFunc: the xmlInputReadCallback - * @closeFunc: the xmlInputCloseCallback - * - * Register a new set of I/O callback for handling parser input. - * - * Returns the registered handler number or -1 in case of error - */ -int -xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc, - xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc, - xmlInputCloseCallback closeFunc) { - if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) { - return(-1); - } - xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc; - xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc; - xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc; - xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc; - xmlInputCallbackInitialized = 1; - return(xmlInputCallbackNr++); +static int +xmlIODefaultMatch(const char *filename ATTRIBUTE_UNUSED) { + return(1); }
-#ifdef LIBXML_OUTPUT_ENABLED -/** - * xmlRegisterOutputCallbacks: - * @matchFunc: the xmlOutputMatchCallback - * @openFunc: the xmlOutputOpenCallback - * @writeFunc: the xmlOutputWriteCallback - * @closeFunc: the xmlOutputCloseCallback - * - * Register a new set of I/O callback for handling output. - * - * Returns the registered handler number or -1 in case of error - */ int -xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc, - xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc, - xmlOutputCloseCallback closeFunc) { - if (xmlOutputCallbackNr >= MAX_OUTPUT_CALLBACK) { - return(-1); +xmlInputFromFd(xmlParserInputBufferPtr buf, int fd, int unzip) { + int copy; + + (void) unzip; + +#ifdef LIBXML_LZMA_ENABLED + if (unzip) { + xzFile xzStream; + off_t pos; + + pos = lseek(fd, 0, SEEK_CUR); + + copy = dup(fd); + if (copy == -1) + return(xmlIOErr(0, "dup()")); + + xzStream = __libxml2_xzdopen("?", copy, "rb"); + + if (xzStream == NULL) { + close(copy); + } else { + int compressed = (__libxml2_xzcompressed(xzStream) > 0); + + if ((compressed) || + /* Try to rewind if not gzip compressed */ + (pos < 0) || + (lseek(fd, pos, SEEK_SET) < 0)) { + /* + * If a file isn't seekable, we pipe uncompressed + * input through xzlib. + */ + buf->context = xzStream; + buf->readcallback = xmlXzfileRead; + buf->closecallback = xmlXzfileClose; + buf->compressed = compressed; + + return(XML_ERR_OK); + } + + xmlXzfileClose(xzStream); + } } - xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc; - xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc; - xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc; - xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc; - xmlOutputCallbackInitialized = 1; - return(xmlOutputCallbackNr++); +#endif /* LIBXML_LZMA_ENABLED */ + +#ifdef LIBXML_ZLIB_ENABLED + if (unzip) { + gzFile gzStream; + off_t pos; + + pos = lseek(fd, 0, SEEK_CUR); + + copy = dup(fd); + if (copy == -1) + return(xmlIOErr(0, "dup()")); + + gzStream = gzdopen(copy, "rb"); + + if (gzStream == NULL) { + close(copy); + } else { + int compressed = (gzdirect(gzStream) == 0); + + if ((compressed) || + /* Try to rewind if not gzip compressed */ + (pos < 0) || + (lseek(fd, pos, SEEK_SET) < 0)) { + /* + * If a file isn't seekable, we pipe uncompressed + * input through zlib. + */ + buf->context = gzStream; + buf->readcallback = xmlGzfileRead; + buf->closecallback = xmlGzfileClose; + buf->compressed = compressed; + + return(XML_ERR_OK); + } + + xmlGzfileClose(gzStream); + } + } +#endif /* LIBXML_ZLIB_ENABLED */ + + copy = dup(fd); + if (copy == -1) + return(xmlIOErr(0, "dup()")); + + buf->context = (void *) (ptrdiff_t) copy; + buf->readcallback = xmlFdRead; + buf->closecallback = xmlFdClose; + + return(XML_ERR_OK); } -#endif /* LIBXML_OUTPUT_ENABLED */
/** - * xmlRegisterDefaultInputCallbacks: + * xmlInputDefaultOpen: + * @buf: input buffer to be filled + * @filename: filename or URI * - * Registers the default compiled-in I/O handlers. + * Returns an xmlParserErrors code. */ -void -xmlRegisterDefaultInputCallbacks(void) { - if (xmlInputCallbackInitialized) - return; +static int +xmlInputDefaultOpen(xmlParserInputBufferPtr buf, const char *filename) { + int ret; + int fd;
- xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen, - xmlFileRead, xmlFileClose); -#ifdef LIBXML_ZLIB_ENABLED - xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen, - xmlGzfileRead, xmlGzfileClose); -#endif /* LIBXML_ZLIB_ENABLED */ -#ifdef LIBXML_LZMA_ENABLED - xmlRegisterInputCallbacks(xmlXzfileMatch, xmlXzfileOpen, - xmlXzfileRead, xmlXzfileClose); -#endif /* LIBXML_LZMA_ENABLED */ +#ifdef LIBXML_FTP_ENABLED + if (xmlIOFTPMatch(filename)) { + buf->context = xmlIOFTPOpen(filename); + + if (buf->context != NULL) { + buf->readcallback = xmlIOFTPRead; + buf->closecallback = xmlIOFTPClose; + return(XML_ERR_OK); + } + } +#endif /* LIBXML_FTP_ENABLED */
#ifdef LIBXML_HTTP_ENABLED - xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen, - xmlIOHTTPRead, xmlIOHTTPClose); + if (xmlIOHTTPMatch(filename)) { + buf->context = xmlIOHTTPOpen(filename); + + if (buf->context != NULL) { + buf->readcallback = xmlIOHTTPRead; + buf->closecallback = xmlIOHTTPClose; + return(XML_ERR_OK); + } + } #endif /* LIBXML_HTTP_ENABLED */
-#ifdef LIBXML_FTP_ENABLED - xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen, - xmlIOFTPRead, xmlIOFTPClose); -#endif /* LIBXML_FTP_ENABLED */ - xmlInputCallbackInitialized = 1; + if (!xmlFileMatch(filename)) + return(XML_IO_ENOENT); + + ret = xmlFdOpen(filename, 0, &fd); + if (ret != XML_ERR_OK) + return(ret); + + ret = xmlInputFromFd(buf, fd, /* unzip */ 1); + + close(fd); + + return(ret); }
#ifdef LIBXML_OUTPUT_ENABLED /** - * xmlRegisterDefaultOutputCallbacks: + * xmlOutputDefaultOpen: + * @buf: input buffer to be filled + * @filename: filename or URI + * @compression: compression level or 0 + * @is_file_uri: whether filename is a file URI * - * Registers the default compiled-in I/O handlers. + * Returns an xmlParserErrors code. */ -void -xmlRegisterDefaultOutputCallbacks (void) { - if (xmlOutputCallbackInitialized) - return; +static int +xmlOutputDefaultOpen(xmlOutputBufferPtr buf, const char *filename, + int compression) { + int fd;
- xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW, - xmlFileWrite, xmlFileClose); + (void) compression;
-#ifdef LIBXML_HTTP_ENABLED - xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW, - xmlIOHTTPWrite, xmlIOHTTPClosePut); -#endif + if (!strcmp(filename, "-")) { + fd = dup(STDOUT_FILENO); + + if (fd < 0) + return(xmlIOErr(0, "dup()")); + } else { + int ret;
-/********************************* - No way a-priori to distinguish between gzipped files from - uncompressed ones except opening if existing then closing - and saving with same compression ratio ... a pain. + ret = xmlFdOpen(filename, /* write */ 1, &fd); + if (ret != XML_ERR_OK) + return(ret); + }
#ifdef LIBXML_ZLIB_ENABLED - xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen, - xmlGzfileWrite, xmlGzfileClose); -#endif + if ((compression > 0) && (compression <= 9)) { + gzFile gzStream; + char mode[15];
- Nor FTP PUT .... -#ifdef LIBXML_FTP_ENABLED - xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen, - xmlIOFTPWrite, xmlIOFTPClose); -#endif - **********************************/ - xmlOutputCallbackInitialized = 1; -} + snprintf(mode, sizeof(mode), "wb%d", compression); + gzStream = gzdopen(fd, mode);
-#ifdef LIBXML_HTTP_ENABLED -/** - * xmlRegisterHTTPPostCallbacks: - * - * By default, libxml submits HTTP output requests using the "PUT" method. - * Calling this method changes the HTTP output method to use the "POST" - * method instead. - * - */ -void -xmlRegisterHTTPPostCallbacks( void ) { + if (gzStream == NULL) { + close(fd); + return(xmlIOErr(XML_IO_UNKNOWN, "gzdopen()")); + }
- /* Register defaults if not done previously */ + buf->context = gzStream; + buf->writecallback = xmlGzfileWrite; + buf->closecallback = xmlGzfileClose;
- if ( xmlOutputCallbackInitialized == 0 ) - xmlRegisterDefaultOutputCallbacks( ); + return(XML_ERR_OK); + } +#endif /* LIBXML_ZLIB_ENABLED */
- xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW, - xmlIOHTTPWrite, xmlIOHTTPClosePost); - return; + buf->context = (void *) (ptrdiff_t) fd; + buf->writecallback = xmlFdWrite; + buf->closecallback = xmlFdClose; + return(XML_ERR_OK); } #endif -#endif /* LIBXML_OUTPUT_ENABLED */
/** * xmlAllocParserInputBuffer: - * @enc: the charset encoding if known + * @enc: the charset encoding if known (deprecated) + * + * Create a buffered parser input for progressive parsing. * - * Create a buffered parser input for progressive parsing + * The encoding argument is deprecated and should be set to + * XML_CHAR_ENCODING_NONE. The encoding can be changed with + * xmlSwitchEncoding or xmlSwitchEncodingName later on. * * Returns the new parser input or NULL */ @@ -2257,7 +1388,13 @@ xmlAllocParserInputBuffer(xmlCharEncoding enc) { return(NULL); } xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_DOUBLEIT); - ret->encoder = xmlGetCharEncodingHandler(enc); + if (enc != XML_CHAR_ENCODING_NONE) { + if (xmlLookupCharEncodingHandler(enc, &ret->encoder) != 0) { + /* We can't handle errors properly here. */ + xmlFreeParserInputBuffer(ret); + return(NULL); + } + } if (ret->encoder != NULL) ret->raw = xmlBufCreateSize(2 * xmlDefaultBufferSize); else @@ -2294,7 +1431,7 @@ xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) { xmlFree(ret); return(NULL); } - xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_DOUBLEIT); + xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_IO);
ret->encoder = encoder; if (encoder != NULL) { @@ -2409,22 +1546,36 @@ xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) { * flushes and close the output I/O channel * and free up all the associated resources * - * Returns the number of byte written or -1 in case of error. + * Returns the number of byte written or a negative xmlParserErrors + * code in case of error. */ int xmlOutputBufferClose(xmlOutputBufferPtr out) { - int written; - int err_rc = 0; + int ret;
if (out == NULL) return (-1); + if (out->writecallback != NULL) xmlOutputBufferFlush(out); + if (out->closecallback != NULL) { - err_rc = out->closecallback(out->context); + int code = out->closecallback(out->context); + + if ((code != XML_ERR_OK) && (out->error == XML_ERR_OK)) { + if (code < 0) + out->error = XML_IO_UNKNOWN; + else + out->error = code; + } } - written = out->written; + + if (out->error != XML_ERR_OK) + ret = -out->error; + else + ret = out->written; + if (out->conv) { xmlBufFree(out->conv); out->conv = NULL; @@ -2437,81 +1588,79 @@ xmlOutputBufferClose(xmlOutputBufferPtr out) out->buffer = NULL; }
- if (out->error) - err_rc = -1; xmlFree(out); - return ((err_rc == 0) ? written : err_rc); + + return(ret); } #endif /* LIBXML_OUTPUT_ENABLED */
-xmlParserInputBufferPtr -__xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) { - xmlParserInputBufferPtr ret; - int i = 0; - void *context = NULL; +/** + * xmlParserInputBufferCreateFilenameInt: + * @URI: the filename or URI + * @enc: encoding enum (deprecated) + * @out: pointer to resulting input buffer + * + * Returns an xmlParserErrors code. + */ +static int +xmlParserInputBufferCreateFilenameInt(const char *URI, xmlCharEncoding enc, + xmlParserInputBufferPtr *out) { + xmlParserInputBufferPtr buf; + int ret; + int i;
- if (xmlInputCallbackInitialized == 0) - xmlRegisterDefaultInputCallbacks(); + xmlInitParser();
- if (URI == NULL) return(NULL); + *out = NULL; + if (URI == NULL) + return(XML_ERR_ARGUMENT); + + /* + * Allocate the Input buffer front-end. + */ + buf = xmlAllocParserInputBuffer(enc); + if (buf == NULL) + return(XML_ERR_NO_MEMORY);
/* * Try to find one of the input accept method accepting that scheme * Go in reverse to give precedence to user defined handlers. */ - if (context == NULL) { - for (i = xmlInputCallbackNr - 1;i >= 0;i--) { - if ((xmlInputCallbackTable[i].matchcallback != NULL) && - (xmlInputCallbackTable[i].matchcallback(URI) != 0)) { - context = xmlInputCallbackTable[i].opencallback(URI); - if (context != NULL) { - break; - } - } - } + ret = XML_IO_ENOENT; + for (i = xmlInputCallbackNr - 1; i >= 0; i--) { + xmlInputCallback *cb = &xmlInputCallbackTable[i]; + + if (cb->matchcallback == xmlIODefaultMatch) { + ret = xmlInputDefaultOpen(buf, URI); + + if ((ret == XML_ERR_OK) || (ret != XML_IO_ENOENT)) + break; + } else if ((cb->matchcallback != NULL) && + (cb->matchcallback(URI) != 0)) { + buf->context = cb->opencallback(URI); + if (buf->context != NULL) { + buf->readcallback = cb->readcallback; + buf->closecallback = cb->closecallback; + ret = XML_ERR_OK; + break; + } + } } - if (context == NULL) { - return(NULL); + if (ret != XML_ERR_OK) { + xmlFreeParserInputBuffer(buf); + *out = NULL; + return(ret); }
- /* - * Allocate the Input buffer front-end. - */ - ret = xmlAllocParserInputBuffer(enc); - if (ret != NULL) { - ret->context = context; - ret->readcallback = xmlInputCallbackTable[i].readcallback; - ret->closecallback = xmlInputCallbackTable[i].closecallback; -#ifdef LIBXML_ZLIB_ENABLED - if ((xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) && - (strcmp(URI, "-") != 0)) { -#if defined(ZLIB_VERNUM) && ZLIB_VERNUM >= 0x1230 - ret->compressed = !gzdirect(context); -#else - if (((z_stream *)context)->avail_in > 4) { - char *cptr, buff4[4]; - cptr = (char *) ((z_stream *)context)->next_in; - if (gzread(context, buff4, 4) == 4) { - if (strncmp(buff4, cptr, 4) == 0) - ret->compressed = 0; - else - ret->compressed = 1; - gzrewind(context); - } - } -#endif - } -#endif -#ifdef LIBXML_LZMA_ENABLED - if ((xmlInputCallbackTable[i].opencallback == xmlXzfileOpen) && - (strcmp(URI, "-") != 0)) { - ret->compressed = __libxml2_xzcompressed(context); - } -#endif - } - else - xmlInputCallbackTable[i].closecallback (context); + *out = buf; + return(ret); +} + +xmlParserInputBufferPtr +__xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) { + xmlParserInputBufferPtr ret;
+ xmlParserInputBufferCreateFilenameInt(URI, enc, &ret); return(ret); }
@@ -2521,7 +1670,6 @@ __xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) { * @enc: the charset encoding if known * * Create a buffered parser input for the progressive parsing of a file - * If filename is "-' then we use stdin as the input. * Automatic support for ZLIB/Compress compressed document is provided * by default if found at compile-time. * Do an encoding check if enc == XML_CHAR_ENCODING_NONE @@ -2530,135 +1678,106 @@ __xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) { */ xmlParserInputBufferPtr xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) { - if ((xmlParserInputBufferCreateFilenameValue)) { - return xmlParserInputBufferCreateFilenameValue(URI, enc); - } - return __xmlParserInputBufferCreateFilename(URI, enc); + if (xmlParserInputBufferCreateFilenameValue != NULL) + return(xmlParserInputBufferCreateFilenameValue(URI, enc)); + + return(__xmlParserInputBufferCreateFilename(URI, enc)); +} + +/** + * xmlParserInputBufferCreateFilenameSafe: + * @URI: the filename or URI + * @enc: encoding enum (deprecated) + * @out: pointer to resulting input buffer + * + * Create an input buffer for a filename or URI. + * + * Returns an xmlParserErrors code. + */ +int +xmlParserInputBufferCreateFilenameSafe(const char *URI, xmlCharEncoding enc, + xmlParserInputBufferPtr *out) { + if (xmlParserInputBufferCreateFilenameValue != NULL) { + *out = xmlParserInputBufferCreateFilenameValue(URI, enc); + + if (*out == NULL) + return(XML_IO_ENOENT); + return(XML_ERR_OK); + } + + return(xmlParserInputBufferCreateFilenameInt(URI, enc, out)); }
#ifdef LIBXML_OUTPUT_ENABLED xmlOutputBufferPtr __xmlOutputBufferCreateFilename(const char *URI, xmlCharEncodingHandlerPtr encoder, - int compression ATTRIBUTE_UNUSED) { + int compression) { xmlOutputBufferPtr ret; xmlURIPtr puri; int i = 0; - void *context = NULL; char *unescaped = NULL; -#ifdef LIBXML_ZLIB_ENABLED - int is_file_uri = 1; -#endif
- if (xmlOutputCallbackInitialized == 0) - xmlRegisterDefaultOutputCallbacks(); + xmlInitParser();
- if (URI == NULL) return(NULL); + if (URI == NULL) + return(NULL);
puri = xmlParseURI(URI); if (puri != NULL) { -#ifdef LIBXML_ZLIB_ENABLED - if ((puri->scheme != NULL) && - (!xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file"))) - is_file_uri = 0; -#endif - /* - * try to limit the damages of the URI unescaping code. - */ - if ((puri->scheme == NULL) || - (xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file"))) - unescaped = xmlURIUnescapeString(URI, 0, NULL); - xmlFreeURI(puri); + /* + * try to limit the damages of the URI unescaping code. + */ + if (puri->scheme == NULL) { + unescaped = xmlURIUnescapeString(URI, 0, NULL); + if (unescaped == NULL) { + xmlFreeURI(puri); + return(NULL); + } + URI = unescaped; + } + xmlFreeURI(puri); }
/* - * Try to find one of the output accept method accepting that scheme - * Go in reverse to give precedence to user defined handlers. - * try with an unescaped version of the URI + * Allocate the Output buffer front-end. */ - if (unescaped != NULL) { -#ifdef LIBXML_ZLIB_ENABLED - if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) { - context = xmlGzfileOpenW(unescaped, compression); - if (context != NULL) { - ret = xmlAllocOutputBufferInternal(encoder); - if (ret != NULL) { - ret->context = context; - ret->writecallback = xmlGzfileWrite; - ret->closecallback = xmlGzfileClose; - } - xmlFree(unescaped); - return(ret); - } - } -#endif - for (i = xmlOutputCallbackNr - 1;i >= 0;i--) { - if ((xmlOutputCallbackTable[i].matchcallback != NULL) && - (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) { -#if defined(LIBXML_HTTP_ENABLED) && defined(LIBXML_ZLIB_ENABLED) - /* Need to pass compression parameter into HTTP open calls */ - if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch) - context = xmlIOHTTPOpenW(unescaped, compression); - else -#endif - context = xmlOutputCallbackTable[i].opencallback(unescaped); - if (context != NULL) - break; - } - } - xmlFree(unescaped); + ret = xmlAllocOutputBufferInternal(encoder); + if (ret == NULL) { + xmlFree(unescaped); + return(NULL); }
/* - * If this failed try with a non-escaped URI this may be a strange - * filename + * Try to find one of the output accept method accepting that scheme + * Go in reverse to give precedence to user defined handlers. */ - if (context == NULL) { -#ifdef LIBXML_ZLIB_ENABLED - if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) { - context = xmlGzfileOpenW(URI, compression); - if (context != NULL) { - ret = xmlAllocOutputBufferInternal(encoder); - if (ret != NULL) { - ret->context = context; - ret->writecallback = xmlGzfileWrite; - ret->closecallback = xmlGzfileClose; - } - else - xmlGzfileClose(context); - return(ret); - } - } -#endif - for (i = xmlOutputCallbackNr - 1;i >= 0;i--) { - if ((xmlOutputCallbackTable[i].matchcallback != NULL) && - (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) { -#if defined(LIBXML_HTTP_ENABLED) && defined(LIBXML_ZLIB_ENABLED) - /* Need to pass compression parameter into HTTP open calls */ - if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch) - context = xmlIOHTTPOpenW(URI, compression); - else -#endif - context = xmlOutputCallbackTable[i].opencallback(URI); - if (context != NULL) - break; - } - } - } + for (i = xmlOutputCallbackNr - 1; i >= 0; i--) { + xmlOutputCallback *cb = &xmlOutputCallbackTable[i]; + int code;
- if (context == NULL) { - return(NULL); + if (cb->matchcallback == xmlIODefaultMatch) { + code = xmlOutputDefaultOpen(ret, URI, compression); + /* TODO: Handle other errors */ + if (code == XML_ERR_OK) + break; + } else if ((cb->matchcallback != NULL) && + (cb->matchcallback(URI) != 0)) { + ret->context = cb->opencallback(URI); + if (ret->context != NULL) { + ret->writecallback = cb->writecallback; + ret->closecallback = cb->closecallback; + break; + } + } }
- /* - * Allocate the Output buffer front-end. - */ - ret = xmlAllocOutputBufferInternal(encoder); - if (ret != NULL) { - ret->context = context; - ret->writecallback = xmlOutputCallbackTable[i].writecallback; - ret->closecallback = xmlOutputCallbackTable[i].closecallback; + if (ret->context == NULL) { + xmlOutputBufferClose(ret); + ret = NULL; } + + xmlFree(unescaped); return(ret); }
@@ -2691,27 +1810,28 @@ xmlOutputBufferCreateFilename(const char *URI, /** * xmlParserInputBufferCreateFile: * @file: a FILE* - * @enc: the charset encoding if known + * @enc: the charset encoding if known (deprecated) * * Create a buffered parser input for the progressive parsing of a FILE * * buffered C I/O * + * The encoding argument is deprecated and should be set to + * XML_CHAR_ENCODING_NONE. The encoding can be changed with + * xmlSwitchEncoding or xmlSwitchEncodingName later on. + * * Returns the new parser input or NULL */ xmlParserInputBufferPtr xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) { xmlParserInputBufferPtr ret;
- if (xmlInputCallbackInitialized == 0) - xmlRegisterDefaultInputCallbacks(); - if (file == NULL) return(NULL);
ret = xmlAllocParserInputBuffer(enc); if (ret != NULL) { ret->context = file; ret->readcallback = xmlFileRead; - ret->closecallback = xmlFileFlush; + ret->closecallback = NULL; }
return(ret); @@ -2732,9 +1852,6 @@ xmlOutputBufferPtr xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) { xmlOutputBufferPtr ret;
- if (xmlOutputCallbackInitialized == 0) - xmlRegisterDefaultOutputCallbacks(); - if (file == NULL) return(NULL);
ret = xmlAllocOutputBufferInternal(encoder); @@ -2779,7 +1896,7 @@ xmlOutputBufferCreateBuffer(xmlBufferPtr buffer, */ const xmlChar * xmlOutputBufferGetContent(xmlOutputBufferPtr out) { - if ((out == NULL) || (out->buffer == NULL)) + if ((out == NULL) || (out->buffer == NULL) || (out->error != 0)) return(NULL);
return(xmlBufContent(out->buffer)); @@ -2795,7 +1912,7 @@ xmlOutputBufferGetContent(xmlOutputBufferPtr out) { */ size_t xmlOutputBufferGetSize(xmlOutputBufferPtr out) { - if ((out == NULL) || (out->buffer == NULL)) + if ((out == NULL) || (out->buffer == NULL) || (out->error != 0)) return(0);
return(xmlBufUse(out->buffer)); @@ -2807,11 +1924,15 @@ xmlOutputBufferGetSize(xmlOutputBufferPtr out) { /** * xmlParserInputBufferCreateFd: * @fd: a file descriptor number - * @enc: the charset encoding if known + * @enc: the charset encoding if known (deprecated) * * Create a buffered parser input for the progressive parsing for the input * from a file descriptor * + * The encoding argument is deprecated and should be set to + * XML_CHAR_ENCODING_NONE. The encoding can be changed with + * xmlSwitchEncoding or xmlSwitchEncodingName later on. + * * Returns the new parser input or NULL */ xmlParserInputBufferPtr @@ -2824,7 +1945,6 @@ xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) { if (ret != NULL) { ret->context = (void *) (ptrdiff_t) fd; ret->readcallback = xmlFdRead; - ret->closecallback = xmlFdClose; }
return(ret); @@ -2854,17 +1974,71 @@ static int xmlMemClose(void *vctxt) { xmlMemIOCtxt *ctxt = vctxt;
- if (ctxt->mem != 0) + if (ctxt->mem != NULL) xmlFree(ctxt->mem); xmlFree(ctxt); return(0); }
+/** + * xmlNewInputBufferMemory: + * @mem: memory buffer + * @size: size of buffer + * @flags: flags + * @enc: the charset encoding if known (deprecated) + * + * Create an input buffer for memory. + * + * Returns the new input buffer or NULL. + */ +xmlParserInputBufferPtr +xmlNewInputBufferMemory(const void *mem, size_t size, int flags, + xmlCharEncoding enc) { + xmlParserInputBufferPtr ret; + xmlMemIOCtxt *ctxt; + char *copy = NULL; + + if ((flags & XML_INPUT_BUF_STATIC) == 0) { + if (size + 1 == 0) + return(NULL); + copy = xmlMalloc(size + 1); + if (copy == NULL) + return(NULL); + memcpy(copy, mem, size); + copy[size] = 0; + + mem = copy; + } + + ret = xmlAllocParserInputBuffer(enc); + if (ret == NULL) { + xmlFree(copy); + return(NULL); + } + + ctxt = xmlMalloc(sizeof(*ctxt)); + if (ctxt == NULL) { + xmlFreeParserInputBuffer(ret); + xmlFree(copy); + return(NULL); + } + + ctxt->mem = copy; + ctxt->cur = mem; + ctxt->size = size; + + ret->context = ctxt; + ret->readcallback = xmlMemRead; + ret->closecallback = xmlMemClose; + + return(ret); +} + /** * xmlParserInputBufferCreateMem: * @mem: the memory input * @size: the length of the memory block - * @enc: the charset encoding if known + * @enc: the charset encoding if known (deprecated) * * Create a parser input buffer for parsing from a memory area. * @@ -2880,28 +2054,11 @@ xmlMemClose(void *vctxt) { * Returns the new parser input or NULL in case of error. */ xmlParserInputBufferPtr -xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) { - xmlParserInputBufferPtr buf; - xmlMemIOCtxt *ctxt; - char *copy; - - if ((size < 0) || (mem == NULL)) - return(NULL); - - copy = (char *) xmlStrndup((const xmlChar *) mem, size); - if (copy == NULL) - return(NULL); - - buf = xmlParserInputBufferCreateStatic(copy, size, enc); - if (buf == NULL) { - xmlFree(copy); +xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) { + if ((mem == NULL) || (size < 0)) return(NULL); - } - - ctxt = buf->context; - ctxt->mem = copy;
- return(buf); + return(xmlNewInputBufferMemory(mem, size, 0, enc)); }
/** @@ -2925,40 +2082,20 @@ xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) { xmlParserInputBufferPtr xmlParserInputBufferCreateStatic(const char *mem, int size, xmlCharEncoding enc) { - xmlParserInputBufferPtr ret; - xmlMemIOCtxt *ctxt; - - if ((size < 0) || (mem == NULL)) - return(NULL); - - ret = xmlAllocParserInputBuffer(enc); - if (ret == NULL) - return(NULL); - - ctxt = xmlMalloc(sizeof(*ctxt)); - if (ctxt == NULL) { - xmlFreeParserInputBuffer(ret); + if ((mem == NULL) || (size < 0)) return(NULL); - } - ctxt->mem = NULL; - ctxt->cur = mem; - ctxt->size = size; - - ret->context = ctxt; - ret->readcallback = xmlMemRead; - ret->closecallback = xmlMemClose;
- return(ret); + return(xmlNewInputBufferMemory(mem, size, XML_INPUT_BUF_STATIC, enc)); }
typedef struct { - const xmlChar *str; + const char *str; } xmlStringIOCtxt;
static int xmlStringRead(void *vctxt, char *buf, int size) { xmlStringIOCtxt *ctxt = vctxt; - const xmlChar *zero; + const char *zero; size_t len;
zero = memchr(ctxt->str, 0, size); @@ -2977,20 +2114,22 @@ xmlStringClose(void *vctxt) { }
/** - * xmlParserInputBufferCreateString: - * @str: a null-terminated string + * xmlNewInputBufferString: + * @str: C string + * @flags: flags * - * Create a buffered parser input for the progressive parsing for the input - * from a null-terminated C string. + * Create an input buffer for a null-teriminated C string. * - * Returns the new parser input or NULL + * Returns the new input buffer or NULL. */ xmlParserInputBufferPtr -xmlParserInputBufferCreateString(const xmlChar *str) { +xmlNewInputBufferString(const char *str, int flags) { xmlParserInputBufferPtr ret; xmlStringIOCtxt *ctxt;
- if (str == NULL) return(NULL); + if ((flags & XML_INPUT_BUF_STATIC) == 0) + return(xmlNewInputBufferMemory(str, strlen(str), flags, + XML_CHAR_ENCODING_NONE));
ret = xmlAllocParserInputBuffer(XML_CHAR_ENCODING_NONE); if (ret == NULL) @@ -3001,6 +2140,7 @@ xmlParserInputBufferCreateString(const xmlChar *str) { xmlFreeParserInputBuffer(ret); return(NULL); } + ctxt->str = str;
ret->context = ctxt; @@ -3043,11 +2183,15 @@ xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) { * @ioread: an I/O read function * @ioclose: an I/O close function * @ioctx: an I/O handler - * @enc: the charset encoding if known + * @enc: the charset encoding if known (deprecated) * * Create a buffered parser input for the progressive parsing for the input * from an I/O handler * + * The encoding argument is deprecated and should be set to + * XML_CHAR_ENCODING_NONE. The encoding can be changed with + * xmlSwitchEncoding or xmlSwitchEncodingName later on. + * * Returns the new parser input or NULL */ xmlParserInputBufferPtr @@ -3108,13 +2252,17 @@ xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite, * Returns the old value of the registration function */ xmlParserInputBufferCreateFilenameFunc -xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func) +xmlParserInputBufferCreateFilenameDefault( + xmlParserInputBufferCreateFilenameFunc func) { - xmlParserInputBufferCreateFilenameFunc old = xmlParserInputBufferCreateFilenameValue; - if (old == NULL) { - old = __xmlParserInputBufferCreateFilename; - } + xmlParserInputBufferCreateFilenameFunc old;
+ old = xmlParserInputBufferCreateFilenameValue; + if (old == NULL) + old = __xmlParserInputBufferCreateFilename; + + if (func == __xmlParserInputBufferCreateFilename) + func = NULL; xmlParserInputBufferCreateFilenameValue = func; return(old); } @@ -3256,7 +2404,10 @@ xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) { if (res <= 0) in->readcallback = endOfInput; if (res < 0) { - in->error = XML_IO_UNKNOWN; + if (res == -1) + in->error = XML_IO_UNKNOWN; + else + in->error = -res; return(-1); }
@@ -3341,10 +2492,16 @@ xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) { */ if (out->conv == NULL) { out->conv = xmlBufCreate(); + if (out->conv == NULL) { + out->error = XML_ERR_NO_MEMORY; + return(-1); + } } ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk); - if (ret != 0) + if (ret != 0) { + out->error = XML_ERR_NO_MEMORY; return(-1); + }
if ((xmlBufUse(out->buffer) < MINLEN) && (chunk == len)) goto done; @@ -3353,19 +2510,18 @@ xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) { * convert as much as possible to the parser reading buffer. */ ret = xmlCharEncOutput(out, 0); - if ((ret < 0) && (ret != -3)) { - xmlIOErr(XML_IO_ENCODER, NULL); - out->error = XML_IO_ENCODER; + if (ret < 0) return(-1); - } if (out->writecallback) nbchars = xmlBufUse(out->conv); else nbchars = ret >= 0 ? ret : 0; } else { ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk); - if (ret != 0) + if (ret != 0) { + out->error = XML_ERR_NO_MEMORY; return(-1); + } if (out->writecallback) nbchars = xmlBufUse(out->buffer); else @@ -3393,8 +2549,10 @@ xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) { xmlBufShrink(out->buffer, ret); } if (ret < 0) { - xmlIOErr(XML_IO_WRITE, NULL); - out->error = XML_IO_WRITE; + int errNo = (ret == -1) ? XML_IO_WRITE : -ret; + + xmlIOErr(errNo, NULL); + out->error = errNo; return(ret); } if (out->written > INT_MAX - ret) @@ -3517,8 +2675,10 @@ xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str, * not the case force a flush, but make sure we stay in the loop */ if (chunk < 40) { - if (xmlBufGrow(out->buffer, 100) < 0) + if (xmlBufGrow(out->buffer, 100) < 0) { + out->error = XML_ERR_NO_MEMORY; return(-1); + } oldwritten = -1; continue; } @@ -3532,11 +2692,17 @@ xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str, */ if (out->conv == NULL) { out->conv = xmlBufCreate(); + if (out->conv == NULL) { + out->error = XML_ERR_NO_MEMORY; + return(-1); + } } ret = escaping(xmlBufEnd(out->buffer) , &chunk, str, &cons); - if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */ - return(-1); + if (ret < 0) { + out->error = XML_ERR_NO_MEMORY; + return(-1); + } xmlBufAddLen(out->buffer, chunk);
if ((xmlBufUse(out->buffer) < MINLEN) && (cons == len)) @@ -3546,19 +2712,18 @@ xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str, * convert as much as possible to the output buffer. */ ret = xmlCharEncOutput(out, 0); - if ((ret < 0) && (ret != -3)) { - xmlIOErr(XML_IO_ENCODER, NULL); - out->error = XML_IO_ENCODER; + if (ret < 0) return(-1); - } if (out->writecallback) nbchars = xmlBufUse(out->conv); else nbchars = ret >= 0 ? ret : 0; } else { ret = escaping(xmlBufEnd(out->buffer), &chunk, str, &cons); - if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */ - return(-1); + if (ret < 0) { + out->error = XML_ERR_NO_MEMORY; + return(-1); + } xmlBufAddLen(out->buffer, chunk); if (out->writecallback) nbchars = xmlBufUse(out->buffer); @@ -3587,16 +2752,20 @@ xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str, xmlBufShrink(out->buffer, ret); } if (ret < 0) { - xmlIOErr(XML_IO_WRITE, NULL); - out->error = XML_IO_WRITE; - return(ret); + int errNo = (ret == -1) ? XML_IO_WRITE : -ret; + xmlIOErr(errNo, NULL); + out->error = errNo; + return(-1); } if (out->written > INT_MAX - ret) out->written = INT_MAX; else out->written += ret; } else if (xmlBufAvail(out->buffer) < MINLEN) { - xmlBufGrow(out->buffer, MINLEN); + if (xmlBufGrow(out->buffer, MINLEN) < 0) { + out->error = XML_ERR_NO_MEMORY; + return(-1); + } } written += nbchars; } while ((len > 0) && (oldwritten != written)); @@ -3632,6 +2801,56 @@ xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) { return(len); }
+/** + * xmlOutputBufferWriteQuotedString: + * @buf: output buffer + * @string: the string to add + * + * routine which manage and grows an output buffer. This one writes + * a quoted or double quoted #xmlChar string, checking first if it holds + * quote or double-quotes internally + */ +void +xmlOutputBufferWriteQuotedString(xmlOutputBufferPtr buf, + const xmlChar *string) { + const xmlChar *cur, *base; + + if ((buf == NULL) || (buf->error)) + return; + + if (xmlStrchr(string, '"')) { + if (xmlStrchr(string, ''')) { + xmlOutputBufferWrite(buf, 1, """); + base = cur = string; + while(*cur != 0){ + if(*cur == '"'){ + if (base != cur) + xmlOutputBufferWrite(buf, cur - base, + (const char *) base); + xmlOutputBufferWrite(buf, 6, """); + cur++; + base = cur; + } + else { + cur++; + } + } + if (base != cur) + xmlOutputBufferWrite(buf, cur - base, (const char *) base); + xmlOutputBufferWrite(buf, 1, """); + } + else{ + xmlOutputBufferWrite(buf, 1, "'"); + xmlOutputBufferWriteString(buf, (const char *) string); + xmlOutputBufferWrite(buf, 1, "'"); + } + } else { + xmlOutputBufferWrite(buf, 1, """); + xmlOutputBufferWriteString(buf, (const char *) string); + xmlOutputBufferWrite(buf, 1, """); + } +} + /** * xmlOutputBufferFlush: * @out: a buffered output @@ -3654,11 +2873,8 @@ xmlOutputBufferFlush(xmlOutputBufferPtr out) { */ do { nbchars = xmlCharEncOutput(out, 0); - if (nbchars < 0) { - xmlIOErr(XML_IO_ENCODER, NULL); - out->error = XML_IO_ENCODER; + if (nbchars < 0) return(-1); - } } while (nbchars); }
@@ -3680,8 +2896,10 @@ xmlOutputBufferFlush(xmlOutputBufferPtr out) { xmlBufShrink(out->buffer, ret); } if (ret < 0) { - xmlIOErr(XML_IO_FLUSH, NULL); - out->error = XML_IO_FLUSH; + int errNo = (ret == -1) ? XML_IO_WRITE : -ret; + + xmlIOErr(errNo, NULL); + out->error = errNo; return(ret); } if (out->written > INT_MAX - ret) @@ -3707,9 +2925,6 @@ xmlParserGetDirectory(const char *filename) { char dir[1024]; char *cur;
- if (xmlInputCallbackInitialized == 0) - xmlRegisterDefaultInputCallbacks(); - if (filename == NULL) return(NULL);
#if defined(_WIN32) @@ -3730,340 +2945,219 @@ xmlParserGetDirectory(const char *filename) { else *cur = 0; ret = xmlMemStrdup(dir); } else { - if (getcwd(dir, 1024) != NULL) { - dir[1023] = 0; - ret = xmlMemStrdup(dir); - } + ret = xmlMemStrdup("."); } return(ret); #undef IS_XMLPGD_SEP }
-/**************************************************************** - * * - * External entities loading * - * * - ****************************************************************/ - /** - * xmlCheckHTTPInput: - * @ctxt: an XML parser context - * @ret: an XML parser input + * xmlNoNetExists: + * @filename: the path to check + * + * DEPRECATED: Internal function, don't use. * - * Check an input in case it was created from an HTTP stream, in that - * case it will handle encoding and update of the base URL in case of - * redirection. It also checks for HTTP errors in which case the input - * is cleanly freed up and an appropriate error is raised in context + * Like xmlCheckFilename but handles file URIs. * - * Returns the input or NULL in case of HTTP error. + * Returns 0, 1, or 2. */ -xmlParserInputPtr -xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) { - /* Avoid unused variable warning if features are disabled. */ - (void) ctxt; +int +xmlNoNetExists(const char *filename) { + char *fromUri; + int ret;
-#ifdef LIBXML_HTTP_ENABLED - if ((ret != NULL) && (ret->buf != NULL) && - (ret->buf->readcallback == xmlIOHTTPRead) && - (ret->buf->context != NULL)) { - const char *encoding; - const char *redir; - const char *mime; - int code; + if (filename == NULL) + return(0);
- code = xmlNanoHTTPReturnCode(ret->buf->context); - if (code >= 400) { - /* fatal error */ - if (ret->filename != NULL) - __xmlLoaderErr(ctxt, "failed to load HTTP resource "%s"\n", - (const char *) ret->filename); - else - __xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL); - xmlFreeInputStream(ret); - ret = NULL; - } else { + if (xmlConvertUriToPath(filename, &fromUri) < 0) + return(0);
- mime = xmlNanoHTTPMimeType(ret->buf->context); - if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) || - (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) { - encoding = xmlNanoHTTPEncoding(ret->buf->context); - if (encoding != NULL) { - xmlCharEncodingHandlerPtr handler; - - handler = xmlFindCharEncodingHandler(encoding); - if (handler != NULL) { - xmlSwitchInputEncoding(ctxt, ret, handler); - } else { - __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING, - "Unknown encoding %s", - BAD_CAST encoding, NULL); - } - } -#if 0 - } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) { -#endif - } - redir = xmlNanoHTTPRedir(ret->buf->context); - if (redir != NULL) { - if (ret->filename != NULL) - xmlFree((xmlChar *) ret->filename); - if (ret->directory != NULL) { - xmlFree((xmlChar *) ret->directory); - ret->directory = NULL; - } - ret->filename = - (char *) xmlStrdup((const xmlChar *) redir); - } - } - } -#endif + if (fromUri != NULL) + filename = fromUri; + + ret = xmlCheckFilename(filename); + + xmlFree(fromUri); return(ret); }
-static int xmlNoNetExists(const char *URL) { - const char *path; +/************************************************************************ + * * + * Input/output callbacks * + * * + ************************************************************************/
- if (URL == NULL) - return(0); +/** + * xmlInitIOCallbacks: + * + * Initialize callback tables. + */ +void +xmlInitIOCallbacks(void) +{ + xmlInputCallbackNr = 1; + xmlInputCallbackTable[0].matchcallback = xmlIODefaultMatch;
- if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17)) -#if defined (_WIN32) - path = &URL[17]; -#else - path = &URL[16]; -#endif - else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) { -#if defined (_WIN32) - path = &URL[8]; -#else - path = &URL[7]; +#ifdef LIBXML_OUTPUT_ENABLED + xmlOutputCallbackNr = 1; + xmlOutputCallbackTable[0].matchcallback = xmlIODefaultMatch; #endif - } else - path = URL; - - return xmlCheckFilename(path); }
-#ifdef LIBXML_CATALOG_ENABLED - /** - * xmlResolveResourceFromCatalog: - * @URL: the URL for the entity to load - * @ID: the System ID for the entity to load - * @ctxt: the context in which the entity is called or NULL + * xmlRegisterInputCallbacks: + * @matchFunc: the xmlInputMatchCallback + * @openFunc: the xmlInputOpenCallback + * @readFunc: the xmlInputReadCallback + * @closeFunc: the xmlInputCloseCallback * - * Resolves the URL and ID against the appropriate catalog. - * This function is used by xmlDefaultExternalEntityLoader and - * xmlNoNetExternalEntityLoader. + * Register a new set of I/O callback for handling parser input. * - * Returns a new allocated URL, or NULL. + * Returns the registered handler number or -1 in case of error */ -static xmlChar * -xmlResolveResourceFromCatalog(const char *URL, const char *ID, - xmlParserCtxtPtr ctxt) { - xmlChar *resource = NULL; - xmlCatalogAllow pref; - - /* - * If the resource doesn't exists as a file, - * try to load it from the resource pointed in the catalogs - */ - pref = xmlCatalogGetDefaults(); - - if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) { - /* - * Do a local lookup - */ - if ((ctxt != NULL) && (ctxt->catalogs != NULL) && - ((pref == XML_CATA_ALLOW_ALL) || - (pref == XML_CATA_ALLOW_DOCUMENT))) { - resource = xmlCatalogLocalResolve(ctxt->catalogs, - (const xmlChar *)ID, - (const xmlChar *)URL); - } - /* - * Try a global lookup - */ - if ((resource == NULL) && - ((pref == XML_CATA_ALLOW_ALL) || - (pref == XML_CATA_ALLOW_GLOBAL))) { - resource = xmlCatalogResolve((const xmlChar *)ID, - (const xmlChar *)URL); - } - if ((resource == NULL) && (URL != NULL)) - resource = xmlStrdup((const xmlChar *) URL); - - /* - * TODO: do an URI lookup on the reference - */ - if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) { - xmlChar *tmp = NULL; - - if ((ctxt != NULL) && (ctxt->catalogs != NULL) && - ((pref == XML_CATA_ALLOW_ALL) || - (pref == XML_CATA_ALLOW_DOCUMENT))) { - tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource); - } - if ((tmp == NULL) && - ((pref == XML_CATA_ALLOW_ALL) || - (pref == XML_CATA_ALLOW_GLOBAL))) { - tmp = xmlCatalogResolveURI(resource); - } +int +xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc, + xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc, + xmlInputCloseCallback closeFunc) { + xmlInitParser();
- if (tmp != NULL) { - xmlFree(resource); - resource = tmp; - } - } + if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) { + return(-1); } - - return resource; + xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc; + xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc; + xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc; + xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc; + return(xmlInputCallbackNr++); }
-#endif +/** + * xmlRegisterDefaultInputCallbacks: + * + * Registers the default compiled-in I/O handlers. + */ +void +xmlRegisterDefaultInputCallbacks(void) { + xmlRegisterInputCallbacks(xmlIODefaultMatch, NULL, NULL, NULL); +}
/** - * xmlDefaultExternalEntityLoader: - * @URL: the URL for the entity to load - * @ID: the System ID for the entity to load - * @ctxt: the context in which the entity is called or NULL + * xmlPopInputCallbacks: * - * By default we don't load external entities, yet. + * Clear the top input callback from the input stack. this includes the + * compiled-in I/O. * - * Returns a new allocated xmlParserInputPtr, or NULL. + * Returns the number of input callback registered or -1 in case of error. */ -static xmlParserInputPtr -xmlDefaultExternalEntityLoader(const char *URL, const char *ID, - xmlParserCtxtPtr ctxt) +int +xmlPopInputCallbacks(void) { - xmlParserInputPtr ret = NULL; - xmlChar *resource = NULL; + xmlInitParser();
- if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) { - int options = ctxt->options; - - ctxt->options -= XML_PARSE_NONET; - ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt); - ctxt->options = options; - return(ret); - } -#ifdef LIBXML_CATALOG_ENABLED - resource = xmlResolveResourceFromCatalog(URL, ID, ctxt); -#endif + if (xmlInputCallbackNr <= 0) + return(-1);
- if (resource == NULL) - resource = (xmlChar *) URL; + xmlInputCallbackNr--;
- if (resource == NULL) { - if (ID == NULL) - ID = "NULL"; - __xmlLoaderErr(ctxt, "failed to load external entity "%s"\n", ID); - return (NULL); - } - ret = xmlNewInputFromFile(ctxt, (const char *) resource); - if ((resource != NULL) && (resource != (xmlChar *) URL)) - xmlFree(resource); - return (ret); + return(xmlInputCallbackNr); }
-static xmlExternalEntityLoader xmlCurrentExternalEntityLoader = - xmlDefaultExternalEntityLoader; - /** - * xmlSetExternalEntityLoader: - * @f: the new entity resolver function + * xmlCleanupInputCallbacks: * - * Changes the defaultexternal entity resolver function for the application + * clears the entire input callback table. this includes the + * compiled-in I/O. */ void -xmlSetExternalEntityLoader(xmlExternalEntityLoader f) { - xmlCurrentExternalEntityLoader = f; +xmlCleanupInputCallbacks(void) +{ + xmlInitParser(); + + xmlInputCallbackNr = 0; }
+#ifdef LIBXML_OUTPUT_ENABLED /** - * xmlGetExternalEntityLoader: + * xmlRegisterOutputCallbacks: + * @matchFunc: the xmlOutputMatchCallback + * @openFunc: the xmlOutputOpenCallback + * @writeFunc: the xmlOutputWriteCallback + * @closeFunc: the xmlOutputCloseCallback * - * Get the default external entity resolver function for the application + * Register a new set of I/O callback for handling output. + * + * Returns the registered handler number or -1 in case of error + */ +int +xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc, + xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc, + xmlOutputCloseCallback closeFunc) { + xmlInitParser(); + + if (xmlOutputCallbackNr >= MAX_OUTPUT_CALLBACK) { + return(-1); + } + xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc; + xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc; + xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc; + xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc; + return(xmlOutputCallbackNr++); +} + +/** + * xmlRegisterDefaultOutputCallbacks: * - * Returns the xmlExternalEntityLoader function pointer + * Registers the default compiled-in I/O handlers. */ -xmlExternalEntityLoader -xmlGetExternalEntityLoader(void) { - return(xmlCurrentExternalEntityLoader); +void +xmlRegisterDefaultOutputCallbacks (void) { + xmlRegisterOutputCallbacks(xmlIODefaultMatch, NULL, NULL, NULL); }
/** - * xmlLoadExternalEntity: - * @URL: the URL for the entity to load - * @ID: the Public ID for the entity to load - * @ctxt: the context in which the entity is called or NULL + * xmlPopOutputCallbacks: * - * Load an external entity, note that the use of this function for - * unparsed entities may generate problems + * Remove the top output callbacks from the output stack. This includes the + * compiled-in I/O. * - * Returns the xmlParserInputPtr or NULL + * Returns the number of output callback registered or -1 in case of error. */ -xmlParserInputPtr -xmlLoadExternalEntity(const char *URL, const char *ID, - xmlParserCtxtPtr ctxt) { - if ((URL != NULL) && (xmlNoNetExists(URL) == 0)) { - char *canonicFilename; - xmlParserInputPtr ret; +int +xmlPopOutputCallbacks(void) +{ + xmlInitParser();
- canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL); - if (canonicFilename == NULL) { - xmlErrMemory(ctxt, "building canonical path\n"); - return(NULL); - } + if (xmlOutputCallbackNr <= 0) + return(-1);
- ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt); - xmlFree(canonicFilename); - return(ret); - } - return(xmlCurrentExternalEntityLoader(URL, ID, ctxt)); -} + xmlOutputCallbackNr--;
-/************************************************************************ - * * - * Disabling Network access * - * * - ************************************************************************/ + return(xmlOutputCallbackNr); +}
/** - * xmlNoNetExternalEntityLoader: - * @URL: the URL for the entity to load - * @ID: the System ID for the entity to load - * @ctxt: the context in which the entity is called or NULL - * - * A specific entity loader disabling network accesses, though still - * allowing local catalog accesses for resolution. + * xmlCleanupOutputCallbacks: * - * Returns a new allocated xmlParserInputPtr, or NULL. + * clears the entire output callback table. this includes the + * compiled-in I/O callbacks. */ -xmlParserInputPtr -xmlNoNetExternalEntityLoader(const char *URL, const char *ID, - xmlParserCtxtPtr ctxt) { - xmlParserInputPtr input = NULL; - xmlChar *resource = NULL; - -#ifdef LIBXML_CATALOG_ENABLED - resource = xmlResolveResourceFromCatalog(URL, ID, ctxt); -#endif +void +xmlCleanupOutputCallbacks(void) +{ + xmlInitParser();
- if (resource == NULL) - resource = (xmlChar *) URL; + xmlOutputCallbackNr = 0; +}
- if (resource != NULL) { - if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) || - (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) { - xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource); - if (resource != (xmlChar *) URL) - xmlFree(resource); - return(NULL); - } - } - input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt); - if (resource != (xmlChar *) URL) - xmlFree(resource); - return(input); +#ifdef LIBXML_HTTP_ENABLED +/** + * xmlRegisterHTTPPostCallbacks: + * + * DEPRECATED: Support for HTTP POST has been removed. + */ +void +xmlRegisterHTTPPostCallbacks(void) { + xmlRegisterDefaultOutputCallbacks(); } +#endif +#endif /* LIBXML_OUTPUT_ENABLED */ diff --git a/libs/xml2/xmlmemory.c b/libs/xml2/xmlmemory.c index d8cb18aaa6a..9ba8714dd79 100644 --- a/libs/xml2/xmlmemory.c +++ b/libs/xml2/xmlmemory.c @@ -12,18 +12,6 @@ #include <ctype.h> #include <time.h>
-/** - * MEM_LIST: - * - * keep track of all allocated blocks for error reporting - * Always build the memory list ! - */ -#ifdef DEBUG_MEMORY_LOCATION -#ifndef MEM_LIST -#define MEM_LIST /* keep a list of all the allocated memory blocks */ -#endif -#endif - #include <libxml/xmlmemory.h> #include <libxml/xmlerror.h> #include <libxml/parser.h> @@ -34,62 +22,31 @@
static unsigned long debugMemSize = 0; static unsigned long debugMemBlocks = 0; -static unsigned long debugMaxMemSize = 0; static xmlMutex xmlMemMutex;
-void xmlMallocBreakpoint(void); - /************************************************************************ * * * Macros, variables and associated types * * * ************************************************************************/
-#if !defined(LIBXML_THREAD_ENABLED) && !defined(LIBXML_THREAD_ALLOC_ENABLED) -#ifdef xmlMalloc -#undef xmlMalloc -#endif -#ifdef xmlRealloc -#undef xmlRealloc -#endif -#ifdef xmlMemStrdup -#undef xmlMemStrdup -#endif -#endif - /* * Each of the blocks allocated begin with a header containing information */
#define MEMTAG 0x5aa5U
-#define MALLOC_TYPE 1 -#define REALLOC_TYPE 2 -#define STRDUP_TYPE 3 -#define MALLOC_ATOMIC_TYPE 4 -#define REALLOC_ATOMIC_TYPE 5 - typedef struct memnod { unsigned int mh_tag; - unsigned int mh_type; - unsigned long mh_number; size_t mh_size; -#ifdef MEM_LIST - struct memnod *mh_next; - struct memnod *mh_prev; -#endif - const char *mh_file; - unsigned int mh_line; -} MEMHDR; - +} MEMHDR;
#ifdef SUN4 #define ALIGN_SIZE 16 #else #define ALIGN_SIZE sizeof(double) #endif -#define HDR_SIZE sizeof(MEMHDR) -#define RESERVE_SIZE (((HDR_SIZE + (ALIGN_SIZE-1)) \ +#define RESERVE_SIZE (((sizeof(MEMHDR) + ALIGN_SIZE - 1) \ / ALIGN_SIZE ) * ALIGN_SIZE)
#define MAX_SIZE_T ((size_t)-1) @@ -97,102 +54,21 @@ typedef struct memnod { #define CLIENT_2_HDR(a) ((void *) (((char *) (a)) - RESERVE_SIZE)) #define HDR_2_CLIENT(a) ((void *) (((char *) (a)) + RESERVE_SIZE))
- -static unsigned int block=0; -static unsigned int xmlMemStopAtBlock = 0; -static void *xmlMemTraceBlockAt = NULL; -#ifdef MEM_LIST -static MEMHDR *memlist = NULL; -#endif - -static void debugmem_tag_error(void *addr); -#ifdef MEM_LIST -static void debugmem_list_add(MEMHDR *); -static void debugmem_list_delete(MEMHDR *); -#endif -#define Mem_Tag_Err(a) debugmem_tag_error(a); - -#ifndef TEST_POINT -#define TEST_POINT -#endif - -/** - * xmlMallocBreakpoint: - * - * Breakpoint to use in conjunction with xmlMemStopAtBlock. When the block - * number reaches the specified value this function is called. One need to add a breakpoint - * to it to get the context in which the given block is allocated. - */ - -void -xmlMallocBreakpoint(void) { - xmlGenericError(xmlGenericErrorContext, - "xmlMallocBreakpoint reached on block %d\n", xmlMemStopAtBlock); -} - /** * xmlMallocLoc: * @size: an int specifying the size in byte to allocate. * @file: the file name or NULL * @line: the line number * - * a malloc() equivalent, with logging of the allocation info. + * DEPRECATED: don't use * * Returns a pointer to the allocated area or NULL in case of lack of memory. */ - void * -xmlMallocLoc(size_t size, const char * file, int line) +xmlMallocLoc(size_t size, const char *file ATTRIBUTE_UNUSED, + int line ATTRIBUTE_UNUSED) { - MEMHDR *p; - void *ret; - - xmlInitParser(); - - TEST_POINT - - if (size > (MAX_SIZE_T - RESERVE_SIZE)) { - xmlGenericError(xmlGenericErrorContext, - "xmlMallocLoc : Unsigned overflow\n"); - return(NULL); - } - - p = (MEMHDR *) malloc(RESERVE_SIZE+size); - - if (!p) { - xmlGenericError(xmlGenericErrorContext, - "xmlMallocLoc : Out of free space\n"); - return(NULL); - } - p->mh_tag = MEMTAG; - p->mh_size = size; - p->mh_type = MALLOC_TYPE; - p->mh_file = file; - p->mh_line = line; - xmlMutexLock(&xmlMemMutex); - p->mh_number = ++block; - debugMemSize += size; - debugMemBlocks++; - if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize; -#ifdef MEM_LIST - debugmem_list_add(p); -#endif - xmlMutexUnlock(&xmlMemMutex); - - if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint(); - - ret = HDR_2_CLIENT(p); - - if (xmlMemTraceBlockAt == ret) { - xmlGenericError(xmlGenericErrorContext, - "%p : Malloc(%lu) Ok\n", xmlMemTraceBlockAt, - (long unsigned)size); - xmlMallocBreakpoint(); - } - - TEST_POINT - - return(ret); + return(xmlMemMalloc(size)); }
/** @@ -201,174 +77,119 @@ xmlMallocLoc(size_t size, const char * file, int line) * @file: the file name or NULL * @line: the line number * - * a malloc() equivalent, with logging of the allocation info. + * DEPRECATED: don't use * * Returns a pointer to the allocated area or NULL in case of lack of memory. */ +void * +xmlMallocAtomicLoc(size_t size, const char *file ATTRIBUTE_UNUSED, + int line ATTRIBUTE_UNUSED) +{ + return(xmlMemMalloc(size)); +}
+/** + * xmlMemMalloc: + * @size: an int specifying the size in byte to allocate. + * + * a malloc() equivalent, with logging of the allocation info. + * + * Returns a pointer to the allocated area or NULL in case of lack of memory. + */ void * -xmlMallocAtomicLoc(size_t size, const char * file, int line) +xmlMemMalloc(size_t size) { MEMHDR *p; - void *ret;
xmlInitParser();
- TEST_POINT - if (size > (MAX_SIZE_T - RESERVE_SIZE)) { - xmlGenericError(xmlGenericErrorContext, - "xmlMallocAtomicLoc : Unsigned overflow\n"); - return(NULL); + fprintf(stderr, "xmlMemMalloc: Unsigned overflow\n"); + return(NULL); }
- p = (MEMHDR *) malloc(RESERVE_SIZE+size); - + p = (MEMHDR *) malloc(RESERVE_SIZE + size); if (!p) { - xmlGenericError(xmlGenericErrorContext, - "xmlMallocAtomicLoc : Out of free space\n"); - return(NULL); + fprintf(stderr, "xmlMemMalloc: Out of memory\n"); + return(NULL); } p->mh_tag = MEMTAG; p->mh_size = size; - p->mh_type = MALLOC_ATOMIC_TYPE; - p->mh_file = file; - p->mh_line = line; + xmlMutexLock(&xmlMemMutex); - p->mh_number = ++block; debugMemSize += size; debugMemBlocks++; - if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize; -#ifdef MEM_LIST - debugmem_list_add(p); -#endif xmlMutexUnlock(&xmlMemMutex);
- if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint(); - - ret = HDR_2_CLIENT(p); - - if (xmlMemTraceBlockAt == ret) { - xmlGenericError(xmlGenericErrorContext, - "%p : Malloc(%lu) Ok\n", xmlMemTraceBlockAt, - (long unsigned)size); - xmlMallocBreakpoint(); - } - - TEST_POINT - - return(ret); + return(HDR_2_CLIENT(p)); } + /** - * xmlMemMalloc: + * xmlReallocLoc: + * @ptr: the initial memory block pointer * @size: an int specifying the size in byte to allocate. + * @file: the file name or NULL + * @line: the line number * - * a malloc() equivalent, with logging of the allocation info. + * DEPRECATED: don't use * * Returns a pointer to the allocated area or NULL in case of lack of memory. */ - void * -xmlMemMalloc(size_t size) +xmlReallocLoc(void *ptr, size_t size, const char *file ATTRIBUTE_UNUSED, + int line ATTRIBUTE_UNUSED) { - return(xmlMallocLoc(size, "none", 0)); + return(xmlMemRealloc(ptr, size)); }
/** - * xmlReallocLoc: + * xmlMemRealloc: * @ptr: the initial memory block pointer * @size: an int specifying the size in byte to allocate. - * @file: the file name or NULL - * @line: the line number * * a realloc() equivalent, with logging of the allocation info. * * Returns a pointer to the allocated area or NULL in case of lack of memory. */ - void * -xmlReallocLoc(void *ptr,size_t size, const char * file, int line) -{ +xmlMemRealloc(void *ptr, size_t size) { MEMHDR *p, *tmp; - unsigned long number; + size_t oldSize;
if (ptr == NULL) - return(xmlMallocLoc(size, file, line)); + return(xmlMemMalloc(size));
xmlInitParser(); - TEST_POINT + + if (size > (MAX_SIZE_T - RESERVE_SIZE)) { + fprintf(stderr, "xmlMemRealloc: Unsigned overflow\n"); + return(NULL); + }
p = CLIENT_2_HDR(ptr); - number = p->mh_number; - if (xmlMemStopAtBlock == number) xmlMallocBreakpoint(); if (p->mh_tag != MEMTAG) { - Mem_Tag_Err(p); - goto error; + fprintf(stderr, "xmlMemRealloc: Tag error\n"); + return(NULL); } + oldSize = p->mh_size; p->mh_tag = ~MEMTAG; - xmlMutexLock(&xmlMemMutex); - debugMemSize -= p->mh_size; - debugMemBlocks--; -#ifdef MEM_LIST - debugmem_list_delete(p); -#endif - xmlMutexUnlock(&xmlMemMutex);
- if (size > (MAX_SIZE_T - RESERVE_SIZE)) { - xmlGenericError(xmlGenericErrorContext, - "xmlReallocLoc : Unsigned overflow\n"); - return(NULL); - } - - tmp = (MEMHDR *) realloc(p,RESERVE_SIZE+size); + tmp = (MEMHDR *) realloc(p, RESERVE_SIZE + size); if (!tmp) { - free(p); - goto error; + p->mh_tag = MEMTAG; + fprintf(stderr, "xmlMemRealloc: Out of memory\n"); + return(NULL); } p = tmp; - if (xmlMemTraceBlockAt == ptr) { - xmlGenericError(xmlGenericErrorContext, - "%p : Realloced(%lu -> %lu) Ok\n", - xmlMemTraceBlockAt, (long unsigned)p->mh_size, - (long unsigned)size); - xmlMallocBreakpoint(); - } p->mh_tag = MEMTAG; - p->mh_number = number; - p->mh_type = REALLOC_TYPE; p->mh_size = size; - p->mh_file = file; - p->mh_line = line; + xmlMutexLock(&xmlMemMutex); + debugMemSize -= oldSize; debugMemSize += size; - debugMemBlocks++; - if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize; -#ifdef MEM_LIST - debugmem_list_add(p); -#endif xmlMutexUnlock(&xmlMemMutex);
- TEST_POINT - return(HDR_2_CLIENT(p)); - -error: - return(NULL); -} - -/** - * xmlMemRealloc: - * @ptr: the initial memory block pointer - * @size: an int specifying the size in byte to allocate. - * - * a realloc() equivalent, with logging of the allocation info. - * - * Returns a pointer to the allocated area or NULL in case of lack of memory. - */ - -void * -xmlMemRealloc(void *ptr,size_t size) { - return(xmlReallocLoc(ptr, size, "none", 0)); }
/** @@ -381,53 +202,30 @@ void xmlMemFree(void *ptr) { MEMHDR *p; - char *target;
if (ptr == NULL) - return; + return;
if (ptr == (void *) -1) { - xmlGenericError(xmlGenericErrorContext, - "trying to free pointer from freed area\n"); - goto error; - } - - if (xmlMemTraceBlockAt == ptr) { - xmlGenericError(xmlGenericErrorContext, - "%p : Freed()\n", xmlMemTraceBlockAt); - xmlMallocBreakpoint(); + fprintf(stderr, "xmlMemFree: Pointer from freed area\n"); + return; }
- TEST_POINT - - target = (char *) ptr; - p = CLIENT_2_HDR(ptr); if (p->mh_tag != MEMTAG) { - Mem_Tag_Err(p); - goto error; + fprintf(stderr, "xmlMemFree: Tag error\n"); + return; } - if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint(); p->mh_tag = ~MEMTAG; - memset(target, -1, p->mh_size); + memset(ptr, -1, p->mh_size); + xmlMutexLock(&xmlMemMutex); debugMemSize -= p->mh_size; debugMemBlocks--; -#ifdef MEM_LIST - debugmem_list_delete(p); -#endif xmlMutexUnlock(&xmlMemMutex);
free(p);
- TEST_POINT - - return; - -error: - xmlGenericError(xmlGenericErrorContext, - "xmlMemFree(%p) error\n", ptr); - xmlMallocBreakpoint(); return; }
@@ -437,78 +235,56 @@ error: * @file: the file name or NULL * @line: the line number * - * a strdup() equivalent, with logging of the allocation info. + * DEPRECATED: don't use * * Returns a pointer to the new string or NULL if allocation error occurred. */ - char * -xmlMemStrdupLoc(const char *str, const char *file, int line) +xmlMemStrdupLoc(const char *str, const char *file ATTRIBUTE_UNUSED, + int line ATTRIBUTE_UNUSED) { + return(xmlMemoryStrdup(str)); +} + +/** + * xmlMemoryStrdup: + * @str: the initial string pointer + * + * a strdup() equivalent, with logging of the allocation info. + * + * Returns a pointer to the new string or NULL if allocation error occurred. + */ +char * +xmlMemoryStrdup(const char *str) { char *s; size_t size = strlen(str) + 1; MEMHDR *p;
xmlInitParser(); - TEST_POINT
if (size > (MAX_SIZE_T - RESERVE_SIZE)) { - xmlGenericError(xmlGenericErrorContext, - "xmlMemStrdupLoc : Unsigned overflow\n"); - return(NULL); + fprintf(stderr, "xmlMemoryStrdup: Unsigned overflow\n"); + return(NULL); }
- p = (MEMHDR *) malloc(RESERVE_SIZE+size); + p = (MEMHDR *) malloc(RESERVE_SIZE + size); if (!p) { - goto error; + fprintf(stderr, "xmlMemoryStrdup: Out of memory\n"); + return(NULL); } p->mh_tag = MEMTAG; p->mh_size = size; - p->mh_type = STRDUP_TYPE; - p->mh_file = file; - p->mh_line = line; + xmlMutexLock(&xmlMemMutex); - p->mh_number = ++block; debugMemSize += size; debugMemBlocks++; - if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize; -#ifdef MEM_LIST - debugmem_list_add(p); -#endif xmlMutexUnlock(&xmlMemMutex);
s = (char *) HDR_2_CLIENT(p);
- if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint(); - - strcpy(s,str); - - TEST_POINT - - if (xmlMemTraceBlockAt == s) { - xmlGenericError(xmlGenericErrorContext, - "%p : Strdup() Ok\n", xmlMemTraceBlockAt); - xmlMallocBreakpoint(); - } + memcpy(s, str, size);
return(s); - -error: - return(NULL); -} - -/** - * xmlMemoryStrdup: - * @str: the initial string pointer - * - * a strdup() equivalent, with logging of the allocation info. - * - * Returns a pointer to the new string or NULL if allocation error occurred. - */ - -char * -xmlMemoryStrdup(const char *str) { - return(xmlMemStrdupLoc(str, "none", 0)); }
/** @@ -565,256 +341,47 @@ xmlMemBlocks(void) {
/** * xmlMemDisplayLast: - * @fp: a FILE descriptor used as the output file, if NULL, the result is - * written to the file .memorylist + * @fp: a FILE descriptor * @nbBytes: the amount of memory to dump * - * the last nbBytes of memory allocated and not freed, useful for dumping - * the memory left allocated between two places at runtime. + * DEPRECATED: This feature was removed. */ - void -xmlMemDisplayLast(FILE *fp, long nbBytes) +xmlMemDisplayLast(FILE *fp ATTRIBUTE_UNUSED, long nbBytes ATTRIBUTE_UNUSED) { -#ifdef MEM_LIST - MEMHDR *p; - unsigned idx; - int nb = 0; -#endif - FILE *old_fp = fp; - - if (nbBytes <= 0) - return; - - if (fp == NULL) { - fp = fopen(".memorylist", "w"); - if (fp == NULL) - return; - } - -#ifdef MEM_LIST - fprintf(fp," Last %li MEMORY ALLOCATED : %lu, MAX was %lu\n", - nbBytes, debugMemSize, debugMaxMemSize); - fprintf(fp,"BLOCK NUMBER SIZE TYPE\n"); - idx = 0; - xmlMutexLock(&xmlMemMutex); - p = memlist; - while ((p) && (nbBytes > 0)) { - fprintf(fp,"%-5u %6lu %6lu ",idx++,p->mh_number, - (unsigned long)p->mh_size); - switch (p->mh_type) { - case STRDUP_TYPE:fprintf(fp,"strdup() in ");break; - case MALLOC_TYPE:fprintf(fp,"malloc() in ");break; - case REALLOC_TYPE:fprintf(fp,"realloc() in ");break; - case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc() in ");break; - case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break; - default: - fprintf(fp,"Unknown memory block, may be corrupted"); - xmlMutexUnlock(&xmlMemMutex); - if (old_fp == NULL) - fclose(fp); - return; - } - if (p->mh_file != NULL) fprintf(fp,"%s(%u)", p->mh_file, p->mh_line); - if (p->mh_tag != MEMTAG) - fprintf(fp," INVALID"); - nb++; - - fprintf(fp,"\n"); - nbBytes -= (unsigned long)p->mh_size; - p = p->mh_next; - } - xmlMutexUnlock(&xmlMemMutex); -#else - fprintf(fp,"Memory list not compiled (MEM_LIST not defined !)\n"); -#endif - if (old_fp == NULL) - fclose(fp); }
/** * xmlMemDisplay: - * @fp: a FILE descriptor used as the output file, if NULL, the result is - * written to the file .memorylist + * @fp: a FILE descriptor * - * show in-extenso the memory blocks allocated + * DEPRECATED: This feature was removed. */ - void -xmlMemDisplay(FILE *fp) +xmlMemDisplay(FILE *fp ATTRIBUTE_UNUSED) { -#ifdef MEM_LIST - MEMHDR *p; - unsigned idx; - int nb = 0; - time_t currentTime; - char buf[500]; - struct tm * tstruct; -#endif - FILE *old_fp = fp; - - if (fp == NULL) { - fp = fopen(".memorylist", "w"); - if (fp == NULL) - return; - } - -#ifdef MEM_LIST - currentTime = time(NULL); - tstruct = localtime(¤tTime); - strftime(buf, sizeof(buf) - 1, "%I:%M:%S %p", tstruct); - fprintf(fp," %s\n\n", buf); - - - fprintf(fp," MEMORY ALLOCATED : %lu, MAX was %lu\n", - debugMemSize, debugMaxMemSize); - fprintf(fp,"BLOCK NUMBER SIZE TYPE\n"); - idx = 0; - xmlMutexLock(&xmlMemMutex); - p = memlist; - while (p) { - fprintf(fp,"%-5u %6lu %6lu ",idx++,p->mh_number, - (unsigned long)p->mh_size); - switch (p->mh_type) { - case STRDUP_TYPE:fprintf(fp,"strdup() in ");break; - case MALLOC_TYPE:fprintf(fp,"malloc() in ");break; - case REALLOC_TYPE:fprintf(fp,"realloc() in ");break; - case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc() in ");break; - case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break; - default: - fprintf(fp,"Unknown memory block, may be corrupted"); - xmlMutexUnlock(&xmlMemMutex); - if (old_fp == NULL) - fclose(fp); - return; - } - if (p->mh_file != NULL) fprintf(fp,"%s(%u)", p->mh_file, p->mh_line); - if (p->mh_tag != MEMTAG) - fprintf(fp," INVALID"); - nb++; - - fprintf(fp,"\n"); - p = p->mh_next; - } - xmlMutexUnlock(&xmlMemMutex); -#else - fprintf(fp,"Memory list not compiled (MEM_LIST not defined !)\n"); -#endif - if (old_fp == NULL) - fclose(fp); }
-#ifdef MEM_LIST - -static void debugmem_list_add(MEMHDR *p) -{ - p->mh_next = memlist; - p->mh_prev = NULL; - if (memlist) memlist->mh_prev = p; - memlist = p; -} - -static void debugmem_list_delete(MEMHDR *p) -{ - if (p->mh_next) - p->mh_next->mh_prev = p->mh_prev; - if (p->mh_prev) - p->mh_prev->mh_next = p->mh_next; - else memlist = p->mh_next; -} - -#endif - -/* - * debugmem_tag_error: - * - * internal error function. - */ - -static void debugmem_tag_error(void *p) -{ - xmlGenericError(xmlGenericErrorContext, - "Memory tag error occurs :%p \n\t bye\n", p); -#ifdef MEM_LIST - if (stderr) - xmlMemDisplay(stderr); -#endif -} - -#ifdef MEM_LIST -static FILE *xmlMemoryDumpFile = NULL; -#endif - /** * xmlMemShow: - * @fp: a FILE descriptor used as the output file + * @fp: a FILE descriptor * @nr: number of entries to dump * - * show a show display of the memory allocated, and dump - * the @nr last allocated areas which were not freed + * DEPRECATED: This feature was removed. */ - void -xmlMemShow(FILE *fp, int nr ATTRIBUTE_UNUSED) +xmlMemShow(FILE *fp ATTRIBUTE_UNUSED, int nr ATTRIBUTE_UNUSED) { -#ifdef MEM_LIST - MEMHDR *p; -#endif - - if (fp != NULL) - fprintf(fp," MEMORY ALLOCATED : %lu, MAX was %lu\n", - debugMemSize, debugMaxMemSize); -#ifdef MEM_LIST - xmlMutexLock(&xmlMemMutex); - if (nr > 0) { - fprintf(fp,"NUMBER SIZE TYPE WHERE\n"); - p = memlist; - while ((p) && nr > 0) { - fprintf(fp,"%6lu %6lu ",p->mh_number,(unsigned long)p->mh_size); - switch (p->mh_type) { - case STRDUP_TYPE:fprintf(fp,"strdup() in ");break; - case MALLOC_TYPE:fprintf(fp,"malloc() in ");break; - case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc() in ");break; - case REALLOC_TYPE:fprintf(fp,"realloc() in ");break; - case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break; - default:fprintf(fp," ??? in ");break; - } - if (p->mh_file != NULL) - fprintf(fp,"%s(%u)", p->mh_file, p->mh_line); - if (p->mh_tag != MEMTAG) - fprintf(fp," INVALID"); - fprintf(fp,"\n"); - nr--; - p = p->mh_next; - } - } - xmlMutexUnlock(&xmlMemMutex); -#endif /* MEM_LIST */ }
/** * xmlMemoryDump: * - * Dump in-extenso the memory blocks allocated to the file .memorylist + * DEPRECATED: This feature was removed. */ - void xmlMemoryDump(void) { -#ifdef MEM_LIST - FILE *dump; - - if (debugMaxMemSize == 0) - return; - dump = fopen(".memdump", "w"); - if (dump == NULL) - xmlMemoryDumpFile = stderr; - else xmlMemoryDumpFile = dump; - - xmlMemDisplay(xmlMemoryDumpFile); - - if (dump != NULL) fclose(dump); -#endif /* MEM_LIST */ }
@@ -828,6 +395,8 @@ xmlMemoryDump(void) * xmlInitMemory: * * DEPRECATED: Alias for xmlInitParser. + * + * Returns 0. */ int xmlInitMemory(void) { @@ -839,23 +408,10 @@ xmlInitMemory(void) { * xmlInitMemoryInternal: * * Initialize the memory layer. - * - * Returns 0 on success */ void xmlInitMemoryInternal(void) { - char *breakpoint; - xmlInitMutex(&xmlMemMutex); - - breakpoint = getenv("XML_MEM_BREAKPOINT"); - if (breakpoint != NULL) { - sscanf(breakpoint, "%ud", &xmlMemStopAtBlock); - } - breakpoint = getenv("XML_MEM_TRACE"); - if (breakpoint != NULL) { - sscanf(breakpoint, "%p", &xmlMemTraceBlockAt); - } - + xmlInitMutex(&xmlMemMutex); }
/** diff --git a/libs/xml2/xmlreader.c b/libs/xml2/xmlreader.c index 1d954f21310..38dd1140d6d 100644 --- a/libs/xml2/xmlreader.c +++ b/libs/xml2/xmlreader.c @@ -40,14 +40,13 @@ #endif
#include "private/buf.h" -#include "private/parser.h" +#include "private/error.h" #include "private/tree.h" +#include "private/parser.h" #ifdef LIBXML_XINCLUDE_ENABLED #include "private/xinclude.h" #endif
-#define MAX_ERR_MSG_SIZE 64000 - #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION /* Keeping free objects can hide memory errors. */ #define MAX_FREE_NODES 1 @@ -55,39 +54,14 @@ #define MAX_FREE_NODES 100 #endif
-/* - * The following VA_COPY was coded following an example in - * the Samba project. It may not be sufficient for some - * esoteric implementations of va_list but (hopefully) will - * be sufficient for libxml2. - */ -#ifndef VA_COPY - #ifdef HAVE_VA_COPY - #define VA_COPY(dest, src) va_copy(dest, src) +#ifndef va_copy + #ifdef __va_copy + #define va_copy(dest, src) __va_copy(dest, src) #else - #ifdef HAVE___VA_COPY - #define VA_COPY(dest,src) __va_copy(dest, src) - #else - #ifndef VA_LIST_IS_ARRAY - #define VA_COPY(dest,src) (dest) = (src) - #else - #include <string.h> - #define VA_COPY(dest,src) memcpy((char *)(dest),(char *)(src),sizeof(va_list)) - #endif - #endif + #define va_copy(dest, src) memcpy(&(dest), &(src), sizeof(va_list)) #endif #endif
-/** - * TODO: - * - * macro to flag unimplemented blocks - */ -#define TODO \ - xmlGenericError(xmlGenericErrorContext, \ - "Unimplemented block at %s:%d\n", \ - __FILE__, __LINE__); - #define CHUNK_SIZE 512 /************************************************************************ * * @@ -188,22 +162,9 @@ struct _xmlTextReader { #define NODE_IS_PRESERVED 0x2 #define NODE_IS_SPRESERVED 0x4
-/** - * CONSTSTR: - * - * Macro used to return an interned string - */ -#define CONSTSTR(str) xmlDictLookup(reader->dict, (str), -1) -#define CONSTQSTR(p, str) xmlDictQLookup(reader->dict, (p), (str)) - static int xmlTextReaderReadTree(xmlTextReaderPtr reader); static int xmlTextReaderNextTree(xmlTextReaderPtr reader);
-/************************************************************************ - * * - * Our own version of the freeing routines as we recycle nodes * - * * - ************************************************************************/ /** * DICT_FREE: * @str: a string @@ -219,6 +180,65 @@ static int xmlTextReaderNextTree(xmlTextReaderPtr reader); static void xmlTextReaderFreeNode(xmlTextReaderPtr reader, xmlNodePtr cur); static void xmlTextReaderFreeNodeList(xmlTextReaderPtr reader, xmlNodePtr cur);
+static void +xmlTextReaderErrMemory(xmlTextReaderPtr reader) { + if (reader->ctxt != NULL) + xmlCtxtErrMemory(reader->ctxt); + else + xmlRaiseMemoryError(NULL, NULL, NULL, XML_FROM_PARSER, NULL); + reader->mode = XML_TEXTREADER_MODE_ERROR; + reader->state = XML_TEXTREADER_ERROR; +} + +static xmlChar * +readerStrdup(xmlTextReaderPtr reader, const xmlChar *string) { + xmlChar *copy; + + if (string == NULL) + return(NULL); + + copy = xmlStrdup(string); + if (copy == NULL) + xmlTextReaderErrMemory(reader); + + return(copy); +} + +static const xmlChar * +constString(xmlTextReaderPtr reader, const xmlChar *string) { + const xmlChar *dictString; + + if (string == NULL) + return(NULL); + + dictString = xmlDictLookup(reader->dict, string, -1); + if (dictString == NULL) + xmlTextReaderErrMemory(reader); + + return(dictString); +} + +static const xmlChar * +constQString(xmlTextReaderPtr reader, const xmlChar *prefix, + const xmlChar *name) { + const xmlChar *dictString; + + if (name == NULL) + return(NULL); + + dictString = xmlDictQLookup(reader->dict, prefix, name); + if (dictString == NULL) + xmlTextReaderErrMemory(reader); + + return(dictString); +} + +/************************************************************************ + * * + * Our own version of the freeing routines as we recycle nodes * + * * + ************************************************************************/ + /** * xmlTextReaderFreeProp: * @reader: the xmlTextReaderPtr used @@ -242,7 +262,19 @@ xmlTextReaderFreeProp(xmlTextReaderPtr reader, xmlAttrPtr cur) { if (cur->children != NULL) xmlTextReaderFreeNodeList(reader, cur->children);
- DICT_FREE(cur->name); + if (cur->id != NULL) { + /* + * Operating in streaming mode, attr is gonna disappear + */ + cur->id->attr = NULL; + if (cur->id->name != NULL) + DICT_FREE(cur->id->name); + cur->id->name = cur->name; + cur->name = NULL; + } else { + DICT_FREE(cur->name); + } + if ((reader != NULL) && (reader->ctxt != NULL) && (reader->ctxt->freeAttrsNr < MAX_FREE_NODES)) { cur->next = reader->ctxt->freeAttrs; @@ -498,6 +530,34 @@ xmlTextReaderFreeDoc(xmlTextReaderPtr reader, xmlDocPtr cur) { * * ************************************************************************/
+static void +xmlTextReaderStructuredRelay(void *userData, const xmlError *error) +{ + xmlTextReaderPtr reader = (xmlTextReaderPtr) userData; + + if (reader->sErrorFunc != NULL) { + reader->sErrorFunc(reader->errorFuncArg, error); + } else if (reader->errorFunc != NULL) { + xmlParserSeverities severity; + + if ((error->domain == XML_FROM_VALID) || + (error->domain == XML_FROM_DTD)) { + if (error->level == XML_ERR_WARNING) + severity = XML_PARSER_SEVERITY_VALIDITY_WARNING; + else + severity = XML_PARSER_SEVERITY_VALIDITY_ERROR; + } else { + if (error->level == XML_ERR_WARNING) + severity = XML_PARSER_SEVERITY_WARNING; + else + severity = XML_PARSER_SEVERITY_ERROR; + } + + reader->errorFunc(reader->errorFuncArg, error->message, severity, + reader->ctxt); + } +} + /** * xmlTextReaderEntPush: * @reader: the xmlTextReaderPtr used @@ -517,7 +577,7 @@ xmlTextReaderEntPush(xmlTextReaderPtr reader, xmlNodePtr value) tmp = (xmlNodePtr *) xmlRealloc(reader->entTab, newSize * sizeof(*tmp)); if (tmp == NULL) { - xmlGenericError(xmlGenericErrorContext, "xmlRealloc failed !\n"); + xmlTextReaderErrMemory(reader); return (-1); } reader->entTab = tmp; @@ -734,11 +794,10 @@ xmlTextReaderPushData(xmlTextReaderPtr reader) { break; } } else if (val < 0) { - xmlGenericError(xmlGenericErrorContext, - "xmlParserInputBufferRead failed\n"); - reader->mode = XML_TEXTREADER_MODE_EOF; - reader->state = oldstate; - return(val); + xmlCtxtErrIO(reader->ctxt, reader->input->error, NULL); + reader->mode = XML_TEXTREADER_MODE_ERROR; + reader->state = XML_TEXTREADER_ERROR; + return(-1); }
} else @@ -820,8 +879,8 @@ xmlTextReaderPushData(xmlTextReaderPtr reader) { * * Push the current node for validation */ -static void -xmlTextReaderValidatePush(xmlTextReaderPtr reader ATTRIBUTE_UNUSED) { +static int +xmlTextReaderValidatePush(xmlTextReaderPtr reader) { xmlNodePtr node = reader->node;
#ifdef LIBXML_VALID_ENABLED @@ -831,17 +890,24 @@ xmlTextReaderValidatePush(xmlTextReaderPtr reader ATTRIBUTE_UNUSED) { reader->ctxt->valid &= xmlValidatePushElement(&reader->ctxt->vctxt, reader->ctxt->myDoc, node, node->name); } else { - /* TODO use the BuildQName interface */ + xmlChar buf[50]; xmlChar *qname;
- qname = xmlStrdup(node->ns->prefix); - qname = xmlStrcat(qname, BAD_CAST ":"); - qname = xmlStrcat(qname, node->name); + qname = xmlBuildQName(node->name, node->ns->prefix, buf, 50); + if (qname == NULL) { + xmlTextReaderErrMemory(reader); + return(-1); + } reader->ctxt->valid &= xmlValidatePushElement(&reader->ctxt->vctxt, reader->ctxt->myDoc, node, qname); - if (qname != NULL) - xmlFree(qname); + if (qname != buf) + xmlFree(qname); } + /*if (reader->ctxt->errNo == XML_ERR_NO_MEMORY) { + reader->mode = XML_TEXTREADER_MODE_ERROR; + reader->state = XML_TEXTREADER_ERROR; + return(-1); + }*/ } #endif /* LIBXML_VALID_ENABLED */ #ifdef LIBXML_SCHEMAS_ENABLED @@ -849,7 +915,7 @@ xmlTextReaderValidatePush(xmlTextReaderPtr reader ATTRIBUTE_UNUSED) { (reader->rngValidCtxt != NULL)) { int ret;
- if (reader->rngFullNode != NULL) return; + if (reader->rngFullNode != NULL) return(0); ret = xmlRelaxNGValidatePushElement(reader->rngValidCtxt, reader->ctxt->myDoc, node); @@ -871,6 +937,8 @@ xmlTextReaderValidatePush(xmlTextReaderPtr reader ATTRIBUTE_UNUSED) { reader->rngValidErrors++; } #endif + + return(0); }
/** @@ -910,7 +978,7 @@ xmlTextReaderValidateCData(xmlTextReaderPtr reader, * * Pop the current node from validation */ -static void +static int xmlTextReaderValidatePop(xmlTextReaderPtr reader) { xmlNodePtr node = reader->node;
@@ -921,17 +989,24 @@ xmlTextReaderValidatePop(xmlTextReaderPtr reader) { reader->ctxt->valid &= xmlValidatePopElement(&reader->ctxt->vctxt, reader->ctxt->myDoc, node, node->name); } else { - /* TODO use the BuildQName interface */ + xmlChar buf[50]; xmlChar *qname;
- qname = xmlStrdup(node->ns->prefix); - qname = xmlStrcat(qname, BAD_CAST ":"); - qname = xmlStrcat(qname, node->name); + qname = xmlBuildQName(node->name, node->ns->prefix, buf, 50); + if (qname == NULL) { + xmlTextReaderErrMemory(reader); + return(-1); + } reader->ctxt->valid &= xmlValidatePopElement(&reader->ctxt->vctxt, reader->ctxt->myDoc, node, qname); - if (qname != NULL) - xmlFree(qname); + if (qname != buf) + xmlFree(qname); } + /*if (reader->ctxt->errNo == XML_ERR_NO_MEMORY) { + reader->mode = XML_TEXTREADER_MODE_ERROR; + reader->state = XML_TEXTREADER_ERROR; + return(-1); + }*/ } #endif /* LIBXML_VALID_ENABLED */ #ifdef LIBXML_SCHEMAS_ENABLED @@ -942,7 +1017,7 @@ xmlTextReaderValidatePop(xmlTextReaderPtr reader) { if (reader->rngFullNode != NULL) { if (node == reader->rngFullNode) reader->rngFullNode = NULL; - return; + return(0); } ret = xmlRelaxNGValidatePopElement(reader->rngValidCtxt, reader->ctxt->myDoc, @@ -951,6 +1026,8 @@ xmlTextReaderValidatePop(xmlTextReaderPtr reader) { reader->rngValidErrors++; } #endif + + return(0); }
/** @@ -961,7 +1038,7 @@ xmlTextReaderValidatePop(xmlTextReaderPtr reader) { * entity substitution is not activated. As a result the parser interface * must walk through the entity and do the validation calls */ -static void +static int xmlTextReaderValidateEntity(xmlTextReaderPtr reader) { xmlNodePtr oldnode = reader->node; xmlNodePtr node = reader->node; @@ -989,7 +1066,8 @@ xmlTextReaderValidateEntity(xmlTextReaderPtr reader) { #ifdef LIBXML_REGEXP_ENABLED } else if (node->type == XML_ELEMENT_NODE) { reader->node = node; - xmlTextReaderValidatePush(reader); + if (xmlTextReaderValidatePush(reader) < 0) + return(-1); } else if ((node->type == XML_TEXT_NODE) || (node->type == XML_CDATA_SECTION_NODE)) { xmlTextReaderValidateCData(reader, node->content, @@ -1004,7 +1082,8 @@ xmlTextReaderValidateEntity(xmlTextReaderPtr reader) { node = node->children; continue; } else if (node->type == XML_ELEMENT_NODE) { - xmlTextReaderValidatePop(reader); + if (xmlTextReaderValidatePop(reader) < 0) + return(-1); } skip_children: if (node->next != NULL) { @@ -1025,7 +1104,8 @@ skip_children: } } reader->node = node; - xmlTextReaderValidatePop(reader); + if (xmlTextReaderValidatePop(reader) < 0) + return(-1); } if ((node->type == XML_ENTITY_DECL) && (reader->ent != NULL) && (reader->ent->children == node)) { @@ -1040,6 +1120,8 @@ skip_children: } while ((node != NULL) && (node != oldnode)); } while ((node != NULL) && (node != oldnode)); reader->node = oldnode; + + return(0); } #endif /* LIBXML_REGEXP_ENABLED */
@@ -1082,7 +1164,8 @@ xmlTextReaderDoExpand(xmlTextReaderPtr reader) { if ((reader == NULL) || (reader->node == NULL) || (reader->ctxt == NULL)) return(-1); do { - if (reader->ctxt->instate == XML_PARSER_EOF) return(1); + if (PARSER_STOPPED(reader->ctxt)) + return(1);
if (xmlTextReaderGetSuccessor(reader->node) != NULL) return(1); @@ -1093,60 +1176,13 @@ xmlTextReaderDoExpand(xmlTextReaderPtr reader) { val = xmlTextReaderPushData(reader); if (val < 0){ reader->mode = XML_TEXTREADER_MODE_ERROR; + reader->state = XML_TEXTREADER_ERROR; return(-1); } } while(reader->mode != XML_TEXTREADER_MODE_EOF); return(1); }
-/** - * xmlTextReaderCollectSiblings: - * @node: the first child - * - * Traverse depth-first through all sibling nodes and their children - * nodes and concatenate their content. This is an auxiliary function - * to xmlTextReaderReadString. - * - * Returns a string containing the content, or NULL in case of error. - */ -static xmlChar * -xmlTextReaderCollectSiblings(xmlNodePtr node) -{ - xmlBufferPtr buffer; - xmlChar *ret; - - if ((node == NULL) || (node->type == XML_NAMESPACE_DECL)) - return(NULL); - - buffer = xmlBufferCreate(); - if (buffer == NULL) - return NULL; - xmlBufferSetAllocationScheme(buffer, XML_BUFFER_ALLOC_DOUBLEIT); - - for ( ; node != NULL; node = node->next) { - switch (node->type) { - case XML_TEXT_NODE: - case XML_CDATA_SECTION_NODE: - xmlBufferCat(buffer, node->content); - break; - case XML_ELEMENT_NODE: { - xmlChar *tmp; - - tmp = xmlTextReaderCollectSiblings(node->children); - xmlBufferCat(buffer, tmp); - xmlFree(tmp); - break; - } - default: - break; - } - } - ret = buffer->content; - buffer->content = NULL; - xmlBufferFree(buffer); - return(ret); -} - /** * xmlTextReaderRead: * @reader: the xmlTextReaderPtr used @@ -1163,9 +1199,11 @@ xmlTextReaderRead(xmlTextReaderPtr reader) { xmlTextReaderState oldstate = XML_TEXTREADER_START; xmlNodePtr oldnode = NULL;
- if (reader == NULL) return(-1); + if (reader->state == XML_TEXTREADER_ERROR) + return(-1); + reader->curnode = NULL; if (reader->doc != NULL) return(xmlTextReaderReadTree(reader)); @@ -1179,11 +1217,11 @@ xmlTextReaderRead(xmlTextReaderPtr reader) { */ do { val = xmlTextReaderPushData(reader); - if (val < 0){ - reader->mode = XML_TEXTREADER_MODE_ERROR; - reader->state = XML_TEXTREADER_ERROR; - return(-1); - } + if (val < 0) { + reader->mode = XML_TEXTREADER_MODE_ERROR; + reader->state = XML_TEXTREADER_ERROR; + return(-1); + } } while ((reader->ctxt->node == NULL) && ((reader->mode != XML_TEXTREADER_MODE_EOF) && (reader->state != XML_TEXTREADER_DONE))); @@ -1191,11 +1229,11 @@ xmlTextReaderRead(xmlTextReaderPtr reader) { if (reader->ctxt->myDoc != NULL) { reader->node = reader->ctxt->myDoc->children; } - if (reader->node == NULL){ - reader->mode = XML_TEXTREADER_MODE_ERROR; - reader->state = XML_TEXTREADER_ERROR; + if (reader->node == NULL) { + reader->mode = XML_TEXTREADER_MODE_ERROR; + reader->state = XML_TEXTREADER_ERROR; return(-1); - } + } reader->state = XML_TEXTREADER_ELEMENT; } else { if (reader->ctxt->myDoc != NULL) { @@ -1215,10 +1253,13 @@ xmlTextReaderRead(xmlTextReaderPtr reader) {
get_next_node: if (reader->node == NULL) { - if (reader->mode == XML_TEXTREADER_MODE_EOF) + if (reader->mode == XML_TEXTREADER_MODE_EOF) { return(0); - else + } else { + reader->mode = XML_TEXTREADER_MODE_ERROR; + reader->state = XML_TEXTREADER_ERROR; return(-1); + } }
/* @@ -1240,13 +1281,14 @@ get_next_node: ((reader->ctxt->node == NULL) || (reader->ctxt->node == reader->node) || (reader->ctxt->node == reader->node->parent)) && - (reader->ctxt->instate != XML_PARSER_EOF)) { + (reader->ctxt->instate != XML_PARSER_EOF) && + (PARSER_STOPPED(reader->ctxt) == 0)) { val = xmlTextReaderPushData(reader); - if (val < 0){ - reader->mode = XML_TEXTREADER_MODE_ERROR; - reader->state = XML_TEXTREADER_ERROR; + if (val < 0) { + reader->mode = XML_TEXTREADER_MODE_ERROR; + reader->state = XML_TEXTREADER_ERROR; return(-1); - } + } if (reader->node == NULL) goto node_end; } @@ -1276,7 +1318,8 @@ get_next_node: #ifdef LIBXML_REGEXP_ENABLED if ((reader->validate) && (reader->node->type == XML_ELEMENT_NODE)) - xmlTextReaderValidatePop(reader); + if (xmlTextReaderValidatePop(reader) < 0) + return(-1); #endif /* LIBXML_REGEXP_ENABLED */ if ((reader->preserves > 0) && (reader->node->extra & NODE_IS_SPRESERVED)) @@ -1313,8 +1356,11 @@ get_next_node: goto node_found; } #ifdef LIBXML_REGEXP_ENABLED - if ((reader->validate != XML_TEXTREADER_NOT_VALIDATE) && (reader->node->type == XML_ELEMENT_NODE)) - xmlTextReaderValidatePop(reader); + if ((reader->validate != XML_TEXTREADER_NOT_VALIDATE) && + (reader->node->type == XML_ELEMENT_NODE)) { + if (xmlTextReaderValidatePop(reader) < 0) + return(-1); + } #endif /* LIBXML_REGEXP_ENABLED */ if ((reader->preserves > 0) && (reader->node->extra & NODE_IS_SPRESERVED)) @@ -1326,8 +1372,11 @@ get_next_node: if (reader->mode != XML_TEXTREADER_MODE_EOF) { val = xmlParseChunk(reader->ctxt, "", 0, 1); reader->state = XML_TEXTREADER_DONE; - if (val != 0) + if (val != 0) { + reader->mode = XML_TEXTREADER_MODE_ERROR; + reader->state = XML_TEXTREADER_ERROR; return(-1); + } } reader->node = NULL; reader->depth = -1; @@ -1387,16 +1436,29 @@ node_found: (xmlStrEqual(reader->node->ns->href, XINCLUDE_OLD_NS)))) { if (reader->xincctxt == NULL) { reader->xincctxt = xmlXIncludeNewContext(reader->ctxt->myDoc); + if (reader->xincctxt == NULL) { + xmlTextReaderErrMemory(reader); + return(-1); + } xmlXIncludeSetFlags(reader->xincctxt, reader->parserFlags & (~XML_PARSE_NOXINCNODE)); xmlXIncludeSetStreamingMode(reader->xincctxt, 1); + if ((reader->errorFunc != NULL) || (reader->sErrorFunc != NULL)) + xmlXIncludeSetErrorHandler(reader->xincctxt, + xmlTextReaderStructuredRelay, reader); } /* * expand that node and process it */ if (xmlTextReaderExpand(reader) == NULL) - return -1; - xmlXIncludeProcessNode(reader->xincctxt, reader->node); + return(-1); + if (xmlXIncludeProcessNode(reader->xincctxt, reader->node) < 0) { + int err = xmlXIncludeGetLastError(reader->xincctxt); + + if (err == XML_ERR_NO_MEMORY) + xmlTextReaderErrMemory(reader); + return(-1); + } } if ((reader->node != NULL) && (reader->node->type == XML_XINCLUDE_START)) { reader->in_xinclude++; @@ -1424,7 +1486,8 @@ node_found: } else if ((reader->node != NULL) && (reader->node->type == XML_ENTITY_REF_NODE) && (reader->ctxt != NULL) && (reader->validate)) { - xmlTextReaderValidateEntity(reader); + if (xmlTextReaderValidateEntity(reader) < 0) + return(-1); #endif /* LIBXML_REGEXP_ENABLED */ } if ((reader->node != NULL) && @@ -1441,7 +1504,8 @@ node_found: if ((node->type == XML_ELEMENT_NODE) && ((reader->state != XML_TEXTREADER_END) && (reader->state != XML_TEXTREADER_BACKTRACK))) { - xmlTextReaderValidatePush(reader); + if (xmlTextReaderValidatePush(reader) < 0) + return(-1); } else if ((node->type == XML_TEXT_NODE) || (node->type == XML_CDATA_SECTION_NODE)) { xmlTextReaderValidateCData(reader, node->content, @@ -1547,6 +1611,37 @@ xmlTextReaderNext(xmlTextReaderPtr reader) { }
#ifdef LIBXML_WRITER_ENABLED +static void +xmlTextReaderDumpCopy(xmlTextReaderPtr reader, xmlOutputBufferPtr output, + xmlNodePtr node) { + if ((node->type == XML_DTD_NODE) || + (node->type == XML_ELEMENT_DECL) || + (node->type == XML_ATTRIBUTE_DECL) || + (node->type == XML_ENTITY_DECL)) + return; + + if ((node->type == XML_DOCUMENT_NODE) || + (node->type == XML_HTML_DOCUMENT_NODE)) { + xmlNodeDumpOutput(output, node->doc, node, 0, 0, NULL); + } else { + xmlNodePtr copy; + + /* + * Create a copy to make sure that namespace declarations from + * ancestors are added. + */ + copy = xmlDocCopyNode(node, node->doc, 1); + if (copy == NULL) { + xmlTextReaderErrMemory(reader); + return; + } + + xmlNodeDumpOutput(output, copy->doc, copy, 0, 0, NULL); + + xmlFreeNode(copy); + } +} + /** * xmlTextReaderReadInnerXml: * @reader: the xmlTextReaderPtr used @@ -1558,47 +1653,36 @@ xmlTextReaderNext(xmlTextReaderPtr reader) { * string must be deallocated by the caller. */ xmlChar * -xmlTextReaderReadInnerXml(xmlTextReaderPtr reader ATTRIBUTE_UNUSED) +xmlTextReaderReadInnerXml(xmlTextReaderPtr reader) { - xmlChar *resbuf; - xmlNodePtr node, cur_node; - xmlBufferPtr buff, buff2; - xmlDocPtr doc; + xmlOutputBufferPtr output; + xmlNodePtr cur; + xmlChar *ret;
- if (xmlTextReaderExpand(reader) == NULL) { - return NULL; - } - doc = reader->node->doc; - buff = xmlBufferCreate(); - if (buff == NULL) - return NULL; - xmlBufferSetAllocationScheme(buff, XML_BUFFER_ALLOC_DOUBLEIT); - for (cur_node = reader->node->children; cur_node != NULL; - cur_node = cur_node->next) { - /* XXX: Why is the node copied? */ - node = xmlDocCopyNode(cur_node, doc, 1); - /* XXX: Why do we need a second buffer? */ - buff2 = xmlBufferCreate(); - xmlBufferSetAllocationScheme(buff2, XML_BUFFER_ALLOC_DOUBLEIT); - if (xmlNodeDump(buff2, doc, node, 0, 0) == -1) { - xmlFreeNode(node); - xmlBufferFree(buff2); - xmlBufferFree(buff); - return NULL; - } - xmlBufferCat(buff, buff2->content); - xmlFreeNode(node); - xmlBufferFree(buff2); + if (xmlTextReaderExpand(reader) == NULL) + return(NULL); + + if (reader->node == NULL) + return(NULL); + + output = xmlAllocOutputBuffer(NULL); + if (output == NULL) { + xmlTextReaderErrMemory(reader); + return(NULL); } - resbuf = buff->content; - buff->content = NULL;
- xmlBufferFree(buff); - return resbuf; + for (cur = reader->node->children; cur != NULL; cur = cur->next) + xmlTextReaderDumpCopy(reader, output, cur); + + if (output->error) + xmlCtxtErrIO(reader->ctxt, output->error, NULL); + + ret = xmlBufDetach(output->buffer); + xmlOutputBufferClose(output); + + return(ret); } -#endif
-#ifdef LIBXML_WRITER_ENABLED /** * xmlTextReaderReadOuterXml: * @reader: the xmlTextReaderPtr used @@ -1610,38 +1694,33 @@ xmlTextReaderReadInnerXml(xmlTextReaderPtr reader ATTRIBUTE_UNUSED) * by the caller. */ xmlChar * -xmlTextReaderReadOuterXml(xmlTextReaderPtr reader ATTRIBUTE_UNUSED) +xmlTextReaderReadOuterXml(xmlTextReaderPtr reader) { - xmlChar *resbuf; + xmlOutputBufferPtr output; xmlNodePtr node; - xmlBufferPtr buff; - xmlDocPtr doc; + xmlChar *ret; + + if (xmlTextReaderExpand(reader) == NULL) + return(NULL);
- if (xmlTextReaderExpand(reader) == NULL) { - return NULL; - } node = reader->node; - doc = node->doc; - /* XXX: Why is the node copied? */ - if (node->type == XML_DTD_NODE) { - node = (xmlNodePtr) xmlCopyDtd((xmlDtdPtr) node); - } else { - node = xmlDocCopyNode(node, doc, 1); - } - buff = xmlBufferCreate(); - xmlBufferSetAllocationScheme(buff, XML_BUFFER_ALLOC_DOUBLEIT); - if (xmlNodeDump(buff, doc, node, 0, 0) == -1) { - xmlFreeNode(node); - xmlBufferFree(buff); - return NULL; + if (node == NULL) + return(NULL); + + output = xmlAllocOutputBuffer(NULL); + if (output == NULL) { + xmlTextReaderErrMemory(reader); + return(NULL); }
- resbuf = buff->content; - buff->content = NULL; + xmlTextReaderDumpCopy(reader, output, node); + if (output->error) + xmlCtxtErrIO(reader->ctxt, output->error, NULL); + + ret = xmlBufDetach(output->buffer); + xmlOutputBufferClose(output);
- xmlFreeNode(node); - xmlBufferFree(buff); - return resbuf; + return(ret); } #endif
@@ -1651,36 +1730,79 @@ xmlTextReaderReadOuterXml(xmlTextReaderPtr reader ATTRIBUTE_UNUSED) * * Reads the contents of an element or a text node as a string. * - * Returns a string containing the contents of the Element or Text node, - * or NULL if the reader is positioned on any other type of node. + * Returns a string containing the contents of the non-empty Element or + * Text node (including CDATA sections), or NULL if the reader + * is positioned on any other type of node. * The string must be deallocated by the caller. */ xmlChar * xmlTextReaderReadString(xmlTextReaderPtr reader) { - xmlNodePtr node; + xmlNodePtr node, cur; + xmlBufPtr buf; + xmlChar *ret;
if ((reader == NULL) || (reader->node == NULL)) return(NULL);
node = (reader->curnode != NULL) ? reader->curnode : reader->node; switch (node->type) { - case XML_TEXT_NODE: - if (node->content != NULL) - return(xmlStrdup(node->content)); - break; - case XML_ELEMENT_NODE: - if (xmlTextReaderDoExpand(reader) != -1) { - return xmlTextReaderCollectSiblings(node->children); - } - break; - case XML_ATTRIBUTE_NODE: - TODO - break; - default: - break; + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: + break; + case XML_ELEMENT_NODE: + if ((xmlTextReaderDoExpand(reader) == -1) || + (node->children == NULL)) + return(NULL); + break; + default: + return(NULL); } - return(NULL); + + buf = xmlBufCreateSize(30); + if (buf == NULL) { + xmlTextReaderErrMemory(reader); + return(NULL); + } + xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT); + + cur = node; + while (cur != NULL) { + switch (cur->type) { + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: + xmlBufCat(buf, cur->content); + break; + + case XML_ELEMENT_NODE: + if (cur->children != NULL) { + cur = cur->children; + continue; + } + break; + + default: + break; + } + + if (cur == node) + goto done; + + while (cur->next == NULL) { + cur = cur->parent; + if (cur == node) + goto done; + } + cur = cur->next; + } + +done: + ret = xmlBufDetach(buf); + if (ret == NULL) + xmlTextReaderErrMemory(reader); + + xmlBufFree(buf); + return(ret); }
#if 0 @@ -1710,7 +1832,6 @@ xmlTextReaderReadBase64(xmlTextReaderPtr reader,
if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE)) return(0); - TODO return(0); }
@@ -1740,7 +1861,6 @@ xmlTextReaderReadBinHex(xmlTextReaderPtr reader,
if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE)) return(0); - TODO return(0); } #endif @@ -1940,11 +2060,8 @@ xmlNewTextReader(xmlParserInputBufferPtr input, const char *URI) { if (input == NULL) return(NULL); ret = xmlMalloc(sizeof(xmlTextReader)); - if (ret == NULL) { - xmlGenericError(xmlGenericErrorContext, - "xmlNewTextReader : malloc failed\n"); + if (ret == NULL) return(NULL); - } memset(ret, 0, sizeof(xmlTextReader)); ret->doc = NULL; ret->entTab = NULL; @@ -1954,8 +2071,6 @@ xmlNewTextReader(xmlParserInputBufferPtr input, const char *URI) { ret->buffer = xmlBufCreateSize(100); if (ret->buffer == NULL) { xmlFree(ret); - xmlGenericError(xmlGenericErrorContext, - "xmlNewTextReader : malloc failed\n"); return(NULL); } /* no operation on a reader should require a huge buffer */ @@ -1965,8 +2080,6 @@ xmlNewTextReader(xmlParserInputBufferPtr input, const char *URI) { if (ret->sax == NULL) { xmlBufFree(ret->buffer); xmlFree(ret); - xmlGenericError(xmlGenericErrorContext, - "xmlNewTextReader : malloc failed\n"); return(NULL); } xmlSAXVersion(ret->sax, 2); @@ -2012,8 +2125,6 @@ xmlNewTextReader(xmlParserInputBufferPtr input, const char *URI) { }
if (ret->ctxt == NULL) { - xmlGenericError(xmlGenericErrorContext, - "xmlNewTextReader : malloc failed\n"); xmlBufFree(ret->buffer); xmlFree(ret->sax); xmlFree(ret); @@ -2027,7 +2138,6 @@ xmlNewTextReader(xmlParserInputBufferPtr input, const char *URI) { /* * use the parser dictionary to allocate all elements and attributes names */ - ret->ctxt->docdict = 1; ret->dict = ret->ctxt->dict; #ifdef LIBXML_XINCLUDE_ENABLED ret->xinclude = 0; @@ -2051,7 +2161,6 @@ xmlTextReaderPtr xmlNewTextReaderFilename(const char *URI) { xmlParserInputBufferPtr input; xmlTextReaderPtr ret; - char *directory = NULL;
input = xmlParserInputBufferCreateFilename(URI, XML_CHAR_ENCODING_NONE); if (input == NULL) @@ -2062,12 +2171,6 @@ xmlNewTextReaderFilename(const char *URI) { return(NULL); } ret->allocs |= XML_TEXTREADER_INPUT; - if (ret->ctxt->directory == NULL) - directory = xmlParserGetDirectory(URI); - if ((ret->ctxt->directory == NULL) && (directory != NULL)) - ret->ctxt->directory = (char *) xmlStrdup((xmlChar *) directory); - if (directory != NULL) - xmlFree(directory); return(ret); }
@@ -2143,6 +2246,7 @@ xmlFreeTextReader(xmlTextReaderPtr reader) { * Methods for XmlTextReader * * * ************************************************************************/ + /** * xmlTextReaderClose: * @reader: the xmlTextReaderPtr used @@ -2223,7 +2327,7 @@ xmlTextReaderGetAttributeNo(xmlTextReaderPtr reader, int no) { ns = ns->next; } if (ns != NULL) - return(xmlStrdup(ns->href)); + return(readerStrdup(reader, ns->href));
cur = reader->node->properties; if (cur == NULL) @@ -2235,8 +2339,11 @@ xmlTextReaderGetAttributeNo(xmlTextReaderPtr reader, int no) { } /* TODO walk the DTD if present */
+ if (cur->children == NULL) + return(NULL); ret = xmlNodeListGetString(reader->node->doc, cur->children, 1); - if (ret == NULL) return(xmlStrdup((xmlChar *)"")); + if (ret == NULL) + xmlTextReaderErrMemory(reader); return(ret); }
@@ -2253,9 +2360,10 @@ xmlTextReaderGetAttributeNo(xmlTextReaderPtr reader, int no) { xmlChar * xmlTextReaderGetAttribute(xmlTextReaderPtr reader, const xmlChar *name) { xmlChar *prefix = NULL; - xmlChar *localname; + const xmlChar *localname; xmlNsPtr ns; xmlChar *ret = NULL; + int result;
if ((reader == NULL) || (name == NULL)) return(NULL); @@ -2268,43 +2376,56 @@ xmlTextReaderGetAttribute(xmlTextReaderPtr reader, const xmlChar *name) { if (reader->node->type != XML_ELEMENT_NODE) return(NULL);
- localname = xmlSplitQName2(name, &prefix); + localname = xmlSplitQName4(name, &prefix); if (localname == NULL) { - /* - * Namespace default decl - */ - if (xmlStrEqual(name, BAD_CAST "xmlns")) { - ns = reader->node->nsDef; - while (ns != NULL) { - if (ns->prefix == NULL) { - return(xmlStrdup(ns->href)); - } - ns = ns->next; - } - return NULL; - } - return(xmlGetNoNsProp(reader->node, name)); - } + xmlTextReaderErrMemory(reader); + return(NULL); + } + if (prefix == NULL) { + /* + * Namespace default decl + */ + if (xmlStrEqual(name, BAD_CAST "xmlns")) { + ns = reader->node->nsDef; + while (ns != NULL) { + if (ns->prefix == NULL) { + return(readerStrdup(reader, ns->href)); + } + ns = ns->next; + } + return NULL; + } + + result = xmlNodeGetAttrValue(reader->node, name, NULL, &ret); + if (result < 0) + xmlTextReaderErrMemory(reader); + return(ret); + }
/* * Namespace default decl */ if (xmlStrEqual(prefix, BAD_CAST "xmlns")) { - ns = reader->node->nsDef; - while (ns != NULL) { - if ((ns->prefix != NULL) && (xmlStrEqual(ns->prefix, localname))) { - ret = xmlStrdup(ns->href); - break; - } - ns = ns->next; - } + ns = reader->node->nsDef; + while (ns != NULL) { + if ((ns->prefix != NULL) && (xmlStrEqual(ns->prefix, localname))) { + ret = readerStrdup(reader, ns->href); + break; + } + ns = ns->next; + } } else { - ns = xmlSearchNs(reader->node->doc, reader->node, prefix); - if (ns != NULL) - ret = xmlGetNsProp(reader->node, localname, ns->href); - } + result = xmlSearchNsSafe(reader->node, prefix, &ns); + if (result < 0) + xmlTextReaderErrMemory(reader); + if (ns != NULL) { + result = xmlNodeGetAttrValue(reader->node, localname, ns->href, + &ret); + if (result < 0) + xmlTextReaderErrMemory(reader); + } + }
- xmlFree(localname); if (prefix != NULL) xmlFree(prefix); return(ret); @@ -2325,8 +2446,10 @@ xmlTextReaderGetAttribute(xmlTextReaderPtr reader, const xmlChar *name) { xmlChar * xmlTextReaderGetAttributeNs(xmlTextReaderPtr reader, const xmlChar *localName, const xmlChar *namespaceURI) { + xmlChar *ret = NULL; xmlChar *prefix = NULL; xmlNsPtr ns; + int result;
if ((reader == NULL) || (localName == NULL)) return(NULL); @@ -2340,21 +2463,25 @@ xmlTextReaderGetAttributeNs(xmlTextReaderPtr reader, const xmlChar *localName, return(NULL);
if (xmlStrEqual(namespaceURI, BAD_CAST "http://www.w3.org/2000/xmlns/")) { - if (! xmlStrEqual(localName, BAD_CAST "xmlns")) { - prefix = BAD_CAST localName; - } - ns = reader->node->nsDef; - while (ns != NULL) { - if ((prefix == NULL && ns->prefix == NULL) || - ((ns->prefix != NULL) && (xmlStrEqual(ns->prefix, localName)))) { - return xmlStrdup(ns->href); - } - ns = ns->next; - } - return NULL; + if (! xmlStrEqual(localName, BAD_CAST "xmlns")) { + prefix = BAD_CAST localName; + } + ns = reader->node->nsDef; + while (ns != NULL) { + if ((prefix == NULL && ns->prefix == NULL) || + ((ns->prefix != NULL) && (xmlStrEqual(ns->prefix, localName)))) { + return readerStrdup(reader, ns->href); + } + ns = ns->next; + } + return NULL; }
- return(xmlGetNsProp(reader->node, localName, namespaceURI)); + result = xmlNodeGetAttrValue(reader->node, localName, namespaceURI, &ret); + if (result < 0) + xmlTextReaderErrMemory(reader); + + return(ret); }
/** @@ -2403,7 +2530,6 @@ xmlTextReaderGetRemainder(xmlTextReaderPtr reader) { * - by the layer which allocated it. * - by the layer to which would have been returned to. */ - TODO return(NULL); } return(ret); @@ -2423,16 +2549,21 @@ xmlTextReaderGetRemainder(xmlTextReaderPtr reader) { xmlChar * xmlTextReaderLookupNamespace(xmlTextReaderPtr reader, const xmlChar *prefix) { xmlNsPtr ns; + int result;
if (reader == NULL) return(NULL); if (reader->node == NULL) return(NULL);
- ns = xmlSearchNs(reader->node->doc, reader->node, prefix); + result = xmlSearchNsSafe(reader->node, prefix, &ns); + if (result < 0) { + xmlTextReaderErrMemory(reader); + return(NULL); + } if (ns == NULL) return(NULL); - return(xmlStrdup(ns->href)); + return(readerStrdup(reader, ns->href)); }
/** @@ -2498,7 +2629,7 @@ xmlTextReaderMoveToAttributeNo(xmlTextReaderPtr reader, int no) { int xmlTextReaderMoveToAttribute(xmlTextReaderPtr reader, const xmlChar *name) { xmlChar *prefix = NULL; - xmlChar *localname; + const xmlChar *localname; xmlNsPtr ns; xmlAttrPtr prop;
@@ -2511,8 +2642,12 @@ xmlTextReaderMoveToAttribute(xmlTextReaderPtr reader, const xmlChar *name) { if (reader->node->type != XML_ELEMENT_NODE) return(0);
- localname = xmlSplitQName2(name, &prefix); + localname = xmlSplitQName4(name, &prefix); if (localname == NULL) { + xmlTextReaderErrMemory(reader); + return(-1); + } + if (prefix == NULL) { /* * Namespace default decl */ @@ -2574,15 +2709,11 @@ xmlTextReaderMoveToAttribute(xmlTextReaderPtr reader, const xmlChar *name) { prop = prop->next; } not_found: - if (localname != NULL) - xmlFree(localname); if (prefix != NULL) xmlFree(prefix); return(0);
found: - if (localname != NULL) - xmlFree(localname); if (prefix != NULL) xmlFree(prefix); return(1); @@ -2769,12 +2900,24 @@ xmlTextReaderReadAttributeValue(xmlTextReaderPtr reader) { if (reader->faketext == NULL) { reader->faketext = xmlNewDocText(reader->node->doc, ns->href); + if (reader->faketext == NULL) { + xmlTextReaderErrMemory(reader); + return(-1); + } } else { if ((reader->faketext->content != NULL) && (reader->faketext->content != (xmlChar *) &(reader->faketext->properties))) xmlFree(reader->faketext->content); - reader->faketext->content = xmlStrdup(ns->href); + if (ns->href == NULL) { + reader->faketext->content = NULL; + } else { + reader->faketext->content = xmlStrdup(ns->href); + if (reader->faketext->content == NULL) { + xmlTextReaderErrMemory(reader); + return(-1); + } + } } reader->curnode = reader->faketext; } else { @@ -2806,7 +2949,7 @@ xmlTextReaderConstEncoding(xmlTextReaderPtr reader) { else if (reader->doc != NULL) encoding = reader->doc->encoding;
- return(CONSTSTR(encoding)); + return(constString(reader, encoding)); }
@@ -2980,14 +3123,14 @@ xmlTextReaderLocalName(xmlTextReaderPtr reader) { if (node->type == XML_NAMESPACE_DECL) { xmlNsPtr ns = (xmlNsPtr) node; if (ns->prefix == NULL) - return(xmlStrdup(BAD_CAST "xmlns")); + return(readerStrdup(reader, BAD_CAST "xmlns")); else - return(xmlStrdup(ns->prefix)); + return(readerStrdup(reader, ns->prefix)); } if ((node->type != XML_ELEMENT_NODE) && (node->type != XML_ATTRIBUTE_NODE)) return(xmlTextReaderName(reader)); - return(xmlStrdup(node->name)); + return(readerStrdup(reader, node->name)); }
/** @@ -3011,7 +3154,7 @@ xmlTextReaderConstLocalName(xmlTextReaderPtr reader) { if (node->type == XML_NAMESPACE_DECL) { xmlNsPtr ns = (xmlNsPtr) node; if (ns->prefix == NULL) - return(CONSTSTR(BAD_CAST "xmlns")); + return(constString(reader, BAD_CAST "xmlns")); else return(ns->prefix); } @@ -3046,41 +3189,41 @@ xmlTextReaderName(xmlTextReaderPtr reader) { case XML_ATTRIBUTE_NODE: if ((node->ns == NULL) || (node->ns->prefix == NULL)) - return(xmlStrdup(node->name)); + return(readerStrdup(reader, node->name));
- ret = xmlStrdup(node->ns->prefix); - ret = xmlStrcat(ret, BAD_CAST ":"); - ret = xmlStrcat(ret, node->name); + ret = xmlBuildQName(node->name, node->ns->prefix, NULL, 0); + if (ret == NULL) + xmlTextReaderErrMemory(reader); return(ret); case XML_TEXT_NODE: - return(xmlStrdup(BAD_CAST "#text")); + return(readerStrdup(reader, BAD_CAST "#text")); case XML_CDATA_SECTION_NODE: - return(xmlStrdup(BAD_CAST "#cdata-section")); + return(readerStrdup(reader, BAD_CAST "#cdata-section")); case XML_ENTITY_NODE: case XML_ENTITY_REF_NODE: - return(xmlStrdup(node->name)); + return(readerStrdup(reader, node->name)); case XML_PI_NODE: - return(xmlStrdup(node->name)); + return(readerStrdup(reader, node->name)); case XML_COMMENT_NODE: - return(xmlStrdup(BAD_CAST "#comment")); + return(readerStrdup(reader, BAD_CAST "#comment")); case XML_DOCUMENT_NODE: case XML_HTML_DOCUMENT_NODE: - return(xmlStrdup(BAD_CAST "#document")); + return(readerStrdup(reader, BAD_CAST "#document")); case XML_DOCUMENT_FRAG_NODE: - return(xmlStrdup(BAD_CAST "#document-fragment")); + return(readerStrdup(reader, BAD_CAST "#document-fragment")); case XML_NOTATION_NODE: - return(xmlStrdup(node->name)); + return(readerStrdup(reader, node->name)); case XML_DOCUMENT_TYPE_NODE: case XML_DTD_NODE: - return(xmlStrdup(node->name)); + return(readerStrdup(reader, node->name)); case XML_NAMESPACE_DECL: { xmlNsPtr ns = (xmlNsPtr) node;
- ret = xmlStrdup(BAD_CAST "xmlns"); if (ns->prefix == NULL) - return(ret); - ret = xmlStrcat(ret, BAD_CAST ":"); - ret = xmlStrcat(ret, ns->prefix); + return(readerStrdup(reader, BAD_CAST "xmlns")); + ret = xmlBuildQName(ns->prefix, BAD_CAST "xmlns", NULL, 0); + if (ret == NULL) + xmlTextReaderErrMemory(reader); return(ret); }
@@ -3119,34 +3262,34 @@ xmlTextReaderConstName(xmlTextReaderPtr reader) { if ((node->ns == NULL) || (node->ns->prefix == NULL)) return(node->name); - return(CONSTQSTR(node->ns->prefix, node->name)); + return(constQString(reader, node->ns->prefix, node->name)); case XML_TEXT_NODE: - return(CONSTSTR(BAD_CAST "#text")); + return(constString(reader, BAD_CAST "#text")); case XML_CDATA_SECTION_NODE: - return(CONSTSTR(BAD_CAST "#cdata-section")); + return(constString(reader, BAD_CAST "#cdata-section")); case XML_ENTITY_NODE: case XML_ENTITY_REF_NODE: - return(CONSTSTR(node->name)); + return(constString(reader, node->name)); case XML_PI_NODE: - return(CONSTSTR(node->name)); + return(constString(reader, node->name)); case XML_COMMENT_NODE: - return(CONSTSTR(BAD_CAST "#comment")); + return(constString(reader, BAD_CAST "#comment")); case XML_DOCUMENT_NODE: case XML_HTML_DOCUMENT_NODE: - return(CONSTSTR(BAD_CAST "#document")); + return(constString(reader, BAD_CAST "#document")); case XML_DOCUMENT_FRAG_NODE: - return(CONSTSTR(BAD_CAST "#document-fragment")); + return(constString(reader, BAD_CAST "#document-fragment")); case XML_NOTATION_NODE: - return(CONSTSTR(node->name)); + return(constString(reader, node->name)); case XML_DOCUMENT_TYPE_NODE: case XML_DTD_NODE: - return(CONSTSTR(node->name)); + return(constString(reader, node->name)); case XML_NAMESPACE_DECL: { xmlNsPtr ns = (xmlNsPtr) node;
if (ns->prefix == NULL) - return(CONSTSTR(BAD_CAST "xmlns")); - return(CONSTQSTR(BAD_CAST "xmlns", ns->prefix)); + return(constString(reader, BAD_CAST "xmlns")); + return(constQString(reader, BAD_CAST "xmlns", ns->prefix)); }
case XML_ELEMENT_DECL: @@ -3181,13 +3324,13 @@ xmlTextReaderPrefix(xmlTextReaderPtr reader) { xmlNsPtr ns = (xmlNsPtr) node; if (ns->prefix == NULL) return(NULL); - return(xmlStrdup(BAD_CAST "xmlns")); + return(readerStrdup(reader, BAD_CAST "xmlns")); } if ((node->type != XML_ELEMENT_NODE) && (node->type != XML_ATTRIBUTE_NODE)) return(NULL); if ((node->ns != NULL) && (node->ns->prefix != NULL)) - return(xmlStrdup(node->ns->prefix)); + return(readerStrdup(reader, node->ns->prefix)); return(NULL); }
@@ -3213,13 +3356,13 @@ xmlTextReaderConstPrefix(xmlTextReaderPtr reader) { xmlNsPtr ns = (xmlNsPtr) node; if (ns->prefix == NULL) return(NULL); - return(CONSTSTR(BAD_CAST "xmlns")); + return(constString(reader, BAD_CAST "xmlns")); } if ((node->type != XML_ELEMENT_NODE) && (node->type != XML_ATTRIBUTE_NODE)) return(NULL); if ((node->ns != NULL) && (node->ns->prefix != NULL)) - return(CONSTSTR(node->ns->prefix)); + return(constString(reader, node->ns->prefix)); return(NULL); }
@@ -3242,12 +3385,12 @@ xmlTextReaderNamespaceUri(xmlTextReaderPtr reader) { else node = reader->node; if (node->type == XML_NAMESPACE_DECL) - return(xmlStrdup(BAD_CAST "http://www.w3.org/2000/xmlns/")); + return(readerStrdup(reader, BAD_CAST "http://www.w3.org/2000/xmlns/")); if ((node->type != XML_ELEMENT_NODE) && (node->type != XML_ATTRIBUTE_NODE)) return(NULL); if (node->ns != NULL) - return(xmlStrdup(node->ns->href)); + return(readerStrdup(reader, node->ns->href)); return(NULL); }
@@ -3270,12 +3413,12 @@ xmlTextReaderConstNamespaceUri(xmlTextReaderPtr reader) { else node = reader->node; if (node->type == XML_NAMESPACE_DECL) - return(CONSTSTR(BAD_CAST "http://www.w3.org/2000/xmlns/")); + return(constString(reader, BAD_CAST "http://www.w3.org/2000/xmlns/")); if ((node->type != XML_ELEMENT_NODE) && (node->type != XML_ATTRIBUTE_NODE)) return(NULL); if (node->ns != NULL) - return(CONSTSTR(node->ns->href)); + return(constString(reader, node->ns->href)); return(NULL); }
@@ -3290,9 +3433,16 @@ xmlTextReaderConstNamespaceUri(xmlTextReaderPtr reader) { */ xmlChar * xmlTextReaderBaseUri(xmlTextReaderPtr reader) { + xmlChar *ret = NULL; + int result; + if ((reader == NULL) || (reader->node == NULL)) return(NULL); - return(xmlNodeGetBase(NULL, reader->node)); + result = xmlNodeGetBaseSafe(NULL, reader->node, &ret); + if (result < 0) + xmlTextReaderErrMemory(reader); + + return(ret); }
/** @@ -3308,13 +3458,16 @@ const xmlChar * xmlTextReaderConstBaseUri(xmlTextReaderPtr reader) { xmlChar *tmp; const xmlChar *ret; + int result;
if ((reader == NULL) || (reader->node == NULL)) return(NULL); - tmp = xmlNodeGetBase(NULL, reader->node); + result = xmlNodeGetBaseSafe(NULL, reader->node, &tmp); + if (result < 0) + xmlTextReaderErrMemory(reader); if (tmp == NULL) return(NULL); - ret = CONSTSTR(tmp); + ret = constString(reader, tmp); xmlFree(tmp); return(ret); } @@ -3427,23 +3580,26 @@ xmlTextReaderValue(xmlTextReaderPtr reader) {
switch (node->type) { case XML_NAMESPACE_DECL: - return(xmlStrdup(((xmlNsPtr) node)->href)); + return(readerStrdup(reader, ((xmlNsPtr) node)->href)); case XML_ATTRIBUTE_NODE:{ xmlAttrPtr attr = (xmlAttrPtr) node; + xmlDocPtr doc = NULL; + xmlChar *ret;
+ if (attr->children == NULL) + return(NULL); if (attr->parent != NULL) - return (xmlNodeListGetString - (attr->parent->doc, attr->children, 1)); - else - return (xmlNodeListGetString(NULL, attr->children, 1)); - break; + doc = attr->parent->doc; + ret = xmlNodeListGetString(doc, attr->children, 1); + if (ret == NULL) + xmlTextReaderErrMemory(reader); + return(ret); } case XML_TEXT_NODE: case XML_CDATA_SECTION_NODE: case XML_PI_NODE: case XML_COMMENT_NODE: - if (node->content != NULL) - return (xmlStrdup(node->content)); + return(readerStrdup(reader, node->content)); default: break; } @@ -3485,11 +3641,8 @@ xmlTextReaderConstValue(xmlTextReaderPtr reader) { else { if (reader->buffer == NULL) { reader->buffer = xmlBufCreateSize(100); - if (reader->buffer == NULL) { - xmlGenericError(xmlGenericErrorContext, - "xmlTextReaderSetup : malloc failed\n"); + if (reader->buffer == NULL) return (NULL); - } xmlBufSetAllocationScheme(reader->buffer, XML_BUFFER_ALLOC_DOUBLEIT); } else @@ -3497,12 +3650,12 @@ xmlTextReaderConstValue(xmlTextReaderPtr reader) { xmlBufGetNodeContent(reader->buffer, node); ret = xmlBufContent(reader->buffer); if (ret == NULL) { + xmlTextReaderErrMemory(reader); /* error on the buffer best to reallocate */ xmlBufFree(reader->buffer); reader->buffer = xmlBufCreateSize(100); xmlBufSetAllocationScheme(reader->buffer, XML_BUFFER_ALLOC_DOUBLEIT); - ret = BAD_CAST ""; } return(ret); } @@ -3589,7 +3742,7 @@ xmlTextReaderConstXmlLang(xmlTextReaderPtr reader) { tmp = xmlNodeGetLang(reader->node); if (tmp == NULL) return(NULL); - ret = CONSTSTR(tmp); + ret = constString(reader, tmp); xmlFree(tmp); return(ret); } @@ -3609,7 +3762,7 @@ const xmlChar * xmlTextReaderConstString(xmlTextReaderPtr reader, const xmlChar *str) { if (reader == NULL) return(NULL); - return(CONSTSTR(str)); + return(constString(reader, str)); }
/** @@ -3664,18 +3817,21 @@ xmlTextReaderSetParserProp(xmlTextReaderPtr reader, int prop, int value) { if (ctxt->loadsubset == 0) { if (reader->mode != XML_TEXTREADER_MODE_INITIAL) return(-1); - ctxt->loadsubset = XML_DETECT_IDS; + ctxt->options |= XML_PARSE_DTDLOAD; + ctxt->loadsubset |= XML_DETECT_IDS; } } else { - ctxt->loadsubset = 0; + ctxt->options &= ~XML_PARSE_DTDLOAD; + ctxt->loadsubset &= ~XML_DETECT_IDS; } return(0); case XML_PARSER_DEFAULTATTRS: if (value != 0) { + ctxt->options |= XML_PARSE_DTDATTR; ctxt->loadsubset |= XML_COMPLETE_ATTRS; } else { - if (ctxt->loadsubset & XML_COMPLETE_ATTRS) - ctxt->loadsubset -= XML_COMPLETE_ATTRS; + ctxt->options &= ~XML_PARSE_DTDATTR; + ctxt->loadsubset &= ~XML_COMPLETE_ATTRS; } return(0); case XML_PARSER_VALIDATE: @@ -3810,10 +3966,7 @@ xmlTextReaderPreserve(xmlTextReaderPtr reader) { if (reader == NULL) return(NULL);
- if (reader->curnode != NULL) - cur = reader->curnode; - else - cur = reader->node; + cur = reader->node; if (cur == NULL) return(NULL);
@@ -3823,7 +3976,7 @@ xmlTextReaderPreserve(xmlTextReaderPtr reader) { } reader->preserves++;
- parent = cur->parent; + parent = cur->parent;; while (parent != NULL) { if (parent->type == XML_ELEMENT_NODE) parent->extra |= NODE_IS_PRESERVED; @@ -3863,7 +4016,7 @@ xmlTextReaderPreservePattern(xmlTextReaderPtr reader, const xmlChar *pattern, reader->patternTab = (xmlPatternPtr *) xmlMalloc(reader->patternMax * sizeof(reader->patternTab[0])); if (reader->patternTab == NULL) { - xmlGenericError(xmlGenericErrorContext, "xmlMalloc failed !\n"); + xmlTextReaderErrMemory(reader); return (-1); } } @@ -3874,7 +4027,7 @@ xmlTextReaderPreservePattern(xmlTextReaderPtr reader, const xmlChar *pattern, reader->patternMax * sizeof(reader->patternTab[0])); if (tmp == NULL) { - xmlGenericError(xmlGenericErrorContext, "xmlRealloc failed !\n"); + xmlTextReaderErrMemory(reader); reader->patternMax /= 2; return (-1); } @@ -3911,80 +4064,6 @@ xmlTextReaderCurrentDoc(xmlTextReaderPtr reader) { }
#ifdef LIBXML_SCHEMAS_ENABLED -static char *xmlTextReaderBuildMessage(const char *msg, va_list ap) LIBXML_ATTR_FORMAT(1,0); - -static void -xmlTextReaderValidityError(void *ctxt, const char *msg, ...) LIBXML_ATTR_FORMAT(2,3); - -static void -xmlTextReaderValidityWarning(void *ctxt, const char *msg, ...) LIBXML_ATTR_FORMAT(2,3); - -static void -xmlTextReaderValidityErrorRelay(void *ctx, const char *msg, ...) LIBXML_ATTR_FORMAT(2,3); - -static void -xmlTextReaderValidityWarningRelay(void *ctx, const char *msg, ...) LIBXML_ATTR_FORMAT(2,3); - -static void -xmlTextReaderValidityErrorRelay(void *ctx, const char *msg, ...) -{ - xmlTextReaderPtr reader = (xmlTextReaderPtr) ctx; - - char *str; - - va_list ap; - - va_start(ap, msg); - str = xmlTextReaderBuildMessage(msg, ap); - if (!reader->errorFunc) { - xmlTextReaderValidityError(ctx, "%s", str); - } else { - reader->errorFunc(reader->errorFuncArg, str, - XML_PARSER_SEVERITY_VALIDITY_ERROR, - NULL /* locator */ ); - } - if (str != NULL) - xmlFree(str); - va_end(ap); -} - -static void -xmlTextReaderValidityWarningRelay(void *ctx, const char *msg, ...) -{ - xmlTextReaderPtr reader = (xmlTextReaderPtr) ctx; - - char *str; - - va_list ap; - - va_start(ap, msg); - str = xmlTextReaderBuildMessage(msg, ap); - if (!reader->errorFunc) { - xmlTextReaderValidityWarning(ctx, "%s", str); - } else { - reader->errorFunc(reader->errorFuncArg, str, - XML_PARSER_SEVERITY_VALIDITY_WARNING, - NULL /* locator */ ); - } - if (str != NULL) - xmlFree(str); - va_end(ap); -} - -static void -xmlTextReaderStructuredError(void *ctxt, const xmlError *error); - -static void -xmlTextReaderValidityStructuredRelay(void *userData, const xmlError *error) -{ - xmlTextReaderPtr reader = (xmlTextReaderPtr) userData; - - if (reader->sErrorFunc) { - reader->sErrorFunc(reader->errorFuncArg, error); - } else { - xmlTextReaderStructuredError(reader, error); - } -} /** * xmlTextReaderRelaxNGSetSchema: * @reader: the xmlTextReaderPtr used @@ -4031,17 +4110,9 @@ xmlTextReaderRelaxNGSetSchema(xmlTextReaderPtr reader, xmlRelaxNGPtr schema) { reader->rngValidCtxt = xmlRelaxNGNewValidCtxt(schema); if (reader->rngValidCtxt == NULL) return(-1); - if (reader->errorFunc != NULL) { - xmlRelaxNGSetValidErrors(reader->rngValidCtxt, - xmlTextReaderValidityErrorRelay, - xmlTextReaderValidityWarningRelay, - reader); - } - if (reader->sErrorFunc != NULL) { - xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, - xmlTextReaderValidityStructuredRelay, - reader); - } + if ((reader->errorFunc != NULL) || (reader->sErrorFunc != NULL)) + xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, + xmlTextReaderStructuredRelay, reader); reader->rngValidErrors = 0; reader->rngFullNode = NULL; reader->validate = XML_TEXTREADER_VALIDATE_RNG; @@ -4173,17 +4244,9 @@ xmlTextReaderSetSchema(xmlTextReaderPtr reader, xmlSchemaPtr schema) { xmlTextReaderLocator, (void *) reader);
- if (reader->errorFunc != NULL) { - xmlSchemaSetValidErrors(reader->xsdValidCtxt, - xmlTextReaderValidityErrorRelay, - xmlTextReaderValidityWarningRelay, - reader); - } - if (reader->sErrorFunc != NULL) { - xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt, - xmlTextReaderValidityStructuredRelay, - reader); - } + if ((reader->errorFunc != NULL) || (reader->sErrorFunc != NULL)) + xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt, + xmlTextReaderStructuredRelay, reader); reader->xsdValidErrors = 0; reader->validate = XML_TEXTREADER_VALIDATE_XSD; return(0); @@ -4243,21 +4306,14 @@ xmlTextReaderRelaxNGValidateInternal(xmlTextReaderPtr reader, /* Parse the schema and create validation environment. */
pctxt = xmlRelaxNGNewParserCtxt(rng); - if (reader->errorFunc != NULL) { - xmlRelaxNGSetParserErrors(pctxt, - xmlTextReaderValidityErrorRelay, - xmlTextReaderValidityWarningRelay, - reader); - } - if (reader->sErrorFunc != NULL) { - xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, - xmlTextReaderValidityStructuredRelay, - reader); - } + if ((reader->errorFunc != NULL) || (reader->sErrorFunc != NULL)) + xmlRelaxNGSetParserStructuredErrors(pctxt, + xmlTextReaderStructuredRelay, reader); reader->rngSchemas = xmlRelaxNGParse(pctxt); xmlRelaxNGFreeParserCtxt(pctxt); if (reader->rngSchemas == NULL) return(-1); + reader->rngValidCtxt = xmlRelaxNGNewValidCtxt(reader->rngSchemas); if (reader->rngValidCtxt == NULL) { xmlRelaxNGFree(reader->rngSchemas); @@ -4275,17 +4331,9 @@ xmlTextReaderRelaxNGValidateInternal(xmlTextReaderPtr reader, * TODO: In case the user provides the validation context we * could make this redirection optional. */ - if (reader->errorFunc != NULL) { - xmlRelaxNGSetValidErrors(reader->rngValidCtxt, - xmlTextReaderValidityErrorRelay, - xmlTextReaderValidityWarningRelay, - reader); - } - if (reader->sErrorFunc != NULL) { - xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, - xmlTextReaderValidityStructuredRelay, - reader); - } + if ((reader->errorFunc != NULL) || (reader->sErrorFunc != NULL)) + xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, + xmlTextReaderStructuredRelay, reader); reader->rngValidErrors = 0; reader->rngFullNode = NULL; reader->validate = XML_TEXTREADER_VALIDATE_RNG; @@ -4348,12 +4396,9 @@ xmlTextReaderSchemaValidateInternal(xmlTextReaderPtr reader, xmlSchemaParserCtxtPtr pctxt; /* Parse the schema and create validation environment. */ pctxt = xmlSchemaNewParserCtxt(xsd); - if (reader->errorFunc != NULL) { - xmlSchemaSetParserErrors(pctxt, - xmlTextReaderValidityErrorRelay, - xmlTextReaderValidityWarningRelay, - reader); - } + if ((reader->errorFunc != NULL) || (reader->sErrorFunc != NULL)) + xmlSchemaSetParserStructuredErrors(pctxt, + xmlTextReaderStructuredRelay, reader); reader->xsdSchemas = xmlSchemaParse(pctxt); xmlSchemaFreeParserCtxt(pctxt); if (reader->xsdSchemas == NULL) @@ -4396,17 +4441,9 @@ xmlTextReaderSchemaValidateInternal(xmlTextReaderPtr reader, * TODO: In case the user provides the validation context we * could make this redirection optional. */ - if (reader->errorFunc != NULL) { - xmlSchemaSetValidErrors(reader->xsdValidCtxt, - xmlTextReaderValidityErrorRelay, - xmlTextReaderValidityWarningRelay, - reader); - } - if (reader->sErrorFunc != NULL) { - xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt, - xmlTextReaderValidityStructuredRelay, - reader); - } + if ((reader->errorFunc != NULL) || (reader->sErrorFunc != NULL)) + xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt, + xmlTextReaderStructuredRelay, reader); reader->xsdValidErrors = 0; reader->validate = XML_TEXTREADER_VALIDATE_XSD; return(0); @@ -4545,7 +4582,7 @@ xmlTextReaderConstXmlVersion(xmlTextReaderPtr reader) { if (doc->version == NULL) return(NULL); else - return(CONSTSTR(doc->version)); + return(constString(reader, doc->version)); }
/** @@ -4579,43 +4616,6 @@ xmlTextReaderStandalone(xmlTextReaderPtr reader) { * * ************************************************************************/
-/* helper to build a xmlMalloc'ed string from a format and va_list */ -static char * -xmlTextReaderBuildMessage(const char *msg, va_list ap) { - int size = 0; - int chars; - char *larger; - char *str = NULL; - va_list aq; - - while (1) { - VA_COPY(aq, ap); - chars = vsnprintf(str, size, msg, aq); - va_end(aq); - if (chars < 0) { - xmlGenericError(xmlGenericErrorContext, "vsnprintf failed !\n"); - if (str) - xmlFree(str); - return NULL; - } - if ((chars < size) || (size == MAX_ERR_MSG_SIZE)) - break; - if (chars < MAX_ERR_MSG_SIZE) - size = chars + 1; - else - size = MAX_ERR_MSG_SIZE; - if ((larger = (char *) xmlRealloc(str, size)) == NULL) { - xmlGenericError(xmlGenericErrorContext, "xmlRealloc failed !\n"); - if (str) - xmlFree(str); - return NULL; - } - str = larger; - } - - return str; -} - /** * xmlTextReaderLocatorLineNumber: * @locator: the xmlTextReaderLocatorPtr used @@ -4689,105 +4689,14 @@ xmlTextReaderLocatorBaseURI(xmlTextReaderLocatorPtr locator) { return ret; }
-static void -xmlTextReaderGenericError(void *ctxt, xmlParserSeverities severity, - char *str) -{ - xmlParserCtxtPtr ctx = (xmlParserCtxtPtr) ctxt; - - xmlTextReaderPtr reader = (xmlTextReaderPtr) ctx->_private; - - if (str != NULL) { - if (reader->errorFunc) - reader->errorFunc(reader->errorFuncArg, str, severity, - (xmlTextReaderLocatorPtr) ctx); - xmlFree(str); - } -} - -static void -xmlTextReaderStructuredError(void *ctxt, const xmlError *error) -{ - xmlParserCtxtPtr ctx = (xmlParserCtxtPtr) ctxt; - - xmlTextReaderPtr reader = (xmlTextReaderPtr) ctx->_private; - - if (error && reader->sErrorFunc) { - reader->sErrorFunc(reader->errorFuncArg, (xmlErrorPtr) error); - } -} - -static void LIBXML_ATTR_FORMAT(2,3) -xmlTextReaderError(void *ctxt, const char *msg, ...) -{ - va_list ap; - - va_start(ap, msg); - xmlTextReaderGenericError(ctxt, - XML_PARSER_SEVERITY_ERROR, - xmlTextReaderBuildMessage(msg, ap)); - va_end(ap); - -} - -static void LIBXML_ATTR_FORMAT(2,3) -xmlTextReaderWarning(void *ctxt, const char *msg, ...) -{ - va_list ap; - - va_start(ap, msg); - xmlTextReaderGenericError(ctxt, - XML_PARSER_SEVERITY_WARNING, - xmlTextReaderBuildMessage(msg, ap)); - va_end(ap); -} - -static void -xmlTextReaderValidityError(void *ctxt, const char *msg, ...) -{ - va_list ap; - - int len = xmlStrlen((const xmlChar *) msg); - - if ((len > 1) && (msg[len - 2] != ':')) { - /* - * some callbacks only report locator information: - * skip them (mimicking behaviour in error.c) - */ - va_start(ap, msg); - xmlTextReaderGenericError(ctxt, - XML_PARSER_SEVERITY_VALIDITY_ERROR, - xmlTextReaderBuildMessage(msg, ap)); - va_end(ap); - } -} - -static void -xmlTextReaderValidityWarning(void *ctxt, const char *msg, ...) -{ - va_list ap; - - int len = xmlStrlen((const xmlChar *) msg); - - if ((len != 0) && (msg[len - 1] != ':')) { - /* - * some callbacks only report locator information: - * skip them (mimicking behaviour in error.c) - */ - va_start(ap, msg); - xmlTextReaderGenericError(ctxt, - XML_PARSER_SEVERITY_VALIDITY_WARNING, - xmlTextReaderBuildMessage(msg, ap)); - va_end(ap); - } -} - /** * xmlTextReaderSetErrorHandler: * @reader: the xmlTextReaderPtr used * @f: the callback function to call on error and warnings * @arg: a user argument to pass to the callback function * + * DEPRECATED: Use xmlTextReaderSetStructuredErrorHandler. + * * Register a callback function that will be called on error and warnings. * * If @f is NULL, the default error and warning handlers are restored. @@ -4797,53 +4706,35 @@ xmlTextReaderSetErrorHandler(xmlTextReaderPtr reader, xmlTextReaderErrorFunc f, void *arg) { if (f != NULL) { - reader->ctxt->sax->error = xmlTextReaderError; - reader->ctxt->sax->serror = NULL; - reader->ctxt->vctxt.error = xmlTextReaderValidityError; - reader->ctxt->sax->warning = xmlTextReaderWarning; - reader->ctxt->vctxt.warning = xmlTextReaderValidityWarning; reader->errorFunc = f; reader->sErrorFunc = NULL; reader->errorFuncArg = arg; + xmlCtxtSetErrorHandler(reader->ctxt, + xmlTextReaderStructuredRelay, reader); #ifdef LIBXML_SCHEMAS_ENABLED if (reader->rngValidCtxt) { - xmlRelaxNGSetValidErrors(reader->rngValidCtxt, - xmlTextReaderValidityErrorRelay, - xmlTextReaderValidityWarningRelay, - reader); - xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, NULL, - reader); + xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, + xmlTextReaderStructuredRelay, reader); } if (reader->xsdValidCtxt) { - xmlSchemaSetValidErrors(reader->xsdValidCtxt, - xmlTextReaderValidityErrorRelay, - xmlTextReaderValidityWarningRelay, - reader); - xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt, NULL, - reader); + xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt, + xmlTextReaderStructuredRelay, reader); } #endif } else { /* restore defaults */ - reader->ctxt->sax->error = xmlParserError; - reader->ctxt->vctxt.error = xmlParserValidityError; - reader->ctxt->sax->warning = xmlParserWarning; - reader->ctxt->vctxt.warning = xmlParserValidityWarning; reader->errorFunc = NULL; reader->sErrorFunc = NULL; reader->errorFuncArg = NULL; + xmlCtxtSetErrorHandler(reader->ctxt, NULL, NULL); #ifdef LIBXML_SCHEMAS_ENABLED if (reader->rngValidCtxt) { - xmlRelaxNGSetValidErrors(reader->rngValidCtxt, NULL, NULL, - reader); xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, NULL, - reader); + NULL); } if (reader->xsdValidCtxt) { - xmlSchemaSetValidErrors(reader->xsdValidCtxt, NULL, NULL, - reader); xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt, NULL, - reader); + NULL); } #endif } @@ -4864,52 +4755,35 @@ xmlTextReaderSetStructuredErrorHandler(xmlTextReaderPtr reader, xmlStructuredErrorFunc f, void *arg) { if (f != NULL) { - reader->ctxt->sax->error = NULL; - reader->ctxt->sax->serror = xmlTextReaderStructuredError; - reader->ctxt->vctxt.error = xmlTextReaderValidityError; - reader->ctxt->sax->warning = xmlTextReaderWarning; - reader->ctxt->vctxt.warning = xmlTextReaderValidityWarning; reader->sErrorFunc = f; reader->errorFunc = NULL; reader->errorFuncArg = arg; + xmlCtxtSetErrorHandler(reader->ctxt, + xmlTextReaderStructuredRelay, reader); #ifdef LIBXML_SCHEMAS_ENABLED if (reader->rngValidCtxt) { - xmlRelaxNGSetValidErrors(reader->rngValidCtxt, NULL, NULL, - reader); xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, - xmlTextReaderValidityStructuredRelay, - reader); + xmlTextReaderStructuredRelay, reader); } if (reader->xsdValidCtxt) { - xmlSchemaSetValidErrors(reader->xsdValidCtxt, NULL, NULL, - reader); xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt, - xmlTextReaderValidityStructuredRelay, - reader); + xmlTextReaderStructuredRelay, reader); } #endif } else { /* restore defaults */ - reader->ctxt->sax->error = xmlParserError; - reader->ctxt->sax->serror = NULL; - reader->ctxt->vctxt.error = xmlParserValidityError; - reader->ctxt->sax->warning = xmlParserWarning; - reader->ctxt->vctxt.warning = xmlParserValidityWarning; reader->errorFunc = NULL; reader->sErrorFunc = NULL; reader->errorFuncArg = NULL; + xmlCtxtSetErrorHandler(reader->ctxt, NULL, NULL); #ifdef LIBXML_SCHEMAS_ENABLED if (reader->rngValidCtxt) { - xmlRelaxNGSetValidErrors(reader->rngValidCtxt, NULL, NULL, - reader); xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, NULL, - reader); + NULL); } if (reader->xsdValidCtxt) { - xmlSchemaSetValidErrors(reader->xsdValidCtxt, NULL, NULL, - reader); xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt, NULL, - reader); + NULL); } #endif } @@ -5009,8 +4883,6 @@ xmlTextReaderSetup(xmlTextReaderPtr reader, if (reader->buffer == NULL) reader->buffer = xmlBufCreateSize(100); if (reader->buffer == NULL) { - xmlGenericError(xmlGenericErrorContext, - "xmlTextReaderSetup : malloc failed\n"); return (-1); } /* no operation on a reader should require a huge buffer */ @@ -5019,8 +4891,6 @@ xmlTextReaderSetup(xmlTextReaderPtr reader, if (reader->sax == NULL) reader->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler)); if (reader->sax == NULL) { - xmlGenericError(xmlGenericErrorContext, - "xmlTextReaderSetup : malloc failed\n"); return (-1); } xmlSAXVersion(reader->sax, 2); @@ -5067,13 +4937,15 @@ xmlTextReaderSetup(xmlTextReaderPtr reader, reader->base = 0; reader->cur = 0; } + if (reader->ctxt == NULL) { + return (-1); + } } else { xmlParserInputPtr inputStream; xmlParserInputBufferPtr buf; - xmlCharEncoding enc = XML_CHAR_ENCODING_NONE;
xmlCtxtReset(reader->ctxt); - buf = xmlAllocParserInputBuffer(enc); + buf = xmlAllocParserInputBuffer(XML_CHAR_ENCODING_NONE); if (buf == NULL) return(-1); inputStream = xmlNewInputStream(reader->ctxt); if (inputStream == NULL) { @@ -5092,11 +4964,6 @@ xmlTextReaderSetup(xmlTextReaderPtr reader, inputPush(reader->ctxt, inputStream); reader->cur = 0; } - if (reader->ctxt == NULL) { - xmlGenericError(xmlGenericErrorContext, - "xmlTextReaderSetup : malloc failed\n"); - return (-1); - } } if (reader->dict != NULL) { if (reader->ctxt->dict != NULL) { @@ -5118,7 +4985,6 @@ xmlTextReaderSetup(xmlTextReaderPtr reader, /* * use the parser dictionary to allocate all elements and attributes names */ - reader->ctxt->docdict = 1; reader->ctxt->parseMode = XML_PARSE_READER;
#ifdef LIBXML_XINCLUDE_ENABLED @@ -5129,6 +4995,8 @@ xmlTextReaderSetup(xmlTextReaderPtr reader, if (options & XML_PARSE_XINCLUDE) { reader->xinclude = 1; reader->xinclude_name = xmlDictLookup(reader->dict, XINCLUDE_NODE, -1); + if (reader->xinclude_name == NULL) + return(-1); options -= XML_PARSE_XINCLUDE; } else reader->xinclude = 0; @@ -5152,17 +5020,15 @@ xmlTextReaderSetup(xmlTextReaderPtr reader, reader->validate = XML_TEXTREADER_VALIDATE_DTD;
xmlCtxtUseOptions(reader->ctxt, options); - if (encoding != NULL) { - xmlCharEncodingHandlerPtr hdlr; - - hdlr = xmlFindCharEncodingHandler(encoding); - if (hdlr != NULL) - xmlSwitchToEncoding(reader->ctxt, hdlr); - } + if (encoding != NULL) + xmlSwitchEncodingName(reader->ctxt, encoding); if ((URL != NULL) && (reader->ctxt->input != NULL) && - (reader->ctxt->input->filename == NULL)) + (reader->ctxt->input->filename == NULL)) { reader->ctxt->input->filename = (char *) xmlStrdup((const xmlChar *) URL); + if (reader->ctxt->input->filename == NULL) + return(-1); + }
reader->doc = NULL;
@@ -5182,6 +5048,22 @@ xmlTextReaderSetMaxAmplification(xmlTextReaderPtr reader, unsigned maxAmpl) xmlCtxtSetMaxAmplification(reader->ctxt, maxAmpl); }
+/** + * xmlTextReaderGetLastError: + * @reader: an XML reader + * + * Available since 2.13.0. + * + * Returns the last error. + */ +const xmlError * +xmlTextReaderGetLastError(xmlTextReaderPtr reader) +{ + if (reader == NULL) + return(NULL); + return(&reader->ctxt->lastError); +} + /** * xmlTextReaderByteConsumed: * @reader: an XML reader @@ -5221,8 +5103,6 @@ xmlReaderWalker(xmlDocPtr doc)
ret = xmlMalloc(sizeof(xmlTextReader)); if (ret == NULL) { - xmlGenericError(xmlGenericErrorContext, - "xmlNewTextReader : malloc failed\n"); return(NULL); } memset(ret, 0, sizeof(xmlTextReader)); @@ -5285,7 +5165,10 @@ xmlReaderForFile(const char *filename, const char *encoding, int options) reader = xmlNewTextReaderFilename(filename); if (reader == NULL) return (NULL); - xmlTextReaderSetup(reader, NULL, NULL, encoding, options); + if (xmlTextReaderSetup(reader, NULL, NULL, encoding, options) < 0) { + xmlFreeTextReader(reader); + return (NULL); + } return (reader); }
@@ -5319,7 +5202,10 @@ xmlReaderForMemory(const char *buffer, int size, const char *URL, return (NULL); } reader->allocs |= XML_TEXTREADER_INPUT; - xmlTextReaderSetup(reader, NULL, URL, encoding, options); + if (xmlTextReaderSetup(reader, NULL, URL, encoding, options) < 0) { + xmlFreeTextReader(reader); + return (NULL); + } return (reader); }
@@ -5356,7 +5242,10 @@ xmlReaderForFd(int fd, const char *URL, const char *encoding, int options) return (NULL); } reader->allocs |= XML_TEXTREADER_INPUT; - xmlTextReaderSetup(reader, NULL, URL, encoding, options); + if (xmlTextReaderSetup(reader, NULL, URL, encoding, options) < 0) { + xmlFreeTextReader(reader); + return (NULL); + } return (reader); }
@@ -5398,7 +5287,10 @@ xmlReaderForIO(xmlInputReadCallback ioread, xmlInputCloseCallback ioclose, return (NULL); } reader->allocs |= XML_TEXTREADER_INPUT; - xmlTextReaderSetup(reader, NULL, URL, encoding, options); + if (xmlTextReaderSetup(reader, NULL, URL, encoding, options) < 0) { + xmlFreeTextReader(reader); + return (NULL); + } return (reader); }
diff --git a/libs/xml2/xmlregexp.c b/libs/xml2/xmlregexp.c index f434a0cf986..31e3d1a6229 100644 --- a/libs/xml2/xmlregexp.c +++ b/libs/xml2/xmlregexp.c @@ -38,16 +38,6 @@
#define MAX_PUSH 10000000
-/* - * -2 and -3 are used by xmlValidateElementType for other things. - */ -#define XML_REGEXP_OK 0 -#define XML_REGEXP_NOT_FOUND (-1) -#define XML_REGEXP_INTERNAL_ERROR (-4) -#define XML_REGEXP_OUT_OF_MEMORY (-5) -#define XML_REGEXP_INTERNAL_LIMIT (-6) -#define XML_REGEXP_INVALID_UTF8 (-7) - #ifdef ERROR #undef ERROR #endif @@ -66,16 +56,6 @@ */ #define PREV (ctxt->cur[-1])
-/** - * TODO: - * - * macro to flag unimplemented blocks - */ -#define TODO \ - xmlGenericError(xmlGenericErrorContext, \ - "Unimplemented block at %s:%d\n", \ - __FILE__, __LINE__); - /************************************************************************ * * * Datatypes and structures * @@ -378,17 +358,12 @@ static int xmlRegCheckCharacterRange(xmlRegAtomType type, int codepoint, * Handle an out of memory condition */ static void -xmlRegexpErrMemory(xmlRegParserCtxtPtr ctxt, const char *extra) +xmlRegexpErrMemory(xmlRegParserCtxtPtr ctxt) { - const char *regexp = NULL; - if (ctxt != NULL) { - regexp = (const char *) ctxt->string; - ctxt->error = XML_ERR_NO_MEMORY; - } - __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_REGEXP, - XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra, - regexp, NULL, 0, 0, - "Memory allocation failed : %s\n", extra); + if (ctxt != NULL) + ctxt->error = XML_ERR_NO_MEMORY; + + xmlRaiseMemoryError(NULL, NULL, NULL, XML_FROM_REGEXP, NULL); }
/** @@ -402,16 +377,20 @@ xmlRegexpErrCompile(xmlRegParserCtxtPtr ctxt, const char *extra) { const char *regexp = NULL; int idx = 0; + int res;
if (ctxt != NULL) { regexp = (const char *) ctxt->string; idx = ctxt->cur - ctxt->string; ctxt->error = XML_REGEXP_COMPILE_ERROR; } - __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_REGEXP, - XML_REGEXP_COMPILE_ERROR, XML_ERR_FATAL, NULL, 0, extra, - regexp, NULL, idx, 0, - "failed to compile: %s\n", extra); + + res = __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_REGEXP, + XML_REGEXP_COMPILE_ERROR, XML_ERR_FATAL, + NULL, 0, extra, regexp, NULL, idx, 0, + "failed to compile: %s\n", extra); + if (res < 0) + xmlRegexpErrMemory(ctxt); }
/************************************************************************ @@ -462,7 +441,7 @@ xmlRegEpxFromParse(xmlRegParserCtxtPtr ctxt) {
ret = (xmlRegexpPtr) xmlMalloc(sizeof(xmlRegexp)); if (ret == NULL) { - xmlRegexpErrMemory(ctxt, "compiling regexp"); + xmlRegexpErrMemory(ctxt); return(NULL); } memset(ret, 0, sizeof(xmlRegexp)); @@ -477,7 +456,7 @@ xmlRegEpxFromParse(xmlRegParserCtxtPtr ctxt) { ret->flags = ctxt->flags; if (ret->determinist == -1) { if (xmlRegexpIsDeterminist(ret) < 0) { - xmlRegexpErrMemory(ctxt, "checking determinism"); + xmlRegexpErrMemory(ctxt); xmlFree(ret); return(NULL); } @@ -507,7 +486,7 @@ xmlRegEpxFromParse(xmlRegParserCtxtPtr ctxt) {
stateRemap = xmlMalloc(ret->nbStates * sizeof(int)); if (stateRemap == NULL) { - xmlRegexpErrMemory(ctxt, "compiling regexp"); + xmlRegexpErrMemory(ctxt); xmlFree(ret); return(NULL); } @@ -521,14 +500,14 @@ xmlRegEpxFromParse(xmlRegParserCtxtPtr ctxt) { } stringMap = xmlMalloc(ret->nbAtoms * sizeof(char *)); if (stringMap == NULL) { - xmlRegexpErrMemory(ctxt, "compiling regexp"); + xmlRegexpErrMemory(ctxt); xmlFree(stateRemap); xmlFree(ret); return(NULL); } stringRemap = xmlMalloc(ret->nbAtoms * sizeof(int)); if (stringRemap == NULL) { - xmlRegexpErrMemory(ctxt, "compiling regexp"); + xmlRegexpErrMemory(ctxt); xmlFree(stringMap); xmlFree(stateRemap); xmlFree(ret); @@ -607,7 +586,7 @@ xmlRegEpxFromParse(xmlRegParserCtxtPtr ctxt) { transdata = (void **) xmlRegCalloc2(nbstates, nbatoms, sizeof(void *)); if (transdata == NULL) { - xmlRegexpErrMemory(ctxt, "compiling regexp"); + xmlRegexpErrMemory(ctxt); break; } } @@ -698,8 +677,13 @@ xmlRegNewParserCtxt(const xmlChar *string) { if (ret == NULL) return(NULL); memset(ret, 0, sizeof(xmlRegParserCtxt)); - if (string != NULL) + if (string != NULL) { ret->string = xmlStrdup(string); + if (ret->string == NULL) { + xmlFree(ret); + return(NULL); + } + } ret->cur = ret->string; ret->neg = 0; ret->negs = 0; @@ -727,7 +711,7 @@ xmlRegNewRange(xmlRegParserCtxtPtr ctxt,
ret = (xmlRegRangePtr) xmlMalloc(sizeof(xmlRegRange)); if (ret == NULL) { - xmlRegexpErrMemory(ctxt, "allocating range"); + xmlRegexpErrMemory(ctxt); return(NULL); } ret->neg = neg; @@ -775,7 +759,7 @@ xmlRegCopyRange(xmlRegParserCtxtPtr ctxt, xmlRegRangePtr range) { if (range->blockName != NULL) { ret->blockName = xmlStrdup(range->blockName); if (ret->blockName == NULL) { - xmlRegexpErrMemory(ctxt, "allocating range"); + xmlRegexpErrMemory(ctxt); xmlRegFreeRange(ret); return(NULL); } @@ -798,7 +782,7 @@ xmlRegNewAtom(xmlRegParserCtxtPtr ctxt, xmlRegAtomType type) {
ret = (xmlRegAtomPtr) xmlMalloc(sizeof(xmlRegAtom)); if (ret == NULL) { - xmlRegexpErrMemory(ctxt, "allocating atom"); + xmlRegexpErrMemory(ctxt); return(NULL); } memset(ret, 0, sizeof(xmlRegAtom)); @@ -850,7 +834,7 @@ xmlRegCopyAtom(xmlRegParserCtxtPtr ctxt, xmlRegAtomPtr atom) {
ret = (xmlRegAtomPtr) xmlMalloc(sizeof(xmlRegAtom)); if (ret == NULL) { - xmlRegexpErrMemory(ctxt, "copying atom"); + xmlRegexpErrMemory(ctxt); return(NULL); } memset(ret, 0, sizeof(xmlRegAtom)); @@ -864,7 +848,7 @@ xmlRegCopyAtom(xmlRegParserCtxtPtr ctxt, xmlRegAtomPtr atom) { ret->ranges = (xmlRegRangePtr *) xmlMalloc(sizeof(xmlRegRangePtr) * atom->nbRanges); if (ret->ranges == NULL) { - xmlRegexpErrMemory(ctxt, "copying atom"); + xmlRegexpErrMemory(ctxt); goto error; } for (i = 0;i < atom->nbRanges;i++) { @@ -887,7 +871,7 @@ xmlRegNewState(xmlRegParserCtxtPtr ctxt) {
ret = (xmlRegStatePtr) xmlMalloc(sizeof(xmlRegState)); if (ret == NULL) { - xmlRegexpErrMemory(ctxt, "allocating state"); + xmlRegexpErrMemory(ctxt); return(NULL); } memset(ret, 0, sizeof(xmlRegState)); @@ -1199,7 +1183,7 @@ xmlRegAtomAddRange(xmlRegParserCtxtPtr ctxt, xmlRegAtomPtr atom, atom->ranges = (xmlRegRangePtr *) xmlMalloc(atom->maxRanges * sizeof(xmlRegRangePtr)); if (atom->ranges == NULL) { - xmlRegexpErrMemory(ctxt, "adding ranges"); + xmlRegexpErrMemory(ctxt); atom->maxRanges = 0; return(NULL); } @@ -1209,7 +1193,7 @@ xmlRegAtomAddRange(xmlRegParserCtxtPtr ctxt, xmlRegAtomPtr atom, tmp = (xmlRegRangePtr *) xmlRealloc(atom->ranges, atom->maxRanges * sizeof(xmlRegRangePtr)); if (tmp == NULL) { - xmlRegexpErrMemory(ctxt, "adding ranges"); + xmlRegexpErrMemory(ctxt); atom->maxRanges /= 2; return(NULL); } @@ -1231,7 +1215,7 @@ xmlRegGetCounter(xmlRegParserCtxtPtr ctxt) { ctxt->counters = (xmlRegCounter *) xmlMalloc(ctxt->maxCounters * sizeof(xmlRegCounter)); if (ctxt->counters == NULL) { - xmlRegexpErrMemory(ctxt, "allocating counter"); + xmlRegexpErrMemory(ctxt); ctxt->maxCounters = 0; return(-1); } @@ -1241,7 +1225,7 @@ xmlRegGetCounter(xmlRegParserCtxtPtr ctxt) { tmp = (xmlRegCounter *) xmlRealloc(ctxt->counters, ctxt->maxCounters * sizeof(xmlRegCounter)); if (tmp == NULL) { - xmlRegexpErrMemory(ctxt, "allocating counter"); + xmlRegexpErrMemory(ctxt); ctxt->maxCounters /= 2; return(-1); } @@ -1264,7 +1248,7 @@ xmlRegAtomPush(xmlRegParserCtxtPtr ctxt, xmlRegAtomPtr atom) {
tmp = xmlRealloc(ctxt->atoms, newSize * sizeof(xmlRegAtomPtr)); if (tmp == NULL) { - xmlRegexpErrMemory(ctxt, "allocating counter"); + xmlRegexpErrMemory(ctxt); return(-1); } ctxt->atoms = tmp; @@ -1283,7 +1267,7 @@ xmlRegStateAddTransTo(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr target, target->transTo = (int *) xmlMalloc(target->maxTransTo * sizeof(int)); if (target->transTo == NULL) { - xmlRegexpErrMemory(ctxt, "adding transition"); + xmlRegexpErrMemory(ctxt); target->maxTransTo = 0; return; } @@ -1293,7 +1277,7 @@ xmlRegStateAddTransTo(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr target, tmp = (int *) xmlRealloc(target->transTo, target->maxTransTo * sizeof(int)); if (tmp == NULL) { - xmlRegexpErrMemory(ctxt, "adding transition"); + xmlRegexpErrMemory(ctxt); target->maxTransTo /= 2; return; } @@ -1339,7 +1323,7 @@ xmlRegStateAddTrans(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr state, state->trans = (xmlRegTrans *) xmlMalloc(state->maxTrans * sizeof(xmlRegTrans)); if (state->trans == NULL) { - xmlRegexpErrMemory(ctxt, "adding transition"); + xmlRegexpErrMemory(ctxt); state->maxTrans = 0; return; } @@ -1349,7 +1333,7 @@ xmlRegStateAddTrans(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr state, tmp = (xmlRegTrans *) xmlRealloc(state->trans, state->maxTrans * sizeof(xmlRegTrans)); if (tmp == NULL) { - xmlRegexpErrMemory(ctxt, "adding transition"); + xmlRegexpErrMemory(ctxt); state->maxTrans /= 2; return; } @@ -1375,7 +1359,7 @@ xmlRegStatePush(xmlRegParserCtxtPtr ctxt) {
tmp = xmlRealloc(ctxt->states, newSize * sizeof(tmp[0])); if (tmp == NULL) { - xmlRegexpErrMemory(ctxt, "adding state"); + xmlRegexpErrMemory(ctxt); return(NULL); } ctxt->states = tmp; @@ -3060,7 +3044,6 @@ xmlFARegExecSave(xmlRegExecCtxtPtr exec) { exec->rollbacks = (xmlRegExecRollback *) xmlMalloc(exec->maxRollbacks * sizeof(xmlRegExecRollback)); if (exec->rollbacks == NULL) { - xmlRegexpErrMemory(NULL, "saving regexp"); exec->maxRollbacks = 0; exec->status = XML_REGEXP_OUT_OF_MEMORY; return; @@ -3075,7 +3058,6 @@ xmlFARegExecSave(xmlRegExecCtxtPtr exec) { tmp = (xmlRegExecRollback *) xmlRealloc(exec->rollbacks, exec->maxRollbacks * sizeof(xmlRegExecRollback)); if (tmp == NULL) { - xmlRegexpErrMemory(NULL, "saving regexp"); exec->maxRollbacks /= 2; exec->status = XML_REGEXP_OUT_OF_MEMORY; return; @@ -3092,7 +3074,6 @@ xmlFARegExecSave(xmlRegExecCtxtPtr exec) { exec->rollbacks[exec->nbRollbacks].counts = (int *) xmlMalloc(exec->comp->nbCounters * sizeof(int)); if (exec->rollbacks[exec->nbRollbacks].counts == NULL) { - xmlRegexpErrMemory(NULL, "saving regexp"); exec->status = XML_REGEXP_OUT_OF_MEMORY; return; } @@ -3157,7 +3138,6 @@ xmlFARegExec(xmlRegexpPtr comp, const xmlChar *content) { if (comp->nbCounters > 0) { exec->counts = (int *) xmlMalloc(comp->nbCounters * sizeof(int)); if (exec->counts == NULL) { - xmlRegexpErrMemory(NULL, "running regexp"); return(XML_REGEXP_OUT_OF_MEMORY); } memset(exec->counts, 0, comp->nbCounters * sizeof(int)); @@ -3440,10 +3420,8 @@ xmlRegNewExecCtxt(xmlRegexpPtr comp, xmlRegExecCallbacks callback, void *data) { if ((comp->compact == NULL) && (comp->states == NULL)) return(NULL); exec = (xmlRegExecCtxtPtr) xmlMalloc(sizeof(xmlRegExecCtxt)); - if (exec == NULL) { - xmlRegexpErrMemory(NULL, "creating execution context"); + if (exec == NULL) return(NULL); - } memset(exec, 0, sizeof(xmlRegExecCtxt)); exec->inputString = NULL; exec->index = 0; @@ -3467,7 +3445,6 @@ xmlRegNewExecCtxt(xmlRegexpPtr comp, xmlRegExecCallbacks callback, void *data) { exec->counts = (int *) xmlMalloc(comp->nbCounters * sizeof(int) * 2); if (exec->counts == NULL) { - xmlRegexpErrMemory(NULL, "creating execution context"); xmlFree(exec); return(NULL); } @@ -3523,6 +3500,22 @@ xmlRegFreeExecCtxt(xmlRegExecCtxtPtr exec) { xmlFree(exec); }
+static int +xmlRegExecSetErrString(xmlRegExecCtxtPtr exec, const xmlChar *value) { + if (exec->errString != NULL) + xmlFree(exec->errString); + if (value == NULL) { + exec->errString = NULL; + } else { + exec->errString = xmlStrdup(value); + if (exec->errString == NULL) { + exec->status = XML_REGEXP_OUT_OF_MEMORY; + return(-1); + } + } + return(0); +} + static void xmlFARegExecSaveInputString(xmlRegExecCtxtPtr exec, const xmlChar *value, void *data) { @@ -3531,8 +3524,8 @@ xmlFARegExecSaveInputString(xmlRegExecCtxtPtr exec, const xmlChar *value, exec->inputStack = (xmlRegInputTokenPtr) xmlMalloc(exec->inputStackMax * sizeof(xmlRegInputToken)); if (exec->inputStack == NULL) { - xmlRegexpErrMemory(NULL, "pushing input string"); exec->inputStackMax = 0; + exec->status = XML_REGEXP_OUT_OF_MEMORY; return; } } else if (exec->inputStackNr + 1 >= exec->inputStackMax) { @@ -3542,13 +3535,21 @@ xmlFARegExecSaveInputString(xmlRegExecCtxtPtr exec, const xmlChar *value, tmp = (xmlRegInputTokenPtr) xmlRealloc(exec->inputStack, exec->inputStackMax * sizeof(xmlRegInputToken)); if (tmp == NULL) { - xmlRegexpErrMemory(NULL, "pushing input string"); exec->inputStackMax /= 2; + exec->status = XML_REGEXP_OUT_OF_MEMORY; return; } exec->inputStack = tmp; } - exec->inputStack[exec->inputStackNr].value = xmlStrdup(value); + if (value == NULL) { + exec->inputStack[exec->inputStackNr].value = NULL; + } else { + exec->inputStack[exec->inputStackNr].value = xmlStrdup(value); + if (exec->inputStack[exec->inputStackNr].value == NULL) { + exec->status = XML_REGEXP_OUT_OF_MEMORY; + return; + } + } exec->inputStack[exec->inputStackNr].data = data; exec->inputStackNr++; exec->inputStack[exec->inputStackNr].value = NULL; @@ -3667,12 +3668,10 @@ xmlRegCompactPushString(xmlRegExecCtxtPtr exec, * current token */ error: - if (exec->errString != NULL) - xmlFree(exec->errString); - exec->errString = xmlStrdup(value); exec->errStateNo = state; exec->status = XML_REGEXP_NOT_FOUND; - return(XML_REGEXP_NOT_FOUND); + xmlRegExecSetErrString(exec, value); + return(exec->status); }
/** @@ -3921,9 +3920,8 @@ xmlRegExecPushStringInternal(xmlRegExecCtxtPtr exec, const xmlChar *value, * entering a sink state, save the current state as error * state. */ - if (exec->errString != NULL) - xmlFree(exec->errString); - exec->errString = xmlStrdup(value); + if (xmlRegExecSetErrString(exec, value) < 0) + break; exec->errState = exec->state; memcpy(exec->errCounts, exec->counts, exec->comp->nbCounters * sizeof(int)); @@ -3960,9 +3958,8 @@ rollback: if ((progress) && (exec->state != NULL) && (exec->state->type != XML_REGEXP_SINK_STATE)) { progress = 0; - if (exec->errString != NULL) - xmlFree(exec->errString); - exec->errString = xmlStrdup(value); + if (xmlRegExecSetErrString(exec, value) < 0) + break; exec->errState = exec->state; if (exec->comp->nbCounters) memcpy(exec->errCounts, exec->counts, @@ -4160,10 +4157,8 @@ xmlRegExecGetValues(xmlRegExecCtxtPtr exec, int err, continue; if (trans->count == REGEXP_ALL_LAX_COUNTER) { /* this should not be reached but ... */ - TODO; } else if (trans->count == REGEXP_ALL_COUNTER) { /* this should not be reached but ... */ - TODO; } else if (trans->counter >= 0) { xmlRegCounterPtr counter = NULL; int count; @@ -4665,6 +4660,8 @@ xmlFAParseCharProp(xmlRegParserCtxtPtr ctxt) { } type = XML_REGEXP_BLOCK_NAME; blockName = xmlStrndup(start, ctxt->cur - start); + if (blockName == NULL) + xmlRegexpErrMemory(ctxt); } else { ERROR("Unknown char property"); return; @@ -5676,6 +5673,11 @@ xmlAutomataNewTransition(xmlAutomataPtr am, xmlAutomataStatePtr from, return(NULL); atom->data = data; atom->valuep = xmlStrdup(token); + if (atom->valuep == NULL) { + xmlRegFreeAtom(atom); + xmlRegexpErrMemory(am); + return(NULL); + }
if (xmlFAGenerateTransitions(am, from, to, atom) < 0) { xmlRegFreeAtom(atom); @@ -6287,6 +6289,8 @@ xmlAutomataCompile(xmlAutomataPtr am) {
if ((am == NULL) || (am->error != 0)) return(NULL); xmlFAEliminateEpsilonTransitions(am); + if (am->error != 0) + return(NULL); /* xmlFAComputesDeterminism(am); */ ret = xmlRegEpxFromParse(am);
diff --git a/libs/xml2/xmlsave.c b/libs/xml2/xmlsave.c index dc48c573033..94c0b14d472 100644 --- a/libs/xml2/xmlsave.c +++ b/libs/xml2/xmlsave.c @@ -9,6 +9,8 @@ #define IN_LIBXML #include "libxml.h"
+#include <limits.h> +#include <stdlib.h> #include <string.h> #include <libxml/xmlmemory.h> #include <libxml/parserInternals.h> @@ -22,17 +24,13 @@ #include "private/buf.h" #include "private/enc.h" #include "private/error.h" +#include "private/io.h" #include "private/save.h"
#ifdef LIBXML_OUTPUT_ENABLED
#define XHTML_NS_NAME BAD_CAST "http://www.w3.org/1999/xhtml"
-#define TODO \ - xmlGenericError(xmlGenericErrorContext, \ - "Unimplemented block at %s:%d\n", \ - __FILE__, __LINE__); - struct _xmlSaveCtxt { void *_private; int type; @@ -63,9 +61,11 @@ struct _xmlSaveCtxt { * Handle an out of memory condition */ static void -xmlSaveErrMemory(const char *extra) +xmlSaveErrMemory(xmlOutputBufferPtr out) { - __xmlSimpleError(XML_FROM_OUTPUT, XML_ERR_NO_MEMORY, NULL, NULL, extra); + if (out != NULL) + out->error = XML_ERR_NO_MEMORY; + xmlRaiseMemoryError(NULL, NULL, NULL, XML_FROM_OUTPUT, NULL); }
/** @@ -77,9 +77,23 @@ xmlSaveErrMemory(const char *extra) * Handle an out of memory condition */ static void -xmlSaveErr(int code, xmlNodePtr node, const char *extra) +xmlSaveErr(xmlOutputBufferPtr out, int code, xmlNodePtr node, + const char *extra) { const char *msg = NULL; + int res; + + /* Don't overwrite memory errors */ + if ((out != NULL) && (out->error == XML_ERR_NO_MEMORY)) + return; + + if (code == XML_ERR_NO_MEMORY) { + xmlSaveErrMemory(out); + return; + } + + if (out != NULL) + out->error = code;
switch(code) { case XML_SAVE_NOT_UTF8: @@ -97,7 +111,13 @@ xmlSaveErr(int code, xmlNodePtr node, const char *extra) default: msg = "unexpected error number\n"; } - __xmlSimpleError(XML_FROM_OUTPUT, code, node, msg, extra); + + res = __xmlRaiseError(NULL, NULL, NULL, NULL, node, + XML_FROM_OUTPUT, code, XML_ERR_ERROR, NULL, 0, + extra, NULL, NULL, 0, 0, + msg, extra); + if (res < 0) + xmlSaveErrMemory(out); }
/************************************************************************ @@ -198,79 +218,52 @@ xmlEscapeEntities(unsigned char* out, int *outlen, *out++ = ';'; in++; continue; + } else if (*in == 0xD) { + if (outend - out < 5) break; + *out++ = '&'; + *out++ = '#'; + *out++ = 'x'; + *out++ = 'D'; + *out++ = ';'; + in++; } else if (((*in >= 0x20) && (*in < 0x80)) || - (*in == '\n') || (*in == '\t')) { + (*in == 0xA) || (*in == 0x9)) { /* * default case, just copy ! */ *out++ = *in++; continue; - } else if (*in >= 0x80) { - /* - * We assume we have UTF-8 input. - */ + } else if (*in < 0x80) { + /* invalid control char */ + if (outend - out < 8) break; + out = xmlSerializeHexCharRef(out, 0xFFFD); + in++; + } else { + int len; + if (outend - out < 11) break;
- if (*in < 0xC0) { - xmlSaveErr(XML_SAVE_NOT_UTF8, NULL, NULL); - in++; - goto error; - } else if (*in < 0xE0) { - if (inend - in < 2) break; - val = (in[0]) & 0x1F; - val <<= 6; - val |= (in[1]) & 0x3F; - in += 2; - } else if (*in < 0xF0) { - if (inend - in < 3) break; - val = (in[0]) & 0x0F; - val <<= 6; - val |= (in[1]) & 0x3F; - val <<= 6; - val |= (in[2]) & 0x3F; - in += 3; - } else if (*in < 0xF8) { - if (inend - in < 4) break; - val = (in[0]) & 0x07; - val <<= 6; - val |= (in[1]) & 0x3F; - val <<= 6; - val |= (in[2]) & 0x3F; - val <<= 6; - val |= (in[3]) & 0x3F; - in += 4; - } else { - xmlSaveErr(XML_SAVE_CHAR_INVALID, NULL, NULL); - in++; - goto error; - } - if (!IS_CHAR(val)) { - xmlSaveErr(XML_SAVE_CHAR_INVALID, NULL, NULL); - in++; - goto error; - } + len = inend - in; + val = xmlGetUTF8Char(in, &len); + + if (val < 0) { + val = 0xFFFD; + in++; + } else { + if (!IS_CHAR(val)) + val = 0xFFFD; + in += len; + }
/* * We could do multiple things here. Just save as a char ref */ out = xmlSerializeHexCharRef(out, val); - } else if (IS_BYTE_CHAR(*in)) { - if (outend - out < 6) break; - out = xmlSerializeHexCharRef(out, *in++); - } else { - xmlGenericError(xmlGenericErrorContext, - "xmlEscapeEntities : char out of range\n"); - in++; - goto error; } } *outlen = out - outstart; *inlen = in - base; return(0); -error: - *outlen = out - outstart; - *inlen = in - base; - return(-1); }
/************************************************************************ @@ -340,15 +333,18 @@ xmlNewSaveCtxt(const char *encoding, int options)
ret = (xmlSaveCtxtPtr) xmlMalloc(sizeof(xmlSaveCtxt)); if (ret == NULL) { - xmlSaveErrMemory("creating saving context"); + xmlSaveErrMemory(NULL); return ( NULL ); } memset(ret, 0, sizeof(xmlSaveCtxt));
if (encoding != NULL) { - ret->handler = xmlFindCharEncodingHandler(encoding); - if (ret->handler == NULL) { - xmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, NULL, encoding); + int res; + + res = xmlOpenCharEncodingHandler(encoding, /* output */ 1, + &ret->handler); + if (res != XML_ERR_OK) { + xmlSaveErr(NULL, res, NULL, encoding); xmlFreeSaveCtxt(ret); return(NULL); } @@ -397,14 +393,13 @@ xmlAttrSerializeContent(xmlOutputBufferPtr buf, xmlAttrPtr attr) while (children != NULL) { switch (children->type) { case XML_TEXT_NODE: - xmlBufAttrSerializeTxtContent(buf->buffer, attr->doc, - attr, children->content); + xmlBufAttrSerializeTxtContent(buf, attr->doc, + children->content); break; case XML_ENTITY_REF_NODE: - xmlBufAdd(buf->buffer, BAD_CAST "&", 1); - xmlBufAdd(buf->buffer, children->name, - xmlStrlen(children->name)); - xmlBufAdd(buf->buffer, BAD_CAST ";", 1); + xmlOutputBufferWrite(buf, 1, "&"); + xmlOutputBufferWriteString(buf, (const char *) children->name); + xmlOutputBufferWrite(buf, 1, ";"); break; default: /* should not happen unless we have a badly built tree */ @@ -414,6 +409,46 @@ xmlAttrSerializeContent(xmlOutputBufferPtr buf, xmlAttrPtr attr) } }
+/** + * xmlBufDumpNotationDecl: + * @buf: the XML buffer output + * @nota: A notation declaration + * + * This will dump the content the notation declaration as an XML DTD definition + */ +static void +xmlBufDumpNotationDecl(xmlOutputBufferPtr buf, xmlNotationPtr nota) { + xmlOutputBufferWrite(buf, 11, "<!NOTATION "); + xmlOutputBufferWriteString(buf, (const char *) nota->name); + + if (nota->PublicID != NULL) { + xmlOutputBufferWrite(buf, 8, " PUBLIC "); + xmlOutputBufferWriteQuotedString(buf, nota->PublicID); + if (nota->SystemID != NULL) { + xmlOutputBufferWrite(buf, 1, " "); + xmlOutputBufferWriteQuotedString(buf, nota->SystemID); + } + } else { + xmlOutputBufferWrite(buf, 8, " SYSTEM "); + xmlOutputBufferWriteQuotedString(buf, nota->SystemID); + } + + xmlOutputBufferWrite(buf, 3, " >\n"); +} + +/** + * xmlBufDumpNotationDeclScan: + * @nota: A notation declaration + * @buf: the XML buffer output + * + * This is called with the hash scan function, and just reverses args + */ +static void +xmlBufDumpNotationDeclScan(void *nota, void *buf, + const xmlChar *name ATTRIBUTE_UNUSED) { + xmlBufDumpNotationDecl((xmlOutputBufferPtr) buf, (xmlNotationPtr) nota); +} + /** * xmlBufDumpNotationTable: * @buf: an xmlBufPtr output @@ -422,19 +457,105 @@ xmlAttrSerializeContent(xmlOutputBufferPtr buf, xmlAttrPtr attr) * This will dump the content of the notation table as an XML DTD definition */ static void -xmlBufDumpNotationTable(xmlBufPtr buf, xmlNotationTablePtr table) { - xmlBufferPtr buffer; - - buffer = xmlBufferCreate(); - if (buffer == NULL) { - /* - * TODO set the error in buf - */ - return; +xmlBufDumpNotationTable(xmlOutputBufferPtr buf, xmlNotationTablePtr table) { + xmlHashScan(table, xmlBufDumpNotationDeclScan, buf); +} + +/** + * xmlBufDumpElementOccur: + * @buf: output buffer + * @cur: element table + * + * Dump the occurrence operator of an element. + */ +static void +xmlBufDumpElementOccur(xmlOutputBufferPtr buf, xmlElementContentPtr cur) { + switch (cur->ocur) { + case XML_ELEMENT_CONTENT_ONCE: + break; + case XML_ELEMENT_CONTENT_OPT: + xmlOutputBufferWrite(buf, 1, "?"); + break; + case XML_ELEMENT_CONTENT_MULT: + xmlOutputBufferWrite(buf, 1, "*"); + break; + case XML_ELEMENT_CONTENT_PLUS: + xmlOutputBufferWrite(buf, 1, "+"); + break; } - xmlBufferSetAllocationScheme(buffer, XML_BUFFER_ALLOC_DOUBLEIT); - xmlDumpNotationTable(buffer, table); - xmlBufMergeBuffer(buf, buffer); +} + +/** + * xmlBufDumpElementContent: + * @buf: output buffer + * @content: element table + * + * This will dump the content of the element table as an XML DTD definition + */ +static void +xmlBufDumpElementContent(xmlOutputBufferPtr buf, + xmlElementContentPtr content) { + xmlElementContentPtr cur; + + if (content == NULL) return; + + xmlOutputBufferWrite(buf, 1, "("); + cur = content; + + do { + if (cur == NULL) return; + + switch (cur->type) { + case XML_ELEMENT_CONTENT_PCDATA: + xmlOutputBufferWrite(buf, 7, "#PCDATA"); + break; + case XML_ELEMENT_CONTENT_ELEMENT: + if (cur->prefix != NULL) { + xmlOutputBufferWriteString(buf, + (const char *) cur->prefix); + xmlOutputBufferWrite(buf, 1, ":"); + } + xmlOutputBufferWriteString(buf, (const char *) cur->name); + break; + case XML_ELEMENT_CONTENT_SEQ: + case XML_ELEMENT_CONTENT_OR: + if ((cur != content) && + (cur->parent != NULL) && + ((cur->type != cur->parent->type) || + (cur->ocur != XML_ELEMENT_CONTENT_ONCE))) + xmlOutputBufferWrite(buf, 1, "("); + cur = cur->c1; + continue; + } + + while (cur != content) { + xmlElementContentPtr parent = cur->parent; + + if (parent == NULL) return; + + if (((cur->type == XML_ELEMENT_CONTENT_OR) || + (cur->type == XML_ELEMENT_CONTENT_SEQ)) && + ((cur->type != parent->type) || + (cur->ocur != XML_ELEMENT_CONTENT_ONCE))) + xmlOutputBufferWrite(buf, 1, ")"); + xmlBufDumpElementOccur(buf, cur); + + if (cur == parent->c1) { + if (parent->type == XML_ELEMENT_CONTENT_SEQ) + xmlOutputBufferWrite(buf, 3, " , "); + else if (parent->type == XML_ELEMENT_CONTENT_OR) + xmlOutputBufferWrite(buf, 3, " | "); + + cur = parent->c2; + break; + } + + cur = parent; + } + } while (cur != content); + + xmlOutputBufferWrite(buf, 1, ")"); + xmlBufDumpElementOccur(buf, content); }
/** @@ -446,43 +567,173 @@ xmlBufDumpNotationTable(xmlBufPtr buf, xmlNotationTablePtr table) { * DTD definition */ static void -xmlBufDumpElementDecl(xmlBufPtr buf, xmlElementPtr elem) { - xmlBufferPtr buffer; - - buffer = xmlBufferCreate(); - if (buffer == NULL) { - /* - * TODO set the error in buf - */ - return; +xmlBufDumpElementDecl(xmlOutputBufferPtr buf, xmlElementPtr elem) { + xmlOutputBufferWrite(buf, 10, "<!ELEMENT "); + if (elem->prefix != NULL) { + xmlOutputBufferWriteString(buf, (const char *) elem->prefix); + xmlOutputBufferWrite(buf, 1, ":"); } - xmlBufferSetAllocationScheme(buffer, XML_BUFFER_ALLOC_DOUBLEIT); - xmlDumpElementDecl(buffer, elem); - xmlBufMergeBuffer(buf, buffer); + xmlOutputBufferWriteString(buf, (const char *) elem->name); + xmlOutputBufferWrite(buf, 1, " "); + + switch (elem->etype) { + case XML_ELEMENT_TYPE_EMPTY: + xmlOutputBufferWrite(buf, 5, "EMPTY"); + break; + case XML_ELEMENT_TYPE_ANY: + xmlOutputBufferWrite(buf, 3, "ANY"); + break; + case XML_ELEMENT_TYPE_MIXED: + case XML_ELEMENT_TYPE_ELEMENT: + xmlBufDumpElementContent(buf, elem->content); + break; + default: + /* assert(0); */ + break; + } + + xmlOutputBufferWrite(buf, 2, ">\n"); }
+/** + * xmlBufDumpEnumeration: + * @buf: output buffer + * @enum: An enumeration + * + * This will dump the content of the enumeration + */ +static void +xmlBufDumpEnumeration(xmlOutputBufferPtr buf, xmlEnumerationPtr cur) { + while (cur != NULL) { + xmlOutputBufferWriteString(buf, (const char *) cur->name); + if (cur->next != NULL) + xmlOutputBufferWrite(buf, 3, " | "); + + cur = cur->next; + } + + xmlOutputBufferWrite(buf, 1, ")"); +} /** * xmlBufDumpAttributeDecl: - * @buf: an xmlBufPtr output + * @buf: output buffer * @attr: An attribute declaration * * This will dump the content of the attribute declaration as an XML * DTD definition */ static void -xmlBufDumpAttributeDecl(xmlBufPtr buf, xmlAttributePtr attr) { - xmlBufferPtr buffer; - - buffer = xmlBufferCreate(); - if (buffer == NULL) { - /* - * TODO set the error in buf - */ - return; +xmlBufDumpAttributeDecl(xmlOutputBufferPtr buf, xmlAttributePtr attr) { + xmlOutputBufferWrite(buf, 10, "<!ATTLIST "); + xmlOutputBufferWriteString(buf, (const char *) attr->elem); + xmlOutputBufferWrite(buf, 1, " "); + if (attr->prefix != NULL) { + xmlOutputBufferWriteString(buf, (const char *) attr->prefix); + xmlOutputBufferWrite(buf, 1, ":"); + } + xmlOutputBufferWriteString(buf, (const char *) attr->name); + + switch (attr->atype) { + case XML_ATTRIBUTE_CDATA: + xmlOutputBufferWrite(buf, 6, " CDATA"); + break; + case XML_ATTRIBUTE_ID: + xmlOutputBufferWrite(buf, 3, " ID"); + break; + case XML_ATTRIBUTE_IDREF: + xmlOutputBufferWrite(buf, 6, " IDREF"); + break; + case XML_ATTRIBUTE_IDREFS: + xmlOutputBufferWrite(buf, 7, " IDREFS"); + break; + case XML_ATTRIBUTE_ENTITY: + xmlOutputBufferWrite(buf, 7, " ENTITY"); + break; + case XML_ATTRIBUTE_ENTITIES: + xmlOutputBufferWrite(buf, 9, " ENTITIES"); + break; + case XML_ATTRIBUTE_NMTOKEN: + xmlOutputBufferWrite(buf, 8, " NMTOKEN"); + break; + case XML_ATTRIBUTE_NMTOKENS: + xmlOutputBufferWrite(buf, 9, " NMTOKENS"); + break; + case XML_ATTRIBUTE_ENUMERATION: + xmlOutputBufferWrite(buf, 2, " ("); + xmlBufDumpEnumeration(buf, attr->tree); + break; + case XML_ATTRIBUTE_NOTATION: + xmlOutputBufferWrite(buf, 11, " NOTATION ("); + xmlBufDumpEnumeration(buf, attr->tree); + break; + default: + /* assert(0); */ + break; + } + + switch (attr->def) { + case XML_ATTRIBUTE_NONE: + break; + case XML_ATTRIBUTE_REQUIRED: + xmlOutputBufferWrite(buf, 10, " #REQUIRED"); + break; + case XML_ATTRIBUTE_IMPLIED: + xmlOutputBufferWrite(buf, 9, " #IMPLIED"); + break; + case XML_ATTRIBUTE_FIXED: + xmlOutputBufferWrite(buf, 7, " #FIXED"); + break; + default: + /* assert(0); */ + break; + } + + if (attr->defaultValue != NULL) { + xmlOutputBufferWrite(buf, 1, " "); + xmlOutputBufferWriteQuotedString(buf, attr->defaultValue); + } + + xmlOutputBufferWrite(buf, 2, ">\n"); +} + +/** + * xmlBufDumpEntityContent: + * @buf: output buffer + * @content: entity content. + * + * This will dump the quoted string value, taking care of the special + * treatment required by % + */ +static void +xmlBufDumpEntityContent(xmlOutputBufferPtr buf, const xmlChar *content) { + if (xmlStrchr(content, '%')) { + const char * base, *cur; + + xmlOutputBufferWrite(buf, 1, """); + base = cur = (const char *) content; + while (*cur != 0) { + if (*cur == '"') { + if (base != cur) + xmlOutputBufferWrite(buf, cur - base, base); + xmlOutputBufferWrite(buf, 6, """); + cur++; + base = cur; + } else if (*cur == '%') { + if (base != cur) + xmlOutputBufferWrite(buf, cur - base, base); + xmlOutputBufferWrite(buf, 6, "%"); + cur++; + base = cur; + } else { + cur++; + } + } + if (base != cur) + xmlOutputBufferWrite(buf, cur - base, base); + xmlOutputBufferWrite(buf, 1, """); + } else { + xmlOutputBufferWriteQuotedString(buf, content); } - xmlBufferSetAllocationScheme(buffer, XML_BUFFER_ALLOC_DOUBLEIT); - xmlDumpAttributeDecl(buffer, attr); - xmlBufMergeBuffer(buf, buffer); }
/** @@ -493,19 +744,47 @@ xmlBufDumpAttributeDecl(xmlBufPtr buf, xmlAttributePtr attr) { * This will dump the content of the entity table as an XML DTD definition */ static void -xmlBufDumpEntityDecl(xmlBufPtr buf, xmlEntityPtr ent) { - xmlBufferPtr buffer; - - buffer = xmlBufferCreate(); - if (buffer == NULL) { - /* - * TODO set the error in buf - */ - return; +xmlBufDumpEntityDecl(xmlOutputBufferPtr buf, xmlEntityPtr ent) { + if ((ent->etype == XML_INTERNAL_PARAMETER_ENTITY) || + (ent->etype == XML_EXTERNAL_PARAMETER_ENTITY)) + xmlOutputBufferWrite(buf, 11, "<!ENTITY % "); + else + xmlOutputBufferWrite(buf, 9, "<!ENTITY "); + xmlOutputBufferWriteString(buf, (const char *) ent->name); + xmlOutputBufferWrite(buf, 1, " "); + + if ((ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY) || + (ent->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) || + (ent->etype == XML_EXTERNAL_PARAMETER_ENTITY)) { + if (ent->ExternalID != NULL) { + xmlOutputBufferWrite(buf, 7, "PUBLIC "); + xmlOutputBufferWriteQuotedString(buf, ent->ExternalID); + xmlOutputBufferWrite(buf, 1, " "); + } else { + xmlOutputBufferWrite(buf, 7, "SYSTEM "); + } + xmlOutputBufferWriteQuotedString(buf, ent->SystemID); + } + + if (ent->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) { + if (ent->content != NULL) { /* Should be true ! */ + xmlOutputBufferWrite(buf, 7, " NDATA "); + if (ent->orig != NULL) + xmlOutputBufferWriteString(buf, (const char *) ent->orig); + else + xmlOutputBufferWriteString(buf, (const char *) ent->content); + } + } + + if ((ent->etype == XML_INTERNAL_GENERAL_ENTITY) || + (ent->etype == XML_INTERNAL_PARAMETER_ENTITY)) { + if (ent->orig != NULL) + xmlOutputBufferWriteQuotedString(buf, ent->orig); + else + xmlBufDumpEntityContent(buf, ent->content); } - xmlBufferSetAllocationScheme(buffer, XML_BUFFER_ALLOC_DOUBLEIT); - xmlDumpEntityDecl(buffer, ent); - xmlBufMergeBuffer(buf, buffer); + + xmlOutputBufferWrite(buf, 2, ">\n"); }
/************************************************************************ @@ -518,18 +797,21 @@ static int xmlSaveSwitchEncoding(xmlSaveCtxtPtr ctxt, const char *encoding) { xmlOutputBufferPtr buf = ctxt->buf;
if ((encoding != NULL) && (buf->encoder == NULL) && (buf->conv == NULL)) { - buf->encoder = xmlFindCharEncodingHandler((const char *)encoding); - if (buf->encoder == NULL) { - xmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, NULL, - (const char *)encoding); - return(-1); - } + xmlCharEncodingHandler *handler; + int res; + + res = xmlOpenCharEncodingHandler(encoding, /* output */ 1, &handler); + if (res != XML_ERR_OK) { + xmlSaveErr(buf, res, NULL, encoding); + return(-1); + } buf->conv = xmlBufCreate(); if (buf->conv == NULL) { - xmlCharEncCloseFunc(buf->encoder); - xmlSaveErrMemory("creating encoding buffer"); + xmlCharEncCloseFunc(handler); + xmlSaveErrMemory(buf); return(-1); } + buf->encoder = handler; /* * initialize the state, e.g. if outputting a BOM */ @@ -588,7 +870,8 @@ xmlOutputBufferWriteWSNonSig(xmlSaveCtxtPtr ctxt, int extra) * If @ctxt is supplied, @buf should be its buffer. */ static void -xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur, xmlSaveCtxtPtr ctxt) { +xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNsPtr cur, + xmlSaveCtxtPtr ctxt) { if ((cur == NULL) || (buf == NULL)) return; if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) { if (xmlStrEqual(cur->prefix, BAD_CAST "xml")) @@ -605,24 +888,12 @@ xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur, xmlSaveCtxtPtr ctxt) { xmlOutputBufferWriteString(buf, (const char *)cur->prefix); } else xmlOutputBufferWrite(buf, 5, "xmlns"); - xmlOutputBufferWrite(buf, 1, "="); - xmlBufWriteQuotedString(buf->buffer, cur->href); + xmlOutputBufferWrite(buf, 2, "=""); + xmlBufAttrSerializeTxtContent(buf, doc, cur->href); + xmlOutputBufferWrite(buf, 1, """); } }
-/** - * xmlNsDumpOutputCtxt - * @ctxt: the save context - * @cur: a namespace - * - * Dump a local Namespace definition to a save context. - * Should be called in the context of attribute dumps. - */ -static void -xmlNsDumpOutputCtxt(xmlSaveCtxtPtr ctxt, xmlNsPtr cur) { - xmlNsDumpOutput(ctxt->buf, cur, ctxt); -} - /** * xmlNsListDumpOutputCtxt * @ctxt: the save context @@ -632,9 +903,9 @@ xmlNsDumpOutputCtxt(xmlSaveCtxtPtr ctxt, xmlNsPtr cur) { * Should be called in the context of attribute dumps. */ static void -xmlNsListDumpOutputCtxt(xmlSaveCtxtPtr ctxt, xmlNsPtr cur) { +xmlNsListDumpOutputCtxt(xmlSaveCtxtPtr ctxt, xmlDocPtr doc, xmlNsPtr cur) { while (cur != NULL) { - xmlNsDumpOutput(ctxt->buf, cur, ctxt); + xmlNsDumpOutput(ctxt->buf, doc, cur, ctxt); cur = cur->next; } } @@ -650,7 +921,7 @@ xmlNsListDumpOutputCtxt(xmlSaveCtxtPtr ctxt, xmlNsPtr cur) { void xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) { while (cur != NULL) { - xmlNsDumpOutput(buf, cur, NULL); + xmlNsDumpOutput(buf, NULL, cur, NULL); cur = cur->next; } } @@ -676,12 +947,12 @@ xmlDtdDumpOutput(xmlSaveCtxtPtr ctxt, xmlDtdPtr dtd) { xmlOutputBufferWriteString(buf, (const char *)dtd->name); if (dtd->ExternalID != NULL) { xmlOutputBufferWrite(buf, 8, " PUBLIC "); - xmlBufWriteQuotedString(buf->buffer, dtd->ExternalID); + xmlOutputBufferWriteQuotedString(buf, dtd->ExternalID); xmlOutputBufferWrite(buf, 1, " "); - xmlBufWriteQuotedString(buf->buffer, dtd->SystemID); + xmlOutputBufferWriteQuotedString(buf, dtd->SystemID); } else if (dtd->SystemID != NULL) { xmlOutputBufferWrite(buf, 8, " SYSTEM "); - xmlBufWriteQuotedString(buf->buffer, dtd->SystemID); + xmlOutputBufferWriteQuotedString(buf, dtd->SystemID); } if ((dtd->entities == NULL) && (dtd->elements == NULL) && (dtd->attributes == NULL) && (dtd->notations == NULL) && @@ -696,8 +967,7 @@ xmlDtdDumpOutput(xmlSaveCtxtPtr ctxt, xmlDtdPtr dtd) { */ if ((dtd->notations != NULL) && ((dtd->doc == NULL) || (dtd->doc->intSubset == dtd))) { - xmlBufDumpNotationTable(buf->buffer, - (xmlNotationTablePtr) dtd->notations); + xmlBufDumpNotationTable(buf, (xmlNotationTablePtr) dtd->notations); } format = ctxt->format; level = ctxt->level; @@ -735,7 +1005,19 @@ xmlAttrDumpOutput(xmlSaveCtxtPtr ctxt, xmlAttrPtr cur) { } xmlOutputBufferWriteString(buf, (const char *)cur->name); xmlOutputBufferWrite(buf, 2, "=""); - xmlAttrSerializeContent(buf, cur); +#ifdef LIBXML_HTML_ENABLED + if ((ctxt->options & XML_SAVE_XHTML) && + (cur->ns == NULL) && + ((cur->children == NULL) || + (cur->children->content == NULL) || + (cur->children->content[0] == 0)) && + (htmlIsBooleanAttr(cur->name))) { + xmlOutputBufferWriteString(buf, (const char *) cur->name); + } else +#endif + { + xmlAttrSerializeContent(buf, cur); + } xmlOutputBufferWrite(buf, 1, """); }
@@ -839,15 +1121,15 @@ xmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) { break;
case XML_ELEMENT_DECL: - xmlBufDumpElementDecl(buf->buffer, (xmlElementPtr) cur); + xmlBufDumpElementDecl(buf, (xmlElementPtr) cur); break;
case XML_ATTRIBUTE_DECL: - xmlBufDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur); + xmlBufDumpAttributeDecl(buf, (xmlAttributePtr) cur); break;
case XML_ENTITY_DECL: - xmlBufDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur); + xmlBufDumpEntityDecl(buf, (xmlEntityPtr) cur); break;
case XML_ELEMENT_NODE: @@ -875,7 +1157,7 @@ xmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) { } xmlOutputBufferWriteString(buf, (const char *)cur->name); if (cur->nsDef) - xmlNsListDumpOutputCtxt(ctxt, cur->nsDef); + xmlNsListDumpOutputCtxt(ctxt, cur->doc, cur->nsDef); for (attr = cur->properties; attr != NULL; attr = attr->next) xmlAttrDumpOutput(ctxt, attr);
@@ -1015,7 +1297,7 @@ xmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) { break;
case XML_NAMESPACE_DECL: - xmlNsDumpOutputCtxt(ctxt, (xmlNsPtr) cur); + xmlNsDumpOutput(buf, NULL, (xmlNsPtr) cur, ctxt); break;
default: @@ -1164,12 +1446,12 @@ xmlDocContentDumpOutput(xmlSaveCtxtPtr ctxt, xmlDocPtr cur) { if ((ctxt->options & XML_SAVE_NO_DECL) == 0) { xmlOutputBufferWrite(buf, 14, "<?xml version="); if (cur->version != NULL) - xmlBufWriteQuotedString(buf->buffer, cur->version); + xmlOutputBufferWriteQuotedString(buf, cur->version); else xmlOutputBufferWrite(buf, 5, ""1.0""); if (encoding != NULL) { xmlOutputBufferWrite(buf, 10, " encoding="); - xmlBufWriteQuotedString(buf->buffer, (xmlChar *) encoding); + xmlOutputBufferWriteQuotedString(buf, (xmlChar *) encoding); } switch (cur->standalone) { case 0: @@ -1249,7 +1531,7 @@ xhtmlIsEmpty(xmlNodePtr node) { return(0); if (node->children != NULL) return(0); - switch (node->name[0]) { + switch (node->name ? node->name[0] : 0) { case 'a': if (xmlStrEqual(node->name, BAD_CAST "area")) return(1); @@ -1329,17 +1611,6 @@ xhtmlAttrListDumpOutput(xmlSaveCtxtPtr ctxt, xmlAttrPtr cur) { if ((cur->ns != NULL) && (xmlStrEqual(cur->name, BAD_CAST "lang")) && (xmlStrEqual(cur->ns->prefix, BAD_CAST "xml"))) xml_lang = cur; - else if ((cur->ns == NULL) && - ((cur->children == NULL) || - (cur->children->content == NULL) || - (cur->children->content[0] == 0)) && - (htmlIsBooleanAttr(cur->name))) { - if (cur->children != NULL) - xmlFreeNode(cur->children); - cur->children = xmlNewDocText(cur->doc, cur->name); - if (cur->children != NULL) - cur->children->parent = (xmlNodePtr) cur; - } xmlAttrDumpOutput(ctxt, cur); cur = cur->next; } @@ -1390,13 +1661,16 @@ xhtmlAttrListDumpOutput(xmlSaveCtxtPtr ctxt, xmlAttrPtr cur) { */ static void xhtmlNodeDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) { - int format = ctxt->format, addmeta; + int format = ctxt->format, addmeta, oldoptions; xmlNodePtr tmp, root, unformattedNode = NULL, parent; xmlChar *start, *end; xmlOutputBufferPtr buf = ctxt->buf;
if (cur == NULL) return;
+ oldoptions = ctxt->options; + ctxt->options |= XML_SAVE_XHTML; + root = cur; parent = cur->parent; while (1) { @@ -1407,7 +1681,7 @@ xhtmlNodeDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) { break;
case XML_NAMESPACE_DECL: - xmlNsDumpOutputCtxt(ctxt, (xmlNsPtr) cur); + xmlNsDumpOutput(buf, NULL, (xmlNsPtr) cur, ctxt); break;
case XML_DTD_NODE: @@ -1424,15 +1698,15 @@ xhtmlNodeDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) { break;
case XML_ELEMENT_DECL: - xmlBufDumpElementDecl(buf->buffer, (xmlElementPtr) cur); + xmlBufDumpElementDecl(buf, (xmlElementPtr) cur); break;
case XML_ATTRIBUTE_DECL: - xmlBufDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur); + xmlBufDumpAttributeDecl(buf, (xmlAttributePtr) cur); break;
case XML_ENTITY_DECL: - xmlBufDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur); + xmlBufDumpEntityDecl(buf, (xmlEntityPtr) cur); break;
case XML_ELEMENT_NODE: @@ -1462,7 +1736,7 @@ xhtmlNodeDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) {
xmlOutputBufferWriteString(buf, (const char *)cur->name); if (cur->nsDef) - xmlNsListDumpOutputCtxt(ctxt, cur->nsDef); + xmlNsListDumpOutputCtxt(ctxt, cur->doc, cur->nsDef); if ((xmlStrEqual(cur->name, BAD_CAST "html") && (cur->ns == NULL) && (cur->nsDef == NULL))) { /* @@ -1707,6 +1981,8 @@ xhtmlNodeDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) { } } } + + ctxt->options = oldoptions; } #endif
@@ -1888,6 +2164,40 @@ xmlSaveTree(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) return(ret); }
+/** + * xmlSaveNotationDecl: + * @ctxt: save context + * @cur: notation + * + * Serialize a notation declaration. + * + * Return 0 on succes, -1 on error. + */ +int +xmlSaveNotationDecl(xmlSaveCtxtPtr ctxt, xmlNotationPtr cur) { + if (ctxt == NULL) + return(-1); + xmlBufDumpNotationDecl(ctxt->buf, cur); + return(0); +} + +/** + * xmlSaveNotationTable: + * @ctxt: save context + * @cur: notation table + * + * Serialize notation declarations of a document. + * + * Return 0 on succes, -1 on error. + */ +int +xmlSaveNotationTable(xmlSaveCtxtPtr ctxt, xmlNotationTablePtr cur) { + if (ctxt == NULL) + return(-1); + xmlBufDumpNotationTable(ctxt->buf, cur); + return(0); +} + /** * xmlSaveFlush: * @ctxt: a document saving context @@ -1925,6 +2235,30 @@ xmlSaveClose(xmlSaveCtxtPtr ctxt) return(ret); }
+/** + * xmlSaveFinish: + * @ctxt: a document saving context + * + * Close a document saving context, i.e. make sure that all bytes have + * been output and free the associated data. + * + * Available since 2.13.0. + * + * Returns an xmlParserErrors code. + */ +int +xmlSaveFinish(xmlSaveCtxtPtr ctxt) +{ + int ret; + + if (ctxt == NULL) + return(XML_ERR_INTERNAL_ERROR); + xmlSaveFlush(ctxt); + ret = ctxt->buf->error; + xmlFreeSaveCtxt(ctxt); + return(ret); +} + /** * xmlSaveSetEscape: * @ctxt: a document saving context @@ -1967,63 +2301,62 @@ xmlSaveSetAttrEscape(xmlSaveCtxtPtr ctxt, xmlCharEncodingOutputFunc escape)
/** * xmlBufAttrSerializeTxtContent: - * @buf: and xmlBufPtr output + * @buf: output buffer * @doc: the document - * @attr: the attribute node * @string: the text content * * Serialize text attribute values to an xmlBufPtr */ void -xmlBufAttrSerializeTxtContent(xmlBufPtr buf, xmlDocPtr doc, - xmlAttrPtr attr, const xmlChar * string) +xmlBufAttrSerializeTxtContent(xmlOutputBufferPtr buf, xmlDocPtr doc, + const xmlChar *string) { - xmlChar *base, *cur; + const xmlChar *base, *cur;
if (string == NULL) return; - base = cur = (xmlChar *) string; + base = cur = string; while (*cur != 0) { if (*cur == '\n') { if (base != cur) - xmlBufAdd(buf, base, cur - base); - xmlBufAdd(buf, BAD_CAST " ", 5); + xmlOutputBufferWrite(buf, cur - base, (const char *) base); + xmlOutputBufferWrite(buf, 5, " "); cur++; base = cur; } else if (*cur == '\r') { if (base != cur) - xmlBufAdd(buf, base, cur - base); - xmlBufAdd(buf, BAD_CAST " ", 5); + xmlOutputBufferWrite(buf, cur - base, (const char *) base); + xmlOutputBufferWrite(buf, 5, " "); cur++; base = cur; } else if (*cur == '\t') { if (base != cur) - xmlBufAdd(buf, base, cur - base); - xmlBufAdd(buf, BAD_CAST "	", 4); + xmlOutputBufferWrite(buf, cur - base, (const char *) base); + xmlOutputBufferWrite(buf, 4, "	"); cur++; base = cur; } else if (*cur == '"') { if (base != cur) - xmlBufAdd(buf, base, cur - base); - xmlBufAdd(buf, BAD_CAST """, 6); + xmlOutputBufferWrite(buf, cur - base, (const char *) base); + xmlOutputBufferWrite(buf, 6, """); cur++; base = cur; } else if (*cur == '<') { if (base != cur) - xmlBufAdd(buf, base, cur - base); - xmlBufAdd(buf, BAD_CAST "<", 4); + xmlOutputBufferWrite(buf, cur - base, (const char *) base); + xmlOutputBufferWrite(buf, 4, "<"); cur++; base = cur; } else if (*cur == '>') { if (base != cur) - xmlBufAdd(buf, base, cur - base); - xmlBufAdd(buf, BAD_CAST ">", 4); + xmlOutputBufferWrite(buf, cur - base, (const char *) base); + xmlOutputBufferWrite(buf, 4, ">"); cur++; base = cur; } else if (*cur == '&') { if (base != cur) - xmlBufAdd(buf, base, cur - base); - xmlBufAdd(buf, BAD_CAST "&", 5); + xmlOutputBufferWrite(buf, cur - base, (const char *) base); + xmlOutputBufferWrite(buf, 5, "&"); cur++; base = cur; } else if ((*cur >= 0x80) && (cur[1] != 0) && @@ -2032,61 +2365,34 @@ xmlBufAttrSerializeTxtContent(xmlBufPtr buf, xmlDocPtr doc, * We assume we have UTF-8 content. */ unsigned char tmp[12]; - int val = 0, l = 1; + int val = 0, l = 4;
if (base != cur) - xmlBufAdd(buf, base, cur - base); - if (*cur < 0xC0) { - xmlSaveErr(XML_SAVE_NOT_UTF8, (xmlNodePtr) attr, NULL); - xmlSerializeHexCharRef(tmp, *cur); - xmlBufAdd(buf, (xmlChar *) tmp, -1); - cur++; - base = cur; - continue; - } else if (*cur < 0xE0) { - val = (cur[0]) & 0x1F; - val <<= 6; - val |= (cur[1]) & 0x3F; - l = 2; - } else if ((*cur < 0xF0) && (cur [2] != 0)) { - val = (cur[0]) & 0x0F; - val <<= 6; - val |= (cur[1]) & 0x3F; - val <<= 6; - val |= (cur[2]) & 0x3F; - l = 3; - } else if ((*cur < 0xF8) && (cur [2] != 0) && (cur[3] != 0)) { - val = (cur[0]) & 0x07; - val <<= 6; - val |= (cur[1]) & 0x3F; - val <<= 6; - val |= (cur[2]) & 0x3F; - val <<= 6; - val |= (cur[3]) & 0x3F; - l = 4; - } - if ((l == 1) || (!IS_CHAR(val))) { - xmlSaveErr(XML_SAVE_CHAR_INVALID, (xmlNodePtr) attr, NULL); - xmlSerializeHexCharRef(tmp, *cur); - xmlBufAdd(buf, (xmlChar *) tmp, -1); + xmlOutputBufferWrite(buf, cur - base, (const char *) base); + + val = xmlGetUTF8Char(cur, &l); + if (val < 0) { + val = 0xFFFD; cur++; - base = cur; - continue; + } else { + if (!IS_CHAR(val)) + val = 0xFFFD; + cur += l; } + /* * We could do multiple things here. Just save * as a char ref */ xmlSerializeHexCharRef(tmp, val); - xmlBufAdd(buf, (xmlChar *) tmp, -1); - cur += l; + xmlOutputBufferWriteString(buf, (const char *) tmp); base = cur; } else { cur++; } } if (base != cur) - xmlBufAdd(buf, base, cur - base); + xmlOutputBufferWrite(buf, cur - base, (const char *) base); }
/** @@ -2100,17 +2406,19 @@ xmlBufAttrSerializeTxtContent(xmlBufPtr buf, xmlDocPtr doc, */ void xmlAttrSerializeTxtContent(xmlBufferPtr buf, xmlDocPtr doc, - xmlAttrPtr attr, const xmlChar * string) + xmlAttrPtr attr ATTRIBUTE_UNUSED, + const xmlChar *string) { - xmlBufPtr buffer; + xmlOutputBufferPtr out;
if ((buf == NULL) || (string == NULL)) return; - buffer = xmlBufFromBuffer(buf); - if (buffer == NULL) - return; - xmlBufAttrSerializeTxtContent(buffer, doc, attr, string); - xmlBufBackToBuffer(buffer); + out = xmlOutputBufferCreateBuffer(buf, NULL); + xmlBufAttrSerializeTxtContent(out, doc, string); + xmlOutputBufferFlush(out); + if ((out == NULL) || (out->error)) + xmlFree(xmlBufferDetach(buf)); + xmlOutputBufferClose(out); }
/** @@ -2138,6 +2446,10 @@ xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
if ((buf == NULL) || (cur == NULL)) return(-1); + if (level < 0) + level = 0; + else if (level > 100) + level = 100; buffer = xmlBufFromBuffer(buf); if (buffer == NULL) return(-1); @@ -2169,22 +2481,22 @@ xmlBufNodeDump(xmlBufPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level, int format) { size_t use; - int ret; + size_t ret; xmlOutputBufferPtr outbuf; int oldalloc;
xmlInitParser();
if (cur == NULL) { - return (-1); + return ((size_t) -1); } if (buf == NULL) { - return (-1); + return ((size_t) -1); } outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer)); if (outbuf == NULL) { - xmlSaveErrMemory("creating buffer"); - return (-1); + xmlSaveErrMemory(NULL); + return ((size_t) -1); } memset(outbuf, 0, (size_t) sizeof(xmlOutputBuffer)); outbuf->buffer = buf; @@ -2199,8 +2511,11 @@ xmlBufNodeDump(xmlBufPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level, xmlBufSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT); xmlNodeDumpOutput(outbuf, doc, cur, level, format, NULL); xmlBufSetAllocationScheme(buf, oldalloc); + if (outbuf->error) + ret = (size_t) -1; + else + ret = xmlBufUse(buf) - use; xmlFree(outbuf); - ret = xmlBufUse(buf) - use; return (ret); }
@@ -2226,13 +2541,11 @@ xmlElemDump(FILE * f, xmlDocPtr doc, xmlNodePtr cur) outbuf = xmlOutputBufferCreateFile(f, NULL); if (outbuf == NULL) return; - if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) { #ifdef LIBXML_HTML_ENABLED + if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) htmlNodeDumpOutput(outbuf, doc, cur, NULL); -#else - xmlSaveErr(XML_ERR_INTERNAL_ERROR, cur, "HTML support not compiled in\n"); + else #endif /* LIBXML_HTML_ENABLED */ - } else xmlNodeDumpOutput(outbuf, doc, cur, 0, 1, NULL); xmlOutputBufferClose(outbuf); } @@ -2272,6 +2585,11 @@ xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
if ((buf == NULL) || (cur == NULL)) return;
+ if (level < 0) + level = 0; + else if (level > 100) + level = 100; + if (encoding == NULL) encoding = "UTF-8";
@@ -2347,16 +2665,18 @@ xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr, if (txt_encoding == NULL) txt_encoding = (const char *) out_doc->encoding; if (txt_encoding != NULL) { - conv_hdlr = xmlFindCharEncodingHandler(txt_encoding); - if ( conv_hdlr == NULL ) { - xmlSaveErr(XML_SAVE_UNKNOWN_ENCODING, (xmlNodePtr) out_doc, - txt_encoding); + int res; + + res = xmlOpenCharEncodingHandler(txt_encoding, /* output */ 1, + &conv_hdlr); + if (res != XML_ERR_OK) { + xmlSaveErr(NULL, res, NULL, txt_encoding); return; } }
if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) { - xmlSaveErrMemory("creating buffer"); + xmlSaveErrMemory(NULL); xmlCharEncCloseFunc(conv_hdlr); return; } @@ -2370,21 +2690,18 @@ xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr, ctxt.options |= XML_SAVE_AS_XML; xmlDocContentDumpOutput(&ctxt, out_doc); xmlOutputBufferFlush(out_buff); - if (out_buff->conv != NULL) { - *doc_txt_len = xmlBufUse(out_buff->conv); - *doc_txt_ptr = xmlStrndup(xmlBufContent(out_buff->conv), *doc_txt_len); - } else { - *doc_txt_len = xmlBufUse(out_buff->buffer); - *doc_txt_ptr = xmlStrndup(xmlBufContent(out_buff->buffer),*doc_txt_len); - } - (void)xmlOutputBufferClose(out_buff);
- if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) { - *doc_txt_len = 0; - xmlSaveErrMemory("creating output"); + if (!out_buff->error) { + if (out_buff->conv != NULL) { + *doc_txt_len = xmlBufUse(out_buff->conv); + *doc_txt_ptr = xmlBufDetach(out_buff->conv); + } else { + *doc_txt_len = xmlBufUse(out_buff->buffer); + *doc_txt_ptr = xmlBufDetach(out_buff->buffer); + } }
- return; + xmlOutputBufferClose(out_buff); }
/** @@ -2466,8 +2783,10 @@ xmlDocFormatDump(FILE *f, xmlDocPtr cur, int format) { encoding = (const char *) cur->encoding;
if (encoding != NULL) { - handler = xmlFindCharEncodingHandler(encoding); - if (handler == NULL) { + int res; + + res = xmlOpenCharEncodingHandler(encoding, /* output */ 1, &handler); + if (res != XML_ERR_OK) { xmlFree((char *) cur->encoding); cur->encoding = NULL; encoding = NULL; @@ -2603,10 +2922,11 @@ xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur, encoding = (const char *) cur->encoding;
if (encoding != NULL) { + int res;
- handler = xmlFindCharEncodingHandler(encoding); - if (handler == NULL) - return(-1); + res = xmlOpenCharEncodingHandler(encoding, /* output */ 1, &handler); + if (res != XML_ERR_OK) + return(-1); }
#ifdef LIBXML_ZLIB_ENABLED diff --git a/libs/xml2/xmlschemas.c b/libs/xml2/xmlschemas.c index 76cf6819687..4bdabd129b8 100644 --- a/libs/xml2/xmlschemas.c +++ b/libs/xml2/xmlschemas.c @@ -96,10 +96,6 @@ #endif
#define UNBOUNDED (1 << 30) -#define TODO \ - xmlGenericError(xmlGenericErrorContext, \ - "Unimplemented block at %s:%d\n", \ - __FILE__, __LINE__);
#define XML_SCHEMAS_NO_NAMESPACE (const xmlChar *) "##"
@@ -1898,22 +1894,6 @@ xmlSchemaFormatFacetEnumSet(xmlSchemaAbstractCtxtPtr actxt, * * ************************************************************************/
-#if 0 -static void -xmlSchemaErrMemory(const char *msg) -{ - __xmlSimpleError(XML_FROM_SCHEMASP, XML_ERR_NO_MEMORY, NULL, NULL, - msg); -} -#endif - -static void -xmlSchemaPSimpleErr(const char *msg) -{ - __xmlSimpleError(XML_FROM_SCHEMASP, XML_ERR_NO_MEMORY, NULL, NULL, - msg); -} - /** * xmlSchemaPErrMemory: * @node: a context node @@ -1922,13 +1902,66 @@ xmlSchemaPSimpleErr(const char *msg) * Handle an out of memory condition */ static void -xmlSchemaPErrMemory(xmlSchemaParserCtxtPtr ctxt, - const char *extra, xmlNodePtr node) +xmlSchemaPErrMemory(xmlSchemaParserCtxtPtr ctxt) { - if (ctxt != NULL) + xmlGenericErrorFunc channel = NULL; + xmlStructuredErrorFunc schannel = NULL; + void *data = NULL; + + if (ctxt != NULL) { ctxt->nberrors++; - __xmlSimpleError(XML_FROM_SCHEMASP, XML_ERR_NO_MEMORY, node, NULL, - extra); + ctxt->err = XML_ERR_NO_MEMORY; + channel = ctxt->error; + schannel = ctxt->serror; + data = ctxt->errCtxt; + } + + xmlRaiseMemoryError(schannel, channel, data, XML_FROM_SCHEMASP, NULL); +} + +static void LIBXML_ATTR_FORMAT(11,12) +xmlSchemaPErrFull(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node, int code, + xmlErrorLevel level, const char *file, int line, + const xmlChar *str1, const xmlChar *str2, const xmlChar *str3, + int col, const char *msg, ...) { + xmlGenericErrorFunc channel = NULL; + xmlStructuredErrorFunc schannel = NULL; + void *data = NULL; + int res; + va_list ap; + + if (ctxt != NULL) { + /* Don't overwrite memory errors */ + if (ctxt->err == XML_ERR_NO_MEMORY) + return; + + if (level == XML_ERR_WARNING) { + channel = ctxt->warning; + } else { + ctxt->nberrors++; + ctxt->err = code; + channel = ctxt->error; + } + data = ctxt->errCtxt; + schannel = ctxt->serror; + } + + if ((channel == NULL) && (schannel == NULL)) { + channel = xmlGenericError; + data = xmlGenericErrorContext; + } + + va_start(ap, msg); + res = xmlVRaiseError(schannel, channel, data, ctxt, node, + XML_FROM_SCHEMASP, code, level, file, line, + (const char *) str1, + (const char *) str2, + (const char *) str3, + 0, col, msg, ap); + va_end(ap); + + if (res < 0) + xmlSchemaPErrMemory(ctxt); }
/** @@ -1943,24 +1976,11 @@ xmlSchemaPErrMemory(xmlSchemaParserCtxtPtr ctxt, * Handle a parser error */ static void LIBXML_ATTR_FORMAT(4,0) -xmlSchemaPErr(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node, int error, +xmlSchemaPErr(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node, int code, const char *msg, const xmlChar * str1, const xmlChar * str2) { - xmlGenericErrorFunc channel = NULL; - xmlStructuredErrorFunc schannel = NULL; - void *data = NULL; - - if (ctxt != NULL) { - ctxt->nberrors++; - ctxt->err = error; - channel = ctxt->error; - data = ctxt->errCtxt; - schannel = ctxt->serror; - } - __xmlRaiseError(schannel, channel, data, ctxt, node, XML_FROM_SCHEMASP, - error, XML_ERR_ERROR, NULL, 0, - (const char *) str1, (const char *) str2, NULL, 0, 0, - msg, str1, str2); + xmlSchemaPErrFull(ctxt, node, code, XML_ERR_ERROR, NULL, 0, + str1, str2, NULL, 0, msg, str1, str2); }
/** @@ -2005,29 +2025,15 @@ xmlSchemaPErr2(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node, * Handle a parser error */ static void LIBXML_ATTR_FORMAT(7,0) -xmlSchemaPErrExt(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node, int error, +xmlSchemaPErrExt(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node, int code, const xmlChar * strData1, const xmlChar * strData2, const xmlChar * strData3, const char *msg, const xmlChar * str1, const xmlChar * str2, const xmlChar * str3, const xmlChar * str4, const xmlChar * str5) { - - xmlGenericErrorFunc channel = NULL; - xmlStructuredErrorFunc schannel = NULL; - void *data = NULL; - - if (ctxt != NULL) { - ctxt->nberrors++; - ctxt->err = error; - channel = ctxt->error; - data = ctxt->errCtxt; - schannel = ctxt->serror; - } - __xmlRaiseError(schannel, channel, data, ctxt, node, XML_FROM_SCHEMASP, - error, XML_ERR_ERROR, NULL, 0, - (const char *) strData1, (const char *) strData2, - (const char *) strData3, 0, 0, msg, str1, str2, - str3, str4, str5); + xmlSchemaPErrFull(ctxt, node, code, XML_ERR_ERROR, NULL, 0, + strData1, strData2, strData3, 0, + msg, str1, str2, str3, str4, str5); }
/************************************************************************ @@ -2044,23 +2050,66 @@ xmlSchemaPErrExt(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node, int error, * Handle an out of memory condition */ static void -xmlSchemaVErrMemory(xmlSchemaValidCtxtPtr ctxt, - const char *extra, xmlNodePtr node) +xmlSchemaVErrMemory(xmlSchemaValidCtxtPtr ctxt) { + xmlGenericErrorFunc channel = NULL; + xmlStructuredErrorFunc schannel = NULL; + void *data = NULL; + if (ctxt != NULL) { ctxt->nberrors++; - ctxt->err = XML_SCHEMAV_INTERNAL; + ctxt->err = XML_ERR_NO_MEMORY; + channel = ctxt->error; + schannel = ctxt->serror; + data = ctxt->errCtxt; } - __xmlSimpleError(XML_FROM_SCHEMASV, XML_ERR_NO_MEMORY, node, NULL, - extra); + + xmlRaiseMemoryError(schannel, channel, data, XML_FROM_SCHEMASV, NULL); }
-static void LIBXML_ATTR_FORMAT(2,0) -xmlSchemaPSimpleInternalErr(xmlNodePtr node, - const char *msg, const xmlChar *str) -{ - __xmlSimpleError(XML_FROM_SCHEMASP, XML_SCHEMAP_INTERNAL, node, - msg, (const char *) str); +static void LIBXML_ATTR_FORMAT(11,12) +xmlSchemaVErrFull(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node, int code, + xmlErrorLevel level, const char *file, int line, + const xmlChar *str1, const xmlChar *str2, const xmlChar *str3, + int col, const char *msg, ...) { + xmlGenericErrorFunc channel = NULL; + xmlStructuredErrorFunc schannel = NULL; + void *data = NULL; + int res; + va_list ap; + + if (ctxt != NULL) { + /* Don't overwrite memory errors */ + if (ctxt->err == XML_ERR_NO_MEMORY) + return; + + if (level == XML_ERR_WARNING) { + channel = ctxt->warning; + } else { + ctxt->nberrors++; + ctxt->err = code; + channel = ctxt->error; + } + data = ctxt->errCtxt; + schannel = ctxt->serror; + } + + if ((channel == NULL) && (schannel == NULL)) { + channel = xmlGenericError; + data = xmlGenericErrorContext; + } + + va_start(ap, msg); + res = xmlVRaiseError(schannel, channel, data, ctxt, node, + XML_FROM_SCHEMASV, code, level, file, line, + (const char *) str1, + (const char *) str2, + (const char *) str3, + 0, col, msg, ap); + va_end(ap); + + if (res < 0) + xmlSchemaVErrMemory(ctxt); }
#define WXS_ERROR_TYPE_ERROR 1 @@ -2083,28 +2132,15 @@ xmlSchemaPSimpleInternalErr(xmlNodePtr node, static void LIBXML_ATTR_FORMAT(6,0) xmlSchemaErr4Line(xmlSchemaAbstractCtxtPtr ctxt, xmlErrorLevel errorLevel, - int error, xmlNodePtr node, int line, const char *msg, + int code, xmlNodePtr node, int line, const char *msg, const xmlChar *str1, const xmlChar *str2, const xmlChar *str3, const xmlChar *str4) { - xmlStructuredErrorFunc schannel = NULL; - xmlGenericErrorFunc channel = NULL; - void *data = NULL; - if (ctxt != NULL) { if (ctxt->type == XML_SCHEMA_CTXT_VALIDATOR) { xmlSchemaValidCtxtPtr vctxt = (xmlSchemaValidCtxtPtr) ctxt; const char *file = NULL; int col = 0; - if (errorLevel != XML_ERR_WARNING) { - vctxt->nberrors++; - vctxt->err = error; - channel = vctxt->error; - } else { - channel = vctxt->warning; - } - schannel = vctxt->serror; - data = vctxt->errCtxt;
/* * Error node. If we specify a line number, then @@ -2161,30 +2197,15 @@ xmlSchemaErr4Line(xmlSchemaAbstractCtxtPtr ctxt, if ((file == NULL) && (vctxt->filename != NULL)) file = vctxt->filename;
- __xmlRaiseError(schannel, channel, data, ctxt, - node, XML_FROM_SCHEMASV, - error, errorLevel, file, line, - (const char *) str1, (const char *) str2, - (const char *) str3, 0, col, msg, str1, str2, str3, str4); - + xmlSchemaVErrFull(vctxt, node, code, errorLevel, + file, line, str1, str2, str3, col, + msg, str1, str2, str3, str4); } else if (ctxt->type == XML_SCHEMA_CTXT_PARSER) { xmlSchemaParserCtxtPtr pctxt = (xmlSchemaParserCtxtPtr) ctxt; - if (errorLevel != XML_ERR_WARNING) { - pctxt->nberrors++; - pctxt->err = error; - channel = pctxt->error; - } else { - channel = pctxt->warning; - } - schannel = pctxt->serror; - data = pctxt->errCtxt; - __xmlRaiseError(schannel, channel, data, ctxt, - node, XML_FROM_SCHEMASP, error, - errorLevel, NULL, 0, - (const char *) str1, (const char *) str2, - (const char *) str3, 0, 0, msg, str1, str2, str3, str4); - } else { - TODO + + xmlSchemaPErrFull(pctxt, node, code, errorLevel, + NULL, 0, str1, str2, str3, 0, + msg, str1, str2, str3, str4); } } } @@ -2305,7 +2326,7 @@ xmlSchemaFormatNodeForError(xmlChar ** msg, */ *msg = xmlStrdup(BAD_CAST ""); } else { - TODO + /* TODO */ return (NULL); }
@@ -3322,7 +3343,7 @@ xmlSchemaNewSchema(xmlSchemaParserCtxtPtr ctxt)
ret = (xmlSchemaPtr) xmlMalloc(sizeof(xmlSchema)); if (ret == NULL) { - xmlSchemaPErrMemory(ctxt, "allocating schema", NULL); + xmlSchemaPErrMemory(ctxt); return (NULL); } memset(ret, 0, sizeof(xmlSchema)); @@ -3369,7 +3390,7 @@ xmlSchemaNewAnnot(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node)
ret = (xmlSchemaAnnotPtr) xmlMalloc(sizeof(xmlSchemaAnnot)); if (ret == NULL) { - xmlSchemaPErrMemory(ctxt, "allocating annotation", node); + xmlSchemaPErrMemory(ctxt); return (NULL); } memset(ret, 0, sizeof(xmlSchemaAnnot)); @@ -3384,8 +3405,7 @@ xmlSchemaItemListCreate(void)
ret = xmlMalloc(sizeof(xmlSchemaItemList)); if (ret == NULL) { - xmlSchemaPErrMemory(NULL, - "allocating an item list structure", NULL); + xmlSchemaPErrMemory(NULL); return (NULL); } memset(ret, 0, sizeof(xmlSchemaItemList)); @@ -3412,7 +3432,7 @@ xmlSchemaItemListAdd(xmlSchemaItemListPtr list, void *item)
tmp = (void **) xmlRealloc(list->items, newSize * sizeof(void *)); if (tmp == NULL) { - xmlSchemaPErrMemory(NULL, "growing item list", NULL); + xmlSchemaPErrMemory(NULL); return(-1); } list->items = tmp; @@ -3433,7 +3453,7 @@ xmlSchemaItemListAddSize(xmlSchemaItemListPtr list, list->items = (void **) xmlMalloc( initialSize * sizeof(void *)); if (list->items == NULL) { - xmlSchemaPErrMemory(NULL, "allocating new item list", NULL); + xmlSchemaPErrMemory(NULL); return(-1); } list->sizeItems = initialSize; @@ -3444,7 +3464,7 @@ xmlSchemaItemListAddSize(xmlSchemaItemListPtr list, tmp = (void **) xmlRealloc(list->items, list->sizeItems * sizeof(void *)); if (tmp == NULL) { - xmlSchemaPErrMemory(NULL, "growing item list", NULL); + xmlSchemaPErrMemory(NULL); list->sizeItems /= 2; return(-1); } @@ -3463,7 +3483,7 @@ xmlSchemaItemListInsert(xmlSchemaItemListPtr list, void *item, int idx)
tmp = (void **) xmlRealloc(list->items, newSize * sizeof(void *)); if (tmp == NULL) { - xmlSchemaPErrMemory(NULL, "growing item list", NULL); + xmlSchemaPErrMemory(NULL); return(-1); } list->items = tmp; @@ -3497,7 +3517,7 @@ xmlSchemaItemListInsertSize(xmlSchemaItemListPtr list, list->items = (void **) xmlMalloc( initialSize * sizeof(void *)); if (list->items == NULL) { - xmlSchemaPErrMemory(NULL, "allocating new item list", NULL); + xmlSchemaPErrMemory(NULL); return(-1); } list->sizeItems = initialSize; @@ -3506,7 +3526,7 @@ xmlSchemaItemListInsertSize(xmlSchemaItemListPtr list, list->items = (void **) xmlRealloc(list->items, list->sizeItems * sizeof(void *)); if (list->items == NULL) { - xmlSchemaPErrMemory(NULL, "growing item list", NULL); + xmlSchemaPErrMemory(NULL); list->sizeItems = 0; return(-1); } @@ -3531,11 +3551,8 @@ static int xmlSchemaItemListRemove(xmlSchemaItemListPtr list, int idx) { int i; - if ((list->items == NULL) || (idx >= list->nbItems)) { - xmlSchemaPSimpleErr("Internal error: xmlSchemaItemListRemove, " - "index error.\n"); + if ((list->items == NULL) || (idx >= list->nbItems)) return(-1); - }
if (list->nbItems == 1) { /* TODO: Really free the list? */ @@ -3627,7 +3644,7 @@ xmlSchemaBucketCreate(xmlSchemaParserCtxtPtr pctxt, size = sizeof(xmlSchemaImport); ret = (xmlSchemaBucketPtr) xmlMalloc(size); if (ret == NULL) { - xmlSchemaPErrMemory(NULL, "allocating schema bucket", NULL); + xmlSchemaPErrMemory(NULL); return(NULL); } memset(ret, 0, size); @@ -4155,13 +4172,8 @@ xmlSchemaComponentListFree(xmlSchemaItemListPtr list) case XML_SCHEMA_EXTRA_QNAMEREF: xmlSchemaFreeQNameRef((xmlSchemaQNameRefPtr) item); break; - default: { + default: /* TODO: This should never be hit. */ - xmlSchemaPSimpleInternalErr(NULL, - "Internal error: xmlSchemaComponentListFree, " - "unexpected component type '%s'\n", - (const xmlChar *) WXS_ITEM_TYPE_NAME(item)); - } break; } } @@ -4180,9 +4192,6 @@ xmlSchemaFree(xmlSchemaPtr schema) { if (schema == NULL) return; - /* @volatiles is not used anymore :-/ */ - if (schema->volatiles != NULL) - TODO /* * Note that those slots are not responsible for freeing * schema components anymore; this will now be done by @@ -4675,7 +4684,7 @@ xmlSchemaGetNodeContent(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node) ret = xmlDictLookup(ctxt->dict, val, -1); xmlFree(val); if (ret == NULL) - xmlSchemaPErrMemory(ctxt, "getting node content", node); + xmlSchemaPErrMemory(ctxt); return(ret); }
@@ -4934,7 +4943,7 @@ xmlSchemaGetNamedComponent(xmlSchemaPtr schema, return ((xmlSchemaBasicItemPtr) xmlSchemaGetElem(schema, name, targetNs)); default: - TODO + /* TODO */ return (NULL); } } @@ -5088,7 +5097,7 @@ xmlSchemaAddNotation(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
ret = (xmlSchemaNotationPtr) xmlMalloc(sizeof(xmlSchemaNotation)); if (ret == NULL) { - xmlSchemaPErrMemory(ctxt, "add annotation", NULL); + xmlSchemaPErrMemory(ctxt); return (NULL); } memset(ret, 0, sizeof(xmlSchemaNotation)); @@ -5125,7 +5134,7 @@ xmlSchemaAddAttribute(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
ret = (xmlSchemaAttributePtr) xmlMalloc(sizeof(xmlSchemaAttribute)); if (ret == NULL) { - xmlSchemaPErrMemory(ctxt, "allocating attribute", NULL); + xmlSchemaPErrMemory(ctxt); return (NULL); } memset(ret, 0, sizeof(xmlSchemaAttribute)); @@ -5165,7 +5174,7 @@ xmlSchemaAddAttributeUse(xmlSchemaParserCtxtPtr pctxt,
ret = (xmlSchemaAttributeUsePtr) xmlMalloc(sizeof(xmlSchemaAttributeUse)); if (ret == NULL) { - xmlSchemaPErrMemory(pctxt, "allocating attribute", NULL); + xmlSchemaPErrMemory(pctxt); return (NULL); } memset(ret, 0, sizeof(xmlSchemaAttributeUse)); @@ -5194,8 +5203,7 @@ xmlSchemaAddRedef(xmlSchemaParserCtxtPtr pctxt, ret = (xmlSchemaRedefPtr) xmlMalloc(sizeof(xmlSchemaRedef)); if (ret == NULL) { - xmlSchemaPErrMemory(pctxt, - "allocating redefinition info", NULL); + xmlSchemaPErrMemory(pctxt); return (NULL); } memset(ret, 0, sizeof(xmlSchemaRedef)); @@ -5239,7 +5247,7 @@ xmlSchemaAddAttributeGroupDefinition(xmlSchemaParserCtxtPtr pctxt, ret = (xmlSchemaAttributeGroupPtr) xmlMalloc(sizeof(xmlSchemaAttributeGroup)); if (ret == NULL) { - xmlSchemaPErrMemory(pctxt, "allocating attribute group", NULL); + xmlSchemaPErrMemory(pctxt); return (NULL); } memset(ret, 0, sizeof(xmlSchemaAttributeGroup)); @@ -5288,7 +5296,7 @@ xmlSchemaAddElement(xmlSchemaParserCtxtPtr ctxt,
ret = (xmlSchemaElementPtr) xmlMalloc(sizeof(xmlSchemaElement)); if (ret == NULL) { - xmlSchemaPErrMemory(ctxt, "allocating element", NULL); + xmlSchemaPErrMemory(ctxt); return (NULL); } memset(ret, 0, sizeof(xmlSchemaElement)); @@ -5330,7 +5338,7 @@ xmlSchemaAddType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType)); if (ret == NULL) { - xmlSchemaPErrMemory(ctxt, "allocating type", NULL); + xmlSchemaPErrMemory(ctxt); return (NULL); } memset(ret, 0, sizeof(xmlSchemaType)); @@ -5366,8 +5374,7 @@ xmlSchemaNewQNameRef(xmlSchemaParserCtxtPtr pctxt, ret = (xmlSchemaQNameRefPtr) xmlMalloc(sizeof(xmlSchemaQNameRef)); if (ret == NULL) { - xmlSchemaPErrMemory(pctxt, - "allocating QName reference item", NULL); + xmlSchemaPErrMemory(pctxt); return (NULL); } ret->node = NULL; @@ -5391,8 +5398,7 @@ xmlSchemaAddAttributeUseProhib(xmlSchemaParserCtxtPtr pctxt) ret = (xmlSchemaAttributeUseProhibPtr) xmlMalloc(sizeof(xmlSchemaAttributeUseProhib)); if (ret == NULL) { - xmlSchemaPErrMemory(pctxt, - "allocating attribute use prohibition", NULL); + xmlSchemaPErrMemory(pctxt); return (NULL); } memset(ret, 0, sizeof(xmlSchemaAttributeUseProhib)); @@ -5428,8 +5434,7 @@ xmlSchemaAddModelGroup(xmlSchemaParserCtxtPtr ctxt, ret = (xmlSchemaModelGroupPtr) xmlMalloc(sizeof(xmlSchemaModelGroup)); if (ret == NULL) { - xmlSchemaPErrMemory(ctxt, "allocating model group component", - NULL); + xmlSchemaPErrMemory(ctxt); return (NULL); } memset(ret, 0, sizeof(xmlSchemaModelGroup)); @@ -5467,8 +5472,7 @@ xmlSchemaAddParticle(xmlSchemaParserCtxtPtr ctxt, ret = (xmlSchemaParticlePtr) xmlMalloc(sizeof(xmlSchemaParticle)); if (ret == NULL) { - xmlSchemaPErrMemory(ctxt, "allocating particle component", - NULL); + xmlSchemaPErrMemory(ctxt); return (NULL); } ret->type = XML_SCHEMA_TYPE_PARTICLE; @@ -5514,7 +5518,7 @@ xmlSchemaAddModelGroupDefinition(xmlSchemaParserCtxtPtr ctxt, ret = (xmlSchemaModelGroupDefPtr) xmlMalloc(sizeof(xmlSchemaModelGroupDef)); if (ret == NULL) { - xmlSchemaPErrMemory(ctxt, "adding group", NULL); + xmlSchemaPErrMemory(ctxt); return (NULL); } memset(ret, 0, sizeof(xmlSchemaModelGroupDef)); @@ -5553,7 +5557,7 @@ xmlSchemaNewWildcardNsConstraint(xmlSchemaParserCtxtPtr ctxt) ret = (xmlSchemaWildcardNsPtr) xmlMalloc(sizeof(xmlSchemaWildcardNs)); if (ret == NULL) { - xmlSchemaPErrMemory(ctxt, "creating wildcard namespace constraint", NULL); + xmlSchemaPErrMemory(ctxt); return (NULL); } ret->value = NULL; @@ -5573,8 +5577,7 @@ xmlSchemaAddIDC(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
ret = (xmlSchemaIDCPtr) xmlMalloc(sizeof(xmlSchemaIDC)); if (ret == NULL) { - xmlSchemaPErrMemory(ctxt, - "allocating an identity-constraint definition", NULL); + xmlSchemaPErrMemory(ctxt); return (NULL); } memset(ret, 0, sizeof(xmlSchemaIDC)); @@ -5614,7 +5617,7 @@ xmlSchemaAddWildcard(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
ret = (xmlSchemaWildcardPtr) xmlMalloc(sizeof(xmlSchemaWildcard)); if (ret == NULL) { - xmlSchemaPErrMemory(ctxt, "adding wildcard", NULL); + xmlSchemaPErrMemory(ctxt); return (NULL); } memset(ret, 0, sizeof(xmlSchemaWildcard)); @@ -5655,8 +5658,7 @@ xmlSchemaSubstGroupAdd(xmlSchemaParserCtxtPtr pctxt, /* Create a new substitution group. */ ret = (xmlSchemaSubstGroupPtr) xmlMalloc(sizeof(xmlSchemaSubstGroup)); if (ret == NULL) { - xmlSchemaPErrMemory(NULL, - "allocating a substitution group container", NULL); + xmlSchemaPErrMemory(NULL); return(NULL); } memset(ret, 0, sizeof(xmlSchemaSubstGroup)); @@ -5896,8 +5898,8 @@ xmlSchemaPValAttrNodeID(xmlSchemaParserCtxtPtr ctxt, xmlAttrPtr attr) * NOTE: the IDness might have already be declared in the DTD */ if (attr->atype != XML_ATTRIBUTE_ID) { - xmlIDPtr res; xmlChar *strip; + int res;
/* * TODO: Use xmlSchemaStrip here; it's not exported at this @@ -5908,8 +5910,10 @@ xmlSchemaPValAttrNodeID(xmlSchemaParserCtxtPtr ctxt, xmlAttrPtr attr) xmlFree((xmlChar *) value); value = strip; } - res = xmlAddID(NULL, attr->doc, value, attr); - if (res == NULL) { + res = xmlAddIDSafe(attr, value); + if (res < 0) { + xmlSchemaPErrMemory(ctxt); + } else if (res == 0) { ret = XML_SCHEMAP_S4S_ATTR_INVALID_VALUE; xmlSchemaPSimpleTypeErr(ctxt, XML_SCHEMAP_S4S_ATTR_INVALID_VALUE, @@ -5917,8 +5921,7 @@ xmlSchemaPValAttrNodeID(xmlSchemaParserCtxtPtr ctxt, xmlAttrPtr attr) xmlSchemaGetBuiltInType(XML_SCHEMAS_ID), NULL, NULL, "Duplicate value '%s' of simple " "type 'xs:ID'", value, NULL); - } else - attr->atype = XML_ATTRIBUTE_ID; + } } } else if (ret > 0) { ret = XML_SCHEMAP_S4S_ATTR_INVALID_VALUE; @@ -6607,7 +6610,7 @@ xmlSchemaParseFacet(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
facet = xmlSchemaNewFacet(); if (facet == NULL) { - xmlSchemaPErrMemory(ctxt, "allocating facet", node); + xmlSchemaPErrMemory(ctxt); return (NULL); } facet->node = node; @@ -8017,8 +8020,7 @@ xmlSchemaCheckCSelectorXPath(xmlSchemaParserCtxtPtr ctxt, nsArray = (const xmlChar **) xmlMalloc( (count * 2 + 1) * sizeof(const xmlChar *)); if (nsArray == NULL) { - xmlSchemaPErrMemory(ctxt, "allocating a namespace array", - NULL); + xmlSchemaPErrMemory(ctxt); xmlFree(nsList); return (-1); } @@ -8061,7 +8063,7 @@ xmlSchemaCheckCSelectorXPath(xmlSchemaParserCtxtPtr ctxt, return (annot); \ } \ cur = item->annot; \ - if (cur->next != NULL) { \ + while (cur->next != NULL) { \ cur = cur->next; \ } \ cur->next = annot; @@ -8205,9 +8207,7 @@ xmlSchemaParseIDCSelectorAndField(xmlSchemaParserCtxtPtr ctxt, */ item = (xmlSchemaIDCSelectPtr) xmlMalloc(sizeof(xmlSchemaIDCSelect)); if (item == NULL) { - xmlSchemaPErrMemory(ctxt, - "allocating a 'selector' of an identity-constraint definition", - NULL); + xmlSchemaPErrMemory(ctxt); return (NULL); } memset(item, 0, sizeof(xmlSchemaIDCSelect)); @@ -8884,8 +8884,7 @@ xmlSchemaParseUnion(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, break; tmp = xmlStrndup(cur, end - cur); if (tmp == NULL) { - xmlSchemaPErrMemory(ctxt, "xmlSchemaParseUnion, " - "duplicating type name", NULL); + xmlSchemaPErrMemory(ctxt); return (-1); } if (xmlSchemaPValAttrNodeQNameValue(ctxt, schema, @@ -8896,8 +8895,7 @@ xmlSchemaParseUnion(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, link = (xmlSchemaTypeLinkPtr) xmlMalloc(sizeof(xmlSchemaTypeLink)); if (link == NULL) { - xmlSchemaPErrMemory(ctxt, "xmlSchemaParseUnion, " - "allocating a type link", NULL); + xmlSchemaPErrMemory(ctxt); FREE_AND_NULL(tmp) return (-1); } @@ -9831,7 +9829,7 @@ xmlSchemaSchemaRelationCreate(void) ret = (xmlSchemaSchemaRelationPtr) xmlMalloc(sizeof(xmlSchemaSchemaRelation)); if (ret == NULL) { - xmlSchemaPErrMemory(NULL, "allocating schema relation", NULL); + xmlSchemaPErrMemory(NULL); return(NULL); } memset(ret, 0, sizeof(xmlSchemaSchemaRelation)); @@ -9888,23 +9886,20 @@ xmlSchemaConstructionCtxtCreate(xmlDictPtr dict) ret = (xmlSchemaConstructionCtxtPtr) xmlMalloc(sizeof(xmlSchemaConstructionCtxt)); if (ret == NULL) { - xmlSchemaPErrMemory(NULL, - "allocating schema construction context", NULL); + xmlSchemaPErrMemory(NULL); return (NULL); } memset(ret, 0, sizeof(xmlSchemaConstructionCtxt));
ret->buckets = xmlSchemaItemListCreate(); if (ret->buckets == NULL) { - xmlSchemaPErrMemory(NULL, - "allocating list of schema buckets", NULL); + xmlSchemaPErrMemory(NULL); xmlFree(ret); return (NULL); } ret->pending = xmlSchemaItemListCreate(); if (ret->pending == NULL) { - xmlSchemaPErrMemory(NULL, - "allocating list of pending global components", NULL); + xmlSchemaPErrMemory(NULL); xmlSchemaConstructionCtxtFree(ret); return (NULL); } @@ -9920,8 +9915,7 @@ xmlSchemaParserCtxtCreate(void)
ret = (xmlSchemaParserCtxtPtr) xmlMalloc(sizeof(xmlSchemaParserCtxt)); if (ret == NULL) { - xmlSchemaPErrMemory(NULL, "allocating schema parser context", - NULL); + xmlSchemaPErrMemory(NULL); return (NULL); } memset(ret, 0, sizeof(xmlSchemaParserCtxt)); @@ -10506,10 +10500,13 @@ doc_load:
parserCtxt = xmlNewParserCtxt(); if (parserCtxt == NULL) { - xmlSchemaPErrMemory(NULL, "xmlSchemaGetDoc, " - "allocating a parser context", NULL); + xmlSchemaPErrMemory(NULL); goto exit_failure; } + + if (pctxt->serror != NULL) + xmlCtxtSetErrorHandler(parserCtxt, pctxt->serror, pctxt->errCtxt); + if ((pctxt->dict != NULL) && (parserCtxt->dict != NULL)) { /* * TODO: Do we have to burden the schema parser dict with all @@ -11670,7 +11667,7 @@ xmlSchemaParseRestriction(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, facetLink = (xmlSchemaFacetLinkPtr) xmlMalloc(sizeof(xmlSchemaFacetLink)); if (facetLink == NULL) { - xmlSchemaPErrMemory(ctxt, "allocating a facet link", NULL); + xmlSchemaPErrMemory(ctxt); xmlFree(facetLink); return (NULL); } @@ -13117,8 +13114,7 @@ xmlSchemaBuildContentModel(xmlSchemaTypePtr type, ctxt->am = NULL; ctxt->am = xmlNewAutomata(); if (ctxt->am == NULL) { - xmlGenericError(xmlGenericErrorContext, - "Cannot create automata for complex type %s\n", type->name); + xmlSchemaPErrMemory(ctxt); return; } ctxt->state = xmlAutomataGetInitState(ctxt->am); @@ -13133,14 +13129,12 @@ xmlSchemaBuildContentModel(xmlSchemaTypePtr type, XML_SCHEMAP_INTERNAL, WXS_BASIC_CAST type, type->node, "Failed to compile the content model", NULL); -#if 0 /* disabled in Wine */ } else if (xmlRegexpIsDeterminist(type->contModel) != 1) { xmlSchemaPCustomErr(ctxt, XML_SCHEMAP_NOT_DETERMINISTIC, /* XML_SCHEMAS_ERR_NOTDETERMINIST, */ WXS_BASIC_CAST type, type->node, "The content model is not determinist", NULL); -#endif } else { } ctxt->state = NULL; @@ -13302,7 +13296,7 @@ xmlSchemaResolveUnionMemberTypes(xmlSchemaParserCtxtPtr ctxt, while (memberType != NULL) { link = (xmlSchemaTypeLinkPtr) xmlMalloc(sizeof(xmlSchemaTypeLink)); if (link == NULL) { - xmlSchemaPErrMemory(ctxt, "allocating a type link", NULL); + xmlSchemaPErrMemory(ctxt); return (-1); } link->type = memberType; @@ -17743,8 +17737,7 @@ xmlSchemaDeriveAndValidateFacets(xmlSchemaParserCtxtPtr pctxt, link = (xmlSchemaFacetLinkPtr) xmlMalloc(sizeof(xmlSchemaFacetLink)); if (link == NULL) { - xmlSchemaPErrMemory(pctxt, - "deriving facets, creating a facet link", NULL); + xmlSchemaPErrMemory(pctxt); return (-1); } link->facet = cur->facet; @@ -17797,8 +17790,7 @@ xmlSchemaFinishMemberTypeDefinitionsProperty(xmlSchemaParserCtxtPtr pctxt, newLink = (xmlSchemaTypeLinkPtr) xmlMalloc(sizeof(xmlSchemaTypeLink)); if (newLink == NULL) { - xmlSchemaPErrMemory(pctxt, "allocating a type link", - NULL); + xmlSchemaPErrMemory(pctxt); return (-1); } newLink->type = subLink->type; @@ -18678,7 +18670,7 @@ xmlSchemaCheckFacet(xmlSchemaFacetPtr facet, PERROR_INT("xmlSchemaCheckFacet", "value was not computed"); } - TODO + /* TODO */ } break; } @@ -20130,7 +20122,7 @@ xmlSchemaResolveAttrUseReferences(xmlSchemaAttributeUsePtr ause, WXS_BASIC_CAST ause, ause->node, "ref", ref->name, ref->targetNamespace, XML_SCHEMA_TYPE_ATTRIBUTE, NULL); - return(ctxt->err); + return(ctxt->err);; } } return(0); @@ -21355,6 +21347,8 @@ exit_failure: * @warn: the warning callback * @ctx: contextual data for the callbacks * + * DEPRECATED: Use xmlSchemaSetParserStructuredErrors. + * * Set the callback functions used to handle errors for a validation context */ void @@ -21931,9 +21925,7 @@ xmlSchemaAugmentIDC(void *payload, void *data,
aidc = (xmlSchemaIDCAugPtr) xmlMalloc(sizeof(xmlSchemaIDCAug)); if (aidc == NULL) { - xmlSchemaVErrMemory(vctxt, - "xmlSchemaAugmentIDC: allocating an augmented IDC definition", - NULL); + xmlSchemaVErrMemory(vctxt); return; } aidc->keyrefDepth = -1; @@ -21985,8 +21977,7 @@ xmlSchemaIDCNewBinding(xmlSchemaIDCPtr idcDef) ret = (xmlSchemaPSVIIDCBindingPtr) xmlMalloc( sizeof(xmlSchemaPSVIIDCBinding)); if (ret == NULL) { - xmlSchemaVErrMemory(NULL, - "allocating a PSVI IDC binding item", NULL); + xmlSchemaVErrMemory(NULL); return (NULL); } memset(ret, 0, sizeof(xmlSchemaPSVIIDCBinding)); @@ -22016,8 +22007,7 @@ xmlSchemaIDCStoreNodeTableItem(xmlSchemaValidCtxtPtr vctxt, vctxt->idcNodes = (xmlSchemaPSVIIDCNodePtr *) xmlMalloc(20 * sizeof(xmlSchemaPSVIIDCNodePtr)); if (vctxt->idcNodes == NULL) { - xmlSchemaVErrMemory(vctxt, - "allocating the IDC node table item list", NULL); + xmlSchemaVErrMemory(vctxt); return (-1); } vctxt->sizeIdcNodes = 20; @@ -22027,8 +22017,7 @@ xmlSchemaIDCStoreNodeTableItem(xmlSchemaValidCtxtPtr vctxt, xmlRealloc(vctxt->idcNodes, vctxt->sizeIdcNodes * sizeof(xmlSchemaPSVIIDCNodePtr)); if (vctxt->idcNodes == NULL) { - xmlSchemaVErrMemory(vctxt, - "re-allocating the IDC node table item list", NULL); + xmlSchemaVErrMemory(vctxt); return (-1); } } @@ -22057,8 +22046,7 @@ xmlSchemaIDCStoreKey(xmlSchemaValidCtxtPtr vctxt, vctxt->idcKeys = (xmlSchemaPSVIIDCKeyPtr *) xmlMalloc(40 * sizeof(xmlSchemaPSVIIDCKeyPtr)); if (vctxt->idcKeys == NULL) { - xmlSchemaVErrMemory(vctxt, - "allocating the IDC key storage list", NULL); + xmlSchemaVErrMemory(vctxt); return (-1); } vctxt->sizeIdcKeys = 40; @@ -22068,8 +22056,7 @@ xmlSchemaIDCStoreKey(xmlSchemaValidCtxtPtr vctxt, xmlRealloc(vctxt->idcKeys, vctxt->sizeIdcKeys * sizeof(xmlSchemaPSVIIDCKeyPtr)); if (vctxt->idcKeys == NULL) { - xmlSchemaVErrMemory(vctxt, - "re-allocating the IDC key storage list", NULL); + xmlSchemaVErrMemory(vctxt); return (-1); } } @@ -22096,8 +22083,7 @@ xmlSchemaIDCAppendNodeTableItem(xmlSchemaPSVIIDCBindingPtr bind, bind->nodeTable = (xmlSchemaPSVIIDCNodePtr *) xmlMalloc(10 * sizeof(xmlSchemaPSVIIDCNodePtr)); if (bind->nodeTable == NULL) { - xmlSchemaVErrMemory(NULL, - "allocating an array of IDC node-table items", NULL); + xmlSchemaVErrMemory(NULL); return(-1); } } else if (bind->sizeNodes <= bind->nbNodes) { @@ -22106,8 +22092,7 @@ xmlSchemaIDCAppendNodeTableItem(xmlSchemaPSVIIDCBindingPtr bind, xmlRealloc(bind->nodeTable, bind->sizeNodes * sizeof(xmlSchemaPSVIIDCNodePtr)); if (bind->nodeTable == NULL) { - xmlSchemaVErrMemory(NULL, - "re-allocating an array of IDC node-table items", NULL); + xmlSchemaVErrMemory(NULL); return(-1); } } @@ -22367,8 +22352,7 @@ xmlSchemaIDCAddStateObject(xmlSchemaValidCtxtPtr vctxt, */ sto = (xmlSchemaIDCStateObjPtr) xmlMalloc(sizeof(xmlSchemaIDCStateObj)); if (sto == NULL) { - xmlSchemaVErrMemory(NULL, - "allocating an IDC state object", NULL); + xmlSchemaVErrMemory(NULL); return (-1); } memset(sto, 0, sizeof(xmlSchemaIDCStateObj)); @@ -22456,8 +22440,7 @@ xmlSchemaXPathEvaluate(xmlSchemaValidCtxtPtr vctxt, if (sto->history == NULL) { sto->history = (int *) xmlMalloc(5 * sizeof(int)); if (sto->history == NULL) { - xmlSchemaVErrMemory(NULL, - "allocating the state object history", NULL); + xmlSchemaVErrMemory(NULL); return(-1); } sto->sizeHistory = 5; @@ -22466,8 +22449,7 @@ xmlSchemaXPathEvaluate(xmlSchemaValidCtxtPtr vctxt, sto->history = (int *) xmlRealloc(sto->history, sto->sizeHistory * sizeof(int)); if (sto->history == NULL) { - xmlSchemaVErrMemory(NULL, - "re-allocating the state object history", NULL); + xmlSchemaVErrMemory(NULL); return(-1); } } @@ -22735,9 +22717,7 @@ xmlSchemaXPathProcessHistory(xmlSchemaValidCtxtPtr vctxt, xmlMalloc(matcher->sizeKeySeqs * sizeof(xmlSchemaPSVIIDCKeyPtr *)); if (matcher->keySeqs == NULL) { - xmlSchemaVErrMemory(NULL, - "allocating an array of key-sequences", - NULL); + xmlSchemaVErrMemory(NULL); return(-1); } memset(matcher->keySeqs, 0, @@ -22752,9 +22732,7 @@ xmlSchemaXPathProcessHistory(xmlSchemaValidCtxtPtr vctxt, matcher->sizeKeySeqs * sizeof(xmlSchemaPSVIIDCKeyPtr *)); if (matcher->keySeqs == NULL) { - xmlSchemaVErrMemory(NULL, - "reallocating an array of key-sequences", - NULL); + xmlSchemaVErrMemory(NULL); return (-1); } /* @@ -22804,8 +22782,7 @@ create_sequence: matcher->aidc->def->nbFields * sizeof(xmlSchemaPSVIIDCKeyPtr)); if (keySeq == NULL) { - xmlSchemaVErrMemory(NULL, - "allocating an IDC key-sequence", NULL); + xmlSchemaVErrMemory(NULL); return(-1); } memset(keySeq, 0, matcher->aidc->def->nbFields * @@ -22819,8 +22796,7 @@ create_key: key = (xmlSchemaPSVIIDCKeyPtr) xmlMalloc( sizeof(xmlSchemaPSVIIDCKey)); if (key == NULL) { - xmlSchemaVErrMemory(NULL, - "allocating a IDC key", NULL); + xmlSchemaVErrMemory(NULL); xmlFree(keySeq); matcher->keySeqs[pos] = NULL; return(-1); @@ -22982,8 +22958,7 @@ create_key: ntItem = (xmlSchemaPSVIIDCNodePtr) xmlMalloc( sizeof(xmlSchemaPSVIIDCNode)); if (ntItem == NULL) { - xmlSchemaVErrMemory(NULL, - "allocating an IDC node-table item", NULL); + xmlSchemaVErrMemory(NULL); xmlFree(*keySeq); *keySeq = NULL; return(-1); @@ -23202,8 +23177,7 @@ xmlSchemaIDCRegisterMatchers(xmlSchemaValidCtxtPtr vctxt, matcher = (xmlSchemaIDCMatcherPtr) xmlMalloc(sizeof(xmlSchemaIDCMatcher)); if (matcher == NULL) { - xmlSchemaVErrMemory(vctxt, - "allocating an IDC matcher", NULL); + xmlSchemaVErrMemory(vctxt); return (-1); } memset(matcher, 0, sizeof(xmlSchemaIDCMatcher)); @@ -23350,7 +23324,7 @@ xmlSchemaIDCFillNodeTables(xmlSchemaValidCtxtPtr vctxt, j++; } while (j < nbDupls); } - if (nbNodeTable) { + if (bind->nbNodes) { j = 0; do { if (nbFields == 1) { @@ -23401,7 +23375,7 @@ xmlSchemaIDCFillNodeTables(xmlSchemaValidCtxtPtr vctxt,
next_node_table_entry: j++; - } while (j < nbNodeTable); + } while (j < bind->nbNodes); } /* * If everything is fine, then add the IDC target-node to @@ -23618,8 +23592,7 @@ xmlSchemaBubbleIDCNodeTables(xmlSchemaValidCtxtPtr vctxt) parBind->nodeTable = (xmlSchemaPSVIIDCNodePtr *) xmlMalloc(10 * sizeof(xmlSchemaPSVIIDCNodePtr)); if (parBind->nodeTable == NULL) { - xmlSchemaVErrMemory(NULL, - "allocating IDC list of node-table items", NULL); + xmlSchemaVErrMemory(NULL); goto internal_error; } parBind->sizeNodes = 1; @@ -23629,8 +23602,7 @@ xmlSchemaBubbleIDCNodeTables(xmlSchemaValidCtxtPtr vctxt) xmlRealloc(parBind->nodeTable, parBind->sizeNodes * sizeof(xmlSchemaPSVIIDCNodePtr)); if (parBind->nodeTable == NULL) { - xmlSchemaVErrMemory(NULL, - "re-allocating IDC list of node-table items", NULL); + xmlSchemaVErrMemory(NULL); goto internal_error; } } @@ -23683,9 +23655,7 @@ xmlSchemaBubbleIDCNodeTables(xmlSchemaValidCtxtPtr vctxt) xmlMalloc(bind->nbNodes * sizeof(xmlSchemaPSVIIDCNodePtr)); if (parBind->nodeTable == NULL) { - xmlSchemaVErrMemory(NULL, - "allocating an array of IDC node-table " - "items", NULL); + xmlSchemaVErrMemory(NULL); xmlSchemaIDCFreeBinding(parBind); goto internal_error; } @@ -23894,8 +23864,7 @@ xmlSchemaGetFreshAttrInfo(xmlSchemaValidCtxtPtr vctxt) xmlMalloc(sizeof(xmlSchemaAttrInfoPtr)); vctxt->sizeAttrInfos = 1; if (vctxt->attrInfos == NULL) { - xmlSchemaVErrMemory(vctxt, - "allocating attribute info list", NULL); + xmlSchemaVErrMemory(vctxt); return (NULL); } } else if (vctxt->sizeAttrInfos <= vctxt->nbAttrInfos) { @@ -23904,8 +23873,7 @@ xmlSchemaGetFreshAttrInfo(xmlSchemaValidCtxtPtr vctxt) xmlRealloc(vctxt->attrInfos, vctxt->sizeAttrInfos * sizeof(xmlSchemaAttrInfoPtr)); if (vctxt->attrInfos == NULL) { - xmlSchemaVErrMemory(vctxt, - "re-allocating attribute info list", NULL); + xmlSchemaVErrMemory(vctxt); return (NULL); } } else { @@ -23924,7 +23892,7 @@ xmlSchemaGetFreshAttrInfo(xmlSchemaValidCtxtPtr vctxt) iattr = (xmlSchemaAttrInfoPtr) xmlMalloc(sizeof(xmlSchemaAttrInfo)); if (iattr == NULL) { - xmlSchemaVErrMemory(vctxt, "creating new attribute info", NULL); + xmlSchemaVErrMemory(vctxt); return (NULL); } memset(iattr, 0, sizeof(xmlSchemaAttrInfo)); @@ -24075,8 +24043,7 @@ xmlSchemaGetFreshElemInfo(xmlSchemaValidCtxtPtr vctxt) vctxt->elemInfos = (xmlSchemaNodeInfoPtr *) xmlMalloc(10 * sizeof(xmlSchemaNodeInfoPtr)); if (vctxt->elemInfos == NULL) { - xmlSchemaVErrMemory(vctxt, - "allocating the element info array", NULL); + xmlSchemaVErrMemory(vctxt); return (NULL); } memset(vctxt->elemInfos, 0, 10 * sizeof(xmlSchemaNodeInfoPtr)); @@ -24089,8 +24056,7 @@ xmlSchemaGetFreshElemInfo(xmlSchemaValidCtxtPtr vctxt) xmlRealloc(vctxt->elemInfos, vctxt->sizeElemInfos * sizeof(xmlSchemaNodeInfoPtr)); if (vctxt->elemInfos == NULL) { - xmlSchemaVErrMemory(vctxt, - "re-allocating the element info array", NULL); + xmlSchemaVErrMemory(vctxt); return (NULL); } /* @@ -24106,8 +24072,7 @@ xmlSchemaGetFreshElemInfo(xmlSchemaValidCtxtPtr vctxt) info = (xmlSchemaNodeInfoPtr) xmlMalloc(sizeof(xmlSchemaNodeInfo)); if (info == NULL) { - xmlSchemaVErrMemory(vctxt, - "allocating an element info", NULL); + xmlSchemaVErrMemory(vctxt); return (NULL); } vctxt->elemInfos[vctxt->depth] = info; @@ -24570,7 +24535,6 @@ xmlSchemaVCheckCVCSimpleType(xmlSchemaAbstractCtxtPtr actxt, /* * Validation via a public API is not implemented yet. */ - TODO goto internal_error; } if (ret != 0) { @@ -25383,7 +25347,6 @@ xmlSchemaVAttributesComplex(xmlSchemaValidCtxtPtr vctxt) if (wildIDs != 0) { /* VAL TODO */ iattr->state = XML_SCHEMAS_ATTR_ERR_WILD_DUPLICATE_ID; - TODO continue; } wildIDs++; @@ -25401,7 +25364,6 @@ xmlSchemaVAttributesComplex(xmlSchemaValidCtxtPtr vctxt) XML_SCHEMAS_ID)) { /* URGENT VAL TODO: implement */ iattr->state = XML_SCHEMAS_ATTR_ERR_WILD_AND_USE_ID; - TODO break; } } @@ -25537,7 +25499,7 @@ xmlSchemaVAttributesComplex(xmlSchemaValidCtxtPtr vctxt) ns = xmlSearchNsByHref(defAttrOwnerElem->doc, defAttrOwnerElem, iattr->nsName); if (ns == NULL) { - xmlChar prefix[12]; + xmlChar prefix[13]; int counter = 0;
/* @@ -25545,7 +25507,7 @@ xmlSchemaVAttributesComplex(xmlSchemaValidCtxtPtr vctxt) * root node if no namespace declaration is in scope. */ do { - snprintf((char *) prefix, 12, "p%d", counter++); + snprintf((char *) prefix, 13, "p%d", counter++); ns = xmlSearchNs(defAttrOwnerElem->doc, defAttrOwnerElem, BAD_CAST prefix); if (counter > 1000) { @@ -25655,14 +25617,12 @@ xmlSchemaVAttributesComplex(xmlSchemaValidCtxtPtr vctxt) */ if (iattr->val == NULL) { /* VAL TODO: A value was not precomputed. */ - TODO goto eval_idcs; } if ((iattr->use != NULL) && (iattr->use->defValue != NULL)) { if (iattr->use->defVal == NULL) { /* VAL TODO: A default value was not precomputed. */ - TODO goto eval_idcs; } iattr->vcValue = iattr->use->defValue; @@ -25677,7 +25637,6 @@ xmlSchemaVAttributesComplex(xmlSchemaValidCtxtPtr vctxt) } else { if (iattr->decl->defVal == NULL) { /* VAL TODO: A default value was not precomputed. */ - TODO goto eval_idcs; } iattr->vcValue = iattr->decl->defValue; @@ -27202,7 +27161,6 @@ xmlSchemaSAXHandleReference(void *ctx ATTRIBUTE_UNUSED, if ((vctxt->skipDepth != -1) && (vctxt->depth >= vctxt->skipDepth)) return; /* SAX VAL TODO: What to do here? */ - TODO }
static void @@ -27263,9 +27221,7 @@ xmlSchemaSAXHandleStartElementNs(void *ctx, (const xmlChar **) xmlMalloc(10 * sizeof(const xmlChar *)); if (ielem->nsBindings == NULL) { - xmlSchemaVErrMemory(vctxt, - "allocating namespace bindings for SAX validation", - NULL); + xmlSchemaVErrMemory(vctxt); goto internal_error; } ielem->nbNsBindings = 0; @@ -27277,9 +27233,7 @@ xmlSchemaSAXHandleStartElementNs(void *ctx, (void *) ielem->nsBindings, ielem->sizeNsBindings * 2 * sizeof(const xmlChar *)); if (ielem->nsBindings == NULL) { - xmlSchemaVErrMemory(vctxt, - "re-allocating namespace bindings for SAX validation", - NULL); + xmlSchemaVErrMemory(vctxt); goto internal_error; } } @@ -27317,9 +27271,7 @@ xmlSchemaSAXHandleStartElementNs(void *ctx, valueLen = attributes[j+4] - attributes[j+3]; value = xmlMallocAtomic(valueLen + 1); if (value == NULL) { - xmlSchemaVErrMemory(vctxt, - "allocating string for decoded attribute", - NULL); + xmlSchemaVErrMemory(vctxt); goto internal_error; } for (k = 0, l = 0; k < valueLen; l++) { @@ -27436,7 +27388,7 @@ xmlSchemaNewValidCtxt(xmlSchemaPtr schema)
ret = (xmlSchemaValidCtxtPtr) xmlMalloc(sizeof(xmlSchemaValidCtxt)); if (ret == NULL) { - xmlSchemaVErrMemory(NULL, "allocating validation context", NULL); + xmlSchemaVErrMemory(NULL); return (NULL); } memset(ret, 0, sizeof(xmlSchemaValidCtxt)); @@ -27704,6 +27656,8 @@ xmlSchemaIsValid(xmlSchemaValidCtxtPtr ctxt) * @warn: the warning function * @ctx: the functions context * + * DEPRECATED: Use xmlSchemaSetValidStructuredErrors. + * * Set the error and warning callback information */ void @@ -28384,7 +28338,7 @@ warningSplit(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...) { xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx; if ((ctxt != NULL) && (ctxt->user_sax != NULL) && (ctxt->user_sax->warning != NULL)) { - TODO + /* TODO */ } } static void @@ -28392,7 +28346,7 @@ errorSplit(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...) { xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx; if ((ctxt != NULL) && (ctxt->user_sax != NULL) && (ctxt->user_sax->error != NULL)) { - TODO + /* TODO */ } } static void @@ -28400,7 +28354,7 @@ fatalErrorSplit(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...) { xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx; if ((ctxt != NULL) && (ctxt->user_sax != NULL) && (ctxt->user_sax->fatalError != NULL)) { - TODO + /* TODO */ } }
@@ -28826,7 +28780,7 @@ xmlSchemaValidateStream(xmlSchemaValidCtxtPtr ctxt, xmlCtxtUseOptions(pctxt, options); #endif
- inputStream = xmlNewIOInputStream(pctxt, input, enc); + inputStream = xmlNewIOInputStream(pctxt, input, enc);; if (inputStream == NULL) { ret = -1; goto done; diff --git a/libs/xml2/xmlschemastypes.c b/libs/xml2/xmlschemastypes.c index de95d940762..1c0c1f2f3e1 100644 --- a/libs/xml2/xmlschemastypes.c +++ b/libs/xml2/xmlschemastypes.c @@ -28,6 +28,7 @@ #include <libxml/hash.h> #include <libxml/xpath.h> #include <libxml/uri.h> +#include <string.h>
#include <libxml/xmlschemas.h> #include <libxml/schemasInternals.h> @@ -41,11 +42,6 @@ extern double xmlXPathPINF; extern double xmlXPathNINF; #endif
-#define TODO \ - xmlGenericError(xmlGenericErrorContext, \ - "Unimplemented block at %s:%d\n", \ - __FILE__, __LINE__); - #define XML_SCHEMAS_NAMESPACE_NAME \ (const xmlChar *)"http://www.w3.org/2001/XMLSchema"
@@ -82,15 +78,11 @@ struct _xmlSchemaValDuration {
typedef struct _xmlSchemaValDecimal xmlSchemaValDecimal; typedef xmlSchemaValDecimal *xmlSchemaValDecimalPtr; -struct _xmlSchemaValDecimal { - /* would use long long but not portable */ - unsigned long lo; - unsigned long mi; - unsigned long hi; - unsigned int extra; - unsigned int sign:1; - unsigned int frac:7; - unsigned int total:8; +struct _xmlSchemaValDecimal +{ + xmlChar *str; + unsigned integralPlaces; + unsigned fractionalPlaces; };
typedef struct _xmlSchemaValQName xmlSchemaValQName; @@ -200,9 +192,9 @@ static xmlSchemaTypePtr xmlSchemaTypeNmtokensDef = NULL; * Handle an out of memory condition */ static void -xmlSchemaTypeErrMemory(xmlNodePtr node, const char *extra) +xmlSchemaTypeErrMemory(void) { - __xmlSimpleError(XML_FROM_DATATYPE, XML_ERR_NO_MEMORY, node, NULL, extra); + xmlRaiseMemoryError(NULL, NULL, NULL, XML_FROM_DATATYPE, NULL); }
/************************************************************************ @@ -236,6 +228,8 @@ static xmlSchemaFacetPtr xmlSchemaNewMinLengthFacet(int value) { xmlSchemaFacetPtr ret; + size_t bufsize; + xmlSchemaValDecimal *decimal;
ret = xmlSchemaNewFacet(); if (ret == NULL) { @@ -245,9 +239,19 @@ xmlSchemaNewMinLengthFacet(int value) ret->val = xmlSchemaNewValue(XML_SCHEMAS_NNINTEGER); if (ret->val == NULL) { xmlFree(ret); - return(NULL); + return(NULL); } - ret->val->value.decimal.lo = value; + bufsize = snprintf(NULL, 0, "%+d.0", value) + 1; + decimal = &ret->val->value.decimal; + decimal->str = xmlMalloc(bufsize); + if (decimal->str == NULL) + { + xmlSchemaFreeFacet(ret); + return NULL; + } + snprintf((char *)decimal->str, bufsize, "%+d.0", value); + decimal->integralPlaces = bufsize - 4; + decimal->fractionalPlaces = 1; return (ret); }
@@ -265,7 +269,7 @@ xmlSchemaInitBasicType(const char *name, xmlSchemaValType type,
ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType)); if (ret == NULL) { - xmlSchemaTypeErrMemory(NULL, "could not initialize basic types"); + xmlSchemaTypeErrMemory(); return(NULL); } memset(ret, 0, sizeof(xmlSchemaType)); @@ -326,6 +330,90 @@ xmlSchemaInitBasicType(const char *name, xmlSchemaValType type, return(ret); }
+static const xmlChar * +xmlSchemaValDecimalGetFractionalPart(const xmlSchemaValDecimal *decimal) +{ + /* 2 = sign+dot */ + return decimal->str+2+decimal->integralPlaces; +} + +static int +xmlSchemaValDecimalIsInteger(const xmlSchemaValDecimal *decimal) +{ + return decimal->fractionalPlaces == 1 && xmlSchemaValDecimalGetFractionalPart(decimal)[0] == '0'; +} + +static unsigned long +xmlSchemaValDecimalGetSignificantDigitCount(const xmlSchemaValDecimal *decimal) +{ + unsigned fractionalPlaces = xmlSchemaValDecimalIsInteger(decimal) ? 0 : decimal->fractionalPlaces; + unsigned integralPlaces = decimal->integralPlaces; + if(integralPlaces == 1 && decimal->str[1] == '0') + { + integralPlaces = 0; + } + if(integralPlaces+fractionalPlaces == 0) + { + /* 0, but that's still 1 significant digit */ + return 1; + } + return integralPlaces+fractionalPlaces; +} + +/** + * @brief Compares two decimals + * + * @param lhs + * @param rhs + * @return positive value if lhs > rhs, negative if lhs < rhs, or 0 if lhs == rhs + */ +static int xmlSchemaValDecimalCompare(const xmlSchemaValDecimal *lhs, const xmlSchemaValDecimal *rhs) +{ + int sign = 1; + /* may be +0 and -0 for some reason, handle */ + if(strcmp((const char*)lhs->str+1, "0.0") == 0 && + strcmp((const char*)rhs->str+1, "0.0") == 0) + { + return 0; + } + /* first take care of sign */ + if(lhs->str[0] != rhs->str[0]) + { + /* ASCII- > ASCII+ */ + return rhs->str[0]-lhs->str[0]; + } + /* signs are equal, but if negative the comparison must be reversed */ + if(lhs->str[0] == '-') + { + sign = -1; + } + /* internal representation never contains leading zeroes, longer decimal representation = larger number */ + if(lhs->integralPlaces != rhs->integralPlaces) + { + return ((int)lhs->integralPlaces-(int)rhs->integralPlaces)*sign; + } + /* same length, only digits => lexicographical sorting == numerical sorting. + If integral parts are equal it will compare compare fractional parts. Again, lexicographical is good enough, + length doesn't matter. We'll be starting from 0.1, always comparing like to like, and NULL < '0' + If one is shorter and is equal until end, it must be smaller, since there are no trailing zeroes + and the longer number must therefore have at least one non-zero digit after the other has ended. + +1 to skip the sign + */ + return strcmp((const char*)lhs->str+1, (const char*)rhs->str+1)*sign; +} + +static int xmlSchemaValDecimalCompareWithInteger(const xmlSchemaValDecimal *lhs, long rhs) +{ + /* can handle integers up to 128 bits, should be good for a while */ + char buf[43]; + xmlSchemaValDecimal tmpVal; + /* 3 = sign+dot+0+NULL */ + tmpVal.integralPlaces = snprintf(buf, sizeof(buf), "%+ld.0", rhs)-3; + tmpVal.str = (xmlChar*)buf; + tmpVal.fractionalPlaces = 1; + return xmlSchemaValDecimalCompare(lhs, &tmpVal); +} + /* * WARNING: Those type reside normally in xmlschemas.c but are * redefined here locally in oder of being able to use them for xs:anyType- @@ -373,7 +461,7 @@ xmlSchemaAddParticle(void) ret = (xmlSchemaParticlePtr) xmlMalloc(sizeof(xmlSchemaParticle)); if (ret == NULL) { - xmlSchemaTypeErrMemory(NULL, "allocating particle component"); + xmlSchemaTypeErrMemory(); return (NULL); } memset(ret, 0, sizeof(xmlSchemaParticle)); @@ -435,7 +523,7 @@ xmlSchemaInitTypes(void) return (0); xmlSchemaTypesBank = xmlHashCreate(40); if (xmlSchemaTypesBank == NULL) { - xmlSchemaTypeErrMemory(NULL, NULL); + xmlSchemaTypeErrMemory(); goto error; }
@@ -466,7 +554,7 @@ xmlSchemaInitTypes(void) sequence = (xmlSchemaModelGroupPtr) xmlMalloc(sizeof(xmlSchemaModelGroup)); if (sequence == NULL) { - xmlSchemaTypeErrMemory(NULL, "allocating model group component"); + xmlSchemaTypeErrMemory(); goto error; } memset(sequence, 0, sizeof(xmlSchemaModelGroup)); @@ -482,7 +570,7 @@ xmlSchemaInitTypes(void) /* The wildcard */ wild = (xmlSchemaWildcardPtr) xmlMalloc(sizeof(xmlSchemaWildcard)); if (wild == NULL) { - xmlSchemaTypeErrMemory(NULL, "allocating wildcard component"); + xmlSchemaTypeErrMemory(); goto error; } memset(wild, 0, sizeof(xmlSchemaWildcard)); @@ -495,8 +583,7 @@ xmlSchemaInitTypes(void) */ wild = (xmlSchemaWildcardPtr) xmlMalloc(sizeof(xmlSchemaWildcard)); if (wild == NULL) { - xmlSchemaTypeErrMemory(NULL, "could not create an attribute " - "wildcard on anyType"); + xmlSchemaTypeErrMemory(); goto error; } memset(wild, 0, sizeof(xmlSchemaWildcard)); @@ -1179,6 +1266,23 @@ xmlSchemaFreeValue(xmlSchemaValPtr value) { if (value->value.base64.str != NULL) xmlFree(value->value.base64.str); break; + case XML_SCHEMAS_DECIMAL: + case XML_SCHEMAS_INTEGER: + case XML_SCHEMAS_NNINTEGER: + case XML_SCHEMAS_PINTEGER: + case XML_SCHEMAS_NPINTEGER: + case XML_SCHEMAS_NINTEGER: + case XML_SCHEMAS_INT: + case XML_SCHEMAS_UINT: + case XML_SCHEMAS_LONG: + case XML_SCHEMAS_ULONG: + case XML_SCHEMAS_SHORT: + case XML_SCHEMAS_USHORT: + case XML_SCHEMAS_BYTE: + case XML_SCHEMAS_UBYTE: + if (value->value.decimal.str != NULL) + xmlFree(value->value.decimal.str); + break; default: break; } @@ -1273,7 +1377,7 @@ static const unsigned int daysInMonthLeap[12] = ((dt)->hour == 24 && (dt)->min == 0 && (dt)->sec == 0)
#define VALID_TIME(dt) \ - (((VALID_HOUR(dt->hour) && VALID_MIN(dt->min) && \ + (((VALID_HOUR((int)dt->hour) && VALID_MIN((int)dt->min) && \ VALID_SEC(dt->sec)) || VALID_END_OF_DAY(dt)) && \ VALID_TZO(dt->tzo))
@@ -2238,21 +2342,16 @@ xmlSchemaValAtomicListNode(xmlSchemaTypePtr type, const xmlChar *value, /** * xmlSchemaParseUInt: * @str: pointer to the string R/W - * @llo: pointer to the low result - * @lmi: pointer to the mid result - * @lhi: pointer to the high result + * @val: pointer to the resulting decimal * - * Parse an unsigned long into 3 fields. + * Parse an unsigned long into a decimal. * * Returns the number of significant digits in the number or * -1 if overflow of the capacity and -2 if it's not a number. */ -static int -xmlSchemaParseUInt(const xmlChar **str, unsigned long *llo, - unsigned long *lmi, unsigned long *lhi) { - unsigned long lo = 0, mi = 0, hi = 0; - const xmlChar *tmp, *cur = *str; - int ret = 0, i = 0; +static int xmlSchemaParseUInt(const xmlChar **str, xmlSchemaValDecimalPtr val) { + const xmlChar *tmp, *cur = *str; + int ret = 0, i = 0;
if (!((*cur >= '0') && (*cur <= '9'))) return(-2); @@ -2260,31 +2359,29 @@ xmlSchemaParseUInt(const xmlChar **str, unsigned long *llo, while (*cur == '0') { /* ignore leading zeroes */ cur++; } + /* back up in case there is nothing after the leading zeroes */ + if(!(*cur >= '0' && *cur <= '9')) + { + --cur; + } tmp = cur; while ((*tmp != 0) && (*tmp >= '0') && (*tmp <= '9')) { i++;tmp++;ret++; } - if (i > 24) { - *str = tmp; - return(-1); - } - while (i > 16) { - hi = hi * 10 + (*cur++ - '0'); - i--; - } - while (i > 8) { - mi = mi * 10 + (*cur++ - '0'); - i--; - } - while (i > 0) { - lo = lo * 10 + (*cur++ - '0'); - i--; + if (val->integralPlaces + val->fractionalPlaces < (unsigned)i + 1) + { + if (val->str != NULL) + { + xmlFree(val->str); + } + /* sign, dot, fractional 0 and NULL terminator */ + val->str = xmlMalloc(i + 4); } + val->fractionalPlaces = 1; + val->integralPlaces = i; + snprintf((char *)val->str, i + 4, "+%.*s.0", i, cur);
- *str = cur; - *llo = lo; - *lmi = mi; - *lhi = hi; + *str = tmp; return(ret); }
@@ -2472,9 +2569,11 @@ xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value, } case XML_SCHEMAS_DECIMAL:{ const xmlChar *cur = value; - unsigned int len, neg, integ, hasLeadingZeroes; - xmlChar cval[25]; - xmlChar *cptr = cval; + const xmlChar *numStart, *numEnd; + xmlSchemaValDecimal decimal; + xmlChar sign; + + memset(&decimal, 0, sizeof(decimal));
if ((cur == NULL) || (*cur == 0)) goto return1; @@ -2488,9 +2587,9 @@ xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value, /* * First we handle an optional sign. */ - neg = 0; + sign = '+'; if (*cur == '-') { - neg = 1; + sign = '-'; cur++; } else if (*cur == '+') cur++; @@ -2499,47 +2598,44 @@ xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value, */ if (*cur == 0) goto return1; - /* - * Next we "pre-parse" the number, in preparation for calling - * the common routine xmlSchemaParseUInt. We get rid of any - * leading zeroes (because we have reserved only 25 chars), - * and note the position of a decimal point. - */ - len = 0; - integ = ~0u; - hasLeadingZeroes = 0; + /* * Skip leading zeroes. */ while (*cur == '0') { cur++; - hasLeadingZeroes = 1; - } - if (*cur != 0) { - do { - if ((*cur >= '0') && (*cur <= '9')) { - *cptr++ = *cur++; - len++; - } else if (*cur == '.') { - cur++; - integ = len; - do { - if ((*cur >= '0') && (*cur <= '9')) { - *cptr++ = *cur++; - len++; - } else - break; - } while (len < 24); - /* - * Disallow "." but allow "00." - */ - if ((len == 0) && (!hasLeadingZeroes)) - goto return1; - break; - } else - break; - } while (len < 24); } + + numStart = cur; + + while ((*cur >= '0') && (*cur <= '9')) { + ++cur; + ++decimal.integralPlaces; + } + if (*cur == '.') { + ++cur; + } + while ((*cur >= '0') && (*cur <= '9')) { + ++cur; + ++decimal.fractionalPlaces; + } + + /* disallow "." */ + if ( + decimal.fractionalPlaces == 0 && decimal.integralPlaces == 0 + && (numStart == value || numStart[-1] != '0') + ) { + goto return1; + } + + numEnd = cur; + + /* find if there are trailing FRACTIONAL zeroes, and deal with them if necessary */ + while (numEnd > numStart && decimal.fractionalPlaces && numEnd[-1] == '0') { + --numEnd; + --decimal.fractionalPlaces; + } + if (normOnTheFly) while IS_WSP_BLANK_CH(*cur) cur++; if (*cur != 0) @@ -2547,50 +2643,36 @@ xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value, if (val != NULL) { v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL); if (v != NULL) { - /* - * Now evaluate the significant digits of the number - */ - if (len != 0) { - - if (integ != ~0u) { - /* - * Get rid of trailing zeroes in the - * fractional part. - */ - while ((len != integ) && (*(cptr-1) == '0')) { - cptr--; - len--; - } - } - /* - * Terminate the (preparsed) string. - */ - if (len != 0) { - *cptr = 0; - cptr = cval; - - xmlSchemaParseUInt((const xmlChar **)&cptr, - &v->value.decimal.lo, - &v->value.decimal.mi, - &v->value.decimal.hi); - } - } - /* - * Set the total digits to 1 if a zero value. - */ - v->value.decimal.sign = neg; - if (len == 0) { - /* Speedup for zero values. */ - v->value.decimal.total = 1; - } else { - v->value.decimal.total = len; - if (integ == ~0u) - v->value.decimal.frac = 0; - else - v->value.decimal.frac = len - integ; - } + /* create a standardized representation */ + size_t bufsize; + const char *integralStart = (const char *)numStart; + const char *fractionalStart = (const char *)numEnd - decimal.fractionalPlaces; + if (decimal.integralPlaces == 0) + { + integralStart = "0"; + decimal.integralPlaces = 1; + } + if (decimal.fractionalPlaces == 0) + { + fractionalStart = "0"; + decimal.fractionalPlaces = 1; + } + /* 3 = sign, dot, NULL terminator */ + bufsize = decimal.integralPlaces + decimal.fractionalPlaces + 3; + decimal.str = xmlMalloc(bufsize); + if (!decimal.str) + { + goto error; + } + snprintf((char *)decimal.str, bufsize, "%c%.*s.%.*s", sign, decimal.integralPlaces, integralStart, + decimal.fractionalPlaces, fractionalStart); + v->value.decimal = decimal; *val = v; } + else + { + goto error; + } } goto return0; } @@ -2970,19 +3052,19 @@ xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value, * NOTE: the IDness might have already be declared in the DTD */ if (attr->atype != XML_ATTRIBUTE_ID) { - xmlIDPtr res; xmlChar *strip; + int res;
strip = xmlSchemaStrip(value); if (strip != NULL) { - res = xmlAddID(NULL, node->doc, strip, attr); + res = xmlAddIDSafe(attr, strip); xmlFree(strip); } else - res = xmlAddID(NULL, node->doc, value, attr); - if (res == NULL) { + res = xmlAddIDSafe(attr, value); + if (res < 0) { + goto error; + } else if (res == 0) { ret = 2; - } else { - attr->atype = XML_ATTRIBUTE_ID; } } } @@ -3046,7 +3128,7 @@ xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value, ret = 4; } if ((ret == 0) && (val != NULL)) { - TODO; + /* TODO */ } if ((ret == 0) && (node != NULL) && (node->type == XML_ATTRIBUTE_NODE)) { @@ -3198,7 +3280,7 @@ xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value, */ cur = xmlStrndup(start, i); if (cur == NULL) { - xmlSchemaTypeErrMemory(node, "allocating hexbin data"); + xmlSchemaTypeErrMemory(); xmlFree(v); goto return1; } @@ -3325,7 +3407,7 @@ xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value, base = (xmlChar *) xmlMallocAtomic(i + pad + 1); if (base == NULL) { - xmlSchemaTypeErrMemory(node, "allocating base64 data"); + xmlSchemaTypeErrMemory(); xmlFree(v); goto return1; } @@ -3345,201 +3427,152 @@ xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value, case XML_SCHEMAS_PINTEGER: case XML_SCHEMAS_NPINTEGER: case XML_SCHEMAS_NINTEGER: - case XML_SCHEMAS_NNINTEGER:{ - const xmlChar *cur = value; - unsigned long lo, mi, hi; - int sign = 0; - - if (cur == NULL) - goto return1; - if (normOnTheFly) - while IS_WSP_BLANK_CH(*cur) cur++; - if (*cur == '-') { - sign = 1; - cur++; - } else if (*cur == '+') - cur++; - ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi); - if (ret < 0) - goto return1; - if (normOnTheFly) - while IS_WSP_BLANK_CH(*cur) cur++; - if (*cur != 0) - goto return1; - if (type->builtInType == XML_SCHEMAS_NPINTEGER) { - if ((sign == 0) && - ((hi != 0) || (mi != 0) || (lo != 0))) - goto return1; - } else if (type->builtInType == XML_SCHEMAS_PINTEGER) { - if (sign == 1) - goto return1; - if ((hi == 0) && (mi == 0) && (lo == 0)) - goto return1; - } else if (type->builtInType == XML_SCHEMAS_NINTEGER) { - if (sign == 0) - goto return1; - if ((hi == 0) && (mi == 0) && (lo == 0)) - goto return1; - } else if (type->builtInType == XML_SCHEMAS_NNINTEGER) { - if ((sign == 1) && - ((hi != 0) || (mi != 0) || (lo != 0))) - goto return1; - } - if (val != NULL) { - v = xmlSchemaNewValue(type->builtInType); - if (v != NULL) { - if (ret == 0) - ret++; - v->value.decimal.lo = lo; - v->value.decimal.mi = mi; - v->value.decimal.hi = hi; - v->value.decimal.sign = sign; - v->value.decimal.frac = 0; - v->value.decimal.total = ret; - *val = v; - } - } - goto return0; - } + case XML_SCHEMAS_NNINTEGER: case XML_SCHEMAS_LONG: case XML_SCHEMAS_BYTE: case XML_SCHEMAS_SHORT: - case XML_SCHEMAS_INT:{ + case XML_SCHEMAS_INT: + case XML_SCHEMAS_UINT: + case XML_SCHEMAS_ULONG: + case XML_SCHEMAS_USHORT: + case XML_SCHEMAS_UBYTE: { const xmlChar *cur = value; - unsigned long lo, mi, hi; - int sign = 0; + xmlSchemaValDecimal decimal; + xmlChar sign = '+'; + + memset(&decimal, 0, sizeof(decimal));
if (cur == NULL) goto return1; if (normOnTheFly) while IS_WSP_BLANK_CH(*cur) cur++; if (*cur == '-') { - sign = 1; + sign = '-'; cur++; } else if (*cur == '+') cur++; - ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi); + ret = xmlSchemaParseUInt(&cur, &decimal); + /* add sign */ if (ret < 0) - goto return1; + goto valIntegerReturn1; + decimal.str[0] = sign; if (normOnTheFly) while IS_WSP_BLANK_CH(*cur) cur++; if (*cur != 0) - goto return1; - if (type->builtInType == XML_SCHEMAS_LONG) { - if (hi >= 922) { - if (hi > 922) - goto return1; - if (mi >= 33720368) { - if (mi > 33720368) - goto return1; - if ((sign == 0) && (lo > 54775807)) - goto return1; - if ((sign == 1) && (lo > 54775808)) - goto return1; - } - } - } else if (type->builtInType == XML_SCHEMAS_INT) { - if (hi != 0) - goto return1; - if (mi >= 21) { - if (mi > 21) - goto return1; - if ((sign == 0) && (lo > 47483647)) - goto return1; - if ((sign == 1) && (lo > 47483648)) - goto return1; - } - } else if (type->builtInType == XML_SCHEMAS_SHORT) { - if ((mi != 0) || (hi != 0)) - goto return1; - if ((sign == 1) && (lo > 32768)) - goto return1; - if ((sign == 0) && (lo > 32767)) - goto return1; - } else if (type->builtInType == XML_SCHEMAS_BYTE) { - if ((mi != 0) || (hi != 0)) - goto return1; - if ((sign == 1) && (lo > 128)) - goto return1; - if ((sign == 0) && (lo > 127)) - goto return1; + goto valIntegerReturn1; + if (type->builtInType == XML_SCHEMAS_NPINTEGER) + { + if(xmlSchemaValDecimalCompareWithInteger(&decimal, 0) > 0) + goto valIntegerReturn1; } - if (val != NULL) { - v = xmlSchemaNewValue(type->builtInType); - if (v != NULL) { - v->value.decimal.lo = lo; - v->value.decimal.mi = mi; - v->value.decimal.hi = hi; - v->value.decimal.sign = sign; - v->value.decimal.frac = 0; - v->value.decimal.total = ret; - *val = v; - } + else if (type->builtInType == XML_SCHEMAS_PINTEGER) + { + if (sign == '-') + goto valIntegerReturn1; + if (xmlSchemaValDecimalCompareWithInteger(&decimal, 0) <= 0) + goto valIntegerReturn1; } - goto return0; - } - case XML_SCHEMAS_UINT: - case XML_SCHEMAS_ULONG: - case XML_SCHEMAS_USHORT: - case XML_SCHEMAS_UBYTE:{ - const xmlChar *cur = value; - unsigned long lo, mi, hi; - - if (cur == NULL) - goto return1; - if (normOnTheFly) - while IS_WSP_BLANK_CH(*cur) cur++; - ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi); - if (ret < 0) - goto return1; - if (normOnTheFly) - while IS_WSP_BLANK_CH(*cur) cur++; - if (*cur != 0) - goto return1; - if (type->builtInType == XML_SCHEMAS_ULONG) { - if (hi >= 1844) { - if (hi > 1844) - goto return1; - if (mi >= 67440737) { - if (mi > 67440737) - goto return1; - if (lo > 9551615) - goto return1; - } - } - } else if (type->builtInType == XML_SCHEMAS_UINT) { - if (hi != 0) - goto return1; - if (mi >= 42) { - if (mi > 42) - goto return1; - if (lo > 94967295) - goto return1; - } - } else if (type->builtInType == XML_SCHEMAS_USHORT) { - if ((mi != 0) || (hi != 0)) - goto return1; - if (lo > 65535) - goto return1; - } else if (type->builtInType == XML_SCHEMAS_UBYTE) { - if ((mi != 0) || (hi != 0)) - goto return1; - if (lo > 255) - goto return1; + else if (type->builtInType == XML_SCHEMAS_NINTEGER) + { + if (xmlSchemaValDecimalCompareWithInteger(&decimal, 0) >= 0) + goto valIntegerReturn1; + } + else if (type->builtInType == XML_SCHEMAS_NNINTEGER) + { + if (xmlSchemaValDecimalCompareWithInteger(&decimal, 0) < 0) + goto valIntegerReturn1; + } + else if(type->builtInType == XML_SCHEMAS_LONG) + { + /* (u)int64_t may not be available on 32 bit platform, just use decimal */ + xmlSchemaValDecimal tmpDecimal; + static const char maxLong[] = "+9223372036854775807.0"; + static const char minLong[] = "-9223372036854775808.0"; + tmpDecimal.fractionalPlaces = 1; + tmpDecimal.integralPlaces = 19; + tmpDecimal.str = BAD_CAST maxLong; + if (xmlSchemaValDecimalCompare(&decimal, &tmpDecimal) > 0) + goto valIntegerReturn1; + tmpDecimal.str = BAD_CAST minLong; + if (xmlSchemaValDecimalCompare(&decimal, &tmpDecimal) < 0) + goto valIntegerReturn1; + } + else if(type->builtInType == XML_SCHEMAS_ULONG) + { + xmlSchemaValDecimal tmpDecimal; + static const char maxULong[] = "+18446744073709551615.0"; + tmpDecimal.fractionalPlaces = 1; + tmpDecimal.integralPlaces = 20; + tmpDecimal.str = (xmlChar*)maxULong; + if (xmlSchemaValDecimalCompare(&decimal, &tmpDecimal) > 0) + goto valIntegerReturn1; + if (xmlSchemaValDecimalCompareWithInteger(&decimal, 0) < 0) + goto valIntegerReturn1; + } + else if(type->builtInType == XML_SCHEMAS_INT) + { + if (xmlSchemaValDecimalCompareWithInteger(&decimal, 0x7fffffff) > 0) /* INT32_MAX */ + goto valIntegerReturn1; + if (xmlSchemaValDecimalCompareWithInteger(&decimal, -0x7fffffff-1) < 0) /* INT32_MIN */ + goto valIntegerReturn1; + } + else if(type->builtInType == XML_SCHEMAS_SHORT) + { + if (xmlSchemaValDecimalCompareWithInteger(&decimal, 0x7fff) > 0) /* INT16_MAX */ + goto valIntegerReturn1; + if (xmlSchemaValDecimalCompareWithInteger(&decimal, -0x8000) < 0) /* INT16_MIN */ + goto valIntegerReturn1; + } + else if(type->builtInType == XML_SCHEMAS_BYTE) + {if (xmlSchemaValDecimalCompareWithInteger(&decimal, 0x7f) > 0) /* INT8_MAX */ + goto valIntegerReturn1; + if (xmlSchemaValDecimalCompareWithInteger(&decimal, -0x80) < 0) /* INT8_MIN */ + goto valIntegerReturn1; + } + else if(type->builtInType == XML_SCHEMAS_UINT) + { + xmlSchemaValDecimal tmpDecimal; + static const char maxUInt[] = "+4294967295.0"; + tmpDecimal.fractionalPlaces = 1; + tmpDecimal.integralPlaces = 10; + tmpDecimal.str = (xmlChar*)maxUInt; + if (xmlSchemaValDecimalCompare(&decimal, &tmpDecimal) > 0) + goto valIntegerReturn1; + if (xmlSchemaValDecimalCompareWithInteger(&decimal, 0) < 0) + goto valIntegerReturn1; + } + else if(type->builtInType == XML_SCHEMAS_USHORT) + { + if (xmlSchemaValDecimalCompareWithInteger(&decimal, 0xffff) > 0) /* UINT16_MAX */ + goto valIntegerReturn1; + if (xmlSchemaValDecimalCompareWithInteger(&decimal, 0) < 0) + goto valIntegerReturn1; + } + else if(type->builtInType == XML_SCHEMAS_UBYTE) + { + if (xmlSchemaValDecimalCompareWithInteger(&decimal, 0xff) > 0) /* UINT8_MAX */ + goto valIntegerReturn1; + if (xmlSchemaValDecimalCompareWithInteger(&decimal, 0) < 0) + goto valIntegerReturn1; } if (val != NULL) { v = xmlSchemaNewValue(type->builtInType); if (v != NULL) { - v->value.decimal.lo = lo; - v->value.decimal.mi = mi; - v->value.decimal.hi = hi; - v->value.decimal.sign = 0; - v->value.decimal.frac = 0; - v->value.decimal.total = ret; + v->value.decimal = decimal; *val = v; } } + else if(decimal.str != NULL) + { + xmlFree(decimal.str); + } goto return0; + valIntegerReturn1: + if(decimal.str != NULL) + { + xmlFree(decimal.str); + } + goto return1; } }
@@ -3636,139 +3669,16 @@ xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value, static int xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y) { - xmlSchemaValPtr swp; - int order = 1, integx, integy, dlen; - unsigned long hi, mi, lo; - - /* - * First test: If x is -ve and not zero - */ - if ((x->value.decimal.sign) && - ((x->value.decimal.lo != 0) || - (x->value.decimal.mi != 0) || - (x->value.decimal.hi != 0))) { - /* - * Then if y is -ve and not zero reverse the compare - */ - if ((y->value.decimal.sign) && - ((y->value.decimal.lo != 0) || - (y->value.decimal.mi != 0) || - (y->value.decimal.hi != 0))) - order = -1; - /* - * Otherwise (y >= 0) we have the answer - */ - else - return (-1); - /* - * If x is not -ve and y is -ve we have the answer - */ - } else if ((y->value.decimal.sign) && - ((y->value.decimal.lo != 0) || - (y->value.decimal.mi != 0) || - (y->value.decimal.hi != 0))) { - return (1); - } - /* - * If it's not simply determined by a difference in sign, - * then we need to compare the actual values of the two nums. - * To do this, we start by looking at the integral parts. - * If the number of integral digits differ, then we have our - * answer. - */ - integx = x->value.decimal.total - x->value.decimal.frac; - integy = y->value.decimal.total - y->value.decimal.frac; - /* - * NOTE: We changed the "total" for values like "0.1" - * (or "-0.1" or ".1") to be 1, which was 2 previously. - * Therefore the special case, when such values are - * compared with 0, needs to be handled separately; - * otherwise a zero would be recognized incorrectly as - * greater than those values. This has the nice side effect - * that we gain an overall optimized comparison with zeroes. - * Note that a "0" has a "total" of 1 already. - */ - if (integx == 1) { - if (x->value.decimal.lo == 0) { - if (integy != 1) - return -order; - else if (y->value.decimal.lo != 0) - return -order; - else - return(0); - } - } - if (integy == 1) { - if (y->value.decimal.lo == 0) { - if (integx != 1) - return order; - else if (x->value.decimal.lo != 0) - return order; - else - return(0); - } - } - - if (integx > integy) - return order; - else if (integy > integx) - return -order; - - /* - * If the number of integral digits is the same for both numbers, - * then things get a little more complicated. We need to "normalize" - * the numbers in order to properly compare them. To do this, we - * look at the total length of each number (length => number of - * significant digits), and divide the "shorter" by 10 (decreasing - * the length) until they are of equal length. - */ - dlen = x->value.decimal.total - y->value.decimal.total; - if (dlen < 0) { /* y has more digits than x */ - swp = x; - hi = y->value.decimal.hi; - mi = y->value.decimal.mi; - lo = y->value.decimal.lo; - dlen = -dlen; - order = -order; - } else { /* x has more digits than y */ - swp = y; - hi = x->value.decimal.hi; - mi = x->value.decimal.mi; - lo = x->value.decimal.lo; - } - while (dlen > 8) { /* in effect, right shift by 10**8 */ - lo = mi; - mi = hi; - hi = 0; - dlen -= 8; - } - while (dlen > 0) { - unsigned long rem1, rem2; - rem1 = (hi % 10) * 100000000L; - hi = hi / 10; - rem2 = (mi % 10) * 100000000L; - mi = (mi + rem1) / 10; - lo = (lo + rem2) / 10; - dlen--; + int res = xmlSchemaValDecimalCompare(&x->value.decimal, &y->value.decimal); + if(res > 0) + { + return 1; } - if (hi > swp->value.decimal.hi) { - return order; - } else if (hi == swp->value.decimal.hi) { - if (mi > swp->value.decimal.mi) { - return order; - } else if (mi == swp->value.decimal.mi) { - if (lo > swp->value.decimal.lo) { - return order; - } else if (lo == swp->value.decimal.lo) { - if (x->value.decimal.total == y->value.decimal.total) { - return 0; - } else { - return order; - } - } - } + if(res < 0) + { + return -1; } - return -order; + return 0; }
/** @@ -3955,6 +3865,24 @@ xmlSchemaCopyValue(xmlSchemaValPtr val) cur->value.base64.str = xmlStrdup(BAD_CAST val->value.base64.str); break; + case XML_SCHEMAS_DECIMAL: + case XML_SCHEMAS_INTEGER: + case XML_SCHEMAS_PINTEGER: + case XML_SCHEMAS_NPINTEGER: + case XML_SCHEMAS_NINTEGER: + case XML_SCHEMAS_NNINTEGER: + case XML_SCHEMAS_LONG: + case XML_SCHEMAS_BYTE: + case XML_SCHEMAS_SHORT: + case XML_SCHEMAS_INT: + case XML_SCHEMAS_UINT: + case XML_SCHEMAS_ULONG: + case XML_SCHEMAS_USHORT: + case XML_SCHEMAS_UBYTE: + cur = xmlSchemaDupVal(val); + if (val->value.decimal.str != NULL) + cur->value.decimal.str = xmlStrdup(BAD_CAST val->value.decimal.str); + break; default: cur = xmlSchemaDupVal(val); break; @@ -5045,7 +4973,7 @@ xmlSchemaCompareValuesInternal(xmlSchemaValType xtype, * TODO: Compare those against QName. */ if (ytype == XML_SCHEMAS_QNAME) { - TODO + /* TODO */ if (y == NULL) return(-2); return (-2); @@ -5170,7 +5098,7 @@ xmlSchemaCompareValuesInternal(xmlSchemaValType xtype, case XML_SCHEMAS_IDREFS: case XML_SCHEMAS_ENTITIES: case XML_SCHEMAS_NMTOKENS: - TODO + /* TODO */ break; } return -2; @@ -5320,9 +5248,10 @@ xmlSchemaGetFacetValueAsULong(xmlSchemaFacetPtr facet) /* * TODO: Check if this is a decimal. */ + char *discard; if (facet == NULL || facet->val == NULL) return 0; - return ((unsigned long) facet->val->value.decimal.lo); + return strtoul((const char*)facet->val->value.decimal.str+1, &discard, 10); }
/** @@ -5350,21 +5279,21 @@ xmlSchemaValidateListSimpleTypeFacet(xmlSchemaFacetPtr facet, * (compare value.decimal.mi and value.decimal.hi as well?). */ if (facet->type == XML_SCHEMA_FACET_LENGTH) { - if (actualLen != facet->val->value.decimal.lo) { + if (actualLen != xmlSchemaGetFacetValueAsULong(facet)) { if (expectedLen != NULL) - *expectedLen = facet->val->value.decimal.lo; + *expectedLen = xmlSchemaGetFacetValueAsULong(facet); return (XML_SCHEMAV_CVC_LENGTH_VALID); } } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) { - if (actualLen < facet->val->value.decimal.lo) { + if (actualLen < xmlSchemaGetFacetValueAsULong(facet)) { if (expectedLen != NULL) - *expectedLen = facet->val->value.decimal.lo; + *expectedLen = xmlSchemaGetFacetValueAsULong(facet); return (XML_SCHEMAV_CVC_MINLENGTH_VALID); } } else if (facet->type == XML_SCHEMA_FACET_MAXLENGTH) { - if (actualLen > facet->val->value.decimal.lo) { + if (actualLen > xmlSchemaGetFacetValueAsULong(facet)) { if (expectedLen != NULL) - *expectedLen = facet->val->value.decimal.lo; + *expectedLen = xmlSchemaGetFacetValueAsULong(facet); return (XML_SCHEMAV_CVC_MAXLENGTH_VALID); } } else @@ -5417,7 +5346,8 @@ xmlSchemaValidateLengthFacetInternal(xmlSchemaFacetPtr facet, if ((facet->val == NULL) || ((facet->val->type != XML_SCHEMAS_DECIMAL) && (facet->val->type != XML_SCHEMAS_NNINTEGER)) || - (facet->val->value.decimal.frac != 0)) { + !(xmlSchemaValDecimalIsInteger(&facet->val->value.decimal))) + { return(-1); } if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY)) @@ -5471,21 +5401,22 @@ xmlSchemaValidateLengthFacetInternal(xmlSchemaFacetPtr facet, */ return (0); default: - TODO + /* TODO */ + break; } } *length = (unsigned long) len; /* - * TODO: Return the whole expected value, i.e. "lo", "mi" and "hi". + * TODO: Return the whole expected value. (This may be possible now with xmlSchemaValDecimalCompareWithInteger) */ if (facet->type == XML_SCHEMA_FACET_LENGTH) { - if (len != facet->val->value.decimal.lo) + if (len != xmlSchemaGetFacetValueAsULong(facet)) return(XML_SCHEMAV_CVC_LENGTH_VALID); } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) { - if (len < facet->val->value.decimal.lo) + if (len < xmlSchemaGetFacetValueAsULong(facet)) return(XML_SCHEMAV_CVC_MINLENGTH_VALID); } else { - if (len > facet->val->value.decimal.lo) + if (len > xmlSchemaGetFacetValueAsULong(facet)) return(XML_SCHEMAV_CVC_MAXLENGTH_VALID); }
@@ -5681,7 +5612,7 @@ xmlSchemaValidateFacetInternal(xmlSchemaFacetPtr facet, if ((facet->val == NULL) || ((facet->val->type != XML_SCHEMAS_DECIMAL) && (facet->val->type != XML_SCHEMAS_NNINTEGER)) || - (facet->val->value.decimal.frac != 0)) { + !xmlSchemaValDecimalIsInteger(&facet->val->value.decimal)) { return(-1); } if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY)) @@ -5725,18 +5656,18 @@ xmlSchemaValidateFacetInternal(xmlSchemaFacetPtr facet, len = xmlSchemaNormLen(value); break; default: - TODO + /* TODO */ + break; } } if (facet->type == XML_SCHEMA_FACET_LENGTH) { - if (len != facet->val->value.decimal.lo) + if (len != xmlSchemaGetFacetValueAsULong(facet)) return(XML_SCHEMAV_CVC_LENGTH_VALID); } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) { - if (len < facet->val->value.decimal.lo) + if (len < xmlSchemaGetFacetValueAsULong(facet)) return(XML_SCHEMAV_CVC_MINLENGTH_VALID); - } else { - if (len > facet->val->value.decimal.lo) - return(XML_SCHEMAV_CVC_MAXLENGTH_VALID); + } else if (len > xmlSchemaGetFacetValueAsULong(facet)) { + return (XML_SCHEMAV_CVC_MAXLENGTH_VALID); } break; } @@ -5746,7 +5677,7 @@ xmlSchemaValidateFacetInternal(xmlSchemaFacetPtr facet, if ((facet->val == NULL) || ((facet->val->type != XML_SCHEMAS_PINTEGER) && (facet->val->type != XML_SCHEMAS_NNINTEGER)) || - (facet->val->value.decimal.frac != 0)) { + !xmlSchemaValDecimalIsInteger(&facet->val->value.decimal)) { return(-1); } if ((val == NULL) || @@ -5767,16 +5698,17 @@ xmlSchemaValidateFacetInternal(xmlSchemaFacetPtr facet, return(-1); } if (facet->type == XML_SCHEMA_FACET_TOTALDIGITS) { - if (val->value.decimal.total > facet->val->value.decimal.lo) + if (xmlSchemaValDecimalGetSignificantDigitCount(&val->value.decimal) > xmlSchemaGetFacetValueAsULong(facet)) return(XML_SCHEMAV_CVC_TOTALDIGITS_VALID);
} else if (facet->type == XML_SCHEMA_FACET_FRACTIONDIGITS) { - if (val->value.decimal.frac > facet->val->value.decimal.lo) + if ((xmlSchemaValDecimalIsInteger(&val->value.decimal) ? 0 : val->value.decimal.fractionalPlaces) > xmlSchemaGetFacetValueAsULong(facet)) return(XML_SCHEMAV_CVC_FRACTIONDIGITS_VALID); } break; default: - TODO + /* TODO */ + break; } return(0);
@@ -6002,75 +5934,13 @@ xmlSchemaGetCanonValue(xmlSchemaValPtr val, const xmlChar **retValue) BAD_CAST val->value.qname.uri); } break; - case XML_SCHEMAS_DECIMAL: - /* - * TODO: Lookout for a more simple implementation. - */ - if ((val->value.decimal.total == 1) && - (val->value.decimal.lo == 0)) { - *retValue = xmlStrdup(BAD_CAST "0.0"); - } else { - xmlSchemaValDecimal dec = val->value.decimal; - int bufsize; - char *buf = NULL, *offs; - - /* Add room for the decimal point as well. */ - bufsize = dec.total + 2; - if (dec.sign) - bufsize++; - /* Add room for leading/trailing zero. */ - if ((dec.frac == 0) || (dec.frac == dec.total)) - bufsize++; - buf = xmlMalloc(bufsize); - if (buf == NULL) - return(-1); - offs = buf; - if (dec.sign) - *offs++ = '-'; - if (dec.frac == dec.total) { - *offs++ = '0'; - *offs++ = '.'; - } - if (dec.hi != 0) - snprintf(offs, bufsize - (offs - buf), - "%lu%lu%lu", dec.hi, dec.mi, dec.lo); - else if (dec.mi != 0) - snprintf(offs, bufsize - (offs - buf), - "%lu%lu", dec.mi, dec.lo); - else - snprintf(offs, bufsize - (offs - buf), - "%lu", dec.lo); - - if (dec.frac != 0) { - if (dec.frac != dec.total) { - int diff = dec.total - dec.frac; - /* - * Insert the decimal point. - */ - memmove(offs + diff + 1, offs + diff, dec.frac +1); - offs[diff] = '.'; - } else { - unsigned int i = 0; - /* - * Insert missing zeroes behind the decimal point. - */ - while (*(offs + i) != 0) - i++; - if (i < dec.total) { - memmove(offs + (dec.total - i), offs, i +1); - memset(offs, '0', dec.total - i); - } - } - } else { - /* - * Append decimal point and zero. - */ - offs = buf + bufsize - 1; - *offs-- = 0; - *offs-- = '0'; - *offs-- = '.'; - } - *retValue = BAD_CAST buf; + case XML_SCHEMAS_DECIMAL: { + xmlChar *start = val->value.decimal.str; + if(start[0] == '+') + { + start += 1; + } + *retValue = xmlStrdup(start); } break; case XML_SCHEMAS_INTEGER: @@ -6085,40 +5955,20 @@ xmlSchemaGetCanonValue(xmlSchemaValPtr val, const xmlChar **retValue) case XML_SCHEMAS_UINT: case XML_SCHEMAS_ULONG: case XML_SCHEMAS_USHORT: - case XML_SCHEMAS_UBYTE: - if ((val->value.decimal.total == 1) && - (val->value.decimal.lo == 0)) - *retValue = xmlStrdup(BAD_CAST "0"); - else { - xmlSchemaValDecimal dec = val->value.decimal; - int bufsize = dec.total + 1; - - /* Add room for the decimal point as well. */ - if (dec.sign) - bufsize++; - *retValue = xmlMalloc(bufsize); - if (*retValue == NULL) - return(-1); - if (dec.hi != 0) { - if (dec.sign) - snprintf((char *) *retValue, bufsize, - "-%lu%lu%lu", dec.hi, dec.mi, dec.lo); - else - snprintf((char *) *retValue, bufsize, - "%lu%lu%lu", dec.hi, dec.mi, dec.lo); - } else if (dec.mi != 0) { - if (dec.sign) - snprintf((char *) *retValue, bufsize, - "-%lu%lu", dec.mi, dec.lo); - else - snprintf((char *) *retValue, bufsize, - "%lu%lu", dec.mi, dec.lo); - } else { - if (dec.sign) - snprintf((char *) *retValue, bufsize, "-%lu", dec.lo); - else - snprintf((char *) *retValue, bufsize, "%lu", dec.lo); - } + case XML_SCHEMAS_UBYTE: { + xmlChar *start = val->value.decimal.str; + /* 2 = sign+NULL */ + size_t bufSize = val->value.decimal.integralPlaces+2; + if(start[0] == '+') + { + start += 1; + bufSize -= 1; + } + *retValue = xmlMalloc(bufSize); + if(*retValue) { + /* no need to limit string length in format, it will only print bufSize-1 chars anyways */ + snprintf((char*)*retValue, bufSize, "%s", start); + } } break; case XML_SCHEMAS_BOOLEAN: diff --git a/libs/xml2/xmlstring.c b/libs/xml2/xmlstring.c index ce1c12dabbc..219697e3518 100644 --- a/libs/xml2/xmlstring.c +++ b/libs/xml2/xmlstring.c @@ -26,6 +26,14 @@ #include "private/parser.h" #include "private/string.h"
+#ifndef va_copy + #ifdef __va_copy + #define va_copy(dest, src) __va_copy(dest, src) + #else + #define va_copy(dest, src) memcpy(&(dest), &(src), sizeof(va_list)) + #endif +#endif + /************************************************************************ * * * Commodity functions to handle xmlChars * @@ -461,7 +469,8 @@ xmlStrncat(xmlChar *cur, const xmlChar *add, int len) { return(NULL); ret = (xmlChar *) xmlRealloc(cur, (size_t) size + len + 1); if (ret == NULL) { - return(cur); + xmlFree(cur); + return(NULL); } memcpy(&ret[size], add, len); ret[size + len] = 0; @@ -490,18 +499,17 @@ xmlStrncatNew(const xmlChar *str1, const xmlChar *str2, int len) { if (len < 0) return(NULL); } - if ((str2 == NULL) || (len == 0)) - return(xmlStrdup(str1)); if (str1 == NULL) return(xmlStrndup(str2, len)); + if ((str2 == NULL) || (len == 0)) + return(xmlStrdup(str1));
size = xmlStrlen(str1); if ((size < 0) || (size > INT_MAX - len)) return(NULL); ret = (xmlChar *) xmlMalloc((size_t) size + len + 1); - if (ret == NULL) { - return(xmlStrndup(str1, size)); - } + if (ret == NULL) + return(NULL); memcpy(ret, str1, size); memcpy(&ret[size], str2, len); ret[size + len] = 0; @@ -585,6 +593,148 @@ xmlStrVPrintf(xmlChar *buf, int len, const char *msg, va_list ap) { return(ret); }
+/** + * xmlStrVASPrintf: + * @out: pointer to the resulting string + * @maxSize: maximum size of the output buffer + * @msg: printf format string + * @ap: arguments for format string + * + * Creates a newly allocated string according to format. + * + * Returns 0 on success, 1 if the result was truncated or on other + * errors, -1 if a memory allocation failed. + */ +int +xmlStrVASPrintf(xmlChar **out, int maxSize, const char *msg, va_list ap) { + char empty[1]; + va_list copy; + xmlChar *buf; + int res, size; + int truncated = 0; + + if (out == NULL) + return(1); + *out = NULL; + if (msg == NULL) + return(1); + if (maxSize < 32) + maxSize = 32; + + va_copy(copy, ap); + res = vsnprintf(empty, 1, msg, copy); + va_end(copy); + + if (res > 0) { + /* snprintf seems to work according to C99. */ + + if (res < maxSize) { + size = res + 1; + } else { + size = maxSize; + truncated = 1; + } + buf = xmlMalloc(size); + if (buf == NULL) + return(-1); + if (vsnprintf((char *) buf, size, msg, ap) < 0) { + xmlFree(buf); + return(1); + } + } else { + /* + * Unfortunately, older snprintf implementations don't follow the + * C99 spec. If the output exceeds the size of the buffer, they can + * return -1, 0 or the number of characters written instead of the + * needed size. Older MSCVRT also won't write a terminating null + * byte if the buffer is too small. + * + * If the value returned is non-negative and strictly less than + * the buffer size (without terminating null), the result should + * have been written completely, so we double the buffer size + * until this condition is true. This assumes that snprintf will + * eventually return a non-negative value. Otherwise, we will + * allocate more and more memory until we run out. + * + * Note that this code path is also executed on conforming + * platforms if the output is the empty string. + */ + + buf = NULL; + size = 32; + while (1) { + buf = xmlMalloc(size); + if (buf == NULL) + return(-1); + + va_copy(copy, ap); + res = vsnprintf((char *) buf, size, msg, copy); + va_end(copy); + if ((res >= 0) && (res < size - 1)) + break; + + if (size >= maxSize) { + truncated = 1; + break; + } + + xmlFree(buf); + + if (size > maxSize / 2) + size = maxSize; + else + size *= 2; + } + } + + /* + * If the output was truncated, make sure that the buffer doesn't + * end with a truncated UTF-8 sequence. + */ + if (truncated != 0) { + int i = size - 1; + + while (i > 0) { + /* Break after ASCII */ + if (buf[i-1] < 0x80) + break; + i -= 1; + /* Break before non-ASCII */ + if (buf[i] >= 0xc0) + break; + } + + buf[i] = 0; + } + + *out = (xmlChar *) buf; + return(truncated); +} + +/** + * xmlStrASPrintf: + * @out: pointer to the resulting string + * @maxSize: maximum size of the output buffer + * @msg: printf format string + * @...: arguments for format string + * + * See xmlStrVASPrintf. + * + * Returns 0 on success, 1 if the result was truncated or on other + * errors, -1 if a memory allocation failed. + */ +int +xmlStrASPrintf(xmlChar **out, int maxSize, const char *msg, ...) { + va_list ap; + int ret; + + va_start(ap, msg); + ret = xmlStrVASPrintf(out, maxSize, msg, ap); + va_end(ap); + + return(ret); +} + /************************************************************************ * * * Generic UTF8 handling routines * @@ -956,8 +1106,9 @@ xmlUTF8Strloc(const xmlChar *utf, const xmlChar *utfchar) { * Create a substring from a given UTF-8 string * Note: positions are given in units of UTF-8 chars * - * Returns a pointer to a newly created string - * or NULL if any problem + * Returns a pointer to a newly created string or NULL if the + * start index is out of bounds or a memory allocation failed. + * If len is too large, the result is truncated. */
xmlChar * @@ -972,16 +1123,18 @@ xmlUTF8Strsub(const xmlChar *utf, int start, int len) { /* * Skip over any leading chars */ - for (i = 0;i < start;i++) { - if ((ch=*utf++) == 0) return(NULL); - if ( ch & 0x80 ) { - /* if not simple ascii, verify proper format */ - if ( (ch & 0xc0) != 0xc0 ) - return(NULL); - /* then skip over remaining bytes for this char */ - while ( (ch <<= 1) & 0x80 ) - if ( (*utf++ & 0xc0) != 0x80 ) + for (i = 0; i < start; i++) { + ch = *utf++; + if (ch == 0) + return(NULL); + /* skip over remaining bytes for this char */ + if (ch & 0x80) { + ch <<= 1; + while (ch & 0x80) { + if (*utf++ == 0) return(NULL); + ch <<= 1; + } } }
diff --git a/libs/xml2/xpath.c b/libs/xml2/xpath.c index 660d70e50fd..485d774738f 100644 --- a/libs/xml2/xpath.c +++ b/libs/xml2/xpath.c @@ -51,14 +51,12 @@ #include "private/error.h" #include "private/xpath.h"
+/* Disabled for now */ +#if 0 #ifdef LIBXML_PATTERN_ENABLED #define XPATH_STREAMING #endif - -#define TODO \ - xmlGenericError(xmlGenericErrorContext, \ - "Unimplemented block at %s:%d\n", \ - __FILE__, __LINE__); +#endif
/** * WITH_TIM_SORT: @@ -226,7 +224,7 @@ xmlXPathIsInf(double val) { * the test should just be name[0] = ' ' */
-static xmlNs xmlXPathXMLNamespaceStruct = { +static const xmlNs xmlXPathXMLNamespaceStruct = { NULL, XML_NAMESPACE_DECL, XML_XML_NAMESPACE, @@ -234,7 +232,7 @@ static xmlNs xmlXPathXMLNamespaceStruct = { NULL, NULL }; -static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct; +static const xmlNs *const xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct; #ifndef LIBXML_THREAD_ENABLED /* * Optimizer is disabled only when threaded apps are detected while @@ -626,123 +624,100 @@ static const char* const xmlXPathErrorMessages[] = { /** * xmlXPathErrMemory: * @ctxt: an XPath context - * @extra: extra information * - * Handle a redefinition of attribute error + * Handle a memory allocation failure. */ -static void -xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra) +void +xmlXPathErrMemory(xmlXPathContextPtr ctxt) { - if (ctxt != NULL) { - xmlResetError(&ctxt->lastError); - if (extra) { - xmlChar buf[200]; - - xmlStrPrintf(buf, 200, - "Memory allocation failed : %s\n", - extra); - ctxt->lastError.message = (char *) xmlStrdup(buf); - } else { - ctxt->lastError.message = (char *) - xmlStrdup(BAD_CAST "Memory allocation failed\n"); - } - ctxt->lastError.domain = XML_FROM_XPATH; - ctxt->lastError.code = XML_ERR_NO_MEMORY; - if (ctxt->error != NULL) - ctxt->error(ctxt->userData, &ctxt->lastError); - } else { - if (extra) - __xmlRaiseError(NULL, NULL, NULL, - NULL, NULL, XML_FROM_XPATH, - XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, - extra, NULL, NULL, 0, 0, - "Memory allocation failed : %s\n", extra); - else - __xmlRaiseError(NULL, NULL, NULL, - NULL, NULL, XML_FROM_XPATH, - XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, - NULL, NULL, NULL, 0, 0, - "Memory allocation failed\n"); - } + if (ctxt == NULL) + return; + xmlRaiseMemoryError(ctxt->error, NULL, ctxt->userData, XML_FROM_XPATH, + &ctxt->lastError); }
/** * xmlXPathPErrMemory: * @ctxt: an XPath parser context - * @extra: extra information * - * Handle a redefinition of attribute error + * Handle a memory allocation failure. */ -static void -xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra) +void +xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt) { if (ctxt == NULL) - xmlXPathErrMemory(NULL, extra); - else { - ctxt->error = XPATH_MEMORY_ERROR; - xmlXPathErrMemory(ctxt->context, extra); - } + return; + ctxt->error = XPATH_MEMORY_ERROR; + xmlXPathErrMemory(ctxt->context); }
/** * xmlXPathErr: * @ctxt: a XPath parser context - * @error: the error code + * @code: the error code * * Handle an XPath error */ void -xmlXPathErr(xmlXPathParserContextPtr ctxt, int error) +xmlXPathErr(xmlXPathParserContextPtr ctxt, int code) { - if ((error < 0) || (error > MAXERRNO)) - error = MAXERRNO; - if (ctxt == NULL) { - __xmlRaiseError(NULL, NULL, NULL, - NULL, NULL, XML_FROM_XPATH, - error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, - XML_ERR_ERROR, NULL, 0, - NULL, NULL, NULL, 0, 0, - "%s", xmlXPathErrorMessages[error]); - return; - } + xmlStructuredErrorFunc schannel = NULL; + xmlGenericErrorFunc channel = NULL; + void *data = NULL; + xmlNodePtr node = NULL; + int res; + + if (ctxt == NULL) + return; + if ((code < 0) || (code > MAXERRNO)) + code = MAXERRNO; /* Only report the first error */ if (ctxt->error != 0) return; - ctxt->error = error; - if (ctxt->context == NULL) { - __xmlRaiseError(NULL, NULL, NULL, - NULL, NULL, XML_FROM_XPATH, - error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, - XML_ERR_ERROR, NULL, 0, - (const char *) ctxt->base, NULL, NULL, - ctxt->cur - ctxt->base, 0, - "%s", xmlXPathErrorMessages[error]); - return; - }
- /* cleanup current last error */ - xmlResetError(&ctxt->context->lastError); + ctxt->error = code;
- ctxt->context->lastError.domain = XML_FROM_XPATH; - ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK - - XPATH_EXPRESSION_OK; - ctxt->context->lastError.level = XML_ERR_ERROR; - ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base); - ctxt->context->lastError.int1 = ctxt->cur - ctxt->base; - ctxt->context->lastError.node = ctxt->context->debugNode; - if (ctxt->context->error != NULL) { - ctxt->context->error(ctxt->context->userData, - &ctxt->context->lastError); - } else { - __xmlRaiseError(NULL, NULL, NULL, - NULL, ctxt->context->debugNode, XML_FROM_XPATH, - error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, - XML_ERR_ERROR, NULL, 0, - (const char *) ctxt->base, NULL, NULL, - ctxt->cur - ctxt->base, 0, - "%s", xmlXPathErrorMessages[error]); + if (ctxt->context != NULL) { + xmlErrorPtr err = &ctxt->context->lastError; + + /* Don't overwrite memory error. */ + if (err->code == XML_ERR_NO_MEMORY) + return; + + /* cleanup current last error */ + xmlResetError(err); + + err->domain = XML_FROM_XPATH; + err->code = code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK; + err->level = XML_ERR_ERROR; + if (ctxt->base != NULL) { + err->str1 = (char *) xmlStrdup(ctxt->base); + if (err->str1 == NULL) { + xmlXPathPErrMemory(ctxt); + return; + } + } + err->int1 = ctxt->cur - ctxt->base; + err->node = ctxt->context->debugNode; + + schannel = ctxt->context->error; + data = ctxt->context->userData; + node = ctxt->context->debugNode; + } + + if (schannel == NULL) { + channel = xmlGenericError; + data = xmlGenericErrorContext; }
+ res = __xmlRaiseError(schannel, channel, data, NULL, node, XML_FROM_XPATH, + code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK, + XML_ERR_ERROR, NULL, 0, + (const char *) ctxt->base, NULL, NULL, + ctxt->cur - ctxt->base, 0, + "%s", xmlXPathErrorMessages[code]); + if (res < 0) + xmlXPathPErrMemory(ctxt); }
/** @@ -786,104 +761,6 @@ xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) { #define OP_LIMIT_EXCEEDED(ctxt, n) \ ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
-/************************************************************************ - * * - * Utilities * - * * - ************************************************************************/ - -/** - * xsltPointerList: - * - * Pointer-list for various purposes. - */ -typedef struct _xmlPointerList xmlPointerList; -typedef xmlPointerList *xmlPointerListPtr; -struct _xmlPointerList { - void **items; - int number; - int size; -}; -/* -* TODO: Since such a list-handling is used in xmlschemas.c and libxslt -* and here, we should make the functions public. -*/ -static int -xmlPointerListAddSize(xmlPointerListPtr list, - void *item, - int initialSize) -{ - if (list->size <= list->number) { - void **tmp; - size_t newSize; - - if (list->size == 0) { - if (initialSize <= 0) - initialSize = 1; - newSize = initialSize; - } else { - if (list->size > 50000000) { - xmlXPathErrMemory(NULL, - "xmlPointerListAddSize: re-allocating item\n"); - return(-1); - } - newSize = list->size * 2; - } - tmp = (void **) xmlRealloc(list->items, newSize * sizeof(void *)); - if (tmp == NULL) { - xmlXPathErrMemory(NULL, - "xmlPointerListAddSize: re-allocating item\n"); - return(-1); - } - list->items = tmp; - list->size = newSize; - } - list->items[list->number++] = item; - return(0); -} - -/** - * xsltPointerListCreate: - * - * Creates an xsltPointerList structure. - * - * Returns a xsltPointerList structure or NULL in case of an error. - */ -static xmlPointerListPtr -xmlPointerListCreate(int initialSize) -{ - xmlPointerListPtr ret; - - ret = xmlMalloc(sizeof(xmlPointerList)); - if (ret == NULL) { - xmlXPathErrMemory(NULL, - "xmlPointerListCreate: allocating item\n"); - return (NULL); - } - memset(ret, 0, sizeof(xmlPointerList)); - if (initialSize > 0) { - xmlPointerListAddSize(ret, NULL, initialSize); - ret->number = 0; - } - return (ret); -} - -/** - * xsltPointerListFree: - * - * Frees the xsltPointerList structure. This does not free - * the content of the list. - */ -static void -xmlPointerListFree(xmlPointerListPtr list) -{ - if (list == NULL) - return; - if (list->items != NULL) - xmlFree(list->items); - xmlFree(list); -} - /************************************************************************ * * * Parser Types * @@ -982,8 +859,7 @@ struct _xmlXPathCompExpr { * Forward declarations * * * ************************************************************************/ -static void -xmlXPathFreeValueTree(xmlNodeSetPtr obj); + static void xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj); static int @@ -1014,17 +890,14 @@ xmlXPathNewCompExpr(void) { xmlXPathCompExprPtr cur;
cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr)); - if (cur == NULL) { - xmlXPathErrMemory(NULL, "allocating component\n"); + if (cur == NULL) return(NULL); - } memset(cur, 0, sizeof(xmlXPathCompExpr)); cur->maxStep = 10; cur->nbStep = 0; cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep * sizeof(xmlXPathStepOp)); if (cur->steps == NULL) { - xmlXPathErrMemory(NULL, "allocating steps\n"); xmlFree(cur); return(NULL); } @@ -1109,7 +982,7 @@ xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2, xmlXPathStepOp *real;
if (comp->maxStep >= XPATH_MAX_STEPS) { - xmlXPathPErrMemory(ctxt, "adding step\n"); + xmlXPathPErrMemory(ctxt); return(-1); } comp->maxStep *= 2; @@ -1117,7 +990,7 @@ xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2, comp->maxStep * sizeof(xmlXPathStepOp)); if (real == NULL) { comp->maxStep /= 2; - xmlXPathPErrMemory(ctxt, "adding step\n"); + xmlXPathPErrMemory(ctxt); return(-1); } comp->steps = real; @@ -1203,20 +1076,14 @@ xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op), \
/* #define XP_DEFAULT_CACHE_ON */
-#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL)) - typedef struct _xmlXPathContextCache xmlXPathContextCache; typedef xmlXPathContextCache *xmlXPathContextCachePtr; struct _xmlXPathContextCache { - xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */ - xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */ - xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */ - xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */ - xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */ + xmlXPathObjectPtr nodesetObjs; /* stringval points to next */ + xmlXPathObjectPtr miscObjs; /* stringval points to next */ + int numNodeset; int maxNodeset; - int maxString; - int maxBoolean; - int maxNumber; + int numMisc; int maxMisc; };
@@ -1226,11 +1093,6 @@ struct _xmlXPathContextCache { * * ************************************************************************/
-#define STRANGE \ - xmlGenericError(xmlGenericErrorContext, \ - "Internal error at %s:%d\n", \ - __FILE__, __LINE__); - #ifdef LIBXML_DEBUG_ENABLED static void xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) { @@ -1695,42 +1557,31 @@ xmlXPathNewCache(void) xmlXPathContextCachePtr ret;
ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache)); - if (ret == NULL) { - xmlXPathErrMemory(NULL, "creating object cache\n"); + if (ret == NULL) return(NULL); - } memset(ret, 0 , sizeof(xmlXPathContextCache)); ret->maxNodeset = 100; - ret->maxString = 100; - ret->maxBoolean = 100; - ret->maxNumber = 100; ret->maxMisc = 100; return(ret); }
static void -xmlXPathCacheFreeObjectList(xmlPointerListPtr list) +xmlXPathCacheFreeObjectList(xmlXPathObjectPtr list) { - int i; - xmlXPathObjectPtr obj; + while (list != NULL) { + xmlXPathObjectPtr next;
- if (list == NULL) - return; + next = (void *) list->stringval;
- for (i = 0; i < list->number; i++) { - obj = list->items[i]; - /* - * Note that it is already assured that we don't need to - * look out for namespace nodes in the node-set. - */ - if (obj->nodesetval != NULL) { - if (obj->nodesetval->nodeTab != NULL) - xmlFree(obj->nodesetval->nodeTab); - xmlFree(obj->nodesetval); + if (list->nodesetval != NULL) { + if (list->nodesetval->nodeTab != NULL) + xmlFree(list->nodesetval->nodeTab); + xmlFree(list->nodesetval); } - xmlFree(obj); + xmlFree(list); + + list = next; } - xmlPointerListFree(list); }
static void @@ -1740,12 +1591,6 @@ xmlXPathFreeCache(xmlXPathContextCachePtr cache) return; if (cache->nodesetObjs) xmlXPathCacheFreeObjectList(cache->nodesetObjs); - if (cache->stringObjs) - xmlXPathCacheFreeObjectList(cache->stringObjs); - if (cache->booleanObjs) - xmlXPathCacheFreeObjectList(cache->booleanObjs); - if (cache->numberObjs) - xmlXPathCacheFreeObjectList(cache->numberObjs); if (cache->miscObjs) xmlXPathCacheFreeObjectList(cache->miscObjs); xmlFree(cache); @@ -1767,8 +1612,8 @@ xmlXPathFreeCache(xmlXPathContextCachePtr cache) * @value: * This will set the maximum number of XPath objects * to be cached per slot - * There are 5 slots for: node-set, string, number, boolean, and - * misc objects. Use <0 for the default number (100). + * There are two slots for node-set and misc objects. + * Use <0 for the default number (100). * Other values for @options have currently no effect. * * Returns 0 if the setting succeeded, and -1 on API or internal errors. @@ -1786,17 +1631,16 @@ xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
if (ctxt->cache == NULL) { ctxt->cache = xmlXPathNewCache(); - if (ctxt->cache == NULL) + if (ctxt->cache == NULL) { + xmlXPathErrMemory(ctxt); return(-1); + } } cache = (xmlXPathContextCachePtr) ctxt->cache; if (options == 0) { if (value < 0) value = 100; cache->maxNodeset = value; - cache->maxString = value; - cache->maxNumber = value; - cache->maxBoolean = value; cache->maxMisc = value; } } else if (ctxt->cache != NULL) { @@ -1808,7 +1652,7 @@ xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
/** * xmlXPathCacheWrapNodeSet: - * @ctxt: the XPath context + * @pctxt: the XPath context * @val: the NodePtr value * * This is the cached version of xmlXPathWrapNodeSet(). @@ -1819,32 +1663,35 @@ xmlXPathContextSetCache(xmlXPathContextPtr ctxt, * In case of error the node set is destroyed and NULL is returned. */ static xmlXPathObjectPtr -xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val) +xmlXPathCacheWrapNodeSet(xmlXPathParserContextPtr pctxt, xmlNodeSetPtr val) { + xmlXPathObjectPtr ret; + xmlXPathContextPtr ctxt = pctxt->context; + if ((ctxt != NULL) && (ctxt->cache != NULL)) { xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
- if ((cache->miscObjs != NULL) && - (cache->miscObjs->number != 0)) - { - xmlXPathObjectPtr ret; - - ret = (xmlXPathObjectPtr) - cache->miscObjs->items[--cache->miscObjs->number]; + if (cache->miscObjs != NULL) { + ret = cache->miscObjs; + cache->miscObjs = (void *) ret->stringval; + cache->numMisc -= 1; + ret->stringval = NULL; ret->type = XPATH_NODESET; ret->nodesetval = val; return(ret); } }
- return(xmlXPathWrapNodeSet(val)); - + ret = xmlXPathWrapNodeSet(val); + if (ret == NULL) + xmlXPathPErrMemory(pctxt); + return(ret); }
/** * xmlXPathCacheWrapString: - * @ctxt: the XPath context + * @pctxt the XPath context * @val: the xmlChar * value * * This is the cached version of xmlXPathWrapString(). @@ -1853,43 +1700,33 @@ xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val) * Returns the created or reused object. */ static xmlXPathObjectPtr -xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val) +xmlXPathCacheWrapString(xmlXPathParserContextPtr pctxt, xmlChar *val) { + xmlXPathObjectPtr ret; + xmlXPathContextPtr ctxt = pctxt->context; + if ((ctxt != NULL) && (ctxt->cache != NULL)) { xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
- if ((cache->stringObjs != NULL) && - (cache->stringObjs->number != 0)) - { - - xmlXPathObjectPtr ret; - - ret = (xmlXPathObjectPtr) - cache->stringObjs->items[--cache->stringObjs->number]; - ret->type = XPATH_STRING; - ret->stringval = val; - return(ret); - } else if ((cache->miscObjs != NULL) && - (cache->miscObjs->number != 0)) - { - xmlXPathObjectPtr ret; - /* - * Fallback to misc-cache. - */ - ret = (xmlXPathObjectPtr) - cache->miscObjs->items[--cache->miscObjs->number]; - + if (cache->miscObjs != NULL) { + ret = cache->miscObjs; + cache->miscObjs = (void *) ret->stringval; + cache->numMisc -= 1; ret->type = XPATH_STRING; ret->stringval = val; return(ret); } } - return(xmlXPathWrapString(val)); + + ret = xmlXPathWrapString(val); + if (ret == NULL) + xmlXPathPErrMemory(pctxt); + return(ret); }
/** * xmlXPathCacheNewNodeSet: - * @ctxt: the XPath context + * @pctxt the XPath context * @val: the NodePtr value * * This is the cached version of xmlXPathNewNodeSet(). @@ -1899,38 +1736,37 @@ xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val) * Returns the created or reused object. */ static xmlXPathObjectPtr -xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val) +xmlXPathCacheNewNodeSet(xmlXPathParserContextPtr pctxt, xmlNodePtr val) { - if ((ctxt != NULL) && (ctxt->cache)) { + xmlXPathObjectPtr ret; + xmlXPathContextPtr ctxt = pctxt->context; + + if ((ctxt != NULL) && (ctxt->cache != NULL)) { xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
- if ((cache->nodesetObjs != NULL) && - (cache->nodesetObjs->number != 0)) - { - xmlXPathObjectPtr ret; + if (cache->nodesetObjs != NULL) { /* * Use the nodeset-cache. */ - ret = (xmlXPathObjectPtr) - cache->nodesetObjs->items[--cache->nodesetObjs->number]; + ret = cache->nodesetObjs; + cache->nodesetObjs = (void *) ret->stringval; + cache->numNodeset -= 1; + ret->stringval = NULL; ret->type = XPATH_NODESET; ret->boolval = 0; if (val) { if ((ret->nodesetval->nodeMax == 0) || (val->type == XML_NAMESPACE_DECL)) { - /* TODO: Check memory error. */ - xmlXPathNodeSetAddUnique(ret->nodesetval, val); + if (xmlXPathNodeSetAddUnique(ret->nodesetval, val) < 0) + xmlXPathPErrMemory(pctxt); } else { ret->nodesetval->nodeTab[0] = val; ret->nodesetval->nodeNr = 1; } } return(ret); - } else if ((cache->miscObjs != NULL) && - (cache->miscObjs->number != 0)) - { - xmlXPathObjectPtr ret; + } else if (cache->miscObjs != NULL) { xmlNodeSetPtr set; /* * Fallback to misc-cache. @@ -1938,26 +1774,29 @@ xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
set = xmlXPathNodeSetCreate(val); if (set == NULL) { - ctxt->lastError.domain = XML_FROM_XPATH; - ctxt->lastError.code = XML_ERR_NO_MEMORY; + xmlXPathPErrMemory(pctxt); return(NULL); }
- ret = (xmlXPathObjectPtr) - cache->miscObjs->items[--cache->miscObjs->number]; - + ret = cache->miscObjs; + cache->miscObjs = (void *) ret->stringval; + cache->numMisc -= 1; + ret->stringval = NULL; ret->type = XPATH_NODESET; ret->boolval = 0; ret->nodesetval = set; return(ret); } } - return(xmlXPathNewNodeSet(val)); + ret = xmlXPathNewNodeSet(val); + if (ret == NULL) + xmlXPathPErrMemory(pctxt); + return(ret); }
/** * xmlXPathCacheNewString: - * @ctxt: the XPath context + * @pctxt the XPath context * @val: the xmlChar * value * * This is the cached version of xmlXPathNewString(). @@ -1966,58 +1805,43 @@ xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val) * Returns the created or reused object. */ static xmlXPathObjectPtr -xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val) +xmlXPathCacheNewString(xmlXPathParserContextPtr pctxt, const xmlChar *val) { - if ((ctxt != NULL) && (ctxt->cache)) { - xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; - - if ((cache->stringObjs != NULL) && - (cache->stringObjs->number != 0)) - { - xmlXPathObjectPtr ret; - xmlChar *copy; + xmlXPathObjectPtr ret; + xmlXPathContextPtr ctxt = pctxt->context;
- if (val == NULL) - val = BAD_CAST ""; - copy = xmlStrdup(val); - if (copy == NULL) { - xmlXPathErrMemory(ctxt, NULL); - return(NULL); - } + if ((ctxt != NULL) && (ctxt->cache != NULL)) { + xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
- ret = (xmlXPathObjectPtr) - cache->stringObjs->items[--cache->stringObjs->number]; - ret->type = XPATH_STRING; - ret->stringval = copy; - return(ret); - } else if ((cache->miscObjs != NULL) && - (cache->miscObjs->number != 0)) - { - xmlXPathObjectPtr ret; + if (cache->miscObjs != NULL) { xmlChar *copy;
if (val == NULL) val = BAD_CAST ""; copy = xmlStrdup(val); if (copy == NULL) { - xmlXPathErrMemory(ctxt, NULL); + xmlXPathPErrMemory(pctxt); return(NULL); }
- ret = (xmlXPathObjectPtr) - cache->miscObjs->items[--cache->miscObjs->number]; - + ret = cache->miscObjs; + cache->miscObjs = (void *) ret->stringval; + cache->numMisc -= 1; ret->type = XPATH_STRING; ret->stringval = copy; return(ret); } } - return(xmlXPathNewString(val)); + + ret = xmlXPathNewString(val); + if (ret == NULL) + xmlXPathPErrMemory(pctxt); + return(ret); }
/** * xmlXPathCacheNewCString: - * @ctxt: the XPath context + * @pctxt the XPath context * @val: the char * value * * This is the cached version of xmlXPathNewCString(). @@ -2026,14 +1850,14 @@ xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val) * Returns the created or reused object. */ static xmlXPathObjectPtr -xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val) +xmlXPathCacheNewCString(xmlXPathParserContextPtr pctxt, const char *val) { - return xmlXPathCacheNewString(ctxt, BAD_CAST val); + return xmlXPathCacheNewString(pctxt, BAD_CAST val); }
/** * xmlXPathCacheNewBoolean: - * @ctxt: the XPath context + * @pctxt the XPath context * @val: the boolean value * * This is the cached version of xmlXPathNewBoolean(). @@ -2042,40 +1866,34 @@ xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val) * Returns the created or reused object. */ static xmlXPathObjectPtr -xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val) +xmlXPathCacheNewBoolean(xmlXPathParserContextPtr pctxt, int val) { - if ((ctxt != NULL) && (ctxt->cache)) { - xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; - - if ((cache->booleanObjs != NULL) && - (cache->booleanObjs->number != 0)) - { - xmlXPathObjectPtr ret; - - ret = (xmlXPathObjectPtr) - cache->booleanObjs->items[--cache->booleanObjs->number]; - ret->type = XPATH_BOOLEAN; - ret->boolval = (val != 0); - return(ret); - } else if ((cache->miscObjs != NULL) && - (cache->miscObjs->number != 0)) - { - xmlXPathObjectPtr ret; + xmlXPathObjectPtr ret; + xmlXPathContextPtr ctxt = pctxt->context;
- ret = (xmlXPathObjectPtr) - cache->miscObjs->items[--cache->miscObjs->number]; + if ((ctxt != NULL) && (ctxt->cache != NULL)) { + xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
+ if (cache->miscObjs != NULL) { + ret = cache->miscObjs; + cache->miscObjs = (void *) ret->stringval; + cache->numMisc -= 1; + ret->stringval = NULL; ret->type = XPATH_BOOLEAN; ret->boolval = (val != 0); return(ret); } } - return(xmlXPathNewBoolean(val)); + + ret = xmlXPathNewBoolean(val); + if (ret == NULL) + xmlXPathPErrMemory(pctxt); + return(ret); }
/** * xmlXPathCacheNewFloat: - * @ctxt: the XPath context + * @pctxt the XPath context * @val: the double value * * This is the cached version of xmlXPathNewFloat(). @@ -2084,89 +1902,34 @@ xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val) * Returns the created or reused object. */ static xmlXPathObjectPtr -xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val) +xmlXPathCacheNewFloat(xmlXPathParserContextPtr pctxt, double val) { - if ((ctxt != NULL) && (ctxt->cache)) { - xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; - - if ((cache->numberObjs != NULL) && - (cache->numberObjs->number != 0)) - { - xmlXPathObjectPtr ret; - - ret = (xmlXPathObjectPtr) - cache->numberObjs->items[--cache->numberObjs->number]; - ret->type = XPATH_NUMBER; - ret->floatval = val; - return(ret); - } else if ((cache->miscObjs != NULL) && - (cache->miscObjs->number != 0)) - { - xmlXPathObjectPtr ret; + xmlXPathObjectPtr ret; + xmlXPathContextPtr ctxt = pctxt->context;
- ret = (xmlXPathObjectPtr) - cache->miscObjs->items[--cache->miscObjs->number]; + if ((ctxt != NULL) && (ctxt->cache != NULL)) { + xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
+ if (cache->miscObjs != NULL) { + ret = cache->miscObjs; + cache->miscObjs = (void *) ret->stringval; + cache->numMisc -= 1; + ret->stringval = NULL; ret->type = XPATH_NUMBER; ret->floatval = val; return(ret); } } - return(xmlXPathNewFloat(val)); -} - -/** - * xmlXPathCacheConvertString: - * @ctxt: the XPath context - * @val: an XPath object - * - * This is the cached version of xmlXPathConvertString(). - * Converts an existing object to its string() equivalent - * - * Returns a created or reused object, the old one is freed (cached) - * (or the operation is done directly on @val) - */ - -static xmlXPathObjectPtr -xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { - xmlChar *res = NULL;
- if (val == NULL) - return(xmlXPathCacheNewCString(ctxt, "")); - - switch (val->type) { - case XPATH_UNDEFINED: - break; - case XPATH_NODESET: - case XPATH_XSLT_TREE: - res = xmlXPathCastNodeSetToString(val->nodesetval); - break; - case XPATH_STRING: - return(val); - case XPATH_BOOLEAN: - res = xmlXPathCastBooleanToString(val->boolval); - break; - case XPATH_NUMBER: - res = xmlXPathCastNumberToString(val->floatval); - break; - case XPATH_USERS: -#ifdef LIBXML_XPTR_LOCS_ENABLED - case XPATH_POINT: - case XPATH_RANGE: - case XPATH_LOCATIONSET: -#endif /* LIBXML_XPTR_LOCS_ENABLED */ - TODO; - break; - } - xmlXPathReleaseObject(ctxt, val); - if (res == NULL) - return(xmlXPathCacheNewCString(ctxt, "")); - return(xmlXPathCacheWrapString(ctxt, res)); + ret = xmlXPathNewFloat(val); + if (ret == NULL) + xmlXPathPErrMemory(pctxt); + return(ret); }
/** * xmlXPathCacheObjectCopy: - * @ctxt: the XPath context + * @pctxt the XPath context * @val: the original object * * This is the cached version of xmlXPathObjectCopy(). @@ -2175,83 +1938,104 @@ xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { * Returns a created or reused created object. */ static xmlXPathObjectPtr -xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) +xmlXPathCacheObjectCopy(xmlXPathParserContextPtr pctxt, xmlXPathObjectPtr val) { + xmlXPathObjectPtr ret; + xmlXPathContextPtr ctxt = pctxt->context; + if (val == NULL) return(NULL);
- if (XP_HAS_CACHE(ctxt)) { + if ((ctxt != NULL) && (ctxt->cache != NULL)) { switch (val->type) { - case XPATH_NODESET: - return(xmlXPathCacheWrapNodeSet(ctxt, - xmlXPathNodeSetMerge(NULL, val->nodesetval))); + case XPATH_NODESET: { + xmlNodeSetPtr set; + + set = xmlXPathNodeSetMerge(NULL, val->nodesetval); + if (set == NULL) { + xmlXPathPErrMemory(pctxt); + return(NULL); + } + return(xmlXPathCacheWrapNodeSet(pctxt, set)); + } case XPATH_STRING: - return(xmlXPathCacheNewString(ctxt, val->stringval)); + return(xmlXPathCacheNewString(pctxt, val->stringval)); case XPATH_BOOLEAN: - return(xmlXPathCacheNewBoolean(ctxt, val->boolval)); + return(xmlXPathCacheNewBoolean(pctxt, val->boolval)); case XPATH_NUMBER: - return(xmlXPathCacheNewFloat(ctxt, val->floatval)); + return(xmlXPathCacheNewFloat(pctxt, val->floatval)); default: break; } } - return(xmlXPathObjectCopy(val)); -} - -/** - * xmlXPathCacheConvertBoolean: - * @ctxt: the XPath context - * @val: an XPath object - * - * This is the cached version of xmlXPathConvertBoolean(). - * Converts an existing object to its boolean() equivalent - * - * Returns a created or reused object, the old one is freed (or the operation - * is done directly on @val) - */ -static xmlXPathObjectPtr -xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { - xmlXPathObjectPtr ret; - - if (val == NULL) - return(xmlXPathCacheNewBoolean(ctxt, 0)); - if (val->type == XPATH_BOOLEAN) - return(val); - ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val)); - xmlXPathReleaseObject(ctxt, val); + ret = xmlXPathObjectCopy(val); + if (ret == NULL) + xmlXPathPErrMemory(pctxt); return(ret); }
+/************************************************************************ + * * + * Parser stacks related functions and macros * + * * + ************************************************************************/ + /** - * xmlXPathCacheConvertNumber: - * @ctxt: the XPath context + * xmlXPathCastToNumberInternal: + * @ctxt: parser context * @val: an XPath object * - * This is the cached version of xmlXPathConvertNumber(). - * Converts an existing object to its number() equivalent + * Converts an XPath object to its number value * - * Returns a created or reused object, the old one is freed (or the operation - * is done directly on @val) + * Returns the number value */ -static xmlXPathObjectPtr -xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { - xmlXPathObjectPtr ret; +static double +xmlXPathCastToNumberInternal(xmlXPathParserContextPtr ctxt, + xmlXPathObjectPtr val) { + double ret = 0.0;
if (val == NULL) - return(xmlXPathCacheNewFloat(ctxt, 0.0)); - if (val->type == XPATH_NUMBER) - return(val); - ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val)); - xmlXPathReleaseObject(ctxt, val); + return(xmlXPathNAN); + switch (val->type) { + case XPATH_UNDEFINED: + ret = xmlXPathNAN; + break; + case XPATH_NODESET: + case XPATH_XSLT_TREE: { + xmlChar *str; + + str = xmlXPathCastNodeSetToString(val->nodesetval); + if (str == NULL) { + xmlXPathPErrMemory(ctxt); + ret = xmlXPathNAN; + } else { + ret = xmlXPathCastStringToNumber(str); + xmlFree(str); + } + break; + } + case XPATH_STRING: + ret = xmlXPathCastStringToNumber(val->stringval); + break; + case XPATH_NUMBER: + ret = val->floatval; + break; + case XPATH_BOOLEAN: + ret = xmlXPathCastBooleanToNumber(val->boolval); + break; + case XPATH_USERS: +#ifdef LIBXML_XPTR_LOCS_ENABLED + case XPATH_POINT: + case XPATH_RANGE: + case XPATH_LOCATIONSET: +#endif /* LIBXML_XPTR_LOCS_ENABLED */ + /* TODO */ + ret = xmlXPathNAN; + break; + } return(ret); }
-/************************************************************************ - * * - * Parser stacks related functions and macros * - * * - ************************************************************************/ - /** * valuePop: * @ctxt: an XPath evaluation context @@ -2295,17 +2079,16 @@ valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value) if (ctxt == NULL) return(-1); if (value == NULL) { /* - * A NULL value typically indicates that a memory allocation failed, - * so we set ctxt->error here to propagate the error. + * A NULL value typically indicates that a memory allocation failed. */ - ctxt->error = XPATH_MEMORY_ERROR; + xmlXPathPErrMemory(ctxt); return(-1); } if (ctxt->valueNr >= ctxt->valueMax) { xmlXPathObjectPtr *tmp;
if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) { - xmlXPathPErrMemory(ctxt, "XPath stack depth limit reached\n"); + xmlXPathPErrMemory(ctxt); xmlXPathFreeObject(value); return (-1); } @@ -2313,7 +2096,7 @@ valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value) 2 * ctxt->valueMax * sizeof(ctxt->valueTab[0])); if (tmp == NULL) { - xmlXPathPErrMemory(ctxt, "pushing value\n"); + xmlXPathPErrMemory(ctxt); xmlXPathFreeObject(value); return (-1); } @@ -2372,7 +2155,7 @@ xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) { return(0); } if (obj->type != XPATH_NUMBER) - ret = xmlXPathCastToNumber(obj); + ret = xmlXPathCastToNumberInternal(ctxt, obj); else ret = obj->floatval; xmlXPathReleaseObject(ctxt->context, obj); @@ -2398,10 +2181,9 @@ xmlXPathPopString (xmlXPathParserContextPtr ctxt) { xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); return(NULL); } - ret = xmlXPathCastToString(obj); /* this does required strdup */ - /* TODO: needs refactoring somewhere else */ - if (obj->stringval == ret) - obj->stringval = NULL; + ret = xmlXPathCastToString(obj); + if (ret == NULL) + xmlXPathPErrMemory(ctxt); xmlXPathReleaseObject(ctxt->context, obj); return(ret); } @@ -2644,9 +2426,7 @@ xmlXPathFormatNumber(double number, char buffer[], int buffersize) /* Finally copy result back to caller */ size = strlen(work) + 1; if (size > buffersize) { -#if 0 /* avoid compiler warning */ work[buffersize - 1] = 0; -#endif size = buffersize; } memmove(buffer, work, size); @@ -2932,16 +2712,25 @@ xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) { * Allocate a new Namespace and fill the fields. */ cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); - if (cur == NULL) { - xmlXPathErrMemory(NULL, "duplicating namespace\n"); + if (cur == NULL) return(NULL); - } memset(cur, 0, sizeof(xmlNs)); cur->type = XML_NAMESPACE_DECL; - if (ns->href != NULL) + if (ns->href != NULL) { cur->href = xmlStrdup(ns->href); - if (ns->prefix != NULL) + if (cur->href == NULL) { + xmlFree(cur); + return(NULL); + } + } + if (ns->prefix != NULL) { cur->prefix = xmlStrdup(ns->prefix); + if (cur->prefix == NULL) { + xmlFree((xmlChar *) cur->href); + xmlFree(cur); + return(NULL); + } + } cur->next = (xmlNsPtr) node; return((xmlNodePtr) cur); } @@ -2981,16 +2770,13 @@ xmlXPathNodeSetCreate(xmlNodePtr val) { xmlNodeSetPtr ret;
ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet)); - if (ret == NULL) { - xmlXPathErrMemory(NULL, "creating nodeset\n"); + if (ret == NULL) return(NULL); - } memset(ret, 0 , sizeof(xmlNodeSet)); if (val != NULL) { ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); if (ret->nodeTab == NULL) { - xmlXPathErrMemory(NULL, "creating nodeset\n"); xmlFree(ret); return(NULL); } @@ -3087,26 +2873,20 @@ xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) { if (cur->nodeMax == 0) { cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); - if (cur->nodeTab == NULL) { - xmlXPathErrMemory(NULL, "growing nodeset\n"); + if (cur->nodeTab == NULL) return(-1); - } memset(cur->nodeTab, 0 , XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); cur->nodeMax = XML_NODESET_DEFAULT; } else if (cur->nodeNr == cur->nodeMax) { xmlNodePtr *temp;
- if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) { - xmlXPathErrMemory(NULL, "growing nodeset hit limit\n"); + if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) return(-1); - } temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 * sizeof(xmlNodePtr)); - if (temp == NULL) { - xmlXPathErrMemory(NULL, "growing nodeset\n"); + if (temp == NULL) return(-1); - } cur->nodeMax *= 2; cur->nodeTab = temp; } @@ -3145,26 +2925,20 @@ xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) { if (cur->nodeMax == 0) { cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); - if (cur->nodeTab == NULL) { - xmlXPathErrMemory(NULL, "growing nodeset\n"); + if (cur->nodeTab == NULL) return(-1); - } memset(cur->nodeTab, 0 , XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); cur->nodeMax = XML_NODESET_DEFAULT; } else if (cur->nodeNr == cur->nodeMax) { xmlNodePtr *temp;
- if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) { - xmlXPathErrMemory(NULL, "growing nodeset hit limit\n"); + if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) return(-1); - } temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 * sizeof(xmlNodePtr)); - if (temp == NULL) { - xmlXPathErrMemory(NULL, "growing nodeset\n"); + if (temp == NULL) return(-1); - } cur->nodeMax *= 2; cur->nodeTab = temp; } @@ -3201,26 +2975,20 @@ xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) { if (cur->nodeMax == 0) { cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); - if (cur->nodeTab == NULL) { - xmlXPathErrMemory(NULL, "growing nodeset\n"); + if (cur->nodeTab == NULL) return(-1); - } memset(cur->nodeTab, 0 , XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); cur->nodeMax = XML_NODESET_DEFAULT; } else if (cur->nodeNr == cur->nodeMax) { xmlNodePtr *temp;
- if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) { - xmlXPathErrMemory(NULL, "growing nodeset hit limit\n"); + if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) return(-1); - } temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 * sizeof(xmlNodePtr)); - if (temp == NULL) { - xmlXPathErrMemory(NULL, "growing nodeset\n"); + if (temp == NULL) return(-1); - } cur->nodeTab = temp; cur->nodeMax *= 2; } @@ -3253,12 +3021,13 @@ xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) { int i, j, initNr, skip; xmlNodePtr n1, n2;
- if (val2 == NULL) return(val1); if (val1 == NULL) { val1 = xmlXPathNodeSetCreate(NULL); if (val1 == NULL) return (NULL); } + if (val2 == NULL) + return(val1);
/* @@ with_ns to check whether namespace nodes should be looked at @@ */ initNr = val1->nodeNr; @@ -3294,26 +3063,20 @@ xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) { if (val1->nodeMax == 0) { val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); - if (val1->nodeTab == NULL) { - xmlXPathErrMemory(NULL, "merging nodeset\n"); + if (val1->nodeTab == NULL) goto error; - } memset(val1->nodeTab, 0 , XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); val1->nodeMax = XML_NODESET_DEFAULT; } else if (val1->nodeNr == val1->nodeMax) { xmlNodePtr *temp;
- if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) { - xmlXPathErrMemory(NULL, "merging nodeset hit limit\n"); + if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) goto error; - } temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 * sizeof(xmlNodePtr)); - if (temp == NULL) { - xmlXPathErrMemory(NULL, "merging nodeset\n"); + if (temp == NULL) goto error; - } val1->nodeTab = temp; val1->nodeMax *= 2; } @@ -3386,26 +3149,20 @@ xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2) if (set1->nodeMax == 0) { set1->nodeTab = (xmlNodePtr *) xmlMalloc( XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); - if (set1->nodeTab == NULL) { - xmlXPathErrMemory(NULL, "merging nodeset\n"); + if (set1->nodeTab == NULL) goto error; - } memset(set1->nodeTab, 0, XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); set1->nodeMax = XML_NODESET_DEFAULT; } else if (set1->nodeNr >= set1->nodeMax) { xmlNodePtr *temp;
- if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) { - xmlXPathErrMemory(NULL, "merging nodeset hit limit\n"); + if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) goto error; - } temp = (xmlNodePtr *) xmlRealloc( set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr)); - if (temp == NULL) { - xmlXPathErrMemory(NULL, "merging nodeset\n"); + if (temp == NULL) goto error; - } set1->nodeTab = temp; set1->nodeMax *= 2; } @@ -3447,26 +3204,20 @@ xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2) if (set1->nodeMax == 0) { set1->nodeTab = (xmlNodePtr *) xmlMalloc( XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); - if (set1->nodeTab == NULL) { - xmlXPathErrMemory(NULL, "merging nodeset\n"); + if (set1->nodeTab == NULL) goto error; - } memset(set1->nodeTab, 0, XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); set1->nodeMax = XML_NODESET_DEFAULT; } else if (set1->nodeNr >= set1->nodeMax) { xmlNodePtr *temp;
- if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) { - xmlXPathErrMemory(NULL, "merging nodeset hit limit\n"); + if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) goto error; - } temp = (xmlNodePtr *) xmlRealloc( set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr)); - if (temp == NULL) { - xmlXPathErrMemory(NULL, "merging nodeset\n"); + if (temp == NULL) goto error; - } set1->nodeTab = temp; set1->nodeMax *= 2; } @@ -3625,34 +3376,6 @@ xmlXPathNodeSetKeepLast(xmlNodeSetPtr set) set->nodeNr = 1; }
-/** - * xmlXPathFreeValueTree: - * @obj: the xmlNodeSetPtr to free - * - * Free the NodeSet compound and the actual tree, this is different - * from xmlXPathFreeNodeSet() - */ -static void -xmlXPathFreeValueTree(xmlNodeSetPtr obj) { - int i; - - if (obj == NULL) return; - - if (obj->nodeTab != NULL) { - for (i = 0;i < obj->nodeNr;i++) { - if (obj->nodeTab[i] != NULL) { - if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) { - xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]); - } else { - xmlFreeNodeList(obj->nodeTab[i]); - } - } - } - xmlFree(obj->nodeTab); - } - xmlFree(obj); -} - /** * xmlXPathNewNodeSet: * @val: the NodePtr value @@ -3667,15 +3390,16 @@ xmlXPathNewNodeSet(xmlNodePtr val) { xmlXPathObjectPtr ret;
ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); - if (ret == NULL) { - xmlXPathErrMemory(NULL, "creating nodeset\n"); + if (ret == NULL) return(NULL); - } memset(ret, 0 , sizeof(xmlXPathObject)); ret->type = XPATH_NODESET; ret->boolval = 0; - /* TODO: Check memory error. */ ret->nodesetval = xmlXPathNodeSetCreate(val); + if (ret->nodesetval == NULL) { + xmlFree(ret); + return(NULL); + } /* @@ with_ns to check whether namespace nodes should be looked at @@ */ return(ret); } @@ -3693,16 +3417,11 @@ xmlXPathObjectPtr xmlXPathNewValueTree(xmlNodePtr val) { xmlXPathObjectPtr ret;
- ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); - if (ret == NULL) { - xmlXPathErrMemory(NULL, "creating result value tree\n"); + ret = xmlXPathNewNodeSet(val); + if (ret == NULL) return(NULL); - } - memset(ret, 0 , sizeof(xmlXPathObject)); ret->type = XPATH_XSLT_TREE; - ret->boolval = 1; - ret->user = (void *) val; - ret->nodesetval = xmlXPathNodeSetCreate(val); + return(ret); }
@@ -3719,7 +3438,6 @@ xmlXPathObjectPtr xmlXPathNewNodeSetList(xmlNodeSetPtr val) { xmlXPathObjectPtr ret; - int i;
if (val == NULL) ret = NULL; @@ -3728,12 +3446,12 @@ xmlXPathNewNodeSetList(xmlNodeSetPtr val) else { ret = xmlXPathNewNodeSet(val->nodeTab[0]); if (ret) { - for (i = 1; i < val->nodeNr; ++i) { - /* TODO: Propagate memory error. */ - if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]) - < 0) break; - } - } + ret->nodesetval = xmlXPathNodeSetMerge(NULL, val); + if (ret->nodesetval == NULL) { + xmlFree(ret); + return(NULL); + } + } }
return (ret); @@ -3755,7 +3473,6 @@ xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); if (ret == NULL) { - xmlXPathErrMemory(NULL, "creating node set object\n"); xmlXPathFreeNodeSet(val); return(NULL); } @@ -3798,8 +3515,9 @@ xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { if (xmlXPathNodeSetIsEmpty(nodes2)) return(nodes1);
- /* TODO: Check memory error. */ ret = xmlXPathNodeSetCreate(NULL); + if (ret == NULL) + return(NULL); if (xmlXPathNodeSetIsEmpty(nodes1)) return(ret);
@@ -3808,9 +3526,10 @@ xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { for (i = 0; i < l1; i++) { cur = xmlXPathNodeSetItem(nodes1, i); if (!xmlXPathNodeSetContains(nodes2, cur)) { - /* TODO: Propagate memory error. */ - if (xmlXPathNodeSetAddUnique(ret, cur) < 0) - break; + if (xmlXPathNodeSetAddUnique(ret, cur) < 0) { + xmlXPathFreeNodeSet(ret); + return(NULL); + } } } return(ret); @@ -3845,9 +3564,10 @@ xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { for (i = 0; i < l1; i++) { cur = xmlXPathNodeSetItem(nodes1, i); if (xmlXPathNodeSetContains(nodes2, cur)) { - /* TODO: Propagate memory error. */ - if (xmlXPathNodeSetAddUnique(ret, cur) < 0) - break; + if (xmlXPathNodeSetAddUnique(ret, cur) < 0) { + xmlXPathFreeNodeSet(ret); + return(NULL); + } } } return(ret); @@ -3985,9 +3705,10 @@ xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) { cur = xmlXPathNodeSetItem(nodes, i); if (cur == node) break; - /* TODO: Propagate memory error. */ - if (xmlXPathNodeSetAddUnique(ret, cur) < 0) - break; + if (xmlXPathNodeSetAddUnique(ret, cur) < 0) { + xmlXPathFreeNodeSet(ret); + return(NULL); + } } return(ret); } @@ -4091,9 +3812,10 @@ xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) { cur = xmlXPathNodeSetItem(nodes, i); if (cur == node) break; - /* TODO: Propagate memory error. */ - if (xmlXPathNodeSetAddUnique(ret, cur) < 0) - break; + if (xmlXPathNodeSetAddUnique(ret, cur) < 0) { + xmlXPathFreeNodeSet(ret); + return(NULL); + } } xmlXPathNodeSetSort(ret); /* bug 413451 */ return(ret); @@ -4201,6 +3923,8 @@ xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name, int xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name, const xmlChar *ns_uri, xmlXPathFunction f) { + int ret; + if (ctxt == NULL) return(-1); if (name == NULL) @@ -4208,13 +3932,21 @@ xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
if (ctxt->funcHash == NULL) ctxt->funcHash = xmlHashCreate(0); - if (ctxt->funcHash == NULL) + if (ctxt->funcHash == NULL) { + xmlXPathErrMemory(ctxt); return(-1); + } if (f == NULL) return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL)); XML_IGNORE_FPTR_CAST_WARNINGS - return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f)); + ret = xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f); XML_POP_WARNINGS + if (ret < 0) { + xmlXPathErrMemory(ctxt); + return(-1); + } + + return(0); }
/** @@ -4443,8 +4175,7 @@ xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name, if (name == NULL) return(NULL);
- return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr) - xmlHashLookup2(ctxt->varHash, name, ns_uri))); + return(xmlXPathObjectCopy(xmlHashLookup2(ctxt->varHash, name, ns_uri))); }
/** @@ -4487,17 +4218,22 @@ xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
if (ctxt->nsHash == NULL) ctxt->nsHash = xmlHashCreate(10); - if (ctxt->nsHash == NULL) + if (ctxt->nsHash == NULL) { + xmlXPathErrMemory(ctxt); return(-1); + } if (ns_uri == NULL) return(xmlHashRemoveEntry(ctxt->nsHash, prefix, xmlHashDefaultDeallocator));
copy = xmlStrdup(ns_uri); - if (copy == NULL) + if (copy == NULL) { + xmlXPathErrMemory(ctxt); return(-1); + } if (xmlHashUpdateEntry(ctxt->nsHash, prefix, copy, xmlHashDefaultDeallocator) < 0) { + xmlXPathErrMemory(ctxt); xmlFree(copy); return(-1); } @@ -4522,10 +4258,8 @@ xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) { if (prefix == NULL) return(NULL);
-#ifdef XML_XML_NAMESPACE if (xmlStrEqual(prefix, (const xmlChar *) "xml")) return(XML_XML_NAMESPACE); -#endif
if (ctxt->namespaces != NULL) { int i; @@ -4576,10 +4310,8 @@ xmlXPathNewFloat(double val) { xmlXPathObjectPtr ret;
ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); - if (ret == NULL) { - xmlXPathErrMemory(NULL, "creating float object\n"); + if (ret == NULL) return(NULL); - } memset(ret, 0 , sizeof(xmlXPathObject)); ret->type = XPATH_NUMBER; ret->floatval = val; @@ -4599,10 +4331,8 @@ xmlXPathNewBoolean(int val) { xmlXPathObjectPtr ret;
ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); - if (ret == NULL) { - xmlXPathErrMemory(NULL, "creating boolean object\n"); + if (ret == NULL) return(NULL); - } memset(ret, 0 , sizeof(xmlXPathObject)); ret->type = XPATH_BOOLEAN; ret->boolval = (val != 0); @@ -4622,10 +4352,8 @@ xmlXPathNewString(const xmlChar *val) { xmlXPathObjectPtr ret;
ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); - if (ret == NULL) { - xmlXPathErrMemory(NULL, "creating string object\n"); + if (ret == NULL) return(NULL); - } memset(ret, 0 , sizeof(xmlXPathObject)); ret->type = XPATH_STRING; if (val == NULL) @@ -4654,7 +4382,6 @@ xmlXPathWrapString (xmlChar *val) {
ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); if (ret == NULL) { - xmlXPathErrMemory(NULL, "creating string object\n"); xmlFree(val); return(NULL); } @@ -4703,10 +4430,8 @@ xmlXPathWrapExternal (void *val) { xmlXPathObjectPtr ret;
ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); - if (ret == NULL) { - xmlXPathErrMemory(NULL, "creating user object\n"); + if (ret == NULL) return(NULL); - } memset(ret, 0 , sizeof(xmlXPathObject)); ret->type = XPATH_USERS; ret->user = val; @@ -4729,10 +4454,8 @@ xmlXPathObjectCopy(xmlXPathObjectPtr val) { return(NULL);
ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); - if (ret == NULL) { - xmlXPathErrMemory(NULL, "copying object\n"); + if (ret == NULL) return(NULL); - } memcpy(ret, val , sizeof(xmlXPathObject)); switch (val->type) { case XPATH_BOOLEAN: @@ -4783,8 +4506,11 @@ xmlXPathObjectCopy(xmlXPathObjectPtr val) { break; #endif case XPATH_NODESET: - /* TODO: Check memory error. */ ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval); + if (ret->nodesetval == NULL) { + xmlFree(ret); + return(NULL); + } /* Do not deallocate the copied tree value */ ret->boolval = 0; break; @@ -4799,10 +4525,9 @@ xmlXPathObjectCopy(xmlXPathObjectPtr val) { case XPATH_USERS: ret->user = val->user; break; - case XPATH_UNDEFINED: - xmlGenericError(xmlGenericErrorContext, - "xmlXPathObjectCopy: unsupported type %d\n", - val->type); + default: + xmlFree(ret); + ret = NULL; break; } return(ret); @@ -4818,20 +4543,8 @@ void xmlXPathFreeObject(xmlXPathObjectPtr obj) { if (obj == NULL) return; if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) { - if (obj->boolval) { -#if 0 - if (obj->user != NULL) { - xmlXPathFreeNodeSet(obj->nodesetval); - xmlFreeNodeList((xmlNodePtr) obj->user); - } else -#endif - obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */ - if (obj->nodesetval != NULL) - xmlXPathFreeValueTree(obj->nodesetval); - } else { - if (obj->nodesetval != NULL) - xmlXPathFreeNodeSet(obj->nodesetval); - } + if (obj->nodesetval != NULL) + xmlXPathFreeNodeSet(obj->nodesetval); #ifdef LIBXML_XPTR_LOCS_ENABLED } else if (obj->type == XPATH_LOCATIONSET) { if (obj->user != NULL) @@ -4859,12 +4572,6 @@ xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) { static void xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj) { -#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \ - sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \ - if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj; - -#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n)) - if (obj == NULL) return; if ((ctxt == NULL) || (ctxt->cache == NULL)) { @@ -4877,20 +4584,11 @@ xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj) case XPATH_NODESET: case XPATH_XSLT_TREE: if (obj->nodesetval != NULL) { - if (obj->boolval) { - /* - * It looks like the @boolval is used for - * evaluation if this an XSLT Result Tree Fragment. - * TODO: Check if this assumption is correct. - */ - obj->type = XPATH_XSLT_TREE; /* just for debugging */ - xmlXPathFreeValueTree(obj->nodesetval); - obj->nodesetval = NULL; - } else if ((obj->nodesetval->nodeMax <= 40) && - (XP_CACHE_WANTS(cache->nodesetObjs, - cache->maxNodeset))) - { - XP_CACHE_ADD(cache->nodesetObjs, obj); + if ((obj->nodesetval->nodeMax <= 40) && + (cache->numNodeset < cache->maxNodeset)) { + obj->stringval = (void *) cache->nodesetObjs; + cache->nodesetObjs = obj; + cache->numNodeset += 1; goto obj_cached; } else { xmlXPathFreeNodeSet(obj->nodesetval); @@ -4901,23 +4599,10 @@ xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj) case XPATH_STRING: if (obj->stringval != NULL) xmlFree(obj->stringval); - - if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) { - XP_CACHE_ADD(cache->stringObjs, obj); - goto obj_cached; - } + obj->stringval = NULL; break; case XPATH_BOOLEAN: - if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) { - XP_CACHE_ADD(cache->booleanObjs, obj); - goto obj_cached; - } - break; case XPATH_NUMBER: - if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) { - XP_CACHE_ADD(cache->numberObjs, obj); - goto obj_cached; - } break; #ifdef LIBXML_XPTR_LOCS_ENABLED case XPATH_LOCATIONSET: @@ -4933,22 +4618,22 @@ xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj) /* * Fallback to adding to the misc-objects slot. */ - if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) { - XP_CACHE_ADD(cache->miscObjs, obj); - } else + if (cache->numMisc >= cache->maxMisc) goto free_obj; + obj->stringval = (void *) cache->miscObjs; + cache->miscObjs = obj; + cache->numMisc += 1;
obj_cached: + obj->boolval = 0; if (obj->nodesetval != NULL) { xmlNodeSetPtr tmpset = obj->nodesetval;
/* - * TODO: Due to those nasty ns-nodes, we need to traverse - * the list and free the ns-nodes. - * URGENT TODO: Check if it's actually slowing things down. - * Maybe we shouldn't try to preserve the list. + * Due to those nasty ns-nodes, we need to traverse + * the list and free the ns-nodes. */ - if (tmpset->nodeNr > 1) { + if (tmpset->nodeNr > 0) { int i; xmlNodePtr node;
@@ -4960,16 +4645,9 @@ obj_cached: xmlXPathNodeSetFreeNs((xmlNsPtr) node); } } - } else if (tmpset->nodeNr == 1) { - if ((tmpset->nodeTab[0] != NULL) && - (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL)) - xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]); } tmpset->nodeNr = 0; - memset(obj, 0, sizeof(xmlXPathObject)); - obj->nodesetval = tmpset; - } else - memset(obj, 0, sizeof(xmlXPathObject)); + }
return;
@@ -5054,10 +4732,7 @@ xmlXPathCastNumberToString (double val) { */ xmlChar * xmlXPathCastNodeToString (xmlNodePtr node) { -xmlChar *ret; - if ((ret = xmlNodeGetContent(node)) == NULL) - ret = xmlStrdup((const xmlChar *) ""); - return(ret); + return(xmlNodeGetContent(node)); }
/** @@ -5116,7 +4791,7 @@ xmlXPathCastToString(xmlXPathObjectPtr val) { case XPATH_RANGE: case XPATH_LOCATIONSET: #endif /* LIBXML_XPTR_LOCS_ENABLED */ - TODO + /* TODO */ ret = xmlStrdup((const xmlChar *) ""); break; } @@ -5160,7 +4835,7 @@ xmlXPathConvertString(xmlXPathObjectPtr val) { case XPATH_RANGE: case XPATH_LOCATIONSET: #endif /* LIBXML_XPTR_LOCS_ENABLED */ - TODO; + /* TODO */ break; } xmlXPathFreeObject(val); @@ -5198,23 +4873,25 @@ xmlXPathCastStringToNumber(const xmlChar * val) { }
/** - * xmlXPathCastNodeToNumber: + * xmlXPathNodeToNumberInternal: * @node: a node * * Converts a node to its number value * * Returns the number value */ -double -xmlXPathCastNodeToNumber (xmlNodePtr node) { +static double +xmlXPathNodeToNumberInternal(xmlXPathParserContextPtr ctxt, xmlNodePtr node) { xmlChar *strval; double ret;
if (node == NULL) return(xmlXPathNAN); strval = xmlXPathCastNodeToString(node); - if (strval == NULL) + if (strval == NULL) { + xmlXPathPErrMemory(ctxt); return(xmlXPathNAN); + } ret = xmlXPathCastStringToNumber(strval); xmlFree(strval);
@@ -5222,70 +4899,52 @@ xmlXPathCastNodeToNumber (xmlNodePtr node) { }
/** - * xmlXPathCastNodeSetToNumber: - * @ns: a node-set + * xmlXPathCastNodeToNumber: + * @node: a node * - * Converts a node-set to its number value + * Converts a node to its number value * * Returns the number value */ double -xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) { - xmlChar *str; - double ret; - - if (ns == NULL) - return(xmlXPathNAN); - str = xmlXPathCastNodeSetToString(ns); - ret = xmlXPathCastStringToNumber(str); - xmlFree(str); - return(ret); +xmlXPathCastNodeToNumber (xmlNodePtr node) { + return(xmlXPathNodeToNumberInternal(NULL, node)); }
/** - * xmlXPathCastToNumber: - * @val: an XPath object + * xmlXPathCastNodeSetToNumber: + * @ns: a node-set * - * Converts an XPath object to its number value + * Converts a node-set to its number value * * Returns the number value */ double -xmlXPathCastToNumber(xmlXPathObjectPtr val) { - double ret = 0.0; +xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) { + xmlChar *str; + double ret;
- if (val == NULL) + if (ns == NULL) return(xmlXPathNAN); - switch (val->type) { - case XPATH_UNDEFINED: - ret = xmlXPathNAN; - break; - case XPATH_NODESET: - case XPATH_XSLT_TREE: - ret = xmlXPathCastNodeSetToNumber(val->nodesetval); - break; - case XPATH_STRING: - ret = xmlXPathCastStringToNumber(val->stringval); - break; - case XPATH_NUMBER: - ret = val->floatval; - break; - case XPATH_BOOLEAN: - ret = xmlXPathCastBooleanToNumber(val->boolval); - break; - case XPATH_USERS: -#ifdef LIBXML_XPTR_LOCS_ENABLED - case XPATH_POINT: - case XPATH_RANGE: - case XPATH_LOCATIONSET: -#endif /* LIBXML_XPTR_LOCS_ENABLED */ - TODO; - ret = xmlXPathNAN; - break; - } + str = xmlXPathCastNodeSetToString(ns); + ret = xmlXPathCastStringToNumber(str); + xmlFree(str); return(ret); }
+/** + * xmlXPathCastToNumber: + * @val: an XPath object + * + * Converts an XPath object to its number value + * + * Returns the number value + */ +double +xmlXPathCastToNumber(xmlXPathObjectPtr val) { + return(xmlXPathCastToNumberInternal(NULL, val)); +} + /** * xmlXPathConvertNumber: * @val: an XPath object @@ -5390,7 +5049,7 @@ xmlXPathCastToBoolean (xmlXPathObjectPtr val) { case XPATH_RANGE: case XPATH_LOCATIONSET: #endif /* LIBXML_XPTR_LOCS_ENABLED */ - TODO; + /* TODO */ ret = 0; break; } @@ -5439,10 +5098,8 @@ xmlXPathNewContext(xmlDocPtr doc) { xmlXPathContextPtr ret;
ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext)); - if (ret == NULL) { - xmlXPathErrMemory(NULL, "creating context\n"); + if (ret == NULL) return(NULL); - } memset(ret, 0 , sizeof(xmlXPathContext)); ret->doc = doc; ret->node = NULL; @@ -5453,8 +5110,6 @@ xmlXPathNewContext(xmlDocPtr doc) { ret->max_types = 0; ret->types = NULL;
- ret->funcHash = xmlHashCreate(0); - ret->nb_axis = 0; ret->max_axis = 0; ret->axis = NULL; @@ -5474,6 +5129,11 @@ xmlXPathNewContext(xmlDocPtr doc) {
xmlXPathRegisterAllFunctions(ret);
+ if (ret->lastError.code != XML_ERR_OK) { + xmlXPathFreeContext(ret); + return(NULL); + } + return(ret); }
@@ -5496,43 +5156,33 @@ xmlXPathFreeContext(xmlXPathContextPtr ctxt) { xmlFree(ctxt); }
+/** + * xmlXPathSetErrorHandler: + * @ctxt: the XPath context + * @handler: error handler + * @data: user data which will be passed to the handler + * + * Register a callback function that will be called on errors and + * warnings. If handler is NULL, the error handler will be deactivated. + * + * Available since 2.13.0. + */ +void +xmlXPathSetErrorHandler(xmlXPathContextPtr ctxt, + xmlStructuredErrorFunc handler, void *data) { + if (ctxt == NULL) + return; + + ctxt->error = handler; + ctxt->userData = data; +} + /************************************************************************ * * * Routines to handle XPath parser contexts * * * ************************************************************************/
-#define CHECK_CTXT(ctxt) \ - if (ctxt == NULL) { \ - __xmlRaiseError(NULL, NULL, NULL, \ - NULL, NULL, XML_FROM_XPATH, \ - XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \ - __FILE__, __LINE__, \ - NULL, NULL, NULL, 0, 0, \ - "NULL context pointer\n"); \ - return(NULL); \ - } \ - -#define CHECK_CTXT_NEG(ctxt) \ - if (ctxt == NULL) { \ - __xmlRaiseError(NULL, NULL, NULL, \ - NULL, NULL, XML_FROM_XPATH, \ - XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \ - __FILE__, __LINE__, \ - NULL, NULL, NULL, 0, 0, \ - "NULL context pointer\n"); \ - return(-1); \ - } \ - - -#define CHECK_CONTEXT(ctxt) \ - if ((ctxt == NULL) || (ctxt->doc == NULL) || \ - (ctxt->doc->children == NULL)) { \ - xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \ - return(NULL); \ - } - - /** * xmlXPathNewParserContext: * @str: the XPath expression @@ -5548,7 +5198,7 @@ xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext)); if (ret == NULL) { - xmlXPathErrMemory(ctxt, "creating parser context\n"); + xmlXPathErrMemory(ctxt); return(NULL); } memset(ret, 0 , sizeof(xmlXPathParserContext)); @@ -5557,6 +5207,7 @@ xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
ret->comp = xmlXPathNewCompExpr(); if (ret->comp == NULL) { + xmlXPathErrMemory(ctxt); xmlFree(ret->valueTab); xmlFree(ret); return(NULL); @@ -5584,7 +5235,7 @@ xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext)); if (ret == NULL) { - xmlXPathErrMemory(ctxt, "creating evaluation context\n"); + xmlXPathErrMemory(ctxt); return(NULL); } memset(ret, 0 , sizeof(xmlXPathParserContext)); @@ -5594,7 +5245,7 @@ xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) { xmlMalloc(10 * sizeof(xmlXPathObjectPtr)); if (ret->valueTab == NULL) { xmlFree(ret); - xmlXPathErrMemory(ctxt, "creating evaluation context\n"); + xmlXPathErrMemory(ctxt); return(NULL); } ret->valueNr = 0; @@ -5815,15 +5466,16 @@ xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict, for (i = 0;i < ns->nodeNr;i++) { str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); if (str2 != NULL) { - valuePush(ctxt, - xmlXPathCacheNewString(ctxt->context, str2)); + valuePush(ctxt, xmlXPathCacheNewString(ctxt, str2)); xmlFree(str2); xmlXPathNumberFunction(ctxt, 1); - valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f)); + valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, f)); ret = xmlXPathCompareValues(ctxt, inf, strict); if (ret) break; - } + } else { + xmlXPathPErrMemory(ctxt); + } } } xmlXPathReleaseObject(ctxt->context, arg); @@ -5871,13 +5523,15 @@ xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict, str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); if (str2 != NULL) { valuePush(ctxt, - xmlXPathCacheNewString(ctxt->context, str2)); + xmlXPathCacheNewString(ctxt, str2)); xmlFree(str2); - valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s)); + valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, s)); ret = xmlXPathCompareValues(ctxt, inf, strict); if (ret) break; - } + } else { + xmlXPathPErrMemory(ctxt); + } } } xmlXPathReleaseObject(ctxt->context, arg); @@ -5914,7 +5568,7 @@ xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict, * and then the comparison must be done when possible */ static int -xmlXPathCompareNodeSets(int inf, int strict, +xmlXPathCompareNodeSets(xmlXPathParserContextPtr ctxt, int inf, int strict, xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) { int i, j, init = 0; double val1; @@ -5951,19 +5605,19 @@ xmlXPathCompareNodeSets(int inf, int strict,
values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double)); if (values2 == NULL) { - /* TODO: Propagate memory error. */ - xmlXPathErrMemory(NULL, "comparing nodesets\n"); + xmlXPathPErrMemory(ctxt); xmlXPathFreeObject(arg1); xmlXPathFreeObject(arg2); return(0); } for (i = 0;i < ns1->nodeNr;i++) { - val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]); + val1 = xmlXPathNodeToNumberInternal(ctxt, ns1->nodeTab[i]); if (xmlXPathIsNaN(val1)) continue; for (j = 0;j < ns2->nodeNr;j++) { if (init == 0) { - values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]); + values2[j] = xmlXPathNodeToNumberInternal(ctxt, + ns2->nodeTab[j]); } if (xmlXPathIsNaN(values2[j])) continue; @@ -6021,7 +5675,7 @@ xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict, return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val)); case XPATH_NODESET: case XPATH_XSLT_TREE: - return(xmlXPathCompareNodeSets(inf, strict, arg, val)); + return(xmlXPathCompareNodeSets(ctxt, inf, strict, arg, val)); case XPATH_STRING: return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val)); case XPATH_BOOLEAN: @@ -6030,10 +5684,6 @@ xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict, valuePush(ctxt, val); return(xmlXPathCompareValues(ctxt, inf, strict)); default: - xmlGenericError(xmlGenericErrorContext, - "xmlXPathCompareNodeSetValue: Can't compare node set " - "and object of type %d\n", - val->type); xmlXPathReleaseObject(ctxt->context, arg); xmlXPathReleaseObject(ctxt->context, val); XP_ERROR0(XPATH_INVALID_TYPE); @@ -6056,7 +5706,8 @@ xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict, * Returns 0 or 1 depending on the results of the test. */ static int -xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq) +xmlXPathEqualNodeSetString(xmlXPathParserContextPtr ctxt, + xmlXPathObjectPtr arg, const xmlChar * str, int neq) { int i; xmlNodeSetPtr ns; @@ -6077,22 +5728,20 @@ xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq) for (i = 0; i < ns->nodeNr; i++) { if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) { str2 = xmlNodeGetContent(ns->nodeTab[i]); - if ((str2 != NULL) && (xmlStrEqual(str, str2))) { + if (str2 == NULL) { + xmlXPathPErrMemory(ctxt); + return(0); + } + if (xmlStrEqual(str, str2)) { xmlFree(str2); if (neq) continue; return (1); - } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) { - if (neq) - continue; - return (1); } else if (neq) { - if (str2 != NULL) - xmlFree(str2); + xmlFree(str2); return (1); } - if (str2 != NULL) - xmlFree(str2); + xmlFree(str2); } else if (neq) return (1); } @@ -6132,7 +5781,7 @@ xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt, for (i=0;i<ns->nodeNr;i++) { str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); if (str2 != NULL) { - valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2)); + valuePush(ctxt, xmlXPathCacheNewString(ctxt, str2)); xmlFree(str2); xmlXPathNumberFunction(ctxt, 1); CHECK_ERROR0; @@ -6151,7 +5800,9 @@ xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt, if (neq) ret = 1; } - } + } else { + xmlXPathPErrMemory(ctxt); + } } }
@@ -6177,7 +5828,8 @@ xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt, * Returns 0 or 1 depending on the results of the test. */ static int -xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) { +xmlXPathEqualNodeSets(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr arg1, + xmlXPathObjectPtr arg2, int neq) { int i, j; unsigned int *hashs1; unsigned int *hashs2; @@ -6213,30 +5865,26 @@ xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *)); if (values1 == NULL) { - /* TODO: Propagate memory error. */ - xmlXPathErrMemory(NULL, "comparing nodesets\n"); + xmlXPathPErrMemory(ctxt); return(0); } hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int)); if (hashs1 == NULL) { - /* TODO: Propagate memory error. */ - xmlXPathErrMemory(NULL, "comparing nodesets\n"); + xmlXPathPErrMemory(ctxt); xmlFree(values1); return(0); } memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *)); values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *)); if (values2 == NULL) { - /* TODO: Propagate memory error. */ - xmlXPathErrMemory(NULL, "comparing nodesets\n"); + xmlXPathPErrMemory(ctxt); xmlFree(hashs1); xmlFree(values1); return(0); } hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int)); if (hashs2 == NULL) { - /* TODO: Propagate memory error. */ - xmlXPathErrMemory(NULL, "comparing nodesets\n"); + xmlXPathPErrMemory(ctxt); xmlFree(hashs1); xmlFree(values1); xmlFree(values2); @@ -6255,10 +5903,16 @@ xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) { } } else { - if (values1[i] == NULL) + if (values1[i] == NULL) { values1[i] = xmlNodeGetContent(ns1->nodeTab[i]); - if (values2[j] == NULL) + if (values1[i] == NULL) + xmlXPathPErrMemory(ctxt); + } + if (values2[j] == NULL) { values2[j] = xmlNodeGetContent(ns2->nodeTab[j]); + if (values2[j] == NULL) + xmlXPathPErrMemory(ctxt); + } ret = xmlStrEqual(values1[i], values2[j]) ^ neq; if (ret) break; @@ -6315,7 +5969,7 @@ xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt, case XPATH_RANGE: case XPATH_LOCATIONSET: #endif /* LIBXML_XPTR_LOCS_ENABLED */ - TODO + /* TODO */ break; case XPATH_NODESET: case XPATH_XSLT_TREE: @@ -6372,7 +6026,7 @@ xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt, case XPATH_RANGE: case XPATH_LOCATIONSET: #endif /* LIBXML_XPTR_LOCS_ENABLED */ - TODO + /* TODO */ break; case XPATH_NODESET: case XPATH_XSLT_TREE: @@ -6433,7 +6087,7 @@ xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt, case XPATH_RANGE: case XPATH_LOCATIONSET: #endif /* LIBXML_XPTR_LOCS_ENABLED */ - TODO + /* TODO */ break; case XPATH_NODESET: case XPATH_XSLT_TREE: @@ -6446,7 +6100,7 @@ xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt, case XPATH_RANGE: case XPATH_LOCATIONSET: #endif /* LIBXML_XPTR_LOCS_ENABLED */ - TODO + /* TODO */ break; case XPATH_NODESET: case XPATH_XSLT_TREE: @@ -6504,7 +6158,7 @@ xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) { break; case XPATH_NODESET: case XPATH_XSLT_TREE: - ret = xmlXPathEqualNodeSets(arg1, arg2, 0); + ret = xmlXPathEqualNodeSets(ctxt, arg1, arg2, 0); break; case XPATH_BOOLEAN: if ((arg1->nodesetval == NULL) || @@ -6517,7 +6171,8 @@ xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) { ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0); break; case XPATH_STRING: - ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0); + ret = xmlXPathEqualNodeSetString(ctxt, arg1, + arg2->stringval, 0); break; case XPATH_USERS: #ifdef LIBXML_XPTR_LOCS_ENABLED @@ -6525,7 +6180,7 @@ xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) { case XPATH_RANGE: case XPATH_LOCATIONSET: #endif /* LIBXML_XPTR_LOCS_ENABLED */ - TODO + /* TODO */ break; } xmlXPathReleaseObject(ctxt->context, arg1); @@ -6583,7 +6238,7 @@ xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) { break; case XPATH_NODESET: case XPATH_XSLT_TREE: - ret = xmlXPathEqualNodeSets(arg1, arg2, 1); + ret = xmlXPathEqualNodeSets(ctxt, arg1, arg2, 1); break; case XPATH_BOOLEAN: if ((arg1->nodesetval == NULL) || @@ -6596,7 +6251,8 @@ xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) { ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1); break; case XPATH_STRING: - ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1); + ret = xmlXPathEqualNodeSetString(ctxt, arg1, + arg2->stringval, 1); break; case XPATH_USERS: #ifdef LIBXML_XPTR_LOCS_ENABLED @@ -6604,7 +6260,7 @@ xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) { case XPATH_RANGE: case XPATH_LOCATIONSET: #endif /* LIBXML_XPTR_LOCS_ENABLED */ - TODO + /* TODO */ break; } xmlXPathReleaseObject(ctxt->context, arg1); @@ -6664,7 +6320,7 @@ xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) { */ if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) && ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){ - ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2); + ret = xmlXPathCompareNodeSets(ctxt, inf, strict, arg1, arg2); } else { if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict, @@ -6776,7 +6432,7 @@ xmlXPathAddValues(xmlXPathParserContextPtr ctxt) { arg = valuePop(ctxt); if (arg == NULL) XP_ERROR(XPATH_INVALID_OPERAND); - val = xmlXPathCastToNumber(arg); + val = xmlXPathCastToNumberInternal(ctxt, arg); xmlXPathReleaseObject(ctxt->context, arg); CAST_TO_NUMBER; CHECK_TYPE(XPATH_NUMBER); @@ -6799,7 +6455,7 @@ xmlXPathSubValues(xmlXPathParserContextPtr ctxt) { arg = valuePop(ctxt); if (arg == NULL) XP_ERROR(XPATH_INVALID_OPERAND); - val = xmlXPathCastToNumber(arg); + val = xmlXPathCastToNumberInternal(ctxt, arg); xmlXPathReleaseObject(ctxt->context, arg); CAST_TO_NUMBER; CHECK_TYPE(XPATH_NUMBER); @@ -6822,7 +6478,7 @@ xmlXPathMultValues(xmlXPathParserContextPtr ctxt) { arg = valuePop(ctxt); if (arg == NULL) XP_ERROR(XPATH_INVALID_OPERAND); - val = xmlXPathCastToNumber(arg); + val = xmlXPathCastToNumberInternal(ctxt, arg); xmlXPathReleaseObject(ctxt->context, arg); CAST_TO_NUMBER; CHECK_TYPE(XPATH_NUMBER); @@ -6846,7 +6502,7 @@ xmlXPathDivValues(xmlXPathParserContextPtr ctxt) { arg = valuePop(ctxt); if (arg == NULL) XP_ERROR(XPATH_INVALID_OPERAND); - val = xmlXPathCastToNumber(arg); + val = xmlXPathCastToNumberInternal(ctxt, arg); xmlXPathReleaseObject(ctxt->context, arg); CAST_TO_NUMBER; CHECK_TYPE(XPATH_NUMBER); @@ -6869,7 +6525,7 @@ xmlXPathModValues(xmlXPathParserContextPtr ctxt) { arg = valuePop(ctxt); if (arg == NULL) XP_ERROR(XPATH_INVALID_OPERAND); - arg2 = xmlXPathCastToNumber(arg); + arg2 = xmlXPathCastToNumberInternal(ctxt, arg); xmlXPathReleaseObject(ctxt->context, arg); CAST_TO_NUMBER; CHECK_TYPE(XPATH_NUMBER); @@ -7673,14 +7329,17 @@ xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { if (cur == NULL) { if (ctxt->context->tmpNsList != NULL) xmlFree(ctxt->context->tmpNsList); - ctxt->context->tmpNsList = - xmlGetNsList(ctxt->context->doc, ctxt->context->node); ctxt->context->tmpNsNr = 0; - if (ctxt->context->tmpNsList != NULL) { - while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) { - ctxt->context->tmpNsNr++; - } - } + if (xmlGetNsListSafe(ctxt->context->doc, ctxt->context->node, + &ctxt->context->tmpNsList) < 0) { + xmlXPathPErrMemory(ctxt); + return(NULL); + } + if (ctxt->context->tmpNsList != NULL) { + while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) { + ctxt->context->tmpNsNr++; + } + } return((xmlNodePtr) xmlXPathXMLNamespace); } if (ctxt->context->tmpNsNr > 0) { @@ -7743,8 +7402,8 @@ void xmlXPathRoot(xmlXPathParserContextPtr ctxt) { if ((ctxt == NULL) || (ctxt->context == NULL)) return; - valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, - (xmlNodePtr) ctxt->context->doc)); + valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, + (xmlNodePtr) ctxt->context->doc)); }
/************************************************************************ @@ -7769,8 +7428,7 @@ xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) { CHECK_ARITY(0); if (ctxt->context->contextSize >= 0) { valuePush(ctxt, - xmlXPathCacheNewFloat(ctxt->context, - (double) ctxt->context->contextSize)); + xmlXPathCacheNewFloat(ctxt, (double) ctxt->context->contextSize)); } else { XP_ERROR(XPATH_INVALID_CTXT_SIZE); } @@ -7791,9 +7449,8 @@ void xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) { CHECK_ARITY(0); if (ctxt->context->proximityPosition >= 0) { - valuePush(ctxt, - xmlXPathCacheNewFloat(ctxt->context, - (double) ctxt->context->proximityPosition)); + valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, + (double) ctxt->context->proximityPosition)); } else { XP_ERROR(XPATH_INVALID_CTXT_POSITION); } @@ -7819,9 +7476,9 @@ xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) { cur = valuePop(ctxt);
if ((cur == NULL) || (cur->nodesetval == NULL)) - valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0)); + valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0.0)); else - valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, + valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, (double) cur->nodesetval->nodeNr)); xmlXPathReleaseObject(ctxt->context, cur); } @@ -7855,28 +7512,33 @@ xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) { cur++;
ID = xmlStrndup(ids, cur - ids); - if (ID != NULL) { - /* - * We used to check the fact that the value passed - * was an NCName, but this generated much troubles for - * me and Aleksey Sanin, people blatantly violated that - * constraint, like Visa3D spec. - * if (xmlValidateNCName(ID, 1) == 0) - */ - attr = xmlGetID(doc, ID); - if (attr != NULL) { - if (attr->type == XML_ATTRIBUTE_NODE) - elem = attr->parent; - else if (attr->type == XML_ELEMENT_NODE) - elem = (xmlNodePtr) attr; - else - elem = NULL; - /* TODO: Check memory error. */ - if (elem != NULL) - xmlXPathNodeSetAdd(ret, elem); - } - xmlFree(ID); - } + if (ID == NULL) { + xmlXPathFreeNodeSet(ret); + return(NULL); + } + /* + * We used to check the fact that the value passed + * was an NCName, but this generated much troubles for + * me and Aleksey Sanin, people blatantly violated that + * constraint, like Visa3D spec. + * if (xmlValidateNCName(ID, 1) == 0) + */ + attr = xmlGetID(doc, ID); + xmlFree(ID); + if (attr != NULL) { + if (attr->type == XML_ATTRIBUTE_NODE) + elem = attr->parent; + else if (attr->type == XML_ELEMENT_NODE) + elem = (xmlNodePtr) attr; + else + elem = NULL; + if (elem != NULL) { + if (xmlXPathNodeSetAdd(ret, elem) < 0) { + xmlXPathFreeNodeSet(ret); + return(NULL); + } + } + }
while (IS_BLANK_CH(*cur)) cur++; ids = cur; @@ -7915,30 +7577,40 @@ xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) { xmlNodeSetPtr ns; int i;
- /* TODO: Check memory error. */ ret = xmlXPathNodeSetCreate(NULL); + if (ret == NULL) + xmlXPathPErrMemory(ctxt);
if (obj->nodesetval != NULL) { for (i = 0; i < obj->nodesetval->nodeNr; i++) { tokens = xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]); + if (tokens == NULL) + xmlXPathPErrMemory(ctxt); ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens); - /* TODO: Check memory error. */ + if (ns == NULL) + xmlXPathPErrMemory(ctxt); ret = xmlXPathNodeSetMerge(ret, ns); + if (ret == NULL) + xmlXPathPErrMemory(ctxt); xmlXPathFreeNodeSet(ns); if (tokens != NULL) xmlFree(tokens); } } xmlXPathReleaseObject(ctxt->context, obj); - valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret)); + valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret)); return; } - obj = xmlXPathCacheConvertString(ctxt->context, obj); - if (obj == NULL) return; - ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval); - valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret)); + tokens = xmlXPathCastToString(obj); + if (tokens == NULL) + xmlXPathPErrMemory(ctxt); xmlXPathReleaseObject(ctxt->context, obj); + ret = xmlXPathGetElementsByIds(ctxt->context->doc, tokens); + if (ret == NULL) + xmlXPathPErrMemory(ctxt); + xmlFree(tokens); + valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret)); return; }
@@ -7962,8 +7634,7 @@ xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) { if (ctxt == NULL) return;
if (nargs == 0) { - valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, - ctxt->context->node)); + valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node)); nargs = 1; }
@@ -7975,7 +7646,7 @@ xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) { cur = valuePop(ctxt);
if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { - valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); + valuePush(ctxt, xmlXPathCacheNewCString(ctxt, "")); } else { int i = 0; /* Should be first in document order !!!!! */ switch (cur->nodesetval->nodeTab[i]->type) { @@ -7983,18 +7654,17 @@ xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) { case XML_ATTRIBUTE_NODE: case XML_PI_NODE: if (cur->nodesetval->nodeTab[i]->name[0] == ' ') - valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); + valuePush(ctxt, xmlXPathCacheNewCString(ctxt, "")); else - valuePush(ctxt, - xmlXPathCacheNewString(ctxt->context, + valuePush(ctxt, xmlXPathCacheNewString(ctxt, cur->nodesetval->nodeTab[i]->name)); break; case XML_NAMESPACE_DECL: - valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, + valuePush(ctxt, xmlXPathCacheNewString(ctxt, ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix)); break; default: - valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); + valuePush(ctxt, xmlXPathCacheNewCString(ctxt, "")); } } xmlXPathReleaseObject(ctxt->context, cur); @@ -8021,8 +7691,7 @@ xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) { if (ctxt == NULL) return;
if (nargs == 0) { - valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, - ctxt->context->node)); + valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node)); nargs = 1; } CHECK_ARITY(1); @@ -8033,20 +7702,20 @@ xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) { cur = valuePop(ctxt);
if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { - valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); + valuePush(ctxt, xmlXPathCacheNewCString(ctxt, "")); } else { int i = 0; /* Should be first in document order !!!!! */ switch (cur->nodesetval->nodeTab[i]->type) { case XML_ELEMENT_NODE: case XML_ATTRIBUTE_NODE: if (cur->nodesetval->nodeTab[i]->ns == NULL) - valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); + valuePush(ctxt, xmlXPathCacheNewCString(ctxt, "")); else - valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, + valuePush(ctxt, xmlXPathCacheNewString(ctxt, cur->nodesetval->nodeTab[i]->ns->href)); break; default: - valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); + valuePush(ctxt, xmlXPathCacheNewCString(ctxt, "")); } } xmlXPathReleaseObject(ctxt->context, cur); @@ -8080,8 +7749,7 @@ xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) xmlXPathObjectPtr cur;
if (nargs == 0) { - valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, - ctxt->context->node)); + valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node)); nargs = 1; }
@@ -8093,7 +7761,7 @@ xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) cur = valuePop(ctxt);
if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { - valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); + valuePush(ctxt, xmlXPathCacheNewCString(ctxt, "")); } else { int i = 0; /* Should be first in document order !!!!! */
@@ -8102,11 +7770,10 @@ xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) case XML_ATTRIBUTE_NODE: if (cur->nodesetval->nodeTab[i]->name[0] == ' ') valuePush(ctxt, - xmlXPathCacheNewCString(ctxt->context, "")); + xmlXPathCacheNewCString(ctxt, "")); else if ((cur->nodesetval->nodeTab[i]->ns == NULL) || (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) { - valuePush(ctxt, - xmlXPathCacheNewString(ctxt->context, + valuePush(ctxt, xmlXPathCacheNewString(ctxt, cur->nodesetval->nodeTab[i]->name)); } else { xmlChar *fullname; @@ -8117,13 +7784,12 @@ xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) if (fullname == cur->nodesetval->nodeTab[i]->name) fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name); if (fullname == NULL) - xmlXPathPErrMemory(ctxt, NULL); - valuePush(ctxt, xmlXPathCacheWrapString( - ctxt->context, fullname)); + xmlXPathPErrMemory(ctxt); + valuePush(ctxt, xmlXPathCacheWrapString(ctxt, fullname)); } break; default: - valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, + valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, cur->nodesetval->nodeTab[i])); xmlXPathLocalNameFunction(ctxt, 1); } @@ -8171,19 +7837,28 @@ xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) { xmlXPathObjectPtr cur; + xmlChar *stringval;
if (ctxt == NULL) return; if (nargs == 0) { - valuePush(ctxt, - xmlXPathCacheWrapString(ctxt->context, - xmlXPathCastNodeToString(ctxt->context->node))); + stringval = xmlXPathCastNodeToString(ctxt->context->node); + if (stringval == NULL) + xmlXPathPErrMemory(ctxt); + valuePush(ctxt, xmlXPathCacheWrapString(ctxt, stringval)); return; }
CHECK_ARITY(1); cur = valuePop(ctxt); if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND); - valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur)); + if (cur->type != XPATH_STRING) { + stringval = xmlXPathCastToString(cur); + if (stringval == NULL) + xmlXPathPErrMemory(ctxt); + xmlXPathReleaseObject(ctxt->context, cur); + cur = xmlXPathCacheWrapString(ctxt, stringval); + } + valuePush(ctxt, cur); }
/** @@ -8206,12 +7881,14 @@ xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) { if ((ctxt == NULL) || (ctxt->context == NULL)) return; if (ctxt->context->node == NULL) { - valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0)); + valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0)); } else { xmlChar *content;
content = xmlXPathCastNodeToString(ctxt->context->node); - valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, + if (content == NULL) + xmlXPathPErrMemory(ctxt); + valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, xmlUTF8Strlen(content))); xmlFree(content); } @@ -8221,7 +7898,7 @@ xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) { CAST_TO_STRING; CHECK_TYPE(XPATH_STRING); cur = valuePop(ctxt); - valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, + valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, xmlUTF8Strlen(cur->stringval))); xmlXPathReleaseObject(ctxt->context, cur); } @@ -8262,6 +7939,8 @@ xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) { XP_ERROR(XPATH_INVALID_TYPE); } tmp = xmlStrcat(newobj->stringval, cur->stringval); + if (tmp == NULL) + xmlXPathPErrMemory(ctxt); newobj->stringval = cur->stringval; cur->stringval = tmp; xmlXPathReleaseObject(ctxt->context, newobj); @@ -8297,9 +7976,9 @@ xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) { XP_ERROR(XPATH_INVALID_TYPE); } if (xmlStrstr(hay->stringval, needle->stringval)) - valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); + valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1)); else - valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); + valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0)); xmlXPathReleaseObject(ctxt->context, hay); xmlXPathReleaseObject(ctxt->context, needle); } @@ -8333,9 +8012,9 @@ xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) { } n = xmlStrlen(needle->stringval); if (xmlStrncmp(hay->stringval, needle->stringval, n)) - valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); + valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0)); else - valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); + valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1)); xmlXPathReleaseObject(ctxt->context, hay); xmlXPathReleaseObject(ctxt->context, needle); } @@ -8427,12 +8106,17 @@ xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) { } }
- if (i < j) { - xmlChar *ret = xmlUTF8Strsub(str->stringval, i - 1, j - i); - valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret)); + i -= 1; + j -= 1; + + if ((i < j) && (i < xmlUTF8Strlen(str->stringval))) { + xmlChar *ret = xmlUTF8Strsub(str->stringval, i, j - i); + if (ret == NULL) + xmlXPathPErrMemory(ctxt); + valuePush(ctxt, xmlXPathCacheNewString(ctxt, ret)); xmlFree(ret); } else { - valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); + valuePush(ctxt, xmlXPathCacheNewCString(ctxt, "")); }
xmlXPathReleaseObject(ctxt->context, str); @@ -8453,31 +8137,34 @@ xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) { */ void xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) { - xmlXPathObjectPtr str; - xmlXPathObjectPtr find; - xmlBufPtr target; - const xmlChar *point; - int offset; - - CHECK_ARITY(2); - CAST_TO_STRING; - find = valuePop(ctxt); - CAST_TO_STRING; - str = valuePop(ctxt); - - target = xmlBufCreate(); - if (target) { + xmlXPathObjectPtr str = NULL; + xmlXPathObjectPtr find = NULL; + const xmlChar *point; + xmlChar *result; + + CHECK_ARITY(2); + CAST_TO_STRING; + find = valuePop(ctxt); + CAST_TO_STRING; + str = valuePop(ctxt); + if (ctxt->error != 0) + goto error; + point = xmlStrstr(str->stringval, find->stringval); - if (point) { - offset = point - str->stringval; - xmlBufAdd(target, str->stringval, offset); + if (point == NULL) { + result = xmlStrdup(BAD_CAST ""); + } else { + result = xmlStrndup(str->stringval, point - str->stringval); } - valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, - xmlBufContent(target))); - xmlBufFree(target); - } - xmlXPathReleaseObject(ctxt->context, str); - xmlXPathReleaseObject(ctxt->context, find); + if (result == NULL) { + xmlXPathPErrMemory(ctxt); + goto error; + } + valuePush(ctxt, xmlXPathCacheWrapString(ctxt, result)); + +error: + xmlXPathReleaseObject(ctxt->context, str); + xmlXPathReleaseObject(ctxt->context, find); }
/** @@ -8489,39 +8176,41 @@ xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) { * string substring-after(string, string) * The substring-after function returns the substring of the first * argument string that follows the first occurrence of the second - * argument string in the first argument string, or the empty stringi + * argument string in the first argument string, or the empty string * if the first argument string does not contain the second argument * string. For example, substring-after("1999/04/01","/") returns 04/01, * and substring-after("1999/04/01","19") returns 99/04/01. */ void xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) { - xmlXPathObjectPtr str; - xmlXPathObjectPtr find; - xmlBufPtr target; - const xmlChar *point; - int offset; - - CHECK_ARITY(2); - CAST_TO_STRING; - find = valuePop(ctxt); - CAST_TO_STRING; - str = valuePop(ctxt); - - target = xmlBufCreate(); - if (target) { + xmlXPathObjectPtr str = NULL; + xmlXPathObjectPtr find = NULL; + const xmlChar *point; + xmlChar *result; + + CHECK_ARITY(2); + CAST_TO_STRING; + find = valuePop(ctxt); + CAST_TO_STRING; + str = valuePop(ctxt); + if (ctxt->error != 0) + goto error; + point = xmlStrstr(str->stringval, find->stringval); - if (point) { - offset = point - str->stringval + xmlStrlen(find->stringval); - xmlBufAdd(target, &str->stringval[offset], - xmlStrlen(str->stringval) - offset); + if (point == NULL) { + result = xmlStrdup(BAD_CAST ""); + } else { + result = xmlStrdup(point + xmlStrlen(find->stringval)); } - valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, - xmlBufContent(target))); - xmlBufFree(target); - } - xmlXPathReleaseObject(ctxt->context, str); - xmlXPathReleaseObject(ctxt->context, find); + if (result == NULL) { + xmlXPathPErrMemory(ctxt); + goto error; + } + valuePush(ctxt, xmlXPathCacheWrapString(ctxt, result)); + +error: + xmlXPathReleaseObject(ctxt->context, str); + xmlXPathReleaseObject(ctxt->context, find); }
/** @@ -8546,9 +8235,10 @@ xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) { if (ctxt == NULL) return; if (nargs == 0) { /* Use current context node */ - valuePush(ctxt, - xmlXPathCacheWrapString(ctxt->context, - xmlXPathCastNodeToString(ctxt->context->node))); + source = xmlXPathCastNodeToString(ctxt->context->node); + if (source == NULL) + xmlXPathPErrMemory(ctxt); + valuePush(ctxt, xmlXPathCacheWrapString(ctxt, source)); nargs = 1; }
@@ -8604,14 +8294,14 @@ xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) { */ void xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) { - xmlXPathObjectPtr str; - xmlXPathObjectPtr from; - xmlXPathObjectPtr to; + xmlXPathObjectPtr str = NULL; + xmlXPathObjectPtr from = NULL; + xmlXPathObjectPtr to = NULL; xmlBufPtr target; int offset, max; int ch; const xmlChar *point; - xmlChar *cptr; + xmlChar *cptr, *content;
CHECK_ARITY(3);
@@ -8621,47 +8311,71 @@ xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) { from = valuePop(ctxt); CAST_TO_STRING; str = valuePop(ctxt); + if (ctxt->error != 0) + goto error;
- target = xmlBufCreate(); - if (target) { - max = xmlUTF8Strlen(to->stringval); - for (cptr = str->stringval; (ch=*cptr); ) { - offset = xmlUTF8Strloc(from->stringval, cptr); - if (offset >= 0) { - if (offset < max) { - point = xmlUTF8Strpos(to->stringval, offset); - if (point) - xmlBufAdd(target, point, xmlUTF8Strsize(point, 1)); - } - } else - xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1)); - - /* Step to next character in input */ - cptr++; - if ( ch & 0x80 ) { - /* if not simple ascii, verify proper format */ - if ( (ch & 0xc0) != 0xc0 ) { - xmlGenericError(xmlGenericErrorContext, - "xmlXPathTranslateFunction: Invalid UTF8 string\n"); - /* not asserting an XPath error is probably better */ - break; - } - /* then skip over remaining bytes for this char */ - while ( (ch <<= 1) & 0x80 ) - if ( (*cptr++ & 0xc0) != 0x80 ) { - xmlGenericError(xmlGenericErrorContext, - "xmlXPathTranslateFunction: Invalid UTF8 string\n"); - /* not asserting an XPath error is probably better */ - break; - } - if (ch & 0x80) /* must have had error encountered */ - break; - } - } + /* + * Account for quadratic runtime + */ + if (ctxt->context->opLimit != 0) { + unsigned long f1 = xmlStrlen(from->stringval); + unsigned long f2 = xmlStrlen(str->stringval); + + if ((f1 > 0) && (f2 > 0)) { + unsigned long p; + + f1 = f1 / 10 + 1; + f2 = f2 / 10 + 1; + p = f1 > ULONG_MAX / f2 ? ULONG_MAX : f1 * f2; + if (xmlXPathCheckOpLimit(ctxt, p) < 0) + goto error; + } + } + + target = xmlBufCreateSize(64); + if (target == NULL) { + xmlXPathPErrMemory(ctxt); + goto error; + } + + max = xmlUTF8Strlen(to->stringval); + for (cptr = str->stringval; (ch=*cptr); ) { + offset = xmlUTF8Strloc(from->stringval, cptr); + if (offset >= 0) { + if (offset < max) { + point = xmlUTF8Strpos(to->stringval, offset); + if (point) + xmlBufAdd(target, point, xmlUTF8Strsize(point, 1)); + } + } else + xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1)); + + /* Step to next character in input */ + cptr++; + if ( ch & 0x80 ) { + /* if not simple ascii, verify proper format */ + if ( (ch & 0xc0) != 0xc0 ) { + xmlXPathErr(ctxt, XPATH_INVALID_CHAR_ERROR); + break; + } + /* then skip over remaining bytes for this char */ + while ( (ch <<= 1) & 0x80 ) + if ( (*cptr++ & 0xc0) != 0x80 ) { + xmlXPathErr(ctxt, XPATH_INVALID_CHAR_ERROR); + break; + } + if (ch & 0x80) /* must have had error encountered */ + break; + } } - valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, - xmlBufContent(target))); + + content = xmlBufDetach(target); + if (content == NULL) + xmlXPathPErrMemory(ctxt); + else + valuePush(ctxt, xmlXPathCacheWrapString(ctxt, content)); xmlBufFree(target); +error: xmlXPathReleaseObject(ctxt->context, str); xmlXPathReleaseObject(ctxt->context, from); xmlXPathReleaseObject(ctxt->context, to); @@ -8687,7 +8401,12 @@ xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) { CHECK_ARITY(1); cur = valuePop(ctxt); if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND); - cur = xmlXPathCacheConvertBoolean(ctxt->context, cur); + if (cur->type != XPATH_BOOLEAN) { + int boolval = xmlXPathCastToBoolean(cur); + + xmlXPathReleaseObject(ctxt->context, cur); + cur = xmlXPathCacheNewBoolean(ctxt, boolval); + } valuePush(ctxt, cur); }
@@ -8720,7 +8439,7 @@ xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) { void xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) { CHECK_ARITY(0); - valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); + valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1)); }
/** @@ -8734,7 +8453,7 @@ xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) { void xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) { CHECK_ARITY(0); - valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); + valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0)); }
/** @@ -8760,8 +8479,9 @@ xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) { */ void xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) { - xmlXPathObjectPtr val = NULL; - const xmlChar *theLang = NULL; + xmlXPathObjectPtr val; + xmlNodePtr cur; + xmlChar *theLang; const xmlChar *lang; int ret = 0; int i; @@ -8771,20 +8491,28 @@ xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) { CHECK_TYPE(XPATH_STRING); val = valuePop(ctxt); lang = val->stringval; - theLang = xmlNodeGetLang(ctxt->context->node); + cur = ctxt->context->node; + while (cur != NULL) { + if (xmlNodeGetAttrValue(cur, BAD_CAST "lang", XML_XML_NAMESPACE, + &theLang) < 0) + xmlXPathPErrMemory(ctxt); + if (theLang != NULL) + break; + cur = cur->parent; + } if ((theLang != NULL) && (lang != NULL)) { for (i = 0;lang[i] != 0;i++) - if (toupper(lang[i]) != toupper(theLang[i])) - goto not_equal; - if ((theLang[i] == 0) || (theLang[i] == '-')) - ret = 1; + if (toupper(lang[i]) != toupper(theLang[i])) + goto not_equal; + if ((theLang[i] == 0) || (theLang[i] == '-')) + ret = 1; } not_equal: if (theLang != NULL) xmlFree((void *)theLang);
xmlXPathReleaseObject(ctxt->context, val); - valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret)); + valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, ret)); }
/** @@ -8803,12 +8531,14 @@ xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) { if (ctxt == NULL) return; if (nargs == 0) { if (ctxt->context->node == NULL) { - valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0)); + valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0.0)); } else { xmlChar* content = xmlNodeGetContent(ctxt->context->node); + if (content == NULL) + xmlXPathPErrMemory(ctxt);
res = xmlXPathStringEvalNumber(content); - valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res)); + valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, res)); xmlFree(content); } return; @@ -8816,7 +8546,14 @@ xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
CHECK_ARITY(1); cur = valuePop(ctxt); - valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur)); + if (cur->type != XPATH_NUMBER) { + double floatval; + + floatval = xmlXPathCastToNumberInternal(ctxt, cur); + xmlXPathReleaseObject(ctxt->context, cur); + cur = xmlXPathCacheNewFloat(ctxt, floatval); + } + valuePush(ctxt, cur); }
/** @@ -8844,10 +8581,11 @@ xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) { for (i = 0; i < cur->nodesetval->nodeNr; i++) { - res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]); + res += xmlXPathNodeToNumberInternal(ctxt, + cur->nodesetval->nodeTab[i]); } } - valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res)); + valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, res)); xmlXPathReleaseObject(ctxt->context, cur); }
@@ -9071,6 +8809,8 @@ xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) { if (count == 0) return(NULL); ret = xmlStrndup(ctxt->cur, count); + if (ret == NULL) + xmlXPathPErrMemory(ctxt); ctxt->cur = in; return(ret); } @@ -9152,6 +8892,8 @@ xmlXPathParseName(xmlXPathParserContextPtr ctxt) { XP_ERRORNULL(XPATH_EXPR_ERROR); } ret = xmlStrndup(ctxt->cur, count); + if (ret == NULL) + xmlXPathPErrMemory(ctxt); ctxt->cur = in; return(ret); } @@ -9161,6 +8903,7 @@ xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) { + xmlChar *ret; xmlChar buf[XML_MAX_NAMELEN + 5]; int len = 0, l; int c; @@ -9199,7 +8942,8 @@ xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) { } buffer = (xmlChar *) xmlMallocAtomic(max); if (buffer == NULL) { - XP_ERRORNULL(XPATH_MEMORY_ERROR); + xmlXPathPErrMemory(ctxt); + return(NULL); } memcpy(buffer, buf, len); while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */ @@ -9217,7 +8961,8 @@ xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) { tmp = (xmlChar *) xmlRealloc(buffer, max); if (tmp == NULL) { xmlFree(buffer); - XP_ERRORNULL(XPATH_MEMORY_ERROR); + xmlXPathPErrMemory(ctxt); + return(NULL); } buffer = tmp; } @@ -9231,7 +8976,10 @@ xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) { } if (len == 0) return(NULL); - return(xmlStrndup(buf, len)); + ret = xmlStrndup(buf, len); + if (ret == NULL) + xmlXPathPErrMemory(ctxt); + return(ret); }
#define MAX_FRAC 20 @@ -9434,7 +9182,7 @@ xmlXPathCompNumber(xmlXPathParserContextPtr ctxt) exponent = -exponent; ret *= pow(10.0, (double) exponent); } - num = xmlXPathCacheNewFloat(ctxt->context, ret); + num = xmlXPathCacheNewFloat(ctxt, ret); if (num == NULL) { ctxt->error = XPATH_MEMORY_ERROR; } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num, @@ -9458,32 +9206,33 @@ static xmlChar * xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) { const xmlChar *q; xmlChar *ret = NULL; + int quote;
if (CUR == '"') { - NEXT; - q = CUR_PTR; - while ((IS_CHAR_CH(CUR)) && (CUR != '"')) - NEXT; - if (!IS_CHAR_CH(CUR)) { - XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR); - } else { - ret = xmlStrndup(q, CUR_PTR - q); - NEXT; - } + quote = '"'; } else if (CUR == ''') { - NEXT; - q = CUR_PTR; - while ((IS_CHAR_CH(CUR)) && (CUR != ''')) - NEXT; - if (!IS_CHAR_CH(CUR)) { - XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR); - } else { - ret = xmlStrndup(q, CUR_PTR - q); - NEXT; - } + quote = '''; } else { XP_ERRORNULL(XPATH_START_LITERAL_ERROR); } + + NEXT; + q = CUR_PTR; + while (CUR != quote) { + int ch; + int len = 4; + + if (CUR == 0) + XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR); + ch = xmlGetUTF8Char(CUR_PTR, &len); + if ((ch < 0) || (IS_CHAR(ch) == 0)) + XP_ERRORNULL(XPATH_INVALID_CHAR_ERROR); + CUR_PTR += len; + } + ret = xmlStrndup(q, CUR_PTR - q); + if (ret == NULL) + xmlXPathPErrMemory(ctxt); + NEXT; return(ret); }
@@ -9500,42 +9249,15 @@ xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) { */ static void xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) { - const xmlChar *q; xmlChar *ret = NULL; xmlXPathObjectPtr lit;
- if (CUR == '"') { - NEXT; - q = CUR_PTR; - while ((IS_CHAR_CH(CUR)) && (CUR != '"')) - NEXT; - if (!IS_CHAR_CH(CUR)) { - XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR); - } else { - ret = xmlStrndup(q, CUR_PTR - q); - NEXT; - } - } else if (CUR == ''') { - NEXT; - q = CUR_PTR; - while ((IS_CHAR_CH(CUR)) && (CUR != ''')) - NEXT; - if (!IS_CHAR_CH(CUR)) { - XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR); - } else { - ret = xmlStrndup(q, CUR_PTR - q); - NEXT; - } - } else { - XP_ERROR(XPATH_START_LITERAL_ERROR); - } - if (ret == NULL) { - xmlXPathPErrMemory(ctxt, NULL); + ret = xmlXPathParseLiteral(ctxt); + if (ret == NULL) return; - } - lit = xmlXPathCacheNewString(ctxt->context, ret); + lit = xmlXPathCacheNewString(ctxt, ret); if (lit == NULL) { - ctxt->error = XPATH_MEMORY_ERROR; + ctxt->error = XPATH_MEMORY_ERROR; } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit, NULL) == -1) { xmlXPathReleaseObject(ctxt->context, lit); @@ -9794,6 +9516,8 @@ xmlXPathScanName(xmlXPathParserContextPtr ctxt) { c = CUR_CHAR(l); } ret = xmlStrndup(cur, ctxt->cur - cur); + if (ret == NULL) + xmlXPathPErrMemory(ctxt); ctxt->cur = cur; return(ret); } @@ -10302,7 +10026,6 @@ xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test, int blanks;
if ((test == NULL) || (type == NULL) || (prefix == NULL)) { - STRANGE; return(NULL); } *type = (xmlXPathTypeVal) 0; @@ -10358,9 +10081,6 @@ xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test, name = NULL; if (CUR != ')') { name = xmlXPathParseLiteral(ctxt); - if (name == NULL) { - XP_ERRORNULL(XPATH_EXPR_ERROR); - } *test = NODE_TEST_PI; SKIP_BLANKS; } @@ -10855,7 +10575,7 @@ xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt, tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab, nodeMax * sizeof(xmlNodePtr)); if (tmp == NULL) { - xmlXPathPErrMemory(ctxt, "shrinking nodeset\n"); + xmlXPathPErrMemory(ctxt); } else { set->nodeTab = tmp; set->nodeMax = nodeMax; @@ -10973,7 +10693,7 @@ xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt, tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab, locMax * sizeof(xmlXPathObjectPtr)); if (tmp == NULL) { - xmlXPathPErrMemory(ctxt, "shrinking locset\n"); + xmlXPathPErrMemory(ctxt); } else { locset->locTab = tmp; locset->locMax = locMax; @@ -11013,8 +10733,6 @@ xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt, * Process inner predicates first. */ if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) { - xmlGenericError(xmlGenericErrorContext, - "xmlXPathCompOpEvalPredicate: Expected a predicate\n"); XP_ERROR(XPATH_INVALID_OPERAND); } if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH) @@ -11097,11 +10815,11 @@ xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, if (hasAxisRange != 0) { \ if (++pos == maxPos) { \ if (addNode(seq, cur) < 0) \ - ctxt->error = XPATH_MEMORY_ERROR; \ + xmlXPathPErrMemory(ctxt); \ goto axis_range_end; } \ } else { \ if (addNode(seq, cur) < 0) \ - ctxt->error = XPATH_MEMORY_ERROR; \ + xmlXPathPErrMemory(ctxt); \ if (breakOnFirstHit) goto first_hit; }
#define XP_TEST_HIT_NS \ @@ -11109,12 +10827,12 @@ xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, if (++pos == maxPos) { \ hasNsNodes = 1; \ if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \ - ctxt->error = XPATH_MEMORY_ERROR; \ + xmlXPathPErrMemory(ctxt); \ goto axis_range_end; } \ } else { \ hasNsNodes = 1; \ if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \ - ctxt->error = XPATH_MEMORY_ERROR; \ + xmlXPathPErrMemory(ctxt); \ if (breakOnFirstHit) goto first_hit; }
xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value; @@ -11254,8 +10972,7 @@ xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, } contextSeq = obj->nodesetval; if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) { - xmlXPathReleaseObject(xpctxt, obj); - valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL)); + valuePush(ctxt, obj); return(0); } /* @@ -11330,7 +11047,7 @@ xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, if (seq == NULL) { seq = xmlXPathNodeSetCreate(NULL); if (seq == NULL) { - /* TODO: Propagate memory error. */ + xmlXPathPErrMemory(ctxt); total = 0; goto error; } @@ -11384,7 +11101,6 @@ xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, switch (test) { case NODE_TEST_NONE: total = 0; - STRANGE goto error; case NODE_TEST_TYPE: if (type == NODE_TYPE_NODE) { @@ -11462,7 +11178,7 @@ xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, } break; case NODE_TEST_NS:{ - TODO; + /* TODO */ break; } case NODE_TEST_NAME: @@ -11544,9 +11260,11 @@ axis_range_end: /* ----------------------------------------------------- */ if (outSeq == NULL) { outSeq = seq; seq = NULL; - } else - /* TODO: Check memory error. */ + } else { outSeq = mergeAndClear(outSeq, seq); + if (outSeq == NULL) + xmlXPathPErrMemory(ctxt); + } /* * Break if only a true/false result was requested. */ @@ -11562,9 +11280,11 @@ first_hit: /* ---------------------------------------------------------- */ if (outSeq == NULL) { outSeq = seq; seq = NULL; - } else - /* TODO: Check memory error. */ + } else { outSeq = mergeAndClear(outSeq, seq); + if (outSeq == NULL) + xmlXPathPErrMemory(ctxt); + } break;
apply_predicates: /* --------------------------------------------------- */ @@ -11624,8 +11344,9 @@ apply_predicates: /* --------------------------------------------------- */ outSeq = seq; seq = NULL; } else { - /* TODO: Check memory error. */ outSeq = mergeAndClear(outSeq, seq); + if (outSeq == NULL) + xmlXPathPErrMemory(ctxt); }
if (toBool) @@ -11651,11 +11372,13 @@ error: * Ensure we return at least an empty set. */ if (outSeq == NULL) { - if ((seq != NULL) && (seq->nodeNr == 0)) + if ((seq != NULL) && (seq->nodeNr == 0)) { outSeq = seq; - else - /* TODO: Check memory error. */ + } else { outSeq = xmlXPathNodeSetCreate(NULL); + if (outSeq == NULL) + xmlXPathPErrMemory(ctxt); + } } if ((seq != NULL) && (seq != outSeq)) { xmlXPathFreeNodeSet(seq); @@ -11664,7 +11387,7 @@ error: * Hand over the result. Better to push the set also in * case of errors. */ - valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq)); + valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, outSeq)); /* * Reset the context node. */ @@ -11762,9 +11485,13 @@ xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt, break; }
- /* TODO: Check memory error. */ - arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, - arg2->nodesetval); + if ((arg2->nodesetval != NULL) && + (arg2->nodesetval->nodeNr != 0)) { + arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, + arg2->nodesetval); + if (arg1->nodesetval == NULL) + xmlXPathPErrMemory(ctxt); + } valuePush(ctxt, arg1); xmlXPathReleaseObject(ctxt->context, arg2); /* optimizer */ @@ -11782,7 +11509,7 @@ xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt, if (op->ch2 != -1) total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); CHECK_ERROR0; - valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, + valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node)); break; case XPATH_OP_COLLECT:{ @@ -11796,9 +11523,7 @@ xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt, break; } case XPATH_OP_VALUE: - valuePush(ctxt, - xmlXPathCacheObjectCopy(ctxt->context, - (xmlXPathObjectPtr) op->value4)); + valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4)); break; case XPATH_OP_SORT: if (op->ch1 != -1) @@ -11902,9 +11627,13 @@ xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op, break; }
- /* TODO: Check memory error. */ - arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, - arg2->nodesetval); + if ((arg2->nodesetval != NULL) && + (arg2->nodesetval->nodeNr != 0)) { + arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, + arg2->nodesetval); + if (arg1->nodesetval == NULL) + xmlXPathPErrMemory(ctxt); + } valuePush(ctxt, arg1); xmlXPathReleaseObject(ctxt->context, arg2); /* optimizer */ @@ -11922,7 +11651,7 @@ xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op, if (op->ch2 != -1) total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); CHECK_ERROR0; - valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, + valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node)); break; case XPATH_OP_COLLECT:{ @@ -11936,9 +11665,7 @@ xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op, break; } case XPATH_OP_VALUE: - valuePush(ctxt, - xmlXPathCacheObjectCopy(ctxt->context, - (xmlXPathObjectPtr) op->value4)); + valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4)); break; case XPATH_OP_SORT: if (op->ch1 != -1) @@ -12124,7 +11851,7 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) equal = xmlXPathEqualValues(ctxt); else equal = xmlXPathNotEqualValues(ctxt); - valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal)); + valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, equal)); break; case XPATH_OP_CMP: total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); @@ -12132,7 +11859,7 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); CHECK_ERROR0; ret = xmlXPathCompareValues(ctxt, op->value, op->value2); - valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret)); + valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, ret)); break; case XPATH_OP_PLUS: total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); @@ -12190,13 +11917,13 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) break; }
- if ((arg1->nodesetval == NULL) || - ((arg2->nodesetval != NULL) && + if (((arg2->nodesetval != NULL) && (arg2->nodesetval->nodeNr != 0))) { - /* TODO: Check memory error. */ arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, arg2->nodesetval); + if (arg1->nodesetval == NULL) + xmlXPathPErrMemory(ctxt); }
valuePush(ctxt, arg1); @@ -12212,8 +11939,8 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) if (op->ch2 != -1) total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); CHECK_ERROR0; - valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, - ctxt->context->node)); + valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, + ctxt->context->node)); break; case XPATH_OP_COLLECT:{ if (op->ch1 == -1) @@ -12226,9 +11953,7 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) break; } case XPATH_OP_VALUE: - valuePush(ctxt, - xmlXPathCacheObjectCopy(ctxt->context, - (xmlXPathObjectPtr) op->value4)); + valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4)); break; case XPATH_OP_VARIABLE:{ xmlXPathObjectPtr val; @@ -12246,10 +11971,7 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
URI = xmlXPathNsLookup(ctxt->context, op->value5); if (URI == NULL) { - xmlGenericError(xmlGenericErrorContext, - "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n", - (char *) op->value4, (char *)op->value5); - ctxt->error = XPATH_UNDEF_PREFIX_ERROR; + XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR); break; } val = xmlXPathVariableLookupNS(ctxt->context, @@ -12273,19 +11995,11 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) if (ctxt->error != XPATH_EXPRESSION_OK) break; } - if (ctxt->valueNr < frame + op->value) { - xmlGenericError(xmlGenericErrorContext, - "xmlXPathCompOpEval: parameter error\n"); - ctxt->error = XPATH_INVALID_OPERAND; - break; - } + if (ctxt->valueNr < frame + op->value) + XP_ERROR0(XPATH_INVALID_OPERAND); for (i = 0; i < op->value; i++) { - if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) { - xmlGenericError(xmlGenericErrorContext, - "xmlXPathCompOpEval: parameter error\n"); - ctxt->error = XPATH_INVALID_OPERAND; - break; - } + if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) + XP_ERROR0(XPATH_INVALID_OPERAND); } if (op->cache != NULL) func = op->cache; @@ -12298,22 +12012,13 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) op->value4); else { URI = xmlXPathNsLookup(ctxt->context, op->value5); - if (URI == NULL) { - xmlGenericError(xmlGenericErrorContext, - "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n", - (char *)op->value4, (char *)op->value5); - ctxt->error = XPATH_UNDEF_PREFIX_ERROR; - break; - } + if (URI == NULL) + XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR); func = xmlXPathFunctionLookupNS(ctxt->context, op->value4, URI); } - if (func == NULL) { - xmlGenericError(xmlGenericErrorContext, - "xmlXPathCompOpEval: function %s not found\n", - (char *)op->value4); + if (func == NULL) XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR); - } op->cache = func; op->cacheURI = (void *) URI; } @@ -12532,8 +12237,8 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) ctxt->context->node = oldlocset->locTab[i]->user; ctxt->context->contextSize = oldlocset->locNr; ctxt->context->proximityPosition = i + 1; - tmp = xmlXPathCacheNewNodeSet(ctxt->context, - ctxt->context->node); + tmp = xmlXPathCacheNewNodeSet(ctxt, + ctxt->context->node); valuePush(ctxt, tmp);
if (op->ch2 != -1) @@ -12595,8 +12300,8 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) /* * OPTIMIZE TODO: Avoid recreation for every iteration. */ - tmp = xmlXPathCacheNewNodeSet(ctxt->context, - ctxt->context->node); + tmp = xmlXPathCacheNewNodeSet(ctxt, + ctxt->context->node); valuePush(ctxt, tmp);
if (op->ch2 != -1) @@ -12643,9 +12348,7 @@ rangeto_error: } #endif /* LIBXML_XPTR_LOCS_ENABLED */ default: - xmlGenericError(xmlGenericErrorContext, - "XPath: unknown precompiled operation %d\n", op->op); - ctxt->error = XPATH_INVALID_OPERAND; + XP_ERROR0(XPATH_INVALID_OPERAND); break; }
@@ -12747,12 +12450,12 @@ start: #ifdef XPATH_STREAMING /** * xmlXPathRunStreamEval: - * @ctxt: the XPath parser context with the compiled expression + * @pctxt: the XPath parser context with the compiled expression * * Evaluate the Precompiled Streamable XPath expression in the given context. */ static int -xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp, +xmlXPathRunStreamEval(xmlXPathParserContextPtr pctxt, xmlPatternPtr comp, xmlXPathObjectPtr *resultSeq, int toBool) { int max_depth, min_depth; @@ -12761,6 +12464,7 @@ xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp, int eval_all_nodes; xmlNodePtr cur = NULL, limit = NULL; xmlStreamCtxtPtr patstream = NULL; + xmlXPathContextPtr ctxt = pctxt->context;
if ((ctxt == NULL) || (comp == NULL)) return(-1); @@ -12782,7 +12486,7 @@ xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp, if (! toBool) { if (resultSeq == NULL) return(-1); - *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL); + *resultSeq = xmlXPathCacheNewNodeSet(pctxt, NULL); if (*resultSeq == NULL) return(-1); } @@ -12791,20 +12495,24 @@ xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp, * handle the special cases of "/" amd "." being matched */ if (min_depth == 0) { + int res; + if (from_root) { /* Select "/" */ if (toBool) return(1); - /* TODO: Check memory error. */ - xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, - (xmlNodePtr) ctxt->doc); + res = xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, + (xmlNodePtr) ctxt->doc); } else { /* Select "self::node()" */ if (toBool) return(1); - /* TODO: Check memory error. */ - xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node); + res = xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, + ctxt->node); } + + if (res < 0) + xmlXPathPErrMemory(pctxt); } if (max_depth == 0) { return(0); @@ -12846,10 +12554,8 @@ xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
patstream = xmlPatternGetStreamCtxt(comp); if (patstream == NULL) { - /* - * QUESTION TODO: Is this an error? - */ - return(0); + xmlXPathPErrMemory(pctxt); + return(-1); }
eval_all_nodes = xmlStreamWantsAnyNode(patstream); @@ -12860,8 +12566,8 @@ xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp, } else if (ret == 1) { if (toBool) goto return_1; - /* TODO: Check memory error. */ - xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur); + if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur) < 0) + xmlXPathPErrMemory(pctxt); } } depth = 0; @@ -12870,8 +12576,7 @@ next_node: do { if (ctxt->opLimit != 0) { if (ctxt->opCount >= ctxt->opLimit) { - xmlGenericError(xmlGenericErrorContext, - "XPath operation limit exceeded\n"); + xmlXPathErr(ctxt, XPATH_RECURSION_LIMIT_EXCEEDED); xmlFreeStreamCtxt(patstream); return(-1); } @@ -12893,15 +12598,13 @@ next_node: break;
if (ret < 0) { - /* NOP. */ + xmlXPathPErrMemory(pctxt); } else if (ret == 1) { if (toBool) goto return_1; - if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur) - < 0) { - ctxt->lastError.domain = XML_FROM_XPATH; - ctxt->lastError.code = XML_ERR_NO_MEMORY; - } + if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, + cur) < 0) + xmlXPathPErrMemory(pctxt); } if ((cur->children == NULL) || (depth >= max_depth)) { ret = xmlStreamPop(patstream); @@ -13001,7 +12704,7 @@ xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool) ctxt->valueTab = (xmlXPathObjectPtr *) xmlMalloc(10 * sizeof(xmlXPathObjectPtr)); if (ctxt->valueTab == NULL) { - xmlXPathPErrMemory(ctxt, "creating evaluation context\n"); + xmlXPathPErrMemory(ctxt); return(-1); } ctxt->valueNr = 0; @@ -13016,8 +12719,7 @@ xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool) /* * Evaluation to boolean result. */ - res = xmlXPathRunStreamEval(ctxt->context, - ctxt->comp->stream, NULL, 1); + res = xmlXPathRunStreamEval(ctxt, ctxt->comp->stream, NULL, 1); if (res != -1) return(res); } else { @@ -13026,8 +12728,7 @@ xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool) /* * Evaluation to a sequence. */ - res = xmlXPathRunStreamEval(ctxt->context, - ctxt->comp->stream, &resObj, 0); + res = xmlXPathRunStreamEval(ctxt, ctxt->comp->stream, &resObj, 0);
if ((res != -1) && (resObj != NULL)) { valuePush(ctxt, resObj); @@ -13044,8 +12745,7 @@ xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool) #endif comp = ctxt->comp; if (comp->last < 0) { - xmlGenericError(xmlGenericErrorContext, - "xmlXPathRunEval: last is less than zero\n"); + xmlXPathErr(ctxt, XPATH_STACK_ERROR); return(-1); } oldDepth = ctxt->context->depth; @@ -13098,7 +12798,7 @@ xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) { return((res->stringval != NULL) && (xmlStrlen(res->stringval) != 0)); default: - STRANGE + break; } return(0); } @@ -13149,7 +12849,7 @@ xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt, } #endif default: - STRANGE + break; } return(0); } @@ -13180,6 +12880,7 @@ xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) { if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) && (!xmlStrchr(str, '@'))) { const xmlChar *tmp; + int res;
/* * We don't try to handle expressions using the verbose axis @@ -13200,7 +12901,7 @@ xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) { if (ctxt->nsNr > 0) { namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*)); if (namespaces == NULL) { - xmlXPathErrMemory(ctxt, "allocating namespaces array\n"); + xmlXPathErrMemory(ctxt); return(NULL); } for (i = 0, j = 0; (j < ctxt->nsNr); j++) { @@ -13213,14 +12914,19 @@ xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) { } }
- stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, namespaces); + res = xmlPatternCompileSafe(str, dict, XML_PATTERN_XPATH, namespaces, + &stream); if (namespaces != NULL) { xmlFree((xmlChar **)namespaces); } + if (res < 0) { + xmlXPathErrMemory(ctxt); + return(NULL); + } if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) { comp = xmlXPathNewCompExpr(); if (comp == NULL) { - xmlXPathErrMemory(ctxt, "allocating streamable expression\n"); + xmlXPathErrMemory(ctxt); xmlFreePattern(stream); return(NULL); } @@ -13325,6 +13031,7 @@ xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt, xmlXPathCompExprPtr xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) { xmlXPathParserContextPtr pctxt; + xmlXPathContextPtr tmpctxt = NULL; xmlXPathCompExprPtr comp; int oldDepth = 0;
@@ -13336,18 +13043,32 @@ xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
xmlInitParser();
+ /* + * We need an xmlXPathContext for the depth check. + */ + if (ctxt == NULL) { + tmpctxt = xmlXPathNewContext(NULL); + if (tmpctxt == NULL) + return(NULL); + ctxt = tmpctxt; + } + pctxt = xmlXPathNewParserContext(str, ctxt); - if (pctxt == NULL) + if (pctxt == NULL) { + if (tmpctxt != NULL) + xmlXPathFreeContext(tmpctxt); return NULL; - if (ctxt != NULL) - oldDepth = ctxt->depth; + } + + oldDepth = ctxt->depth; xmlXPathCompileExpr(pctxt, 1); - if (ctxt != NULL) - ctxt->depth = oldDepth; + ctxt->depth = oldDepth;
if( pctxt->error != XPATH_EXPRESSION_OK ) { xmlXPathFreeParserContext(pctxt); + if (tmpctxt != NULL) + xmlXPathFreeContext(tmpctxt); return(NULL); }
@@ -13372,6 +13093,8 @@ xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) { pctxt->comp = NULL; } xmlXPathFreeParserContext(pctxt); + if (tmpctxt != NULL) + xmlXPathFreeContext(tmpctxt);
if (comp != NULL) { comp->expr = xmlStrdup(str); @@ -13413,18 +13136,18 @@ xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp, int toBool) { xmlXPathParserContextPtr pctxt; - xmlXPathObjectPtr resObj; + xmlXPathObjectPtr resObj = NULL; #ifndef LIBXML_THREAD_ENABLED static int reentance = 0; #endif int res;
- CHECK_CTXT_NEG(ctxt) - if (comp == NULL) return(-1); xmlInitParser();
+ xmlResetError(&ctxt->lastError); + #ifndef LIBXML_THREAD_ENABLED reentance++; if (reentance > 1) @@ -13436,19 +13159,11 @@ xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp, return(-1); res = xmlXPathRunEval(pctxt, toBool);
- if (pctxt->error != XPATH_EXPRESSION_OK) { - resObj = NULL; - } else { - resObj = valuePop(pctxt); - if (resObj == NULL) { - if (!toBool) - xmlGenericError(xmlGenericErrorContext, - "xmlXPathCompiledEval: No result on the stack.\n"); - } else if (pctxt->valueNr > 0) { - xmlGenericError(xmlGenericErrorContext, - "xmlXPathCompiledEval: %d object(s) left on the stack.\n", - pctxt->valueNr); - } + if (pctxt->error == XPATH_EXPRESSION_OK) { + if (pctxt->valueNr != ((toBool) ? 0 : 1)) + xmlXPathErr(pctxt, XPATH_STACK_ERROR); + else if (!toBool) + resObj = valuePop(pctxt); }
if (resObjPtr) @@ -13516,10 +13231,18 @@ xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) { #endif int oldDepth = 0;
- if (ctxt == NULL) return; + if (ctxt == NULL) + return; + if (ctxt->context->lastError.code != 0) + return;
#ifdef XPATH_STREAMING comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base); + if ((comp == NULL) && + (ctxt->context->lastError.code == XML_ERR_NO_MEMORY)) { + xmlXPathPErrMemory(ctxt); + return; + } if (comp != NULL) { if (ctxt->comp != NULL) xmlXPathFreeCompExpr(ctxt->comp); @@ -13566,10 +13289,13 @@ xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) { xmlXPathParserContextPtr ctxt; xmlXPathObjectPtr res;
- CHECK_CTXT(ctx) + if (ctx == NULL) + return(NULL);
xmlInitParser();
+ xmlResetError(&ctx->lastError); + ctxt = xmlXPathNewParserContext(str, ctx); if (ctxt == NULL) return NULL; @@ -13577,16 +13303,11 @@ xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
if (ctxt->error != XPATH_EXPRESSION_OK) { res = NULL; + } else if (ctxt->valueNr != 1) { + xmlXPathErr(ctxt, XPATH_STACK_ERROR); + res = NULL; } else { res = valuePop(ctxt); - if (res == NULL) { - xmlGenericError(xmlGenericErrorContext, - "xmlXPathCompiledEval: No result on the stack.\n"); - } else if (ctxt->valueNr > 0) { - xmlGenericError(xmlGenericErrorContext, - "xmlXPathCompiledEval: %d object(s) left on the stack.\n", - ctxt->valueNr); - } }
xmlXPathFreeParserContext(ctxt); @@ -13719,7 +13440,7 @@ xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) { CAST_TO_STRING; str = valuePop(ctxt);
- target = xmlBufCreate(); + target = xmlBufCreateSize(64);
escape[0] = '%'; escape[3] = 0; @@ -13759,8 +13480,7 @@ xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) { } } } - valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, - xmlBufContent(target))); + valuePush(ctxt, xmlXPathCacheNewString(ctxt, xmlBufContent(target))); xmlBufFree(target); xmlXPathReleaseObject(ctxt->context, str); } diff --git a/libs/xml2/xpointer.c b/libs/xml2/xpointer.c index 8f38dd103fa..8d378123041 100644 --- a/libs/xml2/xpointer.c +++ b/libs/xml2/xpointer.c @@ -45,16 +45,7 @@ #define XPTR_XMLNS_SCHEME
#include "private/error.h" - -#define TODO \ - xmlGenericError(xmlGenericErrorContext, \ - "Unimplemented block at %s:%d\n", \ - __FILE__, __LINE__); - -#define STRANGE \ - xmlGenericError(xmlGenericErrorContext, \ - "Internal error at %s:%d\n", \ - __FILE__, __LINE__); +#include "private/xpath.h"
/************************************************************************ * * @@ -62,63 +53,59 @@ * * ************************************************************************/
-/** - * xmlXPtrErrMemory: - * @extra: extra information - * - * Handle a redefinition of attribute error - */ -static void -xmlXPtrErrMemory(const char *extra) -{ - __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_XPOINTER, - XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0, extra, - NULL, NULL, 0, 0, - "Memory allocation failed : %s\n", extra); -} - /** * xmlXPtrErr: * @ctxt: an XPTR evaluation context * @extra: extra information * - * Handle a redefinition of attribute error + * Handle an XPointer error */ static void LIBXML_ATTR_FORMAT(3,0) -xmlXPtrErr(xmlXPathParserContextPtr ctxt, int error, +xmlXPtrErr(xmlXPathParserContextPtr ctxt, int code, const char * msg, const xmlChar *extra) { - if (ctxt != NULL) - ctxt->error = error; - if ((ctxt == NULL) || (ctxt->context == NULL)) { - __xmlRaiseError(NULL, NULL, NULL, - NULL, NULL, XML_FROM_XPOINTER, error, - XML_ERR_ERROR, NULL, 0, - (const char *) extra, NULL, NULL, 0, 0, - msg, extra); - return; - } + xmlStructuredErrorFunc serror = NULL; + void *data = NULL; + xmlNodePtr node = NULL; + int res;
- /* cleanup current last error */ - xmlResetError(&ctxt->context->lastError); + if (ctxt == NULL) + return; + /* Only report the first error */ + if (ctxt->error != 0) + return;
- ctxt->context->lastError.domain = XML_FROM_XPOINTER; - ctxt->context->lastError.code = error; - ctxt->context->lastError.level = XML_ERR_ERROR; - ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base); - ctxt->context->lastError.int1 = ctxt->cur - ctxt->base; - ctxt->context->lastError.node = ctxt->context->debugNode; - if (ctxt->context->error != NULL) { - ctxt->context->error(ctxt->context->userData, - &ctxt->context->lastError); - } else { - __xmlRaiseError(NULL, NULL, NULL, - NULL, ctxt->context->debugNode, XML_FROM_XPOINTER, - error, XML_ERR_ERROR, NULL, 0, - (const char *) extra, (const char *) ctxt->base, NULL, - ctxt->cur - ctxt->base, 0, - msg, extra); + ctxt->error = code; + + if (ctxt->context != NULL) { + xmlErrorPtr err = &ctxt->context->lastError; + + /* cleanup current last error */ + xmlResetError(err); + + err->domain = XML_FROM_XPOINTER; + err->code = code; + err->level = XML_ERR_ERROR; + err->str1 = (char *) xmlStrdup(ctxt->base); + if (err->str1 == NULL) { + xmlXPathPErrMemory(ctxt); + return; + } + err->int1 = ctxt->cur - ctxt->base; + err->node = ctxt->context->debugNode; + + serror = ctxt->context->error; + data = ctxt->context->userData; + node = ctxt->context->debugNode; } + + res = __xmlRaiseError(serror, NULL, data, NULL, node, + XML_FROM_XPOINTER, code, XML_ERR_ERROR, NULL, 0, + (const char *) extra, (const char *) ctxt->base, + NULL, ctxt->cur - ctxt->base, 0, + msg, extra); + if (res < 0) + xmlXPathPErrMemory(ctxt); }
/************************************************************************ @@ -208,6 +195,18 @@ xmlXPtrGetNthChild(xmlNodePtr cur, int no) { * * ************************************************************************/
+/** + * xmlXPtrErrMemory: + * @extra: extra information + * + * Handle a redefinition of attribute error + */ +static void +xmlXPtrErrMemory(const char *extra ATTRIBUTE_UNUSED) +{ + xmlRaiseMemoryError(NULL, NULL, NULL, XML_FROM_XPOINTER, NULL); +} + /** * xmlXPtrCmpPoints: * @node1: the first node @@ -959,7 +958,7 @@ xmlXPtrEvalXPtrPart(xmlXPathParserContextPtr ctxt, xmlChar *name) { len++; buffer = (xmlChar *) xmlMallocAtomic(len); if (buffer == NULL) { - xmlXPtrErrMemory("allocating buffer"); + xmlXPathPErrMemory(ctxt); xmlFree(name); return; } @@ -1060,7 +1059,8 @@ xmlXPtrEvalXPtrPart(xmlXPathParserContextPtr ctxt, xmlChar *name) { NEXT; SKIP_BLANKS;
- xmlXPathRegisterNs(ctxt->context, prefix, ctxt->cur); + if (xmlXPathRegisterNs(ctxt->context, prefix, ctxt->cur) < 0) + xmlXPathPErrMemory(ctxt); ctxt->base = oldBase; ctxt->cur = oldCur; xmlFree(prefix); @@ -1230,7 +1230,7 @@ xmlXPtrEvalXPointer(xmlXPathParserContextPtr ctxt) { ctxt->valueTab = (xmlXPathObjectPtr *) xmlMalloc(10 * sizeof(xmlXPathObjectPtr)); if (ctxt->valueTab == NULL) { - xmlXPtrErrMemory("allocating evaluation context"); + xmlXPathPErrMemory(ctxt); return; } ctxt->valueNr = 0; @@ -1351,10 +1351,16 @@ xmlXPtrEval(const xmlChar *str, xmlXPathContextPtr ctx) { if ((ctx == NULL) || (str == NULL)) return(NULL);
+ xmlResetError(&ctx->lastError); + ctxt = xmlXPathNewParserContext(str, ctx); - if (ctxt == NULL) + if (ctxt == NULL) { + xmlXPathErrMemory(ctx); return(NULL); + } xmlXPtrEvalXPointer(ctxt); + if (ctx->lastError.code != XML_ERR_OK) + goto error;
if ((ctxt->value != NULL) && #ifdef LIBXML_XPTR_LOCS_ENABLED @@ -1392,11 +1398,12 @@ xmlXPtrEval(const xmlChar *str, xmlXPathContextPtr ctx) { "xmlXPtrEval: object(s) left on the eval stack\n", NULL); } - if (ctxt->error != XPATH_EXPRESSION_OK) { + if (ctx->lastError.code != XML_ERR_OK) { xmlXPathFreeObject(res); res = NULL; }
+error: xmlXPathFreeParserContext(ctxt); return(res); } @@ -1535,7 +1542,7 @@ xmlXPtrBuildRangeNodeList(xmlXPathObjectPtr range) { /* Do not copy DTD information */ break; case XML_ENTITY_DECL: - TODO /* handle crossing entities -> stack needed */ + /* TODO: handle crossing entities -> stack needed */ break; case XML_XINCLUDE_START: case XML_XINCLUDE_END: @@ -1543,7 +1550,6 @@ xmlXPtrBuildRangeNodeList(xmlXPathObjectPtr range) { break; case XML_ATTRIBUTE_NODE: /* Humm, should not happen ! */ - STRANGE break; default: tmp = xmlCopyNode(cur, 1); @@ -1551,7 +1557,6 @@ xmlXPtrBuildRangeNodeList(xmlXPathObjectPtr range) { } if (tmp != NULL) { if ((list == NULL) || ((last == NULL) && (parent == NULL))) { - STRANGE return(NULL); } if (last != NULL) @@ -1565,7 +1570,6 @@ xmlXPtrBuildRangeNodeList(xmlXPathObjectPtr range) { * Skip to next node in document order */ if ((list == NULL) || ((last == NULL) && (parent == NULL))) { - STRANGE return(NULL); } cur = xmlXPtrAdvanceNode(cur, NULL); @@ -1994,7 +1998,8 @@ xmlXPtrCoveringRange(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr loc) { } } default: - TODO /* missed one case ??? */ + /* TODO: missed one case ??? */ + break; } return(NULL); } @@ -2141,7 +2146,8 @@ xmlXPtrInsideRange(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr loc) { } } default: - TODO /* missed one case ??? */ + /* TODO: missed one case ??? */ + break; } return(NULL); } @@ -2276,7 +2282,6 @@ found: (cur->type != XML_HTML_DOCUMENT_NODE) && (cur->type != XML_CDATA_SECTION_NODE)) { if (cur->type == XML_ENTITY_REF_NODE) { /* Shouldn't happen */ - TODO goto skip; } goto next; @@ -2350,7 +2355,6 @@ xmlXPtrAdvanceChar(xmlNodePtr *node, int *indx, int bytes) { } if (pos > len) { /* Strange, the indx in the text node is greater than it's len */ - STRANGE pos = len; } if (pos + bytes >= len) {
Why this particular release?