From 4285d9d12828cc6ac3ea4d63a800c1f9a033a071 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Sat, 17 Nov 2012 17:16:11 +0100 Subject: [PATCH] (Android) Add libxml2 - will be heavily cut down/slimmed down - already took out HTML parser and nanohttp/nanoftp webserver --- android/native/jni/Android.mk | 46 +- android/native/libxml2/Copyright | 27 + android/native/libxml2/DOCBparser.c | 305 + android/native/libxml2/NOTICE | 27 + android/native/libxml2/SAX.c | 132 + android/native/libxml2/SAX2.c | 2919 ++ android/native/libxml2/c14n.c | 2232 ++ android/native/libxml2/catalog.c | 3821 ++ android/native/libxml2/chvalid.c | 336 + android/native/libxml2/config.h | 308 + android/native/libxml2/debugXML.c | 3237 ++ android/native/libxml2/dict.c | 1133 + android/native/libxml2/elfgcchack.h | 16314 +++++++++ android/native/libxml2/encoding.c | 3336 ++ android/native/libxml2/entities.c | 1022 + android/native/libxml2/error.c | 979 + android/native/libxml2/globals.c | 1062 + android/native/libxml2/hash.c | 1125 + android/native/libxml2/legacy.c | 1307 + android/native/libxml2/libxml.h | 70 + android/native/libxml2/libxml/DOCBparser.h | 96 + android/native/libxml2/libxml/HTMLparser.h | 18 + android/native/libxml2/libxml/HTMLtree.h | 21 + android/native/libxml2/libxml/SAX.h | 169 + android/native/libxml2/libxml/SAX2.h | 170 + android/native/libxml2/libxml/c14n.h | 126 + android/native/libxml2/libxml/catalog.h | 182 + android/native/libxml2/libxml/chvalid.h | 230 + android/native/libxml2/libxml/debugXML.h | 217 + android/native/libxml2/libxml/dict.h | 69 + android/native/libxml2/libxml/encoding.h | 226 + android/native/libxml2/libxml/entities.h | 150 + android/native/libxml2/libxml/globals.h | 492 + android/native/libxml2/libxml/hash.h | 233 + android/native/libxml2/libxml/list.h | 137 + android/native/libxml2/libxml/nanohttp.h | 16 + android/native/libxml2/libxml/parser.h | 1237 + .../native/libxml2/libxml/parserInternals.h | 602 + android/native/libxml2/libxml/pattern.h | 100 + android/native/libxml2/libxml/relaxng.h | 213 + .../native/libxml2/libxml/schemasInternals.h | 958 + android/native/libxml2/libxml/schematron.h | 142 + android/native/libxml2/libxml/threads.h | 84 + android/native/libxml2/libxml/tree.h | 1252 + android/native/libxml2/libxml/uri.h | 94 + android/native/libxml2/libxml/valid.h | 458 + android/native/libxml2/libxml/xinclude.h | 129 + android/native/libxml2/libxml/xlink.h | 189 + android/native/libxml2/libxml/xmlIO.h | 317 + android/native/libxml2/libxml/xmlautomata.h | 146 + android/native/libxml2/libxml/xmlerror.h | 944 + android/native/libxml2/libxml/xmlexports.h | 162 + android/native/libxml2/libxml/xmlmemory.h | 224 + android/native/libxml2/libxml/xmlmodule.h | 57 + android/native/libxml2/libxml/xmlreader.h | 424 + android/native/libxml2/libxml/xmlregexp.h | 222 + android/native/libxml2/libxml/xmlsave.h | 88 + android/native/libxml2/libxml/xmlschemas.h | 218 + .../native/libxml2/libxml/xmlschemastypes.h | 151 + android/native/libxml2/libxml/xmlstring.h | 140 + android/native/libxml2/libxml/xmlunicode.h | 202 + android/native/libxml2/libxml/xmlversion.h | 449 + android/native/libxml2/libxml/xmlwriter.h | 485 + android/native/libxml2/libxml/xpath.h | 549 + .../native/libxml2/libxml/xpathInternals.h | 630 + android/native/libxml2/libxml/xpointer.h | 114 + android/native/libxml2/list.c | 779 + android/native/libxml2/parser.c | 14979 ++++++++ android/native/libxml2/parserInternals.c | 2162 ++ .../0001-Add-ICU-support-for-libxml.patch | 559 + .../libxml2/patches/XPath_freeing_error.patch | 30 + android/native/libxml2/pattern.c | 2613 ++ android/native/libxml2/relaxng.c | 11032 ++++++ android/native/libxml2/schematron.c | 1785 + android/native/libxml2/threads.c | 1034 + android/native/libxml2/tree.c | 9913 ++++++ android/native/libxml2/trio.c | 6869 ++++ android/native/libxml2/trio.h | 216 + android/native/libxml2/triodef.h | 222 + android/native/libxml2/trionan.c | 914 + android/native/libxml2/trionan.h | 84 + android/native/libxml2/triop.h | 150 + android/native/libxml2/triostr.c | 2106 ++ android/native/libxml2/triostr.h | 144 + android/native/libxml2/uri.c | 2633 ++ android/native/libxml2/valid.c | 7048 ++++ android/native/libxml2/xinclude.c | 2591 ++ android/native/libxml2/xlink.c | 183 + android/native/libxml2/xmlIO.c | 3209 ++ android/native/libxml2/xmlcatalog.c | 614 + android/native/libxml2/xmllint.c | 3646 ++ android/native/libxml2/xmlmemory.c | 1123 + android/native/libxml2/xmlmodule.c | 445 + android/native/libxml2/xmlreader.c | 5766 ++++ android/native/libxml2/xmlregexp.c | 8153 +++++ android/native/libxml2/xmlsave.c | 1951 ++ android/native/libxml2/xmlschemas.c | 28772 ++++++++++++++++ android/native/libxml2/xmlschemastypes.c | 6134 ++++ android/native/libxml2/xmlstring.c | 984 + android/native/libxml2/xmlunicode.c | 3179 ++ android/native/libxml2/xmlwriter.c | 4699 +++ android/native/libxml2/xpath.c | 15228 ++++++++ android/native/libxml2/xpointer.c | 3012 ++ console/griffin/griffin.c | 10 + console/griffin/hook.h | 1 + 105 files changed, 208240 insertions(+), 2 deletions(-) create mode 100644 android/native/libxml2/Copyright create mode 100644 android/native/libxml2/DOCBparser.c create mode 100644 android/native/libxml2/NOTICE create mode 100644 android/native/libxml2/SAX.c create mode 100644 android/native/libxml2/SAX2.c create mode 100644 android/native/libxml2/c14n.c create mode 100644 android/native/libxml2/catalog.c create mode 100755 android/native/libxml2/chvalid.c create mode 100644 android/native/libxml2/config.h create mode 100644 android/native/libxml2/debugXML.c create mode 100644 android/native/libxml2/dict.c create mode 100644 android/native/libxml2/elfgcchack.h create mode 100644 android/native/libxml2/encoding.c create mode 100644 android/native/libxml2/entities.c create mode 100644 android/native/libxml2/error.c create mode 100644 android/native/libxml2/globals.c create mode 100644 android/native/libxml2/hash.c create mode 100644 android/native/libxml2/legacy.c create mode 100644 android/native/libxml2/libxml.h create mode 100644 android/native/libxml2/libxml/DOCBparser.h create mode 100644 android/native/libxml2/libxml/HTMLparser.h create mode 100644 android/native/libxml2/libxml/HTMLtree.h create mode 100644 android/native/libxml2/libxml/SAX.h create mode 100644 android/native/libxml2/libxml/SAX2.h create mode 100644 android/native/libxml2/libxml/c14n.h create mode 100644 android/native/libxml2/libxml/catalog.h create mode 100644 android/native/libxml2/libxml/chvalid.h create mode 100644 android/native/libxml2/libxml/debugXML.h create mode 100644 android/native/libxml2/libxml/dict.h create mode 100644 android/native/libxml2/libxml/encoding.h create mode 100644 android/native/libxml2/libxml/entities.h create mode 100644 android/native/libxml2/libxml/globals.h create mode 100644 android/native/libxml2/libxml/hash.h create mode 100644 android/native/libxml2/libxml/list.h create mode 100644 android/native/libxml2/libxml/nanohttp.h create mode 100644 android/native/libxml2/libxml/parser.h create mode 100644 android/native/libxml2/libxml/parserInternals.h create mode 100644 android/native/libxml2/libxml/pattern.h create mode 100644 android/native/libxml2/libxml/relaxng.h create mode 100644 android/native/libxml2/libxml/schemasInternals.h create mode 100644 android/native/libxml2/libxml/schematron.h create mode 100644 android/native/libxml2/libxml/threads.h create mode 100644 android/native/libxml2/libxml/tree.h create mode 100644 android/native/libxml2/libxml/uri.h create mode 100644 android/native/libxml2/libxml/valid.h create mode 100644 android/native/libxml2/libxml/xinclude.h create mode 100644 android/native/libxml2/libxml/xlink.h create mode 100644 android/native/libxml2/libxml/xmlIO.h create mode 100644 android/native/libxml2/libxml/xmlautomata.h create mode 100644 android/native/libxml2/libxml/xmlerror.h create mode 100644 android/native/libxml2/libxml/xmlexports.h create mode 100644 android/native/libxml2/libxml/xmlmemory.h create mode 100644 android/native/libxml2/libxml/xmlmodule.h create mode 100644 android/native/libxml2/libxml/xmlreader.h create mode 100644 android/native/libxml2/libxml/xmlregexp.h create mode 100644 android/native/libxml2/libxml/xmlsave.h create mode 100644 android/native/libxml2/libxml/xmlschemas.h create mode 100644 android/native/libxml2/libxml/xmlschemastypes.h create mode 100644 android/native/libxml2/libxml/xmlstring.h create mode 100644 android/native/libxml2/libxml/xmlunicode.h create mode 100644 android/native/libxml2/libxml/xmlversion.h create mode 100644 android/native/libxml2/libxml/xmlwriter.h create mode 100644 android/native/libxml2/libxml/xpath.h create mode 100644 android/native/libxml2/libxml/xpathInternals.h create mode 100644 android/native/libxml2/libxml/xpointer.h create mode 100644 android/native/libxml2/list.c create mode 100644 android/native/libxml2/parser.c create mode 100644 android/native/libxml2/parserInternals.c create mode 100644 android/native/libxml2/patches/0001-Add-ICU-support-for-libxml.patch create mode 100644 android/native/libxml2/patches/XPath_freeing_error.patch create mode 100644 android/native/libxml2/pattern.c create mode 100644 android/native/libxml2/relaxng.c create mode 100644 android/native/libxml2/schematron.c create mode 100644 android/native/libxml2/threads.c create mode 100644 android/native/libxml2/tree.c create mode 100644 android/native/libxml2/trio.c create mode 100644 android/native/libxml2/trio.h create mode 100644 android/native/libxml2/triodef.h create mode 100644 android/native/libxml2/trionan.c create mode 100644 android/native/libxml2/trionan.h create mode 100644 android/native/libxml2/triop.h create mode 100644 android/native/libxml2/triostr.c create mode 100644 android/native/libxml2/triostr.h create mode 100644 android/native/libxml2/uri.c create mode 100644 android/native/libxml2/valid.c create mode 100644 android/native/libxml2/xinclude.c create mode 100644 android/native/libxml2/xlink.c create mode 100644 android/native/libxml2/xmlIO.c create mode 100644 android/native/libxml2/xmlcatalog.c create mode 100644 android/native/libxml2/xmllint.c create mode 100644 android/native/libxml2/xmlmemory.c create mode 100644 android/native/libxml2/xmlmodule.c create mode 100644 android/native/libxml2/xmlreader.c create mode 100644 android/native/libxml2/xmlregexp.c create mode 100644 android/native/libxml2/xmlsave.c create mode 100644 android/native/libxml2/xmlschemas.c create mode 100644 android/native/libxml2/xmlschemastypes.c create mode 100644 android/native/libxml2/xmlstring.c create mode 100644 android/native/libxml2/xmlunicode.c create mode 100644 android/native/libxml2/xmlwriter.c create mode 100644 android/native/libxml2/xpath.c create mode 100644 android/native/libxml2/xpointer.c diff --git a/android/native/jni/Android.mk b/android/native/jni/Android.mk index 768cf1c714..d8ed9e79dd 100644 --- a/android/native/jni/Android.mk +++ b/android/native/jni/Android.mk @@ -26,15 +26,57 @@ endif LOCAL_MODULE := retroarch-activity RARCH_PATH := ../../.. -LOCAL_SRC_FILES = $(RARCH_PATH)/console/griffin/griffin.c +LIBXML_PATH := ../libxml2 +LOCAL_LIBXML_SRC_FILES = $(LIBXML_PATH)/c14n.c \ + $(LIBXML_PATH)/catalog.c \ + $(LIBXML_PATH)/chvalid.c \ + $(LIBXML_PATH)/debugXML.c \ + $(LIBXML_PATH)/dict.c \ + $(LIBXML_PATH)/DOCBparser.c \ + $(LIBXML_PATH)/encoding.c \ + $(LIBXML_PATH)/entities.c \ + $(LIBXML_PATH)/error.c \ + $(LIBXML_PATH)/globals.c \ + $(LIBXML_PATH)/hash.c \ + $(LIBXML_PATH)/legacy.c \ + $(LIBXML_PATH)/list.c \ + $(LIBXML_PATH)/parser.c \ + $(LIBXML_PATH)/parserInternals.c \ + $(LIBXML_PATH)/pattern.c \ + $(LIBXML_PATH)/relaxng.c \ + $(LIBXML_PATH)/SAX.c \ + $(LIBXML_PATH)/SAX2.c \ + $(LIBXML_PATH)/schematron.c \ + $(LIBXML_PATH)/threads.c \ + $(LIBXML_PATH)/tree.c \ + $(LIBXML_PATH)/uri.c \ + $(LIBXML_PATH)/valid.c \ + $(LIBXML_PATH)/xinclude.c \ + $(LIBXML_PATH)/xlink.c \ + $(LIBXML_PATH)/xmlIO.c \ + $(LIBXML_PATH)/xmlmemory.c \ + $(LIBXML_PATH)/xmlmodule.c \ + $(LIBXML_PATH)/xmlreader.c \ + $(LIBXML_PATH)/xmlregexp.c \ + $(LIBXML_PATH)/xmlsave.c \ + $(LIBXML_PATH)/xmlschemas.c \ + $(LIBXML_PATH)/xmlschemastypes.c \ + $(LIBXML_PATH)/xmlstring.c \ + $(LIBXML_PATH)/xmlunicode.c \ + $(LIBXML_PATH)/xmlwriter.c \ + $(LIBXML_PATH)/xpath.c \ + $(LIBXML_PATH)/xpointer.c +LOCAL_SRC_FILES = $(RARCH_PATH)/console/griffin/griffin.c $(LOCAL_LIBXML_SRC_FILES) + ifeq ($(PERF_TEST), 1) LOCAL_CFLAGS += -DPERF_TEST endif -LOCAL_CFLAGS += -O3 -fno-stack-protector -funroll-loops -DNDEBUG -DHAVE_GRIFFIN -DANDROID -DHAVE_DYNAMIC -DHAVE_OPENGL -DHAVE_OPENGLES -DHAVE_VID_CONTEXT -DHAVE_OPENGLES2 -DGLSL_DEBUG -DHAVE_GLSL -DHAVE_ZLIB -DINLINE=inline -DLSB_FIRST -DHAVE_THREAD -D__LIBRETRO__ -DHAVE_CONFIGFILE=1 -DRARCH_PERFORMANCE_MODE -DRARCH_GPU_PERFORMANCE_MODE -DPACKAGE_VERSION=\"$(RARCH_VERSION)\" -std=gnu99 +LOCAL_CFLAGS += -O3 -fno-stack-protector -funroll-loops -DNDEBUG -DHAVE_GRIFFIN -DANDROID -DHAVE_DYNAMIC -DHAVE_OPENGL -DHAVE_OPENGLES -DHAVE_VID_CONTEXT -DHAVE_OPENGLES2 -DGLSL_DEBUG -DHAVE_GLSL -DHAVE_XML -DHAVE_ZLIB -DINLINE=inline -DLSB_FIRST -DHAVE_THREAD -D__LIBRETRO__ -DHAVE_CONFIGFILE=1 -DRARCH_PERFORMANCE_MODE -DRARCH_GPU_PERFORMANCE_MODE -DPACKAGE_VERSION=\"$(RARCH_VERSION)\" -std=gnu99 LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -landroid -lEGL -lGLESv2 -llog -ldl -lz +LOCAL_C_INCLUDES += $(LIBXML_PATH) ifeq ($(HAVE_OPENSL), 1) LOCAL_CFLAGS += -DHAVE_SL diff --git a/android/native/libxml2/Copyright b/android/native/libxml2/Copyright new file mode 100644 index 0000000000..417e95531f --- /dev/null +++ b/android/native/libxml2/Copyright @@ -0,0 +1,27 @@ +Except where otherwise noted in the source code (e.g. the files hash.c, +list.c and the trio files, which are covered by a similar licence but +with different Copyright notices) all the files are: + + Copyright (C) 1998-2003 Daniel Veillard. All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is fur- +nished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT- +NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +DANIEL VEILLARD BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CON- +NECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of Daniel Veillard shall not +be used in advertising or otherwise to promote the sale, use or other deal- +ings in this Software without prior written authorization from him. + diff --git a/android/native/libxml2/DOCBparser.c b/android/native/libxml2/DOCBparser.c new file mode 100644 index 0000000000..3573743352 --- /dev/null +++ b/android/native/libxml2/DOCBparser.c @@ -0,0 +1,305 @@ +/* + * DOCBparser.c : an attempt to parse SGML Docbook documents + * + * This is deprecated !!! + * Code removed with release 2.6.0 it was broken. + * The doc are expect to be migrated to XML DocBook + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + */ + +#define IN_LIBXML +#include "libxml.h" +#ifdef LIBXML_DOCB_ENABLED + +#include +#include + +/** + * docbEncodeEntities: + * @out: a pointer to an array of bytes to store the result + * @outlen: the length of @out + * @in: a pointer to an array of UTF-8 chars + * @inlen: the length of @in + * @quoteChar: the quote character to escape (' or ") or zero. + * + * Take a block of UTF-8 chars in and try to convert it to an ASCII + * plus SGML entities block of chars out. + * + * Returns 0 if success, -2 if the transcoding fails, or -1 otherwise + * The value of @inlen after return is the number of octets consumed + * as the return value is positive, else unpredictable. + * The value of @outlen after return is the number of octets consumed. + */ +int +docbEncodeEntities(unsigned char *out ATTRIBUTE_UNUSED, + int *outlen ATTRIBUTE_UNUSED, + const unsigned char *in ATTRIBUTE_UNUSED, + int *inlen ATTRIBUTE_UNUSED, + int quoteChar ATTRIBUTE_UNUSED) +{ + static int deprecated = 0; + + if (!deprecated) { + xmlGenericError(xmlGenericErrorContext, + "docbEncodeEntities() deprecated function reached\n"); + deprecated = 1; + } + return(-1); +} + +/** + * docbParseDocument: + * @ctxt: an SGML parser context + * + * parse an SGML document (and build a tree if using the standard SAX + * interface). + * + * Returns 0, -1 in case of error. the parser context is augmented + * as a result of the parsing. + */ + +int +docbParseDocument(docbParserCtxtPtr ctxt ATTRIBUTE_UNUSED) +{ + static int deprecated = 0; + + if (!deprecated) { + xmlGenericError(xmlGenericErrorContext, + "docbParseDocument() deprecated function reached\n"); + deprecated = 1; + } + return (xmlParseDocument(ctxt)); +} + +/** + * docbFreeParserCtxt: + * @ctxt: an SGML parser context + * + * Free all the memory used by a parser context. However the parsed + * document in ctxt->myDoc is not freed. + */ + +void +docbFreeParserCtxt(docbParserCtxtPtr ctxt ATTRIBUTE_UNUSED) +{ + static int deprecated = 0; + + if (!deprecated) { + xmlGenericError(xmlGenericErrorContext, + "docbFreeParserCtxt() deprecated function reached\n"); + deprecated = 1; + } + xmlFreeParserCtxt(ctxt); +} + +/** + * docbParseChunk: + * @ctxt: an XML parser context + * @chunk: an char array + * @size: the size in byte of the chunk + * @terminate: last chunk indicator + * + * Parse a Chunk of memory + * + * Returns zero if no error, the xmlParserErrors otherwise. + */ +int +docbParseChunk(docbParserCtxtPtr ctxt ATTRIBUTE_UNUSED, + const char *chunk ATTRIBUTE_UNUSED, + int size ATTRIBUTE_UNUSED, + int terminate ATTRIBUTE_UNUSED) +{ + static int deprecated = 0; + + if (!deprecated) { + xmlGenericError(xmlGenericErrorContext, + "docbParseChunk() deprecated function reached\n"); + deprecated = 1; + } + + return (xmlParseChunk(ctxt, chunk, size, terminate)); +} + +/** + * docbCreatePushParserCtxt: + * @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 + * @enc: an optional encoding + * + * Create a parser context for using the DocBook SGML parser in push mode + * To allow content encoding detection, @size should be >= 4 + * The value of @filename is used for fetching external entities + * and error/warning reports. + * + * Returns the new parser context or NULL + */ +docbParserCtxtPtr +docbCreatePushParserCtxt(docbSAXHandlerPtr sax ATTRIBUTE_UNUSED, + void *user_data ATTRIBUTE_UNUSED, + const char *chunk ATTRIBUTE_UNUSED, + int size ATTRIBUTE_UNUSED, + const char *filename ATTRIBUTE_UNUSED, + xmlCharEncoding enc ATTRIBUTE_UNUSED) +{ + static int deprecated = 0; + + if (!deprecated) { + xmlGenericError(xmlGenericErrorContext, + "docbParseChunk() deprecated function reached\n"); + deprecated = 1; + } + + return(xmlCreatePushParserCtxt(sax, user_data, chunk, size, filename)); +} + +/** + * docbSAXParseDoc: + * @cur: a pointer to an array of xmlChar + * @encoding: a free form C string describing the SGML document encoding, or NULL + * @sax: the SAX handler block + * @userData: if using SAX, this pointer will be provided on callbacks. + * + * parse an SGML in-memory document and build a tree. + * It use the given SAX function block to handle the parsing callback. + * If sax is NULL, fallback to the default DOM tree building routines. + * + * Returns the resulting document tree + */ + +docbDocPtr +docbSAXParseDoc(xmlChar * cur ATTRIBUTE_UNUSED, + const char *encoding ATTRIBUTE_UNUSED, + docbSAXHandlerPtr sax ATTRIBUTE_UNUSED, + void *userData ATTRIBUTE_UNUSED) +{ + static int deprecated = 0; + + if (!deprecated) { + xmlGenericError(xmlGenericErrorContext, + "docbParseChunk() deprecated function reached\n"); + deprecated = 1; + } + + return (xmlSAXParseMemoryWithData(sax, (const char *)cur, + xmlStrlen((const xmlChar *) cur), 0, userData)); +} + +/** + * docbParseDoc: + * @cur: a pointer to an array of xmlChar + * @encoding: a free form C string describing the SGML document encoding, or NULL + * + * parse an SGML in-memory document and build a tree. + * + * Returns the resulting document tree + */ + +docbDocPtr +docbParseDoc(xmlChar * cur ATTRIBUTE_UNUSED, + const char *encoding ATTRIBUTE_UNUSED) +{ + static int deprecated = 0; + + if (!deprecated) { + xmlGenericError(xmlGenericErrorContext, + "docbParseChunk() deprecated function reached\n"); + deprecated = 1; + } + + return (xmlParseDoc(cur)); +} + + +/** + * docbCreateFileParserCtxt: + * @filename: the filename + * @encoding: the SGML document encoding, or NULL + * + * 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 + */ +docbParserCtxtPtr +docbCreateFileParserCtxt(const char *filename ATTRIBUTE_UNUSED, + const char *encoding ATTRIBUTE_UNUSED) +{ + static int deprecated = 0; + + if (!deprecated) { + xmlGenericError(xmlGenericErrorContext, + "docbCreateFileParserCtxt() deprecated function reached\n"); + deprecated = 1; + } + + return (xmlCreateFileParserCtxt(filename)); +} + +/** + * docbSAXParseFile: + * @filename: the filename + * @encoding: a free form C string describing the SGML document encoding, or NULL + * @sax: the SAX handler block + * @userData: if using SAX, this pointer will be provided on callbacks. + * + * parse an SGML file and build a tree. Automatic support for ZLIB/Compress + * compressed document is provided by default if found at compile-time. + * It use the given SAX function block to handle the parsing callback. + * If sax is NULL, fallback to the default DOM tree building routines. + * + * Returns the resulting document tree + */ + +docbDocPtr +docbSAXParseFile(const char *filename ATTRIBUTE_UNUSED, + const char *encoding ATTRIBUTE_UNUSED, + docbSAXHandlerPtr sax ATTRIBUTE_UNUSED, + void *userData ATTRIBUTE_UNUSED) +{ + static int deprecated = 0; + + if (!deprecated) { + xmlGenericError(xmlGenericErrorContext, + "docbSAXParseFile() deprecated function reached\n"); + deprecated = 1; + } + + return (xmlSAXParseFileWithData(sax, filename, 0, userData)); +} + +/** + * docbParseFile: + * @filename: the filename + * @encoding: a free form C string describing document encoding, or NULL + * + * parse a Docbook SGML file and build a tree. Automatic support for + * ZLIB/Compress compressed document is provided by default if found + * at compile-time. + * + * Returns the resulting document tree + */ + +docbDocPtr +docbParseFile(const char *filename ATTRIBUTE_UNUSED, + const char *encoding ATTRIBUTE_UNUSED) +{ + static int deprecated = 0; + + if (!deprecated) { + xmlGenericError(xmlGenericErrorContext, + "docbParseFile() deprecated function reached\n"); + deprecated = 1; + } + + return (xmlParseFile(filename)); +} +#define bottom_DOCBparser +#include "elfgcchack.h" +#endif /* LIBXML_DOCB_ENABLED */ diff --git a/android/native/libxml2/NOTICE b/android/native/libxml2/NOTICE new file mode 100644 index 0000000000..417e95531f --- /dev/null +++ b/android/native/libxml2/NOTICE @@ -0,0 +1,27 @@ +Except where otherwise noted in the source code (e.g. the files hash.c, +list.c and the trio files, which are covered by a similar licence but +with different Copyright notices) all the files are: + + Copyright (C) 1998-2003 Daniel Veillard. All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is fur- +nished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT- +NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +DANIEL VEILLARD BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CON- +NECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of Daniel Veillard shall not +be used in advertising or otherwise to promote the sale, use or other deal- +ings in this Software without prior written authorization from him. + diff --git a/android/native/libxml2/SAX.c b/android/native/libxml2/SAX.c new file mode 100644 index 0000000000..4eebd9cbd3 --- /dev/null +++ b/android/native/libxml2/SAX.c @@ -0,0 +1,132 @@ +/* + * SAX.c : Old SAX v1 handlers to build a tree. + * Deprecated except for compatibility + * + * See Copyright for the status of this software. + * + * Daniel Veillard + */ + + +#define IN_LIBXML +#include "libxml.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef LIBXML_LEGACY_ENABLED +#ifdef LIBXML_SAX1_ENABLED +/** + * initxmlDefaultSAXHandler: + * @hdlr: the SAX handler + * @warning: flag if non-zero sets the handler warning procedure + * + * Initialize the default XML SAX version 1 handler + * DEPRECATED: use xmlSAX2InitDefaultSAXHandler() for the new SAX2 blocks + */ +void +initxmlDefaultSAXHandler(xmlSAXHandlerV1 *hdlr, int warning) +{ + + if(hdlr->initialized == 1) + return; + + hdlr->internalSubset = xmlSAX2InternalSubset; + hdlr->externalSubset = xmlSAX2ExternalSubset; + hdlr->isStandalone = xmlSAX2IsStandalone; + hdlr->hasInternalSubset = xmlSAX2HasInternalSubset; + hdlr->hasExternalSubset = xmlSAX2HasExternalSubset; + hdlr->resolveEntity = xmlSAX2ResolveEntity; + hdlr->getEntity = xmlSAX2GetEntity; + hdlr->getParameterEntity = xmlSAX2GetParameterEntity; + hdlr->entityDecl = xmlSAX2EntityDecl; + hdlr->attributeDecl = xmlSAX2AttributeDecl; + hdlr->elementDecl = xmlSAX2ElementDecl; + hdlr->notationDecl = xmlSAX2NotationDecl; + hdlr->unparsedEntityDecl = xmlSAX2UnparsedEntityDecl; + hdlr->setDocumentLocator = xmlSAX2SetDocumentLocator; + hdlr->startDocument = xmlSAX2StartDocument; + hdlr->endDocument = xmlSAX2EndDocument; + hdlr->startElement = xmlSAX2StartElement; + hdlr->endElement = xmlSAX2EndElement; + hdlr->reference = xmlSAX2Reference; + hdlr->characters = xmlSAX2Characters; + hdlr->cdataBlock = xmlSAX2CDataBlock; + hdlr->ignorableWhitespace = xmlSAX2Characters; + hdlr->processingInstruction = xmlSAX2ProcessingInstruction; + if (warning == 0) + hdlr->warning = NULL; + else + hdlr->warning = xmlParserWarning; + hdlr->error = xmlParserError; + hdlr->fatalError = xmlParserError; + + hdlr->initialized = 1; +} + +#ifdef LIBXML_DOCB_ENABLED +/** + * initdocbDefaultSAXHandler: + * @hdlr: the SAX handler + * + * Initialize the default DocBook SAX version 1 handler + * DEPRECATED: use xmlSAX2InitDocbDefaultSAXHandler() for the new SAX2 blocks + */ +void +initdocbDefaultSAXHandler(xmlSAXHandlerV1 *hdlr) +{ + if(hdlr->initialized == 1) + return; + + hdlr->internalSubset = xmlSAX2InternalSubset; + hdlr->externalSubset = NULL; + hdlr->isStandalone = xmlSAX2IsStandalone; + hdlr->hasInternalSubset = xmlSAX2HasInternalSubset; + hdlr->hasExternalSubset = xmlSAX2HasExternalSubset; + hdlr->resolveEntity = xmlSAX2ResolveEntity; + hdlr->getEntity = xmlSAX2GetEntity; + hdlr->getParameterEntity = NULL; + hdlr->entityDecl = xmlSAX2EntityDecl; + hdlr->attributeDecl = NULL; + hdlr->elementDecl = NULL; + hdlr->notationDecl = NULL; + hdlr->unparsedEntityDecl = NULL; + hdlr->setDocumentLocator = xmlSAX2SetDocumentLocator; + hdlr->startDocument = xmlSAX2StartDocument; + hdlr->endDocument = xmlSAX2EndDocument; + hdlr->startElement = xmlSAX2StartElement; + hdlr->endElement = xmlSAX2EndElement; + hdlr->reference = xmlSAX2Reference; + hdlr->characters = xmlSAX2Characters; + hdlr->cdataBlock = NULL; + hdlr->ignorableWhitespace = xmlSAX2IgnorableWhitespace; + hdlr->processingInstruction = NULL; + hdlr->comment = xmlSAX2Comment; + hdlr->warning = xmlParserWarning; + hdlr->error = xmlParserError; + hdlr->fatalError = xmlParserError; + + hdlr->initialized = 1; +} + +#endif /* LIBXML_DOCB_ENABLED */ + +#endif /* LIBXML_SAX1_ENABLED */ + +#define bottom_SAX +#include "elfgcchack.h" +#endif /* LIBXML_LEGACY_ENABLED */ diff --git a/android/native/libxml2/SAX2.c b/android/native/libxml2/SAX2.c new file mode 100644 index 0000000000..b878beb547 --- /dev/null +++ b/android/native/libxml2/SAX2.c @@ -0,0 +1,2919 @@ +/* + * SAX2.c : Default SAX2 handler to build a tree. + * + * See Copyright for the status of this software. + * + * Daniel Veillard + */ + + +#define IN_LIBXML +#include "libxml.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Define SIZE_T_MAX unless defined through . */ +#ifndef SIZE_T_MAX +# define SIZE_T_MAX ((size_t)-1) +#endif /* !SIZE_T_MAX */ + +/* #define DEBUG_SAX2 */ +/* #define DEBUG_SAX2_TREE */ + +/** + * TODO: + * + * macro to flag unimplemented blocks + * XML_CATALOG_PREFER user env to select between system/public prefered + * option. C.f. Richard Tobin + *> 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__); + +/* + * xmlSAX2ErrMemory: + * @ctxt: an XML validation parser context + * @msg: a string to accompany the error message + */ +static void +xmlSAX2ErrMemory(xmlParserCtxtPtr ctxt, const char *msg) { + if (ctxt != NULL) { + if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL)) + ctxt->sax->error(ctxt->userData, "%s: out of memory\n", msg); + ctxt->errNo = XML_ERR_NO_MEMORY; + ctxt->instate = XML_PARSER_EOF; + ctxt->disableSAX = 1; + } +} + +/** + * xmlValidError: + * @ctxt: an XML validation parser context + * @error: the error number + * @msg: the error message + * @str1: extra data + * @str2: extra data + * + * Handle a validation error + */ +static void +xmlErrValid(xmlParserCtxtPtr ctxt, xmlParserErrors error, + const char *msg, const char *str1, const char *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); + 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); + } +} + +/** + * xmlFatalErrMsg: + * @ctxt: an XML parser context + * @error: the error number + * @msg: the error message + * @str1: an error string + * @str2: an error string + * + * Handle a fatal parser error, i.e. violating Well-Formedness constraints + */ +static void +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; + } +} + +/** + * xmlWarnMsg: + * @ctxt: an XML parser context + * @error: the error number + * @msg: the error message + * @str1: an error string + * @str2: an error string + * + * Handle a parser warning + */ +static void +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); +} + +/** + * xmlNsErrMsg: + * @ctxt: an XML parser context + * @error: the error number + * @msg: the error message + * @str1: an error string + * @str2: an error string + * + * Handle a namespace error + */ +static void +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); +} + +/** + * xmlNsWarnMsg: + * @ctxt: an XML parser context + * @error: the error number + * @msg: the error message + * @str1: an error string + * + * Handle a namespace warning + */ +static void +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); +} + +/** + * xmlSAX2GetPublicId: + * @ctx: the user data (XML parser context) + * + * Provides the public ID e.g. "-//SGMLSOURCE//DTD DEMO//EN" + * + * Returns a xmlChar * + */ +const xmlChar * +xmlSAX2GetPublicId(void *ctx ATTRIBUTE_UNUSED) +{ + /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */ + return(NULL); +} + +/** + * xmlSAX2GetSystemId: + * @ctx: the user data (XML parser context) + * + * Provides the system ID, basically URL or filename e.g. + * http://www.sgmlsource.com/dtds/memo.dtd + * + * Returns a xmlChar * + */ +const xmlChar * +xmlSAX2GetSystemId(void *ctx) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + if ((ctx == NULL) || (ctxt->input == NULL)) return(NULL); + return((const xmlChar *) ctxt->input->filename); +} + +/** + * xmlSAX2GetLineNumber: + * @ctx: the user data (XML parser context) + * + * Provide the line number of the current parsing point. + * + * Returns an int + */ +int +xmlSAX2GetLineNumber(void *ctx) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + if ((ctx == NULL) || (ctxt->input == NULL)) return(0); + return(ctxt->input->line); +} + +/** + * xmlSAX2GetColumnNumber: + * @ctx: the user data (XML parser context) + * + * Provide the column number of the current parsing point. + * + * Returns an int + */ +int +xmlSAX2GetColumnNumber(void *ctx) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + if ((ctx == NULL) || (ctxt->input == NULL)) return(0); + return(ctxt->input->col); +} + +/** + * xmlSAX2IsStandalone: + * @ctx: the user data (XML parser context) + * + * Is this document tagged standalone ? + * + * Returns 1 if true + */ +int +xmlSAX2IsStandalone(void *ctx) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + if ((ctx == NULL) || (ctxt->myDoc == NULL)) return(0); + return(ctxt->myDoc->standalone == 1); +} + +/** + * xmlSAX2HasInternalSubset: + * @ctx: the user data (XML parser context) + * + * Does this document has an internal subset + * + * Returns 1 if true + */ +int +xmlSAX2HasInternalSubset(void *ctx) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + if ((ctxt == NULL) || (ctxt->myDoc == NULL)) return(0); + return(ctxt->myDoc->intSubset != NULL); +} + +/** + * xmlSAX2HasExternalSubset: + * @ctx: the user data (XML parser context) + * + * Does this document has an external subset + * + * Returns 1 if true + */ +int +xmlSAX2HasExternalSubset(void *ctx) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + if ((ctxt == NULL) || (ctxt->myDoc == NULL)) return(0); + return(ctxt->myDoc->extSubset != NULL); +} + +/** + * xmlSAX2InternalSubset: + * @ctx: the user data (XML parser context) + * @name: the root element name + * @ExternalID: the external ID + * @SystemID: the SYSTEM ID (e.g. filename or URL) + * + * Callback on internal subset declaration. + */ +void +xmlSAX2InternalSubset(void *ctx, const xmlChar *name, + const xmlChar *ExternalID, const xmlChar *SystemID) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + xmlDtdPtr dtd; + if (ctx == NULL) return; +#ifdef DEBUG_SAX + xmlGenericError(xmlGenericErrorContext, + "SAX.xmlSAX2InternalSubset(%s, %s, %s)\n", + name, ExternalID, SystemID); +#endif + + if (ctxt->myDoc == NULL) + return; + dtd = xmlGetIntSubset(ctxt->myDoc); + if (dtd != NULL) { + if (ctxt->html) + return; + xmlUnlinkNode((xmlNodePtr) dtd); + xmlFreeDtd(dtd); + ctxt->myDoc->intSubset = NULL; + } + ctxt->myDoc->intSubset = + xmlCreateIntSubset(ctxt->myDoc, name, ExternalID, SystemID); + if (ctxt->myDoc->intSubset == NULL) + xmlSAX2ErrMemory(ctxt, "xmlSAX2InternalSubset"); +} + +/** + * xmlSAX2ExternalSubset: + * @ctx: the user data (XML parser context) + * @name: the root element name + * @ExternalID: the external ID + * @SystemID: the SYSTEM ID (e.g. filename or URL) + * + * Callback on external subset declaration. + */ +void +xmlSAX2ExternalSubset(void *ctx, const xmlChar *name, + const xmlChar *ExternalID, const xmlChar *SystemID) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + if (ctx == NULL) return; +#ifdef DEBUG_SAX + xmlGenericError(xmlGenericErrorContext, + "SAX.xmlSAX2ExternalSubset(%s, %s, %s)\n", + name, ExternalID, SystemID); +#endif + if (((ExternalID != NULL) || (SystemID != NULL)) && + (((ctxt->validate) || (ctxt->loadsubset != 0)) && + (ctxt->wellFormed && ctxt->myDoc))) { + /* + * Try to fetch and parse the external subset. + */ + xmlParserInputPtr oldinput; + int oldinputNr; + int oldinputMax; + xmlParserInputPtr *oldinputTab; + xmlParserInputPtr input = NULL; + xmlCharEncoding enc; + int oldcharset; + + /* + * Ask the Entity resolver to load the damn thing + */ + if ((ctxt->sax != NULL) && (ctxt->sax->resolveEntity != NULL)) + input = ctxt->sax->resolveEntity(ctxt->userData, ExternalID, + SystemID); + if (input == NULL) { + return; + } + + xmlNewDtd(ctxt->myDoc, name, ExternalID, SystemID); + + /* + * make sure we won't destroy the main document context + */ + oldinput = ctxt->input; + oldinputNr = ctxt->inputNr; + oldinputMax = ctxt->inputMax; + oldinputTab = ctxt->inputTab; + oldcharset = ctxt->charset; + + ctxt->inputTab = (xmlParserInputPtr *) + xmlMalloc(5 * sizeof(xmlParserInputPtr)); + if (ctxt->inputTab == NULL) { + xmlSAX2ErrMemory(ctxt, "xmlSAX2ExternalSubset"); + ctxt->input = oldinput; + ctxt->inputNr = oldinputNr; + ctxt->inputMax = oldinputMax; + ctxt->inputTab = oldinputTab; + ctxt->charset = oldcharset; + return; + } + ctxt->inputNr = 0; + ctxt->inputMax = 5; + ctxt->input = NULL; + xmlPushInput(ctxt, input); + + /* + * On the fly encoding conversion if needed + */ + if (ctxt->input->length >= 4) { + enc = xmlDetectCharEncoding(ctxt->input->cur, 4); + xmlSwitchEncoding(ctxt, enc); + } + + if (input->filename == NULL) + input->filename = (char *) xmlCanonicPath(SystemID); + input->line = 1; + input->col = 1; + input->base = ctxt->input->cur; + input->cur = ctxt->input->cur; + input->free = NULL; + + /* + * let's parse that entity knowing it's an external subset. + */ + xmlParseExternalSubset(ctxt, ExternalID, SystemID); + + /* + * Free up the external entities + */ + + while (ctxt->inputNr > 1) + xmlPopInput(ctxt); + xmlFreeInputStream(ctxt->input); + xmlFree(ctxt->inputTab); + + /* + * Restore the parsing context of the main entity + */ + ctxt->input = oldinput; + ctxt->inputNr = oldinputNr; + ctxt->inputMax = oldinputMax; + ctxt->inputTab = oldinputTab; + ctxt->charset = oldcharset; + /* ctxt->wellFormed = oldwellFormed; */ + } +} + +/** + * xmlSAX2ResolveEntity: + * @ctx: the user data (XML parser context) + * @publicId: The public ID of the entity + * @systemId: The system ID of the entity + * + * The entity loader, to control the loading of external entities, + * the application can either: + * - override this xmlSAX2ResolveEntity() callback in the SAX block + * - or better use the xmlSetExternalEntityLoader() function to + * set up it's own entity resolution routine + * + * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour. + */ +xmlParserInputPtr +xmlSAX2ResolveEntity(void *ctx, const xmlChar *publicId, const xmlChar *systemId) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + xmlParserInputPtr ret; + xmlChar *URI; + const char *base = 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); + +#ifdef DEBUG_SAX + xmlGenericError(xmlGenericErrorContext, + "SAX.xmlSAX2ResolveEntity(%s, %s)\n", publicId, systemId); +#endif + + ret = xmlLoadExternalEntity((const char *) URI, + (const char *) publicId, ctxt); + if (URI != NULL) + xmlFree(URI); + return(ret); +} + +/** + * xmlSAX2GetEntity: + * @ctx: the user data (XML parser context) + * @name: The entity name + * + * Get an entity by name + * + * Returns the xmlEntityPtr if found. + */ +xmlEntityPtr +xmlSAX2GetEntity(void *ctx, const xmlChar *name) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + xmlEntityPtr ret = NULL; + + if (ctx == NULL) return(NULL); +#ifdef DEBUG_SAX + xmlGenericError(xmlGenericErrorContext, + "SAX.xmlSAX2GetEntity(%s)\n", name); +#endif + + if (ctxt->inSubset == 0) { + ret = xmlGetPredefinedEntity(name); + if (ret != NULL) + return(ret); + } + if ((ctxt->myDoc != NULL) && (ctxt->myDoc->standalone == 1)) { + if (ctxt->inSubset == 2) { + ctxt->myDoc->standalone = 0; + ret = xmlGetDocEntity(ctxt->myDoc, name); + ctxt->myDoc->standalone = 1; + } else { + ret = xmlGetDocEntity(ctxt->myDoc, name); + if (ret == NULL) { + ctxt->myDoc->standalone = 0; + ret = xmlGetDocEntity(ctxt->myDoc, name); + if (ret != NULL) { + xmlFatalErrMsg(ctxt, XML_ERR_NOT_STANDALONE, + "Entity(%s) document marked standalone but requires external subset\n", + name, NULL); + } + ctxt->myDoc->standalone = 1; + } + } + } else { + ret = xmlGetDocEntity(ctxt->myDoc, name); + } + if ((ret != NULL) && + ((ctxt->validate) || (ctxt->replaceEntities)) && + (ret->children == NULL) && + (ret->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY)) { + int val; + + /* + * for validation purposes we really need to fetch and + * parse the external entity + */ + xmlNodePtr children; + + val = xmlParseCtxtExternalEntity(ctxt, ret->URI, + ret->ExternalID, &children); + if (val == 0) { + xmlAddChildList((xmlNodePtr) ret, children); + } else { + xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_PROCESSING, + "Failure to process entity %s\n", name, NULL); + ctxt->validate = 0; + return(NULL); + } + ret->owner = 1; + if (ret->checked == 0) + ret->checked = 1; + } + return(ret); +} + +/** + * xmlSAX2GetParameterEntity: + * @ctx: the user data (XML parser context) + * @name: The entity name + * + * Get a parameter entity by name + * + * Returns the xmlEntityPtr if found. + */ +xmlEntityPtr +xmlSAX2GetParameterEntity(void *ctx, const xmlChar *name) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + xmlEntityPtr ret; + + if (ctx == NULL) return(NULL); +#ifdef DEBUG_SAX + xmlGenericError(xmlGenericErrorContext, + "SAX.xmlSAX2GetParameterEntity(%s)\n", name); +#endif + + ret = xmlGetParameterEntity(ctxt->myDoc, name); + return(ret); +} + + +/** + * xmlSAX2EntityDecl: + * @ctx: the user data (XML parser context) + * @name: the entity name + * @type: the entity type + * @publicId: The public ID of the entity + * @systemId: The system ID of the entity + * @content: the entity value (without processing). + * + * An entity definition has been parsed + */ +void +xmlSAX2EntityDecl(void *ctx, const xmlChar *name, int type, + const xmlChar *publicId, const xmlChar *systemId, xmlChar *content) +{ + xmlEntityPtr ent; + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + + if (ctx == NULL) return; +#ifdef DEBUG_SAX + xmlGenericError(xmlGenericErrorContext, + "SAX.xmlSAX2EntityDecl(%s, %d, %s, %s, %s)\n", + name, type, publicId, systemId, content); +#endif + 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); + } +} + +/** + * xmlSAX2AttributeDecl: + * @ctx: the user data (XML parser context) + * @elem: the name of the element + * @fullname: the attribute name + * @type: the attribute type + * @def: the type of default value + * @defaultValue: the attribute default value + * @tree: the tree of enumerated value set + * + * An attribute definition has been parsed + */ +void +xmlSAX2AttributeDecl(void *ctx, const xmlChar *elem, const xmlChar *fullname, + int type, int def, const xmlChar *defaultValue, + xmlEnumerationPtr tree) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + xmlAttributePtr attr; + xmlChar *name = NULL, *prefix = NULL; + + if ((ctxt == NULL) || (ctxt->myDoc == NULL)) + return; + +#ifdef DEBUG_SAX + xmlGenericError(xmlGenericErrorContext, + "SAX.xmlSAX2AttributeDecl(%s, %s, %d, %d, %s, ...)\n", + elem, fullname, type, def, defaultValue); +#endif + if ((xmlStrEqual(fullname, BAD_CAST "xml:id")) && + (type != XML_ATTRIBUTE_ID)) { + /* + * Raise the error but keep the validity flag + */ + int tmp = ctxt->valid; + xmlErrValid(ctxt, XML_DTD_XMLID_TYPE, + "xml:id : attribute type should be ID\n", NULL, NULL); + ctxt->valid = tmp; + } + /* TODO: optimize name/prefix allocation */ + name = xmlSplitQName(ctxt, fullname, &prefix); + ctxt->vctxt.valid = 1; + if (ctxt->inSubset == 1) + attr = xmlAddAttributeDecl(&ctxt->vctxt, ctxt->myDoc->intSubset, elem, + name, prefix, (xmlAttributeType) type, + (xmlAttributeDefault) def, defaultValue, tree); + else if (ctxt->inSubset == 2) + attr = xmlAddAttributeDecl(&ctxt->vctxt, ctxt->myDoc->extSubset, elem, + name, prefix, (xmlAttributeType) type, + (xmlAttributeDefault) def, defaultValue, tree); + else { + xmlFatalErrMsg(ctxt, XML_ERR_INTERNAL_ERROR, + "SAX.xmlSAX2AttributeDecl(%s) called while not in subset\n", + name, NULL); + xmlFreeEnumeration(tree); + return; + } +#ifdef LIBXML_VALID_ENABLED + if (ctxt->vctxt.valid == 0) + ctxt->valid = 0; + if ((attr != NULL) && (ctxt->validate) && (ctxt->wellFormed) && + (ctxt->myDoc->intSubset != NULL)) + ctxt->valid &= xmlValidateAttributeDecl(&ctxt->vctxt, ctxt->myDoc, + attr); +#endif /* LIBXML_VALID_ENABLED */ + if (prefix != NULL) + xmlFree(prefix); + if (name != NULL) + xmlFree(name); +} + +/** + * xmlSAX2ElementDecl: + * @ctx: the user data (XML parser context) + * @name: the element name + * @type: the element type + * @content: the element value tree + * + * An element definition has been parsed + */ +void +xmlSAX2ElementDecl(void *ctx, const xmlChar * name, int type, + xmlElementContentPtr content) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + xmlElementPtr elem = NULL; + + if ((ctxt == NULL) || (ctxt->myDoc == NULL)) + return; + +#ifdef DEBUG_SAX + xmlGenericError(xmlGenericErrorContext, + "SAX.xmlSAX2ElementDecl(%s, %d, ...)\n", name, type); +#endif + + if (ctxt->inSubset == 1) + elem = xmlAddElementDecl(&ctxt->vctxt, ctxt->myDoc->intSubset, + name, (xmlElementTypeVal) type, content); + else if (ctxt->inSubset == 2) + elem = xmlAddElementDecl(&ctxt->vctxt, ctxt->myDoc->extSubset, + name, (xmlElementTypeVal) type, content); + else { + xmlFatalErrMsg(ctxt, XML_ERR_INTERNAL_ERROR, + "SAX.xmlSAX2ElementDecl(%s) called while not in subset\n", + name, NULL); + return; + } +#ifdef LIBXML_VALID_ENABLED + if (elem == NULL) + ctxt->valid = 0; + if (ctxt->validate && ctxt->wellFormed && + ctxt->myDoc && ctxt->myDoc->intSubset) + ctxt->valid &= + xmlValidateElementDecl(&ctxt->vctxt, ctxt->myDoc, elem); +#endif /* LIBXML_VALID_ENABLED */ +} + +/** + * xmlSAX2NotationDecl: + * @ctx: the user data (XML parser context) + * @name: The name of the notation + * @publicId: The public ID of the entity + * @systemId: The system ID of the entity + * + * What to do when a notation declaration has been parsed. + */ +void +xmlSAX2NotationDecl(void *ctx, const xmlChar *name, + const xmlChar *publicId, const xmlChar *systemId) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + xmlNotationPtr nota = NULL; + + if ((ctxt == NULL) || (ctxt->myDoc == NULL)) + return; + +#ifdef DEBUG_SAX + xmlGenericError(xmlGenericErrorContext, + "SAX.xmlSAX2NotationDecl(%s, %s, %s)\n", name, publicId, systemId); +#endif + + if ((publicId == NULL) && (systemId == NULL)) { + xmlFatalErrMsg(ctxt, XML_ERR_NOTATION_PROCESSING, + "SAX.xmlSAX2NotationDecl(%s) externalID or PublicID missing\n", + name, NULL); + return; + } else if (ctxt->inSubset == 1) + nota = xmlAddNotationDecl(&ctxt->vctxt, ctxt->myDoc->intSubset, name, + publicId, systemId); + else if (ctxt->inSubset == 2) + nota = xmlAddNotationDecl(&ctxt->vctxt, ctxt->myDoc->extSubset, name, + publicId, systemId); + else { + xmlFatalErrMsg(ctxt, XML_ERR_NOTATION_PROCESSING, + "SAX.xmlSAX2NotationDecl(%s) called while not in subset\n", + name, NULL); + return; + } +#ifdef LIBXML_VALID_ENABLED + if (nota == NULL) ctxt->valid = 0; + if ((ctxt->validate) && (ctxt->wellFormed) && + (ctxt->myDoc->intSubset != NULL)) + ctxt->valid &= xmlValidateNotationDecl(&ctxt->vctxt, ctxt->myDoc, + nota); +#endif /* LIBXML_VALID_ENABLED */ +} + +/** + * xmlSAX2UnparsedEntityDecl: + * @ctx: the user data (XML parser context) + * @name: The name of the entity + * @publicId: The public ID of the entity + * @systemId: The system ID of the entity + * @notationName: the name of the notation + * + * What to do when an unparsed entity declaration is parsed + */ +void +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; +#ifdef DEBUG_SAX + xmlGenericError(xmlGenericErrorContext, + "SAX.xmlSAX2UnparsedEntityDecl(%s, %s, %s, %s)\n", + name, publicId, systemId, notationName); +#endif + 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); + } +} + +/** + * xmlSAX2SetDocumentLocator: + * @ctx: the user data (XML parser context) + * @loc: A SAX Locator + * + * Receive the document locator at startup, actually xmlDefaultSAXLocator + * Everything is available on the context, so this is useless in our case. + */ +void +xmlSAX2SetDocumentLocator(void *ctx ATTRIBUTE_UNUSED, xmlSAXLocatorPtr loc ATTRIBUTE_UNUSED) +{ + /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */ +#ifdef DEBUG_SAX + xmlGenericError(xmlGenericErrorContext, + "SAX.xmlSAX2SetDocumentLocator()\n"); +#endif +} + +/** + * xmlSAX2StartDocument: + * @ctx: the user data (XML parser context) + * + * called when the document start being processed. + */ +void +xmlSAX2StartDocument(void *ctx) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + xmlDocPtr doc; + + if (ctx == NULL) return; + +#ifdef DEBUG_SAX + xmlGenericError(xmlGenericErrorContext, + "SAX.xmlSAX2StartDocument()\n"); +#endif + if (ctxt->html) { + xmlGenericError(xmlGenericErrorContext, + "libxml2 built without HTML support\n"); + ctxt->errNo = XML_ERR_INTERNAL_ERROR; + ctxt->instate = XML_PARSER_EOF; + ctxt->disableSAX = 1; + return; + } else { + doc = ctxt->myDoc = xmlNewDoc(ctxt->version); + if (doc != NULL) { + doc->properties = 0; + if (ctxt->options & XML_PARSE_OLD10) + doc->properties |= XML_DOC_OLD10; + doc->parseFlags = ctxt->options; + if (ctxt->encoding != NULL) + doc->encoding = xmlStrdup(ctxt->encoding); + else + doc->encoding = NULL; + doc->standalone = ctxt->standalone; + } else { + xmlSAX2ErrMemory(ctxt, "xmlSAX2StartDocument"); + return; + } + if ((ctxt->dictNames) && (doc != NULL)) { + doc->dict = ctxt->dict; + xmlDictReference(doc->dict); + } + } + if ((ctxt->myDoc != NULL) && (ctxt->myDoc->URL == NULL) && + (ctxt->input != NULL) && (ctxt->input->filename != NULL)) { + ctxt->myDoc->URL = xmlPathToURI((const xmlChar *)ctxt->input->filename); + if (ctxt->myDoc->URL == NULL) + xmlSAX2ErrMemory(ctxt, "xmlSAX2StartDocument"); + } +} + +/** + * xmlSAX2EndDocument: + * @ctx: the user data (XML parser context) + * + * called when the document end has been detected. + */ +void +xmlSAX2EndDocument(void *ctx) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; +#ifdef DEBUG_SAX + xmlGenericError(xmlGenericErrorContext, + "SAX.xmlSAX2EndDocument()\n"); +#endif + if (ctx == NULL) return; +#ifdef LIBXML_VALID_ENABLED + if (ctxt->validate && ctxt->wellFormed && + ctxt->myDoc && ctxt->myDoc->intSubset) + ctxt->valid &= xmlValidateDocumentFinal(&ctxt->vctxt, ctxt->myDoc); +#endif /* LIBXML_VALID_ENABLED */ + + /* + * Grab the encoding if it was added on-the-fly + */ + if ((ctxt->encoding != NULL) && (ctxt->myDoc != NULL) && + (ctxt->myDoc->encoding == NULL)) { + ctxt->myDoc->encoding = ctxt->encoding; + ctxt->encoding = NULL; + } + if ((ctxt->inputTab != NULL) && + (ctxt->inputNr > 0) && (ctxt->inputTab[0] != NULL) && + (ctxt->inputTab[0]->encoding != NULL) && (ctxt->myDoc != NULL) && + (ctxt->myDoc->encoding == NULL)) { + ctxt->myDoc->encoding = xmlStrdup(ctxt->inputTab[0]->encoding); + } + if ((ctxt->charset != XML_CHAR_ENCODING_NONE) && (ctxt->myDoc != NULL) && + (ctxt->myDoc->charset == XML_CHAR_ENCODING_NONE)) { + ctxt->myDoc->charset = ctxt->charset; + } +} + +#if defined(LIBXML_SAX1_ENABLED) || defined(LIBXML_WRITER_ENABLED) || defined(LIBXML_DOCB_ENABLED) +/** + * xmlSAX2AttributeInternal: + * @ctx: the user data (XML parser context) + * @fullname: The attribute name, including namespace prefix + * @value: The attribute value + * @prefix: the prefix on the element node + * + * Handle an attribute that has been read by the parser. + * The default handling is to convert the attribute into an + * DOM subtree and past it in a new xmlAttr element added to + * the element. + */ +static void +xmlSAX2AttributeInternal(void *ctx, const xmlChar *fullname, + const xmlChar *value, const xmlChar *prefix ATTRIBUTE_UNUSED) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + xmlAttrPtr ret; + xmlChar *name; + xmlChar *ns; + xmlChar *nval; + xmlNsPtr namespace; + + if (ctxt->html) { + name = xmlStrdup(fullname); + ns = NULL; + namespace = NULL; + } else { + /* + * Split the full name into a namespace prefix and the tag name + */ + name = xmlSplitQName(ctxt, fullname, &ns); + if ((name != NULL) && (name[0] == 0)) { + if (xmlStrEqual(ns, BAD_CAST "xmlns")) { + xmlNsErrMsg(ctxt, XML_ERR_NS_DECL_ERROR, + "invalid namespace declaration '%s'\n", + fullname, NULL); + } else { + xmlNsWarnMsg(ctxt, XML_WAR_NS_COLUMN, + "Avoid attribute ending with ':' like '%s'\n", + fullname, NULL); + } + if (ns != NULL) + xmlFree(ns); + ns = NULL; + xmlFree(name); + name = xmlStrdup(fullname); + } + } + if (name == NULL) { + xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElement"); + if (ns != NULL) + xmlFree(ns); + return; + } + + { +#ifdef LIBXML_VALID_ENABLED + /* + * Do the last stage of the attribute normalization + * Needed for HTML too: + * http://www.w3.org/TR/html4/types.html#h-6.2 + */ + ctxt->vctxt.valid = 1; + nval = xmlValidCtxtNormalizeAttributeValue(&ctxt->vctxt, + ctxt->myDoc, ctxt->node, + fullname, value); + if (ctxt->vctxt.valid != 1) { + ctxt->valid = 0; + } + if (nval != NULL) + value = nval; +#else + nval = NULL; +#endif /* LIBXML_VALID_ENABLED */ + } + + /* + * Check whether it's a namespace definition + */ + if ((!ctxt->html) && (ns == NULL) && + (name[0] == 'x') && (name[1] == 'm') && (name[2] == 'l') && + (name[3] == 'n') && (name[4] == 's') && (name[5] == 0)) { + xmlNsPtr nsret; + xmlChar *val; + + if (!ctxt->replaceEntities) { + ctxt->depth++; + val = xmlStringDecodeEntities(ctxt, value, XML_SUBSTITUTE_REF, + 0,0,0); + ctxt->depth--; + } else { + val = (xmlChar *) value; + } + + if (val[0] != 0) { + xmlURIPtr uri; + + uri = xmlParseURI((const char *)val); + if (uri == NULL) { + if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL)) + ctxt->sax->warning(ctxt->userData, + "xmlns: %s not a valid URI\n", val); + } 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); + } + xmlFreeURI(uri); + } + } + + /* a default namespace definition */ + nsret = xmlNewNs(ctxt->node, val, NULL); + +#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) + ctxt->valid &= xmlValidateOneNamespace(&ctxt->vctxt, ctxt->myDoc, + ctxt->node, prefix, nsret, val); +#endif /* LIBXML_VALID_ENABLED */ + if (name != NULL) + xmlFree(name); + if (nval != NULL) + xmlFree(nval); + if (val != value) + xmlFree(val); + return; + } + if ((!ctxt->html) && + (ns != NULL) && (ns[0] == 'x') && (ns[1] == 'm') && (ns[2] == 'l') && + (ns[3] == 'n') && (ns[4] == 's') && (ns[5] == 0)) { + xmlNsPtr nsret; + xmlChar *val; + + if (!ctxt->replaceEntities) { + ctxt->depth++; + val = xmlStringDecodeEntities(ctxt, value, XML_SUBSTITUTE_REF, + 0,0,0); + ctxt->depth--; + if (val == NULL) { + xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElement"); + xmlFree(ns); + if (name != NULL) + xmlFree(name); + return; + } + } else { + val = (xmlChar *) value; + } + + if (val[0] == 0) { + xmlNsErrMsg(ctxt, XML_NS_ERR_EMPTY, + "Empty namespace name for prefix %s\n", name, NULL); + } + if ((ctxt->pedantic != 0) && (val[0] != 0)) { + xmlURIPtr uri; + + uri = xmlParseURI((const char *)val); + if (uri == NULL) { + xmlNsWarnMsg(ctxt, XML_WAR_NS_URI, + "xmlns:%s: %s not a valid URI\n", name, value); + } else { + if (uri->scheme == NULL) { + xmlNsWarnMsg(ctxt, XML_WAR_NS_URI_RELATIVE, + "xmlns:%s: URI %s is not absolute\n", name, value); + } + xmlFreeURI(uri); + } + } + + /* a standard namespace definition */ + nsret = xmlNewNs(ctxt->node, val, name); + xmlFree(ns); +#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) + ctxt->valid &= xmlValidateOneNamespace(&ctxt->vctxt, ctxt->myDoc, + ctxt->node, prefix, nsret, value); +#endif /* LIBXML_VALID_ENABLED */ + if (name != NULL) + xmlFree(name); + if (nval != NULL) + xmlFree(nval); + if (val != value) + xmlFree(val); + return; + } + + if (ns != NULL) { + namespace = xmlSearchNs(ctxt->myDoc, ctxt->node, ns); + + if (namespace == NULL) { + xmlNsErrMsg(ctxt, XML_NS_ERR_UNDEFINED_NAMESPACE, + "Namespace prefix %s of attribute %s is not defined\n", + ns, name); + } else { + xmlAttrPtr prop; + + prop = ctxt->node->properties; + while (prop != NULL) { + if (prop->ns != NULL) { + 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; + goto error; + } + } + prop = prop->next; + } + } + } else { + namespace = NULL; + } + + /* !!!!!! */ + ret = xmlNewNsPropEatName(ctxt->node, namespace, name, NULL); + + if (ret != NULL) { + 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; + } + } else if (value != NULL) { + ret->children = xmlNewDocText(ctxt->myDoc, value); + ret->last = ret->children; + if (ret->children != NULL) + ret->children->parent = (xmlNodePtr) ret; + } + } + +#ifdef LIBXML_VALID_ENABLED + if ((!ctxt->html) && ctxt->validate && ctxt->wellFormed && + ctxt->myDoc && ctxt->myDoc->intSubset) { + + /* + * If we don't substitute entities, the validation should be + * done on a value with replaced entities anyway. + */ + if (!ctxt->replaceEntities) { + xmlChar *val; + + ctxt->depth++; + val = xmlStringDecodeEntities(ctxt, value, XML_SUBSTITUTE_REF, + 0,0,0); + ctxt->depth--; + + if (val == NULL) + ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt, + ctxt->myDoc, ctxt->node, ret, value); + else { + xmlChar *nvalnorm; + + /* + * Do the last stage of the attribute normalization + * 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); + if (nvalnorm != NULL) { + xmlFree(val); + val = nvalnorm; + } + + ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt, + ctxt->myDoc, ctxt->node, ret, val); + xmlFree(val); + } + } else { + ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt, ctxt->myDoc, + ctxt->node, ret, value); + } + } else +#endif /* LIBXML_VALID_ENABLED */ + if (((ctxt->loadsubset & XML_SKIP_IDS) == 0) && + (((ctxt->replaceEntities == 0) && (ctxt->external != 2)) || + ((ctxt->replaceEntities != 0) && (ctxt->inSubset == 0)))) { + /* + * when validating, the ID registration is done at the attribute + * validation level. Otherwise we have to do specific handling here. + */ + if (xmlStrEqual(fullname, BAD_CAST "xml:id")) { + /* + * Add the xml:id value + * + * Open issue: normalization of the value. + */ + if (xmlValidateNCName(value, 1) != 0) { + xmlErrValid(ctxt, XML_DTD_XMLID_VALUE, + "xml:id : attribute value %s is not an NCName\n", + (const char *) value, NULL); + } + xmlAddID(&ctxt->vctxt, ctxt->myDoc, value, ret); + } else if (xmlIsID(ctxt->myDoc, ctxt->node, ret)) + xmlAddID(&ctxt->vctxt, ctxt->myDoc, value, ret); + else if (xmlIsRef(ctxt->myDoc, ctxt->node, ret)) + xmlAddRef(&ctxt->vctxt, ctxt->myDoc, value, ret); + } + +error: + if (nval != NULL) + xmlFree(nval); + if (ns != NULL) + xmlFree(ns); +} + +/* + * xmlCheckDefaultedAttributes: + * + * Check defaulted attributes from the DTD + */ +static void +xmlCheckDefaultedAttributes(xmlParserCtxtPtr ctxt, const xmlChar *name, + const xmlChar *prefix, const xmlChar **atts) { + xmlElementPtr elemDecl; + const xmlChar *att; + int internal = 1; + int i; + + elemDecl = xmlGetDtdQElementDesc(ctxt->myDoc->intSubset, name, prefix); + if (elemDecl == NULL) { + elemDecl = xmlGetDtdQElementDesc(ctxt->myDoc->extSubset, name, prefix); + internal = 0; + } + +process_external_subset: + + if (elemDecl != NULL) { + xmlAttributePtr attr = elemDecl->attributes; + /* + * Check against defaulted attributes from the external subset + * if the document is stamped as standalone + */ + if ((ctxt->myDoc->standalone == 1) && + (ctxt->myDoc->extSubset != NULL) && + (ctxt->validate)) { + while (attr != NULL) { + if ((attr->defaultValue != NULL) && + (xmlGetDtdQAttrDesc(ctxt->myDoc->extSubset, + attr->elem, attr->name, + attr->prefix) == attr) && + (xmlGetDtdQAttrDesc(ctxt->myDoc->intSubset, + attr->elem, attr->name, + attr->prefix) == NULL)) { + xmlChar *fulln; + + if (attr->prefix != NULL) { + fulln = xmlStrdup(attr->prefix); + fulln = xmlStrcat(fulln, BAD_CAST ":"); + fulln = xmlStrcat(fulln, attr->name); + } else { + fulln = xmlStrdup(attr->name); + } + if (fulln == NULL) { + xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElement"); + break; + } + + /* + * Check that the attribute is not declared in the + * serialization + */ + att = NULL; + if (atts != NULL) { + i = 0; + att = atts[i]; + while (att != NULL) { + if (xmlStrEqual(att, fulln)) + break; + i += 2; + att = atts[i]; + } + } + 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); + } + xmlFree(fulln); + } + attr = attr->nexth; + } + } + + /* + * Actually insert defaulted values when needed + */ + attr = elemDecl->attributes; + while (attr != NULL) { + /* + * Make sure that attributes redefinition occuring in the + * internal subset are not overriden by definitions in the + * external subset. + */ + if (attr->defaultValue != NULL) { + /* + * the element should be instantiated in the tree if: + * - this is a namespace prefix + * - the user required for completion in the tree + * like XSLT + * - there isn't already an attribute definition + * in the internal subset overriding it. + */ + if (((attr->prefix != NULL) && + (xmlStrEqual(attr->prefix, BAD_CAST "xmlns"))) || + ((attr->prefix == NULL) && + (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) || + (ctxt->loadsubset & XML_COMPLETE_ATTRS)) { + xmlAttributePtr tst; + + tst = xmlGetDtdQAttrDesc(ctxt->myDoc->intSubset, + attr->elem, attr->name, + attr->prefix); + if ((tst == attr) || (tst == NULL)) { + xmlChar fn[50]; + xmlChar *fulln; + + fulln = xmlBuildQName(attr->name, attr->prefix, fn, 50); + if (fulln == NULL) { + xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElement"); + return; + } + + /* + * Check that the attribute is not declared in the + * serialization + */ + att = NULL; + if (atts != NULL) { + i = 0; + att = atts[i]; + while (att != NULL) { + if (xmlStrEqual(att, fulln)) + break; + i += 2; + att = atts[i]; + } + } + if (att == NULL) { + xmlSAX2AttributeInternal(ctxt, fulln, + attr->defaultValue, prefix); + } + if ((fulln != fn) && (fulln != attr->name)) + xmlFree(fulln); + } + } + } + attr = attr->nexth; + } + if (internal == 1) { + elemDecl = xmlGetDtdQElementDesc(ctxt->myDoc->extSubset, + name, prefix); + internal = 0; + goto process_external_subset; + } + } +} + +/** + * xmlSAX2StartElement: + * @ctx: the user data (XML parser context) + * @fullname: The element name, including namespace prefix + * @atts: An array of name/value attributes pairs, NULL terminated + * + * called when an opening tag has been processed. + */ +void +xmlSAX2StartElement(void *ctx, const xmlChar *fullname, const xmlChar **atts) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + xmlNodePtr ret; + xmlNodePtr parent; + xmlNsPtr ns; + xmlChar *name; + xmlChar *prefix; + const xmlChar *att; + const xmlChar *value; + int i; + + if ((ctx == NULL) || (fullname == NULL) || (ctxt->myDoc == NULL)) return; + parent = ctxt->node; +#ifdef DEBUG_SAX + xmlGenericError(xmlGenericErrorContext, + "SAX.xmlSAX2StartElement(%s)\n", fullname); +#endif + + /* + * First check on validity: + */ + if (ctxt->validate && (ctxt->myDoc->extSubset == NULL) && + ((ctxt->myDoc->intSubset == NULL) || + ((ctxt->myDoc->intSubset->notations == NULL) && + (ctxt->myDoc->intSubset->elements == NULL) && + (ctxt->myDoc->intSubset->attributes == NULL) && + (ctxt->myDoc->intSubset->entities == NULL)))) { + xmlErrValid(ctxt, XML_ERR_NO_DTD, + "Validation failed: no DTD found !", NULL, NULL); + ctxt->validate = 0; + } + + + /* + * Split the full name into a namespace prefix and the tag name + */ + name = xmlSplitQName(ctxt, fullname, &prefix); + + + /* + * Note : the namespace resolution is deferred until the end of the + * attributes parsing, since local namespace can be defined as + * an attribute at this level. + */ + ret = xmlNewDocNodeEatName(ctxt->myDoc, NULL, name, NULL); + if (ret == NULL) { + if (prefix != NULL) + xmlFree(prefix); + xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElement"); + return; + } + if (ctxt->myDoc->children == NULL) { +#ifdef DEBUG_SAX_TREE + xmlGenericError(xmlGenericErrorContext, "Setting %s as root\n", name); +#endif + xmlAddChild((xmlNodePtr) ctxt->myDoc, (xmlNodePtr) ret); + } else if (parent == NULL) { + parent = ctxt->myDoc->children; + } + ctxt->nodemem = -1; + if (ctxt->linenumbers) { + if (ctxt->input != NULL) { + if (ctxt->input->line < 65535) + ret->line = (short) ctxt->input->line; + else + ret->line = 65535; + } + } + + /* + * We are parsing a new node. + */ +#ifdef DEBUG_SAX_TREE + xmlGenericError(xmlGenericErrorContext, "pushing(%s)\n", name); +#endif + nodePush(ctxt, ret); + + /* + * Link the child element + */ + if (parent != NULL) { + if (parent->type == XML_ELEMENT_NODE) { +#ifdef DEBUG_SAX_TREE + xmlGenericError(xmlGenericErrorContext, + "adding child %s to %s\n", name, parent->name); +#endif + xmlAddChild(parent, ret); + } else { +#ifdef DEBUG_SAX_TREE + xmlGenericError(xmlGenericErrorContext, + "adding sibling %s to ", name); + xmlDebugDumpOneNode(stderr, parent, 0); +#endif + xmlAddSibling(parent, ret); + } + } + + /* + * Insert all the defaulted attributes from the DTD especially namespaces + */ + if ((!ctxt->html) && + ((ctxt->myDoc->intSubset != NULL) || + (ctxt->myDoc->extSubset != NULL))) { + xmlCheckDefaultedAttributes(ctxt, name, prefix, atts); + } + + /* + * process all the attributes whose name start with "xmlns" + */ + if (atts != NULL) { + i = 0; + att = atts[i++]; + value = atts[i++]; + if (!ctxt->html) { + while ((att != NULL) && (value != NULL)) { + if ((att[0] == 'x') && (att[1] == 'm') && (att[2] == 'l') && + (att[3] == 'n') && (att[4] == 's')) + xmlSAX2AttributeInternal(ctxt, att, value, prefix); + + att = atts[i++]; + value = atts[i++]; + } + } + } + + /* + * 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); + 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); + } + + /* + * set the namespace node, making sure that if the default namspace + * is unbound on a parent we simply kee it NULL + */ + if ((ns != NULL) && (ns->href != NULL) && + ((ns->href[0] != 0) || (ns->prefix != NULL))) + xmlSetNs(ret, ns); + + /* + * process all the other attributes + */ + if (atts != NULL) { + i = 0; + att = atts[i++]; + value = atts[i++]; + if (ctxt->html) { + while (att != NULL) { + xmlSAX2AttributeInternal(ctxt, att, value, NULL); + att = atts[i++]; + value = atts[i++]; + } + } else { + while ((att != NULL) && (value != NULL)) { + if ((att[0] != 'x') || (att[1] != 'm') || (att[2] != 'l') || + (att[3] != 'n') || (att[4] != 's')) + xmlSAX2AttributeInternal(ctxt, att, value, NULL); + + /* + * Next ones + */ + att = atts[i++]; + value = atts[i++]; + } + } + } + +#ifdef LIBXML_VALID_ENABLED + /* + * If it's the Document root, finish the DTD validation and + * check the document root element for validity + */ + if ((ctxt->validate) && (ctxt->vctxt.finishDtd == XML_CTXT_FINISH_DTD_0)) { + int chk; + + chk = xmlValidateDtdFinal(&ctxt->vctxt, ctxt->myDoc); + if (chk <= 0) + ctxt->valid = 0; + if (chk < 0) + ctxt->wellFormed = 0; + ctxt->valid &= xmlValidateRoot(&ctxt->vctxt, ctxt->myDoc); + ctxt->vctxt.finishDtd = XML_CTXT_FINISH_DTD_1; + } +#endif /* LIBXML_VALID_ENABLED */ + + if (prefix != NULL) + xmlFree(prefix); + +} + +/** + * xmlSAX2EndElement: + * @ctx: the user data (XML parser context) + * @name: The element name + * + * called when the end of an element has been detected. + */ +void +xmlSAX2EndElement(void *ctx, const xmlChar *name ATTRIBUTE_UNUSED) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + xmlParserNodeInfo node_info; + xmlNodePtr cur; + + if (ctx == NULL) return; + cur = ctxt->node; +#ifdef DEBUG_SAX + if (name == NULL) + xmlGenericError(xmlGenericErrorContext, "SAX.xmlSAX2EndElement(NULL)\n"); + else + xmlGenericError(xmlGenericErrorContext, "SAX.xmlSAX2EndElement(%s)\n", name); +#endif + + /* Capture end position and add node */ + if (cur != NULL && ctxt->record_info) { + node_info.end_pos = ctxt->input->cur - ctxt->input->base; + node_info.end_line = ctxt->input->line; + node_info.node = cur; + xmlParserAddNodeInfo(ctxt, &node_info); + } + ctxt->nodemem = -1; + +#ifdef LIBXML_VALID_ENABLED + if (ctxt->validate && ctxt->wellFormed && + ctxt->myDoc && ctxt->myDoc->intSubset) + ctxt->valid &= xmlValidateOneElement(&ctxt->vctxt, ctxt->myDoc, + cur); +#endif /* LIBXML_VALID_ENABLED */ + + + /* + * end of parsing of this node. + */ +#ifdef DEBUG_SAX_TREE + xmlGenericError(xmlGenericErrorContext, "popping(%s)\n", cur->name); +#endif + nodePop(ctxt); +} +#endif /* LIBXML_SAX1_ENABLED || LIBXML_HTML_ENABLE */ + +/* + * xmlSAX2TextNode: + * @ctxt: the parser context + * @str: the input string + * @len: the string length + * + * Remove the entities from an attribute value + * + * Returns the newly allocated string or NULL if not needed or error + */ +static xmlNodePtr +xmlSAX2TextNode(xmlParserCtxtPtr ctxt, const xmlChar *str, int len) { + xmlNodePtr ret; + const xmlChar *intern = NULL; + + /* + * Allocate + */ + if (ctxt->freeElems != NULL) { + ret = ctxt->freeElems; + ctxt->freeElems = ret->next; + ctxt->freeElemsNr--; + } else { + ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); + } + if (ret == NULL) { + xmlErrMemory(ctxt, "xmlSAX2Characters"); + return(NULL); + } + memset(ret, 0, sizeof(xmlNode)); + /* + * intern the formatting blanks found between tags, or the + * very short strings + */ + if (ctxt->dictNames) { + xmlChar cur = str[len]; + + if ((len < (int) (2 * sizeof(void *))) && + (ctxt->options & XML_PARSE_COMPACT)) { + /* store the string in the node overrithing properties and nsDef */ + xmlChar *tmp = (xmlChar *) &(ret->properties); + memcpy(tmp, str, len); + tmp[len] = 0; + intern = tmp; + } else if ((len <= 3) && ((cur == '"') || (cur == '\'') || + ((cur == '<') && (str[len + 1] != '!')))) { + intern = xmlDictLookup(ctxt->dict, str, len); + } else if (IS_BLANK_CH(*str) && (len < 60) && (cur == '<') && + (str[len + 1] != '!')) { + int i; + + for (i = 1;i < len;i++) { + if (!IS_BLANK_CH(str[i])) goto skip; + } + intern = xmlDictLookup(ctxt->dict, str, len); + } + } +skip: + ret->type = XML_TEXT_NODE; + + ret->name = xmlStringText; + if (intern == NULL) { + ret->content = xmlStrndup(str, len); + if (ret->content == NULL) { + xmlSAX2ErrMemory(ctxt, "xmlSAX2TextNode"); + xmlFree(ret); + return(NULL); + } + } else + ret->content = (xmlChar *) intern; + + if (ctxt->input != NULL) + ret->line = ctxt->input->line; + + if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) + xmlRegisterNodeDefaultValue(ret); + return(ret); +} + +#ifdef LIBXML_VALID_ENABLED +/* + * xmlSAX2DecodeAttrEntities: + * @ctxt: the parser context + * @str: the input string + * @len: the string length + * + * Remove the entities from an attribute value + * + * Returns the newly allocated string or NULL if not needed or error + */ +static xmlChar * +xmlSAX2DecodeAttrEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, + const xmlChar *end) { + const xmlChar *in; + xmlChar *ret; + + in = str; + while (in < end) + if (*in++ == '&') + goto decode; + return(NULL); +decode: + ctxt->depth++; + ret = xmlStringLenDecodeEntities(ctxt, str, end - str, + XML_SUBSTITUTE_REF, 0,0,0); + ctxt->depth--; + return(ret); +} +#endif /* LIBXML_VALID_ENABLED */ + +/** + * xmlSAX2AttributeNs: + * @ctx: the user data (XML parser context) + * @localname: the local name of the attribute + * @prefix: the attribute namespace prefix if available + * @URI: the attribute namespace name if available + * @value: Start of the attribute value + * @valueend: end of the attribute value + * + * Handle an attribute that has been read by the parser. + * The default handling is to convert the attribute into an + * DOM subtree and past it in a new xmlAttr element added to + * the element. + */ +static void +xmlSAX2AttributeNs(xmlParserCtxtPtr ctxt, + const xmlChar * localname, + const xmlChar * prefix, + const xmlChar * value, + const xmlChar * valueend) +{ + xmlAttrPtr ret; + xmlNsPtr namespace = NULL; + xmlChar *dup = NULL; + + /* + * Note: if prefix == NULL, the attribute is not in the default namespace + */ + if (prefix != NULL) + namespace = xmlSearchNs(ctxt->myDoc, ctxt->node, prefix); + + /* + * allocate the node + */ + if (ctxt->freeAttrs != NULL) { + ret = ctxt->freeAttrs; + ctxt->freeAttrs = ret->next; + ctxt->freeAttrsNr--; + memset(ret, 0, sizeof(xmlAttr)); + ret->type = XML_ATTRIBUTE_NODE; + + ret->parent = ctxt->node; + ret->doc = ctxt->myDoc; + ret->ns = namespace; + + if (ctxt->dictNames) + ret->name = localname; + else + ret->name = xmlStrdup(localname); + + /* link at the end to preserv order, TODO speed up with a last */ + if (ctxt->node->properties == NULL) { + ctxt->node->properties = ret; + } else { + xmlAttrPtr prev = ctxt->node->properties; + + while (prev->next != NULL) prev = prev->next; + prev->next = ret; + ret->prev = prev; + } + + if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) + xmlRegisterNodeDefaultValue((xmlNodePtr)ret); + } else { + if (ctxt->dictNames) + ret = xmlNewNsPropEatName(ctxt->node, namespace, + (xmlChar *) localname, NULL); + else + ret = xmlNewNsProp(ctxt->node, namespace, localname, NULL); + if (ret == NULL) { + xmlErrMemory(ctxt, "xmlSAX2AttributeNs"); + return; + } + } + + if ((ctxt->replaceEntities == 0) && (!ctxt->html)) { + xmlNodePtr tmp; + + /* + * We know that if there is an entity reference, then + * the string has been dup'ed and terminates with 0 + * otherwise with ' or " + */ + if (*valueend != 0) { + tmp = xmlSAX2TextNode(ctxt, value, valueend - value); + ret->children = tmp; + ret->last = tmp; + if (tmp != NULL) { + 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 (value != NULL) { + xmlNodePtr tmp; + + tmp = xmlSAX2TextNode(ctxt, value, valueend - value); + ret->children = tmp; + ret->last = tmp; + if (tmp != NULL) { + tmp->doc = ret->doc; + tmp->parent = (xmlNodePtr) ret; + } + } + +#ifdef LIBXML_VALID_ENABLED + if ((!ctxt->html) && ctxt->validate && ctxt->wellFormed && + ctxt->myDoc && ctxt->myDoc->intSubset) { + /* + * If we don't substitute entities, the validation should be + * done on a value with replaced entities anyway. + */ + if (!ctxt->replaceEntities) { + dup = xmlSAX2DecodeAttrEntities(ctxt, value, valueend); + if (dup == NULL) { + if (*valueend == 0) { + ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt, + ctxt->myDoc, ctxt->node, ret, value); + } else { + /* + * That should already be normalized. + * cheaper to finally allocate here than duplicate + * entry points in the full validation code + */ + dup = xmlStrndup(value, valueend - value); + + ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt, + ctxt->myDoc, ctxt->node, ret, dup); + } + } else { + /* + * dup now contains a string of the flattened attribute + * content with entities substitued. Check if we need to + * apply an extra layer of normalization. + * It need to be done twice ... it's an extra burden related + * to the ability to keep references in attributes + */ + if (ctxt->attsSpecial != NULL) { + xmlChar *nvalnorm; + xmlChar fn[50]; + xmlChar *fullname; + + fullname = xmlBuildQName(localname, prefix, fn, 50); + if (fullname != NULL) { + ctxt->vctxt.valid = 1; + nvalnorm = xmlValidCtxtNormalizeAttributeValue( + &ctxt->vctxt, ctxt->myDoc, + ctxt->node, fullname, dup); + if (ctxt->vctxt.valid != 1) + ctxt->valid = 0; + + if ((fullname != fn) && (fullname != localname)) + xmlFree(fullname); + if (nvalnorm != NULL) { + xmlFree(dup); + dup = nvalnorm; + } + } + } + + ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt, + ctxt->myDoc, ctxt->node, ret, dup); + } + } else { + /* + * if entities already have been substitued, then + * the attribute as passed is already normalized + */ + dup = xmlStrndup(value, valueend - value); + + ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt, + ctxt->myDoc, ctxt->node, ret, dup); + } + } else +#endif /* LIBXML_VALID_ENABLED */ + if (((ctxt->loadsubset & XML_SKIP_IDS) == 0) && + (((ctxt->replaceEntities == 0) && (ctxt->external != 2)) || + ((ctxt->replaceEntities != 0) && (ctxt->inSubset == 0)))) { + /* + * when validating, the ID registration is done at the attribute + * validation level. Otherwise we have to do specific handling here. + */ + if ((prefix == ctxt->str_xml) && + (localname[0] == 'i') && (localname[1] == 'd') && + (localname[2] == 0)) { + /* + * Add the xml:id value + * + * Open issue: normalization of the value. + */ + if (dup == NULL) + dup = xmlStrndup(value, valueend - value); +#ifdef LIBXML_VALID_ENABLED + if (xmlValidateNCName(dup, 1) != 0) { + xmlErrValid(ctxt, XML_DTD_XMLID_VALUE, + "xml:id : attribute value %s is not an NCName\n", + (const char *) dup, NULL); + } +#endif + xmlAddID(&ctxt->vctxt, ctxt->myDoc, dup, ret); + } else if (xmlIsID(ctxt->myDoc, ctxt->node, ret)) { + /* might be worth duplicate entry points and not copy */ + if (dup == NULL) + dup = xmlStrndup(value, valueend - value); + xmlAddID(&ctxt->vctxt, ctxt->myDoc, dup, ret); + } else if (xmlIsRef(ctxt->myDoc, ctxt->node, ret)) { + if (dup == NULL) + dup = xmlStrndup(value, valueend - value); + xmlAddRef(&ctxt->vctxt, ctxt->myDoc, dup, ret); + } + } + if (dup != NULL) + xmlFree(dup); +} + +/** + * xmlSAX2StartElementNs: + * @ctx: the user data (XML parser context) + * @localname: the local name of the element + * @prefix: the element namespace prefix if available + * @URI: the element namespace name if available + * @nb_namespaces: number of namespace definitions on that node + * @namespaces: pointer to the array of prefix/URI pairs namespace definitions + * @nb_attributes: the number of attributes on that node + * @nb_defaulted: the number of defaulted attributes. + * @attributes: pointer to the array of (localname/prefix/URI/value/end) + * attribute values. + * + * SAX2 callback when an element start has been detected by the parser. + * It provides the namespace informations for the element, as well as + * the new namespace declarations on the element. + */ +void +xmlSAX2StartElementNs(void *ctx, + const xmlChar *localname, + const xmlChar *prefix, + const xmlChar *URI, + int nb_namespaces, + const xmlChar **namespaces, + int nb_attributes, + int nb_defaulted, + const xmlChar **attributes) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + xmlNodePtr ret; + xmlNodePtr parent; + xmlNsPtr last = NULL, ns; + const xmlChar *uri, *pref; + xmlChar *lname = NULL; + int i, j; + + if (ctx == NULL) return; + parent = ctxt->node; + /* + * First check on validity: + */ + if (ctxt->validate && (ctxt->myDoc->extSubset == NULL) && + ((ctxt->myDoc->intSubset == NULL) || + ((ctxt->myDoc->intSubset->notations == NULL) && + (ctxt->myDoc->intSubset->elements == NULL) && + (ctxt->myDoc->intSubset->attributes == NULL) && + (ctxt->myDoc->intSubset->entities == NULL)))) { + xmlErrValid(ctxt, XML_ERR_NO_DTD, + "Validation failed: no DTD found !", NULL, NULL); + ctxt->validate = 0; + } + + /* + * Take care of the rare case of an undefined namespace prefix + */ + if ((prefix != NULL) && (URI == NULL)) { + if (ctxt->dictNames) { + const xmlChar *fullname; + + fullname = xmlDictQLookup(ctxt->dict, prefix, localname); + if (fullname != NULL) + localname = fullname; + } else { + lname = xmlBuildQName(localname, prefix, NULL, 0); + } + } + /* + * allocate the node + */ + if (ctxt->freeElems != NULL) { + ret = ctxt->freeElems; + ctxt->freeElems = ret->next; + ctxt->freeElemsNr--; + memset(ret, 0, sizeof(xmlNode)); + ret->type = XML_ELEMENT_NODE; + + if (ctxt->dictNames) + ret->name = localname; + else { + if (lname == NULL) + ret->name = xmlStrdup(localname); + else + ret->name = lname; + if (ret->name == NULL) { + xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElementNs"); + return; + } + } + if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) + xmlRegisterNodeDefaultValue(ret); + } else { + if (ctxt->dictNames) + ret = xmlNewDocNodeEatName(ctxt->myDoc, NULL, + (xmlChar *) localname, NULL); + else if (lname == NULL) + ret = xmlNewDocNode(ctxt->myDoc, NULL, localname, NULL); + else + ret = xmlNewDocNodeEatName(ctxt->myDoc, NULL, + (xmlChar *) lname, NULL); + if (ret == NULL) { + xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElementNs"); + return; + } + } + if (ctxt->linenumbers) { + if (ctxt->input != NULL) { + if (ctxt->input->line < 65535) + ret->line = (short) ctxt->input->line; + else + ret->line = 65535; + } + } + + if ((ctxt->myDoc->children == NULL) || (parent == NULL)) { + xmlAddChild((xmlNodePtr) ctxt->myDoc, (xmlNodePtr) ret); + } + /* + * Build the namespace list + */ + for (i = 0,j = 0;j < nb_namespaces;j++) { + pref = namespaces[i++]; + uri = namespaces[i++]; + ns = xmlNewNs(NULL, uri, pref); + if (ns != NULL) { + if (last == NULL) { + ret->nsDef = last = ns; + } else { + last->next = ns; + last = ns; + } + if ((URI != NULL) && (prefix == pref)) + ret->ns = ns; + } else { + /* + * any out of memory error would already have been raised + * but we can't be garanteed it's the actual error due to the + * API, best is to skip in this case + */ + continue; + } +#ifdef LIBXML_VALID_ENABLED + if ((!ctxt->html) && ctxt->validate && ctxt->wellFormed && + ctxt->myDoc && ctxt->myDoc->intSubset) { + ctxt->valid &= xmlValidateOneNamespace(&ctxt->vctxt, ctxt->myDoc, + ret, prefix, ns, uri); + } +#endif /* LIBXML_VALID_ENABLED */ + } + ctxt->nodemem = -1; + + /* + * We are parsing a new node. + */ + nodePush(ctxt, ret); + + /* + * Link the child element + */ + if (parent != NULL) { + if (parent->type == XML_ELEMENT_NODE) { + xmlAddChild(parent, ret); + } else { + xmlAddSibling(parent, ret); + } + } + + /* + * Insert the defaulted attributes from the DTD only if requested: + */ + if ((nb_defaulted != 0) && + ((ctxt->loadsubset & XML_COMPLETE_ATTRS) == 0)) + nb_attributes -= nb_defaulted; + + /* + * Search the namespace if it wasn't already found + * Note that, if prefix is NULL, this searches for the default Ns + */ + if ((URI != NULL) && (ret->ns == NULL)) { + ret->ns = xmlSearchNs(ctxt->myDoc, parent, prefix); + if ((ret->ns == NULL) && (xmlStrEqual(prefix, BAD_CAST "xml"))) { + ret->ns = xmlSearchNs(ctxt->myDoc, ret, prefix); + } + if (ret->ns == NULL) { + ns = xmlNewNs(ret, NULL, prefix); + if (ns == NULL) { + + xmlSAX2ErrMemory(ctxt, "xmlSAX2StartElementNs"); + return; + } + if (prefix != NULL) + xmlNsWarnMsg(ctxt, XML_NS_ERR_UNDEFINED_NAMESPACE, + "Namespace prefix %s was not found\n", + prefix, NULL); + else + xmlNsWarnMsg(ctxt, XML_NS_ERR_UNDEFINED_NAMESPACE, + "Namespace default prefix was not found\n", + NULL, NULL); + } + } + + /* + * process all the other attributes + */ + if (nb_attributes > 0) { + for (j = 0,i = 0;i < nb_attributes;i++,j+=5) { + /* + * Handle the rare case of an undefined atribute prefix + */ + if ((attributes[j+1] != NULL) && (attributes[j+2] == NULL)) { + if (ctxt->dictNames) { + const xmlChar *fullname; + + fullname = xmlDictQLookup(ctxt->dict, attributes[j+1], + attributes[j]); + if (fullname != NULL) { + xmlSAX2AttributeNs(ctxt, fullname, NULL, + attributes[j+3], attributes[j+4]); + continue; + } + } else { + lname = xmlBuildQName(attributes[j], attributes[j+1], + NULL, 0); + if (lname != NULL) { + xmlSAX2AttributeNs(ctxt, lname, NULL, + attributes[j+3], attributes[j+4]); + xmlFree(lname); + continue; + } + } + } + xmlSAX2AttributeNs(ctxt, attributes[j], attributes[j+1], + attributes[j+3], attributes[j+4]); + } + } + +#ifdef LIBXML_VALID_ENABLED + /* + * If it's the Document root, finish the DTD validation and + * check the document root element for validity + */ + if ((ctxt->validate) && (ctxt->vctxt.finishDtd == XML_CTXT_FINISH_DTD_0)) { + int chk; + + chk = xmlValidateDtdFinal(&ctxt->vctxt, ctxt->myDoc); + if (chk <= 0) + ctxt->valid = 0; + if (chk < 0) + ctxt->wellFormed = 0; + ctxt->valid &= xmlValidateRoot(&ctxt->vctxt, ctxt->myDoc); + ctxt->vctxt.finishDtd = XML_CTXT_FINISH_DTD_1; + } +#endif /* LIBXML_VALID_ENABLED */ +} + +/** + * xmlSAX2EndElementNs: + * @ctx: the user data (XML parser context) + * @localname: the local name of the element + * @prefix: the element namespace prefix if available + * @URI: the element namespace name if available + * + * SAX2 callback when an element end has been detected by the parser. + * It provides the namespace informations for the element. + */ +void +xmlSAX2EndElementNs(void *ctx, + const xmlChar * localname ATTRIBUTE_UNUSED, + const xmlChar * prefix ATTRIBUTE_UNUSED, + const xmlChar * URI ATTRIBUTE_UNUSED) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + xmlParserNodeInfo node_info; + xmlNodePtr cur; + + if (ctx == NULL) return; + cur = ctxt->node; + /* Capture end position and add node */ + if ((ctxt->record_info) && (cur != NULL)) { + node_info.end_pos = ctxt->input->cur - ctxt->input->base; + node_info.end_line = ctxt->input->line; + node_info.node = cur; + xmlParserAddNodeInfo(ctxt, &node_info); + } + ctxt->nodemem = -1; + +#ifdef LIBXML_VALID_ENABLED + if (ctxt->validate && ctxt->wellFormed && + ctxt->myDoc && ctxt->myDoc->intSubset) + ctxt->valid &= xmlValidateOneElement(&ctxt->vctxt, ctxt->myDoc, cur); +#endif /* LIBXML_VALID_ENABLED */ + + /* + * end of parsing of this node. + */ + nodePop(ctxt); +} + +/** + * xmlSAX2Reference: + * @ctx: the user data (XML parser context) + * @name: The entity name + * + * called when an entity xmlSAX2Reference is detected. + */ +void +xmlSAX2Reference(void *ctx, const xmlChar *name) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + xmlNodePtr ret; + + if (ctx == NULL) return; +#ifdef DEBUG_SAX + xmlGenericError(xmlGenericErrorContext, + "SAX.xmlSAX2Reference(%s)\n", name); +#endif + if (name[0] == '#') + ret = xmlNewCharRef(ctxt->myDoc, name); + else + ret = xmlNewReference(ctxt->myDoc, name); +#ifdef DEBUG_SAX_TREE + xmlGenericError(xmlGenericErrorContext, + "add xmlSAX2Reference %s to %s \n", name, ctxt->node->name); +#endif + if (xmlAddChild(ctxt->node, ret) == NULL) { + xmlFreeNode(ret); + } +} + +/** + * xmlSAX2Characters: + * @ctx: the user data (XML parser context) + * @ch: a xmlChar string + * @len: the number of xmlChar + * + * receiving some chars from the parser. + */ +void +xmlSAX2Characters(void *ctx, const xmlChar *ch, int len) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + xmlNodePtr lastChild; + + if (ctx == NULL) return; +#ifdef DEBUG_SAX + xmlGenericError(xmlGenericErrorContext, + "SAX.xmlSAX2Characters(%.30s, %d)\n", ch, len); +#endif + /* + * Handle the data if any. If there is no child + * add it as content, otherwise if the last child is text, + * concatenate it, else create a new node of type text. + */ + + if (ctxt->node == NULL) { +#ifdef DEBUG_SAX_TREE + xmlGenericError(xmlGenericErrorContext, + "add chars: ctxt->node == NULL !\n"); +#endif + return; + } + lastChild = ctxt->node->last; +#ifdef DEBUG_SAX_TREE + xmlGenericError(xmlGenericErrorContext, + "add chars to %s \n", ctxt->node->name); +#endif + + /* + * Here we needed an accelerator mechanism in case of very large + * elements. Use an attribute in the structure !!! + */ + if (lastChild == NULL) { + lastChild = xmlSAX2TextNode(ctxt, ch, len); + if (lastChild != NULL) { + ctxt->node->children = lastChild; + ctxt->node->last = lastChild; + lastChild->parent = ctxt->node; + lastChild->doc = ctxt->node->doc; + ctxt->nodelen = len; + ctxt->nodemem = len + 1; + } else { + xmlSAX2ErrMemory(ctxt, "xmlSAX2Characters"); + return; + } + } else { + int coalesceText = (lastChild != NULL) && + (lastChild->type == XML_TEXT_NODE) && + (lastChild->name == xmlStringText); + if ((coalesceText) && (ctxt->nodemem != 0)) { + /* + * The whole point of maintaining nodelen and nodemem, + * xmlTextConcat is too costly, i.e. compute length, + * reallocate a new buffer, move data, append ch. Here + * We try to minimaze realloc() uses and avoid copying + * and recomputing length over and over. + */ + if (lastChild->content == (xmlChar *)&(lastChild->properties)) { + lastChild->content = xmlStrdup(lastChild->content); + lastChild->properties = NULL; + } else if ((ctxt->nodemem == ctxt->nodelen + 1) && + (xmlDictOwns(ctxt->dict, lastChild->content))) { + lastChild->content = xmlStrdup(lastChild->content); + } + if (((size_t)ctxt->nodelen + (size_t)len > XML_MAX_TEXT_LENGTH) && + ((ctxt->options & XML_PARSE_HUGE) == 0)) { + xmlSAX2ErrMemory(ctxt, "xmlSAX2Characters: huge text node"); + return; + } + if ((size_t)ctxt->nodelen > SIZE_T_MAX - (size_t)len || + (size_t)ctxt->nodemem + (size_t)len > SIZE_T_MAX / 2) { + xmlSAX2ErrMemory(ctxt, "xmlSAX2Characters overflow prevented"); + return; + } + if (ctxt->nodelen + len >= ctxt->nodemem) { + xmlChar *newbuf; + size_t size; + + size = ctxt->nodemem + len; + size *= 2; + newbuf = (xmlChar *) xmlRealloc(lastChild->content,size); + if (newbuf == NULL) { + xmlSAX2ErrMemory(ctxt, "xmlSAX2Characters"); + return; + } + ctxt->nodemem = size; + lastChild->content = newbuf; + } + memcpy(&lastChild->content[ctxt->nodelen], ch, len); + ctxt->nodelen += len; + lastChild->content[ctxt->nodelen] = 0; + } else if (coalesceText) { + if (xmlTextConcat(lastChild, ch, len)) { + xmlSAX2ErrMemory(ctxt, "xmlSAX2Characters"); + } + if (ctxt->node->children != NULL) { + ctxt->nodelen = xmlStrlen(lastChild->content); + ctxt->nodemem = ctxt->nodelen + 1; + } + } else { + /* Mixed content, first time */ + lastChild = xmlSAX2TextNode(ctxt, ch, len); + if (lastChild != NULL) { + xmlAddChild(ctxt->node, lastChild); + if (ctxt->node->children != NULL) { + ctxt->nodelen = len; + ctxt->nodemem = len + 1; + } + } + } + } +} + +/** + * xmlSAX2IgnorableWhitespace: + * @ctx: the user data (XML parser context) + * @ch: a xmlChar string + * @len: the number of xmlChar + * + * receiving some ignorable whitespaces from the parser. + * UNUSED: by default the DOM building will use xmlSAX2Characters + */ +void +xmlSAX2IgnorableWhitespace(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch ATTRIBUTE_UNUSED, int len ATTRIBUTE_UNUSED) +{ + /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */ +#ifdef DEBUG_SAX + xmlGenericError(xmlGenericErrorContext, + "SAX.xmlSAX2IgnorableWhitespace(%.30s, %d)\n", ch, len); +#endif +} + +/** + * xmlSAX2ProcessingInstruction: + * @ctx: the user data (XML parser context) + * @target: the target name + * @data: the PI data's + * + * A processing instruction has been parsed. + */ +void +xmlSAX2ProcessingInstruction(void *ctx, const xmlChar *target, + const xmlChar *data) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + xmlNodePtr ret; + xmlNodePtr parent; + + if (ctx == NULL) return; + parent = ctxt->node; +#ifdef DEBUG_SAX + xmlGenericError(xmlGenericErrorContext, + "SAX.xmlSAX2ProcessingInstruction(%s, %s)\n", target, data); +#endif + + ret = xmlNewDocPI(ctxt->myDoc, target, data); + if (ret == NULL) return; + + if (ctxt->linenumbers) { + if (ctxt->input != NULL) { + if (ctxt->input->line < 65535) + ret->line = (short) ctxt->input->line; + else + ret->line = 65535; + } + } + if (ctxt->inSubset == 1) { + xmlAddChild((xmlNodePtr) ctxt->myDoc->intSubset, ret); + return; + } else if (ctxt->inSubset == 2) { + xmlAddChild((xmlNodePtr) ctxt->myDoc->extSubset, ret); + return; + } + if ((ctxt->myDoc->children == NULL) || (parent == NULL)) { +#ifdef DEBUG_SAX_TREE + xmlGenericError(xmlGenericErrorContext, + "Setting PI %s as root\n", target); +#endif + xmlAddChild((xmlNodePtr) ctxt->myDoc, (xmlNodePtr) ret); + return; + } + if (parent->type == XML_ELEMENT_NODE) { +#ifdef DEBUG_SAX_TREE + xmlGenericError(xmlGenericErrorContext, + "adding PI %s child to %s\n", target, parent->name); +#endif + xmlAddChild(parent, ret); + } else { +#ifdef DEBUG_SAX_TREE + xmlGenericError(xmlGenericErrorContext, + "adding PI %s sibling to ", target); + xmlDebugDumpOneNode(stderr, parent, 0); +#endif + xmlAddSibling(parent, ret); + } +} + +/** + * xmlSAX2Comment: + * @ctx: the user data (XML parser context) + * @value: the xmlSAX2Comment content + * + * A xmlSAX2Comment has been parsed. + */ +void +xmlSAX2Comment(void *ctx, const xmlChar *value) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + xmlNodePtr ret; + xmlNodePtr parent; + + if (ctx == NULL) return; + parent = ctxt->node; +#ifdef DEBUG_SAX + xmlGenericError(xmlGenericErrorContext, "SAX.xmlSAX2Comment(%s)\n", value); +#endif + ret = xmlNewDocComment(ctxt->myDoc, value); + if (ret == NULL) return; + if (ctxt->linenumbers) { + if (ctxt->input != NULL) { + if (ctxt->input->line < 65535) + ret->line = (short) ctxt->input->line; + else + ret->line = 65535; + } + } + + if (ctxt->inSubset == 1) { + xmlAddChild((xmlNodePtr) ctxt->myDoc->intSubset, ret); + return; + } else if (ctxt->inSubset == 2) { + xmlAddChild((xmlNodePtr) ctxt->myDoc->extSubset, ret); + return; + } + if ((ctxt->myDoc->children == NULL) || (parent == NULL)) { +#ifdef DEBUG_SAX_TREE + xmlGenericError(xmlGenericErrorContext, + "Setting xmlSAX2Comment as root\n"); +#endif + xmlAddChild((xmlNodePtr) ctxt->myDoc, (xmlNodePtr) ret); + return; + } + if (parent->type == XML_ELEMENT_NODE) { +#ifdef DEBUG_SAX_TREE + xmlGenericError(xmlGenericErrorContext, + "adding xmlSAX2Comment child to %s\n", parent->name); +#endif + xmlAddChild(parent, ret); + } else { +#ifdef DEBUG_SAX_TREE + xmlGenericError(xmlGenericErrorContext, + "adding xmlSAX2Comment sibling to "); + xmlDebugDumpOneNode(stderr, parent, 0); +#endif + xmlAddSibling(parent, ret); + } +} + +/** + * xmlSAX2CDataBlock: + * @ctx: the user data (XML parser context) + * @value: The pcdata content + * @len: the block length + * + * called when a pcdata block has been parsed + */ +void +xmlSAX2CDataBlock(void *ctx, const xmlChar *value, int len) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + xmlNodePtr ret, lastChild; + + if (ctx == NULL) return; +#ifdef DEBUG_SAX + xmlGenericError(xmlGenericErrorContext, + "SAX.pcdata(%.10s, %d)\n", value, len); +#endif + lastChild = xmlGetLastChild(ctxt->node); +#ifdef DEBUG_SAX_TREE + xmlGenericError(xmlGenericErrorContext, + "add chars to %s \n", ctxt->node->name); +#endif + if ((lastChild != NULL) && + (lastChild->type == XML_CDATA_SECTION_NODE)) { + xmlTextConcat(lastChild, value, len); + } else { + ret = xmlNewCDataBlock(ctxt->myDoc, value, len); + xmlAddChild(ctxt->node, ret); + } +} + +static int xmlSAX2DefaultVersionValue = 2; + +#ifdef LIBXML_SAX1_ENABLED +/** + * xmlSAXDefaultVersion: + * @version: the version, 1 or 2 + * + * Set the default version of SAX used globally by the library. + * By default, during initialization the default is set to 2. + * Note that it is generally a better coding style to use + * xmlSAXVersion() to set up the version explicitly for a given + * parsing context. + * + * Returns the previous value in case of success and -1 in case of error. + */ +int +xmlSAXDefaultVersion(int version) +{ + int ret = xmlSAX2DefaultVersionValue; + + if ((version != 1) && (version != 2)) + return(-1); + xmlSAX2DefaultVersionValue = version; + return(ret); +} +#endif /* LIBXML_SAX1_ENABLED */ + +/** + * xmlSAXVersion: + * @hdlr: the SAX handler + * @version: the version, 1 or 2 + * + * Initialize the default XML SAX handler according to the version + * + * Returns 0 in case of success and -1 in case of error. + */ +int +xmlSAXVersion(xmlSAXHandler *hdlr, int version) +{ + if (hdlr == NULL) return(-1); + if (version == 2) { + hdlr->startElement = NULL; + hdlr->endElement = NULL; + hdlr->startElementNs = xmlSAX2StartElementNs; + hdlr->endElementNs = xmlSAX2EndElementNs; + hdlr->serror = NULL; + hdlr->initialized = XML_SAX2_MAGIC; +#ifdef LIBXML_SAX1_ENABLED + } else if (version == 1) { + hdlr->startElement = xmlSAX2StartElement; + hdlr->endElement = xmlSAX2EndElement; + hdlr->initialized = 1; +#endif /* LIBXML_SAX1_ENABLED */ + } else + return(-1); + hdlr->internalSubset = xmlSAX2InternalSubset; + hdlr->externalSubset = xmlSAX2ExternalSubset; + hdlr->isStandalone = xmlSAX2IsStandalone; + hdlr->hasInternalSubset = xmlSAX2HasInternalSubset; + hdlr->hasExternalSubset = xmlSAX2HasExternalSubset; + hdlr->resolveEntity = xmlSAX2ResolveEntity; + hdlr->getEntity = xmlSAX2GetEntity; + hdlr->getParameterEntity = xmlSAX2GetParameterEntity; + hdlr->entityDecl = xmlSAX2EntityDecl; + hdlr->attributeDecl = xmlSAX2AttributeDecl; + hdlr->elementDecl = xmlSAX2ElementDecl; + hdlr->notationDecl = xmlSAX2NotationDecl; + hdlr->unparsedEntityDecl = xmlSAX2UnparsedEntityDecl; + hdlr->setDocumentLocator = xmlSAX2SetDocumentLocator; + hdlr->startDocument = xmlSAX2StartDocument; + hdlr->endDocument = xmlSAX2EndDocument; + hdlr->reference = xmlSAX2Reference; + hdlr->characters = xmlSAX2Characters; + hdlr->cdataBlock = xmlSAX2CDataBlock; + hdlr->ignorableWhitespace = xmlSAX2Characters; + hdlr->processingInstruction = xmlSAX2ProcessingInstruction; + hdlr->comment = xmlSAX2Comment; + hdlr->warning = xmlParserWarning; + hdlr->error = xmlParserError; + hdlr->fatalError = xmlParserError; + + return(0); +} + +/** + * xmlSAX2InitDefaultSAXHandler: + * @hdlr: the SAX handler + * @warning: flag if non-zero sets the handler warning procedure + * + * Initialize the default XML SAX2 handler + */ +void +xmlSAX2InitDefaultSAXHandler(xmlSAXHandler *hdlr, int warning) +{ + if ((hdlr == NULL) || (hdlr->initialized != 0)) + return; + + xmlSAXVersion(hdlr, xmlSAX2DefaultVersionValue); + if (warning == 0) + hdlr->warning = NULL; + else + hdlr->warning = xmlParserWarning; +} + +/** + * xmlDefaultSAXHandlerInit: + * + * Initialize the default SAX2 handler + */ +void +xmlDefaultSAXHandlerInit(void) +{ +#ifdef LIBXML_SAX1_ENABLED + xmlSAXVersion((xmlSAXHandlerPtr) &xmlDefaultSAXHandler, 1); +#endif /* LIBXML_SAX1_ENABLED */ +} + +#ifdef LIBXML_DOCB_ENABLED + +/** + * xmlSAX2InitDocbDefaultSAXHandler: + * @hdlr: the SAX handler + * + * Initialize the default DocBook SAX2 handler + */ +void +xmlSAX2InitDocbDefaultSAXHandler(xmlSAXHandler *hdlr) +{ + if ((hdlr == NULL) || (hdlr->initialized != 0)) + return; + + hdlr->internalSubset = xmlSAX2InternalSubset; + hdlr->externalSubset = NULL; + hdlr->isStandalone = xmlSAX2IsStandalone; + hdlr->hasInternalSubset = xmlSAX2HasInternalSubset; + hdlr->hasExternalSubset = xmlSAX2HasExternalSubset; + hdlr->resolveEntity = xmlSAX2ResolveEntity; + hdlr->getEntity = xmlSAX2GetEntity; + hdlr->getParameterEntity = NULL; + hdlr->entityDecl = xmlSAX2EntityDecl; + hdlr->attributeDecl = NULL; + hdlr->elementDecl = NULL; + hdlr->notationDecl = NULL; + hdlr->unparsedEntityDecl = NULL; + hdlr->setDocumentLocator = xmlSAX2SetDocumentLocator; + hdlr->startDocument = xmlSAX2StartDocument; + hdlr->endDocument = xmlSAX2EndDocument; + hdlr->startElement = xmlSAX2StartElement; + hdlr->endElement = xmlSAX2EndElement; + hdlr->reference = xmlSAX2Reference; + hdlr->characters = xmlSAX2Characters; + hdlr->cdataBlock = NULL; + hdlr->ignorableWhitespace = xmlSAX2IgnorableWhitespace; + hdlr->processingInstruction = NULL; + hdlr->comment = xmlSAX2Comment; + hdlr->warning = xmlParserWarning; + hdlr->error = xmlParserError; + hdlr->fatalError = xmlParserError; + + hdlr->initialized = 1; +} + +/** + * docbDefaultSAXHandlerInit: + * + * Initialize the default SAX handler + */ +void +docbDefaultSAXHandlerInit(void) +{ + xmlSAX2InitDocbDefaultSAXHandler((xmlSAXHandlerPtr) &docbDefaultSAXHandler); +} + +#endif /* LIBXML_DOCB_ENABLED */ +#define bottom_SAX2 +#include "elfgcchack.h" diff --git a/android/native/libxml2/c14n.c b/android/native/libxml2/c14n.c new file mode 100644 index 0000000000..2adee79c88 --- /dev/null +++ b/android/native/libxml2/c14n.c @@ -0,0 +1,2232 @@ +/* + * "Canonical XML" implementation + * http://www.w3.org/TR/xml-c14n + * + * "Exclusive XML Canonicalization" implementation + * http://www.w3.org/TR/xml-exc-c14n + * + * See Copyright for the status of this software. + * + * Author: Aleksey Sanin + */ +#define IN_LIBXML +#include "libxml.h" +#ifdef LIBXML_C14N_ENABLED +#ifdef LIBXML_OUTPUT_ENABLED + +#ifdef HAVE_STDLIB_H +#include +#endif +#include + +#include +#include +#include +#include +#include +#include +#include + +/************************************************************************ + * * + * Some declaration better left private ATM * + * * + ************************************************************************/ + +typedef enum { + XMLC14N_BEFORE_DOCUMENT_ELEMENT = 0, + XMLC14N_INSIDE_DOCUMENT_ELEMENT = 1, + XMLC14N_AFTER_DOCUMENT_ELEMENT = 2 +} xmlC14NPosition; + +typedef struct _xmlC14NVisibleNsStack { + int nsCurEnd; /* number of nodes in the set */ + int nsPrevStart; /* the begginning of the stack for previous visible node */ + int nsPrevEnd; /* the end of the stack for previous visible node */ + int nsMax; /* size of the array as allocated */ + xmlNsPtr *nsTab; /* array of ns in no particular order */ + xmlNodePtr *nodeTab; /* array of nodes in no particular order */ +} xmlC14NVisibleNsStack, *xmlC14NVisibleNsStackPtr; + +typedef struct _xmlC14NCtx { + /* input parameters */ + xmlDocPtr doc; + xmlC14NIsVisibleCallback is_visible_callback; + void* user_data; + int with_comments; + xmlOutputBufferPtr buf; + + /* position in the XML document */ + xmlC14NPosition pos; + int parent_is_doc; + xmlC14NVisibleNsStackPtr ns_rendered; + + /* C14N mode */ + xmlC14NMode mode; + + /* exclusive canonicalization */ + xmlChar **inclusive_ns_prefixes; + + /* error number */ + int error; +} xmlC14NCtx, *xmlC14NCtxPtr; + +static xmlC14NVisibleNsStackPtr xmlC14NVisibleNsStackCreate (void); +static void xmlC14NVisibleNsStackDestroy (xmlC14NVisibleNsStackPtr cur); +static void xmlC14NVisibleNsStackAdd (xmlC14NVisibleNsStackPtr cur, + xmlNsPtr ns, + xmlNodePtr node); +static void xmlC14NVisibleNsStackSave (xmlC14NVisibleNsStackPtr cur, + xmlC14NVisibleNsStackPtr state); +static void xmlC14NVisibleNsStackRestore (xmlC14NVisibleNsStackPtr cur, + xmlC14NVisibleNsStackPtr state); +static void xmlC14NVisibleNsStackShift (xmlC14NVisibleNsStackPtr cur); +static int xmlC14NVisibleNsStackFind (xmlC14NVisibleNsStackPtr cur, + xmlNsPtr ns); +static int xmlExcC14NVisibleNsStackFind (xmlC14NVisibleNsStackPtr cur, + xmlNsPtr ns, + xmlC14NCtxPtr ctx); + +static int xmlC14NIsNodeInNodeset (xmlNodeSetPtr nodes, + xmlNodePtr node, + xmlNodePtr parent); + + + +static int xmlC14NProcessNode(xmlC14NCtxPtr ctx, xmlNodePtr cur); +static int xmlC14NProcessNodeList(xmlC14NCtxPtr ctx, xmlNodePtr cur); +typedef enum { + XMLC14N_NORMALIZE_ATTR = 0, + XMLC14N_NORMALIZE_COMMENT = 1, + XMLC14N_NORMALIZE_PI = 2, + XMLC14N_NORMALIZE_TEXT = 3 +} xmlC14NNormalizationMode; + +static xmlChar *xmlC11NNormalizeString(const xmlChar * input, + xmlC14NNormalizationMode mode); + +#define xmlC11NNormalizeAttr( a ) \ + xmlC11NNormalizeString((a), XMLC14N_NORMALIZE_ATTR) +#define xmlC11NNormalizeComment( a ) \ + xmlC11NNormalizeString((a), XMLC14N_NORMALIZE_COMMENT) +#define xmlC11NNormalizePI( a ) \ + xmlC11NNormalizeString((a), XMLC14N_NORMALIZE_PI) +#define xmlC11NNormalizeText( a ) \ + xmlC11NNormalizeString((a), XMLC14N_NORMALIZE_TEXT) + +#define xmlC14NIsVisible( ctx, node, parent ) \ + (((ctx)->is_visible_callback != NULL) ? \ + (ctx)->is_visible_callback((ctx)->user_data, \ + (xmlNodePtr)(node), (xmlNodePtr)(parent)) : 1) + +#define xmlC14NIsExclusive( ctx ) \ + ( (ctx)->mode == XML_C14N_EXCLUSIVE_1_0 ) + +/************************************************************************ + * * + * Some factorized error routines * + * * + ************************************************************************/ + +/** + * xmlC14NErrMemory: + * @extra: extra informations + * + * Handle a redefinition of memory error + */ +static void +xmlC14NErrMemory(const char *extra) +{ + __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_C14N, + XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0, extra, + NULL, NULL, 0, 0, + "Memory allocation failed : %s\n", extra); +} + +/** + * xmlC14NErrParam: + * @extra: extra informations + * + * Handle a redefinition of param error + */ +static void +xmlC14NErrParam(const char *extra) +{ + __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_C14N, + XML_ERR_INTERNAL_ERROR, XML_ERR_ERROR, NULL, 0, extra, + NULL, NULL, 0, 0, + "Invalid parameter : %s\n", extra); +} + +/** + * xmlC14NErrInternal: + * @extra: extra informations + * + * Handle a redefinition of internal error + */ +static void +xmlC14NErrInternal(const char *extra) +{ + __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_C14N, + XML_ERR_INTERNAL_ERROR, XML_ERR_ERROR, NULL, 0, extra, + NULL, NULL, 0, 0, + "Internal error : %s\n", extra); +} + +/** + * xmlC14NErrInvalidNode: + * @extra: extra informations + * + * Handle a redefinition of invalid node error + */ +static void +xmlC14NErrInvalidNode(const char *node_type, const char *extra) +{ + __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_C14N, + XML_C14N_INVALID_NODE, XML_ERR_ERROR, NULL, 0, extra, + NULL, NULL, 0, 0, + "Node %s is invalid here : %s\n", node_type, extra); +} + +/** + * xmlC14NErrUnknownNode: + * @extra: extra informations + * + * Handle a redefinition of unknown node error + */ +static void +xmlC14NErrUnknownNode(int node_type, const char *extra) +{ + __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_C14N, + XML_C14N_UNKNOW_NODE, XML_ERR_ERROR, NULL, 0, extra, + NULL, NULL, 0, 0, + "Unknown node type %d found : %s\n", node_type, extra); +} + +/** + * xmlC14NErrRelativeNamespace: + * @extra: extra informations + * + * Handle a redefinition of relative namespace error + */ +static void +xmlC14NErrRelativeNamespace(const char *ns_uri) +{ + __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_C14N, + XML_C14N_RELATIVE_NAMESPACE, XML_ERR_ERROR, NULL, 0, NULL, + NULL, NULL, 0, 0, + "Relative namespace UR is invalid here : %s\n", ns_uri); +} + + + +/** + * xmlC14NErr: + * @ctxt: a C14N evaluation context + * @node: the context node + * @error: the erorr code + * @msg: the message + * @extra: extra informations + * + * Handle a redefinition of attribute error + */ +static void +xmlC14NErr(xmlC14NCtxPtr ctxt, xmlNodePtr node, int error, + const char * msg) +{ + if (ctxt != NULL) + ctxt->error = error; + __xmlRaiseError(NULL, NULL, NULL, + ctxt, node, XML_FROM_C14N, error, + XML_ERR_ERROR, NULL, 0, + NULL, NULL, NULL, 0, 0, "%s", msg); +} + +/************************************************************************ + * * + * The implementation internals * + * * + ************************************************************************/ +#define XML_NAMESPACES_DEFAULT 16 + +static int +xmlC14NIsNodeInNodeset(xmlNodeSetPtr nodes, xmlNodePtr node, xmlNodePtr parent) { + if((nodes != NULL) && (node != NULL)) { + if(node->type != XML_NAMESPACE_DECL) { + return(xmlXPathNodeSetContains(nodes, node)); + } else { + xmlNs ns; + + memcpy(&ns, node, sizeof(ns)); + + /* this is a libxml hack! check xpath.c for details */ + if((parent != NULL) && (parent->type == XML_ATTRIBUTE_NODE)) { + ns.next = (xmlNsPtr)parent->parent; + } else { + ns.next = (xmlNsPtr)parent; + } + + /* + * If the input is an XPath node-set, then the node-set must explicitly + * contain every node to be rendered to the canonical form. + */ + return(xmlXPathNodeSetContains(nodes, (xmlNodePtr)&ns)); + } + } + return(1); +} + +static xmlC14NVisibleNsStackPtr +xmlC14NVisibleNsStackCreate(void) { + xmlC14NVisibleNsStackPtr ret; + + ret = (xmlC14NVisibleNsStackPtr) xmlMalloc(sizeof(xmlC14NVisibleNsStack)); + if (ret == NULL) { + xmlC14NErrMemory("creating namespaces stack"); + return(NULL); + } + memset(ret, 0 , (size_t) sizeof(xmlC14NVisibleNsStack)); + return(ret); +} + +static void +xmlC14NVisibleNsStackDestroy(xmlC14NVisibleNsStackPtr cur) { + if(cur == NULL) { + xmlC14NErrParam("destroying namespaces stack"); + return; + } + if(cur->nsTab != NULL) { + memset(cur->nsTab, 0, cur->nsMax * sizeof(xmlNsPtr)); + xmlFree(cur->nsTab); + } + if(cur->nodeTab != NULL) { + memset(cur->nodeTab, 0, cur->nsMax * sizeof(xmlNodePtr)); + xmlFree(cur->nodeTab); + } + memset(cur, 0, sizeof(xmlC14NVisibleNsStack)); + xmlFree(cur); + +} + +static void +xmlC14NVisibleNsStackAdd(xmlC14NVisibleNsStackPtr cur, xmlNsPtr ns, xmlNodePtr node) { + if((cur == NULL) || + ((cur->nsTab == NULL) && (cur->nodeTab != NULL)) || + ((cur->nsTab != NULL) && (cur->nodeTab == NULL))) { + xmlC14NErrParam("adding namespace to stack"); + return; + } + + if ((cur->nsTab == NULL) && (cur->nodeTab == NULL)) { + cur->nsTab = (xmlNsPtr*) xmlMalloc(XML_NAMESPACES_DEFAULT * sizeof(xmlNsPtr)); + cur->nodeTab = (xmlNodePtr*) xmlMalloc(XML_NAMESPACES_DEFAULT * sizeof(xmlNodePtr)); + if ((cur->nsTab == NULL) || (cur->nodeTab == NULL)) { + xmlC14NErrMemory("adding node to stack"); + return; + } + memset(cur->nsTab, 0 , XML_NAMESPACES_DEFAULT * sizeof(xmlNsPtr)); + memset(cur->nodeTab, 0 , XML_NAMESPACES_DEFAULT * sizeof(xmlNodePtr)); + cur->nsMax = XML_NAMESPACES_DEFAULT; + } else if(cur->nsMax == cur->nsCurEnd) { + void *tmp; + int tmpSize; + + tmpSize = 2 * cur->nsMax; + tmp = xmlRealloc(cur->nsTab, tmpSize * sizeof(xmlNsPtr)); + if (tmp == NULL) { + xmlC14NErrMemory("adding node to stack"); + return; + } + cur->nsTab = (xmlNsPtr*)tmp; + + tmp = xmlRealloc(cur->nodeTab, tmpSize * sizeof(xmlNodePtr)); + if (tmp == NULL) { + xmlC14NErrMemory("adding node to stack"); + return; + } + cur->nodeTab = (xmlNodePtr*)tmp; + + cur->nsMax = tmpSize; + } + cur->nsTab[cur->nsCurEnd] = ns; + cur->nodeTab[cur->nsCurEnd] = node; + + ++cur->nsCurEnd; +} + +static void +xmlC14NVisibleNsStackSave(xmlC14NVisibleNsStackPtr cur, xmlC14NVisibleNsStackPtr state) { + if((cur == NULL) || (state == NULL)) { + xmlC14NErrParam("saving namespaces stack"); + return; + } + + state->nsCurEnd = cur->nsCurEnd; + state->nsPrevStart = cur->nsPrevStart; + state->nsPrevEnd = cur->nsPrevEnd; +} + +static void +xmlC14NVisibleNsStackRestore(xmlC14NVisibleNsStackPtr cur, xmlC14NVisibleNsStackPtr state) { + if((cur == NULL) || (state == NULL)) { + xmlC14NErrParam("restoring namespaces stack"); + return; + } + cur->nsCurEnd = state->nsCurEnd; + cur->nsPrevStart = state->nsPrevStart; + cur->nsPrevEnd = state->nsPrevEnd; +} + +static void +xmlC14NVisibleNsStackShift(xmlC14NVisibleNsStackPtr cur) { + if(cur == NULL) { + xmlC14NErrParam("shifting namespaces stack"); + return; + } + cur->nsPrevStart = cur->nsPrevEnd; + cur->nsPrevEnd = cur->nsCurEnd; +} + +static int +xmlC14NStrEqual(const xmlChar *str1, const xmlChar *str2) { + if (str1 == str2) return(1); + if (str1 == NULL) return((*str2) == '\0'); + if (str2 == NULL) return((*str1) == '\0'); + do { + if (*str1++ != *str2) return(0); + } while (*str2++); + return(1); +} + +/** + * xmlC14NVisibleNsStackFind: + * @ctx: the C14N context + * @ns: the namespace to check + * + * Checks whether the given namespace was already rendered or not + * + * Returns 1 if we already wrote this namespace or 0 otherwise + */ +static int +xmlC14NVisibleNsStackFind(xmlC14NVisibleNsStackPtr cur, xmlNsPtr ns) +{ + int i; + const xmlChar *prefix; + const xmlChar *href; + int has_empty_ns; + + if(cur == NULL) { + xmlC14NErrParam("searching namespaces stack (c14n)"); + return (0); + } + + /* + * if the default namespace xmlns="" is not defined yet then + * we do not want to print it out + */ + prefix = ((ns == NULL) || (ns->prefix == NULL)) ? BAD_CAST "" : ns->prefix; + href = ((ns == NULL) || (ns->href == NULL)) ? BAD_CAST "" : ns->href; + has_empty_ns = (xmlC14NStrEqual(prefix, NULL) && xmlC14NStrEqual(href, NULL)); + + if (cur->nsTab != NULL) { + int start = (has_empty_ns) ? 0 : cur->nsPrevStart; + for (i = cur->nsCurEnd - 1; i >= start; --i) { + xmlNsPtr ns1 = cur->nsTab[i]; + + if(xmlC14NStrEqual(prefix, (ns1 != NULL) ? ns1->prefix : NULL)) { + return(xmlC14NStrEqual(href, (ns1 != NULL) ? ns1->href : NULL)); + } + } + } + return(has_empty_ns); +} + +static int +xmlExcC14NVisibleNsStackFind(xmlC14NVisibleNsStackPtr cur, xmlNsPtr ns, xmlC14NCtxPtr ctx) { + int i; + const xmlChar *prefix; + const xmlChar *href; + int has_empty_ns; + + if(cur == NULL) { + xmlC14NErrParam("searching namespaces stack (exc c14n)"); + return (0); + } + + /* + * if the default namespace xmlns="" is not defined yet then + * we do not want to print it out + */ + prefix = ((ns == NULL) || (ns->prefix == NULL)) ? BAD_CAST "" : ns->prefix; + href = ((ns == NULL) || (ns->href == NULL)) ? BAD_CAST "" : ns->href; + has_empty_ns = (xmlC14NStrEqual(prefix, NULL) && xmlC14NStrEqual(href, NULL)); + + if (cur->nsTab != NULL) { + int start = 0; + for (i = cur->nsCurEnd - 1; i >= start; --i) { + xmlNsPtr ns1 = cur->nsTab[i]; + + if(xmlC14NStrEqual(prefix, (ns1 != NULL) ? ns1->prefix : NULL)) { + if(xmlC14NStrEqual(href, (ns1 != NULL) ? ns1->href : NULL)) { + return(xmlC14NIsVisible(ctx, ns1, cur->nodeTab[i])); + } else { + return(0); + } + } + } + } + return(has_empty_ns); +} + + + + +/** + * xmlC14NIsXmlNs: + * @ns: the namespace to check + * + * Checks whether the given namespace is a default "xml:" namespace + * with href="http://www.w3.org/XML/1998/namespace" + * + * Returns 1 if the node is default or 0 otherwise + */ + +/* todo: make it a define? */ +static int +xmlC14NIsXmlNs(xmlNsPtr ns) +{ + return ((ns != NULL) && + (xmlStrEqual(ns->prefix, BAD_CAST "xml")) && + (xmlStrEqual(ns->href, XML_XML_NAMESPACE))); +} + + +/** + * xmlC14NNsCompare: + * @ns1: the pointer to first namespace + * @ns2: the pointer to second namespace + * + * Compares the namespaces by names (prefixes). + * + * Returns -1 if ns1 < ns2, 0 if ns1 == ns2 or 1 if ns1 > ns2. + */ +static int +xmlC14NNsCompare(xmlNsPtr ns1, xmlNsPtr ns2) +{ + if (ns1 == ns2) + return (0); + if (ns1 == NULL) + return (-1); + if (ns2 == NULL) + return (1); + + return (xmlStrcmp(ns1->prefix, ns2->prefix)); +} + + +/** + * xmlC14NPrintNamespaces: + * @ns: the pointer to namespace + * @ctx: the C14N context + * + * Prints the given namespace to the output buffer from C14N context. + * + * Returns 1 on success or 0 on fail. + */ +static int +xmlC14NPrintNamespaces(const xmlNsPtr ns, xmlC14NCtxPtr ctx) +{ + + if ((ns == NULL) || (ctx == NULL)) { + xmlC14NErrParam("writing namespaces"); + return 0; + } + + if (ns->prefix != NULL) { + xmlOutputBufferWriteString(ctx->buf, " xmlns:"); + xmlOutputBufferWriteString(ctx->buf, (const char *) ns->prefix); + xmlOutputBufferWriteString(ctx->buf, "=\""); + } else { + xmlOutputBufferWriteString(ctx->buf, " xmlns=\""); + } + if(ns->href != NULL) { + xmlOutputBufferWriteString(ctx->buf, (const char *) ns->href); + } + xmlOutputBufferWriteString(ctx->buf, "\""); + return (1); +} + +/** + * xmlC14NProcessNamespacesAxis: + * @ctx: the C14N context + * @node: the current node + * + * Prints out canonical namespace axis of the current node to the + * buffer from C14N context as follows + * + * Canonical XML v 1.0 (http://www.w3.org/TR/xml-c14n) + * + * Namespace Axis + * Consider a list L containing only namespace nodes in the + * axis and in the node-set in lexicographic order (ascending). To begin + * processing L, if the first node is not the default namespace node (a node + * with no namespace URI and no local name), then generate a space followed + * by xmlns="" if and only if the following conditions are met: + * - the element E that owns the axis is in the node-set + * - The nearest ancestor element of E in the node-set has a default + * namespace node in the node-set (default namespace nodes always + * have non-empty values in XPath) + * The latter condition eliminates unnecessary occurrences of xmlns="" in + * the canonical form since an element only receives an xmlns="" if its + * default namespace is empty and if it has an immediate parent in the + * canonical form that has a non-empty default namespace. To finish + * processing L, simply process every namespace node in L, except omit + * namespace node with local name xml, which defines the xml prefix, + * if its string value is http://www.w3.org/XML/1998/namespace. + * + * Exclusive XML Canonicalization v 1.0 (http://www.w3.org/TR/xml-exc-c14n) + * Canonical XML applied to a document subset requires the search of the + * ancestor nodes of each orphan element node for attributes in the xml + * namespace, such as xml:lang and xml:space. These are copied into the + * element node except if a declaration of the same attribute is already + * in the attribute axis of the element (whether or not it is included in + * the document subset). This search and copying are omitted from the + * Exclusive XML Canonicalization method. + * + * Returns 0 on success or -1 on fail. + */ +static int +xmlC14NProcessNamespacesAxis(xmlC14NCtxPtr ctx, xmlNodePtr cur, int visible) +{ + xmlNodePtr n; + xmlNsPtr ns, tmp; + xmlListPtr list; + int already_rendered; + int has_empty_ns = 0; + + if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) { + xmlC14NErrParam("processing namespaces axis (c14n)"); + return (-1); + } + + /* + * Create a sorted list to store element namespaces + */ + list = xmlListCreate(NULL, (xmlListDataCompare) xmlC14NNsCompare); + if (list == NULL) { + xmlC14NErrInternal("creating namespaces list (c14n)"); + return (-1); + } + + /* check all namespaces */ + for(n = cur; n != NULL; n = n->parent) { + for(ns = n->nsDef; ns != NULL; ns = ns->next) { + tmp = xmlSearchNs(cur->doc, cur, ns->prefix); + + if((tmp == ns) && !xmlC14NIsXmlNs(ns) && xmlC14NIsVisible(ctx, ns, cur)) { + already_rendered = xmlC14NVisibleNsStackFind(ctx->ns_rendered, ns); + if(visible) { + xmlC14NVisibleNsStackAdd(ctx->ns_rendered, ns, cur); + } + if(!already_rendered) { + xmlListInsert(list, ns); + } + if(xmlStrlen(ns->prefix) == 0) { + has_empty_ns = 1; + } + } + } + } + + /** + * if the first node is not the default namespace node (a node with no + * namespace URI and no local name), then generate a space followed by + * xmlns="" if and only if the following conditions are met: + * - the element E that owns the axis is in the node-set + * - the nearest ancestor element of E in the node-set has a default + * namespace node in the node-set (default namespace nodes always + * have non-empty values in XPath) + */ + if(visible && !has_empty_ns) { + static xmlNs ns_default; + + memset(&ns_default, 0, sizeof(ns_default)); + if(!xmlC14NVisibleNsStackFind(ctx->ns_rendered, &ns_default)) { + xmlC14NPrintNamespaces(&ns_default, ctx); + } + } + + + /* + * print out all elements from list + */ + xmlListWalk(list, (xmlListWalker) xmlC14NPrintNamespaces, (const void *) ctx); + + /* + * Cleanup + */ + xmlListDelete(list); + return (0); +} + + +/** + * xmlExcC14NProcessNamespacesAxis: + * @ctx: the C14N context + * @node: the current node + * + * Prints out exclusive canonical namespace axis of the current node to the + * buffer from C14N context as follows + * + * Exclusive XML Canonicalization + * http://www.w3.org/TR/xml-exc-c14n + * + * If the element node is in the XPath subset then output the node in + * accordance with Canonical XML except for namespace nodes which are + * rendered as follows: + * + * 1. Render each namespace node iff: + * * it is visibly utilized by the immediate parent element or one of + * its attributes, or is present in InclusiveNamespaces PrefixList, and + * * its prefix and value do not appear in ns_rendered. ns_rendered is + * obtained by popping the state stack in order to obtain a list of + * prefixes and their values which have already been rendered by + * an output ancestor of the namespace node's parent element. + * 2. Append the rendered namespace node to the list ns_rendered of namespace + * nodes rendered by output ancestors. Push ns_rendered on state stack and + * recurse. + * 3. After the recursion returns, pop thestate stack. + * + * + * Returns 0 on success or -1 on fail. + */ +static int +xmlExcC14NProcessNamespacesAxis(xmlC14NCtxPtr ctx, xmlNodePtr cur, int visible) +{ + xmlNsPtr ns; + xmlListPtr list; + xmlAttrPtr attr; + int already_rendered; + int has_empty_ns = 0; + int has_visibly_utilized_empty_ns = 0; + int has_empty_ns_in_inclusive_list = 0; + + if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) { + xmlC14NErrParam("processing namespaces axis (exc c14n)"); + return (-1); + } + + if(!xmlC14NIsExclusive(ctx)) { + xmlC14NErrParam("processing namespaces axis (exc c14n)"); + return (-1); + + } + + /* + * Create a sorted list to store element namespaces + */ + list = xmlListCreate(NULL, (xmlListDataCompare) xmlC14NNsCompare); + if (list == NULL) { + xmlC14NErrInternal("creating namespaces list (exc c14n)"); + return (-1); + } + + /* + * process inclusive namespaces: + * All namespace nodes appearing on inclusive ns list are + * handled as provided in Canonical XML + */ + if(ctx->inclusive_ns_prefixes != NULL) { + xmlChar *prefix; + int i; + + for (i = 0; ctx->inclusive_ns_prefixes[i] != NULL; ++i) { + prefix = ctx->inclusive_ns_prefixes[i]; + /* + * Special values for namespace with empty prefix + */ + if (xmlStrEqual(prefix, BAD_CAST "#default") + || xmlStrEqual(prefix, BAD_CAST "")) { + prefix = NULL; + has_empty_ns_in_inclusive_list = 1; + } + + ns = xmlSearchNs(cur->doc, cur, prefix); + if((ns != NULL) && !xmlC14NIsXmlNs(ns) && xmlC14NIsVisible(ctx, ns, cur)) { + already_rendered = xmlC14NVisibleNsStackFind(ctx->ns_rendered, ns); + if(visible) { + xmlC14NVisibleNsStackAdd(ctx->ns_rendered, ns, cur); + } + if(!already_rendered) { + xmlListInsert(list, ns); + } + if(xmlStrlen(ns->prefix) == 0) { + has_empty_ns = 1; + } + } + } + } + + /* add node namespace */ + if(cur->ns != NULL) { + ns = cur->ns; + } else { + ns = xmlSearchNs(cur->doc, cur, NULL); + has_visibly_utilized_empty_ns = 1; + } + if((ns != NULL) && !xmlC14NIsXmlNs(ns)) { + if(visible && xmlC14NIsVisible(ctx, ns, cur)) { + if(!xmlExcC14NVisibleNsStackFind(ctx->ns_rendered, ns, ctx)) { + xmlListInsert(list, ns); + } + } + if(visible) { + xmlC14NVisibleNsStackAdd(ctx->ns_rendered, ns, cur); + } + if(xmlStrlen(ns->prefix) == 0) { + has_empty_ns = 1; + } + } + + + /* add attributes */ + for(attr = cur->properties; attr != NULL; attr = attr->next) { + /* + * we need to check that attribute is visible and has non + * default namespace (XML Namespaces: "default namespaces + * do not apply directly to attributes") + */ + if((attr->ns != NULL) && !xmlC14NIsXmlNs(attr->ns) && xmlC14NIsVisible(ctx, attr, cur)) { + already_rendered = xmlExcC14NVisibleNsStackFind(ctx->ns_rendered, attr->ns, ctx); + xmlC14NVisibleNsStackAdd(ctx->ns_rendered, attr->ns, cur); + if(!already_rendered && visible) { + xmlListInsert(list, attr->ns); + } + if(xmlStrlen(attr->ns->prefix) == 0) { + has_empty_ns = 1; + } + } else if((attr->ns != NULL) && (xmlStrlen(attr->ns->prefix) == 0) && (xmlStrlen(attr->ns->href) == 0)) { + has_visibly_utilized_empty_ns = 1; + } + } + + /* + * Process xmlns="" + */ + if(visible && has_visibly_utilized_empty_ns && + !has_empty_ns && !has_empty_ns_in_inclusive_list) { + static xmlNs ns_default; + + memset(&ns_default, 0, sizeof(ns_default)); + + already_rendered = xmlExcC14NVisibleNsStackFind(ctx->ns_rendered, &ns_default, ctx); + if(!already_rendered) { + xmlC14NPrintNamespaces(&ns_default, ctx); + } + } else if(visible && !has_empty_ns && has_empty_ns_in_inclusive_list) { + static xmlNs ns_default; + + memset(&ns_default, 0, sizeof(ns_default)); + if(!xmlC14NVisibleNsStackFind(ctx->ns_rendered, &ns_default)) { + xmlC14NPrintNamespaces(&ns_default, ctx); + } + } + + + + /* + * print out all elements from list + */ + xmlListWalk(list, (xmlListWalker) xmlC14NPrintNamespaces, (const void *) ctx); + + /* + * Cleanup + */ + xmlListDelete(list); + return (0); +} + + +/** + * xmlC14NIsXmlAttr: + * @attr: the attr to check + * + * Checks whether the given attribute is a default "xml:" namespace + * with href="http://www.w3.org/XML/1998/namespace" + * + * Returns 1 if the node is default or 0 otherwise + */ + +/* todo: make it a define? */ +static int +xmlC14NIsXmlAttr(xmlAttrPtr attr) +{ + return ((attr->ns != NULL) && + (xmlC14NIsXmlNs(attr->ns) != 0)); +} + + +/** + * xmlC14NAttrsCompare: + * @attr1: the pointer tls o first attr + * @attr2: the pointer to second attr + * + * Prints the given attribute to the output buffer from C14N context. + * + * Returns -1 if attr1 < attr2, 0 if attr1 == attr2 or 1 if attr1 > attr2. + */ +static int +xmlC14NAttrsCompare(xmlAttrPtr attr1, xmlAttrPtr attr2) +{ + int ret = 0; + + /* + * Simple cases + */ + if (attr1 == attr2) + return (0); + if (attr1 == NULL) + return (-1); + if (attr2 == NULL) + return (1); + if (attr1->ns == attr2->ns) { + return (xmlStrcmp(attr1->name, attr2->name)); + } + + /* + * Attributes in the default namespace are first + * because the default namespace is not applied to + * unqualified attributes + */ + if (attr1->ns == NULL) + return (-1); + if (attr2->ns == NULL) + return (1); + if (attr1->ns->prefix == NULL) + return (-1); + if (attr2->ns->prefix == NULL) + return (1); + + ret = xmlStrcmp(attr1->ns->href, attr2->ns->href); + if (ret == 0) { + ret = xmlStrcmp(attr1->name, attr2->name); + } + return (ret); +} + + +/** + * xmlC14NPrintAttrs: + * @attr: the pointer to attr + * @ctx: the C14N context + * + * Prints out canonical attribute urrent node to the + * buffer from C14N context as follows + * + * Canonical XML v 1.0 (http://www.w3.org/TR/xml-c14n) + * + * Returns 1 on success or 0 on fail. + */ +static int +xmlC14NPrintAttrs(const xmlAttrPtr attr, xmlC14NCtxPtr ctx) +{ + xmlChar *value; + xmlChar *buffer; + + if ((attr == NULL) || (ctx == NULL)) { + xmlC14NErrParam("writing attributes"); + return (0); + } + + xmlOutputBufferWriteString(ctx->buf, " "); + if (attr->ns != NULL && xmlStrlen(attr->ns->prefix) > 0) { + xmlOutputBufferWriteString(ctx->buf, + (const char *) attr->ns->prefix); + xmlOutputBufferWriteString(ctx->buf, ":"); + } + xmlOutputBufferWriteString(ctx->buf, (const char *) attr->name); + xmlOutputBufferWriteString(ctx->buf, "=\""); + + value = xmlNodeListGetString(ctx->doc, attr->children, 1); + /* todo: should we log an error if value==NULL ? */ + if (value != NULL) { + buffer = xmlC11NNormalizeAttr(value); + xmlFree(value); + if (buffer != NULL) { + xmlOutputBufferWriteString(ctx->buf, (const char *) buffer); + xmlFree(buffer); + } else { + xmlC14NErrInternal("normalizing attributes axis"); + return (0); + } + } + xmlOutputBufferWriteString(ctx->buf, "\""); + return (1); +} + +/** + * xmlC14NFindHiddenParentAttr: + * + * Finds an attribute in a hidden parent node. + * + * Returns a pointer to the attribute node (if found) or NULL otherwise. + */ +static xmlAttrPtr +xmlC14NFindHiddenParentAttr(xmlC14NCtxPtr ctx, xmlNodePtr cur, const xmlChar * name, const xmlChar * ns) +{ + xmlAttrPtr res; + while((cur != NULL) && (!xmlC14NIsVisible(ctx, cur, cur->parent))) { + res = xmlHasNsProp(cur, name, ns); + if(res != NULL) { + return res; + } + + cur = cur->parent; + } + + return NULL; +} + +/** + * xmlC14NFixupBaseAttr: + * + * Fixes up the xml:base attribute + * + * Returns the newly created attribute or NULL + */ +static xmlAttrPtr +xmlC14NFixupBaseAttr(xmlC14NCtxPtr ctx, xmlAttrPtr xml_base_attr) +{ + xmlChar * res = NULL; + xmlNodePtr cur; + xmlAttrPtr attr; + xmlChar * tmp_str; + xmlChar * tmp_str2; + int tmp_str_len; + + if ((ctx == NULL) || (xml_base_attr == NULL) || (xml_base_attr->parent == NULL)) { + xmlC14NErrParam("processing xml:base attribute"); + return (NULL); + } + + /* start from current value */ + res = xmlNodeListGetString(ctx->doc, xml_base_attr->children, 1); + if(res == NULL) { + xmlC14NErrInternal("processing xml:base attribute - can't get attr value"); + return (NULL); + } + + /* go up the stack until we find a node that we rendered already */ + cur = xml_base_attr->parent->parent; + while((cur != NULL) && (!xmlC14NIsVisible(ctx, cur, cur->parent))) { + attr = xmlHasNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE); + if(attr != NULL) { + /* get attr value */ + tmp_str = xmlNodeListGetString(ctx->doc, attr->children, 1); + if(tmp_str == NULL) { + xmlFree(res); + + xmlC14NErrInternal("processing xml:base attribute - can't get attr value"); + return (NULL); + } + + /* we need to add '/' if our current base uri ends with '..' or '.' + to ensure that we are forced to go "up" all the time */ + tmp_str_len = xmlStrlen(tmp_str); + if(tmp_str_len > 1 && tmp_str[tmp_str_len - 2] == '.') { + tmp_str2 = xmlStrcat(tmp_str, BAD_CAST "/"); + if(tmp_str2 == NULL) { + xmlFree(tmp_str); + xmlFree(res); + + xmlC14NErrInternal("processing xml:base attribute - can't modify uri"); + return (NULL); + } + + tmp_str = tmp_str2; + } + + /* build uri */ + tmp_str2 = xmlBuildURI(res, tmp_str); + if(tmp_str2 == NULL) { + xmlFree(tmp_str); + xmlFree(res); + + xmlC14NErrInternal("processing xml:base attribute - can't construct uri"); + return (NULL); + } + + /* cleanup and set the new res */ + xmlFree(tmp_str); + xmlFree(res); + res = tmp_str2; + } + + /* next */ + cur = cur->parent; + } + + /* check if result uri is empty or not */ + if((res == NULL) || xmlStrEqual(res, BAD_CAST "")) { + xmlFree(res); + return (NULL); + } + + /* create and return the new attribute node */ + attr = xmlNewNsProp(NULL, xml_base_attr->ns, BAD_CAST "base", res); + if(attr == NULL) { + xmlFree(res); + + xmlC14NErrInternal("processing xml:base attribute - can't construct attribute"); + return (NULL); + } + + /* done */ + xmlFree(res); + return (attr); +} + +/** + * xmlC14NProcessAttrsAxis: + * @ctx: the C14N context + * @cur: the current node + * @parent_visible: the visibility of parent node + * @all_parents_visible: the visibility of all parent nodes + * + * Prints out canonical attribute axis of the current node to the + * buffer from C14N context as follows + * + * Canonical XML v 1.0 (http://www.w3.org/TR/xml-c14n) + * + * Attribute Axis + * In lexicographic order (ascending), process each node that + * is in the element's attribute axis and in the node-set. + * + * The processing of an element node E MUST be modified slightly + * when an XPath node-set is given as input and the element's + * parent is omitted from the node-set. + * + * + * Exclusive XML Canonicalization v 1.0 (http://www.w3.org/TR/xml-exc-c14n) + * + * Canonical XML applied to a document subset requires the search of the + * ancestor nodes of each orphan element node for attributes in the xml + * namespace, such as xml:lang and xml:space. These are copied into the + * element node except if a declaration of the same attribute is already + * in the attribute axis of the element (whether or not it is included in + * the document subset). This search and copying are omitted from the + * Exclusive XML Canonicalization method. + * + * Returns 0 on success or -1 on fail. + */ +static int +xmlC14NProcessAttrsAxis(xmlC14NCtxPtr ctx, xmlNodePtr cur, int parent_visible) +{ + xmlAttrPtr attr; + xmlListPtr list; + xmlAttrPtr attrs_to_delete = NULL; + + /* special processing for 1.1 spec */ + xmlAttrPtr xml_base_attr = NULL; + xmlAttrPtr xml_lang_attr = NULL; + xmlAttrPtr xml_space_attr = NULL; + + if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) { + xmlC14NErrParam("processing attributes axis"); + return (-1); + } + + /* + * Create a sorted list to store element attributes + */ + list = xmlListCreate(NULL, (xmlListDataCompare) xmlC14NAttrsCompare); + if (list == NULL) { + xmlC14NErrInternal("creating attributes list"); + return (-1); + } + + switch(ctx->mode) { + case XML_C14N_1_0: + /* The processing of an element node E MUST be modified slightly when an XPath node-set is + * given as input and the element's parent is omitted from the node-set. The method for processing + * the attribute axis of an element E in the node-set is enhanced. All element nodes along E's + * ancestor axis are examined for nearest occurrences of attributes in the xml namespace, such + * as xml:lang and xml:space (whether or not they are in the node-set). From this list of attributes, + * remove any that are in E's attribute axis (whether or not they are in the node-set). Then, + * lexicographically merge this attribute list with the nodes of E's attribute axis that are in + * the node-set. The result of visiting the attribute axis is computed by processing the attribute + * nodes in this merged attribute list. + */ + + /* + * Add all visible attributes from current node. + */ + attr = cur->properties; + while (attr != NULL) { + /* check that attribute is visible */ + if (xmlC14NIsVisible(ctx, attr, cur)) { + xmlListInsert(list, attr); + } + attr = attr->next; + } + + /* + * Handle xml attributes + */ + if (parent_visible && (cur->parent != NULL) && + (!xmlC14NIsVisible(ctx, cur->parent, cur->parent->parent))) + { + xmlNodePtr tmp; + + /* + * If XPath node-set is not specified then the parent is always + * visible! + */ + tmp = cur->parent; + while (tmp != NULL) { + attr = tmp->properties; + while (attr != NULL) { + if (xmlC14NIsXmlAttr(attr) != 0) { + if (xmlListSearch(list, attr) == NULL) { + xmlListInsert(list, attr); + } + } + attr = attr->next; + } + tmp = tmp->parent; + } + } + + /* done */ + break; + case XML_C14N_EXCLUSIVE_1_0: + /* attributes in the XML namespace, such as xml:lang and xml:space + * are not imported into orphan nodes of the document subset + */ + + /* + * Add all visible attributes from current node. + */ + attr = cur->properties; + while (attr != NULL) { + /* check that attribute is visible */ + if (xmlC14NIsVisible(ctx, attr, cur)) { + xmlListInsert(list, attr); + } + attr = attr->next; + } + + /* do nothing special for xml attributes */ + break; + case XML_C14N_1_1: + /* The processing of an element node E MUST be modified slightly when an XPath node-set is + * given as input and some of the element's ancestors are omitted from the node-set. + * + * Simple inheritable attributes are attributes that have a value that requires at most a simple + * redeclaration. This redeclaration is done by supplying a new value in the child axis. The + * redeclaration of a simple inheritable attribute A contained in one of E's ancestors is done + * by supplying a value to an attribute Ae inside E with the same name. Simple inheritable attributes + * are xml:lang and xml:space. + * + * The method for processing the attribute axis of an element E in the node-set is hence enhanced. + * All element nodes along E's ancestor axis are examined for the nearest occurrences of simple + * inheritable attributes in the xml namespace, such as xml:lang and xml:space (whether or not they + * are in the node-set). From this list of attributes, any simple inheritable attributes that are + * already in E's attribute axis (whether or not they are in the node-set) are removed. Then, + * lexicographically merge this attribute list with the nodes of E's attribute axis that are in + * the node-set. The result of visiting the attribute axis is computed by processing the attribute + * nodes in this merged attribute list. + * + * The xml:id attribute is not a simple inheritable attribute and no processing of these attributes is + * performed. + * + * The xml:base attribute is not a simple inheritable attribute and requires special processing beyond + * a simple redeclaration. + * + * Attributes in the XML namespace other than xml:base, xml:id, xml:lang, and xml:space MUST be processed + * as ordinary attributes. + */ + + /* + * Add all visible attributes from current node. + */ + attr = cur->properties; + while (attr != NULL) { + /* special processing for XML attribute kiks in only when we have invisible parents */ + if ((!parent_visible) || (xmlC14NIsXmlAttr(attr) == 0)) { + /* check that attribute is visible */ + if (xmlC14NIsVisible(ctx, attr, cur)) { + xmlListInsert(list, attr); + } + } else { + int matched = 0; + + /* check for simple inheritance attributes */ + if((!matched) && (xml_lang_attr == NULL) && xmlStrEqual(attr->name, BAD_CAST "lang")) { + xml_lang_attr = attr; + matched = 1; + } + if((!matched) && (xml_space_attr == NULL) && xmlStrEqual(attr->name, BAD_CAST "space")) { + xml_space_attr = attr; + matched = 1; + } + + /* check for base attr */ + if((!matched) && (xml_base_attr == NULL) && xmlStrEqual(attr->name, BAD_CAST "base")) { + xml_base_attr = attr; + matched = 1; + } + + /* otherwise, it is a normal attribute, so just check if it is visible */ + if((!matched) && xmlC14NIsVisible(ctx, attr, cur)) { + xmlListInsert(list, attr); + } + } + + /* move to the next one */ + attr = attr->next; + } + + /* special processing for XML attribute kiks in only when we have invisible parents */ + if ((parent_visible)) { + + /* simple inheritance attributes - copy */ + if(xml_lang_attr == NULL) { + xml_lang_attr = xmlC14NFindHiddenParentAttr(ctx, cur->parent, BAD_CAST "lang", XML_XML_NAMESPACE); + } + if(xml_lang_attr != NULL) { + xmlListInsert(list, xml_lang_attr); + } + if(xml_space_attr == NULL) { + xml_space_attr = xmlC14NFindHiddenParentAttr(ctx, cur->parent, BAD_CAST "space", XML_XML_NAMESPACE); + } + if(xml_space_attr != NULL) { + xmlListInsert(list, xml_space_attr); + } + + /* base uri attribute - fix up */ + if(xml_base_attr == NULL) { + /* if we don't have base uri attribute, check if we have a "hidden" one above */ + xml_base_attr = xmlC14NFindHiddenParentAttr(ctx, cur->parent, BAD_CAST "base", XML_XML_NAMESPACE); + } + if(xml_base_attr != NULL) { + xml_base_attr = xmlC14NFixupBaseAttr(ctx, xml_base_attr); + if(xml_base_attr != NULL) { + xmlListInsert(list, xml_base_attr); + + /* note that we MUST delete returned attr node ourselves! */ + xml_base_attr->next = attrs_to_delete; + attrs_to_delete = xml_base_attr; + } + } + } + + /* done */ + break; + } + + /* + * print out all elements from list + */ + xmlListWalk(list, (xmlListWalker) xmlC14NPrintAttrs, (const void *) ctx); + + /* + * Cleanup + */ + xmlFreePropList(attrs_to_delete); + xmlListDelete(list); + return (0); +} + +/** + * xmlC14NCheckForRelativeNamespaces: + * @ctx: the C14N context + * @cur: the current element node + * + * Checks that current element node has no relative namespaces defined + * + * Returns 0 if the node has no relative namespaces or -1 otherwise. + */ +static int +xmlC14NCheckForRelativeNamespaces(xmlC14NCtxPtr ctx, xmlNodePtr cur) +{ + xmlNsPtr ns; + + if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) { + xmlC14NErrParam("checking for relative namespaces"); + return (-1); + } + + ns = cur->nsDef; + while (ns != NULL) { + if (xmlStrlen(ns->href) > 0) { + xmlURIPtr uri; + + uri = xmlParseURI((const char *) ns->href); + if (uri == NULL) { + xmlC14NErrInternal("parsing namespace uri"); + return (-1); + } + if (xmlStrlen((const xmlChar *) uri->scheme) == 0) { + xmlC14NErrRelativeNamespace(uri->scheme); + xmlFreeURI(uri); + return (-1); + } + if ((xmlStrcasecmp((const xmlChar *) uri->scheme, BAD_CAST "urn") != 0) + && (xmlStrcasecmp((const xmlChar *) uri->scheme, BAD_CAST "dav") !=0) + && (xmlStrlen((const xmlChar *) uri->server) == 0)) { + xmlC14NErrRelativeNamespace(uri->scheme); + xmlFreeURI(uri); + return (-1); + } + xmlFreeURI(uri); + } + ns = ns->next; + } + return (0); +} + +/** + * xmlC14NProcessElementNode: + * @ctx: the pointer to C14N context object + * @cur: the node to process + * @visible: this node is visible + * @all_parents_visible: whether all the parents of this node are visible + * + * Canonical XML v 1.0 (http://www.w3.org/TR/xml-c14n) + * + * Element Nodes + * If the element is not in the node-set, then the result is obtained + * by processing the namespace axis, then the attribute axis, then + * processing the child nodes of the element that are in the node-set + * (in document order). If the element is in the node-set, then the result + * is an open angle bracket (<), the element QName, the result of + * processing the namespace axis, the result of processing the attribute + * axis, a close angle bracket (>), the result of processing the child + * nodes of the element that are in the node-set (in document order), an + * open angle bracket, a forward slash (/), the element QName, and a close + * angle bracket. + * + * Returns non-negative value on success or negative value on fail + */ +static int +xmlC14NProcessElementNode(xmlC14NCtxPtr ctx, xmlNodePtr cur, int visible) +{ + int ret; + xmlC14NVisibleNsStack state; + int parent_is_doc = 0; + + if ((ctx == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) { + xmlC14NErrParam("processing element node"); + return (-1); + } + + /* + * Check relative relative namespaces: + * implementations of XML canonicalization MUST report an operation + * failure on documents containing relative namespace URIs. + */ + if (xmlC14NCheckForRelativeNamespaces(ctx, cur) < 0) { + xmlC14NErrInternal("checking for relative namespaces"); + return (-1); + } + + + /* + * Save ns_rendered stack position + */ + memset(&state, 0, sizeof(state)); + xmlC14NVisibleNsStackSave(ctx->ns_rendered, &state); + + if (visible) { + if (ctx->parent_is_doc) { + /* save this flag into the stack */ + parent_is_doc = ctx->parent_is_doc; + ctx->parent_is_doc = 0; + ctx->pos = XMLC14N_INSIDE_DOCUMENT_ELEMENT; + } + xmlOutputBufferWriteString(ctx->buf, "<"); + + if ((cur->ns != NULL) && (xmlStrlen(cur->ns->prefix) > 0)) { + xmlOutputBufferWriteString(ctx->buf, + (const char *) cur->ns->prefix); + xmlOutputBufferWriteString(ctx->buf, ":"); + } + xmlOutputBufferWriteString(ctx->buf, (const char *) cur->name); + } + + if (!xmlC14NIsExclusive(ctx)) { + ret = xmlC14NProcessNamespacesAxis(ctx, cur, visible); + } else { + ret = xmlExcC14NProcessNamespacesAxis(ctx, cur, visible); + } + if (ret < 0) { + xmlC14NErrInternal("processing namespaces axis"); + return (-1); + } + /* todo: shouldn't this go to "visible only"? */ + if(visible) { + xmlC14NVisibleNsStackShift(ctx->ns_rendered); + } + + ret = xmlC14NProcessAttrsAxis(ctx, cur, visible); + if (ret < 0) { + xmlC14NErrInternal("processing attributes axis"); + return (-1); + } + + if (visible) { + xmlOutputBufferWriteString(ctx->buf, ">"); + } + if (cur->children != NULL) { + ret = xmlC14NProcessNodeList(ctx, cur->children); + if (ret < 0) { + xmlC14NErrInternal("processing childrens list"); + return (-1); + } + } + if (visible) { + xmlOutputBufferWriteString(ctx->buf, "ns != NULL) && (xmlStrlen(cur->ns->prefix) > 0)) { + xmlOutputBufferWriteString(ctx->buf, + (const char *) cur->ns->prefix); + xmlOutputBufferWriteString(ctx->buf, ":"); + } + xmlOutputBufferWriteString(ctx->buf, (const char *) cur->name); + xmlOutputBufferWriteString(ctx->buf, ">"); + if (parent_is_doc) { + /* restore this flag from the stack for next node */ + ctx->parent_is_doc = parent_is_doc; + ctx->pos = XMLC14N_AFTER_DOCUMENT_ELEMENT; + } + } + + /* + * Restore ns_rendered stack position + */ + xmlC14NVisibleNsStackRestore(ctx->ns_rendered, &state); + return (0); +} + +/** + * xmlC14NProcessNode: + * @ctx: the pointer to C14N context object + * @cur: the node to process + * + * Processes the given node + * + * Returns non-negative value on success or negative value on fail + */ +static int +xmlC14NProcessNode(xmlC14NCtxPtr ctx, xmlNodePtr cur) +{ + int ret = 0; + int visible; + + if ((ctx == NULL) || (cur == NULL)) { + xmlC14NErrParam("processing node"); + return (-1); + } + + visible = xmlC14NIsVisible(ctx, cur, cur->parent); + switch (cur->type) { + case XML_ELEMENT_NODE: + ret = xmlC14NProcessElementNode(ctx, cur, visible); + break; + case XML_CDATA_SECTION_NODE: + case XML_TEXT_NODE: + /* + * Text Nodes + * the string value, except all ampersands are replaced + * by &, all open angle brackets (<) are replaced by <, all closing + * angle brackets (>) are replaced by >, and all #xD characters are + * replaced by . + */ + /* cdata sections are processed as text nodes */ + /* todo: verify that cdata sections are included in XPath nodes set */ + if ((visible) && (cur->content != NULL)) { + xmlChar *buffer; + + buffer = xmlC11NNormalizeText(cur->content); + if (buffer != NULL) { + xmlOutputBufferWriteString(ctx->buf, + (const char *) buffer); + xmlFree(buffer); + } else { + xmlC14NErrInternal("normalizing text node"); + return (-1); + } + } + break; + case XML_PI_NODE: + /* + * Processing Instruction (PI) Nodes- + * The opening PI symbol (). If the string value is empty, + * then the leading space is not added. Also, a trailing #xA is + * rendered after the closing PI symbol for PI children of the + * root node with a lesser document order than the document + * element, and a leading #xA is rendered before the opening PI + * symbol of PI children of the root node with a greater document + * order than the document element. + */ + if (visible) { + if (ctx->pos == XMLC14N_AFTER_DOCUMENT_ELEMENT) { + xmlOutputBufferWriteString(ctx->buf, "\x0Abuf, "buf, + (const char *) cur->name); + if ((cur->content != NULL) && (*(cur->content) != '\0')) { + xmlChar *buffer; + + xmlOutputBufferWriteString(ctx->buf, " "); + + /* todo: do we need to normalize pi? */ + buffer = xmlC11NNormalizePI(cur->content); + if (buffer != NULL) { + xmlOutputBufferWriteString(ctx->buf, + (const char *) buffer); + xmlFree(buffer); + } else { + xmlC14NErrInternal("normalizing pi node"); + return (-1); + } + } + + if (ctx->pos == XMLC14N_BEFORE_DOCUMENT_ELEMENT) { + xmlOutputBufferWriteString(ctx->buf, "?>\x0A"); + } else { + xmlOutputBufferWriteString(ctx->buf, "?>"); + } + } + break; + case XML_COMMENT_NODE: + /* + * Comment Nodes + * Nothing if generating canonical XML without comments. For + * canonical XML with comments, generate the opening comment + * symbol (). Also, a trailing #xA is rendered + * after the closing comment symbol for comment children of the + * root node with a lesser document order than the document + * element, and a leading #xA is rendered before the opening + * comment symbol of comment children of the root node with a + * greater document order than the document element. (Comment + * children of the root node represent comments outside of the + * top-level document element and outside of the document type + * declaration). + */ + if (visible && ctx->with_comments) { + if (ctx->pos == XMLC14N_AFTER_DOCUMENT_ELEMENT) { + xmlOutputBufferWriteString(ctx->buf, "\x0A\x0A"); + } else { + xmlOutputBufferWriteString(ctx->buf, "-->"); + } + } + break; + case XML_DOCUMENT_NODE: + case XML_DOCUMENT_FRAG_NODE: /* should be processed as document? */ +#ifdef LIBXML_DOCB_ENABLED + case XML_DOCB_DOCUMENT_NODE: /* should be processed as document? */ +#endif + if (cur->children != NULL) { + ctx->pos = XMLC14N_BEFORE_DOCUMENT_ELEMENT; + ctx->parent_is_doc = 1; + ret = xmlC14NProcessNodeList(ctx, cur->children); + } + break; + + case XML_ATTRIBUTE_NODE: + xmlC14NErrInvalidNode("XML_ATTRIBUTE_NODE", "processing node"); + return (-1); + case XML_NAMESPACE_DECL: + xmlC14NErrInvalidNode("XML_NAMESPACE_DECL", "processing node"); + return (-1); + case XML_ENTITY_REF_NODE: + xmlC14NErrInvalidNode("XML_ENTITY_REF_NODE", "processing node"); + return (-1); + case XML_ENTITY_NODE: + xmlC14NErrInvalidNode("XML_ENTITY_NODE", "processing node"); + return (-1); + + 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: +#ifdef LIBXML_XINCLUDE_ENABLED + case XML_XINCLUDE_START: + case XML_XINCLUDE_END: +#endif + /* + * should be ignored according to "W3C Canonical XML" + */ + break; + default: + xmlC14NErrUnknownNode(cur->type, "processing node"); + return (-1); + } + + return (ret); +} + +/** + * xmlC14NProcessNodeList: + * @ctx: the pointer to C14N context object + * @cur: the node to start from + * + * Processes all nodes in the row starting from cur. + * + * Returns non-negative value on success or negative value on fail + */ +static int +xmlC14NProcessNodeList(xmlC14NCtxPtr ctx, xmlNodePtr cur) +{ + int ret; + + if (ctx == NULL) { + xmlC14NErrParam("processing node list"); + return (-1); + } + + for (ret = 0; cur != NULL && ret >= 0; cur = cur->next) { + ret = xmlC14NProcessNode(ctx, cur); + } + return (ret); +} + + +/** + * xmlC14NFreeCtx: + * @ctx: the pointer to C14N context object + * + * Cleanups the C14N context object. + */ + +static void +xmlC14NFreeCtx(xmlC14NCtxPtr ctx) +{ + if (ctx == NULL) { + xmlC14NErrParam("freeing context"); + return; + } + + if (ctx->ns_rendered != NULL) { + xmlC14NVisibleNsStackDestroy(ctx->ns_rendered); + } + xmlFree(ctx); +} + +/** + * xmlC14NNewCtx: + * @doc: the XML document for canonization + * @is_visible_callback:the function to use to determine is node visible + * or not + * @user_data: the first parameter for @is_visible_callback function + * (in most cases, it is nodes set) + * @mode: the c14n mode (see @xmlC14NMode) + * @inclusive_ns_prefixe the list of inclusive namespace prefixes + * ended with a NULL or NULL if there is no + * inclusive namespaces (only for ` + * canonicalization) + * @with_comments: include comments in the result (!=0) or not (==0) + * @buf: the output buffer to store canonical XML; this + * buffer MUST have encoder==NULL because C14N requires + * UTF-8 output + * + * Creates new C14N context object to store C14N parameters. + * + * Returns pointer to newly created object (success) or NULL (fail) + */ +static xmlC14NCtxPtr +xmlC14NNewCtx(xmlDocPtr doc, + xmlC14NIsVisibleCallback is_visible_callback, void* user_data, + xmlC14NMode mode, xmlChar ** inclusive_ns_prefixes, + int with_comments, xmlOutputBufferPtr buf) +{ + xmlC14NCtxPtr ctx = NULL; + + if ((doc == NULL) || (buf == NULL)) { + xmlC14NErrParam("creating new context"); + return (NULL); + } + + /* + * Validate the encoding output buffer encoding + */ + if (buf->encoder != NULL) { + xmlC14NErr(ctx, (xmlNodePtr) doc, XML_C14N_REQUIRES_UTF8, +"xmlC14NNewCtx: output buffer encoder != NULL but C14N requires UTF8 output\n"); + return (NULL); + } + + /* + * Validate the XML document encoding value, if provided. + */ + if (doc->charset != XML_CHAR_ENCODING_UTF8) { + xmlC14NErr(ctx, (xmlNodePtr) doc, XML_C14N_REQUIRES_UTF8, + "xmlC14NNewCtx: source document not in UTF8\n"); + return (NULL); + } + + /* + * Allocate a new xmlC14NCtxPtr and fill the fields. + */ + ctx = (xmlC14NCtxPtr) xmlMalloc(sizeof(xmlC14NCtx)); + if (ctx == NULL) { + xmlC14NErrMemory("creating context"); + return (NULL); + } + memset(ctx, 0, sizeof(xmlC14NCtx)); + + /* + * initialize C14N context + */ + ctx->doc = doc; + ctx->with_comments = with_comments; + ctx->is_visible_callback = is_visible_callback; + ctx->user_data = user_data; + ctx->buf = buf; + ctx->parent_is_doc = 1; + ctx->pos = XMLC14N_BEFORE_DOCUMENT_ELEMENT; + ctx->ns_rendered = xmlC14NVisibleNsStackCreate(); + + if(ctx->ns_rendered == NULL) { + xmlC14NErr(ctx, (xmlNodePtr) doc, XML_C14N_CREATE_STACK, + "xmlC14NNewCtx: xmlC14NVisibleNsStackCreate failed\n"); + xmlC14NFreeCtx(ctx); + return (NULL); + } + + /* + * Set "mode" flag and remember list of incluseve prefixes + * for exclusive c14n + */ + ctx->mode = mode; + if(xmlC14NIsExclusive(ctx)) { + ctx->inclusive_ns_prefixes = inclusive_ns_prefixes; + } + return (ctx); +} + +/** + * xmlC14NExecute: + * @doc: the XML document for canonization + * @is_visible_callback:the function to use to determine is node visible + * or not + * @user_data: the first parameter for @is_visible_callback function + * (in most cases, it is nodes set) + * @mode: the c14n mode (see @xmlC14NMode) + * @inclusive_ns_prefixes: the list of inclusive namespace prefixes + * ended with a NULL or NULL if there is no + * inclusive namespaces (only for exclusive + * canonicalization, ignored otherwise) + * @with_comments: include comments in the result (!=0) or not (==0) + * @buf: the output buffer to store canonical XML; this + * buffer MUST have encoder==NULL because C14N requires + * UTF-8 output + * + * Dumps the canonized image of given XML document into the provided buffer. + * For details see "Canonical XML" (http://www.w3.org/TR/xml-c14n) or + * "Exclusive XML Canonicalization" (http://www.w3.org/TR/xml-exc-c14n) + * + * Returns non-negative value on success or a negative value on fail + */ +int +xmlC14NExecute(xmlDocPtr doc, xmlC14NIsVisibleCallback is_visible_callback, + void* user_data, int mode, xmlChar **inclusive_ns_prefixes, + int with_comments, xmlOutputBufferPtr buf) { + + xmlC14NCtxPtr ctx; + xmlC14NMode c14n_mode = XML_C14N_1_0; + int ret; + + if ((buf == NULL) || (doc == NULL)) { + xmlC14NErrParam("executing c14n"); + return (-1); + } + + /* for backward compatibility, we have to have "mode" as "int" + and here we check that user gives valid value */ + switch(mode) { + case XML_C14N_1_0: + case XML_C14N_EXCLUSIVE_1_0: + case XML_C14N_1_1: + c14n_mode = (xmlC14NMode)mode; + break; + default: + xmlC14NErrParam("invalid mode for executing c14n"); + return (-1); + } + + /* + * Validate the encoding output buffer encoding + */ + if (buf->encoder != NULL) { + xmlC14NErr(NULL, (xmlNodePtr) doc, XML_C14N_REQUIRES_UTF8, +"xmlC14NExecute: output buffer encoder != NULL but C14N requires UTF8 output\n"); + return (-1); + } + + ctx = xmlC14NNewCtx(doc, is_visible_callback, user_data, + c14n_mode, inclusive_ns_prefixes, + with_comments, buf); + if (ctx == NULL) { + xmlC14NErr(NULL, (xmlNodePtr) doc, XML_C14N_CREATE_CTXT, + "xmlC14NExecute: unable to create C14N context\n"); + return (-1); + } + + + + /* + * Root Node + * The root node is the parent of the top-level document element. The + * result of processing each of its child nodes that is in the node-set + * in document order. The root node does not generate a byte order mark, + * XML declaration, nor anything from within the document type + * declaration. + */ + if (doc->children != NULL) { + ret = xmlC14NProcessNodeList(ctx, doc->children); + if (ret < 0) { + xmlC14NErrInternal("processing docs children list"); + xmlC14NFreeCtx(ctx); + return (-1); + } + } + + /* + * Flush buffer to get number of bytes written + */ + ret = xmlOutputBufferFlush(buf); + if (ret < 0) { + xmlC14NErrInternal("flushing output buffer"); + xmlC14NFreeCtx(ctx); + return (-1); + } + + /* + * Cleanup + */ + xmlC14NFreeCtx(ctx); + return (ret); +} + +/** + * xmlC14NDocSaveTo: + * @doc: the XML document for canonization + * @nodes: the nodes set to be included in the canonized image + * or NULL if all document nodes should be included + * @mode: the c14n mode (see @xmlC14NMode) + * @inclusive_ns_prefixes: the list of inclusive namespace prefixes + * ended with a NULL or NULL if there is no + * inclusive namespaces (only for exclusive + * canonicalization, ignored otherwise) + * @with_comments: include comments in the result (!=0) or not (==0) + * @buf: the output buffer to store canonical XML; this + * buffer MUST have encoder==NULL because C14N requires + * UTF-8 output + * + * Dumps the canonized image of given XML document into the provided buffer. + * For details see "Canonical XML" (http://www.w3.org/TR/xml-c14n) or + * "Exclusive XML Canonicalization" (http://www.w3.org/TR/xml-exc-c14n) + * + * Returns non-negative value on success or a negative value on fail + */ +int +xmlC14NDocSaveTo(xmlDocPtr doc, xmlNodeSetPtr nodes, + int mode, xmlChar ** inclusive_ns_prefixes, + int with_comments, xmlOutputBufferPtr buf) { + return(xmlC14NExecute(doc, + (xmlC14NIsVisibleCallback)xmlC14NIsNodeInNodeset, + nodes, + mode, + inclusive_ns_prefixes, + with_comments, + buf)); +} + + +/** + * xmlC14NDocDumpMemory: + * @doc: the XML document for canonization + * @nodes: the nodes set to be included in the canonized image + * or NULL if all document nodes should be included + * @mode: the c14n mode (see @xmlC14NMode) + * @inclusive_ns_prefixes: the list of inclusive namespace prefixes + * ended with a NULL or NULL if there is no + * inclusive namespaces (only for exclusive + * canonicalization, ignored otherwise) + * @with_comments: include comments in the result (!=0) or not (==0) + * @doc_txt_ptr: the memory pointer for allocated canonical XML text; + * the caller of this functions is responsible for calling + * xmlFree() to free allocated memory + * + * Dumps the canonized image of given XML document into memory. + * For details see "Canonical XML" (http://www.w3.org/TR/xml-c14n) or + * "Exclusive XML Canonicalization" (http://www.w3.org/TR/xml-exc-c14n) + * + * Returns the number of bytes written on success or a negative value on fail + */ +int +xmlC14NDocDumpMemory(xmlDocPtr doc, xmlNodeSetPtr nodes, + int mode, xmlChar ** inclusive_ns_prefixes, + int with_comments, xmlChar ** doc_txt_ptr) +{ + int ret; + xmlOutputBufferPtr buf; + + if (doc_txt_ptr == NULL) { + xmlC14NErrParam("dumping doc to memory"); + return (-1); + } + + *doc_txt_ptr = NULL; + + /* + * create memory buffer with UTF8 (default) encoding + */ + buf = xmlAllocOutputBuffer(NULL); + if (buf == NULL) { + xmlC14NErrMemory("creating output buffer"); + return (-1); + } + + /* + * canonize document and write to buffer + */ + ret = xmlC14NDocSaveTo(doc, nodes, mode, inclusive_ns_prefixes, + with_comments, buf); + if (ret < 0) { + xmlC14NErrInternal("saving doc to output buffer"); + (void) xmlOutputBufferClose(buf); + return (-1); + } + + ret = buf->buffer->use; + if (ret > 0) { + *doc_txt_ptr = xmlStrndup(buf->buffer->content, ret); + } + (void) xmlOutputBufferClose(buf); + + if ((*doc_txt_ptr == NULL) && (ret > 0)) { + xmlC14NErrMemory("coping canonicanized document"); + return (-1); + } + return (ret); +} + +/** + * xmlC14NDocSave: + * @doc: the XML document for canonization + * @nodes: the nodes set to be included in the canonized image + * or NULL if all document nodes should be included + * @mode: the c14n mode (see @xmlC14NMode) + * @inclusive_ns_prefixes: the list of inclusive namespace prefixes + * ended with a NULL or NULL if there is no + * inclusive namespaces (only for exclusive + * canonicalization, ignored otherwise) + * @with_comments: include comments in the result (!=0) or not (==0) + * @filename: the filename to store canonical XML image + * @compression: the compression level (zlib requred): + * -1 - libxml default, + * 0 - uncompressed, + * >0 - compression level + * + * Dumps the canonized image of given XML document into the file. + * For details see "Canonical XML" (http://www.w3.org/TR/xml-c14n) or + * "Exclusive XML Canonicalization" (http://www.w3.org/TR/xml-exc-c14n) + * + * Returns the number of bytes written success or a negative value on fail + */ +int +xmlC14NDocSave(xmlDocPtr doc, xmlNodeSetPtr nodes, + int mode, xmlChar ** inclusive_ns_prefixes, + int with_comments, const char *filename, int compression) +{ + xmlOutputBufferPtr buf; + int ret; + + if (filename == NULL) { + xmlC14NErrParam("saving doc"); + return (-1); + } +#ifdef HAVE_ZLIB_H + if (compression < 0) + compression = xmlGetCompressMode(); +#endif + + /* + * save the content to a temp buffer, use default UTF8 encoding. + */ + buf = xmlOutputBufferCreateFilename(filename, NULL, compression); + if (buf == NULL) { + xmlC14NErrInternal("creating temporary filename"); + return (-1); + } + + /* + * canonize document and write to buffer + */ + ret = xmlC14NDocSaveTo(doc, nodes, mode, inclusive_ns_prefixes, + with_comments, buf); + if (ret < 0) { + xmlC14NErrInternal("cannicanize document to buffer"); + (void) xmlOutputBufferClose(buf); + return (-1); + } + + /* + * get the numbers of bytes written + */ + ret = xmlOutputBufferClose(buf); + return (ret); +} + + + +/* + * Macro used to grow the current buffer. + */ +#define growBufferReentrant() { \ + buffer_size *= 2; \ + buffer = (xmlChar *) \ + xmlRealloc(buffer, buffer_size * sizeof(xmlChar)); \ + if (buffer == NULL) { \ + xmlC14NErrMemory("growing buffer"); \ + return(NULL); \ + } \ +} + +/** + * xmlC11NNormalizeString: + * @input: the input string + * @mode: the normalization mode (attribute, comment, PI or text) + * + * Converts a string to a canonical (normalized) format. The code is stolen + * from xmlEncodeEntitiesReentrant(). Added normalization of \x09, \x0a, \x0A + * and the @mode parameter + * + * Returns a normalized string (caller is responsible for calling xmlFree()) + * or NULL if an error occurs + */ +static xmlChar * +xmlC11NNormalizeString(const xmlChar * input, + xmlC14NNormalizationMode mode) +{ + const xmlChar *cur = input; + xmlChar *buffer = NULL; + xmlChar *out = NULL; + int buffer_size = 0; + + if (input == NULL) + return (NULL); + + /* + * allocate an translation buffer. + */ + buffer_size = 1000; + buffer = (xmlChar *) xmlMallocAtomic(buffer_size * sizeof(xmlChar)); + if (buffer == NULL) { + xmlC14NErrMemory("allocating buffer"); + return (NULL); + } + out = buffer; + + while (*cur != '\0') { + if ((out - buffer) > (buffer_size - 10)) { + int indx = out - buffer; + + growBufferReentrant(); + out = &buffer[indx]; + } + + if ((*cur == '<') && ((mode == XMLC14N_NORMALIZE_ATTR) || + (mode == XMLC14N_NORMALIZE_TEXT))) { + *out++ = '&'; + *out++ = 'l'; + *out++ = 't'; + *out++ = ';'; + } else if ((*cur == '>') && (mode == XMLC14N_NORMALIZE_TEXT)) { + *out++ = '&'; + *out++ = 'g'; + *out++ = 't'; + *out++ = ';'; + } else if ((*cur == '&') && ((mode == XMLC14N_NORMALIZE_ATTR) || + (mode == XMLC14N_NORMALIZE_TEXT))) { + *out++ = '&'; + *out++ = 'a'; + *out++ = 'm'; + *out++ = 'p'; + *out++ = ';'; + } else if ((*cur == '"') && (mode == XMLC14N_NORMALIZE_ATTR)) { + *out++ = '&'; + *out++ = 'q'; + *out++ = 'u'; + *out++ = 'o'; + *out++ = 't'; + *out++ = ';'; + } else if ((*cur == '\x09') && (mode == XMLC14N_NORMALIZE_ATTR)) { + *out++ = '&'; + *out++ = '#'; + *out++ = 'x'; + *out++ = '9'; + *out++ = ';'; + } else if ((*cur == '\x0A') && (mode == XMLC14N_NORMALIZE_ATTR)) { + *out++ = '&'; + *out++ = '#'; + *out++ = 'x'; + *out++ = 'A'; + *out++ = ';'; + } else if ((*cur == '\x0D') && ((mode == XMLC14N_NORMALIZE_ATTR) || + (mode == XMLC14N_NORMALIZE_TEXT) || + (mode == XMLC14N_NORMALIZE_COMMENT) || + (mode == XMLC14N_NORMALIZE_PI))) { + *out++ = '&'; + *out++ = '#'; + *out++ = 'x'; + *out++ = 'D'; + *out++ = ';'; + } else { + /* + * Works because on UTF-8, all extended sequences cannot + * result in bytes in the ASCII range. + */ + *out++ = *cur; + } + cur++; + } + *out = 0; + return (buffer); +} +#endif /* LIBXML_OUTPUT_ENABLED */ +#define bottom_c14n +#include "elfgcchack.h" +#endif /* LIBXML_C14N_ENABLED */ diff --git a/android/native/libxml2/catalog.c b/android/native/libxml2/catalog.c new file mode 100644 index 0000000000..f33a0aa990 --- /dev/null +++ b/android/native/libxml2/catalog.c @@ -0,0 +1,3821 @@ +/** + * catalog.c: set of generic Catalog related routines + * + * Reference: SGML Open Technical Resolution TR9401:1997. + * http://www.jclark.com/sp/catalog.htm + * + * XML Catalogs Working Draft 06 August 2001 + * http://www.oasis-open.org/committees/entity/spec-2001-08-06.html + * + * See Copyright for the status of this software. + * + * Daniel.Veillard@imag.fr + */ + +#define IN_LIBXML +#include "libxml.h" + +#ifdef LIBXML_CATALOG_ENABLED +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_DELEGATE 50 +#define MAX_CATAL_DEPTH 50 + +#ifdef _WIN32 +# define PATH_SEAPARATOR ';' +#else +# define PATH_SEAPARATOR ':' +#endif + +/** + * TODO: + * + * macro to flag unimplemented blocks + * XML_CATALOG_PREFER user env to select between system/public prefered + * option. C.f. Richard Tobin + *> 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 +#define XML_XML_DEFAULT_CATALOG "file:///etc/xml/catalog" +#endif +#ifndef XML_SGML_DEFAULT_CATALOG +#define XML_SGML_DEFAULT_CATALOG "file:///etc/sgml/catalog" +#endif + +#if defined(_WIN32) && defined(_MSC_VER) +#undef XML_XML_DEFAULT_CATALOG +static char XML_XML_DEFAULT_CATALOG[256] = "file:///etc/xml/catalog"; +#if defined(_WIN32_WCE) +/* Windows CE don't have a A variant */ +#define GetModuleHandleA GetModuleHandle +#define GetModuleFileNameA GetModuleFileName +#else +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); + +/************************************************************************ + * * + * Types, all private * + * * + ************************************************************************/ + +typedef enum { + XML_CATA_REMOVED = -1, + XML_CATA_NONE = 0, + XML_CATA_CATALOG, + XML_CATA_BROKEN_CATALOG, + XML_CATA_NEXT_CATALOG, + XML_CATA_GROUP, + XML_CATA_PUBLIC, + XML_CATA_SYSTEM, + XML_CATA_REWRITE_SYSTEM, + XML_CATA_DELEGATE_PUBLIC, + XML_CATA_DELEGATE_SYSTEM, + XML_CATA_URI, + XML_CATA_REWRITE_URI, + XML_CATA_DELEGATE_URI, + SGML_CATA_SYSTEM, + SGML_CATA_PUBLIC, + SGML_CATA_ENTITY, + SGML_CATA_PENTITY, + SGML_CATA_DOCTYPE, + SGML_CATA_LINKTYPE, + SGML_CATA_NOTATION, + SGML_CATA_DELEGATE, + SGML_CATA_BASE, + SGML_CATA_CATALOG, + SGML_CATA_DOCUMENT, + SGML_CATA_SGMLDECL +} xmlCatalogEntryType; + +typedef struct _xmlCatalogEntry xmlCatalogEntry; +typedef xmlCatalogEntry *xmlCatalogEntryPtr; +struct _xmlCatalogEntry { + struct _xmlCatalogEntry *next; + struct _xmlCatalogEntry *parent; + struct _xmlCatalogEntry *children; + xmlCatalogEntryType type; + xmlChar *name; + xmlChar *value; + xmlChar *URL; /* The expanded URL using the base */ + xmlCatalogPrefer prefer; + int dealloc; + int depth; + struct _xmlCatalogEntry *group; +}; + +typedef enum { + XML_XML_CATALOG_TYPE = 1, + XML_SGML_CATALOG_TYPE +} xmlCatalogType; + +#define XML_MAX_SGML_CATA_DEPTH 10 +struct _xmlCatalog { + xmlCatalogType type; /* either XML or SGML */ + + /* + * SGML Catalogs are stored as a simple hash table of catalog entries + * Catalog stack to check against overflows when building the + * SGML catalog + */ + char *catalTab[XML_MAX_SGML_CATA_DEPTH]; /* stack of catals */ + int catalNr; /* Number of current catal streams */ + int catalMax; /* Max number of catal streams */ + xmlHashTablePtr sgml; + + /* + * XML Catalogs are stored as a tree of Catalog entries + */ + xmlCatalogPrefer prefer; + xmlCatalogEntryPtr xml; +}; + +/************************************************************************ + * * + * Global variables * + * * + ************************************************************************/ + +/* + * Those are preferences + */ +static int xmlDebugCatalogs = 0; /* used for debugging */ +static xmlCatalogAllow xmlCatalogDefaultAllow = XML_CATA_ALLOW_ALL; +static xmlCatalogPrefer xmlCatalogDefaultPrefer = XML_CATA_PREFER_PUBLIC; + +/* + * Hash table containing all the trees of XML catalogs parsed by + * the application. + */ +static xmlHashTablePtr xmlCatalogXMLFiles = NULL; + +/* + * The default catalog in use by the application + */ +static xmlCatalogPtr xmlDefaultCatalog = NULL; + +/* + * A mutex for modifying the shared global catalog(s) + * xmlDefaultCatalog tree. + * It also protects xmlCatalogXMLFiles + * The core of this readers/writer scheme is in xmlFetchXMLCatalogFile() + */ +static xmlRMutexPtr xmlCatalogMutex = NULL; + +/* + * Whether the catalog support was initialized. + */ +static int xmlCatalogInitialized = 0; + +/************************************************************************ + * * + * Catalog error handlers * + * * + ************************************************************************/ + +/** + * xmlCatalogErrMemory: + * @extra: extra informations + * + * Handle an out of memory condition + */ +static void +xmlCatalogErrMemory(const char *extra) +{ + __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); +} + +/** + * xmlCatalogErr: + * @catal: the Catalog entry + * @node: the context node + * @msg: the error message + * @extra: extra informations + * + * Handle a catalog error + */ +static void +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); +} + + +/************************************************************************ + * * + * Allocation and Freeing * + * * + ************************************************************************/ + +/** + * xmlNewCatalogEntry: + * @type: type of entry + * @name: name of the entry + * @value: value of the entry + * @prefer: the PUBLIC vs. SYSTEM current preference value + * @group: for members of a group, the group entry + * + * create a new Catalog entry, this type is shared both by XML and + * SGML catalogs, but the acceptable types values differs. + * + * Returns the xmlCatalogEntryPtr or NULL in case of error + */ +static xmlCatalogEntryPtr +xmlNewCatalogEntry(xmlCatalogEntryType type, const xmlChar *name, + const xmlChar *value, const xmlChar *URL, xmlCatalogPrefer prefer, + xmlCatalogEntryPtr group) { + xmlCatalogEntryPtr ret; + xmlChar *normid = NULL; + + ret = (xmlCatalogEntryPtr) xmlMalloc(sizeof(xmlCatalogEntry)); + if (ret == NULL) { + xmlCatalogErrMemory("allocating catalog entry"); + return(NULL); + } + ret->next = NULL; + ret->parent = NULL; + ret->children = NULL; + ret->type = type; + if (type == XML_CATA_PUBLIC || type == XML_CATA_DELEGATE_PUBLIC) { + normid = xmlCatalogNormalizePublic(name); + if (normid != NULL) + name = (*normid != 0 ? normid : NULL); + } + if (name != NULL) + ret->name = xmlStrdup(name); + else + ret->name = NULL; + if (normid != NULL) + xmlFree(normid); + if (value != NULL) + ret->value = xmlStrdup(value); + else + ret->value = NULL; + if (URL == NULL) + URL = value; + if (URL != NULL) + ret->URL = xmlStrdup(URL); + else + ret->URL = NULL; + ret->prefer = prefer; + ret->dealloc = 0; + ret->depth = 0; + ret->group = group; + return(ret); +} + +static void +xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret); + +/** + * xmlFreeCatalogEntry: + * @ret: a Catalog entry + * + * Free the memory allocated to a Catalog entry + */ +static void +xmlFreeCatalogEntry(xmlCatalogEntryPtr ret) { + if (ret == NULL) + return; + /* + * Entries stored in the file hash must be deallocated + * only by the file hash cleaner ! + */ + if (ret->dealloc == 1) + return; + + if (xmlDebugCatalogs) { + if (ret->name != NULL) + xmlGenericError(xmlGenericErrorContext, + "Free catalog entry %s\n", ret->name); + else if (ret->value != NULL) + xmlGenericError(xmlGenericErrorContext, + "Free catalog entry %s\n", ret->value); + else + xmlGenericError(xmlGenericErrorContext, + "Free catalog entry\n"); + } + + if (ret->name != NULL) + xmlFree(ret->name); + if (ret->value != NULL) + xmlFree(ret->value); + if (ret->URL != NULL) + xmlFree(ret->URL); + xmlFree(ret); +} + +/** + * xmlFreeCatalogEntryList: + * @ret: a Catalog entry list + * + * Free the memory allocated to a full chained list of Catalog entries + */ +static void +xmlFreeCatalogEntryList(xmlCatalogEntryPtr ret) { + xmlCatalogEntryPtr next; + + while (ret != NULL) { + next = ret->next; + xmlFreeCatalogEntry(ret); + ret = next; + } +} + +/** + * xmlFreeCatalogHashEntryList: + * @ret: a Catalog entry list + * + * Free the memory allocated to list of Catalog entries from the + * catalog file hash. + */ +static void +xmlFreeCatalogHashEntryList(xmlCatalogEntryPtr catal) { + xmlCatalogEntryPtr children, next; + + if (catal == NULL) + return; + + children = catal->children; + while (children != NULL) { + next = children->next; + children->dealloc = 0; + children->children = NULL; + xmlFreeCatalogEntry(children); + children = next; + } + catal->dealloc = 0; + xmlFreeCatalogEntry(catal); +} + +/** + * xmlCreateNewCatalog: + * @type: type of catalog + * @prefer: the PUBLIC vs. SYSTEM current preference value + * + * create a new Catalog, this type is shared both by XML and + * SGML catalogs, but the acceptable types values differs. + * + * Returns the xmlCatalogPtr or NULL in case of error + */ +static xmlCatalogPtr +xmlCreateNewCatalog(xmlCatalogType type, xmlCatalogPrefer prefer) { + xmlCatalogPtr ret; + + ret = (xmlCatalogPtr) xmlMalloc(sizeof(xmlCatalog)); + if (ret == NULL) { + xmlCatalogErrMemory("allocating catalog"); + return(NULL); + } + memset(ret, 0, sizeof(xmlCatalog)); + ret->type = type; + ret->catalNr = 0; + ret->catalMax = XML_MAX_SGML_CATA_DEPTH; + ret->prefer = prefer; + if (ret->type == XML_SGML_CATALOG_TYPE) + ret->sgml = xmlHashCreate(10); + return(ret); +} + +/** + * xmlFreeCatalog: + * @catal: a Catalog + * + * Free the memory allocated to a Catalog + */ +void +xmlFreeCatalog(xmlCatalogPtr catal) { + if (catal == NULL) + return; + if (catal->xml != NULL) + xmlFreeCatalogEntryList(catal->xml); + if (catal->sgml != NULL) + xmlHashFree(catal->sgml, + (xmlHashDeallocator) xmlFreeCatalogEntry); + xmlFree(catal); +} + +/************************************************************************ + * * + * Serializing Catalogs * + * * + ************************************************************************/ + +#ifdef LIBXML_OUTPUT_ENABLED +/** + * xmlCatalogDumpEntry: + * @entry: the catalog entry + * @out: the file. + * + * Serialize an SGML Catalog entry + */ +static void +xmlCatalogDumpEntry(xmlCatalogEntryPtr entry, FILE *out) { + if ((entry == NULL) || (out == NULL)) + return; + switch (entry->type) { + case SGML_CATA_ENTITY: + fprintf(out, "ENTITY "); break; + case SGML_CATA_PENTITY: + fprintf(out, "ENTITY %%"); break; + case SGML_CATA_DOCTYPE: + fprintf(out, "DOCTYPE "); break; + case SGML_CATA_LINKTYPE: + fprintf(out, "LINKTYPE "); break; + case SGML_CATA_NOTATION: + fprintf(out, "NOTATION "); break; + case SGML_CATA_PUBLIC: + fprintf(out, "PUBLIC "); break; + case SGML_CATA_SYSTEM: + fprintf(out, "SYSTEM "); break; + case SGML_CATA_DELEGATE: + fprintf(out, "DELEGATE "); break; + case SGML_CATA_BASE: + fprintf(out, "BASE "); break; + case SGML_CATA_CATALOG: + fprintf(out, "CATALOG "); break; + case SGML_CATA_DOCUMENT: + fprintf(out, "DOCUMENT "); break; + case SGML_CATA_SGMLDECL: + fprintf(out, "SGMLDECL "); break; + default: + return; + } + switch (entry->type) { + case SGML_CATA_ENTITY: + case SGML_CATA_PENTITY: + case SGML_CATA_DOCTYPE: + case SGML_CATA_LINKTYPE: + case SGML_CATA_NOTATION: + fprintf(out, "%s", (const char *) entry->name); break; + case SGML_CATA_PUBLIC: + case SGML_CATA_SYSTEM: + case SGML_CATA_SGMLDECL: + case SGML_CATA_DOCUMENT: + case SGML_CATA_CATALOG: + case SGML_CATA_BASE: + case SGML_CATA_DELEGATE: + fprintf(out, "\"%s\"", entry->name); break; + default: + break; + } + switch (entry->type) { + case SGML_CATA_ENTITY: + case SGML_CATA_PENTITY: + case SGML_CATA_DOCTYPE: + case SGML_CATA_LINKTYPE: + case SGML_CATA_NOTATION: + case SGML_CATA_PUBLIC: + case SGML_CATA_SYSTEM: + case SGML_CATA_DELEGATE: + fprintf(out, " \"%s\"", entry->value); break; + default: + break; + } + fprintf(out, "\n"); +} + +/** + * xmlDumpXMLCatalogNode: + * @catal: top catalog entry + * @catalog: pointer to the xml tree + * @doc: the containing document + * @ns: the current namespace + * @cgroup: group node for group members + * + * Serializes a Catalog entry, called by xmlDumpXMLCatalog and recursively + * for group entries + */ +static void xmlDumpXMLCatalogNode(xmlCatalogEntryPtr catal, xmlNodePtr catalog, + xmlDocPtr doc, xmlNsPtr ns, xmlCatalogEntryPtr cgroup) { + xmlNodePtr node; + xmlCatalogEntryPtr cur; + /* + * add all the catalog entries + */ + cur = catal; + while (cur != NULL) { + if (cur->group == cgroup) { + switch (cur->type) { + case XML_CATA_REMOVED: + break; + case XML_CATA_BROKEN_CATALOG: + case XML_CATA_CATALOG: + if (cur == catal) { + cur = cur->children; + continue; + } + break; + case XML_CATA_NEXT_CATALOG: + node = xmlNewDocNode(doc, ns, BAD_CAST "nextCatalog", NULL); + xmlSetProp(node, BAD_CAST "catalog", cur->value); + xmlAddChild(catalog, node); + break; + case XML_CATA_NONE: + break; + case XML_CATA_GROUP: + node = xmlNewDocNode(doc, ns, BAD_CAST "group", NULL); + xmlSetProp(node, BAD_CAST "id", cur->name); + if (cur->value != NULL) { + xmlNsPtr xns; + xns = xmlSearchNsByHref(doc, node, XML_XML_NAMESPACE); + if (xns != NULL) + xmlSetNsProp(node, xns, BAD_CAST "base", + cur->value); + } + switch (cur->prefer) { + case XML_CATA_PREFER_NONE: + break; + case XML_CATA_PREFER_PUBLIC: + xmlSetProp(node, BAD_CAST "prefer", BAD_CAST "public"); + break; + case XML_CATA_PREFER_SYSTEM: + xmlSetProp(node, BAD_CAST "prefer", BAD_CAST "system"); + break; + } + xmlDumpXMLCatalogNode(cur->next, node, doc, ns, cur); + xmlAddChild(catalog, node); + break; + case XML_CATA_PUBLIC: + node = xmlNewDocNode(doc, ns, BAD_CAST "public", NULL); + xmlSetProp(node, BAD_CAST "publicId", cur->name); + xmlSetProp(node, BAD_CAST "uri", cur->value); + xmlAddChild(catalog, node); + break; + case XML_CATA_SYSTEM: + node = xmlNewDocNode(doc, ns, BAD_CAST "system", NULL); + xmlSetProp(node, BAD_CAST "systemId", cur->name); + xmlSetProp(node, BAD_CAST "uri", cur->value); + xmlAddChild(catalog, node); + break; + case XML_CATA_REWRITE_SYSTEM: + node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteSystem", NULL); + xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name); + xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value); + xmlAddChild(catalog, node); + break; + case XML_CATA_DELEGATE_PUBLIC: + node = xmlNewDocNode(doc, ns, BAD_CAST "delegatePublic", NULL); + xmlSetProp(node, BAD_CAST "publicIdStartString", cur->name); + xmlSetProp(node, BAD_CAST "catalog", cur->value); + xmlAddChild(catalog, node); + break; + case XML_CATA_DELEGATE_SYSTEM: + node = xmlNewDocNode(doc, ns, BAD_CAST "delegateSystem", NULL); + xmlSetProp(node, BAD_CAST "systemIdStartString", cur->name); + xmlSetProp(node, BAD_CAST "catalog", cur->value); + xmlAddChild(catalog, node); + break; + case XML_CATA_URI: + node = xmlNewDocNode(doc, ns, BAD_CAST "uri", NULL); + xmlSetProp(node, BAD_CAST "name", cur->name); + xmlSetProp(node, BAD_CAST "uri", cur->value); + xmlAddChild(catalog, node); + break; + case XML_CATA_REWRITE_URI: + node = xmlNewDocNode(doc, ns, BAD_CAST "rewriteURI", NULL); + xmlSetProp(node, BAD_CAST "uriStartString", cur->name); + xmlSetProp(node, BAD_CAST "rewritePrefix", cur->value); + xmlAddChild(catalog, node); + break; + case XML_CATA_DELEGATE_URI: + node = xmlNewDocNode(doc, ns, BAD_CAST "delegateURI", NULL); + xmlSetProp(node, BAD_CAST "uriStartString", cur->name); + xmlSetProp(node, BAD_CAST "catalog", cur->value); + xmlAddChild(catalog, node); + break; + case SGML_CATA_SYSTEM: + case SGML_CATA_PUBLIC: + case SGML_CATA_ENTITY: + case SGML_CATA_PENTITY: + case SGML_CATA_DOCTYPE: + case SGML_CATA_LINKTYPE: + case SGML_CATA_NOTATION: + case SGML_CATA_DELEGATE: + case SGML_CATA_BASE: + case SGML_CATA_CATALOG: + case SGML_CATA_DOCUMENT: + case SGML_CATA_SGMLDECL: + break; + } + } + cur = cur->next; + } +} + +static int +xmlDumpXMLCatalog(FILE *out, xmlCatalogEntryPtr catal) { + int ret; + xmlDocPtr doc; + xmlNsPtr ns; + xmlDtdPtr dtd; + xmlNodePtr catalog; + xmlOutputBufferPtr buf; + + /* + * Rebuild a catalog + */ + doc = xmlNewDoc(NULL); + if (doc == NULL) + return(-1); + dtd = xmlNewDtd(doc, BAD_CAST "catalog", + BAD_CAST "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN", +BAD_CAST "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd"); + + xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) dtd); + + ns = xmlNewNs(NULL, XML_CATALOGS_NAMESPACE, NULL); + if (ns == NULL) { + xmlFreeDoc(doc); + return(-1); + } + catalog = xmlNewDocNode(doc, ns, BAD_CAST "catalog", NULL); + if (catalog == NULL) { + xmlFreeNs(ns); + xmlFreeDoc(doc); + return(-1); + } + catalog->nsDef = ns; + xmlAddChild((xmlNodePtr) doc, catalog); + + xmlDumpXMLCatalogNode(catal, catalog, doc, ns, NULL); + + /* + * reserialize it + */ + buf = xmlOutputBufferCreateFile(out, NULL); + if (buf == NULL) { + xmlFreeDoc(doc); + return(-1); + } + ret = xmlSaveFormatFileTo(buf, doc, NULL, 1); + + /* + * Free it + */ + xmlFreeDoc(doc); + + return(ret); +} +#endif /* LIBXML_OUTPUT_ENABLED */ + +/************************************************************************ + * * + * Converting SGML Catalogs to XML * + * * + ************************************************************************/ + +/** + * xmlCatalogConvertEntry: + * @entry: the entry + * @catal: pointer to the catalog being converted + * + * Convert one entry from the catalog + */ +static void +xmlCatalogConvertEntry(xmlCatalogEntryPtr entry, xmlCatalogPtr catal) { + if ((entry == NULL) || (catal == NULL) || (catal->sgml == NULL) || + (catal->xml == NULL)) + return; + switch (entry->type) { + case SGML_CATA_ENTITY: + entry->type = XML_CATA_PUBLIC; + break; + case SGML_CATA_PENTITY: + entry->type = XML_CATA_PUBLIC; + break; + case SGML_CATA_DOCTYPE: + entry->type = XML_CATA_PUBLIC; + break; + case SGML_CATA_LINKTYPE: + entry->type = XML_CATA_PUBLIC; + break; + case SGML_CATA_NOTATION: + entry->type = XML_CATA_PUBLIC; + break; + case SGML_CATA_PUBLIC: + entry->type = XML_CATA_PUBLIC; + break; + case SGML_CATA_SYSTEM: + entry->type = XML_CATA_SYSTEM; + break; + case SGML_CATA_DELEGATE: + entry->type = XML_CATA_DELEGATE_PUBLIC; + break; + case SGML_CATA_CATALOG: + entry->type = XML_CATA_CATALOG; + break; + default: + xmlHashRemoveEntry(catal->sgml, entry->name, + (xmlHashDeallocator) xmlFreeCatalogEntry); + return; + } + /* + * Conversion successful, remove from the SGML catalog + * and add it to the default XML one + */ + xmlHashRemoveEntry(catal->sgml, entry->name, NULL); + entry->parent = catal->xml; + entry->next = NULL; + if (catal->xml->children == NULL) + catal->xml->children = entry; + else { + xmlCatalogEntryPtr prev; + + prev = catal->xml->children; + while (prev->next != NULL) + prev = prev->next; + prev->next = entry; + } +} + +/** + * xmlConvertSGMLCatalog: + * @catal: the catalog + * + * Convert all the SGML catalog entries as XML ones + * + * Returns the number of entries converted if successful, -1 otherwise + */ +int +xmlConvertSGMLCatalog(xmlCatalogPtr catal) { + + if ((catal == NULL) || (catal->type != XML_SGML_CATALOG_TYPE)) + return(-1); + + if (xmlDebugCatalogs) { + xmlGenericError(xmlGenericErrorContext, + "Converting SGML catalog to XML\n"); + } + xmlHashScan(catal->sgml, + (xmlHashScanner) xmlCatalogConvertEntry, + &catal); + return(0); +} + +/************************************************************************ + * * + * Helper function * + * * + ************************************************************************/ + +/** + * xmlCatalogUnWrapURN: + * @urn: an "urn:publicid:" to unwrap + * + * Expand the URN into the equivalent Public Identifier + * + * Returns the new identifier or NULL, the string must be deallocated + * by the caller. + */ +static xmlChar * +xmlCatalogUnWrapURN(const xmlChar *urn) { + xmlChar result[2000]; + unsigned int i = 0; + + if (xmlStrncmp(urn, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) + return(NULL); + urn += sizeof(XML_URN_PUBID) - 1; + + while (*urn != 0) { + if (i > sizeof(result) - 4) + break; + if (*urn == '+') { + result[i++] = ' '; + urn++; + } else if (*urn == ':') { + result[i++] = '/'; + result[i++] = '/'; + urn++; + } else if (*urn == ';') { + result[i++] = ':'; + result[i++] = ':'; + urn++; + } else if (*urn == '%') { + if ((urn[1] == '2') && (urn[2] == 'B')) + result[i++] = '+'; + else if ((urn[1] == '3') && (urn[2] == 'A')) + result[i++] = ':'; + else if ((urn[1] == '2') && (urn[2] == 'F')) + result[i++] = '/'; + else if ((urn[1] == '3') && (urn[2] == 'B')) + result[i++] = ';'; + else if ((urn[1] == '2') && (urn[2] == '7')) + result[i++] = '\''; + else if ((urn[1] == '3') && (urn[2] == 'F')) + result[i++] = '?'; + else if ((urn[1] == '2') && (urn[2] == '3')) + result[i++] = '#'; + else if ((urn[1] == '2') && (urn[2] == '5')) + result[i++] = '%'; + else { + result[i++] = *urn; + urn++; + continue; + } + urn += 3; + } else { + result[i++] = *urn; + urn++; + } + } + result[i] = 0; + + return(xmlStrdup(result)); +} + +/** + * xmlParseCatalogFile: + * @filename: the filename + * + * parse an XML file and build a tree. It's like xmlParseFile() + * except it bypass all catalog lookups. + * + * Returns the resulting document tree or NULL in case of error + */ + +xmlDocPtr +xmlParseCatalogFile(const char *filename) { + xmlDocPtr ret; + xmlParserCtxtPtr ctxt; + char *directory = NULL; + xmlParserInputPtr inputStream; + xmlParserInputBufferPtr buf; + + ctxt = xmlNewParserCtxt(); + if (ctxt == NULL) { +#ifdef LIBXML_SAX1_ENABLED + if (xmlDefaultSAXHandler.error != NULL) { + xmlDefaultSAXHandler.error(NULL, "out of memory\n"); + } +#endif + return(NULL); + } + + buf = xmlParserInputBufferCreateFilename(filename, XML_CHAR_ENCODING_NONE); + if (buf == NULL) { + xmlFreeParserCtxt(ctxt); + return(NULL); + } + + inputStream = xmlNewInputStream(ctxt); + if (inputStream == NULL) { + xmlFreeParserCtxt(ctxt); + return(NULL); + } + + inputStream->filename = (char *) xmlCanonicPath((const xmlChar *)filename); + inputStream->buf = buf; + inputStream->base = inputStream->buf->buffer->content; + inputStream->cur = inputStream->buf->buffer->content; + inputStream->end = + &inputStream->buf->buffer->content[inputStream->buf->buffer->use]; + + inputPush(ctxt, inputStream); + if ((ctxt->directory == NULL) && (directory == NULL)) + directory = xmlParserGetDirectory(filename); + if ((ctxt->directory == NULL) && (directory != NULL)) + ctxt->directory = directory; + ctxt->valid = 0; + ctxt->validate = 0; + ctxt->loadsubset = 0; + ctxt->pedantic = 0; + ctxt->dictNames = 1; + + xmlParseDocument(ctxt); + + if (ctxt->wellFormed) + ret = ctxt->myDoc; + else { + ret = NULL; + xmlFreeDoc(ctxt->myDoc); + ctxt->myDoc = NULL; + } + xmlFreeParserCtxt(ctxt); + + return(ret); +} + +/** + * xmlLoadFileContent: + * @filename: a file path + * + * Load a file content into memory. + * + * Returns a pointer to the 0 terminated string or NULL in case of error + */ +static xmlChar * +xmlLoadFileContent(const char *filename) +{ +#ifdef HAVE_STAT + int fd; +#else + FILE *fd; +#endif + int len; + long size; + +#ifdef HAVE_STAT + struct stat info; +#endif + xmlChar *content; + + if (filename == NULL) + return (NULL); + +#ifdef HAVE_STAT + if (stat(filename, &info) < 0) + return (NULL); +#endif + +#ifdef HAVE_STAT + if ((fd = open(filename, O_RDONLY)) < 0) +#else + if ((fd = fopen(filename, "rb")) == NULL) +#endif + { + return (NULL); + } +#ifdef HAVE_STAT + size = info.st_size; +#else + if (fseek(fd, 0, SEEK_END) || (size = ftell(fd)) == EOF || fseek(fd, 0, SEEK_SET)) { /* File operations denied? ok, just close and return failure */ + fclose(fd); + return (NULL); + } +#endif + content = xmlMallocAtomic(size + 10); + if (content == NULL) { + xmlCatalogErrMemory("allocating catalog data"); + return (NULL); + } +#ifdef HAVE_STAT + len = read(fd, content, size); + close(fd); +#else + len = fread(content, 1, size, fd); + fclose(fd); +#endif + if (len < 0) { + xmlFree(content); + return (NULL); + } + content[len] = 0; + + return(content); +} + +/** + * xmlCatalogNormalizePublic: + * @pubID: the public ID string + * + * Normalizes the Public Identifier + * + * Implements 6.2. Public Identifier Normalization + * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html + * + * Returns the new string or NULL, the string must be deallocated + * by the caller. + */ +static xmlChar * +xmlCatalogNormalizePublic(const xmlChar *pubID) +{ + int ok = 1; + int white; + const xmlChar *p; + xmlChar *ret; + xmlChar *q; + + if (pubID == NULL) + return(NULL); + + white = 1; + for (p = pubID;*p != 0 && ok;p++) { + if (!xmlIsBlank_ch(*p)) + white = 0; + else if (*p == 0x20 && !white) + white = 1; + else + ok = 0; + } + if (ok && !white) /* is normalized */ + return(NULL); + + ret = xmlStrdup(pubID); + q = ret; + white = 0; + for (p = pubID;*p != 0;p++) { + if (xmlIsBlank_ch(*p)) { + if (q != ret) + white = 1; + } else { + if (white) { + *(q++) = 0x20; + white = 0; + } + *(q++) = *p; + } + } + *q = 0; + return(ret); +} + +/************************************************************************ + * * + * The XML Catalog parser * + * * + ************************************************************************/ + +static xmlCatalogEntryPtr +xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename); +static void +xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer, + xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup); +static xmlChar * +xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID, + const xmlChar *sysID); +static xmlChar * +xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI); + + +/** + * xmlGetXMLCatalogEntryType: + * @name: the name + * + * lookup the internal type associated to an XML catalog entry name + * + * Returns the type associated with that name + */ +static xmlCatalogEntryType +xmlGetXMLCatalogEntryType(const xmlChar *name) { + xmlCatalogEntryType type = XML_CATA_NONE; + if (xmlStrEqual(name, (const xmlChar *) "system")) + type = XML_CATA_SYSTEM; + else if (xmlStrEqual(name, (const xmlChar *) "public")) + type = XML_CATA_PUBLIC; + else if (xmlStrEqual(name, (const xmlChar *) "rewriteSystem")) + type = XML_CATA_REWRITE_SYSTEM; + else if (xmlStrEqual(name, (const xmlChar *) "delegatePublic")) + type = XML_CATA_DELEGATE_PUBLIC; + else if (xmlStrEqual(name, (const xmlChar *) "delegateSystem")) + type = XML_CATA_DELEGATE_SYSTEM; + else if (xmlStrEqual(name, (const xmlChar *) "uri")) + type = XML_CATA_URI; + else if (xmlStrEqual(name, (const xmlChar *) "rewriteURI")) + type = XML_CATA_REWRITE_URI; + else if (xmlStrEqual(name, (const xmlChar *) "delegateURI")) + type = XML_CATA_DELEGATE_URI; + else if (xmlStrEqual(name, (const xmlChar *) "nextCatalog")) + type = XML_CATA_NEXT_CATALOG; + else if (xmlStrEqual(name, (const xmlChar *) "catalog")) + type = XML_CATA_CATALOG; + return(type); +} + +/** + * xmlParseXMLCatalogOneNode: + * @cur: the XML node + * @type: the type of Catalog entry + * @name: the name of the node + * @attrName: the attribute holding the value + * @uriAttrName: the attribute holding the URI-Reference + * @prefer: the PUBLIC vs. SYSTEM current preference value + * @cgroup: the group which includes this node + * + * Finishes the examination of an XML tree node of a catalog and build + * a Catalog entry from it. + * + * Returns the new Catalog entry node or NULL in case of error. + */ +static xmlCatalogEntryPtr +xmlParseXMLCatalogOneNode(xmlNodePtr cur, xmlCatalogEntryType type, + const xmlChar *name, const xmlChar *attrName, + const xmlChar *uriAttrName, xmlCatalogPrefer prefer, + xmlCatalogEntryPtr cgroup) { + int ok = 1; + xmlChar *uriValue; + xmlChar *nameValue = NULL; + xmlChar *base = NULL; + xmlChar *URL = NULL; + xmlCatalogEntryPtr ret = NULL; + + if (attrName != NULL) { + nameValue = xmlGetProp(cur, attrName); + if (nameValue == NULL) { + xmlCatalogErr(ret, cur, XML_CATALOG_MISSING_ATTR, + "%s entry lacks '%s'\n", name, attrName, NULL); + ok = 0; + } + } + uriValue = xmlGetProp(cur, uriAttrName); + if (uriValue == NULL) { + xmlCatalogErr(ret, cur, XML_CATALOG_MISSING_ATTR, + "%s entry lacks '%s'\n", name, uriAttrName, NULL); + ok = 0; + } + if (!ok) { + if (nameValue != NULL) + xmlFree(nameValue); + if (uriValue != NULL) + xmlFree(uriValue); + return(NULL); + } + + base = xmlNodeGetBase(cur->doc, cur); + URL = xmlBuildURI(uriValue, base); + if (URL != NULL) { + if (xmlDebugCatalogs > 1) { + if (nameValue != NULL) + xmlGenericError(xmlGenericErrorContext, + "Found %s: '%s' '%s'\n", name, nameValue, URL); + else + xmlGenericError(xmlGenericErrorContext, + "Found %s: '%s'\n", name, URL); + } + ret = xmlNewCatalogEntry(type, nameValue, uriValue, URL, prefer, cgroup); + } else { + xmlCatalogErr(ret, cur, XML_CATALOG_ENTRY_BROKEN, + "%s entry '%s' broken ?: %s\n", name, uriAttrName, uriValue); + } + if (nameValue != NULL) + xmlFree(nameValue); + if (uriValue != NULL) + xmlFree(uriValue); + if (base != NULL) + xmlFree(base); + if (URL != NULL) + xmlFree(URL); + return(ret); +} + +/** + * xmlParseXMLCatalogNode: + * @cur: the XML node + * @prefer: the PUBLIC vs. SYSTEM current preference value + * @parent: the parent Catalog entry + * @cgroup: the group which includes this node + * + * Examines an XML tree node of a catalog and build + * a Catalog entry from it adding it to its parent. The examination can + * be recursive. + */ +static void +xmlParseXMLCatalogNode(xmlNodePtr cur, xmlCatalogPrefer prefer, + xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup) +{ + xmlChar *base = NULL; + xmlCatalogEntryPtr entry = NULL; + + if (cur == NULL) + return; + if (xmlStrEqual(cur->name, BAD_CAST "group")) { + xmlChar *prop; + xmlCatalogPrefer pref = XML_CATA_PREFER_NONE; + + prop = xmlGetProp(cur, BAD_CAST "prefer"); + if (prop != NULL) { + if (xmlStrEqual(prop, BAD_CAST "system")) { + prefer = XML_CATA_PREFER_SYSTEM; + } else if (xmlStrEqual(prop, BAD_CAST "public")) { + prefer = XML_CATA_PREFER_PUBLIC; + } else { + xmlCatalogErr(parent, cur, XML_CATALOG_PREFER_VALUE, + "Invalid value for prefer: '%s'\n", + prop, NULL, NULL); + } + xmlFree(prop); + pref = prefer; + } + prop = xmlGetProp(cur, BAD_CAST "id"); + base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE); + entry = xmlNewCatalogEntry(XML_CATA_GROUP, prop, base, NULL, pref, cgroup); + xmlFree(prop); + } else if (xmlStrEqual(cur->name, BAD_CAST "public")) { + entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_PUBLIC, + BAD_CAST "public", BAD_CAST "publicId", BAD_CAST "uri", prefer, cgroup); + } else if (xmlStrEqual(cur->name, BAD_CAST "system")) { + entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_SYSTEM, + BAD_CAST "system", BAD_CAST "systemId", BAD_CAST "uri", prefer, cgroup); + } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteSystem")) { + entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_SYSTEM, + BAD_CAST "rewriteSystem", BAD_CAST "systemIdStartString", + BAD_CAST "rewritePrefix", prefer, cgroup); + } else if (xmlStrEqual(cur->name, BAD_CAST "delegatePublic")) { + entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_PUBLIC, + BAD_CAST "delegatePublic", BAD_CAST "publicIdStartString", + BAD_CAST "catalog", prefer, cgroup); + } else if (xmlStrEqual(cur->name, BAD_CAST "delegateSystem")) { + entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_SYSTEM, + BAD_CAST "delegateSystem", BAD_CAST "systemIdStartString", + BAD_CAST "catalog", prefer, cgroup); + } else if (xmlStrEqual(cur->name, BAD_CAST "uri")) { + entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_URI, + BAD_CAST "uri", BAD_CAST "name", + BAD_CAST "uri", prefer, cgroup); + } else if (xmlStrEqual(cur->name, BAD_CAST "rewriteURI")) { + entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_REWRITE_URI, + BAD_CAST "rewriteURI", BAD_CAST "uriStartString", + BAD_CAST "rewritePrefix", prefer, cgroup); + } else if (xmlStrEqual(cur->name, BAD_CAST "delegateURI")) { + entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_DELEGATE_URI, + BAD_CAST "delegateURI", BAD_CAST "uriStartString", + BAD_CAST "catalog", prefer, cgroup); + } else if (xmlStrEqual(cur->name, BAD_CAST "nextCatalog")) { + entry = xmlParseXMLCatalogOneNode(cur, XML_CATA_NEXT_CATALOG, + BAD_CAST "nextCatalog", NULL, + BAD_CAST "catalog", prefer, cgroup); + } + if (entry != NULL) { + if (parent != NULL) { + entry->parent = parent; + if (parent->children == NULL) + parent->children = entry; + else { + xmlCatalogEntryPtr prev; + + prev = parent->children; + while (prev->next != NULL) + prev = prev->next; + prev->next = entry; + } + } + if (entry->type == XML_CATA_GROUP) { + /* + * Recurse to propagate prefer to the subtree + * (xml:base handling is automated) + */ + xmlParseXMLCatalogNodeList(cur->children, prefer, parent, entry); + } + } + if (base != NULL) + xmlFree(base); +} + +/** + * xmlParseXMLCatalogNodeList: + * @cur: the XML node list of siblings + * @prefer: the PUBLIC vs. SYSTEM current preference value + * @parent: the parent Catalog entry + * @cgroup: the group which includes this list + * + * Examines a list of XML sibling nodes of a catalog and build + * a list of Catalog entry from it adding it to the parent. + * The examination will recurse to examine node subtrees. + */ +static void +xmlParseXMLCatalogNodeList(xmlNodePtr cur, xmlCatalogPrefer prefer, + xmlCatalogEntryPtr parent, xmlCatalogEntryPtr cgroup) { + while (cur != NULL) { + if ((cur->ns != NULL) && (cur->ns->href != NULL) && + (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) { + xmlParseXMLCatalogNode(cur, prefer, parent, cgroup); + } + cur = cur->next; + } + /* TODO: sort the list according to REWRITE lengths and prefer value */ +} + +/** + * xmlParseXMLCatalogFile: + * @prefer: the PUBLIC vs. SYSTEM current preference value + * @filename: the filename for the catalog + * + * Parses the catalog file to extract the XML tree and then analyze the + * tree to build a list of Catalog entries corresponding to this catalog + * + * Returns the resulting Catalog entries list + */ +static xmlCatalogEntryPtr +xmlParseXMLCatalogFile(xmlCatalogPrefer prefer, const xmlChar *filename) { + xmlDocPtr doc; + xmlNodePtr cur; + xmlChar *prop; + xmlCatalogEntryPtr parent = NULL; + + if (filename == NULL) + return(NULL); + + doc = xmlParseCatalogFile((const char *) filename); + if (doc == NULL) { + if (xmlDebugCatalogs) + xmlGenericError(xmlGenericErrorContext, + "Failed to parse catalog %s\n", filename); + return(NULL); + } + + if (xmlDebugCatalogs) + xmlGenericError(xmlGenericErrorContext, + "%d Parsing catalog %s\n", xmlGetThreadId(), filename); + + cur = xmlDocGetRootElement(doc); + if ((cur != NULL) && (xmlStrEqual(cur->name, BAD_CAST "catalog")) && + (cur->ns != NULL) && (cur->ns->href != NULL) && + (xmlStrEqual(cur->ns->href, XML_CATALOGS_NAMESPACE))) { + + parent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, + (const xmlChar *)filename, NULL, prefer, NULL); + if (parent == NULL) { + xmlFreeDoc(doc); + return(NULL); + } + + prop = xmlGetProp(cur, BAD_CAST "prefer"); + if (prop != NULL) { + if (xmlStrEqual(prop, BAD_CAST "system")) { + prefer = XML_CATA_PREFER_SYSTEM; + } else if (xmlStrEqual(prop, BAD_CAST "public")) { + prefer = XML_CATA_PREFER_PUBLIC; + } else { + xmlCatalogErr(NULL, cur, XML_CATALOG_PREFER_VALUE, + "Invalid value for prefer: '%s'\n", + prop, NULL, NULL); + } + xmlFree(prop); + } + cur = cur->children; + xmlParseXMLCatalogNodeList(cur, prefer, parent, NULL); + } else { + xmlCatalogErr(NULL, (xmlNodePtr) doc, XML_CATALOG_NOT_CATALOG, + "File %s is not an XML Catalog\n", + filename, NULL, NULL); + xmlFreeDoc(doc); + return(NULL); + } + xmlFreeDoc(doc); + return(parent); +} + +/** + * xmlFetchXMLCatalogFile: + * @catal: an existing but incomplete catalog entry + * + * Fetch and parse the subcatalog referenced by an entry + * + * Returns 0 in case of success, -1 otherwise + */ +static int +xmlFetchXMLCatalogFile(xmlCatalogEntryPtr catal) { + xmlCatalogEntryPtr doc; + + if (catal == NULL) + return(-1); + if (catal->URL == NULL) + return(-1); + if (catal->children != NULL) + return(-1); + + /* + * lock the whole catalog for modification + */ + xmlRMutexLock(xmlCatalogMutex); + if (catal->children != NULL) { + /* Okay someone else did it in the meantime */ + xmlRMutexUnlock(xmlCatalogMutex); + return(0); + } + + if (xmlCatalogXMLFiles != NULL) { + doc = (xmlCatalogEntryPtr) + xmlHashLookup(xmlCatalogXMLFiles, catal->URL); + if (doc != NULL) { + if (xmlDebugCatalogs) + xmlGenericError(xmlGenericErrorContext, + "Found %s in file hash\n", catal->URL); + + if (catal->type == XML_CATA_CATALOG) + catal->children = doc->children; + else + catal->children = doc; + catal->dealloc = 0; + xmlRMutexUnlock(xmlCatalogMutex); + return(0); + } + if (xmlDebugCatalogs) + xmlGenericError(xmlGenericErrorContext, + "%s not found in file hash\n", catal->URL); + } + + /* + * Fetch and parse. Note that xmlParseXMLCatalogFile does not + * use the existing catalog, there is no recursion allowed at + * that level. + */ + doc = xmlParseXMLCatalogFile(catal->prefer, catal->URL); + if (doc == NULL) { + catal->type = XML_CATA_BROKEN_CATALOG; + xmlRMutexUnlock(xmlCatalogMutex); + return(-1); + } + + if (catal->type == XML_CATA_CATALOG) + catal->children = doc->children; + else + catal->children = doc; + + doc->dealloc = 1; + + if (xmlCatalogXMLFiles == NULL) + xmlCatalogXMLFiles = xmlHashCreate(10); + if (xmlCatalogXMLFiles != NULL) { + if (xmlDebugCatalogs) + xmlGenericError(xmlGenericErrorContext, + "%s added to file hash\n", catal->URL); + xmlHashAddEntry(xmlCatalogXMLFiles, catal->URL, doc); + } + xmlRMutexUnlock(xmlCatalogMutex); + return(0); +} + +/************************************************************************ + * * + * XML Catalog handling * + * * + ************************************************************************/ + +/** + * xmlAddXMLCatalog: + * @catal: top of an XML catalog + * @type: the type of record to add to the catalog + * @orig: the system, public or prefix to match (or NULL) + * @replace: the replacement value for the match + * + * Add an entry in the XML catalog, it may overwrite existing but + * different entries. + * + * Returns 0 if successful, -1 otherwise + */ +static int +xmlAddXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *type, + const xmlChar *orig, const xmlChar *replace) { + xmlCatalogEntryPtr cur; + xmlCatalogEntryType typ; + int doregister = 0; + + if ((catal == NULL) || + ((catal->type != XML_CATA_CATALOG) && + (catal->type != XML_CATA_BROKEN_CATALOG))) + return(-1); + if (catal->children == NULL) { + xmlFetchXMLCatalogFile(catal); + } + if (catal->children == NULL) + doregister = 1; + + typ = xmlGetXMLCatalogEntryType(type); + if (typ == XML_CATA_NONE) { + if (xmlDebugCatalogs) + xmlGenericError(xmlGenericErrorContext, + "Failed to add unknown element %s to catalog\n", type); + return(-1); + } + + cur = catal->children; + /* + * Might be a simple "update in place" + */ + if (cur != NULL) { + while (cur != NULL) { + if ((orig != NULL) && (cur->type == typ) && + (xmlStrEqual(orig, cur->name))) { + if (xmlDebugCatalogs) + xmlGenericError(xmlGenericErrorContext, + "Updating element %s to catalog\n", type); + if (cur->value != NULL) + xmlFree(cur->value); + if (cur->URL != NULL) + xmlFree(cur->URL); + cur->value = xmlStrdup(replace); + cur->URL = xmlStrdup(replace); + return(0); + } + if (cur->next == NULL) + break; + cur = cur->next; + } + } + if (xmlDebugCatalogs) + xmlGenericError(xmlGenericErrorContext, + "Adding element %s to catalog\n", type); + if (cur == NULL) + catal->children = xmlNewCatalogEntry(typ, orig, replace, + NULL, catal->prefer, NULL); + else + cur->next = xmlNewCatalogEntry(typ, orig, replace, + NULL, catal->prefer, NULL); + if (doregister) { + catal->type = XML_CATA_CATALOG; + cur = xmlHashLookup(xmlCatalogXMLFiles, catal->URL); + if (cur != NULL) + cur->children = catal->children; + } + + return(0); +} + +/** + * xmlDelXMLCatalog: + * @catal: top of an XML catalog + * @value: the value to remove from the catalog + * + * Remove entries in the XML catalog where the value or the URI + * is equal to @value + * + * Returns the number of entries removed if successful, -1 otherwise + */ +static int +xmlDelXMLCatalog(xmlCatalogEntryPtr catal, const xmlChar *value) { + xmlCatalogEntryPtr cur; + int ret = 0; + + if ((catal == NULL) || + ((catal->type != XML_CATA_CATALOG) && + (catal->type != XML_CATA_BROKEN_CATALOG))) + return(-1); + if (value == NULL) + return(-1); + if (catal->children == NULL) { + xmlFetchXMLCatalogFile(catal); + } + + /* + * Scan the children + */ + cur = catal->children; + while (cur != NULL) { + if (((cur->name != NULL) && (xmlStrEqual(value, cur->name))) || + (xmlStrEqual(value, cur->value))) { + if (xmlDebugCatalogs) { + if (cur->name != NULL) + xmlGenericError(xmlGenericErrorContext, + "Removing element %s from catalog\n", cur->name); + else + xmlGenericError(xmlGenericErrorContext, + "Removing element %s from catalog\n", cur->value); + } + cur->type = XML_CATA_REMOVED; + } + cur = cur->next; + } + return(ret); +} + +/** + * xmlCatalogXMLResolve: + * @catal: a catalog list + * @pubID: the public ID string + * @sysID: the system ID string + * + * Do a complete resolution lookup of an External Identifier for a + * list of catalog entries. + * + * Implements (or tries to) 7.1. External Identifier Resolution + * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html + * + * Returns the URI of the resource or NULL if not found + */ +static xmlChar * +xmlCatalogXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID, + const xmlChar *sysID) { + xmlChar *ret = NULL; + xmlCatalogEntryPtr cur; + int haveDelegate = 0; + int haveNext = 0; + + /* + * protection against loops + */ + if (catal->depth > MAX_CATAL_DEPTH) { + xmlCatalogErr(catal, NULL, XML_CATALOG_RECURSION, + "Detected recursion in catalog %s\n", + catal->name, NULL, NULL); + return(NULL); + } + catal->depth++; + + /* + * First tries steps 2/ 3/ 4/ if a system ID is provided. + */ + if (sysID != NULL) { + xmlCatalogEntryPtr rewrite = NULL; + int lenrewrite = 0, len; + cur = catal; + haveDelegate = 0; + while (cur != NULL) { + switch (cur->type) { + case XML_CATA_SYSTEM: + if (xmlStrEqual(sysID, cur->name)) { + if (xmlDebugCatalogs) + xmlGenericError(xmlGenericErrorContext, + "Found system match %s, using %s\n", + cur->name, cur->URL); + catal->depth--; + return(xmlStrdup(cur->URL)); + } + break; + case XML_CATA_REWRITE_SYSTEM: + len = xmlStrlen(cur->name); + if ((len > lenrewrite) && + (!xmlStrncmp(sysID, cur->name, len))) { + lenrewrite = len; + rewrite = cur; + } + break; + case XML_CATA_DELEGATE_SYSTEM: + if (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name))) + haveDelegate++; + break; + case XML_CATA_NEXT_CATALOG: + haveNext++; + break; + default: + break; + } + cur = cur->next; + } + if (rewrite != NULL) { + if (xmlDebugCatalogs) + xmlGenericError(xmlGenericErrorContext, + "Using rewriting rule %s\n", rewrite->name); + ret = xmlStrdup(rewrite->URL); + if (ret != NULL) + ret = xmlStrcat(ret, &sysID[lenrewrite]); + catal->depth--; + return(ret); + } + if (haveDelegate) { + const xmlChar *delegates[MAX_DELEGATE]; + int nbList = 0, i; + + /* + * Assume the entries have been sorted by decreasing substring + * matches when the list was produced. + */ + cur = catal; + while (cur != NULL) { + if ((cur->type == XML_CATA_DELEGATE_SYSTEM) && + (!xmlStrncmp(sysID, cur->name, xmlStrlen(cur->name)))) { + for (i = 0;i < nbList;i++) + if (xmlStrEqual(cur->URL, delegates[i])) + break; + if (i < nbList) { + cur = cur->next; + continue; + } + if (nbList < MAX_DELEGATE) + delegates[nbList++] = cur->URL; + + if (cur->children == NULL) { + xmlFetchXMLCatalogFile(cur); + } + if (cur->children != NULL) { + if (xmlDebugCatalogs) + xmlGenericError(xmlGenericErrorContext, + "Trying system delegate %s\n", cur->URL); + ret = xmlCatalogListXMLResolve( + cur->children, NULL, sysID); + if (ret != NULL) { + catal->depth--; + return(ret); + } + } + } + cur = cur->next; + } + /* + * Apply the cut algorithm explained in 4/ + */ + catal->depth--; + return(XML_CATAL_BREAK); + } + } + /* + * Then tries 5/ 6/ if a public ID is provided + */ + if (pubID != NULL) { + cur = catal; + haveDelegate = 0; + while (cur != NULL) { + switch (cur->type) { + case XML_CATA_PUBLIC: + if (xmlStrEqual(pubID, cur->name)) { + if (xmlDebugCatalogs) + xmlGenericError(xmlGenericErrorContext, + "Found public match %s\n", cur->name); + catal->depth--; + return(xmlStrdup(cur->URL)); + } + break; + case XML_CATA_DELEGATE_PUBLIC: + if (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)) && + (cur->prefer == XML_CATA_PREFER_PUBLIC)) + haveDelegate++; + break; + case XML_CATA_NEXT_CATALOG: + if (sysID == NULL) + haveNext++; + break; + default: + break; + } + cur = cur->next; + } + if (haveDelegate) { + const xmlChar *delegates[MAX_DELEGATE]; + int nbList = 0, i; + + /* + * Assume the entries have been sorted by decreasing substring + * matches when the list was produced. + */ + cur = catal; + while (cur != NULL) { + if ((cur->type == XML_CATA_DELEGATE_PUBLIC) && + (cur->prefer == XML_CATA_PREFER_PUBLIC) && + (!xmlStrncmp(pubID, cur->name, xmlStrlen(cur->name)))) { + + for (i = 0;i < nbList;i++) + if (xmlStrEqual(cur->URL, delegates[i])) + break; + if (i < nbList) { + cur = cur->next; + continue; + } + if (nbList < MAX_DELEGATE) + delegates[nbList++] = cur->URL; + + if (cur->children == NULL) { + xmlFetchXMLCatalogFile(cur); + } + if (cur->children != NULL) { + if (xmlDebugCatalogs) + xmlGenericError(xmlGenericErrorContext, + "Trying public delegate %s\n", cur->URL); + ret = xmlCatalogListXMLResolve( + cur->children, pubID, NULL); + if (ret != NULL) { + catal->depth--; + return(ret); + } + } + } + cur = cur->next; + } + /* + * Apply the cut algorithm explained in 4/ + */ + catal->depth--; + return(XML_CATAL_BREAK); + } + } + if (haveNext) { + cur = catal; + while (cur != NULL) { + if (cur->type == XML_CATA_NEXT_CATALOG) { + if (cur->children == NULL) { + xmlFetchXMLCatalogFile(cur); + } + if (cur->children != NULL) { + ret = xmlCatalogListXMLResolve(cur->children, pubID, sysID); + if (ret != NULL) { + catal->depth--; + return(ret); + } else if (catal->depth > MAX_CATAL_DEPTH) { + return(NULL); + } + } + } + cur = cur->next; + } + } + + catal->depth--; + return(NULL); +} + +/** + * xmlCatalogXMLResolveURI: + * @catal: a catalog list + * @URI: the URI + * @sysID: the system ID string + * + * Do a complete resolution lookup of an External Identifier for a + * list of catalog entries. + * + * Implements (or tries to) 7.2.2. URI Resolution + * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html + * + * Returns the URI of the resource or NULL if not found + */ +static xmlChar * +xmlCatalogXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) { + xmlChar *ret = NULL; + xmlCatalogEntryPtr cur; + int haveDelegate = 0; + int haveNext = 0; + xmlCatalogEntryPtr rewrite = NULL; + int lenrewrite = 0, len; + + if (catal == NULL) + return(NULL); + + if (URI == NULL) + return(NULL); + + if (catal->depth > MAX_CATAL_DEPTH) { + xmlCatalogErr(catal, NULL, XML_CATALOG_RECURSION, + "Detected recursion in catalog %s\n", + catal->name, NULL, NULL); + return(NULL); + } + + /* + * First tries steps 2/ 3/ 4/ if a system ID is provided. + */ + cur = catal; + haveDelegate = 0; + while (cur != NULL) { + switch (cur->type) { + case XML_CATA_URI: + if (xmlStrEqual(URI, cur->name)) { + if (xmlDebugCatalogs) + xmlGenericError(xmlGenericErrorContext, + "Found URI match %s\n", cur->name); + return(xmlStrdup(cur->URL)); + } + break; + case XML_CATA_REWRITE_URI: + len = xmlStrlen(cur->name); + if ((len > lenrewrite) && + (!xmlStrncmp(URI, cur->name, len))) { + lenrewrite = len; + rewrite = cur; + } + break; + case XML_CATA_DELEGATE_URI: + if (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name))) + haveDelegate++; + break; + case XML_CATA_NEXT_CATALOG: + haveNext++; + break; + default: + break; + } + cur = cur->next; + } + if (rewrite != NULL) { + if (xmlDebugCatalogs) + xmlGenericError(xmlGenericErrorContext, + "Using rewriting rule %s\n", rewrite->name); + ret = xmlStrdup(rewrite->URL); + if (ret != NULL) + ret = xmlStrcat(ret, &URI[lenrewrite]); + return(ret); + } + if (haveDelegate) { + const xmlChar *delegates[MAX_DELEGATE]; + int nbList = 0, i; + + /* + * Assume the entries have been sorted by decreasing substring + * matches when the list was produced. + */ + cur = catal; + while (cur != NULL) { + if (((cur->type == XML_CATA_DELEGATE_SYSTEM) || + (cur->type == XML_CATA_DELEGATE_URI)) && + (!xmlStrncmp(URI, cur->name, xmlStrlen(cur->name)))) { + for (i = 0;i < nbList;i++) + if (xmlStrEqual(cur->URL, delegates[i])) + break; + if (i < nbList) { + cur = cur->next; + continue; + } + if (nbList < MAX_DELEGATE) + delegates[nbList++] = cur->URL; + + if (cur->children == NULL) { + xmlFetchXMLCatalogFile(cur); + } + if (cur->children != NULL) { + if (xmlDebugCatalogs) + xmlGenericError(xmlGenericErrorContext, + "Trying URI delegate %s\n", cur->URL); + ret = xmlCatalogListXMLResolveURI( + cur->children, URI); + if (ret != NULL) + return(ret); + } + } + cur = cur->next; + } + /* + * Apply the cut algorithm explained in 4/ + */ + return(XML_CATAL_BREAK); + } + if (haveNext) { + cur = catal; + while (cur != NULL) { + if (cur->type == XML_CATA_NEXT_CATALOG) { + if (cur->children == NULL) { + xmlFetchXMLCatalogFile(cur); + } + if (cur->children != NULL) { + ret = xmlCatalogListXMLResolveURI(cur->children, URI); + if (ret != NULL) + return(ret); + } + } + cur = cur->next; + } + } + + return(NULL); +} + +/** + * xmlCatalogListXMLResolve: + * @catal: a catalog list + * @pubID: the public ID string + * @sysID: the system ID string + * + * Do a complete resolution lookup of an External Identifier for a + * list of catalogs + * + * Implements (or tries to) 7.1. External Identifier Resolution + * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html + * + * Returns the URI of the resource or NULL if not found + */ +static xmlChar * +xmlCatalogListXMLResolve(xmlCatalogEntryPtr catal, const xmlChar *pubID, + const xmlChar *sysID) { + xmlChar *ret = NULL; + xmlChar *urnID = NULL; + xmlChar *normid; + + if (catal == NULL) + return(NULL); + if ((pubID == NULL) && (sysID == NULL)) + return(NULL); + + normid = xmlCatalogNormalizePublic(pubID); + if (normid != NULL) + pubID = (*normid != 0 ? normid : NULL); + + if (!xmlStrncmp(pubID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) { + urnID = xmlCatalogUnWrapURN(pubID); + if (xmlDebugCatalogs) { + if (urnID == NULL) + xmlGenericError(xmlGenericErrorContext, + "Public URN ID %s expanded to NULL\n", pubID); + else + xmlGenericError(xmlGenericErrorContext, + "Public URN ID expanded to %s\n", urnID); + } + ret = xmlCatalogListXMLResolve(catal, urnID, sysID); + if (urnID != NULL) + xmlFree(urnID); + if (normid != NULL) + xmlFree(normid); + return(ret); + } + if (!xmlStrncmp(sysID, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) { + urnID = xmlCatalogUnWrapURN(sysID); + if (xmlDebugCatalogs) { + if (urnID == NULL) + xmlGenericError(xmlGenericErrorContext, + "System URN ID %s expanded to NULL\n", sysID); + else + xmlGenericError(xmlGenericErrorContext, + "System URN ID expanded to %s\n", urnID); + } + if (pubID == NULL) + ret = xmlCatalogListXMLResolve(catal, urnID, NULL); + else if (xmlStrEqual(pubID, urnID)) + ret = xmlCatalogListXMLResolve(catal, pubID, NULL); + else { + ret = xmlCatalogListXMLResolve(catal, pubID, urnID); + } + if (urnID != NULL) + xmlFree(urnID); + if (normid != NULL) + xmlFree(normid); + return(ret); + } + while (catal != NULL) { + if (catal->type == XML_CATA_CATALOG) { + if (catal->children == NULL) { + xmlFetchXMLCatalogFile(catal); + } + if (catal->children != NULL) { + ret = xmlCatalogXMLResolve(catal->children, pubID, sysID); + if (ret != NULL) { + break; + } else if ((catal->children != NULL) && + (catal->children->depth > MAX_CATAL_DEPTH)) { + ret = NULL; + break; + } + } + } + catal = catal->next; + } + if (normid != NULL) + xmlFree(normid); + return(ret); +} + +/** + * xmlCatalogListXMLResolveURI: + * @catal: a catalog list + * @URI: the URI + * + * Do a complete resolution lookup of an URI for a list of catalogs + * + * Implements (or tries to) 7.2. URI Resolution + * from http://www.oasis-open.org/committees/entity/spec-2001-08-06.html + * + * Returns the URI of the resource or NULL if not found + */ +static xmlChar * +xmlCatalogListXMLResolveURI(xmlCatalogEntryPtr catal, const xmlChar *URI) { + xmlChar *ret = NULL; + xmlChar *urnID = NULL; + + if (catal == NULL) + return(NULL); + if (URI == NULL) + return(NULL); + + if (!xmlStrncmp(URI, BAD_CAST XML_URN_PUBID, sizeof(XML_URN_PUBID) - 1)) { + urnID = xmlCatalogUnWrapURN(URI); + if (xmlDebugCatalogs) { + if (urnID == NULL) + xmlGenericError(xmlGenericErrorContext, + "URN ID %s expanded to NULL\n", URI); + else + xmlGenericError(xmlGenericErrorContext, + "URN ID expanded to %s\n", urnID); + } + ret = xmlCatalogListXMLResolve(catal, urnID, NULL); + if (urnID != NULL) + xmlFree(urnID); + return(ret); + } + while (catal != NULL) { + if (catal->type == XML_CATA_CATALOG) { + if (catal->children == NULL) { + xmlFetchXMLCatalogFile(catal); + } + if (catal->children != NULL) { + ret = xmlCatalogXMLResolveURI(catal->children, URI); + if (ret != NULL) + return(ret); + } + } + catal = catal->next; + } + return(ret); +} + +/************************************************************************ + * * + * The SGML Catalog parser * + * * + ************************************************************************/ + + +#define RAW *cur +#define NEXT cur++; +#define SKIP(x) cur += x; + +#define SKIP_BLANKS while (IS_BLANK_CH(*cur)) NEXT; + +/** + * xmlParseSGMLCatalogComment: + * @cur: the current character + * + * Skip a comment in an SGML catalog + * + * Returns new current character + */ +static const xmlChar * +xmlParseSGMLCatalogComment(const xmlChar *cur) { + if ((cur[0] != '-') || (cur[1] != '-')) + return(cur); + SKIP(2); + while ((cur[0] != 0) && ((cur[0] != '-') || ((cur[1] != '-')))) + NEXT; + if (cur[0] == 0) { + return(NULL); + } + return(cur + 2); +} + +/** + * xmlParseSGMLCatalogPubid: + * @cur: the current character + * @id: the return location + * + * Parse an SGML catalog ID + * + * Returns new current character and store the value in @id + */ +static const xmlChar * +xmlParseSGMLCatalogPubid(const xmlChar *cur, xmlChar **id) { + xmlChar *buf = NULL, *tmp; + int len = 0; + int size = 50; + xmlChar stop; + int count = 0; + + *id = NULL; + + if (RAW == '"') { + NEXT; + stop = '"'; + } else if (RAW == '\'') { + NEXT; + stop = '\''; + } else { + stop = ' '; + } + buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar)); + if (buf == NULL) { + xmlCatalogErrMemory("allocating public ID"); + return(NULL); + } + while (IS_PUBIDCHAR_CH(*cur) || (*cur == '?')) { + if ((*cur == stop) && (stop != ' ')) + break; + if ((stop == ' ') && (IS_BLANK_CH(*cur))) + break; + if (len + 1 >= size) { + size *= 2; + tmp = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar)); + if (tmp == NULL) { + xmlCatalogErrMemory("allocating public ID"); + xmlFree(buf); + return(NULL); + } + buf = tmp; + } + buf[len++] = *cur; + count++; + NEXT; + } + buf[len] = 0; + if (stop == ' ') { + if (!IS_BLANK_CH(*cur)) { + xmlFree(buf); + return(NULL); + } + } else { + if (*cur != stop) { + xmlFree(buf); + return(NULL); + } + NEXT; + } + *id = buf; + return(cur); +} + +/** + * xmlParseSGMLCatalogName: + * @cur: the current character + * @name: the return location + * + * Parse an SGML catalog name + * + * Returns new current character and store the value in @name + */ +static const xmlChar * +xmlParseSGMLCatalogName(const xmlChar *cur, xmlChar **name) { + xmlChar buf[XML_MAX_NAMELEN + 5]; + int len = 0; + int c; + + *name = NULL; + + /* + * Handler for more complex cases + */ + c = *cur; + if ((!IS_LETTER(c) && (c != '_') && (c != ':'))) { + return(NULL); + } + + while (((IS_LETTER(c)) || (IS_DIGIT(c)) || + (c == '.') || (c == '-') || + (c == '_') || (c == ':'))) { + buf[len++] = c; + cur++; + c = *cur; + if (len >= XML_MAX_NAMELEN) + return(NULL); + } + *name = xmlStrndup(buf, len); + return(cur); +} + +/** + * xmlGetSGMLCatalogEntryType: + * @name: the entry name + * + * Get the Catalog entry type for a given SGML Catalog name + * + * Returns Catalog entry type + */ +static xmlCatalogEntryType +xmlGetSGMLCatalogEntryType(const xmlChar *name) { + xmlCatalogEntryType type = XML_CATA_NONE; + if (xmlStrEqual(name, (const xmlChar *) "SYSTEM")) + type = SGML_CATA_SYSTEM; + else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC")) + type = SGML_CATA_PUBLIC; + else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE")) + type = SGML_CATA_DELEGATE; + else if (xmlStrEqual(name, (const xmlChar *) "ENTITY")) + type = SGML_CATA_ENTITY; + else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE")) + type = SGML_CATA_DOCTYPE; + else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE")) + type = SGML_CATA_LINKTYPE; + else if (xmlStrEqual(name, (const xmlChar *) "NOTATION")) + type = SGML_CATA_NOTATION; + else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL")) + type = SGML_CATA_SGMLDECL; + else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT")) + type = SGML_CATA_DOCUMENT; + else if (xmlStrEqual(name, (const xmlChar *) "CATALOG")) + type = SGML_CATA_CATALOG; + else if (xmlStrEqual(name, (const xmlChar *) "BASE")) + type = SGML_CATA_BASE; + return(type); +} + +/** + * xmlParseSGMLCatalog: + * @catal: the SGML Catalog + * @value: the content of the SGML Catalog serialization + * @file: the filepath for the catalog + * @super: should this be handled as a Super Catalog in which case + * parsing is not recursive + * + * Parse an SGML catalog content and fill up the @catal hash table with + * the new entries found. + * + * Returns 0 in case of success, -1 in case of error. + */ +static int +xmlParseSGMLCatalog(xmlCatalogPtr catal, const xmlChar *value, + const char *file, int super) { + const xmlChar *cur = value; + xmlChar *base = NULL; + int res; + + if ((cur == NULL) || (file == NULL)) + return(-1); + base = xmlStrdup((const xmlChar *) file); + + while ((cur != NULL) && (cur[0] != 0)) { + SKIP_BLANKS; + if (cur[0] == 0) + break; + if ((cur[0] == '-') && (cur[1] == '-')) { + cur = xmlParseSGMLCatalogComment(cur); + if (cur == NULL) { + /* error */ + break; + } + } else { + xmlChar *sysid = NULL; + xmlChar *name = NULL; + xmlCatalogEntryType type = XML_CATA_NONE; + + cur = xmlParseSGMLCatalogName(cur, &name); + if (name == NULL) { + /* error */ + break; + } + if (!IS_BLANK_CH(*cur)) { + /* error */ + break; + } + SKIP_BLANKS; + if (xmlStrEqual(name, (const xmlChar *) "SYSTEM")) + type = SGML_CATA_SYSTEM; + else if (xmlStrEqual(name, (const xmlChar *) "PUBLIC")) + type = SGML_CATA_PUBLIC; + else if (xmlStrEqual(name, (const xmlChar *) "DELEGATE")) + type = SGML_CATA_DELEGATE; + else if (xmlStrEqual(name, (const xmlChar *) "ENTITY")) + type = SGML_CATA_ENTITY; + else if (xmlStrEqual(name, (const xmlChar *) "DOCTYPE")) + type = SGML_CATA_DOCTYPE; + else if (xmlStrEqual(name, (const xmlChar *) "LINKTYPE")) + type = SGML_CATA_LINKTYPE; + else if (xmlStrEqual(name, (const xmlChar *) "NOTATION")) + type = SGML_CATA_NOTATION; + else if (xmlStrEqual(name, (const xmlChar *) "SGMLDECL")) + type = SGML_CATA_SGMLDECL; + else if (xmlStrEqual(name, (const xmlChar *) "DOCUMENT")) + type = SGML_CATA_DOCUMENT; + else if (xmlStrEqual(name, (const xmlChar *) "CATALOG")) + type = SGML_CATA_CATALOG; + else if (xmlStrEqual(name, (const xmlChar *) "BASE")) + type = SGML_CATA_BASE; + else if (xmlStrEqual(name, (const xmlChar *) "OVERRIDE")) { + xmlFree(name); + cur = xmlParseSGMLCatalogName(cur, &name); + if (name == NULL) { + /* error */ + break; + } + xmlFree(name); + continue; + } + xmlFree(name); + name = NULL; + + switch(type) { + case SGML_CATA_ENTITY: + if (*cur == '%') + type = SGML_CATA_PENTITY; + case SGML_CATA_PENTITY: + case SGML_CATA_DOCTYPE: + case SGML_CATA_LINKTYPE: + case SGML_CATA_NOTATION: + cur = xmlParseSGMLCatalogName(cur, &name); + if (cur == NULL) { + /* error */ + break; + } + if (!IS_BLANK_CH(*cur)) { + /* error */ + break; + } + SKIP_BLANKS; + cur = xmlParseSGMLCatalogPubid(cur, &sysid); + if (cur == NULL) { + /* error */ + break; + } + break; + case SGML_CATA_PUBLIC: + case SGML_CATA_SYSTEM: + case SGML_CATA_DELEGATE: + cur = xmlParseSGMLCatalogPubid(cur, &name); + if (cur == NULL) { + /* error */ + break; + } + if (type != SGML_CATA_SYSTEM) { + xmlChar *normid; + + normid = xmlCatalogNormalizePublic(name); + if (normid != NULL) { + if (name != NULL) + xmlFree(name); + if (*normid != 0) + name = normid; + else { + xmlFree(normid); + name = NULL; + } + } + } + if (!IS_BLANK_CH(*cur)) { + /* error */ + break; + } + SKIP_BLANKS; + cur = xmlParseSGMLCatalogPubid(cur, &sysid); + if (cur == NULL) { + /* error */ + break; + } + break; + case SGML_CATA_BASE: + case SGML_CATA_CATALOG: + case SGML_CATA_DOCUMENT: + case SGML_CATA_SGMLDECL: + cur = xmlParseSGMLCatalogPubid(cur, &sysid); + if (cur == NULL) { + /* error */ + break; + } + break; + default: + break; + } + if (cur == NULL) { + if (name != NULL) + xmlFree(name); + if (sysid != NULL) + xmlFree(sysid); + break; + } else if (type == SGML_CATA_BASE) { + if (base != NULL) + xmlFree(base); + base = xmlStrdup(sysid); + } else if ((type == SGML_CATA_PUBLIC) || + (type == SGML_CATA_SYSTEM)) { + xmlChar *filename; + + filename = xmlBuildURI(sysid, base); + if (filename != NULL) { + xmlCatalogEntryPtr entry; + + entry = xmlNewCatalogEntry(type, name, filename, + NULL, XML_CATA_PREFER_NONE, NULL); + res = xmlHashAddEntry(catal->sgml, name, entry); + if (res < 0) { + xmlFreeCatalogEntry(entry); + } + xmlFree(filename); + } + + } else if (type == SGML_CATA_CATALOG) { + if (super) { + xmlCatalogEntryPtr entry; + + entry = xmlNewCatalogEntry(type, sysid, NULL, NULL, + XML_CATA_PREFER_NONE, NULL); + res = xmlHashAddEntry(catal->sgml, sysid, entry); + if (res < 0) { + xmlFreeCatalogEntry(entry); + } + } else { + xmlChar *filename; + + filename = xmlBuildURI(sysid, base); + if (filename != NULL) { + xmlExpandCatalog(catal, (const char *)filename); + xmlFree(filename); + } + } + } + /* + * drop anything else we won't handle it + */ + if (name != NULL) + xmlFree(name); + if (sysid != NULL) + xmlFree(sysid); + } + } + if (base != NULL) + xmlFree(base); + if (cur == NULL) + return(-1); + return(0); +} + +/************************************************************************ + * * + * SGML Catalog handling * + * * + ************************************************************************/ + +/** + * xmlCatalogGetSGMLPublic: + * @catal: an SGML catalog hash + * @pubID: the public ID string + * + * Try to lookup the catalog local reference associated to a public ID + * + * Returns the local resource if found or NULL otherwise. + */ +static const xmlChar * +xmlCatalogGetSGMLPublic(xmlHashTablePtr catal, const xmlChar *pubID) { + xmlCatalogEntryPtr entry; + xmlChar *normid; + + if (catal == NULL) + return(NULL); + + normid = xmlCatalogNormalizePublic(pubID); + if (normid != NULL) + pubID = (*normid != 0 ? normid : NULL); + + entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, pubID); + if (entry == NULL) { + if (normid != NULL) + xmlFree(normid); + return(NULL); + } + if (entry->type == SGML_CATA_PUBLIC) { + if (normid != NULL) + xmlFree(normid); + return(entry->URL); + } + if (normid != NULL) + xmlFree(normid); + return(NULL); +} + +/** + * xmlCatalogGetSGMLSystem: + * @catal: an SGML catalog hash + * @sysID: the system ID string + * + * Try to lookup the catalog local reference for a system ID + * + * Returns the local resource if found or NULL otherwise. + */ +static const xmlChar * +xmlCatalogGetSGMLSystem(xmlHashTablePtr catal, const xmlChar *sysID) { + xmlCatalogEntryPtr entry; + + if (catal == NULL) + return(NULL); + + entry = (xmlCatalogEntryPtr) xmlHashLookup(catal, sysID); + if (entry == NULL) + return(NULL); + if (entry->type == SGML_CATA_SYSTEM) + return(entry->URL); + return(NULL); +} + +/** + * xmlCatalogSGMLResolve: + * @catal: the SGML catalog + * @pubID: the public ID string + * @sysID: the system ID string + * + * Do a complete resolution lookup of an External Identifier + * + * Returns the URI of the resource or NULL if not found + */ +static const xmlChar * +xmlCatalogSGMLResolve(xmlCatalogPtr catal, const xmlChar *pubID, + const xmlChar *sysID) { + const xmlChar *ret = NULL; + + if (catal->sgml == NULL) + return(NULL); + + if (pubID != NULL) + ret = xmlCatalogGetSGMLPublic(catal->sgml, pubID); + if (ret != NULL) + return(ret); + if (sysID != NULL) + ret = xmlCatalogGetSGMLSystem(catal->sgml, sysID); + if (ret != NULL) + return(ret); + return(NULL); +} + +/************************************************************************ + * * + * Specific Public interfaces * + * * + ************************************************************************/ + +/** + * xmlLoadSGMLSuperCatalog: + * @filename: a file path + * + * Load an SGML super catalog. It won't expand CATALOG or DELEGATE + * references. This is only needed for manipulating SGML Super Catalogs + * like adding and removing CATALOG or DELEGATE entries. + * + * Returns the catalog parsed or NULL in case of error + */ +xmlCatalogPtr +xmlLoadSGMLSuperCatalog(const char *filename) +{ + xmlChar *content; + xmlCatalogPtr catal; + int ret; + + content = xmlLoadFileContent(filename); + if (content == NULL) + return(NULL); + + catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer); + if (catal == NULL) { + xmlFree(content); + return(NULL); + } + + ret = xmlParseSGMLCatalog(catal, content, filename, 1); + xmlFree(content); + if (ret < 0) { + xmlFreeCatalog(catal); + return(NULL); + } + return (catal); +} + +/** + * xmlLoadACatalog: + * @filename: a file path + * + * Load the catalog and build the associated data structures. + * This can be either an XML Catalog or an SGML Catalog + * It will recurse in SGML CATALOG entries. On the other hand XML + * Catalogs are not handled recursively. + * + * Returns the catalog parsed or NULL in case of error + */ +xmlCatalogPtr +xmlLoadACatalog(const char *filename) +{ + xmlChar *content; + xmlChar *first; + xmlCatalogPtr catal; + int ret; + + content = xmlLoadFileContent(filename); + if (content == NULL) + return(NULL); + + + first = content; + + while ((*first != 0) && (*first != '-') && (*first != '<') && + (!(((*first >= 'A') && (*first <= 'Z')) || + ((*first >= 'a') && (*first <= 'z'))))) + first++; + + if (*first != '<') { + catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, xmlCatalogDefaultPrefer); + if (catal == NULL) { + xmlFree(content); + return(NULL); + } + ret = xmlParseSGMLCatalog(catal, content, filename, 0); + if (ret < 0) { + xmlFreeCatalog(catal); + xmlFree(content); + return(NULL); + } + } else { + catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, xmlCatalogDefaultPrefer); + if (catal == NULL) { + xmlFree(content); + return(NULL); + } + catal->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, + NULL, BAD_CAST filename, xmlCatalogDefaultPrefer, NULL); + } + xmlFree(content); + return (catal); +} + +/** + * xmlExpandCatalog: + * @catal: a catalog + * @filename: a file path + * + * Load the catalog and expand the existing catal structure. + * This can be either an XML Catalog or an SGML Catalog + * + * Returns 0 in case of success, -1 in case of error + */ +static int +xmlExpandCatalog(xmlCatalogPtr catal, const char *filename) +{ + int ret; + + if ((catal == NULL) || (filename == NULL)) + return(-1); + + + if (catal->type == XML_SGML_CATALOG_TYPE) { + xmlChar *content; + + content = xmlLoadFileContent(filename); + if (content == NULL) + return(-1); + + ret = xmlParseSGMLCatalog(catal, content, filename, 0); + if (ret < 0) { + xmlFree(content); + return(-1); + } + xmlFree(content); + } else { + xmlCatalogEntryPtr tmp, cur; + tmp = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, + NULL, BAD_CAST filename, xmlCatalogDefaultPrefer, NULL); + + cur = catal->xml; + if (cur == NULL) { + catal->xml = tmp; + } else { + while (cur->next != NULL) cur = cur->next; + cur->next = tmp; + } + } + return (0); +} + +/** + * xmlACatalogResolveSystem: + * @catal: a Catalog + * @sysID: the system ID string + * + * Try to lookup the catalog resource for a system ID + * + * Returns the resource if found or NULL otherwise, the value returned + * must be freed by the caller. + */ +xmlChar * +xmlACatalogResolveSystem(xmlCatalogPtr catal, const xmlChar *sysID) { + xmlChar *ret = NULL; + + if ((sysID == NULL) || (catal == NULL)) + return(NULL); + + if (xmlDebugCatalogs) + xmlGenericError(xmlGenericErrorContext, + "Resolve sysID %s\n", sysID); + + if (catal->type == XML_XML_CATALOG_TYPE) { + ret = xmlCatalogListXMLResolve(catal->xml, NULL, sysID); + if (ret == XML_CATAL_BREAK) + ret = NULL; + } else { + const xmlChar *sgml; + + sgml = xmlCatalogGetSGMLSystem(catal->sgml, sysID); + if (sgml != NULL) + ret = xmlStrdup(sgml); + } + return(ret); +} + +/** + * xmlACatalogResolvePublic: + * @catal: a Catalog + * @pubID: the public ID string + * + * Try to lookup the catalog local reference associated to a public ID in that catalog + * + * Returns the local resource if found or NULL otherwise, the value returned + * must be freed by the caller. + */ +xmlChar * +xmlACatalogResolvePublic(xmlCatalogPtr catal, const xmlChar *pubID) { + xmlChar *ret = NULL; + + if ((pubID == NULL) || (catal == NULL)) + return(NULL); + + if (xmlDebugCatalogs) + xmlGenericError(xmlGenericErrorContext, + "Resolve pubID %s\n", pubID); + + if (catal->type == XML_XML_CATALOG_TYPE) { + ret = xmlCatalogListXMLResolve(catal->xml, pubID, NULL); + if (ret == XML_CATAL_BREAK) + ret = NULL; + } else { + const xmlChar *sgml; + + sgml = xmlCatalogGetSGMLPublic(catal->sgml, pubID); + if (sgml != NULL) + ret = xmlStrdup(sgml); + } + return(ret); +} + +/** + * xmlACatalogResolve: + * @catal: a Catalog + * @pubID: the public ID string + * @sysID: the system ID string + * + * Do a complete resolution lookup of an External Identifier + * + * Returns the URI of the resource or NULL if not found, it must be freed + * by the caller. + */ +xmlChar * +xmlACatalogResolve(xmlCatalogPtr catal, const xmlChar * pubID, + const xmlChar * sysID) +{ + xmlChar *ret = NULL; + + if (((pubID == NULL) && (sysID == NULL)) || (catal == NULL)) + return (NULL); + + if (xmlDebugCatalogs) { + if ((pubID != NULL) && (sysID != NULL)) { + xmlGenericError(xmlGenericErrorContext, + "Resolve: pubID %s sysID %s\n", pubID, sysID); + } else if (pubID != NULL) { + xmlGenericError(xmlGenericErrorContext, + "Resolve: pubID %s\n", pubID); + } else { + xmlGenericError(xmlGenericErrorContext, + "Resolve: sysID %s\n", sysID); + } + } + + if (catal->type == XML_XML_CATALOG_TYPE) { + ret = xmlCatalogListXMLResolve(catal->xml, pubID, sysID); + if (ret == XML_CATAL_BREAK) + ret = NULL; + } else { + const xmlChar *sgml; + + sgml = xmlCatalogSGMLResolve(catal, pubID, sysID); + if (sgml != NULL) + ret = xmlStrdup(sgml); + } + return (ret); +} + +/** + * xmlACatalogResolveURI: + * @catal: a Catalog + * @URI: the URI + * + * Do a complete resolution lookup of an URI + * + * Returns the URI of the resource or NULL if not found, it must be freed + * by the caller. + */ +xmlChar * +xmlACatalogResolveURI(xmlCatalogPtr catal, const xmlChar *URI) { + xmlChar *ret = NULL; + + if ((URI == NULL) || (catal == NULL)) + return(NULL); + + if (xmlDebugCatalogs) + xmlGenericError(xmlGenericErrorContext, + "Resolve URI %s\n", URI); + + if (catal->type == XML_XML_CATALOG_TYPE) { + ret = xmlCatalogListXMLResolveURI(catal->xml, URI); + if (ret == XML_CATAL_BREAK) + ret = NULL; + } else { + const xmlChar *sgml; + + sgml = xmlCatalogSGMLResolve(catal, NULL, URI); + if (sgml != NULL) + ret = xmlStrdup(sgml); + } + return(ret); +} + +#ifdef LIBXML_OUTPUT_ENABLED +/** + * xmlACatalogDump: + * @catal: a Catalog + * @out: the file. + * + * Dump the given catalog to the given file. + */ +void +xmlACatalogDump(xmlCatalogPtr catal, FILE *out) { + if ((out == NULL) || (catal == NULL)) + return; + + if (catal->type == XML_XML_CATALOG_TYPE) { + xmlDumpXMLCatalog(out, catal->xml); + } else { + xmlHashScan(catal->sgml, + (xmlHashScanner) xmlCatalogDumpEntry, out); + } +} +#endif /* LIBXML_OUTPUT_ENABLED */ + +/** + * xmlACatalogAdd: + * @catal: a Catalog + * @type: the type of record to add to the catalog + * @orig: the system, public or prefix to match + * @replace: the replacement value for the match + * + * Add an entry in the catalog, it may overwrite existing but + * different entries. + * + * Returns 0 if successful, -1 otherwise + */ +int +xmlACatalogAdd(xmlCatalogPtr catal, const xmlChar * type, + const xmlChar * orig, const xmlChar * replace) +{ + int res = -1; + + if (catal == NULL) + return(-1); + + if (catal->type == XML_XML_CATALOG_TYPE) { + res = xmlAddXMLCatalog(catal->xml, type, orig, replace); + } else { + xmlCatalogEntryType cattype; + + cattype = xmlGetSGMLCatalogEntryType(type); + if (cattype != XML_CATA_NONE) { + xmlCatalogEntryPtr entry; + + entry = xmlNewCatalogEntry(cattype, orig, replace, NULL, + XML_CATA_PREFER_NONE, NULL); + if (catal->sgml == NULL) + catal->sgml = xmlHashCreate(10); + res = xmlHashAddEntry(catal->sgml, orig, entry); + } + } + return (res); +} + +/** + * xmlACatalogRemove: + * @catal: a Catalog + * @value: the value to remove + * + * Remove an entry from the catalog + * + * Returns the number of entries removed if successful, -1 otherwise + */ +int +xmlACatalogRemove(xmlCatalogPtr catal, const xmlChar *value) { + int res = -1; + + if ((catal == NULL) || (value == NULL)) + return(-1); + + if (catal->type == XML_XML_CATALOG_TYPE) { + res = xmlDelXMLCatalog(catal->xml, value); + } else { + res = xmlHashRemoveEntry(catal->sgml, value, + (xmlHashDeallocator) xmlFreeCatalogEntry); + if (res == 0) + res = 1; + } + return(res); +} + +/** + * xmlNewCatalog: + * @sgml: should this create an SGML catalog + * + * create a new Catalog. + * + * Returns the xmlCatalogPtr or NULL in case of error + */ +xmlCatalogPtr +xmlNewCatalog(int sgml) { + xmlCatalogPtr catal = NULL; + + if (sgml) { + catal = xmlCreateNewCatalog(XML_SGML_CATALOG_TYPE, + xmlCatalogDefaultPrefer); + if ((catal != NULL) && (catal->sgml == NULL)) + catal->sgml = xmlHashCreate(10); + } else + catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, + xmlCatalogDefaultPrefer); + return(catal); +} + +/** + * xmlCatalogIsEmpty: + * @catal: should this create an SGML catalog + * + * Check is a catalog is empty + * + * Returns 1 if the catalog is empty, 0 if not, amd -1 in case of error. + */ +int +xmlCatalogIsEmpty(xmlCatalogPtr catal) { + if (catal == NULL) + return(-1); + + if (catal->type == XML_XML_CATALOG_TYPE) { + if (catal->xml == NULL) + return(1); + if ((catal->xml->type != XML_CATA_CATALOG) && + (catal->xml->type != XML_CATA_BROKEN_CATALOG)) + return(-1); + if (catal->xml->children == NULL) + return(1); + return(0); + } else { + int res; + + if (catal->sgml == NULL) + return(1); + res = xmlHashSize(catal->sgml); + if (res == 0) + return(1); + if (res < 0) + return(-1); + } + return(0); +} + +/************************************************************************ + * * + * Public interfaces manipulating the global shared default catalog * + * * + ************************************************************************/ + +/** + * xmlInitializeCatalogData: + * + * Do the catalog initialization only of global data, doesn't try to load + * any catalog actually. + * this function is not thread safe, catalog initialization should + * preferably be done once at startup + */ +static void +xmlInitializeCatalogData(void) { + if (xmlCatalogInitialized != 0) + return; + + if (getenv("XML_DEBUG_CATALOG")) + xmlDebugCatalogs = 1; + xmlCatalogMutex = xmlNewRMutex(); + + xmlCatalogInitialized = 1; +} +/** + * xmlInitializeCatalog: + * + * Do the catalog initialization. + * this function is not thread safe, catalog initialization should + * preferably be done once at startup + */ +void +xmlInitializeCatalog(void) { + if (xmlCatalogInitialized != 0) + return; + + xmlInitializeCatalogData(); + xmlRMutexLock(xmlCatalogMutex); + + if (getenv("XML_DEBUG_CATALOG")) + xmlDebugCatalogs = 1; + + if (xmlDefaultCatalog == NULL) { + const char *catalogs; + char *path; + const char *cur, *paths; + xmlCatalogPtr catal; + xmlCatalogEntryPtr *nextent; + + 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(buf); + if (uri != NULL) { + strncpy(XML_XML_DEFAULT_CATALOG, uri, 255); + xmlFree(uri); + } + } + } + } + catalogs = XML_XML_DEFAULT_CATALOG; + } +#else + catalogs = XML_XML_DEFAULT_CATALOG; +#endif + + catal = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, + xmlCatalogDefaultPrefer); + if (catal != NULL) { + /* the XML_CATALOG_FILES envvar is allowed to contain a + space-separated list of entries. */ + cur = catalogs; + nextent = &catal->xml; + while (*cur != '\0') { + while (xmlIsBlank_ch(*cur)) + cur++; + if (*cur != 0) { + paths = cur; + while ((*cur != 0) && (!xmlIsBlank_ch(*cur))) + cur++; + path = (char *) xmlStrndup((const xmlChar *)paths, cur - paths); + if (path != NULL) { + *nextent = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, + NULL, BAD_CAST path, xmlCatalogDefaultPrefer, NULL); + if (*nextent != NULL) + nextent = &((*nextent)->next); + xmlFree(path); + } + } + } + xmlDefaultCatalog = catal; + } + } + + xmlRMutexUnlock(xmlCatalogMutex); +} + + +/** + * xmlLoadCatalog: + * @filename: a file path + * + * Load the catalog and makes its definitions effective for the default + * external entity loader. It will recurse in SGML CATALOG entries. + * this function is not thread safe, catalog initialization should + * preferably be done once at startup + * + * Returns 0 in case of success -1 in case of error + */ +int +xmlLoadCatalog(const char *filename) +{ + int ret; + xmlCatalogPtr catal; + + if (!xmlCatalogInitialized) + xmlInitializeCatalogData(); + + xmlRMutexLock(xmlCatalogMutex); + + if (xmlDefaultCatalog == NULL) { + catal = xmlLoadACatalog(filename); + if (catal == NULL) { + xmlRMutexUnlock(xmlCatalogMutex); + return(-1); + } + + xmlDefaultCatalog = catal; + xmlRMutexUnlock(xmlCatalogMutex); + return(0); + } + + ret = xmlExpandCatalog(xmlDefaultCatalog, filename); + xmlRMutexUnlock(xmlCatalogMutex); + return(ret); +} + +/** + * xmlLoadCatalogs: + * @pathss: a list of directories separated by a colon or a space. + * + * Load the catalogs and makes their definitions effective for the default + * external entity loader. + * this function is not thread safe, catalog initialization should + * preferably be done once at startup + */ +void +xmlLoadCatalogs(const char *pathss) { + const char *cur; + const char *paths; + xmlChar *path; +#ifdef _WIN32 + int i, iLen; +#endif + + if (pathss == NULL) + return; + + cur = pathss; + while (*cur != 0) { + while (xmlIsBlank_ch(*cur)) cur++; + if (*cur != 0) { + paths = cur; + while ((*cur != 0) && (*cur != PATH_SEAPARATOR) && (!xmlIsBlank_ch(*cur))) + cur++; + path = xmlStrndup((const xmlChar *)paths, cur - paths); +#ifdef _WIN32 + iLen = strlen(path); + for(i = 0; i < iLen; i++) { + if(path[i] == '\\') { + path[i] = '/'; + } + } +#endif + if (path != NULL) { + xmlLoadCatalog((const char *) path); + xmlFree(path); + } + } + while (*cur == PATH_SEAPARATOR) + cur++; + } +} + +/** + * xmlCatalogCleanup: + * + * Free up all the memory associated with catalogs + */ +void +xmlCatalogCleanup(void) { + if (xmlCatalogInitialized == 0) + return; + + xmlRMutexLock(xmlCatalogMutex); + if (xmlDebugCatalogs) + xmlGenericError(xmlGenericErrorContext, + "Catalogs cleanup\n"); + if (xmlCatalogXMLFiles != NULL) + xmlHashFree(xmlCatalogXMLFiles, + (xmlHashDeallocator)xmlFreeCatalogHashEntryList); + xmlCatalogXMLFiles = NULL; + if (xmlDefaultCatalog != NULL) + xmlFreeCatalog(xmlDefaultCatalog); + xmlDefaultCatalog = NULL; + xmlDebugCatalogs = 0; + xmlCatalogInitialized = 0; + xmlRMutexUnlock(xmlCatalogMutex); + xmlFreeRMutex(xmlCatalogMutex); +} + +/** + * xmlCatalogResolveSystem: + * @sysID: the system ID string + * + * Try to lookup the catalog resource for a system ID + * + * Returns the resource if found or NULL otherwise, the value returned + * must be freed by the caller. + */ +xmlChar * +xmlCatalogResolveSystem(const xmlChar *sysID) { + xmlChar *ret; + + if (!xmlCatalogInitialized) + xmlInitializeCatalog(); + + ret = xmlACatalogResolveSystem(xmlDefaultCatalog, sysID); + return(ret); +} + +/** + * xmlCatalogResolvePublic: + * @pubID: the public ID string + * + * Try to lookup the catalog reference associated to a public ID + * + * Returns the resource if found or NULL otherwise, the value returned + * must be freed by the caller. + */ +xmlChar * +xmlCatalogResolvePublic(const xmlChar *pubID) { + xmlChar *ret; + + if (!xmlCatalogInitialized) + xmlInitializeCatalog(); + + ret = xmlACatalogResolvePublic(xmlDefaultCatalog, pubID); + return(ret); +} + +/** + * xmlCatalogResolve: + * @pubID: the public ID string + * @sysID: the system ID string + * + * Do a complete resolution lookup of an External Identifier + * + * Returns the URI of the resource or NULL if not found, it must be freed + * by the caller. + */ +xmlChar * +xmlCatalogResolve(const xmlChar *pubID, const xmlChar *sysID) { + xmlChar *ret; + + if (!xmlCatalogInitialized) + xmlInitializeCatalog(); + + ret = xmlACatalogResolve(xmlDefaultCatalog, pubID, sysID); + return(ret); +} + +/** + * xmlCatalogResolveURI: + * @URI: the URI + * + * Do a complete resolution lookup of an URI + * + * Returns the URI of the resource or NULL if not found, it must be freed + * by the caller. + */ +xmlChar * +xmlCatalogResolveURI(const xmlChar *URI) { + xmlChar *ret; + + if (!xmlCatalogInitialized) + xmlInitializeCatalog(); + + ret = xmlACatalogResolveURI(xmlDefaultCatalog, URI); + return(ret); +} + +#ifdef LIBXML_OUTPUT_ENABLED +/** + * xmlCatalogDump: + * @out: the file. + * + * Dump all the global catalog content to the given file. + */ +void +xmlCatalogDump(FILE *out) { + if (out == NULL) + return; + + if (!xmlCatalogInitialized) + xmlInitializeCatalog(); + + xmlACatalogDump(xmlDefaultCatalog, out); +} +#endif /* LIBXML_OUTPUT_ENABLED */ + +/** + * xmlCatalogAdd: + * @type: the type of record to add to the catalog + * @orig: the system, public or prefix to match + * @replace: the replacement value for the match + * + * Add an entry in the catalog, it may overwrite existing but + * different entries. + * If called before any other catalog routine, allows to override the + * default shared catalog put in place by xmlInitializeCatalog(); + * + * Returns 0 if successful, -1 otherwise + */ +int +xmlCatalogAdd(const xmlChar *type, const xmlChar *orig, const xmlChar *replace) { + int res = -1; + + if (!xmlCatalogInitialized) + xmlInitializeCatalogData(); + + xmlRMutexLock(xmlCatalogMutex); + /* + * Specific case where one want to override the default catalog + * put in place by xmlInitializeCatalog(); + */ + if ((xmlDefaultCatalog == NULL) && + (xmlStrEqual(type, BAD_CAST "catalog"))) { + xmlDefaultCatalog = xmlCreateNewCatalog(XML_XML_CATALOG_TYPE, + xmlCatalogDefaultPrefer); + xmlDefaultCatalog->xml = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, + orig, NULL, xmlCatalogDefaultPrefer, NULL); + + xmlRMutexUnlock(xmlCatalogMutex); + return(0); + } + + res = xmlACatalogAdd(xmlDefaultCatalog, type, orig, replace); + xmlRMutexUnlock(xmlCatalogMutex); + return(res); +} + +/** + * xmlCatalogRemove: + * @value: the value to remove + * + * Remove an entry from the catalog + * + * Returns the number of entries removed if successful, -1 otherwise + */ +int +xmlCatalogRemove(const xmlChar *value) { + int res; + + if (!xmlCatalogInitialized) + xmlInitializeCatalog(); + + xmlRMutexLock(xmlCatalogMutex); + res = xmlACatalogRemove(xmlDefaultCatalog, value); + xmlRMutexUnlock(xmlCatalogMutex); + return(res); +} + +/** + * xmlCatalogConvert: + * + * Convert all the SGML catalog entries as XML ones + * + * Returns the number of entries converted if successful, -1 otherwise + */ +int +xmlCatalogConvert(void) { + int res = -1; + + if (!xmlCatalogInitialized) + xmlInitializeCatalog(); + + xmlRMutexLock(xmlCatalogMutex); + res = xmlConvertSGMLCatalog(xmlDefaultCatalog); + xmlRMutexUnlock(xmlCatalogMutex); + return(res); +} + +/************************************************************************ + * * + * Public interface manipulating the common preferences * + * * + ************************************************************************/ + +/** + * xmlCatalogGetDefaults: + * + * Used to get the user preference w.r.t. to what catalogs should + * be accepted + * + * Returns the current xmlCatalogAllow value + */ +xmlCatalogAllow +xmlCatalogGetDefaults(void) { + return(xmlCatalogDefaultAllow); +} + +/** + * xmlCatalogSetDefaults: + * @allow: what catalogs should be accepted + * + * Used to set the user preference w.r.t. to what catalogs should + * be accepted + */ +void +xmlCatalogSetDefaults(xmlCatalogAllow allow) { + if (xmlDebugCatalogs) { + switch (allow) { + case XML_CATA_ALLOW_NONE: + xmlGenericError(xmlGenericErrorContext, + "Disabling catalog usage\n"); + break; + case XML_CATA_ALLOW_GLOBAL: + xmlGenericError(xmlGenericErrorContext, + "Allowing only global catalogs\n"); + break; + case XML_CATA_ALLOW_DOCUMENT: + xmlGenericError(xmlGenericErrorContext, + "Allowing only catalogs from the document\n"); + break; + case XML_CATA_ALLOW_ALL: + xmlGenericError(xmlGenericErrorContext, + "Allowing all catalogs\n"); + break; + } + } + xmlCatalogDefaultAllow = allow; +} + +/** + * xmlCatalogSetDefaultPrefer: + * @prefer: the default preference for delegation + * + * Allows to set the preference between public and system for deletion + * in XML Catalog resolution. C.f. section 4.1.1 of the spec + * Values accepted are XML_CATA_PREFER_PUBLIC or XML_CATA_PREFER_SYSTEM + * + * Returns the previous value of the default preference for delegation + */ +xmlCatalogPrefer +xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer) { + xmlCatalogPrefer ret = xmlCatalogDefaultPrefer; + + if (prefer == XML_CATA_PREFER_NONE) + return(ret); + + if (xmlDebugCatalogs) { + switch (prefer) { + case XML_CATA_PREFER_PUBLIC: + xmlGenericError(xmlGenericErrorContext, + "Setting catalog preference to PUBLIC\n"); + break; + case XML_CATA_PREFER_SYSTEM: + xmlGenericError(xmlGenericErrorContext, + "Setting catalog preference to SYSTEM\n"); + break; + case XML_CATA_PREFER_NONE: + break; + } + } + xmlCatalogDefaultPrefer = prefer; + return(ret); +} + +/** + * xmlCatalogSetDebug: + * @level: the debug level of catalogs required + * + * Used to set the debug level for catalog operation, 0 disable + * debugging, 1 enable it + * + * Returns the previous value of the catalog debugging level + */ +int +xmlCatalogSetDebug(int level) { + int ret = xmlDebugCatalogs; + + if (level <= 0) + xmlDebugCatalogs = 0; + else + xmlDebugCatalogs = level; + return(ret); +} + +/************************************************************************ + * * + * Minimal interfaces used for per-document catalogs by the parser * + * * + ************************************************************************/ + +/** + * xmlCatalogFreeLocal: + * @catalogs: a document's list of catalogs + * + * Free up the memory associated to the catalog list + */ +void +xmlCatalogFreeLocal(void *catalogs) { + xmlCatalogEntryPtr catal; + + if (!xmlCatalogInitialized) + xmlInitializeCatalog(); + + catal = (xmlCatalogEntryPtr) catalogs; + if (catal != NULL) + xmlFreeCatalogEntryList(catal); +} + + +/** + * xmlCatalogAddLocal: + * @catalogs: a document's list of catalogs + * @URL: the URL to a new local catalog + * + * Add the new entry to the catalog list + * + * Returns the updated list + */ +void * +xmlCatalogAddLocal(void *catalogs, const xmlChar *URL) { + xmlCatalogEntryPtr catal, add; + + if (!xmlCatalogInitialized) + xmlInitializeCatalog(); + + if (URL == NULL) + return(catalogs); + + if (xmlDebugCatalogs) + xmlGenericError(xmlGenericErrorContext, + "Adding document catalog %s\n", URL); + + add = xmlNewCatalogEntry(XML_CATA_CATALOG, NULL, URL, NULL, + xmlCatalogDefaultPrefer, NULL); + if (add == NULL) + return(catalogs); + + catal = (xmlCatalogEntryPtr) catalogs; + if (catal == NULL) + return((void *) add); + + while (catal->next != NULL) + catal = catal->next; + catal->next = add; + return(catalogs); +} + +/** + * xmlCatalogLocalResolve: + * @catalogs: a document's list of catalogs + * @pubID: the public ID string + * @sysID: the system ID string + * + * Do a complete resolution lookup of an External Identifier using a + * document's private catalog list + * + * Returns the URI of the resource or NULL if not found, it must be freed + * by the caller. + */ +xmlChar * +xmlCatalogLocalResolve(void *catalogs, const xmlChar *pubID, + const xmlChar *sysID) { + xmlCatalogEntryPtr catal; + xmlChar *ret; + + if (!xmlCatalogInitialized) + xmlInitializeCatalog(); + + if ((pubID == NULL) && (sysID == NULL)) + return(NULL); + + if (xmlDebugCatalogs) { + if ((pubID != NULL) && (sysID != NULL)) { + xmlGenericError(xmlGenericErrorContext, + "Local Resolve: pubID %s sysID %s\n", pubID, sysID); + } else if (pubID != NULL) { + xmlGenericError(xmlGenericErrorContext, + "Local Resolve: pubID %s\n", pubID); + } else { + xmlGenericError(xmlGenericErrorContext, + "Local Resolve: sysID %s\n", sysID); + } + } + + catal = (xmlCatalogEntryPtr) catalogs; + if (catal == NULL) + return(NULL); + ret = xmlCatalogListXMLResolve(catal, pubID, sysID); + if ((ret != NULL) && (ret != XML_CATAL_BREAK)) + return(ret); + return(NULL); +} + +/** + * xmlCatalogLocalResolveURI: + * @catalogs: a document's list of catalogs + * @URI: the URI + * + * Do a complete resolution lookup of an URI using a + * document's private catalog list + * + * Returns the URI of the resource or NULL if not found, it must be freed + * by the caller. + */ +xmlChar * +xmlCatalogLocalResolveURI(void *catalogs, const xmlChar *URI) { + xmlCatalogEntryPtr catal; + xmlChar *ret; + + if (!xmlCatalogInitialized) + xmlInitializeCatalog(); + + if (URI == NULL) + return(NULL); + + if (xmlDebugCatalogs) + xmlGenericError(xmlGenericErrorContext, + "Resolve URI %s\n", URI); + + catal = (xmlCatalogEntryPtr) catalogs; + if (catal == NULL) + return(NULL); + ret = xmlCatalogListXMLResolveURI(catal, URI); + if ((ret != NULL) && (ret != XML_CATAL_BREAK)) + return(ret); + return(NULL); +} + +/************************************************************************ + * * + * Deprecated interfaces * + * * + ************************************************************************/ +/** + * xmlCatalogGetSystem: + * @sysID: the system ID string + * + * Try to lookup the catalog reference associated to a system ID + * DEPRECATED, use xmlCatalogResolveSystem() + * + * Returns the resource if found or NULL otherwise. + */ +const xmlChar * +xmlCatalogGetSystem(const xmlChar *sysID) { + xmlChar *ret; + static xmlChar result[1000]; + static int msg = 0; + + if (!xmlCatalogInitialized) + xmlInitializeCatalog(); + + if (msg == 0) { + xmlGenericError(xmlGenericErrorContext, + "Use of deprecated xmlCatalogGetSystem() call\n"); + msg++; + } + + if (sysID == NULL) + return(NULL); + + /* + * Check first the XML catalogs + */ + if (xmlDefaultCatalog != NULL) { + ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, NULL, sysID); + if ((ret != NULL) && (ret != XML_CATAL_BREAK)) { + snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret); + result[sizeof(result) - 1] = 0; + return(result); + } + } + + if (xmlDefaultCatalog != NULL) + return(xmlCatalogGetSGMLSystem(xmlDefaultCatalog->sgml, sysID)); + return(NULL); +} + +/** + * xmlCatalogGetPublic: + * @pubID: the public ID string + * + * Try to lookup the catalog reference associated to a public ID + * DEPRECATED, use xmlCatalogResolvePublic() + * + * Returns the resource if found or NULL otherwise. + */ +const xmlChar * +xmlCatalogGetPublic(const xmlChar *pubID) { + xmlChar *ret; + static xmlChar result[1000]; + static int msg = 0; + + if (!xmlCatalogInitialized) + xmlInitializeCatalog(); + + if (msg == 0) { + xmlGenericError(xmlGenericErrorContext, + "Use of deprecated xmlCatalogGetPublic() call\n"); + msg++; + } + + if (pubID == NULL) + return(NULL); + + /* + * Check first the XML catalogs + */ + if (xmlDefaultCatalog != NULL) { + ret = xmlCatalogListXMLResolve(xmlDefaultCatalog->xml, pubID, NULL); + if ((ret != NULL) && (ret != XML_CATAL_BREAK)) { + snprintf((char *) result, sizeof(result) - 1, "%s", (char *) ret); + result[sizeof(result) - 1] = 0; + return(result); + } + } + + if (xmlDefaultCatalog != NULL) + return(xmlCatalogGetSGMLPublic(xmlDefaultCatalog->sgml, pubID)); + return(NULL); +} + +#define bottom_catalog +#include "elfgcchack.h" +#endif /* LIBXML_CATALOG_ENABLED */ diff --git a/android/native/libxml2/chvalid.c b/android/native/libxml2/chvalid.c new file mode 100755 index 0000000000..00dd962c33 --- /dev/null +++ b/android/native/libxml2/chvalid.c @@ -0,0 +1,336 @@ +/* + * chvalid.c: this module implements the character range + * validation APIs + * + * This file is automatically generated from the cvs source + * definition files using the genChRanges.py Python script + * + * Generation date: Mon Mar 27 11:09:48 2006 + * Sources: chvalid.def + * William Brack + */ + +#define IN_LIBXML +#include "libxml.h" +#include + +/* + * The initial tables ({func_name}_tab) are used to validate whether a + * single-byte character is within the specified group. Each table + * contains 256 bytes, with each byte representing one of the 256 + * possible characters. If the table byte is set, the character is + * allowed. + * + */ +const unsigned char xmlIsPubidChar_tab[256] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }; + +static const xmlChSRange xmlIsBaseChar_srng[] = { {0x100, 0x131}, + {0x134, 0x13e}, {0x141, 0x148}, {0x14a, 0x17e}, {0x180, 0x1c3}, + {0x1cd, 0x1f0}, {0x1f4, 0x1f5}, {0x1fa, 0x217}, {0x250, 0x2a8}, + {0x2bb, 0x2c1}, {0x386, 0x386}, {0x388, 0x38a}, {0x38c, 0x38c}, + {0x38e, 0x3a1}, {0x3a3, 0x3ce}, {0x3d0, 0x3d6}, {0x3da, 0x3da}, + {0x3dc, 0x3dc}, {0x3de, 0x3de}, {0x3e0, 0x3e0}, {0x3e2, 0x3f3}, + {0x401, 0x40c}, {0x40e, 0x44f}, {0x451, 0x45c}, {0x45e, 0x481}, + {0x490, 0x4c4}, {0x4c7, 0x4c8}, {0x4cb, 0x4cc}, {0x4d0, 0x4eb}, + {0x4ee, 0x4f5}, {0x4f8, 0x4f9}, {0x531, 0x556}, {0x559, 0x559}, + {0x561, 0x586}, {0x5d0, 0x5ea}, {0x5f0, 0x5f2}, {0x621, 0x63a}, + {0x641, 0x64a}, {0x671, 0x6b7}, {0x6ba, 0x6be}, {0x6c0, 0x6ce}, + {0x6d0, 0x6d3}, {0x6d5, 0x6d5}, {0x6e5, 0x6e6}, {0x905, 0x939}, + {0x93d, 0x93d}, {0x958, 0x961}, {0x985, 0x98c}, {0x98f, 0x990}, + {0x993, 0x9a8}, {0x9aa, 0x9b0}, {0x9b2, 0x9b2}, {0x9b6, 0x9b9}, + {0x9dc, 0x9dd}, {0x9df, 0x9e1}, {0x9f0, 0x9f1}, {0xa05, 0xa0a}, + {0xa0f, 0xa10}, {0xa13, 0xa28}, {0xa2a, 0xa30}, {0xa32, 0xa33}, + {0xa35, 0xa36}, {0xa38, 0xa39}, {0xa59, 0xa5c}, {0xa5e, 0xa5e}, + {0xa72, 0xa74}, {0xa85, 0xa8b}, {0xa8d, 0xa8d}, {0xa8f, 0xa91}, + {0xa93, 0xaa8}, {0xaaa, 0xab0}, {0xab2, 0xab3}, {0xab5, 0xab9}, + {0xabd, 0xabd}, {0xae0, 0xae0}, {0xb05, 0xb0c}, {0xb0f, 0xb10}, + {0xb13, 0xb28}, {0xb2a, 0xb30}, {0xb32, 0xb33}, {0xb36, 0xb39}, + {0xb3d, 0xb3d}, {0xb5c, 0xb5d}, {0xb5f, 0xb61}, {0xb85, 0xb8a}, + {0xb8e, 0xb90}, {0xb92, 0xb95}, {0xb99, 0xb9a}, {0xb9c, 0xb9c}, + {0xb9e, 0xb9f}, {0xba3, 0xba4}, {0xba8, 0xbaa}, {0xbae, 0xbb5}, + {0xbb7, 0xbb9}, {0xc05, 0xc0c}, {0xc0e, 0xc10}, {0xc12, 0xc28}, + {0xc2a, 0xc33}, {0xc35, 0xc39}, {0xc60, 0xc61}, {0xc85, 0xc8c}, + {0xc8e, 0xc90}, {0xc92, 0xca8}, {0xcaa, 0xcb3}, {0xcb5, 0xcb9}, + {0xcde, 0xcde}, {0xce0, 0xce1}, {0xd05, 0xd0c}, {0xd0e, 0xd10}, + {0xd12, 0xd28}, {0xd2a, 0xd39}, {0xd60, 0xd61}, {0xe01, 0xe2e}, + {0xe30, 0xe30}, {0xe32, 0xe33}, {0xe40, 0xe45}, {0xe81, 0xe82}, + {0xe84, 0xe84}, {0xe87, 0xe88}, {0xe8a, 0xe8a}, {0xe8d, 0xe8d}, + {0xe94, 0xe97}, {0xe99, 0xe9f}, {0xea1, 0xea3}, {0xea5, 0xea5}, + {0xea7, 0xea7}, {0xeaa, 0xeab}, {0xead, 0xeae}, {0xeb0, 0xeb0}, + {0xeb2, 0xeb3}, {0xebd, 0xebd}, {0xec0, 0xec4}, {0xf40, 0xf47}, + {0xf49, 0xf69}, {0x10a0, 0x10c5}, {0x10d0, 0x10f6}, {0x1100, 0x1100}, + {0x1102, 0x1103}, {0x1105, 0x1107}, {0x1109, 0x1109}, {0x110b, 0x110c}, + {0x110e, 0x1112}, {0x113c, 0x113c}, {0x113e, 0x113e}, {0x1140, 0x1140}, + {0x114c, 0x114c}, {0x114e, 0x114e}, {0x1150, 0x1150}, {0x1154, 0x1155}, + {0x1159, 0x1159}, {0x115f, 0x1161}, {0x1163, 0x1163}, {0x1165, 0x1165}, + {0x1167, 0x1167}, {0x1169, 0x1169}, {0x116d, 0x116e}, {0x1172, 0x1173}, + {0x1175, 0x1175}, {0x119e, 0x119e}, {0x11a8, 0x11a8}, {0x11ab, 0x11ab}, + {0x11ae, 0x11af}, {0x11b7, 0x11b8}, {0x11ba, 0x11ba}, {0x11bc, 0x11c2}, + {0x11eb, 0x11eb}, {0x11f0, 0x11f0}, {0x11f9, 0x11f9}, {0x1e00, 0x1e9b}, + {0x1ea0, 0x1ef9}, {0x1f00, 0x1f15}, {0x1f18, 0x1f1d}, {0x1f20, 0x1f45}, + {0x1f48, 0x1f4d}, {0x1f50, 0x1f57}, {0x1f59, 0x1f59}, {0x1f5b, 0x1f5b}, + {0x1f5d, 0x1f5d}, {0x1f5f, 0x1f7d}, {0x1f80, 0x1fb4}, {0x1fb6, 0x1fbc}, + {0x1fbe, 0x1fbe}, {0x1fc2, 0x1fc4}, {0x1fc6, 0x1fcc}, {0x1fd0, 0x1fd3}, + {0x1fd6, 0x1fdb}, {0x1fe0, 0x1fec}, {0x1ff2, 0x1ff4}, {0x1ff6, 0x1ffc}, + {0x2126, 0x2126}, {0x212a, 0x212b}, {0x212e, 0x212e}, {0x2180, 0x2182}, + {0x3041, 0x3094}, {0x30a1, 0x30fa}, {0x3105, 0x312c}, {0xac00, 0xd7a3}}; +const xmlChRangeGroup xmlIsBaseCharGroup = + {197, 0, xmlIsBaseChar_srng, (xmlChLRangePtr)0}; + +static const xmlChSRange xmlIsChar_srng[] = { {0x100, 0xd7ff}, + {0xe000, 0xfffd}}; +static const xmlChLRange xmlIsChar_lrng[] = { {0x10000, 0x10ffff}}; +const xmlChRangeGroup xmlIsCharGroup = + {2, 1, xmlIsChar_srng, xmlIsChar_lrng}; + +static const xmlChSRange xmlIsCombining_srng[] = { {0x300, 0x345}, + {0x360, 0x361}, {0x483, 0x486}, {0x591, 0x5a1}, {0x5a3, 0x5b9}, + {0x5bb, 0x5bd}, {0x5bf, 0x5bf}, {0x5c1, 0x5c2}, {0x5c4, 0x5c4}, + {0x64b, 0x652}, {0x670, 0x670}, {0x6d6, 0x6dc}, {0x6dd, 0x6df}, + {0x6e0, 0x6e4}, {0x6e7, 0x6e8}, {0x6ea, 0x6ed}, {0x901, 0x903}, + {0x93c, 0x93c}, {0x93e, 0x94c}, {0x94d, 0x94d}, {0x951, 0x954}, + {0x962, 0x963}, {0x981, 0x983}, {0x9bc, 0x9bc}, {0x9be, 0x9be}, + {0x9bf, 0x9bf}, {0x9c0, 0x9c4}, {0x9c7, 0x9c8}, {0x9cb, 0x9cd}, + {0x9d7, 0x9d7}, {0x9e2, 0x9e3}, {0xa02, 0xa02}, {0xa3c, 0xa3c}, + {0xa3e, 0xa3e}, {0xa3f, 0xa3f}, {0xa40, 0xa42}, {0xa47, 0xa48}, + {0xa4b, 0xa4d}, {0xa70, 0xa71}, {0xa81, 0xa83}, {0xabc, 0xabc}, + {0xabe, 0xac5}, {0xac7, 0xac9}, {0xacb, 0xacd}, {0xb01, 0xb03}, + {0xb3c, 0xb3c}, {0xb3e, 0xb43}, {0xb47, 0xb48}, {0xb4b, 0xb4d}, + {0xb56, 0xb57}, {0xb82, 0xb83}, {0xbbe, 0xbc2}, {0xbc6, 0xbc8}, + {0xbca, 0xbcd}, {0xbd7, 0xbd7}, {0xc01, 0xc03}, {0xc3e, 0xc44}, + {0xc46, 0xc48}, {0xc4a, 0xc4d}, {0xc55, 0xc56}, {0xc82, 0xc83}, + {0xcbe, 0xcc4}, {0xcc6, 0xcc8}, {0xcca, 0xccd}, {0xcd5, 0xcd6}, + {0xd02, 0xd03}, {0xd3e, 0xd43}, {0xd46, 0xd48}, {0xd4a, 0xd4d}, + {0xd57, 0xd57}, {0xe31, 0xe31}, {0xe34, 0xe3a}, {0xe47, 0xe4e}, + {0xeb1, 0xeb1}, {0xeb4, 0xeb9}, {0xebb, 0xebc}, {0xec8, 0xecd}, + {0xf18, 0xf19}, {0xf35, 0xf35}, {0xf37, 0xf37}, {0xf39, 0xf39}, + {0xf3e, 0xf3e}, {0xf3f, 0xf3f}, {0xf71, 0xf84}, {0xf86, 0xf8b}, + {0xf90, 0xf95}, {0xf97, 0xf97}, {0xf99, 0xfad}, {0xfb1, 0xfb7}, + {0xfb9, 0xfb9}, {0x20d0, 0x20dc}, {0x20e1, 0x20e1}, {0x302a, 0x302f}, + {0x3099, 0x3099}, {0x309a, 0x309a}}; +const xmlChRangeGroup xmlIsCombiningGroup = + {95, 0, xmlIsCombining_srng, (xmlChLRangePtr)0}; + +static const xmlChSRange xmlIsDigit_srng[] = { {0x660, 0x669}, + {0x6f0, 0x6f9}, {0x966, 0x96f}, {0x9e6, 0x9ef}, {0xa66, 0xa6f}, + {0xae6, 0xaef}, {0xb66, 0xb6f}, {0xbe7, 0xbef}, {0xc66, 0xc6f}, + {0xce6, 0xcef}, {0xd66, 0xd6f}, {0xe50, 0xe59}, {0xed0, 0xed9}, + {0xf20, 0xf29}}; +const xmlChRangeGroup xmlIsDigitGroup = + {14, 0, xmlIsDigit_srng, (xmlChLRangePtr)0}; + +static const xmlChSRange xmlIsExtender_srng[] = { {0x2d0, 0x2d0}, + {0x2d1, 0x2d1}, {0x387, 0x387}, {0x640, 0x640}, {0xe46, 0xe46}, + {0xec6, 0xec6}, {0x3005, 0x3005}, {0x3031, 0x3035}, {0x309d, 0x309e}, + {0x30fc, 0x30fe}}; +const xmlChRangeGroup xmlIsExtenderGroup = + {10, 0, xmlIsExtender_srng, (xmlChLRangePtr)0}; + +static const xmlChSRange xmlIsIdeographic_srng[] = { {0x3007, 0x3007}, + {0x3021, 0x3029}, {0x4e00, 0x9fa5}}; +const xmlChRangeGroup xmlIsIdeographicGroup = + {3, 0, xmlIsIdeographic_srng, (xmlChLRangePtr)0}; + + +/** + * xmlCharInRange: + * @val: character to be validated + * @rptr: pointer to range to be used to validate + * + * Does a binary search of the range table to determine if char + * is valid + * + * Returns: true if character valid, false otherwise + */ +int +xmlCharInRange (unsigned int val, const xmlChRangeGroup *rptr) { + int low, high, mid; + const xmlChSRange *sptr; + const xmlChLRange *lptr; + + if (rptr == NULL) return(0); + if (val < 0x10000) { /* is val in 'short' or 'long' array? */ + if (rptr->nbShortRange == 0) + return 0; + low = 0; + high = rptr->nbShortRange - 1; + sptr = rptr->shortRange; + while (low <= high) { + mid = (low + high) / 2; + if ((unsigned short) val < sptr[mid].low) { + high = mid - 1; + } else { + if ((unsigned short) val > sptr[mid].high) { + low = mid + 1; + } else { + return 1; + } + } + } + } else { + if (rptr->nbLongRange == 0) { + return 0; + } + low = 0; + high = rptr->nbLongRange - 1; + lptr = rptr->longRange; + while (low <= high) { + mid = (low + high) / 2; + if (val < lptr[mid].low) { + high = mid - 1; + } else { + if (val > lptr[mid].high) { + low = mid + 1; + } else { + return 1; + } + } + } + } + return 0; +} + + +/** + * xmlIsBaseChar: + * @ch: character to validate + * + * This function is DEPRECATED. + * Use xmlIsBaseChar_ch or xmlIsBaseCharQ instead + * + * Returns true if argument valid, false otherwise + */ +int +xmlIsBaseChar(unsigned int ch) { + return(xmlIsBaseCharQ(ch)); +} + + +/** + * xmlIsBlank: + * @ch: character to validate + * + * This function is DEPRECATED. + * Use xmlIsBlank_ch or xmlIsBlankQ instead + * + * Returns true if argument valid, false otherwise + */ +int +xmlIsBlank(unsigned int ch) { + return(xmlIsBlankQ(ch)); +} + + +/** + * xmlIsChar: + * @ch: character to validate + * + * This function is DEPRECATED. + * Use xmlIsChar_ch or xmlIsCharQ instead + * + * Returns true if argument valid, false otherwise + */ +int +xmlIsChar(unsigned int ch) { + return(xmlIsCharQ(ch)); +} + + +/** + * xmlIsCombining: + * @ch: character to validate + * + * This function is DEPRECATED. + * Use xmlIsCombiningQ instead + * + * Returns true if argument valid, false otherwise + */ +int +xmlIsCombining(unsigned int ch) { + return(xmlIsCombiningQ(ch)); +} + + +/** + * xmlIsDigit: + * @ch: character to validate + * + * This function is DEPRECATED. + * Use xmlIsDigit_ch or xmlIsDigitQ instead + * + * Returns true if argument valid, false otherwise + */ +int +xmlIsDigit(unsigned int ch) { + return(xmlIsDigitQ(ch)); +} + + +/** + * xmlIsExtender: + * @ch: character to validate + * + * This function is DEPRECATED. + * Use xmlIsExtender_ch or xmlIsExtenderQ instead + * + * Returns true if argument valid, false otherwise + */ +int +xmlIsExtender(unsigned int ch) { + return(xmlIsExtenderQ(ch)); +} + + +/** + * xmlIsIdeographic: + * @ch: character to validate + * + * This function is DEPRECATED. + * Use xmlIsIdeographicQ instead + * + * Returns true if argument valid, false otherwise + */ +int +xmlIsIdeographic(unsigned int ch) { + return(xmlIsIdeographicQ(ch)); +} + + +/** + * xmlIsPubidChar: + * @ch: character to validate + * + * This function is DEPRECATED. + * Use xmlIsPubidChar_ch or xmlIsPubidCharQ instead + * + * Returns true if argument valid, false otherwise + */ +int +xmlIsPubidChar(unsigned int ch) { + return(xmlIsPubidCharQ(ch)); +} + +#define bottom_chvalid +#include "elfgcchack.h" diff --git a/android/native/libxml2/config.h b/android/native/libxml2/config.h new file mode 100644 index 0000000000..c05f865e23 --- /dev/null +++ b/android/native/libxml2/config.h @@ -0,0 +1,308 @@ +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.in by autoheader. */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_ANSIDECL_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_ARPA_INET_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ARPA_NAMESER_H 1 + +/* Whether struct sockaddr::__ss_family exists */ +/* #undef HAVE_BROKEN_SS_FAMILY */ + +/* Define to 1 if you have the `class' function. */ +/* #undef HAVE_CLASS */ + +/* Define to 1 if you have the header file. */ +#define HAVE_CTYPE_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_DIRENT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Have dlopen based dso */ +#define HAVE_DLOPEN /**/ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_DL_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_ERRNO_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have the `finite' function. */ +#define HAVE_FINITE 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_FLOAT_H 1 + +/* Define to 1 if you have the `fpclass' function. */ +/* #undef HAVE_FPCLASS */ + +/* Define to 1 if you have the `fprintf' function. */ +#define HAVE_FPRINTF 1 + +/* Define to 1 if you have the `fp_class' function. */ +/* #undef HAVE_FP_CLASS */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_FP_CLASS_H */ + +/* Define to 1 if you have the `ftime' function. */ +#define HAVE_FTIME 1 + +/* Define if getaddrinfo is there */ +/* #undef HAVE_GETADDRINFO */ + +/* Define to 1 if you have the `gettimeofday' function. */ +#define HAVE_GETTIMEOFDAY 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_IEEEFP_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_INTTYPES_H_H */ + +/* Define if isinf is there */ +#define HAVE_ISINF /**/ + +/* Define if isnan is there */ +#define HAVE_ISNAN /**/ + +/* Define to 1 if you have the `isnand' function. */ +/* #undef HAVE_ISNAND */ + +/* Define if history library is there (-lhistory) */ +/* #undef HAVE_LIBHISTORY */ + +/* Have compression library */ +/* #undef HAVE_LIBLZMA */ + +/* Define if pthread library is there (-lpthread) */ +/* #undef HAVE_LIBPTHREAD */ + +/* Define if readline library is there (-lreadline) */ +/* #undef HAVE_LIBREADLINE */ + +/* Have compression library */ +/* #undef HAVE_LIBZ */ + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define to 1 if you have the `localtime' function. */ +#define HAVE_LOCALTIME 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LZMA_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_MALLOC_H 1 Already defined in AndroidConfig.h */ + +/* Define to 1 if you have the header file. */ +#define HAVE_MATH_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NAN_H */ + +/* Define to 1 if you have the header file, and it defines `DIR'. */ +/* #undef HAVE_NDIR_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_NETDB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_IN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_POLL_H 1 + +/* Define to 1 if you have the `printf' function. */ +#define HAVE_PRINTF 1 + +/* Define if is there */ +/* #undef HAVE_PTHREAD_H */ + +/* Define to 1 if you have the `rand' function. */ +#define HAVE_RAND 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_RESOLV_H 1 + +/* Have shl_load based dso */ +/* #undef HAVE_SHLLOAD */ + +/* Define to 1 if you have the `signal' function. */ +#define HAVE_SIGNAL 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SIGNAL_H 1 + +/* Define to 1 if you have the `snprintf' function. */ +#define HAVE_SNPRINTF 1 + +/* Define to 1 if you have the `sprintf' function. */ +#define HAVE_SPRINTF 1 + +/* Define to 1 if you have the `srand' function. */ +#define HAVE_SRAND 1 + +/* Define to 1 if you have the `sscanf' function. */ +#define HAVE_SSCANF 1 + +/* Define to 1 if you have the `stat' function. */ +#define HAVE_STAT 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDARG_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the `strdup' function. */ +#define HAVE_STRDUP 1 + +/* Define to 1 if you have the `strerror' function. */ +#define HAVE_STRERROR 1 + +/* Define to 1 if you have the `strftime' function. */ +#define HAVE_STRFTIME 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the `strndup' function. */ +#define HAVE_STRNDUP 1 + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_DIR_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_MMAN_H 1 + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_NDIR_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SELECT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SOCKET_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIMEB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the `time' function. */ +#define HAVE_TIME 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Whether va_copy() is available */ +#define HAVE_VA_COPY 1 + +/* Define to 1 if you have the `vfprintf' function. */ +#define HAVE_VFPRINTF 1 + +/* Define to 1 if you have the `vsnprintf' function. */ +#define HAVE_VSNPRINTF 1 + +/* Define to 1 if you have the `vsprintf' function. */ +#define HAVE_VSPRINTF 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_ZLIB_H */ + +/* Define to 1 if you have the `_stat' function. */ +/* #undef HAVE__STAT */ + +/* Whether __va_copy() is available */ +/* #undef HAVE___VA_COPY */ + +/* Define as const if the declaration of iconv() needs const. */ +/* #undef ICONV_CONST */ + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#define LT_OBJDIR ".libs/" + +/* Name of package */ +#define PACKAGE "libxml2" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to 1 if the C compiler supports function prototypes. */ +#define PROTOTYPES 1 + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Support for IPv6 */ +/* #undef SUPPORT_IP6 */ + +/* Version number of package */ +#define VERSION "2.7.8" + +/* Determine what socket length (socklen_t) data type is */ +#define XML_SOCKLEN_T socklen_t + +/* Using the Win32 Socket implementation */ +/* #undef _WINSOCKAPI_ */ + +/* Define like PROTOTYPES; this can be used by system headers. */ +#define __PROTOTYPES 1 + +/* Win32 Std C name mangling work-around */ +/* #undef snprintf */ + +/* ss_family is not defined here, use __ss_family instead */ +/* #undef ss_family */ + +/* Win32 Std C name mangling work-around */ +/* #undef vsnprintf */ diff --git a/android/native/libxml2/debugXML.c b/android/native/libxml2/debugXML.c new file mode 100644 index 0000000000..a5283d2a76 --- /dev/null +++ b/android/native/libxml2/debugXML.c @@ -0,0 +1,3237 @@ +/* + * debugXML.c : This is a set of routines used for debugging the tree + * produced by the XML parser. + * + * See Copyright for the status of this software. + * + * Daniel Veillard + */ + +#define IN_LIBXML +#include "libxml.h" +#ifdef LIBXML_DEBUG_ENABLED + +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef LIBXML_SCHEMAS_ENABLED +#include +#endif + +#define DUMP_TEXT_TYPE 1 + +typedef struct _xmlDebugCtxt xmlDebugCtxt; +typedef xmlDebugCtxt *xmlDebugCtxtPtr; +struct _xmlDebugCtxt { + FILE *output; /* the output file */ + char shift[101]; /* used for indenting */ + int depth; /* current depth */ + xmlDocPtr doc; /* current document */ + xmlNodePtr node; /* current node */ + xmlDictPtr dict; /* the doc dictionnary */ + int check; /* do just checkings */ + int errors; /* number of errors found */ + int nodict; /* if the document has no dictionnary */ + int options; /* options */ +}; + +static void xmlCtxtDumpNodeList(xmlDebugCtxtPtr ctxt, xmlNodePtr node); + +static void +xmlCtxtDumpInitCtxt(xmlDebugCtxtPtr ctxt) +{ + int i; + + ctxt->depth = 0; + ctxt->check = 0; + ctxt->errors = 0; + ctxt->output = stdout; + ctxt->doc = NULL; + ctxt->node = NULL; + ctxt->dict = NULL; + ctxt->nodict = 0; + ctxt->options = 0; + for (i = 0; i < 100; i++) + ctxt->shift[i] = ' '; + ctxt->shift[100] = 0; +} + +static void +xmlCtxtDumpCleanCtxt(xmlDebugCtxtPtr ctxt ATTRIBUTE_UNUSED) +{ + /* remove the ATTRIBUTE_UNUSED when this is added */ +} + +/** + * xmlNsCheckScope: + * @node: the node + * @ns: the namespace node + * + * Check that a given namespace is in scope on a node. + * + * Returns 1 if in scope, -1 in case of argument error, + * -2 if the namespace is not in scope, and -3 if not on + * an ancestor node. + */ +static int +xmlNsCheckScope(xmlNodePtr node, xmlNsPtr ns) +{ + xmlNsPtr cur; + + if ((node == NULL) || (ns == NULL)) + return(-1); + + if ((node->type != XML_ELEMENT_NODE) && + (node->type != XML_ATTRIBUTE_NODE) && + (node->type != XML_DOCUMENT_NODE) && + (node->type != XML_TEXT_NODE) && + (node->type != XML_HTML_DOCUMENT_NODE) && + (node->type != XML_XINCLUDE_START)) + return(-2); + + while ((node != NULL) && + ((node->type == XML_ELEMENT_NODE) || + (node->type == XML_ATTRIBUTE_NODE) || + (node->type == XML_TEXT_NODE) || + (node->type == XML_XINCLUDE_START))) { + if ((node->type == XML_ELEMENT_NODE) || + (node->type == XML_XINCLUDE_START)) { + cur = node->nsDef; + while (cur != NULL) { + if (cur == ns) + return(1); + if (xmlStrEqual(cur->prefix, ns->prefix)) + return(-2); + cur = cur->next; + } + } + node = node->parent; + } + /* the xml namespace may be declared on the document node */ + if ((node != NULL) && + ((node->type == XML_DOCUMENT_NODE) || + (node->type == XML_HTML_DOCUMENT_NODE))) { + xmlNsPtr oldNs = ((xmlDocPtr) node)->oldNs; + if (oldNs == ns) + return(1); + } + return(-3); +} + +static void +xmlCtxtDumpSpaces(xmlDebugCtxtPtr ctxt) +{ + if (ctxt->check) + return; + if ((ctxt->output != NULL) && (ctxt->depth > 0)) { + if (ctxt->depth < 50) + fprintf(ctxt->output, "%s", &ctxt->shift[100 - 2 * ctxt->depth]); + else + fprintf(ctxt->output, "%s", ctxt->shift); + } +} + +/** + * xmlDebugErr: + * @ctxt: a debug context + * @error: the error code + * + * Handle a debug error. + */ +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); +} +static void +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); +} +static void +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); +} + +/** + * xmlCtxtNsCheckScope: + * @ctxt: the debugging context + * @node: the node + * @ns: the namespace node + * + * Report if a given namespace is is not in scope. + */ +static void +xmlCtxtNsCheckScope(xmlDebugCtxtPtr ctxt, xmlNodePtr node, xmlNsPtr ns) +{ + int ret; + + ret = xmlNsCheckScope(node, ns); + if (ret == -2) { + if (ns->prefix == NULL) + xmlDebugErr(ctxt, XML_CHECK_NS_SCOPE, + "Reference to default namespace not in scope\n"); + else + xmlDebugErr3(ctxt, XML_CHECK_NS_SCOPE, + "Reference to namespace '%s' not in scope\n", + (char *) ns->prefix); + } + if (ret == -3) { + if (ns->prefix == NULL) + xmlDebugErr(ctxt, XML_CHECK_NS_ANCESTOR, + "Reference to default namespace not on ancestor\n"); + else + xmlDebugErr3(ctxt, XML_CHECK_NS_ANCESTOR, + "Reference to namespace '%s' not on ancestor\n", + (char *) ns->prefix); + } +} + +/** + * xmlCtxtCheckString: + * @ctxt: the debug context + * @str: the string + * + * Do debugging on the string, currently it just checks the UTF-8 content + */ +static void +xmlCtxtCheckString(xmlDebugCtxtPtr ctxt, const xmlChar * str) +{ + if (str == NULL) return; + if (ctxt->check) { + if (!xmlCheckUTF8(str)) { + xmlDebugErr3(ctxt, XML_CHECK_NOT_UTF8, + "String is not UTF-8 %s", (const char *) str); + } + } +} + +/** + * xmlCtxtCheckName: + * @ctxt: the debug context + * @name: the name + * + * Do debugging on the name, for example the dictionnary status and + * conformance to the Name production. + */ +static void +xmlCtxtCheckName(xmlDebugCtxtPtr ctxt, const xmlChar * name) +{ + if (ctxt->check) { + if (name == NULL) { + xmlDebugErr(ctxt, XML_CHECK_NO_NAME, "Name is NULL"); + return; + } + if (xmlValidateName(name, 0)) { + xmlDebugErr3(ctxt, XML_CHECK_NOT_NCNAME, + "Name is not an NCName '%s'", (const char *) name); + } + if ((ctxt->dict != NULL) && + (!xmlDictOwns(ctxt->dict, name)) && + ((ctxt->doc == NULL) || + ((ctxt->doc->parseFlags & (XML_PARSE_SAX1 | XML_PARSE_NODICT)) == 0))) { + xmlDebugErr3(ctxt, XML_CHECK_OUTSIDE_DICT, + "Name is not from the document dictionnary '%s'", + (const char *) name); + } + } +} + +static void +xmlCtxtGenericNodeCheck(xmlDebugCtxtPtr ctxt, xmlNodePtr node) { + xmlDocPtr doc; + xmlDictPtr dict; + + doc = node->doc; + + if (node->parent == NULL) + xmlDebugErr(ctxt, XML_CHECK_NO_PARENT, + "Node has no parent\n"); + if (node->doc == NULL) { + xmlDebugErr(ctxt, XML_CHECK_NO_DOC, + "Node has no doc\n"); + dict = NULL; + } else { + dict = doc->dict; + if ((dict == NULL) && (ctxt->nodict == 0)) { +#if 0 + /* desactivated right now as it raises too many errors */ + if (doc->type == XML_DOCUMENT_NODE) + xmlDebugErr(ctxt, XML_CHECK_NO_DICT, + "Document has no dictionnary\n"); +#endif + ctxt->nodict = 1; + } + if (ctxt->doc == NULL) + ctxt->doc = doc; + + if (ctxt->dict == NULL) { + ctxt->dict = dict; + } + } + if ((node->parent != NULL) && (node->doc != node->parent->doc) && + (!xmlStrEqual(node->name, BAD_CAST "pseudoroot"))) + xmlDebugErr(ctxt, XML_CHECK_WRONG_DOC, + "Node doc differs from parent's one\n"); + if (node->prev == NULL) { + if (node->type == XML_ATTRIBUTE_NODE) { + if ((node->parent != NULL) && + (node != (xmlNodePtr) node->parent->properties)) + xmlDebugErr(ctxt, XML_CHECK_NO_PREV, + "Attr has no prev and not first of attr list\n"); + + } else if ((node->parent != NULL) && (node->parent->children != node)) + xmlDebugErr(ctxt, XML_CHECK_NO_PREV, + "Node has no prev and not first of parent list\n"); + } else { + if (node->prev->next != node) + xmlDebugErr(ctxt, XML_CHECK_WRONG_PREV, + "Node prev->next : back link wrong\n"); + } + if (node->next == NULL) { + if ((node->parent != NULL) && (node->type != XML_ATTRIBUTE_NODE) && + (node->parent->last != node) && + (node->parent->type == XML_ELEMENT_NODE)) + xmlDebugErr(ctxt, XML_CHECK_NO_NEXT, + "Node has no next and not last of parent list\n"); + } else { + if (node->next->prev != node) + xmlDebugErr(ctxt, XML_CHECK_WRONG_NEXT, + "Node next->prev : forward link wrong\n"); + if (node->next->parent != node->parent) + xmlDebugErr(ctxt, XML_CHECK_WRONG_PARENT, + "Node next->prev : forward link wrong\n"); + } + if (node->type == XML_ELEMENT_NODE) { + xmlNsPtr ns; + + ns = node->nsDef; + while (ns != NULL) { + xmlCtxtNsCheckScope(ctxt, node, ns); + ns = ns->next; + } + if (node->ns != NULL) + xmlCtxtNsCheckScope(ctxt, node, node->ns); + } else if (node->type == XML_ATTRIBUTE_NODE) { + if (node->ns != NULL) + xmlCtxtNsCheckScope(ctxt, node, node->ns); + } + + if ((node->type != XML_ELEMENT_NODE) && + (node->type != XML_ATTRIBUTE_NODE) && + (node->type != XML_ELEMENT_DECL) && + (node->type != XML_ATTRIBUTE_DECL) && + (node->type != XML_DTD_NODE) && + (node->type != XML_ELEMENT_DECL) && + (node->type != XML_HTML_DOCUMENT_NODE) && + (node->type != XML_DOCUMENT_NODE)) { + if (node->content != NULL) + xmlCtxtCheckString(ctxt, (const xmlChar *) node->content); + } + switch (node->type) { + case XML_ELEMENT_NODE: + case XML_ATTRIBUTE_NODE: + xmlCtxtCheckName(ctxt, node->name); + break; + case XML_TEXT_NODE: + if ((node->name == xmlStringText) || + (node->name == xmlStringTextNoenc)) + break; + /* some case of entity substitution can lead to this */ + if ((ctxt->dict != NULL) && + (node->name == xmlDictLookup(ctxt->dict, BAD_CAST "nbktext", + 7))) + break; + + xmlDebugErr3(ctxt, XML_CHECK_WRONG_NAME, + "Text node has wrong name '%s'", + (const char *) node->name); + break; + case XML_COMMENT_NODE: + if (node->name == xmlStringComment) + break; + xmlDebugErr3(ctxt, XML_CHECK_WRONG_NAME, + "Comment node has wrong name '%s'", + (const char *) node->name); + break; + case XML_PI_NODE: + xmlCtxtCheckName(ctxt, node->name); + break; + case XML_CDATA_SECTION_NODE: + if (node->name == NULL) + break; + xmlDebugErr3(ctxt, XML_CHECK_NAME_NOT_NULL, + "CData section has non NULL name '%s'", + (const char *) node->name); + break; + case XML_ENTITY_REF_NODE: + case XML_ENTITY_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_NAMESPACE_DECL: + case XML_XINCLUDE_START: + case XML_XINCLUDE_END: +#ifdef LIBXML_DOCB_ENABLED + case XML_DOCB_DOCUMENT_NODE: +#endif + case XML_DOCUMENT_NODE: + case XML_HTML_DOCUMENT_NODE: + break; + } +} + +static void +xmlCtxtDumpString(xmlDebugCtxtPtr ctxt, const xmlChar * str) +{ + int i; + + if (ctxt->check) { + return; + } + /* TODO: check UTF8 content of the string */ + if (str == NULL) { + fprintf(ctxt->output, "(NULL)"); + return; + } + for (i = 0; i < 40; i++) + if (str[i] == 0) + return; + else if (IS_BLANK_CH(str[i])) + fputc(' ', ctxt->output); + else if (str[i] >= 0x80) + fprintf(ctxt->output, "#%X", str[i]); + else + fputc(str[i], ctxt->output); + fprintf(ctxt->output, "..."); +} + +static void +xmlCtxtDumpDtdNode(xmlDebugCtxtPtr ctxt, xmlDtdPtr dtd) +{ + xmlCtxtDumpSpaces(ctxt); + + if (dtd == NULL) { + if (!ctxt->check) + fprintf(ctxt->output, "DTD node is NULL\n"); + return; + } + + if (dtd->type != XML_DTD_NODE) { + xmlDebugErr(ctxt, XML_CHECK_NOT_DTD, + "Node is not a DTD"); + return; + } + if (!ctxt->check) { + if (dtd->name != NULL) + fprintf(ctxt->output, "DTD(%s)", (char *) dtd->name); + else + fprintf(ctxt->output, "DTD"); + if (dtd->ExternalID != NULL) + fprintf(ctxt->output, ", PUBLIC %s", (char *) dtd->ExternalID); + if (dtd->SystemID != NULL) + fprintf(ctxt->output, ", SYSTEM %s", (char *) dtd->SystemID); + fprintf(ctxt->output, "\n"); + } + /* + * Do a bit of checking + */ + xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) dtd); +} + +static void +xmlCtxtDumpAttrDecl(xmlDebugCtxtPtr ctxt, xmlAttributePtr attr) +{ + xmlCtxtDumpSpaces(ctxt); + + if (attr == NULL) { + if (!ctxt->check) + fprintf(ctxt->output, "Attribute declaration is NULL\n"); + return; + } + if (attr->type != XML_ATTRIBUTE_DECL) { + xmlDebugErr(ctxt, XML_CHECK_NOT_ATTR_DECL, + "Node is not an attribute declaration"); + return; + } + if (attr->name != NULL) { + if (!ctxt->check) + fprintf(ctxt->output, "ATTRDECL(%s)", (char *) attr->name); + } else + xmlDebugErr(ctxt, XML_CHECK_NO_NAME, + "Node attribute declaration has no name"); + if (attr->elem != NULL) { + if (!ctxt->check) + fprintf(ctxt->output, " for %s", (char *) attr->elem); + } else + xmlDebugErr(ctxt, XML_CHECK_NO_ELEM, + "Node attribute declaration has no element name"); + if (!ctxt->check) { + switch (attr->atype) { + case XML_ATTRIBUTE_CDATA: + fprintf(ctxt->output, " CDATA"); + break; + case XML_ATTRIBUTE_ID: + fprintf(ctxt->output, " ID"); + break; + case XML_ATTRIBUTE_IDREF: + fprintf(ctxt->output, " IDREF"); + break; + case XML_ATTRIBUTE_IDREFS: + fprintf(ctxt->output, " IDREFS"); + break; + case XML_ATTRIBUTE_ENTITY: + fprintf(ctxt->output, " ENTITY"); + break; + case XML_ATTRIBUTE_ENTITIES: + fprintf(ctxt->output, " ENTITIES"); + break; + case XML_ATTRIBUTE_NMTOKEN: + fprintf(ctxt->output, " NMTOKEN"); + break; + case XML_ATTRIBUTE_NMTOKENS: + fprintf(ctxt->output, " NMTOKENS"); + break; + case XML_ATTRIBUTE_ENUMERATION: + fprintf(ctxt->output, " ENUMERATION"); + break; + case XML_ATTRIBUTE_NOTATION: + fprintf(ctxt->output, " NOTATION "); + break; + } + if (attr->tree != NULL) { + int indx; + xmlEnumerationPtr cur = attr->tree; + + for (indx = 0; indx < 5; indx++) { + if (indx != 0) + fprintf(ctxt->output, "|%s", (char *) cur->name); + else + fprintf(ctxt->output, " (%s", (char *) cur->name); + cur = cur->next; + if (cur == NULL) + break; + } + if (cur == NULL) + fprintf(ctxt->output, ")"); + else + fprintf(ctxt->output, "...)"); + } + switch (attr->def) { + case XML_ATTRIBUTE_NONE: + break; + case XML_ATTRIBUTE_REQUIRED: + fprintf(ctxt->output, " REQUIRED"); + break; + case XML_ATTRIBUTE_IMPLIED: + fprintf(ctxt->output, " IMPLIED"); + break; + case XML_ATTRIBUTE_FIXED: + fprintf(ctxt->output, " FIXED"); + break; + } + if (attr->defaultValue != NULL) { + fprintf(ctxt->output, "\""); + xmlCtxtDumpString(ctxt, attr->defaultValue); + fprintf(ctxt->output, "\""); + } + fprintf(ctxt->output, "\n"); + } + + /* + * Do a bit of checking + */ + xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) attr); +} + +static void +xmlCtxtDumpElemDecl(xmlDebugCtxtPtr ctxt, xmlElementPtr elem) +{ + xmlCtxtDumpSpaces(ctxt); + + if (elem == NULL) { + if (!ctxt->check) + fprintf(ctxt->output, "Element declaration is NULL\n"); + return; + } + if (elem->type != XML_ELEMENT_DECL) { + xmlDebugErr(ctxt, XML_CHECK_NOT_ELEM_DECL, + "Node is not an element declaration"); + return; + } + if (elem->name != NULL) { + if (!ctxt->check) { + fprintf(ctxt->output, "ELEMDECL("); + xmlCtxtDumpString(ctxt, elem->name); + fprintf(ctxt->output, ")"); + } + } else + xmlDebugErr(ctxt, XML_CHECK_NO_NAME, + "Element declaration has no name"); + if (!ctxt->check) { + switch (elem->etype) { + case XML_ELEMENT_TYPE_UNDEFINED: + fprintf(ctxt->output, ", UNDEFINED"); + break; + case XML_ELEMENT_TYPE_EMPTY: + fprintf(ctxt->output, ", EMPTY"); + break; + case XML_ELEMENT_TYPE_ANY: + fprintf(ctxt->output, ", ANY"); + break; + case XML_ELEMENT_TYPE_MIXED: + fprintf(ctxt->output, ", MIXED "); + break; + case XML_ELEMENT_TYPE_ELEMENT: + fprintf(ctxt->output, ", MIXED "); + break; + } + if ((elem->type != XML_ELEMENT_NODE) && (elem->content != NULL)) { + char buf[5001]; + + buf[0] = 0; + xmlSnprintfElementContent(buf, 5000, elem->content, 1); + buf[5000] = 0; + fprintf(ctxt->output, "%s", buf); + } + fprintf(ctxt->output, "\n"); + } + + /* + * Do a bit of checking + */ + xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) elem); +} + +static void +xmlCtxtDumpEntityDecl(xmlDebugCtxtPtr ctxt, xmlEntityPtr ent) +{ + xmlCtxtDumpSpaces(ctxt); + + if (ent == NULL) { + if (!ctxt->check) + fprintf(ctxt->output, "Entity declaration is NULL\n"); + return; + } + if (ent->type != XML_ENTITY_DECL) { + xmlDebugErr(ctxt, XML_CHECK_NOT_ENTITY_DECL, + "Node is not an entity declaration"); + return; + } + if (ent->name != NULL) { + if (!ctxt->check) { + fprintf(ctxt->output, "ENTITYDECL("); + xmlCtxtDumpString(ctxt, ent->name); + fprintf(ctxt->output, ")"); + } + } else + xmlDebugErr(ctxt, XML_CHECK_NO_NAME, + "Entity declaration has no name"); + if (!ctxt->check) { + switch (ent->etype) { + case XML_INTERNAL_GENERAL_ENTITY: + fprintf(ctxt->output, ", internal\n"); + break; + case XML_EXTERNAL_GENERAL_PARSED_ENTITY: + fprintf(ctxt->output, ", external parsed\n"); + break; + case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY: + fprintf(ctxt->output, ", unparsed\n"); + break; + case XML_INTERNAL_PARAMETER_ENTITY: + fprintf(ctxt->output, ", parameter\n"); + break; + case XML_EXTERNAL_PARAMETER_ENTITY: + fprintf(ctxt->output, ", external parameter\n"); + break; + case XML_INTERNAL_PREDEFINED_ENTITY: + fprintf(ctxt->output, ", predefined\n"); + break; + } + if (ent->ExternalID) { + xmlCtxtDumpSpaces(ctxt); + fprintf(ctxt->output, " ExternalID=%s\n", + (char *) ent->ExternalID); + } + if (ent->SystemID) { + xmlCtxtDumpSpaces(ctxt); + fprintf(ctxt->output, " SystemID=%s\n", + (char *) ent->SystemID); + } + if (ent->URI != NULL) { + xmlCtxtDumpSpaces(ctxt); + fprintf(ctxt->output, " URI=%s\n", (char *) ent->URI); + } + if (ent->content) { + xmlCtxtDumpSpaces(ctxt); + fprintf(ctxt->output, " content="); + xmlCtxtDumpString(ctxt, ent->content); + fprintf(ctxt->output, "\n"); + } + } + + /* + * Do a bit of checking + */ + xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) ent); +} + +static void +xmlCtxtDumpNamespace(xmlDebugCtxtPtr ctxt, xmlNsPtr ns) +{ + xmlCtxtDumpSpaces(ctxt); + + if (ns == NULL) { + if (!ctxt->check) + fprintf(ctxt->output, "namespace node is NULL\n"); + return; + } + if (ns->type != XML_NAMESPACE_DECL) { + xmlDebugErr(ctxt, XML_CHECK_NOT_NS_DECL, + "Node is not a namespace declaration"); + return; + } + if (ns->href == NULL) { + if (ns->prefix != NULL) + xmlDebugErr3(ctxt, XML_CHECK_NO_HREF, + "Incomplete namespace %s href=NULL\n", + (char *) ns->prefix); + else + xmlDebugErr(ctxt, XML_CHECK_NO_HREF, + "Incomplete default namespace href=NULL\n"); + } else { + if (!ctxt->check) { + if (ns->prefix != NULL) + fprintf(ctxt->output, "namespace %s href=", + (char *) ns->prefix); + else + fprintf(ctxt->output, "default namespace href="); + + xmlCtxtDumpString(ctxt, ns->href); + fprintf(ctxt->output, "\n"); + } + } +} + +static void +xmlCtxtDumpNamespaceList(xmlDebugCtxtPtr ctxt, xmlNsPtr ns) +{ + while (ns != NULL) { + xmlCtxtDumpNamespace(ctxt, ns); + ns = ns->next; + } +} + +static void +xmlCtxtDumpEntity(xmlDebugCtxtPtr ctxt, xmlEntityPtr ent) +{ + xmlCtxtDumpSpaces(ctxt); + + if (ent == NULL) { + if (!ctxt->check) + fprintf(ctxt->output, "Entity is NULL\n"); + return; + } + if (!ctxt->check) { + switch (ent->etype) { + case XML_INTERNAL_GENERAL_ENTITY: + fprintf(ctxt->output, "INTERNAL_GENERAL_ENTITY "); + break; + case XML_EXTERNAL_GENERAL_PARSED_ENTITY: + fprintf(ctxt->output, "EXTERNAL_GENERAL_PARSED_ENTITY "); + break; + case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY: + fprintf(ctxt->output, "EXTERNAL_GENERAL_UNPARSED_ENTITY "); + break; + case XML_INTERNAL_PARAMETER_ENTITY: + fprintf(ctxt->output, "INTERNAL_PARAMETER_ENTITY "); + break; + case XML_EXTERNAL_PARAMETER_ENTITY: + fprintf(ctxt->output, "EXTERNAL_PARAMETER_ENTITY "); + break; + default: + fprintf(ctxt->output, "ENTITY_%d ! ", (int) ent->etype); + } + fprintf(ctxt->output, "%s\n", ent->name); + if (ent->ExternalID) { + xmlCtxtDumpSpaces(ctxt); + fprintf(ctxt->output, "ExternalID=%s\n", + (char *) ent->ExternalID); + } + if (ent->SystemID) { + xmlCtxtDumpSpaces(ctxt); + fprintf(ctxt->output, "SystemID=%s\n", (char *) ent->SystemID); + } + if (ent->URI) { + xmlCtxtDumpSpaces(ctxt); + fprintf(ctxt->output, "URI=%s\n", (char *) ent->URI); + } + if (ent->content) { + xmlCtxtDumpSpaces(ctxt); + fprintf(ctxt->output, "content="); + xmlCtxtDumpString(ctxt, ent->content); + fprintf(ctxt->output, "\n"); + } + } +} + +/** + * xmlCtxtDumpAttr: + * @output: the FILE * for the output + * @attr: the attribute + * @depth: the indentation level. + * + * Dumps debug information for the attribute + */ +static void +xmlCtxtDumpAttr(xmlDebugCtxtPtr ctxt, xmlAttrPtr attr) +{ + xmlCtxtDumpSpaces(ctxt); + + if (attr == NULL) { + if (!ctxt->check) + fprintf(ctxt->output, "Attr is NULL"); + return; + } + if (!ctxt->check) { + fprintf(ctxt->output, "ATTRIBUTE "); + xmlCtxtDumpString(ctxt, attr->name); + fprintf(ctxt->output, "\n"); + if (attr->children != NULL) { + ctxt->depth++; + xmlCtxtDumpNodeList(ctxt, attr->children); + ctxt->depth--; + } + } + if (attr->name == NULL) + xmlDebugErr(ctxt, XML_CHECK_NO_NAME, + "Attribute has no name"); + + /* + * Do a bit of checking + */ + xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) attr); +} + +/** + * xmlCtxtDumpAttrList: + * @output: the FILE * for the output + * @attr: the attribute list + * @depth: the indentation level. + * + * Dumps debug information for the attribute list + */ +static void +xmlCtxtDumpAttrList(xmlDebugCtxtPtr ctxt, xmlAttrPtr attr) +{ + while (attr != NULL) { + xmlCtxtDumpAttr(ctxt, attr); + attr = attr->next; + } +} + +/** + * xmlCtxtDumpOneNode: + * @output: the FILE * for the output + * @node: the node + * @depth: the indentation level. + * + * Dumps debug information for the element node, it is not recursive + */ +static void +xmlCtxtDumpOneNode(xmlDebugCtxtPtr ctxt, xmlNodePtr node) +{ + if (node == NULL) { + if (!ctxt->check) { + xmlCtxtDumpSpaces(ctxt); + fprintf(ctxt->output, "node is NULL\n"); + } + return; + } + ctxt->node = node; + + switch (node->type) { + case XML_ELEMENT_NODE: + if (!ctxt->check) { + xmlCtxtDumpSpaces(ctxt); + fprintf(ctxt->output, "ELEMENT "); + if ((node->ns != NULL) && (node->ns->prefix != NULL)) { + xmlCtxtDumpString(ctxt, node->ns->prefix); + fprintf(ctxt->output, ":"); + } + xmlCtxtDumpString(ctxt, node->name); + fprintf(ctxt->output, "\n"); + } + break; + case XML_ATTRIBUTE_NODE: + if (!ctxt->check) + xmlCtxtDumpSpaces(ctxt); + fprintf(ctxt->output, "Error, ATTRIBUTE found here\n"); + xmlCtxtGenericNodeCheck(ctxt, node); + return; + case XML_TEXT_NODE: + if (!ctxt->check) { + xmlCtxtDumpSpaces(ctxt); + if (node->name == (const xmlChar *) xmlStringTextNoenc) + fprintf(ctxt->output, "TEXT no enc"); + else + fprintf(ctxt->output, "TEXT"); + if (ctxt->options & DUMP_TEXT_TYPE) { + if (node->content == (xmlChar *) &(node->properties)) + fprintf(ctxt->output, " compact\n"); + else if (xmlDictOwns(ctxt->dict, node->content) == 1) + fprintf(ctxt->output, " interned\n"); + else + fprintf(ctxt->output, "\n"); + } else + fprintf(ctxt->output, "\n"); + } + break; + case XML_CDATA_SECTION_NODE: + if (!ctxt->check) { + xmlCtxtDumpSpaces(ctxt); + fprintf(ctxt->output, "CDATA_SECTION\n"); + } + break; + case XML_ENTITY_REF_NODE: + if (!ctxt->check) { + xmlCtxtDumpSpaces(ctxt); + fprintf(ctxt->output, "ENTITY_REF(%s)\n", + (char *) node->name); + } + break; + case XML_ENTITY_NODE: + if (!ctxt->check) { + xmlCtxtDumpSpaces(ctxt); + fprintf(ctxt->output, "ENTITY\n"); + } + break; + case XML_PI_NODE: + if (!ctxt->check) { + xmlCtxtDumpSpaces(ctxt); + fprintf(ctxt->output, "PI %s\n", (char *) node->name); + } + break; + case XML_COMMENT_NODE: + if (!ctxt->check) { + xmlCtxtDumpSpaces(ctxt); + fprintf(ctxt->output, "COMMENT\n"); + } + break; + case XML_DOCUMENT_NODE: + case XML_HTML_DOCUMENT_NODE: + if (!ctxt->check) { + xmlCtxtDumpSpaces(ctxt); + } + fprintf(ctxt->output, "Error, DOCUMENT found here\n"); + xmlCtxtGenericNodeCheck(ctxt, node); + return; + case XML_DOCUMENT_TYPE_NODE: + if (!ctxt->check) { + xmlCtxtDumpSpaces(ctxt); + fprintf(ctxt->output, "DOCUMENT_TYPE\n"); + } + break; + case XML_DOCUMENT_FRAG_NODE: + if (!ctxt->check) { + xmlCtxtDumpSpaces(ctxt); + fprintf(ctxt->output, "DOCUMENT_FRAG\n"); + } + break; + case XML_NOTATION_NODE: + if (!ctxt->check) { + xmlCtxtDumpSpaces(ctxt); + fprintf(ctxt->output, "NOTATION\n"); + } + break; + case XML_DTD_NODE: + xmlCtxtDumpDtdNode(ctxt, (xmlDtdPtr) node); + return; + case XML_ELEMENT_DECL: + xmlCtxtDumpElemDecl(ctxt, (xmlElementPtr) node); + return; + case XML_ATTRIBUTE_DECL: + xmlCtxtDumpAttrDecl(ctxt, (xmlAttributePtr) node); + return; + case XML_ENTITY_DECL: + xmlCtxtDumpEntityDecl(ctxt, (xmlEntityPtr) node); + return; + case XML_NAMESPACE_DECL: + xmlCtxtDumpNamespace(ctxt, (xmlNsPtr) node); + return; + case XML_XINCLUDE_START: + if (!ctxt->check) { + xmlCtxtDumpSpaces(ctxt); + fprintf(ctxt->output, "INCLUDE START\n"); + } + return; + case XML_XINCLUDE_END: + if (!ctxt->check) { + xmlCtxtDumpSpaces(ctxt); + fprintf(ctxt->output, "INCLUDE END\n"); + } + return; + default: + if (!ctxt->check) + xmlCtxtDumpSpaces(ctxt); + xmlDebugErr2(ctxt, XML_CHECK_UNKNOWN_NODE, + "Unknown node type %d\n", node->type); + return; + } + if (node->doc == NULL) { + if (!ctxt->check) { + xmlCtxtDumpSpaces(ctxt); + } + fprintf(ctxt->output, "PBM: doc == NULL !!!\n"); + } + ctxt->depth++; + if ((node->type == XML_ELEMENT_NODE) && (node->nsDef != NULL)) + xmlCtxtDumpNamespaceList(ctxt, node->nsDef); + if ((node->type == XML_ELEMENT_NODE) && (node->properties != NULL)) + xmlCtxtDumpAttrList(ctxt, node->properties); + if (node->type != XML_ENTITY_REF_NODE) { + if ((node->type != XML_ELEMENT_NODE) && (node->content != NULL)) { + if (!ctxt->check) { + xmlCtxtDumpSpaces(ctxt); + fprintf(ctxt->output, "content="); + xmlCtxtDumpString(ctxt, node->content); + fprintf(ctxt->output, "\n"); + } + } + } else { + xmlEntityPtr ent; + + ent = xmlGetDocEntity(node->doc, node->name); + if (ent != NULL) + xmlCtxtDumpEntity(ctxt, ent); + } + ctxt->depth--; + + /* + * Do a bit of checking + */ + xmlCtxtGenericNodeCheck(ctxt, node); +} + +/** + * xmlCtxtDumpNode: + * @output: the FILE * for the output + * @node: the node + * @depth: the indentation level. + * + * Dumps debug information for the element node, it is recursive + */ +static void +xmlCtxtDumpNode(xmlDebugCtxtPtr ctxt, xmlNodePtr node) +{ + if (node == NULL) { + if (!ctxt->check) { + xmlCtxtDumpSpaces(ctxt); + fprintf(ctxt->output, "node is NULL\n"); + } + return; + } + xmlCtxtDumpOneNode(ctxt, node); + if ((node->type != XML_NAMESPACE_DECL) && + (node->children != NULL) && (node->type != XML_ENTITY_REF_NODE)) { + ctxt->depth++; + xmlCtxtDumpNodeList(ctxt, node->children); + ctxt->depth--; + } +} + +/** + * xmlCtxtDumpNodeList: + * @output: the FILE * for the output + * @node: the node list + * @depth: the indentation level. + * + * Dumps debug information for the list of element node, it is recursive + */ +static void +xmlCtxtDumpNodeList(xmlDebugCtxtPtr ctxt, xmlNodePtr node) +{ + while (node != NULL) { + xmlCtxtDumpNode(ctxt, node); + node = node->next; + } +} + +static void +xmlCtxtDumpDocHead(xmlDebugCtxtPtr ctxt, xmlDocPtr doc) +{ + if (doc == NULL) { + if (!ctxt->check) + fprintf(ctxt->output, "DOCUMENT == NULL !\n"); + return; + } + ctxt->node = (xmlNodePtr) doc; + + switch (doc->type) { + case XML_ELEMENT_NODE: + xmlDebugErr(ctxt, XML_CHECK_FOUND_ELEMENT, + "Misplaced ELEMENT node\n"); + break; + case XML_ATTRIBUTE_NODE: + xmlDebugErr(ctxt, XML_CHECK_FOUND_ATTRIBUTE, + "Misplaced ATTRIBUTE node\n"); + break; + case XML_TEXT_NODE: + xmlDebugErr(ctxt, XML_CHECK_FOUND_TEXT, + "Misplaced TEXT node\n"); + break; + case XML_CDATA_SECTION_NODE: + xmlDebugErr(ctxt, XML_CHECK_FOUND_CDATA, + "Misplaced CDATA node\n"); + break; + case XML_ENTITY_REF_NODE: + xmlDebugErr(ctxt, XML_CHECK_FOUND_ENTITYREF, + "Misplaced ENTITYREF node\n"); + break; + case XML_ENTITY_NODE: + xmlDebugErr(ctxt, XML_CHECK_FOUND_ENTITY, + "Misplaced ENTITY node\n"); + break; + case XML_PI_NODE: + xmlDebugErr(ctxt, XML_CHECK_FOUND_PI, + "Misplaced PI node\n"); + break; + case XML_COMMENT_NODE: + xmlDebugErr(ctxt, XML_CHECK_FOUND_COMMENT, + "Misplaced COMMENT node\n"); + break; + case XML_DOCUMENT_NODE: + if (!ctxt->check) + fprintf(ctxt->output, "DOCUMENT\n"); + break; + case XML_HTML_DOCUMENT_NODE: + if (!ctxt->check) + fprintf(ctxt->output, "HTML DOCUMENT\n"); + break; + case XML_DOCUMENT_TYPE_NODE: + xmlDebugErr(ctxt, XML_CHECK_FOUND_DOCTYPE, + "Misplaced DOCTYPE node\n"); + break; + case XML_DOCUMENT_FRAG_NODE: + xmlDebugErr(ctxt, XML_CHECK_FOUND_FRAGMENT, + "Misplaced FRAGMENT node\n"); + break; + case XML_NOTATION_NODE: + xmlDebugErr(ctxt, XML_CHECK_FOUND_NOTATION, + "Misplaced NOTATION node\n"); + break; + default: + xmlDebugErr2(ctxt, XML_CHECK_UNKNOWN_NODE, + "Unknown node type %d\n", doc->type); + } +} + +/** + * xmlCtxtDumpDocumentHead: + * @output: the FILE * for the output + * @doc: the document + * + * Dumps debug information cncerning the document, not recursive + */ +static void +xmlCtxtDumpDocumentHead(xmlDebugCtxtPtr ctxt, xmlDocPtr doc) +{ + if (doc == NULL) return; + xmlCtxtDumpDocHead(ctxt, doc); + if (!ctxt->check) { + if (doc->name != NULL) { + fprintf(ctxt->output, "name="); + xmlCtxtDumpString(ctxt, BAD_CAST doc->name); + fprintf(ctxt->output, "\n"); + } + if (doc->version != NULL) { + fprintf(ctxt->output, "version="); + xmlCtxtDumpString(ctxt, doc->version); + fprintf(ctxt->output, "\n"); + } + if (doc->encoding != NULL) { + fprintf(ctxt->output, "encoding="); + xmlCtxtDumpString(ctxt, doc->encoding); + fprintf(ctxt->output, "\n"); + } + if (doc->URL != NULL) { + fprintf(ctxt->output, "URL="); + xmlCtxtDumpString(ctxt, doc->URL); + fprintf(ctxt->output, "\n"); + } + if (doc->standalone) + fprintf(ctxt->output, "standalone=true\n"); + } + if (doc->oldNs != NULL) + xmlCtxtDumpNamespaceList(ctxt, doc->oldNs); +} + +/** + * xmlCtxtDumpDocument: + * @output: the FILE * for the output + * @doc: the document + * + * Dumps debug information for the document, it's recursive + */ +static void +xmlCtxtDumpDocument(xmlDebugCtxtPtr ctxt, xmlDocPtr doc) +{ + if (doc == NULL) { + if (!ctxt->check) + fprintf(ctxt->output, "DOCUMENT == NULL !\n"); + return; + } + xmlCtxtDumpDocumentHead(ctxt, doc); + if (((doc->type == XML_DOCUMENT_NODE) || + (doc->type == XML_HTML_DOCUMENT_NODE)) + && (doc->children != NULL)) { + ctxt->depth++; + xmlCtxtDumpNodeList(ctxt, doc->children); + ctxt->depth--; + } +} + +static void +xmlCtxtDumpEntityCallback(xmlEntityPtr cur, xmlDebugCtxtPtr ctxt) +{ + if (cur == NULL) { + if (!ctxt->check) + fprintf(ctxt->output, "Entity is NULL"); + return; + } + if (!ctxt->check) { + fprintf(ctxt->output, "%s : ", (char *) cur->name); + switch (cur->etype) { + case XML_INTERNAL_GENERAL_ENTITY: + fprintf(ctxt->output, "INTERNAL GENERAL, "); + break; + case XML_EXTERNAL_GENERAL_PARSED_ENTITY: + fprintf(ctxt->output, "EXTERNAL PARSED, "); + break; + case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY: + fprintf(ctxt->output, "EXTERNAL UNPARSED, "); + break; + case XML_INTERNAL_PARAMETER_ENTITY: + fprintf(ctxt->output, "INTERNAL PARAMETER, "); + break; + case XML_EXTERNAL_PARAMETER_ENTITY: + fprintf(ctxt->output, "EXTERNAL PARAMETER, "); + break; + default: + xmlDebugErr2(ctxt, XML_CHECK_ENTITY_TYPE, + "Unknown entity type %d\n", cur->etype); + } + if (cur->ExternalID != NULL) + fprintf(ctxt->output, "ID \"%s\"", (char *) cur->ExternalID); + if (cur->SystemID != NULL) + fprintf(ctxt->output, "SYSTEM \"%s\"", (char *) cur->SystemID); + if (cur->orig != NULL) + fprintf(ctxt->output, "\n orig \"%s\"", (char *) cur->orig); + if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) + fprintf(ctxt->output, "\n content \"%s\"", + (char *) cur->content); + fprintf(ctxt->output, "\n"); + } +} + +/** + * xmlCtxtDumpEntities: + * @output: the FILE * for the output + * @doc: the document + * + * Dumps debug information for all the entities in use by the document + */ +static void +xmlCtxtDumpEntities(xmlDebugCtxtPtr ctxt, xmlDocPtr doc) +{ + if (doc == NULL) return; + xmlCtxtDumpDocHead(ctxt, doc); + if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) { + xmlEntitiesTablePtr table = (xmlEntitiesTablePtr) + doc->intSubset->entities; + + if (!ctxt->check) + fprintf(ctxt->output, "Entities in internal subset\n"); + xmlHashScan(table, (xmlHashScanner) xmlCtxtDumpEntityCallback, + ctxt); + } else + fprintf(ctxt->output, "No entities in internal subset\n"); + if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) { + xmlEntitiesTablePtr table = (xmlEntitiesTablePtr) + doc->extSubset->entities; + + if (!ctxt->check) + fprintf(ctxt->output, "Entities in external subset\n"); + xmlHashScan(table, (xmlHashScanner) xmlCtxtDumpEntityCallback, + ctxt); + } else if (!ctxt->check) + fprintf(ctxt->output, "No entities in external subset\n"); +} + +/** + * xmlCtxtDumpDTD: + * @output: the FILE * for the output + * @dtd: the DTD + * + * Dumps debug information for the DTD + */ +static void +xmlCtxtDumpDTD(xmlDebugCtxtPtr ctxt, xmlDtdPtr dtd) +{ + if (dtd == NULL) { + if (!ctxt->check) + fprintf(ctxt->output, "DTD is NULL\n"); + return; + } + xmlCtxtDumpDtdNode(ctxt, dtd); + if (dtd->children == NULL) + fprintf(ctxt->output, " DTD is empty\n"); + else { + ctxt->depth++; + xmlCtxtDumpNodeList(ctxt, dtd->children); + ctxt->depth--; + } +} + +/************************************************************************ + * * + * Public entry points for dump * + * * + ************************************************************************/ + +/** + * xmlDebugDumpString: + * @output: the FILE * for the output + * @str: the string + * + * Dumps informations about the string, shorten it if necessary + */ +void +xmlDebugDumpString(FILE * output, const xmlChar * str) +{ + int i; + + if (output == NULL) + output = stdout; + if (str == NULL) { + fprintf(output, "(NULL)"); + return; + } + for (i = 0; i < 40; i++) + if (str[i] == 0) + return; + else if (IS_BLANK_CH(str[i])) + fputc(' ', output); + else if (str[i] >= 0x80) + fprintf(output, "#%X", str[i]); + else + fputc(str[i], output); + fprintf(output, "..."); +} + +/** + * xmlDebugDumpAttr: + * @output: the FILE * for the output + * @attr: the attribute + * @depth: the indentation level. + * + * Dumps debug information for the attribute + */ +void +xmlDebugDumpAttr(FILE *output, xmlAttrPtr attr, int depth) { + xmlDebugCtxt ctxt; + + if (output == NULL) return; + xmlCtxtDumpInitCtxt(&ctxt); + ctxt.output = output; + ctxt.depth = depth; + xmlCtxtDumpAttr(&ctxt, attr); + xmlCtxtDumpCleanCtxt(&ctxt); +} + + +/** + * xmlDebugDumpEntities: + * @output: the FILE * for the output + * @doc: the document + * + * Dumps debug information for all the entities in use by the document + */ +void +xmlDebugDumpEntities(FILE * output, xmlDocPtr doc) +{ + xmlDebugCtxt ctxt; + + if (output == NULL) return; + xmlCtxtDumpInitCtxt(&ctxt); + ctxt.output = output; + xmlCtxtDumpEntities(&ctxt, doc); + xmlCtxtDumpCleanCtxt(&ctxt); +} + +/** + * xmlDebugDumpAttrList: + * @output: the FILE * for the output + * @attr: the attribute list + * @depth: the indentation level. + * + * Dumps debug information for the attribute list + */ +void +xmlDebugDumpAttrList(FILE * output, xmlAttrPtr attr, int depth) +{ + xmlDebugCtxt ctxt; + + if (output == NULL) return; + xmlCtxtDumpInitCtxt(&ctxt); + ctxt.output = output; + ctxt.depth = depth; + xmlCtxtDumpAttrList(&ctxt, attr); + xmlCtxtDumpCleanCtxt(&ctxt); +} + +/** + * xmlDebugDumpOneNode: + * @output: the FILE * for the output + * @node: the node + * @depth: the indentation level. + * + * Dumps debug information for the element node, it is not recursive + */ +void +xmlDebugDumpOneNode(FILE * output, xmlNodePtr node, int depth) +{ + xmlDebugCtxt ctxt; + + if (output == NULL) return; + xmlCtxtDumpInitCtxt(&ctxt); + ctxt.output = output; + ctxt.depth = depth; + xmlCtxtDumpOneNode(&ctxt, node); + xmlCtxtDumpCleanCtxt(&ctxt); +} + +/** + * xmlDebugDumpNode: + * @output: the FILE * for the output + * @node: the node + * @depth: the indentation level. + * + * Dumps debug information for the element node, it is recursive + */ +void +xmlDebugDumpNode(FILE * output, xmlNodePtr node, int depth) +{ + xmlDebugCtxt ctxt; + + if (output == NULL) + output = stdout; + xmlCtxtDumpInitCtxt(&ctxt); + ctxt.output = output; + ctxt.depth = depth; + xmlCtxtDumpNode(&ctxt, node); + xmlCtxtDumpCleanCtxt(&ctxt); +} + +/** + * xmlDebugDumpNodeList: + * @output: the FILE * for the output + * @node: the node list + * @depth: the indentation level. + * + * Dumps debug information for the list of element node, it is recursive + */ +void +xmlDebugDumpNodeList(FILE * output, xmlNodePtr node, int depth) +{ + xmlDebugCtxt ctxt; + + if (output == NULL) + output = stdout; + xmlCtxtDumpInitCtxt(&ctxt); + ctxt.output = output; + ctxt.depth = depth; + xmlCtxtDumpNodeList(&ctxt, node); + xmlCtxtDumpCleanCtxt(&ctxt); +} + +/** + * xmlDebugDumpDocumentHead: + * @output: the FILE * for the output + * @doc: the document + * + * Dumps debug information cncerning the document, not recursive + */ +void +xmlDebugDumpDocumentHead(FILE * output, xmlDocPtr doc) +{ + xmlDebugCtxt ctxt; + + if (output == NULL) + output = stdout; + xmlCtxtDumpInitCtxt(&ctxt); + ctxt.options |= DUMP_TEXT_TYPE; + ctxt.output = output; + xmlCtxtDumpDocumentHead(&ctxt, doc); + xmlCtxtDumpCleanCtxt(&ctxt); +} + +/** + * xmlDebugDumpDocument: + * @output: the FILE * for the output + * @doc: the document + * + * Dumps debug information for the document, it's recursive + */ +void +xmlDebugDumpDocument(FILE * output, xmlDocPtr doc) +{ + xmlDebugCtxt ctxt; + + if (output == NULL) + output = stdout; + xmlCtxtDumpInitCtxt(&ctxt); + ctxt.options |= DUMP_TEXT_TYPE; + ctxt.output = output; + xmlCtxtDumpDocument(&ctxt, doc); + xmlCtxtDumpCleanCtxt(&ctxt); +} + +/** + * xmlDebugDumpDTD: + * @output: the FILE * for the output + * @dtd: the DTD + * + * Dumps debug information for the DTD + */ +void +xmlDebugDumpDTD(FILE * output, xmlDtdPtr dtd) +{ + xmlDebugCtxt ctxt; + + if (output == NULL) + output = stdout; + xmlCtxtDumpInitCtxt(&ctxt); + ctxt.options |= DUMP_TEXT_TYPE; + ctxt.output = output; + xmlCtxtDumpDTD(&ctxt, dtd); + xmlCtxtDumpCleanCtxt(&ctxt); +} + +/************************************************************************ + * * + * Public entry points for checkings * + * * + ************************************************************************/ + +/** + * xmlDebugCheckDocument: + * @output: the FILE * for the output + * @doc: the document + * + * Check the document for potential content problems, and output + * the errors to @output + * + * Returns the number of errors found + */ +int +xmlDebugCheckDocument(FILE * output, xmlDocPtr doc) +{ + xmlDebugCtxt ctxt; + + if (output == NULL) + output = stdout; + xmlCtxtDumpInitCtxt(&ctxt); + ctxt.output = output; + ctxt.check = 1; + xmlCtxtDumpDocument(&ctxt, doc); + xmlCtxtDumpCleanCtxt(&ctxt); + return(ctxt.errors); +} + +/************************************************************************ + * * + * Helpers for Shell * + * * + ************************************************************************/ + +/** + * xmlLsCountNode: + * @node: the node to count + * + * Count the children of @node. + * + * Returns the number of children of @node. + */ +int +xmlLsCountNode(xmlNodePtr node) { + int ret = 0; + xmlNodePtr list = NULL; + + if (node == NULL) + return(0); + + switch (node->type) { + case XML_ELEMENT_NODE: + list = node->children; + break; + case XML_DOCUMENT_NODE: + case XML_HTML_DOCUMENT_NODE: +#ifdef LIBXML_DOCB_ENABLED + case XML_DOCB_DOCUMENT_NODE: +#endif + list = ((xmlDocPtr) node)->children; + break; + case XML_ATTRIBUTE_NODE: + list = ((xmlAttrPtr) node)->children; + break; + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: + case XML_PI_NODE: + case XML_COMMENT_NODE: + if (node->content != NULL) { + ret = xmlStrlen(node->content); + } + break; + case XML_ENTITY_REF_NODE: + case XML_DOCUMENT_TYPE_NODE: + case XML_ENTITY_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_NAMESPACE_DECL: + case XML_XINCLUDE_START: + case XML_XINCLUDE_END: + ret = 1; + break; + } + for (;list != NULL;ret++) + list = list->next; + return(ret); +} + +/** + * xmlLsOneNode: + * @output: the FILE * for the output + * @node: the node to dump + * + * Dump to @output the type and name of @node. + */ +void +xmlLsOneNode(FILE *output, xmlNodePtr node) { + if (output == NULL) return; + if (node == NULL) { + fprintf(output, "NULL\n"); + return; + } + switch (node->type) { + case XML_ELEMENT_NODE: + fprintf(output, "-"); + break; + case XML_ATTRIBUTE_NODE: + fprintf(output, "a"); + break; + case XML_TEXT_NODE: + fprintf(output, "t"); + break; + case XML_CDATA_SECTION_NODE: + fprintf(output, "C"); + break; + case XML_ENTITY_REF_NODE: + fprintf(output, "e"); + break; + case XML_ENTITY_NODE: + fprintf(output, "E"); + break; + case XML_PI_NODE: + fprintf(output, "p"); + break; + case XML_COMMENT_NODE: + fprintf(output, "c"); + break; + case XML_DOCUMENT_NODE: + fprintf(output, "d"); + break; + case XML_HTML_DOCUMENT_NODE: + fprintf(output, "h"); + break; + case XML_DOCUMENT_TYPE_NODE: + fprintf(output, "T"); + break; + case XML_DOCUMENT_FRAG_NODE: + fprintf(output, "F"); + break; + case XML_NOTATION_NODE: + fprintf(output, "N"); + break; + case XML_NAMESPACE_DECL: + fprintf(output, "n"); + break; + default: + fprintf(output, "?"); + } + if (node->type != XML_NAMESPACE_DECL) { + if (node->properties != NULL) + fprintf(output, "a"); + else + fprintf(output, "-"); + if (node->nsDef != NULL) + fprintf(output, "n"); + else + fprintf(output, "-"); + } + + fprintf(output, " %8d ", xmlLsCountNode(node)); + + switch (node->type) { + case XML_ELEMENT_NODE: + if (node->name != NULL) + fprintf(output, "%s", (const char *) node->name); + break; + case XML_ATTRIBUTE_NODE: + if (node->name != NULL) + fprintf(output, "%s", (const char *) node->name); + break; + case XML_TEXT_NODE: + if (node->content != NULL) { + xmlDebugDumpString(output, node->content); + } + break; + case XML_CDATA_SECTION_NODE: + break; + case XML_ENTITY_REF_NODE: + if (node->name != NULL) + fprintf(output, "%s", (const char *) node->name); + break; + case XML_ENTITY_NODE: + if (node->name != NULL) + fprintf(output, "%s", (const char *) node->name); + break; + case XML_PI_NODE: + if (node->name != NULL) + fprintf(output, "%s", (const char *) node->name); + break; + case XML_COMMENT_NODE: + break; + case XML_DOCUMENT_NODE: + break; + case XML_HTML_DOCUMENT_NODE: + break; + case XML_DOCUMENT_TYPE_NODE: + break; + case XML_DOCUMENT_FRAG_NODE: + break; + case XML_NOTATION_NODE: + break; + case XML_NAMESPACE_DECL: { + xmlNsPtr ns = (xmlNsPtr) node; + + if (ns->prefix == NULL) + fprintf(output, "default -> %s", (char *)ns->href); + else + fprintf(output, "%s -> %s", (char *)ns->prefix, + (char *)ns->href); + break; + } + default: + if (node->name != NULL) + fprintf(output, "%s", (const char *) node->name); + } + fprintf(output, "\n"); +} + +/** + * xmlBoolToText: + * @boolval: a bool to turn into text + * + * Convenient way to turn bool into text + * + * Returns a pointer to either "True" or "False" + */ +const char * +xmlBoolToText(int boolval) +{ + if (boolval) + return("True"); + else + return("False"); +} + +#ifdef LIBXML_XPATH_ENABLED +/**************************************************************** + * * + * The XML shell related functions * + * * + ****************************************************************/ + + + +/* + * TODO: Improvement/cleanups for the XML shell + * - allow to shell out an editor on a subpart + * - cleanup function registrations (with help) and calling + * - provide registration routines + */ + +/** + * xmlShellPrintXPathError: + * @errorType: valid xpath error id + * @arg: the argument that cause xpath to fail + * + * Print the xpath error to libxml default error channel + */ +void +xmlShellPrintXPathError(int errorType, const char *arg) +{ + const char *default_arg = "Result"; + + if (!arg) + arg = default_arg; + + switch (errorType) { + case XPATH_UNDEFINED: + xmlGenericError(xmlGenericErrorContext, + "%s: no such node\n", arg); + break; + + case XPATH_BOOLEAN: + xmlGenericError(xmlGenericErrorContext, + "%s is a Boolean\n", arg); + break; + case XPATH_NUMBER: + xmlGenericError(xmlGenericErrorContext, + "%s is a number\n", arg); + break; + case XPATH_STRING: + xmlGenericError(xmlGenericErrorContext, + "%s is a string\n", arg); + break; + case XPATH_POINT: + xmlGenericError(xmlGenericErrorContext, + "%s is a point\n", arg); + break; + case XPATH_RANGE: + xmlGenericError(xmlGenericErrorContext, + "%s is a range\n", arg); + break; + case XPATH_LOCATIONSET: + xmlGenericError(xmlGenericErrorContext, + "%s is a range\n", arg); + break; + case XPATH_USERS: + xmlGenericError(xmlGenericErrorContext, + "%s is user-defined\n", arg); + break; + case XPATH_XSLT_TREE: + xmlGenericError(xmlGenericErrorContext, + "%s is an XSLT value tree\n", arg); + break; + } +#if 0 + xmlGenericError(xmlGenericErrorContext, + "Try casting the result string function (xpath builtin)\n", + arg); +#endif +} + + +#ifdef LIBXML_OUTPUT_ENABLED +/** + * xmlShellPrintNodeCtxt: + * @ctxt : a non-null shell context + * @node : a non-null node to print to the output FILE + * + * Print node to the output FILE + */ +static void +xmlShellPrintNodeCtxt(xmlShellCtxtPtr ctxt,xmlNodePtr node) +{ + FILE *fp; + + if (!node) + return; + if (ctxt == NULL) + fp = stdout; + else + fp = ctxt->output; + + if (node->type == XML_DOCUMENT_NODE) + xmlDocDump(fp, (xmlDocPtr) node); + else if (node->type == XML_ATTRIBUTE_NODE) + xmlDebugDumpAttrList(fp, (xmlAttrPtr) node, 0); + else + xmlElemDump(fp, node->doc, node); + + fprintf(fp, "\n"); +} + +/** + * xmlShellPrintNode: + * @node : a non-null node to print to the output FILE + * + * Print node to the output FILE + */ +void +xmlShellPrintNode(xmlNodePtr node) +{ + xmlShellPrintNodeCtxt(NULL, node); +} +#endif /* LIBXML_OUTPUT_ENABLED */ + +/** + * xmlShellPrintXPathResultCtxt: + * @ctxt: a valid shell context + * @list: a valid result generated by an xpath evaluation + * + * Prints result to the output FILE + */ +static void +xmlShellPrintXPathResultCtxt(xmlShellCtxtPtr ctxt,xmlXPathObjectPtr list) +{ + if (!ctxt) + return; + + if (list != NULL) { + switch (list->type) { + case XPATH_NODESET:{ +#ifdef LIBXML_OUTPUT_ENABLED + int indx; + + if (list->nodesetval) { + for (indx = 0; indx < list->nodesetval->nodeNr; + indx++) { + xmlShellPrintNodeCtxt(ctxt, + list->nodesetval->nodeTab[indx]); + } + } else { + xmlGenericError(xmlGenericErrorContext, + "Empty node set\n"); + } + break; +#else + xmlGenericError(xmlGenericErrorContext, + "Node set\n"); +#endif /* LIBXML_OUTPUT_ENABLED */ + } + case XPATH_BOOLEAN: + xmlGenericError(xmlGenericErrorContext, + "Is a Boolean:%s\n", + xmlBoolToText(list->boolval)); + break; + case XPATH_NUMBER: + xmlGenericError(xmlGenericErrorContext, + "Is a number:%0g\n", list->floatval); + break; + case XPATH_STRING: + xmlGenericError(xmlGenericErrorContext, + "Is a string:%s\n", list->stringval); + break; + + default: + xmlShellPrintXPathError(list->type, NULL); + } + } +} + +/** + * xmlShellPrintXPathResult: + * @list: a valid result generated by an xpath evaluation + * + * Prints result to the output FILE + */ +void +xmlShellPrintXPathResult(xmlXPathObjectPtr list) +{ + xmlShellPrintXPathResultCtxt(NULL, list); +} + +/** + * xmlShellList: + * @ctxt: the shell context + * @arg: unused + * @node: a node + * @node2: unused + * + * Implements the XML shell function "ls" + * Does an Unix like listing of the given node (like a directory) + * + * Returns 0 + */ +int +xmlShellList(xmlShellCtxtPtr ctxt, + char *arg ATTRIBUTE_UNUSED, xmlNodePtr node, + xmlNodePtr node2 ATTRIBUTE_UNUSED) +{ + xmlNodePtr cur; + if (!ctxt) + return (0); + if (node == NULL) { + fprintf(ctxt->output, "NULL\n"); + return (0); + } + if ((node->type == XML_DOCUMENT_NODE) || + (node->type == XML_HTML_DOCUMENT_NODE)) { + cur = ((xmlDocPtr) node)->children; + } else if (node->type == XML_NAMESPACE_DECL) { + xmlLsOneNode(ctxt->output, node); + return (0); + } else if (node->children != NULL) { + cur = node->children; + } else { + xmlLsOneNode(ctxt->output, node); + return (0); + } + while (cur != NULL) { + xmlLsOneNode(ctxt->output, cur); + cur = cur->next; + } + return (0); +} + +/** + * xmlShellBase: + * @ctxt: the shell context + * @arg: unused + * @node: a node + * @node2: unused + * + * Implements the XML shell function "base" + * dumps the current XML base of the node + * + * Returns 0 + */ +int +xmlShellBase(xmlShellCtxtPtr ctxt, + char *arg ATTRIBUTE_UNUSED, xmlNodePtr node, + xmlNodePtr node2 ATTRIBUTE_UNUSED) +{ + xmlChar *base; + if (!ctxt) + return 0; + if (node == NULL) { + fprintf(ctxt->output, "NULL\n"); + return (0); + } + + base = xmlNodeGetBase(node->doc, node); + + if (base == NULL) { + fprintf(ctxt->output, " No base found !!!\n"); + } else { + fprintf(ctxt->output, "%s\n", base); + xmlFree(base); + } + return (0); +} + +#ifdef LIBXML_TREE_ENABLED +/** + * xmlShellSetBase: + * @ctxt: the shell context + * @arg: the new base + * @node: a node + * @node2: unused + * + * Implements the XML shell function "setbase" + * change the current XML base of the node + * + * Returns 0 + */ +static int +xmlShellSetBase(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED, + char *arg ATTRIBUTE_UNUSED, xmlNodePtr node, + xmlNodePtr node2 ATTRIBUTE_UNUSED) +{ + xmlNodeSetBase(node, (xmlChar*) arg); + return (0); +} +#endif + +#ifdef LIBXML_XPATH_ENABLED +/** + * xmlShellRegisterNamespace: + * @ctxt: the shell context + * @arg: a string in prefix=nsuri format + * @node: unused + * @node2: unused + * + * Implements the XML shell function "setns" + * register/unregister a prefix=namespace pair + * on the XPath context + * + * Returns 0 on success and a negative value otherwise. + */ +static int +xmlShellRegisterNamespace(xmlShellCtxtPtr ctxt, char *arg, + xmlNodePtr node ATTRIBUTE_UNUSED, xmlNodePtr node2 ATTRIBUTE_UNUSED) +{ + xmlChar* nsListDup; + xmlChar* prefix; + xmlChar* href; + xmlChar* next; + + nsListDup = xmlStrdup((xmlChar *) arg); + next = nsListDup; + while(next != NULL) { + /* skip spaces */ + /*while((*next) == ' ') next++;*/ + if((*next) == '\0') break; + + /* find prefix */ + prefix = next; + next = (xmlChar*)xmlStrchr(next, '='); + if(next == NULL) { + fprintf(ctxt->output, "setns: prefix=[nsuri] required\n"); + xmlFree(nsListDup); + return(-1); + } + *(next++) = '\0'; + + /* find href */ + href = next; + next = (xmlChar*)xmlStrchr(next, ' '); + if(next != NULL) { + *(next++) = '\0'; + } + + /* do register namespace */ + if(xmlXPathRegisterNs(ctxt->pctxt, prefix, href) != 0) { + fprintf(ctxt->output,"Error: unable to register NS with prefix=\"%s\" and href=\"%s\"\n", prefix, href); + xmlFree(nsListDup); + return(-1); + } + } + + xmlFree(nsListDup); + return(0); +} +/** + * xmlShellRegisterRootNamespaces: + * @ctxt: the shell context + * @arg: unused + * @node: the root element + * @node2: unused + * + * Implements the XML shell function "setrootns" + * which registers all namespaces declarations found on the root element. + * + * Returns 0 on success and a negative value otherwise. + */ +static int +xmlShellRegisterRootNamespaces(xmlShellCtxtPtr ctxt, char *arg ATTRIBUTE_UNUSED, + xmlNodePtr root, xmlNodePtr node2 ATTRIBUTE_UNUSED) +{ + xmlNsPtr ns; + + if ((root == NULL) || (root->type != XML_ELEMENT_NODE) || + (root->nsDef == NULL) || (ctxt == NULL) || (ctxt->pctxt == NULL)) + return(-1); + ns = root->nsDef; + while (ns != NULL) { + if (ns->prefix == NULL) + xmlXPathRegisterNs(ctxt->pctxt, BAD_CAST "defaultns", ns->href); + else + xmlXPathRegisterNs(ctxt->pctxt, ns->prefix, ns->href); + ns = ns->next; + } + return(0); +} +#endif + +/** + * xmlShellGrep: + * @ctxt: the shell context + * @arg: the string or regular expression to find + * @node: a node + * @node2: unused + * + * Implements the XML shell function "grep" + * dumps informations about the node (namespace, attributes, content). + * + * Returns 0 + */ +static int +xmlShellGrep(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED, + char *arg, xmlNodePtr node, xmlNodePtr node2 ATTRIBUTE_UNUSED) +{ + if (!ctxt) + return (0); + if (node == NULL) + return (0); + if (arg == NULL) + return (0); +#ifdef LIBXML_REGEXP_ENABLED + if ((xmlStrchr((xmlChar *) arg, '?')) || + (xmlStrchr((xmlChar *) arg, '*')) || + (xmlStrchr((xmlChar *) arg, '.')) || + (xmlStrchr((xmlChar *) arg, '['))) { + } +#endif + while (node != NULL) { + if (node->type == XML_COMMENT_NODE) { + if (xmlStrstr(node->content, (xmlChar *) arg)) { + + fprintf(ctxt->output, "%s : ", xmlGetNodePath(node)); + xmlShellList(ctxt, NULL, node, NULL); + } + } else if (node->type == XML_TEXT_NODE) { + if (xmlStrstr(node->content, (xmlChar *) arg)) { + + fprintf(ctxt->output, "%s : ", xmlGetNodePath(node->parent)); + xmlShellList(ctxt, NULL, node->parent, NULL); + } + } + + /* + * Browse the full subtree, deep first + */ + + if ((node->type == XML_DOCUMENT_NODE) || + (node->type == XML_HTML_DOCUMENT_NODE)) { + node = ((xmlDocPtr) node)->children; + } else if ((node->children != NULL) + && (node->type != XML_ENTITY_REF_NODE)) { + /* deep first */ + node = node->children; + } else if (node->next != NULL) { + /* then siblings */ + node = node->next; + } else { + /* go up to parents->next if needed */ + while (node != NULL) { + if (node->parent != NULL) { + node = node->parent; + } + if (node->next != NULL) { + node = node->next; + break; + } + if (node->parent == NULL) { + node = NULL; + break; + } + } + } + } + return (0); +} + +/** + * xmlShellDir: + * @ctxt: the shell context + * @arg: unused + * @node: a node + * @node2: unused + * + * Implements the XML shell function "dir" + * dumps informations about the node (namespace, attributes, content). + * + * Returns 0 + */ +int +xmlShellDir(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED, + char *arg ATTRIBUTE_UNUSED, xmlNodePtr node, + xmlNodePtr node2 ATTRIBUTE_UNUSED) +{ + if (!ctxt) + return (0); + if (node == NULL) { + fprintf(ctxt->output, "NULL\n"); + return (0); + } + if ((node->type == XML_DOCUMENT_NODE) || + (node->type == XML_HTML_DOCUMENT_NODE)) { + xmlDebugDumpDocumentHead(ctxt->output, (xmlDocPtr) node); + } else if (node->type == XML_ATTRIBUTE_NODE) { + xmlDebugDumpAttr(ctxt->output, (xmlAttrPtr) node, 0); + } else { + xmlDebugDumpOneNode(ctxt->output, node, 0); + } + return (0); +} + +/** + * xmlShellSetContent: + * @ctxt: the shell context + * @value: the content as a string + * @node: a node + * @node2: unused + * + * Implements the XML shell function "dir" + * dumps informations about the node (namespace, attributes, content). + * + * Returns 0 + */ +static int +xmlShellSetContent(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED, + char *value, xmlNodePtr node, + xmlNodePtr node2 ATTRIBUTE_UNUSED) +{ + xmlNodePtr results; + xmlParserErrors ret; + + if (!ctxt) + return (0); + if (node == NULL) { + fprintf(ctxt->output, "NULL\n"); + return (0); + } + if (value == NULL) { + fprintf(ctxt->output, "NULL\n"); + return (0); + } + + ret = xmlParseInNodeContext(node, value, strlen(value), 0, &results); + if (ret == XML_ERR_OK) { + if (node->children != NULL) { + xmlFreeNodeList(node->children); + node->children = NULL; + node->last = NULL; + } + xmlAddChildList(node, results); + } else { + fprintf(ctxt->output, "failed to parse content\n"); + } + return (0); +} + +#ifdef LIBXML_SCHEMAS_ENABLED +/** + * xmlShellRNGValidate: + * @ctxt: the shell context + * @schemas: the path to the Relax-NG schemas + * @node: a node + * @node2: unused + * + * Implements the XML shell function "relaxng" + * validating the instance against a Relax-NG schemas + * + * Returns 0 + */ +static int +xmlShellRNGValidate(xmlShellCtxtPtr sctxt, char *schemas, + xmlNodePtr node ATTRIBUTE_UNUSED, + xmlNodePtr node2 ATTRIBUTE_UNUSED) +{ + xmlRelaxNGPtr relaxngschemas; + xmlRelaxNGParserCtxtPtr ctxt; + xmlRelaxNGValidCtxtPtr vctxt; + int ret; + + ctxt = xmlRelaxNGNewParserCtxt(schemas); + xmlRelaxNGSetParserErrors(ctxt, + (xmlRelaxNGValidityErrorFunc) fprintf, + (xmlRelaxNGValidityWarningFunc) fprintf, + stderr); + relaxngschemas = xmlRelaxNGParse(ctxt); + xmlRelaxNGFreeParserCtxt(ctxt); + if (relaxngschemas == NULL) { + xmlGenericError(xmlGenericErrorContext, + "Relax-NG schema %s failed to compile\n", schemas); + return(-1); + } + vctxt = xmlRelaxNGNewValidCtxt(relaxngschemas); + xmlRelaxNGSetValidErrors(vctxt, + (xmlRelaxNGValidityErrorFunc) fprintf, + (xmlRelaxNGValidityWarningFunc) fprintf, + stderr); + ret = xmlRelaxNGValidateDoc(vctxt, sctxt->doc); + if (ret == 0) { + fprintf(stderr, "%s validates\n", sctxt->filename); + } else if (ret > 0) { + fprintf(stderr, "%s fails to validate\n", sctxt->filename); + } else { + fprintf(stderr, "%s validation generated an internal error\n", + sctxt->filename); + } + xmlRelaxNGFreeValidCtxt(vctxt); + if (relaxngschemas != NULL) + xmlRelaxNGFree(relaxngschemas); + return(0); +} +#endif + +#ifdef LIBXML_OUTPUT_ENABLED +/** + * xmlShellCat: + * @ctxt: the shell context + * @arg: unused + * @node: a node + * @node2: unused + * + * Implements the XML shell function "cat" + * dumps the serialization node content (XML or HTML). + * + * Returns 0 + */ +int +xmlShellCat(xmlShellCtxtPtr ctxt, char *arg ATTRIBUTE_UNUSED, + xmlNodePtr node, xmlNodePtr node2 ATTRIBUTE_UNUSED) +{ + if (!ctxt) + return (0); + if (node == NULL) { + fprintf(ctxt->output, "NULL\n"); + return (0); + } + if (ctxt->doc->type == XML_HTML_DOCUMENT_NODE) { + if (node->type == XML_DOCUMENT_NODE) + xmlDocDump(ctxt->output, (xmlDocPtr) node); + else + xmlElemDump(ctxt->output, ctxt->doc, node); + } else { + if (node->type == XML_DOCUMENT_NODE) + xmlDocDump(ctxt->output, (xmlDocPtr) node); + else + xmlElemDump(ctxt->output, ctxt->doc, node); + } + fprintf(ctxt->output, "\n"); + return (0); +} +#endif /* LIBXML_OUTPUT_ENABLED */ + +/** + * xmlShellLoad: + * @ctxt: the shell context + * @filename: the file name + * @node: unused + * @node2: unused + * + * Implements the XML shell function "load" + * loads a new document specified by the filename + * + * Returns 0 or -1 if loading failed + */ +int +xmlShellLoad(xmlShellCtxtPtr ctxt, char *filename, + xmlNodePtr node ATTRIBUTE_UNUSED, + xmlNodePtr node2 ATTRIBUTE_UNUSED) +{ + xmlDocPtr doc; + int html = 0; + + if ((ctxt == NULL) || (filename == NULL)) return(-1); + if (ctxt->doc != NULL) + html = (ctxt->doc->type == XML_HTML_DOCUMENT_NODE); + + if (html) { + fprintf(ctxt->output, "HTML support not compiled in\n"); + doc = NULL; + } else { + doc = xmlReadFile(filename,NULL,0); + } + if (doc != NULL) { + if (ctxt->loaded == 1) { + xmlFreeDoc(ctxt->doc); + } + ctxt->loaded = 1; +#ifdef LIBXML_XPATH_ENABLED + xmlXPathFreeContext(ctxt->pctxt); +#endif /* LIBXML_XPATH_ENABLED */ + xmlFree(ctxt->filename); + ctxt->doc = doc; + ctxt->node = (xmlNodePtr) doc; +#ifdef LIBXML_XPATH_ENABLED + ctxt->pctxt = xmlXPathNewContext(doc); +#endif /* LIBXML_XPATH_ENABLED */ + ctxt->filename = (char *) xmlCanonicPath((xmlChar *) filename); + } else + return (-1); + return (0); +} + +#ifdef LIBXML_OUTPUT_ENABLED +/** + * xmlShellWrite: + * @ctxt: the shell context + * @filename: the file name + * @node: a node in the tree + * @node2: unused + * + * Implements the XML shell function "write" + * Write the current node to the filename, it saves the serialization + * of the subtree under the @node specified + * + * Returns 0 or -1 in case of error + */ +int +xmlShellWrite(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node, + xmlNodePtr node2 ATTRIBUTE_UNUSED) +{ + if (node == NULL) + return (-1); + if ((filename == NULL) || (filename[0] == 0)) { + return (-1); + } +#ifdef W_OK + if (access((char *) filename, W_OK)) { + xmlGenericError(xmlGenericErrorContext, + "Cannot write to %s\n", filename); + return (-1); + } +#endif + switch (node->type) { + case XML_DOCUMENT_NODE: + if (xmlSaveFile((char *) filename, ctxt->doc) < -1) { + xmlGenericError(xmlGenericErrorContext, + "Failed to write to %s\n", filename); + return (-1); + } + break; + case XML_HTML_DOCUMENT_NODE: + if (xmlSaveFile((char *) filename, ctxt->doc) < -1) { + xmlGenericError(xmlGenericErrorContext, + "Failed to write to %s\n", filename); + return (-1); + } + break; + default:{ + FILE *f; + + f = fopen((char *) filename, "w"); + if (f == NULL) { + xmlGenericError(xmlGenericErrorContext, + "Failed to write to %s\n", filename); + return (-1); + } + xmlElemDump(f, ctxt->doc, node); + fclose(f); + } + } + return (0); +} + +/** + * xmlShellSave: + * @ctxt: the shell context + * @filename: the file name (optional) + * @node: unused + * @node2: unused + * + * Implements the XML shell function "save" + * Write the current document to the filename, or it's original name + * + * Returns 0 or -1 in case of error + */ +int +xmlShellSave(xmlShellCtxtPtr ctxt, char *filename, + xmlNodePtr node ATTRIBUTE_UNUSED, + xmlNodePtr node2 ATTRIBUTE_UNUSED) +{ + if ((ctxt == NULL) || (ctxt->doc == NULL)) + return (-1); + if ((filename == NULL) || (filename[0] == 0)) + filename = ctxt->filename; + if (filename == NULL) + return (-1); +#ifdef W_OK + if (access((char *) filename, W_OK)) { + xmlGenericError(xmlGenericErrorContext, + "Cannot save to %s\n", filename); + return (-1); + } +#endif + switch (ctxt->doc->type) { + case XML_DOCUMENT_NODE: + if (xmlSaveFile((char *) filename, ctxt->doc) < 0) { + xmlGenericError(xmlGenericErrorContext, + "Failed to save to %s\n", filename); + } + break; + case XML_HTML_DOCUMENT_NODE: + if (xmlSaveFile((char *) filename, ctxt->doc) < 0) { + xmlGenericError(xmlGenericErrorContext, + "Failed to save to %s\n", filename); + } + break; + default: + xmlGenericError(xmlGenericErrorContext, + "To save to subparts of a document use the 'write' command\n"); + return (-1); + + } + return (0); +} +#endif /* LIBXML_OUTPUT_ENABLED */ + +#ifdef LIBXML_VALID_ENABLED +/** + * xmlShellValidate: + * @ctxt: the shell context + * @dtd: the DTD URI (optional) + * @node: unused + * @node2: unused + * + * Implements the XML shell function "validate" + * Validate the document, if a DTD path is provided, then the validation + * is done against the given DTD. + * + * Returns 0 or -1 in case of error + */ +int +xmlShellValidate(xmlShellCtxtPtr ctxt, char *dtd, + xmlNodePtr node ATTRIBUTE_UNUSED, + xmlNodePtr node2 ATTRIBUTE_UNUSED) +{ + xmlValidCtxt vctxt; + int res = -1; + + if ((ctxt == NULL) || (ctxt->doc == NULL)) return(-1); + vctxt.userData = stderr; + vctxt.error = (xmlValidityErrorFunc) fprintf; + vctxt.warning = (xmlValidityWarningFunc) fprintf; + + if ((dtd == NULL) || (dtd[0] == 0)) { + res = xmlValidateDocument(&vctxt, ctxt->doc); + } else { + xmlDtdPtr subset; + + subset = xmlParseDTD(NULL, (xmlChar *) dtd); + if (subset != NULL) { + res = xmlValidateDtd(&vctxt, ctxt->doc, subset); + + xmlFreeDtd(subset); + } + } + return (res); +} +#endif /* LIBXML_VALID_ENABLED */ + +/** + * xmlShellDu: + * @ctxt: the shell context + * @arg: unused + * @tree: a node defining a subtree + * @node2: unused + * + * Implements the XML shell function "du" + * show the structure of the subtree under node @tree + * If @tree is null, the command works on the current node. + * + * Returns 0 or -1 in case of error + */ +int +xmlShellDu(xmlShellCtxtPtr ctxt, + char *arg ATTRIBUTE_UNUSED, xmlNodePtr tree, + xmlNodePtr node2 ATTRIBUTE_UNUSED) +{ + xmlNodePtr node; + int indent = 0, i; + + if (!ctxt) + return (-1); + + if (tree == NULL) + return (-1); + node = tree; + while (node != NULL) { + if ((node->type == XML_DOCUMENT_NODE) || + (node->type == XML_HTML_DOCUMENT_NODE)) { + fprintf(ctxt->output, "/\n"); + } else if (node->type == XML_ELEMENT_NODE) { + for (i = 0; i < indent; i++) + fprintf(ctxt->output, " "); + fprintf(ctxt->output, "%s\n", node->name); + } else { + } + + /* + * Browse the full subtree, deep first + */ + + if ((node->type == XML_DOCUMENT_NODE) || + (node->type == XML_HTML_DOCUMENT_NODE)) { + node = ((xmlDocPtr) node)->children; + } else if ((node->children != NULL) + && (node->type != XML_ENTITY_REF_NODE)) { + /* deep first */ + node = node->children; + indent++; + } else if ((node != tree) && (node->next != NULL)) { + /* then siblings */ + node = node->next; + } else if (node != tree) { + /* go up to parents->next if needed */ + while (node != tree) { + if (node->parent != NULL) { + node = node->parent; + indent--; + } + if ((node != tree) && (node->next != NULL)) { + node = node->next; + break; + } + if (node->parent == NULL) { + node = NULL; + break; + } + if (node == tree) { + node = NULL; + break; + } + } + /* exit condition */ + if (node == tree) + node = NULL; + } else + node = NULL; + } + return (0); +} + +/** + * xmlShellPwd: + * @ctxt: the shell context + * @buffer: the output buffer + * @node: a node + * @node2: unused + * + * Implements the XML shell function "pwd" + * Show the full path from the root to the node, if needed building + * thumblers when similar elements exists at a given ancestor level. + * The output is compatible with XPath commands. + * + * Returns 0 or -1 in case of error + */ +int +xmlShellPwd(xmlShellCtxtPtr ctxt ATTRIBUTE_UNUSED, char *buffer, + xmlNodePtr node, xmlNodePtr node2 ATTRIBUTE_UNUSED) +{ + xmlChar *path; + + if ((node == NULL) || (buffer == NULL)) + return (-1); + + path = xmlGetNodePath(node); + if (path == NULL) + return (-1); + + /* + * This test prevents buffer overflow, because this routine + * is only called by xmlShell, in which the second argument is + * 500 chars long. + * It is a dirty hack before a cleaner solution is found. + * Documentation should mention that the second argument must + * be at least 500 chars long, and could be stripped if too long. + */ + snprintf(buffer, 499, "%s", path); + buffer[499] = '0'; + xmlFree(path); + + return (0); +} + +/** + * xmlShell: + * @doc: the initial document + * @filename: the output buffer + * @input: the line reading function + * @output: the output FILE*, defaults to stdout if NULL + * + * Implements the XML shell + * This allow to load, validate, view, modify and save a document + * using a environment similar to a UNIX commandline. + */ +void +xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input, + FILE * output) +{ + char prompt[500] = "/ > "; + char *cmdline = NULL, *cur; + char command[100]; + char arg[400]; + int i; + xmlShellCtxtPtr ctxt; + xmlXPathObjectPtr list; + + if (doc == NULL) + return; + if (filename == NULL) + return; + if (input == NULL) + return; + if (output == NULL) + output = stdout; + ctxt = (xmlShellCtxtPtr) xmlMalloc(sizeof(xmlShellCtxt)); + if (ctxt == NULL) + return; + ctxt->loaded = 0; + ctxt->doc = doc; + ctxt->input = input; + ctxt->output = output; + ctxt->filename = (char *) xmlStrdup((xmlChar *) filename); + ctxt->node = (xmlNodePtr) ctxt->doc; + +#ifdef LIBXML_XPATH_ENABLED + ctxt->pctxt = xmlXPathNewContext(ctxt->doc); + if (ctxt->pctxt == NULL) { + xmlFree(ctxt); + return; + } +#endif /* LIBXML_XPATH_ENABLED */ + while (1) { + if (ctxt->node == (xmlNodePtr) ctxt->doc) + snprintf(prompt, sizeof(prompt), "%s > ", "/"); + else if ((ctxt->node != NULL) && (ctxt->node->name)) + snprintf(prompt, sizeof(prompt), "%s > ", ctxt->node->name); + else + snprintf(prompt, sizeof(prompt), "? > "); + prompt[sizeof(prompt) - 1] = 0; + + /* + * Get a new command line + */ + cmdline = ctxt->input(prompt); + if (cmdline == NULL) + break; + + /* + * Parse the command itself + */ + cur = cmdline; + while ((*cur == ' ') || (*cur == '\t')) + cur++; + i = 0; + while ((*cur != ' ') && (*cur != '\t') && + (*cur != '\n') && (*cur != '\r')) { + if (*cur == 0) + break; + command[i++] = *cur++; + } + command[i] = 0; + if (i == 0) + continue; + + /* + * Parse the argument + */ + while ((*cur == ' ') || (*cur == '\t')) + cur++; + i = 0; + while ((*cur != '\n') && (*cur != '\r') && (*cur != 0)) { + if (*cur == 0) + break; + arg[i++] = *cur++; + } + arg[i] = 0; + + /* + * start interpreting the command + */ + if (!strcmp(command, "exit")) + break; + if (!strcmp(command, "quit")) + break; + if (!strcmp(command, "bye")) + break; + if (!strcmp(command, "help")) { + fprintf(ctxt->output, "\tbase display XML base of the node\n"); + fprintf(ctxt->output, "\tsetbase URI change the XML base of the node\n"); + fprintf(ctxt->output, "\tbye leave shell\n"); + fprintf(ctxt->output, "\tcat [node] display node or current node\n"); + fprintf(ctxt->output, "\tcd [path] change directory to path or to root\n"); + fprintf(ctxt->output, "\tdir [path] dumps informations about the node (namespace, attributes, content)\n"); + fprintf(ctxt->output, "\tdu [path] show the structure of the subtree under path or the current node\n"); + fprintf(ctxt->output, "\texit leave shell\n"); + fprintf(ctxt->output, "\thelp display this help\n"); + fprintf(ctxt->output, "\tfree display memory usage\n"); + fprintf(ctxt->output, "\tload [name] load a new document with name\n"); + fprintf(ctxt->output, "\tls [path] list contents of path or the current directory\n"); + fprintf(ctxt->output, "\tset xml_fragment replace the current node content with the fragment parsed in context\n"); +#ifdef LIBXML_XPATH_ENABLED + fprintf(ctxt->output, "\txpath expr evaluate the XPath expression in that context and print the result\n"); + fprintf(ctxt->output, "\tsetns nsreg register a namespace to a prefix in the XPath evaluation context\n"); + fprintf(ctxt->output, "\t format for nsreg is: prefix=[nsuri] (i.e. prefix= unsets a prefix)\n"); + fprintf(ctxt->output, "\tsetrootns register all namespace found on the root element\n"); + fprintf(ctxt->output, "\t the default namespace if any uses 'defaultns' prefix\n"); +#endif /* LIBXML_XPATH_ENABLED */ + fprintf(ctxt->output, "\tpwd display current working directory\n"); + fprintf(ctxt->output, "\tquit leave shell\n"); +#ifdef LIBXML_OUTPUT_ENABLED + fprintf(ctxt->output, "\tsave [name] save this document to name or the original name\n"); + fprintf(ctxt->output, "\twrite [name] write the current node to the filename\n"); +#endif /* LIBXML_OUTPUT_ENABLED */ +#ifdef LIBXML_VALID_ENABLED + fprintf(ctxt->output, "\tvalidate check the document for errors\n"); +#endif /* LIBXML_VALID_ENABLED */ +#ifdef LIBXML_SCHEMAS_ENABLED + fprintf(ctxt->output, "\trelaxng rng validate the document agaisnt the Relax-NG schemas\n"); +#endif + fprintf(ctxt->output, "\tgrep string search for a string in the subtree\n"); +#ifdef LIBXML_VALID_ENABLED + } else if (!strcmp(command, "validate")) { + xmlShellValidate(ctxt, arg, NULL, NULL); +#endif /* LIBXML_VALID_ENABLED */ + } else if (!strcmp(command, "load")) { + xmlShellLoad(ctxt, arg, NULL, NULL); +#ifdef LIBXML_SCHEMAS_ENABLED + } else if (!strcmp(command, "relaxng")) { + xmlShellRNGValidate(ctxt, arg, NULL, NULL); +#endif +#ifdef LIBXML_OUTPUT_ENABLED + } else if (!strcmp(command, "save")) { + xmlShellSave(ctxt, arg, NULL, NULL); + } else if (!strcmp(command, "write")) { + if ((arg == NULL) || (arg[0] == 0)) + xmlGenericError(xmlGenericErrorContext, + "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]; + + if (!xmlShellPwd(ctxt, dir, ctxt->node, NULL)) + fprintf(ctxt->output, "%s\n", dir); + } else if (!strcmp(command, "du")) { + xmlShellDu(ctxt, NULL, ctxt->node, NULL); + } else if (!strcmp(command, "base")) { + xmlShellBase(ctxt, NULL, ctxt->node, NULL); + } else if (!strcmp(command, "set")) { + xmlShellSetContent(ctxt, arg, ctxt->node, NULL); +#ifdef LIBXML_XPATH_ENABLED + } else if (!strcmp(command, "setns")) { + if (arg[0] == 0) { + xmlGenericError(xmlGenericErrorContext, + "setns: prefix=[nsuri] required\n"); + } else { + xmlShellRegisterNamespace(ctxt, arg, NULL, NULL); + } + } else if (!strcmp(command, "setrootns")) { + xmlNodePtr root; + + root = xmlDocGetRootElement(ctxt->doc); + xmlShellRegisterRootNamespaces(ctxt, NULL, root, NULL); + } else if (!strcmp(command, "xpath")) { + if (arg[0] == 0) { + xmlGenericError(xmlGenericErrorContext, + "xpath: expression required\n"); + } else { + ctxt->pctxt->node = ctxt->node; + list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt); + xmlXPathDebugDumpObject(ctxt->output, list, 0); + xmlXPathFreeObject(list); + } +#endif /* LIBXML_XPATH_ENABLED */ +#ifdef LIBXML_TREE_ENABLED + } else if (!strcmp(command, "setbase")) { + xmlShellSetBase(ctxt, arg, ctxt->node, NULL); +#endif + } else if ((!strcmp(command, "ls")) || (!strcmp(command, "dir"))) { + int dir = (!strcmp(command, "dir")); + + if (arg[0] == 0) { + if (dir) + xmlShellDir(ctxt, NULL, ctxt->node, NULL); + else + xmlShellList(ctxt, NULL, ctxt->node, NULL); + } else { + ctxt->pctxt->node = ctxt->node; +#ifdef LIBXML_XPATH_ENABLED + ctxt->pctxt->node = ctxt->node; + list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt); +#else + list = NULL; +#endif /* LIBXML_XPATH_ENABLED */ + if (list != NULL) { + switch (list->type) { + case XPATH_UNDEFINED: + xmlGenericError(xmlGenericErrorContext, + "%s: no such node\n", arg); + break; + case XPATH_NODESET:{ + int indx; + + if (list->nodesetval == NULL) + break; + + for (indx = 0; + indx < list->nodesetval->nodeNr; + indx++) { + if (dir) + xmlShellDir(ctxt, NULL, + list->nodesetval-> + nodeTab[indx], NULL); + else + xmlShellList(ctxt, NULL, + list->nodesetval-> + nodeTab[indx], NULL); + } + break; + } + case XPATH_BOOLEAN: + xmlGenericError(xmlGenericErrorContext, + "%s is a Boolean\n", arg); + break; + case XPATH_NUMBER: + xmlGenericError(xmlGenericErrorContext, + "%s is a number\n", arg); + break; + case XPATH_STRING: + xmlGenericError(xmlGenericErrorContext, + "%s is a string\n", arg); + break; + case XPATH_POINT: + xmlGenericError(xmlGenericErrorContext, + "%s is a point\n", arg); + break; + case XPATH_RANGE: + xmlGenericError(xmlGenericErrorContext, + "%s is a range\n", arg); + break; + case XPATH_LOCATIONSET: + xmlGenericError(xmlGenericErrorContext, + "%s is a range\n", arg); + break; + case XPATH_USERS: + xmlGenericError(xmlGenericErrorContext, + "%s is user-defined\n", arg); + break; + case XPATH_XSLT_TREE: + xmlGenericError(xmlGenericErrorContext, + "%s is an XSLT value tree\n", + arg); + break; + } +#ifdef LIBXML_XPATH_ENABLED + xmlXPathFreeObject(list); +#endif + } else { + xmlGenericError(xmlGenericErrorContext, + "%s: no such node\n", arg); + } + ctxt->pctxt->node = NULL; + } + } else if (!strcmp(command, "cd")) { + if (arg[0] == 0) { + ctxt->node = (xmlNodePtr) ctxt->doc; + } else { +#ifdef LIBXML_XPATH_ENABLED + ctxt->pctxt->node = ctxt->node; + list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt); +#else + list = NULL; +#endif /* LIBXML_XPATH_ENABLED */ + if (list != NULL) { + switch (list->type) { + case XPATH_UNDEFINED: + xmlGenericError(xmlGenericErrorContext, + "%s: no such node\n", arg); + break; + case XPATH_NODESET: + if (list->nodesetval != NULL) { + if (list->nodesetval->nodeNr == 1) { + ctxt->node = list->nodesetval->nodeTab[0]; + if ((ctxt->node != NULL) && + (ctxt->node->type == + XML_NAMESPACE_DECL)) { + xmlGenericError(xmlGenericErrorContext, + "cannot cd to namespace\n"); + ctxt->node = NULL; + } + } else + xmlGenericError(xmlGenericErrorContext, + "%s is a %d Node Set\n", + arg, + list->nodesetval->nodeNr); + } else + xmlGenericError(xmlGenericErrorContext, + "%s is an empty Node Set\n", + arg); + break; + case XPATH_BOOLEAN: + xmlGenericError(xmlGenericErrorContext, + "%s is a Boolean\n", arg); + break; + case XPATH_NUMBER: + xmlGenericError(xmlGenericErrorContext, + "%s is a number\n", arg); + break; + case XPATH_STRING: + xmlGenericError(xmlGenericErrorContext, + "%s is a string\n", arg); + break; + case XPATH_POINT: + xmlGenericError(xmlGenericErrorContext, + "%s is a point\n", arg); + break; + case XPATH_RANGE: + xmlGenericError(xmlGenericErrorContext, + "%s is a range\n", arg); + break; + case XPATH_LOCATIONSET: + xmlGenericError(xmlGenericErrorContext, + "%s is a range\n", arg); + break; + case XPATH_USERS: + xmlGenericError(xmlGenericErrorContext, + "%s is user-defined\n", arg); + break; + case XPATH_XSLT_TREE: + xmlGenericError(xmlGenericErrorContext, + "%s is an XSLT value tree\n", + arg); + break; + } +#ifdef LIBXML_XPATH_ENABLED + xmlXPathFreeObject(list); +#endif + } else { + xmlGenericError(xmlGenericErrorContext, + "%s: no such node\n", arg); + } + ctxt->pctxt->node = NULL; + } +#ifdef LIBXML_OUTPUT_ENABLED + } else if (!strcmp(command, "cat")) { + if (arg[0] == 0) { + xmlShellCat(ctxt, NULL, ctxt->node, NULL); + } else { + ctxt->pctxt->node = ctxt->node; +#ifdef LIBXML_XPATH_ENABLED + ctxt->pctxt->node = ctxt->node; + list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt); +#else + list = NULL; +#endif /* LIBXML_XPATH_ENABLED */ + if (list != NULL) { + switch (list->type) { + case XPATH_UNDEFINED: + xmlGenericError(xmlGenericErrorContext, + "%s: no such node\n", arg); + break; + case XPATH_NODESET:{ + int indx; + + if (list->nodesetval == NULL) + break; + + for (indx = 0; + indx < list->nodesetval->nodeNr; + indx++) { + if (i > 0) + fprintf(ctxt->output, " -------\n"); + xmlShellCat(ctxt, NULL, + list->nodesetval-> + nodeTab[indx], NULL); + } + break; + } + case XPATH_BOOLEAN: + xmlGenericError(xmlGenericErrorContext, + "%s is a Boolean\n", arg); + break; + case XPATH_NUMBER: + xmlGenericError(xmlGenericErrorContext, + "%s is a number\n", arg); + break; + case XPATH_STRING: + xmlGenericError(xmlGenericErrorContext, + "%s is a string\n", arg); + break; + case XPATH_POINT: + xmlGenericError(xmlGenericErrorContext, + "%s is a point\n", arg); + break; + case XPATH_RANGE: + xmlGenericError(xmlGenericErrorContext, + "%s is a range\n", arg); + break; + case XPATH_LOCATIONSET: + xmlGenericError(xmlGenericErrorContext, + "%s is a range\n", arg); + break; + case XPATH_USERS: + xmlGenericError(xmlGenericErrorContext, + "%s is user-defined\n", arg); + break; + case XPATH_XSLT_TREE: + xmlGenericError(xmlGenericErrorContext, + "%s is an XSLT value tree\n", + arg); + break; + } +#ifdef LIBXML_XPATH_ENABLED + xmlXPathFreeObject(list); +#endif + } else { + xmlGenericError(xmlGenericErrorContext, + "%s: no such node\n", arg); + } + ctxt->pctxt->node = NULL; + } +#endif /* LIBXML_OUTPUT_ENABLED */ + } else { + xmlGenericError(xmlGenericErrorContext, + "Unknown command %s\n", command); + } + free(cmdline); /* not xmlFree here ! */ + cmdline = NULL; + } +#ifdef LIBXML_XPATH_ENABLED + xmlXPathFreeContext(ctxt->pctxt); +#endif /* LIBXML_XPATH_ENABLED */ + if (ctxt->loaded) { + xmlFreeDoc(ctxt->doc); + } + if (ctxt->filename != NULL) + xmlFree(ctxt->filename); + xmlFree(ctxt); + if (cmdline != NULL) + free(cmdline); /* not xmlFree here ! */ +} + +#endif /* LIBXML_XPATH_ENABLED */ +#define bottom_debugXML +#include "elfgcchack.h" +#endif /* LIBXML_DEBUG_ENABLED */ diff --git a/android/native/libxml2/dict.c b/android/native/libxml2/dict.c new file mode 100644 index 0000000000..ae4966bcac --- /dev/null +++ b/android/native/libxml2/dict.c @@ -0,0 +1,1133 @@ +/* + * dict.c: dictionary of reusable strings, just used to avoid allocation + * and freeing operations. + * + * Copyright (C) 2003-2012 Daniel Veillard. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND + * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER. + * + * Author: daniel@veillard.com + */ + +#define IN_LIBXML +#include "libxml.h" + +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_TIME_H +#include +#endif + +/* + * Following http://www.ocert.org/advisories/ocert-2011-003.html + * it seems that having hash randomization might be a good idea + * when using XML with untrusted data + * Note1: that it works correctly only if compiled with WITH_BIG_KEY + * which is the default. + * Note2: the fast function used for a small dict won't protect very + * well but since the attack is based on growing a very big hash + * list we will use the BigKey algo as soon as the hash size grows + * over MIN_DICT_SIZE so this actually works + */ +#if defined(HAVE_RAND) && defined(HAVE_SRAND) && defined(HAVE_TIME) +#define DICT_RANDOMIZATION +#endif + +#include +#ifdef HAVE_STDINT_H +#include +#else +#ifdef HAVE_INTTYPES_H +#include +#elif defined(WIN32) +typedef unsigned __int32 uint32_t; +#endif +#endif +#include +#include +#include +#include +#include + +/* #define DEBUG_GROW */ +/* #define DICT_DEBUG_PATTERNS */ + +#define MAX_HASH_LEN 3 +#define MIN_DICT_SIZE 128 +#define MAX_DICT_HASH 8 * 2048 +#define WITH_BIG_KEY + +#ifdef WITH_BIG_KEY +#define xmlDictComputeKey(dict, name, len) \ + (((dict)->size == MIN_DICT_SIZE) ? \ + xmlDictComputeFastKey(name, len, (dict)->seed) : \ + xmlDictComputeBigKey(name, len, (dict)->seed)) + +#define xmlDictComputeQKey(dict, prefix, plen, name, len) \ + (((prefix) == NULL) ? \ + (xmlDictComputeKey(dict, name, len)) : \ + (((dict)->size == MIN_DICT_SIZE) ? \ + xmlDictComputeFastQKey(prefix, plen, name, len, (dict)->seed) : \ + xmlDictComputeBigQKey(prefix, plen, name, len, (dict)->seed))) + +#else /* !WITH_BIG_KEY */ +#define xmlDictComputeKey(dict, name, len) \ + xmlDictComputeFastKey(name, len, (dict)->seed) +#define xmlDictComputeQKey(dict, prefix, plen, name, len) \ + xmlDictComputeFastQKey(prefix, plen, name, len, (dict)->seed) +#endif /* WITH_BIG_KEY */ + +/* + * An entry in the dictionnary + */ +typedef struct _xmlDictEntry xmlDictEntry; +typedef xmlDictEntry *xmlDictEntryPtr; +struct _xmlDictEntry { + struct _xmlDictEntry *next; + const xmlChar *name; + int len; + int valid; + unsigned long okey; +}; + +typedef struct _xmlDictStrings xmlDictStrings; +typedef xmlDictStrings *xmlDictStringsPtr; +struct _xmlDictStrings { + xmlDictStringsPtr next; + xmlChar *free; + xmlChar *end; + int size; + int nbStrings; + xmlChar array[1]; +}; +/* + * The entire dictionnary + */ +struct _xmlDict { + int ref_counter; + + struct _xmlDictEntry *dict; + int size; + int nbElems; + xmlDictStringsPtr strings; + + struct _xmlDict *subdict; + /* used for randomization */ + int seed; +}; + +/* + * A mutex for modifying the reference counter for shared + * dictionaries. + */ +static xmlRMutexPtr xmlDictMutex = NULL; + +/* + * Whether the dictionary mutex was initialized. + */ +static int xmlDictInitialized = 0; + +/** + * xmlInitializeDict: + * + * Do the dictionary mutex initialization. + * this function is not thread safe, initialization should + * preferably be done once at startup + */ +static int xmlInitializeDict(void) { + if (xmlDictInitialized) + return(1); + + if ((xmlDictMutex = xmlNewRMutex()) == NULL) + return(0); + +#ifdef DICT_RANDOMIZATION + srand(time(NULL)); +#endif + xmlDictInitialized = 1; + return(1); +} + +/** + * xmlDictCleanup: + * + * Free the dictionary mutex. + */ +void +xmlDictCleanup(void) { + if (!xmlDictInitialized) + return; + + xmlFreeRMutex(xmlDictMutex); + + xmlDictInitialized = 0; +} + +/* + * xmlDictAddString: + * @dict: the dictionnary + * @name: the name of the userdata + * @len: the length of the name, if -1 it is recomputed + * + * Add the string to the array[s] + * + * Returns the pointer of the local string, or NULL in case of error. + */ +static const xmlChar * +xmlDictAddString(xmlDictPtr dict, const xmlChar *name, int namelen) { + xmlDictStringsPtr pool; + const xmlChar *ret; + int size = 0; /* + sizeof(_xmlDictStrings) == 1024 */ + +#ifdef DICT_DEBUG_PATTERNS + fprintf(stderr, "-"); +#endif + pool = dict->strings; + while (pool != NULL) { + if (pool->end - pool->free > namelen) + goto found_pool; + if (pool->size > size) size = pool->size; + pool = pool->next; + } + /* + * Not found, need to allocate + */ + if (pool == NULL) { + if (size == 0) size = 1000; + else size *= 4; /* exponential growth */ + if (size < 4 * namelen) + size = 4 * namelen; /* just in case ! */ + pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size); + if (pool == NULL) + return(NULL); + pool->size = size; + pool->nbStrings = 0; + pool->free = &pool->array[0]; + pool->end = &pool->array[size]; + pool->next = dict->strings; + dict->strings = pool; +#ifdef DICT_DEBUG_PATTERNS + fprintf(stderr, "+"); +#endif + } +found_pool: + ret = pool->free; + memcpy(pool->free, name, namelen); + pool->free += namelen; + *(pool->free++) = 0; + pool->nbStrings++; + return(ret); +} + +/* + * xmlDictAddQString: + * @dict: the dictionnary + * @prefix: the prefix of the userdata + * @plen: the prefix length + * @name: the name of the userdata + * @len: the length of the name, if -1 it is recomputed + * + * Add the QName to the array[s] + * + * Returns the pointer of the local string, or NULL in case of error. + */ +static const xmlChar * +xmlDictAddQString(xmlDictPtr dict, const xmlChar *prefix, int plen, + const xmlChar *name, int namelen) +{ + xmlDictStringsPtr pool; + const xmlChar *ret; + int size = 0; /* + sizeof(_xmlDictStrings) == 1024 */ + + if (prefix == NULL) return(xmlDictAddString(dict, name, namelen)); + +#ifdef DICT_DEBUG_PATTERNS + fprintf(stderr, "="); +#endif + pool = dict->strings; + while (pool != NULL) { + if (pool->end - pool->free > namelen + plen + 1) + goto found_pool; + if (pool->size > size) size = pool->size; + pool = pool->next; + } + /* + * Not found, need to allocate + */ + if (pool == NULL) { + if (size == 0) size = 1000; + else size *= 4; /* exponential growth */ + if (size < 4 * (namelen + plen + 1)) + size = 4 * (namelen + plen + 1); /* just in case ! */ + pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size); + if (pool == NULL) + return(NULL); + pool->size = size; + pool->nbStrings = 0; + pool->free = &pool->array[0]; + pool->end = &pool->array[size]; + pool->next = dict->strings; + dict->strings = pool; +#ifdef DICT_DEBUG_PATTERNS + fprintf(stderr, "+"); +#endif + } +found_pool: + ret = pool->free; + memcpy(pool->free, prefix, plen); + pool->free += plen; + *(pool->free++) = ':'; + memcpy(pool->free, name, namelen); + pool->free += namelen; + *(pool->free++) = 0; + pool->nbStrings++; + return(ret); +} + +#ifdef WITH_BIG_KEY +/* + * xmlDictComputeBigKey: + * + * Calculate a hash key using a good hash function that works well for + * larger hash table sizes. + * + * Hash function by "One-at-a-Time Hash" see + * http://burtleburtle.net/bob/hash/doobs.html + */ + +static uint32_t +xmlDictComputeBigKey(const xmlChar* data, int namelen, int seed) { + uint32_t hash; + int i; + + if (namelen <= 0 || data == NULL) return(0); + + hash = seed; + + for (i = 0;i < namelen; i++) { + hash += data[i]; + hash += (hash << 10); + hash ^= (hash >> 6); + } + hash += (hash << 3); + hash ^= (hash >> 11); + hash += (hash << 15); + + return hash; +} + +/* + * xmlDictComputeBigQKey: + * + * Calculate a hash key for two strings using a good hash function + * that works well for larger hash table sizes. + * + * Hash function by "One-at-a-Time Hash" see + * http://burtleburtle.net/bob/hash/doobs.html + * + * Neither of the two strings must be NULL. + */ +static unsigned long +xmlDictComputeBigQKey(const xmlChar *prefix, int plen, + const xmlChar *name, int len, int seed) +{ + uint32_t hash; + int i; + + hash = seed; + + for (i = 0;i < plen; i++) { + hash += prefix[i]; + hash += (hash << 10); + hash ^= (hash >> 6); + } + hash += ':'; + hash += (hash << 10); + hash ^= (hash >> 6); + + for (i = 0;i < len; i++) { + hash += name[i]; + hash += (hash << 10); + hash ^= (hash >> 6); + } + hash += (hash << 3); + hash ^= (hash >> 11); + hash += (hash << 15); + + return hash; +} +#endif /* WITH_BIG_KEY */ + +/* + * xmlDictComputeFastKey: + * + * Calculate a hash key using a fast hash function that works well + * for low hash table fill. + */ +static unsigned long +xmlDictComputeFastKey(const xmlChar *name, int namelen, int seed) { + unsigned long value = seed; + + if (name == NULL) return(0); + value = *name; + value <<= 5; + if (namelen > 10) { + value += name[namelen - 1]; + namelen = 10; + } + switch (namelen) { + case 10: value += name[9]; + case 9: value += name[8]; + case 8: value += name[7]; + case 7: value += name[6]; + case 6: value += name[5]; + case 5: value += name[4]; + case 4: value += name[3]; + case 3: value += name[2]; + case 2: value += name[1]; + default: break; + } + return(value); +} + +/* + * xmlDictComputeFastQKey: + * + * Calculate a hash key for two strings using a fast hash function + * that works well for low hash table fill. + * + * Neither of the two strings must be NULL. + */ +static unsigned long +xmlDictComputeFastQKey(const xmlChar *prefix, int plen, + const xmlChar *name, int len, int seed) +{ + unsigned long value = (unsigned long) seed; + + if (plen == 0) + value += 30 * (unsigned long) ':'; + else + value += 30 * (*prefix); + + if (len > 10) { + value += name[len - (plen + 1 + 1)]; + len = 10; + if (plen > 10) + plen = 10; + } + switch (plen) { + case 10: value += prefix[9]; + case 9: value += prefix[8]; + case 8: value += prefix[7]; + case 7: value += prefix[6]; + case 6: value += prefix[5]; + case 5: value += prefix[4]; + case 4: value += prefix[3]; + case 3: value += prefix[2]; + case 2: value += prefix[1]; + case 1: value += prefix[0]; + default: break; + } + len -= plen; + if (len > 0) { + value += (unsigned long) ':'; + len--; + } + switch (len) { + case 10: value += name[9]; + case 9: value += name[8]; + case 8: value += name[7]; + case 7: value += name[6]; + case 6: value += name[5]; + case 5: value += name[4]; + case 4: value += name[3]; + case 3: value += name[2]; + case 2: value += name[1]; + case 1: value += name[0]; + default: break; + } + return(value); +} + +/** + * xmlDictCreate: + * + * Create a new dictionary + * + * Returns the newly created dictionnary, or NULL if an error occured. + */ +xmlDictPtr +xmlDictCreate(void) { + xmlDictPtr dict; + + if (!xmlDictInitialized) + if (!xmlInitializeDict()) + return(NULL); + +#ifdef DICT_DEBUG_PATTERNS + fprintf(stderr, "C"); +#endif + + dict = xmlMalloc(sizeof(xmlDict)); + if (dict) { + dict->ref_counter = 1; + + dict->size = MIN_DICT_SIZE; + dict->nbElems = 0; + dict->dict = xmlMalloc(MIN_DICT_SIZE * sizeof(xmlDictEntry)); + dict->strings = NULL; + dict->subdict = NULL; + if (dict->dict) { + memset(dict->dict, 0, MIN_DICT_SIZE * sizeof(xmlDictEntry)); +#ifdef DICT_RANDOMIZATION + dict->seed = rand(); +#else + dict->seed = 0; +#endif + return(dict); + } + xmlFree(dict); + } + return(NULL); +} + +/** + * xmlDictCreateSub: + * @sub: an existing dictionnary + * + * Create a new dictionary, inheriting strings from the read-only + * dictionnary @sub. On lookup, strings are first searched in the + * new dictionnary, then in @sub, and if not found are created in the + * new dictionnary. + * + * Returns the newly created dictionnary, or NULL if an error occured. + */ +xmlDictPtr +xmlDictCreateSub(xmlDictPtr sub) { + xmlDictPtr dict = xmlDictCreate(); + + if ((dict != NULL) && (sub != NULL)) { +#ifdef DICT_DEBUG_PATTERNS + fprintf(stderr, "R"); +#endif + dict->seed = sub->seed; + dict->subdict = sub; + xmlDictReference(dict->subdict); + } + return(dict); +} + +/** + * xmlDictReference: + * @dict: the dictionnary + * + * Increment the reference counter of a dictionary + * + * Returns 0 in case of success and -1 in case of error + */ +int +xmlDictReference(xmlDictPtr dict) { + if (!xmlDictInitialized) + if (!xmlInitializeDict()) + return(-1); + + if (dict == NULL) return -1; + xmlRMutexLock(xmlDictMutex); + dict->ref_counter++; + xmlRMutexUnlock(xmlDictMutex); + return(0); +} + +/** + * xmlDictGrow: + * @dict: the dictionnary + * @size: the new size of the dictionnary + * + * resize the dictionnary + * + * Returns 0 in case of success, -1 in case of failure + */ +static int +xmlDictGrow(xmlDictPtr dict, int size) { + unsigned long key, okey; + int oldsize, i; + xmlDictEntryPtr iter, next; + struct _xmlDictEntry *olddict; +#ifdef DEBUG_GROW + unsigned long nbElem = 0; +#endif + int ret = 0; + int keep_keys = 1; + + if (dict == NULL) + return(-1); + if (size < 8) + return(-1); + if (size > 8 * 2048) + return(-1); + +#ifdef DICT_DEBUG_PATTERNS + fprintf(stderr, "*"); +#endif + + oldsize = dict->size; + olddict = dict->dict; + if (olddict == NULL) + return(-1); + if (oldsize == MIN_DICT_SIZE) + keep_keys = 0; + + dict->dict = xmlMalloc(size * sizeof(xmlDictEntry)); + if (dict->dict == NULL) { + dict->dict = olddict; + return(-1); + } + memset(dict->dict, 0, size * sizeof(xmlDictEntry)); + dict->size = size; + + /* If the two loops are merged, there would be situations where + a new entry needs to allocated and data copied into it from + the main dict. It is nicer to run through the array twice, first + copying all the elements in the main array (less probability of + allocate) and then the rest, so we only free in the second loop. + */ + for (i = 0; i < oldsize; i++) { + if (olddict[i].valid == 0) + continue; + + if (keep_keys) + okey = olddict[i].okey; + else + okey = xmlDictComputeKey(dict, olddict[i].name, olddict[i].len); + key = okey % dict->size; + + if (dict->dict[key].valid == 0) { + memcpy(&(dict->dict[key]), &(olddict[i]), sizeof(xmlDictEntry)); + dict->dict[key].next = NULL; + dict->dict[key].okey = okey; + } else { + xmlDictEntryPtr entry; + + entry = xmlMalloc(sizeof(xmlDictEntry)); + if (entry != NULL) { + entry->name = olddict[i].name; + entry->len = olddict[i].len; + entry->okey = okey; + entry->next = dict->dict[key].next; + entry->valid = 1; + dict->dict[key].next = entry; + } else { + /* + * we don't have much ways to alert from herei + * result is loosing an entry and unicity garantee + */ + ret = -1; + } + } +#ifdef DEBUG_GROW + nbElem++; +#endif + } + + for (i = 0; i < oldsize; i++) { + iter = olddict[i].next; + while (iter) { + next = iter->next; + + /* + * put back the entry in the new dict + */ + + if (keep_keys) + okey = iter->okey; + else + okey = xmlDictComputeKey(dict, iter->name, iter->len); + key = okey % dict->size; + if (dict->dict[key].valid == 0) { + memcpy(&(dict->dict[key]), iter, sizeof(xmlDictEntry)); + dict->dict[key].next = NULL; + dict->dict[key].valid = 1; + dict->dict[key].okey = okey; + xmlFree(iter); + } else { + iter->next = dict->dict[key].next; + iter->okey = okey; + dict->dict[key].next = iter; + } + +#ifdef DEBUG_GROW + nbElem++; +#endif + + iter = next; + } + } + + xmlFree(olddict); + +#ifdef DEBUG_GROW + xmlGenericError(xmlGenericErrorContext, + "xmlDictGrow : from %d to %d, %d elems\n", oldsize, size, nbElem); +#endif + + return(ret); +} + +/** + * xmlDictFree: + * @dict: the dictionnary + * + * Free the hash @dict and its contents. The userdata is + * deallocated with @f if provided. + */ +void +xmlDictFree(xmlDictPtr dict) { + int i; + xmlDictEntryPtr iter; + xmlDictEntryPtr next; + int inside_dict = 0; + xmlDictStringsPtr pool, nextp; + + if (dict == NULL) + return; + + if (!xmlDictInitialized) + if (!xmlInitializeDict()) + return; + + /* decrement the counter, it may be shared by a parser and docs */ + xmlRMutexLock(xmlDictMutex); + dict->ref_counter--; + if (dict->ref_counter > 0) { + xmlRMutexUnlock(xmlDictMutex); + return; + } + + xmlRMutexUnlock(xmlDictMutex); + + if (dict->subdict != NULL) { + xmlDictFree(dict->subdict); + } + + if (dict->dict) { + for(i = 0; ((i < dict->size) && (dict->nbElems > 0)); i++) { + iter = &(dict->dict[i]); + if (iter->valid == 0) + continue; + inside_dict = 1; + while (iter) { + next = iter->next; + if (!inside_dict) + xmlFree(iter); + dict->nbElems--; + inside_dict = 0; + iter = next; + } + } + xmlFree(dict->dict); + } + pool = dict->strings; + while (pool != NULL) { + nextp = pool->next; + xmlFree(pool); + pool = nextp; + } + xmlFree(dict); +} + +/** + * xmlDictLookup: + * @dict: the dictionnary + * @name: the name of the userdata + * @len: the length of the name, if -1 it is recomputed + * + * Add the @name to the dictionnary @dict if not present. + * + * Returns the internal copy of the name or NULL in case of internal error + */ +const xmlChar * +xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len) { + unsigned long key, okey, nbi = 0; + xmlDictEntryPtr entry; + xmlDictEntryPtr insert; + const xmlChar *ret; + + if ((dict == NULL) || (name == NULL)) + return(NULL); + + if (len < 0) + len = strlen((const char *) name); + + /* + * Check for duplicate and insertion location. + */ + okey = xmlDictComputeKey(dict, name, len); + key = okey % dict->size; + if (dict->dict[key].valid == 0) { + insert = NULL; + } else { + for (insert = &(dict->dict[key]); insert->next != NULL; + insert = insert->next) { +#ifdef __GNUC__ + if ((insert->okey == okey) && (insert->len == len)) { + if (!memcmp(insert->name, name, len)) + return(insert->name); + } +#else + if ((insert->okey == okey) && (insert->len == len) && + (!xmlStrncmp(insert->name, name, len))) + return(insert->name); +#endif + nbi++; + } +#ifdef __GNUC__ + if ((insert->okey == okey) && (insert->len == len)) { + if (!memcmp(insert->name, name, len)) + return(insert->name); + } +#else + if ((insert->okey == okey) && (insert->len == len) && + (!xmlStrncmp(insert->name, name, len))) + return(insert->name); +#endif + } + + if (dict->subdict) { + unsigned long skey; + + /* we cannot always reuse the same okey for the subdict */ + if (((dict->size == MIN_DICT_SIZE) && + (dict->subdict->size != MIN_DICT_SIZE)) || + ((dict->size != MIN_DICT_SIZE) && + (dict->subdict->size == MIN_DICT_SIZE))) + skey = xmlDictComputeKey(dict->subdict, name, len); + else + skey = okey; + + key = skey % dict->subdict->size; + if (dict->subdict->dict[key].valid != 0) { + xmlDictEntryPtr tmp; + + for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL; + tmp = tmp->next) { +#ifdef __GNUC__ + if ((tmp->okey == skey) && (tmp->len == len)) { + if (!memcmp(tmp->name, name, len)) + return(tmp->name); + } +#else + if ((tmp->okey == skey) && (tmp->len == len) && + (!xmlStrncmp(tmp->name, name, len))) + return(tmp->name); +#endif + nbi++; + } +#ifdef __GNUC__ + if ((tmp->okey == skey) && (tmp->len == len)) { + if (!memcmp(tmp->name, name, len)) + return(tmp->name); + } +#else + if ((tmp->okey == skey) && (tmp->len == len) && + (!xmlStrncmp(tmp->name, name, len))) + return(tmp->name); +#endif + } + key = okey % dict->size; + } + + ret = xmlDictAddString(dict, name, len); + if (ret == NULL) + return(NULL); + if (insert == NULL) { + entry = &(dict->dict[key]); + } else { + entry = xmlMalloc(sizeof(xmlDictEntry)); + if (entry == NULL) + return(NULL); + } + entry->name = ret; + entry->len = len; + entry->next = NULL; + entry->valid = 1; + entry->okey = okey; + + + if (insert != NULL) + insert->next = entry; + + dict->nbElems++; + + if ((nbi > MAX_HASH_LEN) && + (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN))) { + if (xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size) != 0) + return(NULL); + } + /* Note that entry may have been freed at this point by xmlDictGrow */ + + return(ret); +} + +/** + * xmlDictExists: + * @dict: the dictionnary + * @name: the name of the userdata + * @len: the length of the name, if -1 it is recomputed + * + * Check if the @name exists in the dictionnary @dict. + * + * Returns the internal copy of the name or NULL if not found. + */ +const xmlChar * +xmlDictExists(xmlDictPtr dict, const xmlChar *name, int len) { + unsigned long key, okey, nbi = 0; + xmlDictEntryPtr insert; + + if ((dict == NULL) || (name == NULL)) + return(NULL); + + if (len < 0) + len = strlen((const char *) name); + + /* + * Check for duplicate and insertion location. + */ + okey = xmlDictComputeKey(dict, name, len); + key = okey % dict->size; + if (dict->dict[key].valid == 0) { + insert = NULL; + } else { + for (insert = &(dict->dict[key]); insert->next != NULL; + insert = insert->next) { +#ifdef __GNUC__ + if ((insert->okey == okey) && (insert->len == len)) { + if (!memcmp(insert->name, name, len)) + return(insert->name); + } +#else + if ((insert->okey == okey) && (insert->len == len) && + (!xmlStrncmp(insert->name, name, len))) + return(insert->name); +#endif + nbi++; + } +#ifdef __GNUC__ + if ((insert->okey == okey) && (insert->len == len)) { + if (!memcmp(insert->name, name, len)) + return(insert->name); + } +#else + if ((insert->okey == okey) && (insert->len == len) && + (!xmlStrncmp(insert->name, name, len))) + return(insert->name); +#endif + } + + if (dict->subdict) { + unsigned long skey; + + /* we cannot always reuse the same okey for the subdict */ + if (((dict->size == MIN_DICT_SIZE) && + (dict->subdict->size != MIN_DICT_SIZE)) || + ((dict->size != MIN_DICT_SIZE) && + (dict->subdict->size == MIN_DICT_SIZE))) + skey = xmlDictComputeKey(dict->subdict, name, len); + else + skey = okey; + + key = skey % dict->subdict->size; + if (dict->subdict->dict[key].valid != 0) { + xmlDictEntryPtr tmp; + + for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL; + tmp = tmp->next) { +#ifdef __GNUC__ + if ((tmp->okey == skey) && (tmp->len == len)) { + if (!memcmp(tmp->name, name, len)) + return(tmp->name); + } +#else + if ((tmp->okey == skey) && (tmp->len == len) && + (!xmlStrncmp(tmp->name, name, len))) + return(tmp->name); +#endif + nbi++; + } +#ifdef __GNUC__ + if ((tmp->okey == skey) && (tmp->len == len)) { + if (!memcmp(tmp->name, name, len)) + return(tmp->name); + } +#else + if ((tmp->okey == skey) && (tmp->len == len) && + (!xmlStrncmp(tmp->name, name, len))) + return(tmp->name); +#endif + } + } + + /* not found */ + return(NULL); +} + +/** + * xmlDictQLookup: + * @dict: the dictionnary + * @prefix: the prefix + * @name: the name + * + * Add the QName @prefix:@name to the hash @dict if not present. + * + * Returns the internal copy of the QName or NULL in case of internal error + */ +const xmlChar * +xmlDictQLookup(xmlDictPtr dict, const xmlChar *prefix, const xmlChar *name) { + unsigned long okey, key, nbi = 0; + xmlDictEntryPtr entry; + xmlDictEntryPtr insert; + const xmlChar *ret; + int len, plen, l; + + if ((dict == NULL) || (name == NULL)) + return(NULL); + if (prefix == NULL) + return(xmlDictLookup(dict, name, -1)); + + l = len = strlen((const char *) name); + plen = strlen((const char *) prefix); + len += 1 + plen; + + /* + * Check for duplicate and insertion location. + */ + okey = xmlDictComputeQKey(dict, prefix, plen, name, l); + key = okey % dict->size; + if (dict->dict[key].valid == 0) { + insert = NULL; + } else { + for (insert = &(dict->dict[key]); insert->next != NULL; + insert = insert->next) { + if ((insert->okey == okey) && (insert->len == len) && + (xmlStrQEqual(prefix, name, insert->name))) + return(insert->name); + nbi++; + } + if ((insert->okey == okey) && (insert->len == len) && + (xmlStrQEqual(prefix, name, insert->name))) + return(insert->name); + } + + if (dict->subdict) { + unsigned long skey; + + /* we cannot always reuse the same okey for the subdict */ + if (((dict->size == MIN_DICT_SIZE) && + (dict->subdict->size != MIN_DICT_SIZE)) || + ((dict->size != MIN_DICT_SIZE) && + (dict->subdict->size == MIN_DICT_SIZE))) + skey = xmlDictComputeQKey(dict->subdict, prefix, plen, name, l); + else + skey = okey; + + key = skey % dict->subdict->size; + if (dict->subdict->dict[key].valid != 0) { + xmlDictEntryPtr tmp; + for (tmp = &(dict->subdict->dict[key]); tmp->next != NULL; + tmp = tmp->next) { + if ((tmp->okey == skey) && (tmp->len == len) && + (xmlStrQEqual(prefix, name, tmp->name))) + return(tmp->name); + nbi++; + } + if ((tmp->okey == skey) && (tmp->len == len) && + (xmlStrQEqual(prefix, name, tmp->name))) + return(tmp->name); + } + key = okey % dict->size; + } + + ret = xmlDictAddQString(dict, prefix, plen, name, l); + if (ret == NULL) + return(NULL); + if (insert == NULL) { + entry = &(dict->dict[key]); + } else { + entry = xmlMalloc(sizeof(xmlDictEntry)); + if (entry == NULL) + return(NULL); + } + entry->name = ret; + entry->len = len; + entry->next = NULL; + entry->valid = 1; + entry->okey = okey; + + if (insert != NULL) + insert->next = entry; + + dict->nbElems++; + + if ((nbi > MAX_HASH_LEN) && + (dict->size <= ((MAX_DICT_HASH / 2) / MAX_HASH_LEN))) + xmlDictGrow(dict, MAX_HASH_LEN * 2 * dict->size); + /* Note that entry may have been freed at this point by xmlDictGrow */ + + return(ret); +} + +/** + * xmlDictOwns: + * @dict: the dictionnary + * @str: the string + * + * check if a string is owned by the disctionary + * + * Returns 1 if true, 0 if false and -1 in case of error + * -1 in case of error + */ +int +xmlDictOwns(xmlDictPtr dict, const xmlChar *str) { + xmlDictStringsPtr pool; + + if ((dict == NULL) || (str == NULL)) + return(-1); + pool = dict->strings; + while (pool != NULL) { + if ((str >= &pool->array[0]) && (str <= pool->free)) + return(1); + pool = pool->next; + } + if (dict->subdict) + return(xmlDictOwns(dict->subdict, str)); + return(0); +} + +/** + * xmlDictSize: + * @dict: the dictionnary + * + * Query the number of elements installed in the hash @dict. + * + * Returns the number of elements in the dictionnary or + * -1 in case of error + */ +int +xmlDictSize(xmlDictPtr dict) { + if (dict == NULL) + return(-1); + if (dict->subdict) + return(dict->nbElems + dict->subdict->nbElems); + return(dict->nbElems); +} + + +#define bottom_dict +#include "elfgcchack.h" diff --git a/android/native/libxml2/elfgcchack.h b/android/native/libxml2/elfgcchack.h new file mode 100644 index 0000000000..301ea0cd3a --- /dev/null +++ b/android/native/libxml2/elfgcchack.h @@ -0,0 +1,16314 @@ +/* + * elfgcchack.h: hack by Arjan van de Ven to speed + * up the code when using gcc for call within the library. + * + * Based on the analysis http://people.redhat.com/drepper/dsohowto.pdf + * from Ulrich drepper. Rewritten to be generated from the XML description + * file for libxml2 API + * autogenerated with xsltproc doc/elfgcchack.xsl doc/libxml2-api.xml + */ + +#ifdef IN_LIBXML +#ifdef __GNUC__ +#ifdef PIC +#ifdef linux +#if (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) || (__GNUC__ > 3) + +#include "libxml/c14n.h" +#include "libxml/catalog.h" +#include "libxml/chvalid.h" +#include "libxml/debugXML.h" +#include "libxml/dict.h" +#include "libxml/DOCBparser.h" +#include "libxml/encoding.h" +#include "libxml/entities.h" +#include "libxml/globals.h" +#include "libxml/hash.h" +#include "libxml/HTMLparser.h" +#include "libxml/HTMLtree.h" +#include "libxml/list.h" +#include "libxml/nanoftp.h" +#include "libxml/nanohttp.h" +#include "libxml/parser.h" +#include "libxml/parserInternals.h" +#include "libxml/pattern.h" +#include "libxml/relaxng.h" +#include "libxml/SAX2.h" +#include "libxml/SAX.h" +#include "libxml/schemasInternals.h" +#include "libxml/schematron.h" +#include "libxml/threads.h" +#include "libxml/tree.h" +#include "libxml/uri.h" +#include "libxml/valid.h" +#include "libxml/xinclude.h" +#include "libxml/xlink.h" +#include "libxml/xmlautomata.h" +#include "libxml/xmlerror.h" +#include "libxml/xmlexports.h" +#include "libxml/xmlIO.h" +#include "libxml/xmlmemory.h" +#include "libxml/xmlreader.h" +#include "libxml/xmlregexp.h" +#include "libxml/xmlsave.h" +#include "libxml/xmlschemas.h" +#include "libxml/xmlschemastypes.h" +#include "libxml/xmlstring.h" +#include "libxml/xmlunicode.h" +#include "libxml/xmlversion.h" +#include "libxml/xmlwriter.h" +#include "libxml/xpath.h" +#include "libxml/xpathInternals.h" +#include "libxml/xpointer.h" +#include "libxml/xmlmodule.h" + +/* special hot spot not exported ones */ + +#ifdef bottom_globals +#undef __xmlGenericError +extern __typeof (__xmlGenericError) __xmlGenericError __attribute((alias("__xmlGenericError__internal_alias"))); +#else +#ifndef __xmlGenericError +extern __typeof (__xmlGenericError) __xmlGenericError__internal_alias __attribute((visibility("hidden"))); +#define __xmlGenericError __xmlGenericError__internal_alias +#endif +#endif + +#ifdef bottom_globals +#undef __xmlGenericErrorContext +extern __typeof (__xmlGenericErrorContext) __xmlGenericErrorContext __attribute((alias("__xmlGenericErrorContext__internal_alias"))); +#else +#ifndef __xmlGenericErrorContext +extern __typeof (__xmlGenericErrorContext) __xmlGenericErrorContext__internal_alias __attribute((visibility("hidden"))); +#define __xmlGenericErrorContext __xmlGenericErrorContext__internal_alias +#endif +#endif + +/* list generated from libxml2-api.xml */ +#if defined(LIBXML_DOCB_ENABLED) +#ifdef bottom_DOCBparser +#undef docbCreatePushParserCtxt +extern __typeof (docbCreatePushParserCtxt) docbCreatePushParserCtxt __attribute((alias("docbCreatePushParserCtxt__internal_alias"))); +#else +#ifndef docbCreatePushParserCtxt +extern __typeof (docbCreatePushParserCtxt) docbCreatePushParserCtxt__internal_alias __attribute((visibility("hidden"))); +#define docbCreatePushParserCtxt docbCreatePushParserCtxt__internal_alias +#endif +#endif +#endif + +#ifdef bottom_parser +#undef inputPop +extern __typeof (inputPop) inputPop __attribute((alias("inputPop__internal_alias"))); +#else +#ifndef inputPop +extern __typeof (inputPop) inputPop__internal_alias __attribute((visibility("hidden"))); +#define inputPop inputPop__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef inputPush +extern __typeof (inputPush) inputPush __attribute((alias("inputPush__internal_alias"))); +#else +#ifndef inputPush +extern __typeof (inputPush) inputPush__internal_alias __attribute((visibility("hidden"))); +#define inputPush inputPush__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef namePop +extern __typeof (namePop) namePop __attribute((alias("namePop__internal_alias"))); +#else +#ifndef namePop +extern __typeof (namePop) namePop__internal_alias __attribute((visibility("hidden"))); +#define namePop namePop__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef namePush +extern __typeof (namePush) namePush __attribute((alias("namePush__internal_alias"))); +#else +#ifndef namePush +extern __typeof (namePush) namePush__internal_alias __attribute((visibility("hidden"))); +#define namePush namePush__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef nodePop +extern __typeof (nodePop) nodePop __attribute((alias("nodePop__internal_alias"))); +#else +#ifndef nodePop +extern __typeof (nodePop) nodePop__internal_alias __attribute((visibility("hidden"))); +#define nodePop nodePop__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef nodePush +extern __typeof (nodePush) nodePush __attribute((alias("nodePush__internal_alias"))); +#else +#ifndef nodePush +extern __typeof (nodePush) nodePush__internal_alias __attribute((visibility("hidden"))); +#define nodePush nodePush__internal_alias +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef valuePop +extern __typeof (valuePop) valuePop __attribute((alias("valuePop__internal_alias"))); +#else +#ifndef valuePop +extern __typeof (valuePop) valuePop__internal_alias __attribute((visibility("hidden"))); +#define valuePop valuePop__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef valuePush +extern __typeof (valuePush) valuePush __attribute((alias("valuePush__internal_alias"))); +#else +#ifndef valuePush +extern __typeof (valuePush) valuePush__internal_alias __attribute((visibility("hidden"))); +#define valuePush valuePush__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_CATALOG_ENABLED) +#ifdef bottom_catalog +#undef xmlACatalogAdd +extern __typeof (xmlACatalogAdd) xmlACatalogAdd __attribute((alias("xmlACatalogAdd__internal_alias"))); +#else +#ifndef xmlACatalogAdd +extern __typeof (xmlACatalogAdd) xmlACatalogAdd__internal_alias __attribute((visibility("hidden"))); +#define xmlACatalogAdd xmlACatalogAdd__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_CATALOG_ENABLED) && defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_catalog +#undef xmlACatalogDump +extern __typeof (xmlACatalogDump) xmlACatalogDump __attribute((alias("xmlACatalogDump__internal_alias"))); +#else +#ifndef xmlACatalogDump +extern __typeof (xmlACatalogDump) xmlACatalogDump__internal_alias __attribute((visibility("hidden"))); +#define xmlACatalogDump xmlACatalogDump__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_CATALOG_ENABLED) +#ifdef bottom_catalog +#undef xmlACatalogRemove +extern __typeof (xmlACatalogRemove) xmlACatalogRemove __attribute((alias("xmlACatalogRemove__internal_alias"))); +#else +#ifndef xmlACatalogRemove +extern __typeof (xmlACatalogRemove) xmlACatalogRemove__internal_alias __attribute((visibility("hidden"))); +#define xmlACatalogRemove xmlACatalogRemove__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_CATALOG_ENABLED) +#ifdef bottom_catalog +#undef xmlACatalogResolve +extern __typeof (xmlACatalogResolve) xmlACatalogResolve __attribute((alias("xmlACatalogResolve__internal_alias"))); +#else +#ifndef xmlACatalogResolve +extern __typeof (xmlACatalogResolve) xmlACatalogResolve__internal_alias __attribute((visibility("hidden"))); +#define xmlACatalogResolve xmlACatalogResolve__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_CATALOG_ENABLED) +#ifdef bottom_catalog +#undef xmlACatalogResolvePublic +extern __typeof (xmlACatalogResolvePublic) xmlACatalogResolvePublic __attribute((alias("xmlACatalogResolvePublic__internal_alias"))); +#else +#ifndef xmlACatalogResolvePublic +extern __typeof (xmlACatalogResolvePublic) xmlACatalogResolvePublic__internal_alias __attribute((visibility("hidden"))); +#define xmlACatalogResolvePublic xmlACatalogResolvePublic__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_CATALOG_ENABLED) +#ifdef bottom_catalog +#undef xmlACatalogResolveSystem +extern __typeof (xmlACatalogResolveSystem) xmlACatalogResolveSystem __attribute((alias("xmlACatalogResolveSystem__internal_alias"))); +#else +#ifndef xmlACatalogResolveSystem +extern __typeof (xmlACatalogResolveSystem) xmlACatalogResolveSystem__internal_alias __attribute((visibility("hidden"))); +#define xmlACatalogResolveSystem xmlACatalogResolveSystem__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_CATALOG_ENABLED) +#ifdef bottom_catalog +#undef xmlACatalogResolveURI +extern __typeof (xmlACatalogResolveURI) xmlACatalogResolveURI __attribute((alias("xmlACatalogResolveURI__internal_alias"))); +#else +#ifndef xmlACatalogResolveURI +extern __typeof (xmlACatalogResolveURI) xmlACatalogResolveURI__internal_alias __attribute((visibility("hidden"))); +#define xmlACatalogResolveURI xmlACatalogResolveURI__internal_alias +#endif +#endif +#endif + +#ifdef bottom_valid +#undef xmlAddAttributeDecl +extern __typeof (xmlAddAttributeDecl) xmlAddAttributeDecl __attribute((alias("xmlAddAttributeDecl__internal_alias"))); +#else +#ifndef xmlAddAttributeDecl +extern __typeof (xmlAddAttributeDecl) xmlAddAttributeDecl__internal_alias __attribute((visibility("hidden"))); +#define xmlAddAttributeDecl xmlAddAttributeDecl__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlAddChild +extern __typeof (xmlAddChild) xmlAddChild __attribute((alias("xmlAddChild__internal_alias"))); +#else +#ifndef xmlAddChild +extern __typeof (xmlAddChild) xmlAddChild__internal_alias __attribute((visibility("hidden"))); +#define xmlAddChild xmlAddChild__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlAddChildList +extern __typeof (xmlAddChildList) xmlAddChildList __attribute((alias("xmlAddChildList__internal_alias"))); +#else +#ifndef xmlAddChildList +extern __typeof (xmlAddChildList) xmlAddChildList__internal_alias __attribute((visibility("hidden"))); +#define xmlAddChildList xmlAddChildList__internal_alias +#endif +#endif + +#ifdef bottom_entities +#undef xmlAddDocEntity +extern __typeof (xmlAddDocEntity) xmlAddDocEntity __attribute((alias("xmlAddDocEntity__internal_alias"))); +#else +#ifndef xmlAddDocEntity +extern __typeof (xmlAddDocEntity) xmlAddDocEntity__internal_alias __attribute((visibility("hidden"))); +#define xmlAddDocEntity xmlAddDocEntity__internal_alias +#endif +#endif + +#ifdef bottom_entities +#undef xmlAddDtdEntity +extern __typeof (xmlAddDtdEntity) xmlAddDtdEntity __attribute((alias("xmlAddDtdEntity__internal_alias"))); +#else +#ifndef xmlAddDtdEntity +extern __typeof (xmlAddDtdEntity) xmlAddDtdEntity__internal_alias __attribute((visibility("hidden"))); +#define xmlAddDtdEntity xmlAddDtdEntity__internal_alias +#endif +#endif + +#ifdef bottom_valid +#undef xmlAddElementDecl +extern __typeof (xmlAddElementDecl) xmlAddElementDecl __attribute((alias("xmlAddElementDecl__internal_alias"))); +#else +#ifndef xmlAddElementDecl +extern __typeof (xmlAddElementDecl) xmlAddElementDecl__internal_alias __attribute((visibility("hidden"))); +#define xmlAddElementDecl xmlAddElementDecl__internal_alias +#endif +#endif + +#ifdef bottom_encoding +#undef xmlAddEncodingAlias +extern __typeof (xmlAddEncodingAlias) xmlAddEncodingAlias __attribute((alias("xmlAddEncodingAlias__internal_alias"))); +#else +#ifndef xmlAddEncodingAlias +extern __typeof (xmlAddEncodingAlias) xmlAddEncodingAlias__internal_alias __attribute((visibility("hidden"))); +#define xmlAddEncodingAlias xmlAddEncodingAlias__internal_alias +#endif +#endif + +#ifdef bottom_valid +#undef xmlAddID +extern __typeof (xmlAddID) xmlAddID __attribute((alias("xmlAddID__internal_alias"))); +#else +#ifndef xmlAddID +extern __typeof (xmlAddID) xmlAddID__internal_alias __attribute((visibility("hidden"))); +#define xmlAddID xmlAddID__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlAddNextSibling +extern __typeof (xmlAddNextSibling) xmlAddNextSibling __attribute((alias("xmlAddNextSibling__internal_alias"))); +#else +#ifndef xmlAddNextSibling +extern __typeof (xmlAddNextSibling) xmlAddNextSibling__internal_alias __attribute((visibility("hidden"))); +#define xmlAddNextSibling xmlAddNextSibling__internal_alias +#endif +#endif + +#ifdef bottom_valid +#undef xmlAddNotationDecl +extern __typeof (xmlAddNotationDecl) xmlAddNotationDecl __attribute((alias("xmlAddNotationDecl__internal_alias"))); +#else +#ifndef xmlAddNotationDecl +extern __typeof (xmlAddNotationDecl) xmlAddNotationDecl__internal_alias __attribute((visibility("hidden"))); +#define xmlAddNotationDecl xmlAddNotationDecl__internal_alias +#endif +#endif + +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_tree +#undef xmlAddPrevSibling +extern __typeof (xmlAddPrevSibling) xmlAddPrevSibling __attribute((alias("xmlAddPrevSibling__internal_alias"))); +#else +#ifndef xmlAddPrevSibling +extern __typeof (xmlAddPrevSibling) xmlAddPrevSibling__internal_alias __attribute((visibility("hidden"))); +#define xmlAddPrevSibling xmlAddPrevSibling__internal_alias +#endif +#endif +#endif + +#ifdef bottom_valid +#undef xmlAddRef +extern __typeof (xmlAddRef) xmlAddRef __attribute((alias("xmlAddRef__internal_alias"))); +#else +#ifndef xmlAddRef +extern __typeof (xmlAddRef) xmlAddRef__internal_alias __attribute((visibility("hidden"))); +#define xmlAddRef xmlAddRef__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlAddSibling +extern __typeof (xmlAddSibling) xmlAddSibling __attribute((alias("xmlAddSibling__internal_alias"))); +#else +#ifndef xmlAddSibling +extern __typeof (xmlAddSibling) xmlAddSibling__internal_alias __attribute((visibility("hidden"))); +#define xmlAddSibling xmlAddSibling__internal_alias +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_xmlIO +#undef xmlAllocOutputBuffer +extern __typeof (xmlAllocOutputBuffer) xmlAllocOutputBuffer __attribute((alias("xmlAllocOutputBuffer__internal_alias"))); +#else +#ifndef xmlAllocOutputBuffer +extern __typeof (xmlAllocOutputBuffer) xmlAllocOutputBuffer__internal_alias __attribute((visibility("hidden"))); +#define xmlAllocOutputBuffer xmlAllocOutputBuffer__internal_alias +#endif +#endif +#endif + +#ifdef bottom_xmlIO +#undef xmlAllocParserInputBuffer +extern __typeof (xmlAllocParserInputBuffer) xmlAllocParserInputBuffer __attribute((alias("xmlAllocParserInputBuffer__internal_alias"))); +#else +#ifndef xmlAllocParserInputBuffer +extern __typeof (xmlAllocParserInputBuffer) xmlAllocParserInputBuffer__internal_alias __attribute((visibility("hidden"))); +#define xmlAllocParserInputBuffer xmlAllocParserInputBuffer__internal_alias +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_xmlsave +#undef xmlAttrSerializeTxtContent +extern __typeof (xmlAttrSerializeTxtContent) xmlAttrSerializeTxtContent __attribute((alias("xmlAttrSerializeTxtContent__internal_alias"))); +#else +#ifndef xmlAttrSerializeTxtContent +extern __typeof (xmlAttrSerializeTxtContent) xmlAttrSerializeTxtContent__internal_alias __attribute((visibility("hidden"))); +#define xmlAttrSerializeTxtContent xmlAttrSerializeTxtContent__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) && defined(LIBXML_AUTOMATA_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlAutomataCompile +extern __typeof (xmlAutomataCompile) xmlAutomataCompile __attribute((alias("xmlAutomataCompile__internal_alias"))); +#else +#ifndef xmlAutomataCompile +extern __typeof (xmlAutomataCompile) xmlAutomataCompile__internal_alias __attribute((visibility("hidden"))); +#define xmlAutomataCompile xmlAutomataCompile__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) && defined(LIBXML_AUTOMATA_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlAutomataGetInitState +extern __typeof (xmlAutomataGetInitState) xmlAutomataGetInitState __attribute((alias("xmlAutomataGetInitState__internal_alias"))); +#else +#ifndef xmlAutomataGetInitState +extern __typeof (xmlAutomataGetInitState) xmlAutomataGetInitState__internal_alias __attribute((visibility("hidden"))); +#define xmlAutomataGetInitState xmlAutomataGetInitState__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) && defined(LIBXML_AUTOMATA_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlAutomataIsDeterminist +extern __typeof (xmlAutomataIsDeterminist) xmlAutomataIsDeterminist __attribute((alias("xmlAutomataIsDeterminist__internal_alias"))); +#else +#ifndef xmlAutomataIsDeterminist +extern __typeof (xmlAutomataIsDeterminist) xmlAutomataIsDeterminist__internal_alias __attribute((visibility("hidden"))); +#define xmlAutomataIsDeterminist xmlAutomataIsDeterminist__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) && defined(LIBXML_AUTOMATA_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlAutomataNewAllTrans +extern __typeof (xmlAutomataNewAllTrans) xmlAutomataNewAllTrans __attribute((alias("xmlAutomataNewAllTrans__internal_alias"))); +#else +#ifndef xmlAutomataNewAllTrans +extern __typeof (xmlAutomataNewAllTrans) xmlAutomataNewAllTrans__internal_alias __attribute((visibility("hidden"))); +#define xmlAutomataNewAllTrans xmlAutomataNewAllTrans__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) && defined(LIBXML_AUTOMATA_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlAutomataNewCountTrans +extern __typeof (xmlAutomataNewCountTrans) xmlAutomataNewCountTrans __attribute((alias("xmlAutomataNewCountTrans__internal_alias"))); +#else +#ifndef xmlAutomataNewCountTrans +extern __typeof (xmlAutomataNewCountTrans) xmlAutomataNewCountTrans__internal_alias __attribute((visibility("hidden"))); +#define xmlAutomataNewCountTrans xmlAutomataNewCountTrans__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) && defined(LIBXML_AUTOMATA_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlAutomataNewCountTrans2 +extern __typeof (xmlAutomataNewCountTrans2) xmlAutomataNewCountTrans2 __attribute((alias("xmlAutomataNewCountTrans2__internal_alias"))); +#else +#ifndef xmlAutomataNewCountTrans2 +extern __typeof (xmlAutomataNewCountTrans2) xmlAutomataNewCountTrans2__internal_alias __attribute((visibility("hidden"))); +#define xmlAutomataNewCountTrans2 xmlAutomataNewCountTrans2__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) && defined(LIBXML_AUTOMATA_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlAutomataNewCountedTrans +extern __typeof (xmlAutomataNewCountedTrans) xmlAutomataNewCountedTrans __attribute((alias("xmlAutomataNewCountedTrans__internal_alias"))); +#else +#ifndef xmlAutomataNewCountedTrans +extern __typeof (xmlAutomataNewCountedTrans) xmlAutomataNewCountedTrans__internal_alias __attribute((visibility("hidden"))); +#define xmlAutomataNewCountedTrans xmlAutomataNewCountedTrans__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) && defined(LIBXML_AUTOMATA_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlAutomataNewCounter +extern __typeof (xmlAutomataNewCounter) xmlAutomataNewCounter __attribute((alias("xmlAutomataNewCounter__internal_alias"))); +#else +#ifndef xmlAutomataNewCounter +extern __typeof (xmlAutomataNewCounter) xmlAutomataNewCounter__internal_alias __attribute((visibility("hidden"))); +#define xmlAutomataNewCounter xmlAutomataNewCounter__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) && defined(LIBXML_AUTOMATA_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlAutomataNewCounterTrans +extern __typeof (xmlAutomataNewCounterTrans) xmlAutomataNewCounterTrans __attribute((alias("xmlAutomataNewCounterTrans__internal_alias"))); +#else +#ifndef xmlAutomataNewCounterTrans +extern __typeof (xmlAutomataNewCounterTrans) xmlAutomataNewCounterTrans__internal_alias __attribute((visibility("hidden"))); +#define xmlAutomataNewCounterTrans xmlAutomataNewCounterTrans__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) && defined(LIBXML_AUTOMATA_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlAutomataNewEpsilon +extern __typeof (xmlAutomataNewEpsilon) xmlAutomataNewEpsilon __attribute((alias("xmlAutomataNewEpsilon__internal_alias"))); +#else +#ifndef xmlAutomataNewEpsilon +extern __typeof (xmlAutomataNewEpsilon) xmlAutomataNewEpsilon__internal_alias __attribute((visibility("hidden"))); +#define xmlAutomataNewEpsilon xmlAutomataNewEpsilon__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) && defined(LIBXML_AUTOMATA_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlAutomataNewNegTrans +extern __typeof (xmlAutomataNewNegTrans) xmlAutomataNewNegTrans __attribute((alias("xmlAutomataNewNegTrans__internal_alias"))); +#else +#ifndef xmlAutomataNewNegTrans +extern __typeof (xmlAutomataNewNegTrans) xmlAutomataNewNegTrans__internal_alias __attribute((visibility("hidden"))); +#define xmlAutomataNewNegTrans xmlAutomataNewNegTrans__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) && defined(LIBXML_AUTOMATA_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlAutomataNewOnceTrans +extern __typeof (xmlAutomataNewOnceTrans) xmlAutomataNewOnceTrans __attribute((alias("xmlAutomataNewOnceTrans__internal_alias"))); +#else +#ifndef xmlAutomataNewOnceTrans +extern __typeof (xmlAutomataNewOnceTrans) xmlAutomataNewOnceTrans__internal_alias __attribute((visibility("hidden"))); +#define xmlAutomataNewOnceTrans xmlAutomataNewOnceTrans__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) && defined(LIBXML_AUTOMATA_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlAutomataNewOnceTrans2 +extern __typeof (xmlAutomataNewOnceTrans2) xmlAutomataNewOnceTrans2 __attribute((alias("xmlAutomataNewOnceTrans2__internal_alias"))); +#else +#ifndef xmlAutomataNewOnceTrans2 +extern __typeof (xmlAutomataNewOnceTrans2) xmlAutomataNewOnceTrans2__internal_alias __attribute((visibility("hidden"))); +#define xmlAutomataNewOnceTrans2 xmlAutomataNewOnceTrans2__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) && defined(LIBXML_AUTOMATA_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlAutomataNewState +extern __typeof (xmlAutomataNewState) xmlAutomataNewState __attribute((alias("xmlAutomataNewState__internal_alias"))); +#else +#ifndef xmlAutomataNewState +extern __typeof (xmlAutomataNewState) xmlAutomataNewState__internal_alias __attribute((visibility("hidden"))); +#define xmlAutomataNewState xmlAutomataNewState__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) && defined(LIBXML_AUTOMATA_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlAutomataNewTransition +extern __typeof (xmlAutomataNewTransition) xmlAutomataNewTransition __attribute((alias("xmlAutomataNewTransition__internal_alias"))); +#else +#ifndef xmlAutomataNewTransition +extern __typeof (xmlAutomataNewTransition) xmlAutomataNewTransition__internal_alias __attribute((visibility("hidden"))); +#define xmlAutomataNewTransition xmlAutomataNewTransition__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) && defined(LIBXML_AUTOMATA_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlAutomataNewTransition2 +extern __typeof (xmlAutomataNewTransition2) xmlAutomataNewTransition2 __attribute((alias("xmlAutomataNewTransition2__internal_alias"))); +#else +#ifndef xmlAutomataNewTransition2 +extern __typeof (xmlAutomataNewTransition2) xmlAutomataNewTransition2__internal_alias __attribute((visibility("hidden"))); +#define xmlAutomataNewTransition2 xmlAutomataNewTransition2__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) && defined(LIBXML_AUTOMATA_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlAutomataSetFinalState +extern __typeof (xmlAutomataSetFinalState) xmlAutomataSetFinalState __attribute((alias("xmlAutomataSetFinalState__internal_alias"))); +#else +#ifndef xmlAutomataSetFinalState +extern __typeof (xmlAutomataSetFinalState) xmlAutomataSetFinalState__internal_alias __attribute((visibility("hidden"))); +#define xmlAutomataSetFinalState xmlAutomataSetFinalState__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_DEBUG_ENABLED) +#ifdef bottom_debugXML +#undef xmlBoolToText +extern __typeof (xmlBoolToText) xmlBoolToText __attribute((alias("xmlBoolToText__internal_alias"))); +#else +#ifndef xmlBoolToText +extern __typeof (xmlBoolToText) xmlBoolToText__internal_alias __attribute((visibility("hidden"))); +#define xmlBoolToText xmlBoolToText__internal_alias +#endif +#endif +#endif + +#ifdef bottom_tree +#undef xmlBufferAdd +extern __typeof (xmlBufferAdd) xmlBufferAdd __attribute((alias("xmlBufferAdd__internal_alias"))); +#else +#ifndef xmlBufferAdd +extern __typeof (xmlBufferAdd) xmlBufferAdd__internal_alias __attribute((visibility("hidden"))); +#define xmlBufferAdd xmlBufferAdd__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlBufferAddHead +extern __typeof (xmlBufferAddHead) xmlBufferAddHead __attribute((alias("xmlBufferAddHead__internal_alias"))); +#else +#ifndef xmlBufferAddHead +extern __typeof (xmlBufferAddHead) xmlBufferAddHead__internal_alias __attribute((visibility("hidden"))); +#define xmlBufferAddHead xmlBufferAddHead__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlBufferCCat +extern __typeof (xmlBufferCCat) xmlBufferCCat __attribute((alias("xmlBufferCCat__internal_alias"))); +#else +#ifndef xmlBufferCCat +extern __typeof (xmlBufferCCat) xmlBufferCCat__internal_alias __attribute((visibility("hidden"))); +#define xmlBufferCCat xmlBufferCCat__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlBufferCat +extern __typeof (xmlBufferCat) xmlBufferCat __attribute((alias("xmlBufferCat__internal_alias"))); +#else +#ifndef xmlBufferCat +extern __typeof (xmlBufferCat) xmlBufferCat__internal_alias __attribute((visibility("hidden"))); +#define xmlBufferCat xmlBufferCat__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlBufferContent +extern __typeof (xmlBufferContent) xmlBufferContent __attribute((alias("xmlBufferContent__internal_alias"))); +#else +#ifndef xmlBufferContent +extern __typeof (xmlBufferContent) xmlBufferContent__internal_alias __attribute((visibility("hidden"))); +#define xmlBufferContent xmlBufferContent__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlBufferCreate +extern __typeof (xmlBufferCreate) xmlBufferCreate __attribute((alias("xmlBufferCreate__internal_alias"))); +#else +#ifndef xmlBufferCreate +extern __typeof (xmlBufferCreate) xmlBufferCreate__internal_alias __attribute((visibility("hidden"))); +#define xmlBufferCreate xmlBufferCreate__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlBufferCreateSize +extern __typeof (xmlBufferCreateSize) xmlBufferCreateSize __attribute((alias("xmlBufferCreateSize__internal_alias"))); +#else +#ifndef xmlBufferCreateSize +extern __typeof (xmlBufferCreateSize) xmlBufferCreateSize__internal_alias __attribute((visibility("hidden"))); +#define xmlBufferCreateSize xmlBufferCreateSize__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlBufferCreateStatic +extern __typeof (xmlBufferCreateStatic) xmlBufferCreateStatic __attribute((alias("xmlBufferCreateStatic__internal_alias"))); +#else +#ifndef xmlBufferCreateStatic +extern __typeof (xmlBufferCreateStatic) xmlBufferCreateStatic__internal_alias __attribute((visibility("hidden"))); +#define xmlBufferCreateStatic xmlBufferCreateStatic__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlBufferDump +extern __typeof (xmlBufferDump) xmlBufferDump __attribute((alias("xmlBufferDump__internal_alias"))); +#else +#ifndef xmlBufferDump +extern __typeof (xmlBufferDump) xmlBufferDump__internal_alias __attribute((visibility("hidden"))); +#define xmlBufferDump xmlBufferDump__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlBufferEmpty +extern __typeof (xmlBufferEmpty) xmlBufferEmpty __attribute((alias("xmlBufferEmpty__internal_alias"))); +#else +#ifndef xmlBufferEmpty +extern __typeof (xmlBufferEmpty) xmlBufferEmpty__internal_alias __attribute((visibility("hidden"))); +#define xmlBufferEmpty xmlBufferEmpty__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlBufferFree +extern __typeof (xmlBufferFree) xmlBufferFree __attribute((alias("xmlBufferFree__internal_alias"))); +#else +#ifndef xmlBufferFree +extern __typeof (xmlBufferFree) xmlBufferFree__internal_alias __attribute((visibility("hidden"))); +#define xmlBufferFree xmlBufferFree__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlBufferGrow +extern __typeof (xmlBufferGrow) xmlBufferGrow __attribute((alias("xmlBufferGrow__internal_alias"))); +#else +#ifndef xmlBufferGrow +extern __typeof (xmlBufferGrow) xmlBufferGrow__internal_alias __attribute((visibility("hidden"))); +#define xmlBufferGrow xmlBufferGrow__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlBufferLength +extern __typeof (xmlBufferLength) xmlBufferLength __attribute((alias("xmlBufferLength__internal_alias"))); +#else +#ifndef xmlBufferLength +extern __typeof (xmlBufferLength) xmlBufferLength__internal_alias __attribute((visibility("hidden"))); +#define xmlBufferLength xmlBufferLength__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlBufferResize +extern __typeof (xmlBufferResize) xmlBufferResize __attribute((alias("xmlBufferResize__internal_alias"))); +#else +#ifndef xmlBufferResize +extern __typeof (xmlBufferResize) xmlBufferResize__internal_alias __attribute((visibility("hidden"))); +#define xmlBufferResize xmlBufferResize__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlBufferSetAllocationScheme +extern __typeof (xmlBufferSetAllocationScheme) xmlBufferSetAllocationScheme __attribute((alias("xmlBufferSetAllocationScheme__internal_alias"))); +#else +#ifndef xmlBufferSetAllocationScheme +extern __typeof (xmlBufferSetAllocationScheme) xmlBufferSetAllocationScheme__internal_alias __attribute((visibility("hidden"))); +#define xmlBufferSetAllocationScheme xmlBufferSetAllocationScheme__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlBufferShrink +extern __typeof (xmlBufferShrink) xmlBufferShrink __attribute((alias("xmlBufferShrink__internal_alias"))); +#else +#ifndef xmlBufferShrink +extern __typeof (xmlBufferShrink) xmlBufferShrink__internal_alias __attribute((visibility("hidden"))); +#define xmlBufferShrink xmlBufferShrink__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlBufferWriteCHAR +extern __typeof (xmlBufferWriteCHAR) xmlBufferWriteCHAR __attribute((alias("xmlBufferWriteCHAR__internal_alias"))); +#else +#ifndef xmlBufferWriteCHAR +extern __typeof (xmlBufferWriteCHAR) xmlBufferWriteCHAR__internal_alias __attribute((visibility("hidden"))); +#define xmlBufferWriteCHAR xmlBufferWriteCHAR__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlBufferWriteChar +extern __typeof (xmlBufferWriteChar) xmlBufferWriteChar __attribute((alias("xmlBufferWriteChar__internal_alias"))); +#else +#ifndef xmlBufferWriteChar +extern __typeof (xmlBufferWriteChar) xmlBufferWriteChar__internal_alias __attribute((visibility("hidden"))); +#define xmlBufferWriteChar xmlBufferWriteChar__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlBufferWriteQuotedString +extern __typeof (xmlBufferWriteQuotedString) xmlBufferWriteQuotedString __attribute((alias("xmlBufferWriteQuotedString__internal_alias"))); +#else +#ifndef xmlBufferWriteQuotedString +extern __typeof (xmlBufferWriteQuotedString) xmlBufferWriteQuotedString__internal_alias __attribute((visibility("hidden"))); +#define xmlBufferWriteQuotedString xmlBufferWriteQuotedString__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlBuildQName +extern __typeof (xmlBuildQName) xmlBuildQName __attribute((alias("xmlBuildQName__internal_alias"))); +#else +#ifndef xmlBuildQName +extern __typeof (xmlBuildQName) xmlBuildQName__internal_alias __attribute((visibility("hidden"))); +#define xmlBuildQName xmlBuildQName__internal_alias +#endif +#endif + +#ifdef bottom_uri +#undef xmlBuildRelativeURI +extern __typeof (xmlBuildRelativeURI) xmlBuildRelativeURI __attribute((alias("xmlBuildRelativeURI__internal_alias"))); +#else +#ifndef xmlBuildRelativeURI +extern __typeof (xmlBuildRelativeURI) xmlBuildRelativeURI__internal_alias __attribute((visibility("hidden"))); +#define xmlBuildRelativeURI xmlBuildRelativeURI__internal_alias +#endif +#endif + +#ifdef bottom_uri +#undef xmlBuildURI +extern __typeof (xmlBuildURI) xmlBuildURI __attribute((alias("xmlBuildURI__internal_alias"))); +#else +#ifndef xmlBuildURI +extern __typeof (xmlBuildURI) xmlBuildURI__internal_alias __attribute((visibility("hidden"))); +#define xmlBuildURI xmlBuildURI__internal_alias +#endif +#endif + +#ifdef bottom_encoding +#undef xmlByteConsumed +extern __typeof (xmlByteConsumed) xmlByteConsumed __attribute((alias("xmlByteConsumed__internal_alias"))); +#else +#ifndef xmlByteConsumed +extern __typeof (xmlByteConsumed) xmlByteConsumed__internal_alias __attribute((visibility("hidden"))); +#define xmlByteConsumed xmlByteConsumed__internal_alias +#endif +#endif + +#if defined(LIBXML_C14N_ENABLED) && defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_c14n +#undef xmlC14NDocDumpMemory +extern __typeof (xmlC14NDocDumpMemory) xmlC14NDocDumpMemory __attribute((alias("xmlC14NDocDumpMemory__internal_alias"))); +#else +#ifndef xmlC14NDocDumpMemory +extern __typeof (xmlC14NDocDumpMemory) xmlC14NDocDumpMemory__internal_alias __attribute((visibility("hidden"))); +#define xmlC14NDocDumpMemory xmlC14NDocDumpMemory__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_C14N_ENABLED) && defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_c14n +#undef xmlC14NDocSave +extern __typeof (xmlC14NDocSave) xmlC14NDocSave __attribute((alias("xmlC14NDocSave__internal_alias"))); +#else +#ifndef xmlC14NDocSave +extern __typeof (xmlC14NDocSave) xmlC14NDocSave__internal_alias __attribute((visibility("hidden"))); +#define xmlC14NDocSave xmlC14NDocSave__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_C14N_ENABLED) && defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_c14n +#undef xmlC14NDocSaveTo +extern __typeof (xmlC14NDocSaveTo) xmlC14NDocSaveTo __attribute((alias("xmlC14NDocSaveTo__internal_alias"))); +#else +#ifndef xmlC14NDocSaveTo +extern __typeof (xmlC14NDocSaveTo) xmlC14NDocSaveTo__internal_alias __attribute((visibility("hidden"))); +#define xmlC14NDocSaveTo xmlC14NDocSaveTo__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_C14N_ENABLED) && defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_c14n +#undef xmlC14NExecute +extern __typeof (xmlC14NExecute) xmlC14NExecute __attribute((alias("xmlC14NExecute__internal_alias"))); +#else +#ifndef xmlC14NExecute +extern __typeof (xmlC14NExecute) xmlC14NExecute__internal_alias __attribute((visibility("hidden"))); +#define xmlC14NExecute xmlC14NExecute__internal_alias +#endif +#endif +#endif + +#ifdef bottom_uri +#undef xmlCanonicPath +extern __typeof (xmlCanonicPath) xmlCanonicPath __attribute((alias("xmlCanonicPath__internal_alias"))); +#else +#ifndef xmlCanonicPath +extern __typeof (xmlCanonicPath) xmlCanonicPath__internal_alias __attribute((visibility("hidden"))); +#define xmlCanonicPath xmlCanonicPath__internal_alias +#endif +#endif + +#if defined(LIBXML_CATALOG_ENABLED) +#ifdef bottom_catalog +#undef xmlCatalogAdd +extern __typeof (xmlCatalogAdd) xmlCatalogAdd __attribute((alias("xmlCatalogAdd__internal_alias"))); +#else +#ifndef xmlCatalogAdd +extern __typeof (xmlCatalogAdd) xmlCatalogAdd__internal_alias __attribute((visibility("hidden"))); +#define xmlCatalogAdd xmlCatalogAdd__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_CATALOG_ENABLED) +#ifdef bottom_catalog +#undef xmlCatalogAddLocal +extern __typeof (xmlCatalogAddLocal) xmlCatalogAddLocal __attribute((alias("xmlCatalogAddLocal__internal_alias"))); +#else +#ifndef xmlCatalogAddLocal +extern __typeof (xmlCatalogAddLocal) xmlCatalogAddLocal__internal_alias __attribute((visibility("hidden"))); +#define xmlCatalogAddLocal xmlCatalogAddLocal__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_CATALOG_ENABLED) +#ifdef bottom_catalog +#undef xmlCatalogCleanup +extern __typeof (xmlCatalogCleanup) xmlCatalogCleanup __attribute((alias("xmlCatalogCleanup__internal_alias"))); +#else +#ifndef xmlCatalogCleanup +extern __typeof (xmlCatalogCleanup) xmlCatalogCleanup__internal_alias __attribute((visibility("hidden"))); +#define xmlCatalogCleanup xmlCatalogCleanup__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_CATALOG_ENABLED) +#ifdef bottom_catalog +#undef xmlCatalogConvert +extern __typeof (xmlCatalogConvert) xmlCatalogConvert __attribute((alias("xmlCatalogConvert__internal_alias"))); +#else +#ifndef xmlCatalogConvert +extern __typeof (xmlCatalogConvert) xmlCatalogConvert__internal_alias __attribute((visibility("hidden"))); +#define xmlCatalogConvert xmlCatalogConvert__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_CATALOG_ENABLED) && defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_catalog +#undef xmlCatalogDump +extern __typeof (xmlCatalogDump) xmlCatalogDump __attribute((alias("xmlCatalogDump__internal_alias"))); +#else +#ifndef xmlCatalogDump +extern __typeof (xmlCatalogDump) xmlCatalogDump__internal_alias __attribute((visibility("hidden"))); +#define xmlCatalogDump xmlCatalogDump__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_CATALOG_ENABLED) +#ifdef bottom_catalog +#undef xmlCatalogFreeLocal +extern __typeof (xmlCatalogFreeLocal) xmlCatalogFreeLocal __attribute((alias("xmlCatalogFreeLocal__internal_alias"))); +#else +#ifndef xmlCatalogFreeLocal +extern __typeof (xmlCatalogFreeLocal) xmlCatalogFreeLocal__internal_alias __attribute((visibility("hidden"))); +#define xmlCatalogFreeLocal xmlCatalogFreeLocal__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_CATALOG_ENABLED) +#ifdef bottom_catalog +#undef xmlCatalogGetDefaults +extern __typeof (xmlCatalogGetDefaults) xmlCatalogGetDefaults __attribute((alias("xmlCatalogGetDefaults__internal_alias"))); +#else +#ifndef xmlCatalogGetDefaults +extern __typeof (xmlCatalogGetDefaults) xmlCatalogGetDefaults__internal_alias __attribute((visibility("hidden"))); +#define xmlCatalogGetDefaults xmlCatalogGetDefaults__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_CATALOG_ENABLED) +#ifdef bottom_catalog +#undef xmlCatalogGetPublic +extern __typeof (xmlCatalogGetPublic) xmlCatalogGetPublic __attribute((alias("xmlCatalogGetPublic__internal_alias"))); +#else +#ifndef xmlCatalogGetPublic +extern __typeof (xmlCatalogGetPublic) xmlCatalogGetPublic__internal_alias __attribute((visibility("hidden"))); +#define xmlCatalogGetPublic xmlCatalogGetPublic__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_CATALOG_ENABLED) +#ifdef bottom_catalog +#undef xmlCatalogGetSystem +extern __typeof (xmlCatalogGetSystem) xmlCatalogGetSystem __attribute((alias("xmlCatalogGetSystem__internal_alias"))); +#else +#ifndef xmlCatalogGetSystem +extern __typeof (xmlCatalogGetSystem) xmlCatalogGetSystem__internal_alias __attribute((visibility("hidden"))); +#define xmlCatalogGetSystem xmlCatalogGetSystem__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_CATALOG_ENABLED) +#ifdef bottom_catalog +#undef xmlCatalogIsEmpty +extern __typeof (xmlCatalogIsEmpty) xmlCatalogIsEmpty __attribute((alias("xmlCatalogIsEmpty__internal_alias"))); +#else +#ifndef xmlCatalogIsEmpty +extern __typeof (xmlCatalogIsEmpty) xmlCatalogIsEmpty__internal_alias __attribute((visibility("hidden"))); +#define xmlCatalogIsEmpty xmlCatalogIsEmpty__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_CATALOG_ENABLED) +#ifdef bottom_catalog +#undef xmlCatalogLocalResolve +extern __typeof (xmlCatalogLocalResolve) xmlCatalogLocalResolve __attribute((alias("xmlCatalogLocalResolve__internal_alias"))); +#else +#ifndef xmlCatalogLocalResolve +extern __typeof (xmlCatalogLocalResolve) xmlCatalogLocalResolve__internal_alias __attribute((visibility("hidden"))); +#define xmlCatalogLocalResolve xmlCatalogLocalResolve__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_CATALOG_ENABLED) +#ifdef bottom_catalog +#undef xmlCatalogLocalResolveURI +extern __typeof (xmlCatalogLocalResolveURI) xmlCatalogLocalResolveURI __attribute((alias("xmlCatalogLocalResolveURI__internal_alias"))); +#else +#ifndef xmlCatalogLocalResolveURI +extern __typeof (xmlCatalogLocalResolveURI) xmlCatalogLocalResolveURI__internal_alias __attribute((visibility("hidden"))); +#define xmlCatalogLocalResolveURI xmlCatalogLocalResolveURI__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_CATALOG_ENABLED) +#ifdef bottom_catalog +#undef xmlCatalogRemove +extern __typeof (xmlCatalogRemove) xmlCatalogRemove __attribute((alias("xmlCatalogRemove__internal_alias"))); +#else +#ifndef xmlCatalogRemove +extern __typeof (xmlCatalogRemove) xmlCatalogRemove__internal_alias __attribute((visibility("hidden"))); +#define xmlCatalogRemove xmlCatalogRemove__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_CATALOG_ENABLED) +#ifdef bottom_catalog +#undef xmlCatalogResolve +extern __typeof (xmlCatalogResolve) xmlCatalogResolve __attribute((alias("xmlCatalogResolve__internal_alias"))); +#else +#ifndef xmlCatalogResolve +extern __typeof (xmlCatalogResolve) xmlCatalogResolve__internal_alias __attribute((visibility("hidden"))); +#define xmlCatalogResolve xmlCatalogResolve__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_CATALOG_ENABLED) +#ifdef bottom_catalog +#undef xmlCatalogResolvePublic +extern __typeof (xmlCatalogResolvePublic) xmlCatalogResolvePublic __attribute((alias("xmlCatalogResolvePublic__internal_alias"))); +#else +#ifndef xmlCatalogResolvePublic +extern __typeof (xmlCatalogResolvePublic) xmlCatalogResolvePublic__internal_alias __attribute((visibility("hidden"))); +#define xmlCatalogResolvePublic xmlCatalogResolvePublic__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_CATALOG_ENABLED) +#ifdef bottom_catalog +#undef xmlCatalogResolveSystem +extern __typeof (xmlCatalogResolveSystem) xmlCatalogResolveSystem __attribute((alias("xmlCatalogResolveSystem__internal_alias"))); +#else +#ifndef xmlCatalogResolveSystem +extern __typeof (xmlCatalogResolveSystem) xmlCatalogResolveSystem__internal_alias __attribute((visibility("hidden"))); +#define xmlCatalogResolveSystem xmlCatalogResolveSystem__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_CATALOG_ENABLED) +#ifdef bottom_catalog +#undef xmlCatalogResolveURI +extern __typeof (xmlCatalogResolveURI) xmlCatalogResolveURI __attribute((alias("xmlCatalogResolveURI__internal_alias"))); +#else +#ifndef xmlCatalogResolveURI +extern __typeof (xmlCatalogResolveURI) xmlCatalogResolveURI__internal_alias __attribute((visibility("hidden"))); +#define xmlCatalogResolveURI xmlCatalogResolveURI__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_CATALOG_ENABLED) +#ifdef bottom_catalog +#undef xmlCatalogSetDebug +extern __typeof (xmlCatalogSetDebug) xmlCatalogSetDebug __attribute((alias("xmlCatalogSetDebug__internal_alias"))); +#else +#ifndef xmlCatalogSetDebug +extern __typeof (xmlCatalogSetDebug) xmlCatalogSetDebug__internal_alias __attribute((visibility("hidden"))); +#define xmlCatalogSetDebug xmlCatalogSetDebug__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_CATALOG_ENABLED) +#ifdef bottom_catalog +#undef xmlCatalogSetDefaultPrefer +extern __typeof (xmlCatalogSetDefaultPrefer) xmlCatalogSetDefaultPrefer __attribute((alias("xmlCatalogSetDefaultPrefer__internal_alias"))); +#else +#ifndef xmlCatalogSetDefaultPrefer +extern __typeof (xmlCatalogSetDefaultPrefer) xmlCatalogSetDefaultPrefer__internal_alias __attribute((visibility("hidden"))); +#define xmlCatalogSetDefaultPrefer xmlCatalogSetDefaultPrefer__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_CATALOG_ENABLED) +#ifdef bottom_catalog +#undef xmlCatalogSetDefaults +extern __typeof (xmlCatalogSetDefaults) xmlCatalogSetDefaults __attribute((alias("xmlCatalogSetDefaults__internal_alias"))); +#else +#ifndef xmlCatalogSetDefaults +extern __typeof (xmlCatalogSetDefaults) xmlCatalogSetDefaults__internal_alias __attribute((visibility("hidden"))); +#define xmlCatalogSetDefaults xmlCatalogSetDefaults__internal_alias +#endif +#endif +#endif + +#ifdef bottom_encoding +#undef xmlCharEncCloseFunc +extern __typeof (xmlCharEncCloseFunc) xmlCharEncCloseFunc __attribute((alias("xmlCharEncCloseFunc__internal_alias"))); +#else +#ifndef xmlCharEncCloseFunc +extern __typeof (xmlCharEncCloseFunc) xmlCharEncCloseFunc__internal_alias __attribute((visibility("hidden"))); +#define xmlCharEncCloseFunc xmlCharEncCloseFunc__internal_alias +#endif +#endif + +#ifdef bottom_encoding +#undef xmlCharEncFirstLine +extern __typeof (xmlCharEncFirstLine) xmlCharEncFirstLine __attribute((alias("xmlCharEncFirstLine__internal_alias"))); +#else +#ifndef xmlCharEncFirstLine +extern __typeof (xmlCharEncFirstLine) xmlCharEncFirstLine__internal_alias __attribute((visibility("hidden"))); +#define xmlCharEncFirstLine xmlCharEncFirstLine__internal_alias +#endif +#endif + +#ifdef bottom_encoding +#undef xmlCharEncInFunc +extern __typeof (xmlCharEncInFunc) xmlCharEncInFunc __attribute((alias("xmlCharEncInFunc__internal_alias"))); +#else +#ifndef xmlCharEncInFunc +extern __typeof (xmlCharEncInFunc) xmlCharEncInFunc__internal_alias __attribute((visibility("hidden"))); +#define xmlCharEncInFunc xmlCharEncInFunc__internal_alias +#endif +#endif + +#ifdef bottom_encoding +#undef xmlCharEncOutFunc +extern __typeof (xmlCharEncOutFunc) xmlCharEncOutFunc __attribute((alias("xmlCharEncOutFunc__internal_alias"))); +#else +#ifndef xmlCharEncOutFunc +extern __typeof (xmlCharEncOutFunc) xmlCharEncOutFunc__internal_alias __attribute((visibility("hidden"))); +#define xmlCharEncOutFunc xmlCharEncOutFunc__internal_alias +#endif +#endif + +#ifdef bottom_chvalid +#undef xmlCharInRange +extern __typeof (xmlCharInRange) xmlCharInRange __attribute((alias("xmlCharInRange__internal_alias"))); +#else +#ifndef xmlCharInRange +extern __typeof (xmlCharInRange) xmlCharInRange__internal_alias __attribute((visibility("hidden"))); +#define xmlCharInRange xmlCharInRange__internal_alias +#endif +#endif + +#ifdef bottom_xmlstring +#undef xmlCharStrdup +extern __typeof (xmlCharStrdup) xmlCharStrdup __attribute((alias("xmlCharStrdup__internal_alias"))); +#else +#ifndef xmlCharStrdup +extern __typeof (xmlCharStrdup) xmlCharStrdup__internal_alias __attribute((visibility("hidden"))); +#define xmlCharStrdup xmlCharStrdup__internal_alias +#endif +#endif + +#ifdef bottom_xmlstring +#undef xmlCharStrndup +extern __typeof (xmlCharStrndup) xmlCharStrndup __attribute((alias("xmlCharStrndup__internal_alias"))); +#else +#ifndef xmlCharStrndup +extern __typeof (xmlCharStrndup) xmlCharStrndup__internal_alias __attribute((visibility("hidden"))); +#define xmlCharStrndup xmlCharStrndup__internal_alias +#endif +#endif + +#ifdef bottom_xmlIO +#undef xmlCheckFilename +extern __typeof (xmlCheckFilename) xmlCheckFilename __attribute((alias("xmlCheckFilename__internal_alias"))); +#else +#ifndef xmlCheckFilename +extern __typeof (xmlCheckFilename) xmlCheckFilename__internal_alias __attribute((visibility("hidden"))); +#define xmlCheckFilename xmlCheckFilename__internal_alias +#endif +#endif + +#ifdef bottom_xmlIO +#undef xmlCheckHTTPInput +extern __typeof (xmlCheckHTTPInput) xmlCheckHTTPInput __attribute((alias("xmlCheckHTTPInput__internal_alias"))); +#else +#ifndef xmlCheckHTTPInput +extern __typeof (xmlCheckHTTPInput) xmlCheckHTTPInput__internal_alias __attribute((visibility("hidden"))); +#define xmlCheckHTTPInput xmlCheckHTTPInput__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlCheckLanguageID +extern __typeof (xmlCheckLanguageID) xmlCheckLanguageID __attribute((alias("xmlCheckLanguageID__internal_alias"))); +#else +#ifndef xmlCheckLanguageID +extern __typeof (xmlCheckLanguageID) xmlCheckLanguageID__internal_alias __attribute((visibility("hidden"))); +#define xmlCheckLanguageID xmlCheckLanguageID__internal_alias +#endif +#endif + +#ifdef bottom_xmlstring +#undef xmlCheckUTF8 +extern __typeof (xmlCheckUTF8) xmlCheckUTF8 __attribute((alias("xmlCheckUTF8__internal_alias"))); +#else +#ifndef xmlCheckUTF8 +extern __typeof (xmlCheckUTF8) xmlCheckUTF8__internal_alias __attribute((visibility("hidden"))); +#define xmlCheckUTF8 xmlCheckUTF8__internal_alias +#endif +#endif + +#ifdef bottom_parserInternals +#undef xmlCheckVersion +extern __typeof (xmlCheckVersion) xmlCheckVersion __attribute((alias("xmlCheckVersion__internal_alias"))); +#else +#ifndef xmlCheckVersion +extern __typeof (xmlCheckVersion) xmlCheckVersion__internal_alias __attribute((visibility("hidden"))); +#define xmlCheckVersion xmlCheckVersion__internal_alias +#endif +#endif + +#if defined(LIBXML_TREE_ENABLED) +#ifdef bottom_tree +#undef xmlChildElementCount +extern __typeof (xmlChildElementCount) xmlChildElementCount __attribute((alias("xmlChildElementCount__internal_alias"))); +#else +#ifndef xmlChildElementCount +extern __typeof (xmlChildElementCount) xmlChildElementCount__internal_alias __attribute((visibility("hidden"))); +#define xmlChildElementCount xmlChildElementCount__internal_alias +#endif +#endif +#endif + +#ifdef bottom_encoding +#undef xmlCleanupCharEncodingHandlers +extern __typeof (xmlCleanupCharEncodingHandlers) xmlCleanupCharEncodingHandlers __attribute((alias("xmlCleanupCharEncodingHandlers__internal_alias"))); +#else +#ifndef xmlCleanupCharEncodingHandlers +extern __typeof (xmlCleanupCharEncodingHandlers) xmlCleanupCharEncodingHandlers__internal_alias __attribute((visibility("hidden"))); +#define xmlCleanupCharEncodingHandlers xmlCleanupCharEncodingHandlers__internal_alias +#endif +#endif + +#ifdef bottom_encoding +#undef xmlCleanupEncodingAliases +extern __typeof (xmlCleanupEncodingAliases) xmlCleanupEncodingAliases __attribute((alias("xmlCleanupEncodingAliases__internal_alias"))); +#else +#ifndef xmlCleanupEncodingAliases +extern __typeof (xmlCleanupEncodingAliases) xmlCleanupEncodingAliases__internal_alias __attribute((visibility("hidden"))); +#define xmlCleanupEncodingAliases xmlCleanupEncodingAliases__internal_alias +#endif +#endif + +#ifdef bottom_globals +#undef xmlCleanupGlobals +extern __typeof (xmlCleanupGlobals) xmlCleanupGlobals __attribute((alias("xmlCleanupGlobals__internal_alias"))); +#else +#ifndef xmlCleanupGlobals +extern __typeof (xmlCleanupGlobals) xmlCleanupGlobals__internal_alias __attribute((visibility("hidden"))); +#define xmlCleanupGlobals xmlCleanupGlobals__internal_alias +#endif +#endif + +#ifdef bottom_xmlIO +#undef xmlCleanupInputCallbacks +extern __typeof (xmlCleanupInputCallbacks) xmlCleanupInputCallbacks __attribute((alias("xmlCleanupInputCallbacks__internal_alias"))); +#else +#ifndef xmlCleanupInputCallbacks +extern __typeof (xmlCleanupInputCallbacks) xmlCleanupInputCallbacks__internal_alias __attribute((visibility("hidden"))); +#define xmlCleanupInputCallbacks xmlCleanupInputCallbacks__internal_alias +#endif +#endif + +#ifdef bottom_xmlmemory +#undef xmlCleanupMemory +extern __typeof (xmlCleanupMemory) xmlCleanupMemory __attribute((alias("xmlCleanupMemory__internal_alias"))); +#else +#ifndef xmlCleanupMemory +extern __typeof (xmlCleanupMemory) xmlCleanupMemory__internal_alias __attribute((visibility("hidden"))); +#define xmlCleanupMemory xmlCleanupMemory__internal_alias +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_xmlIO +#undef xmlCleanupOutputCallbacks +extern __typeof (xmlCleanupOutputCallbacks) xmlCleanupOutputCallbacks __attribute((alias("xmlCleanupOutputCallbacks__internal_alias"))); +#else +#ifndef xmlCleanupOutputCallbacks +extern __typeof (xmlCleanupOutputCallbacks) xmlCleanupOutputCallbacks__internal_alias __attribute((visibility("hidden"))); +#define xmlCleanupOutputCallbacks xmlCleanupOutputCallbacks__internal_alias +#endif +#endif +#endif + +#ifdef bottom_parser +#undef xmlCleanupParser +extern __typeof (xmlCleanupParser) xmlCleanupParser __attribute((alias("xmlCleanupParser__internal_alias"))); +#else +#ifndef xmlCleanupParser +extern __typeof (xmlCleanupParser) xmlCleanupParser__internal_alias __attribute((visibility("hidden"))); +#define xmlCleanupParser xmlCleanupParser__internal_alias +#endif +#endif + +#if defined(LIBXML_LEGACY_ENABLED) +#ifdef bottom_legacy +#undef xmlCleanupPredefinedEntities +extern __typeof (xmlCleanupPredefinedEntities) xmlCleanupPredefinedEntities __attribute((alias("xmlCleanupPredefinedEntities__internal_alias"))); +#else +#ifndef xmlCleanupPredefinedEntities +extern __typeof (xmlCleanupPredefinedEntities) xmlCleanupPredefinedEntities__internal_alias __attribute((visibility("hidden"))); +#define xmlCleanupPredefinedEntities xmlCleanupPredefinedEntities__internal_alias +#endif +#endif +#endif + +#ifdef bottom_threads +#undef xmlCleanupThreads +extern __typeof (xmlCleanupThreads) xmlCleanupThreads __attribute((alias("xmlCleanupThreads__internal_alias"))); +#else +#ifndef xmlCleanupThreads +extern __typeof (xmlCleanupThreads) xmlCleanupThreads__internal_alias __attribute((visibility("hidden"))); +#define xmlCleanupThreads xmlCleanupThreads__internal_alias +#endif +#endif + +#ifdef bottom_parserInternals +#undef xmlClearNodeInfoSeq +extern __typeof (xmlClearNodeInfoSeq) xmlClearNodeInfoSeq __attribute((alias("xmlClearNodeInfoSeq__internal_alias"))); +#else +#ifndef xmlClearNodeInfoSeq +extern __typeof (xmlClearNodeInfoSeq) xmlClearNodeInfoSeq__internal_alias __attribute((visibility("hidden"))); +#define xmlClearNodeInfoSeq xmlClearNodeInfoSeq__internal_alias +#endif +#endif + +#ifdef bottom_parserInternals +#undef xmlClearParserCtxt +extern __typeof (xmlClearParserCtxt) xmlClearParserCtxt __attribute((alias("xmlClearParserCtxt__internal_alias"))); +#else +#ifndef xmlClearParserCtxt +extern __typeof (xmlClearParserCtxt) xmlClearParserCtxt__internal_alias __attribute((visibility("hidden"))); +#define xmlClearParserCtxt xmlClearParserCtxt__internal_alias +#endif +#endif + +#if defined(LIBXML_CATALOG_ENABLED) +#ifdef bottom_catalog +#undef xmlConvertSGMLCatalog +extern __typeof (xmlConvertSGMLCatalog) xmlConvertSGMLCatalog __attribute((alias("xmlConvertSGMLCatalog__internal_alias"))); +#else +#ifndef xmlConvertSGMLCatalog +extern __typeof (xmlConvertSGMLCatalog) xmlConvertSGMLCatalog__internal_alias __attribute((visibility("hidden"))); +#define xmlConvertSGMLCatalog xmlConvertSGMLCatalog__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_TREE_ENABLED) +#ifdef bottom_valid +#undef xmlCopyAttributeTable +extern __typeof (xmlCopyAttributeTable) xmlCopyAttributeTable __attribute((alias("xmlCopyAttributeTable__internal_alias"))); +#else +#ifndef xmlCopyAttributeTable +extern __typeof (xmlCopyAttributeTable) xmlCopyAttributeTable__internal_alias __attribute((visibility("hidden"))); +#define xmlCopyAttributeTable xmlCopyAttributeTable__internal_alias +#endif +#endif +#endif + +#ifdef bottom_parserInternals +#undef xmlCopyChar +extern __typeof (xmlCopyChar) xmlCopyChar __attribute((alias("xmlCopyChar__internal_alias"))); +#else +#ifndef xmlCopyChar +extern __typeof (xmlCopyChar) xmlCopyChar__internal_alias __attribute((visibility("hidden"))); +#define xmlCopyChar xmlCopyChar__internal_alias +#endif +#endif + +#ifdef bottom_parserInternals +#undef xmlCopyCharMultiByte +extern __typeof (xmlCopyCharMultiByte) xmlCopyCharMultiByte __attribute((alias("xmlCopyCharMultiByte__internal_alias"))); +#else +#ifndef xmlCopyCharMultiByte +extern __typeof (xmlCopyCharMultiByte) xmlCopyCharMultiByte__internal_alias __attribute((visibility("hidden"))); +#define xmlCopyCharMultiByte xmlCopyCharMultiByte__internal_alias +#endif +#endif + +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_tree +#undef xmlCopyDoc +extern __typeof (xmlCopyDoc) xmlCopyDoc __attribute((alias("xmlCopyDoc__internal_alias"))); +#else +#ifndef xmlCopyDoc +extern __typeof (xmlCopyDoc) xmlCopyDoc__internal_alias __attribute((visibility("hidden"))); +#define xmlCopyDoc xmlCopyDoc__internal_alias +#endif +#endif +#endif + +#ifdef bottom_valid +#undef xmlCopyDocElementContent +extern __typeof (xmlCopyDocElementContent) xmlCopyDocElementContent __attribute((alias("xmlCopyDocElementContent__internal_alias"))); +#else +#ifndef xmlCopyDocElementContent +extern __typeof (xmlCopyDocElementContent) xmlCopyDocElementContent__internal_alias __attribute((visibility("hidden"))); +#define xmlCopyDocElementContent xmlCopyDocElementContent__internal_alias +#endif +#endif + +#if defined(LIBXML_TREE_ENABLED) +#ifdef bottom_tree +#undef xmlCopyDtd +extern __typeof (xmlCopyDtd) xmlCopyDtd __attribute((alias("xmlCopyDtd__internal_alias"))); +#else +#ifndef xmlCopyDtd +extern __typeof (xmlCopyDtd) xmlCopyDtd__internal_alias __attribute((visibility("hidden"))); +#define xmlCopyDtd xmlCopyDtd__internal_alias +#endif +#endif +#endif + +#ifdef bottom_valid +#undef xmlCopyElementContent +extern __typeof (xmlCopyElementContent) xmlCopyElementContent __attribute((alias("xmlCopyElementContent__internal_alias"))); +#else +#ifndef xmlCopyElementContent +extern __typeof (xmlCopyElementContent) xmlCopyElementContent__internal_alias __attribute((visibility("hidden"))); +#define xmlCopyElementContent xmlCopyElementContent__internal_alias +#endif +#endif + +#if defined(LIBXML_TREE_ENABLED) +#ifdef bottom_valid +#undef xmlCopyElementTable +extern __typeof (xmlCopyElementTable) xmlCopyElementTable __attribute((alias("xmlCopyElementTable__internal_alias"))); +#else +#ifndef xmlCopyElementTable +extern __typeof (xmlCopyElementTable) xmlCopyElementTable__internal_alias __attribute((visibility("hidden"))); +#define xmlCopyElementTable xmlCopyElementTable__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_TREE_ENABLED) +#ifdef bottom_entities +#undef xmlCopyEntitiesTable +extern __typeof (xmlCopyEntitiesTable) xmlCopyEntitiesTable __attribute((alias("xmlCopyEntitiesTable__internal_alias"))); +#else +#ifndef xmlCopyEntitiesTable +extern __typeof (xmlCopyEntitiesTable) xmlCopyEntitiesTable__internal_alias __attribute((visibility("hidden"))); +#define xmlCopyEntitiesTable xmlCopyEntitiesTable__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_TREE_ENABLED) +#ifdef bottom_valid +#undef xmlCopyEnumeration +extern __typeof (xmlCopyEnumeration) xmlCopyEnumeration __attribute((alias("xmlCopyEnumeration__internal_alias"))); +#else +#ifndef xmlCopyEnumeration +extern __typeof (xmlCopyEnumeration) xmlCopyEnumeration__internal_alias __attribute((visibility("hidden"))); +#define xmlCopyEnumeration xmlCopyEnumeration__internal_alias +#endif +#endif +#endif + +#ifdef bottom_error +#undef xmlCopyError +extern __typeof (xmlCopyError) xmlCopyError __attribute((alias("xmlCopyError__internal_alias"))); +#else +#ifndef xmlCopyError +extern __typeof (xmlCopyError) xmlCopyError__internal_alias __attribute((visibility("hidden"))); +#define xmlCopyError xmlCopyError__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlCopyNamespace +extern __typeof (xmlCopyNamespace) xmlCopyNamespace __attribute((alias("xmlCopyNamespace__internal_alias"))); +#else +#ifndef xmlCopyNamespace +extern __typeof (xmlCopyNamespace) xmlCopyNamespace__internal_alias __attribute((visibility("hidden"))); +#define xmlCopyNamespace xmlCopyNamespace__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlCopyNamespaceList +extern __typeof (xmlCopyNamespaceList) xmlCopyNamespaceList __attribute((alias("xmlCopyNamespaceList__internal_alias"))); +#else +#ifndef xmlCopyNamespaceList +extern __typeof (xmlCopyNamespaceList) xmlCopyNamespaceList__internal_alias __attribute((visibility("hidden"))); +#define xmlCopyNamespaceList xmlCopyNamespaceList__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlCopyNode +extern __typeof (xmlCopyNode) xmlCopyNode __attribute((alias("xmlCopyNode__internal_alias"))); +#else +#ifndef xmlCopyNode +extern __typeof (xmlCopyNode) xmlCopyNode__internal_alias __attribute((visibility("hidden"))); +#define xmlCopyNode xmlCopyNode__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlCopyNodeList +extern __typeof (xmlCopyNodeList) xmlCopyNodeList __attribute((alias("xmlCopyNodeList__internal_alias"))); +#else +#ifndef xmlCopyNodeList +extern __typeof (xmlCopyNodeList) xmlCopyNodeList__internal_alias __attribute((visibility("hidden"))); +#define xmlCopyNodeList xmlCopyNodeList__internal_alias +#endif +#endif + +#if defined(LIBXML_TREE_ENABLED) +#ifdef bottom_valid +#undef xmlCopyNotationTable +extern __typeof (xmlCopyNotationTable) xmlCopyNotationTable __attribute((alias("xmlCopyNotationTable__internal_alias"))); +#else +#ifndef xmlCopyNotationTable +extern __typeof (xmlCopyNotationTable) xmlCopyNotationTable__internal_alias __attribute((visibility("hidden"))); +#define xmlCopyNotationTable xmlCopyNotationTable__internal_alias +#endif +#endif +#endif + +#ifdef bottom_tree +#undef xmlCopyProp +extern __typeof (xmlCopyProp) xmlCopyProp __attribute((alias("xmlCopyProp__internal_alias"))); +#else +#ifndef xmlCopyProp +extern __typeof (xmlCopyProp) xmlCopyProp__internal_alias __attribute((visibility("hidden"))); +#define xmlCopyProp xmlCopyProp__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlCopyPropList +extern __typeof (xmlCopyPropList) xmlCopyPropList __attribute((alias("xmlCopyPropList__internal_alias"))); +#else +#ifndef xmlCopyPropList +extern __typeof (xmlCopyPropList) xmlCopyPropList__internal_alias __attribute((visibility("hidden"))); +#define xmlCopyPropList xmlCopyPropList__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlCreateDocParserCtxt +extern __typeof (xmlCreateDocParserCtxt) xmlCreateDocParserCtxt __attribute((alias("xmlCreateDocParserCtxt__internal_alias"))); +#else +#ifndef xmlCreateDocParserCtxt +extern __typeof (xmlCreateDocParserCtxt) xmlCreateDocParserCtxt__internal_alias __attribute((visibility("hidden"))); +#define xmlCreateDocParserCtxt xmlCreateDocParserCtxt__internal_alias +#endif +#endif + +#ifdef bottom_entities +#undef xmlCreateEntitiesTable +extern __typeof (xmlCreateEntitiesTable) xmlCreateEntitiesTable __attribute((alias("xmlCreateEntitiesTable__internal_alias"))); +#else +#ifndef xmlCreateEntitiesTable +extern __typeof (xmlCreateEntitiesTable) xmlCreateEntitiesTable__internal_alias __attribute((visibility("hidden"))); +#define xmlCreateEntitiesTable xmlCreateEntitiesTable__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlCreateEntityParserCtxt +extern __typeof (xmlCreateEntityParserCtxt) xmlCreateEntityParserCtxt __attribute((alias("xmlCreateEntityParserCtxt__internal_alias"))); +#else +#ifndef xmlCreateEntityParserCtxt +extern __typeof (xmlCreateEntityParserCtxt) xmlCreateEntityParserCtxt__internal_alias __attribute((visibility("hidden"))); +#define xmlCreateEntityParserCtxt xmlCreateEntityParserCtxt__internal_alias +#endif +#endif + +#ifdef bottom_valid +#undef xmlCreateEnumeration +extern __typeof (xmlCreateEnumeration) xmlCreateEnumeration __attribute((alias("xmlCreateEnumeration__internal_alias"))); +#else +#ifndef xmlCreateEnumeration +extern __typeof (xmlCreateEnumeration) xmlCreateEnumeration__internal_alias __attribute((visibility("hidden"))); +#define xmlCreateEnumeration xmlCreateEnumeration__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlCreateFileParserCtxt +extern __typeof (xmlCreateFileParserCtxt) xmlCreateFileParserCtxt __attribute((alias("xmlCreateFileParserCtxt__internal_alias"))); +#else +#ifndef xmlCreateFileParserCtxt +extern __typeof (xmlCreateFileParserCtxt) xmlCreateFileParserCtxt__internal_alias __attribute((visibility("hidden"))); +#define xmlCreateFileParserCtxt xmlCreateFileParserCtxt__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlCreateIOParserCtxt +extern __typeof (xmlCreateIOParserCtxt) xmlCreateIOParserCtxt __attribute((alias("xmlCreateIOParserCtxt__internal_alias"))); +#else +#ifndef xmlCreateIOParserCtxt +extern __typeof (xmlCreateIOParserCtxt) xmlCreateIOParserCtxt__internal_alias __attribute((visibility("hidden"))); +#define xmlCreateIOParserCtxt xmlCreateIOParserCtxt__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlCreateIntSubset +extern __typeof (xmlCreateIntSubset) xmlCreateIntSubset __attribute((alias("xmlCreateIntSubset__internal_alias"))); +#else +#ifndef xmlCreateIntSubset +extern __typeof (xmlCreateIntSubset) xmlCreateIntSubset__internal_alias __attribute((visibility("hidden"))); +#define xmlCreateIntSubset xmlCreateIntSubset__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlCreateMemoryParserCtxt +extern __typeof (xmlCreateMemoryParserCtxt) xmlCreateMemoryParserCtxt __attribute((alias("xmlCreateMemoryParserCtxt__internal_alias"))); +#else +#ifndef xmlCreateMemoryParserCtxt +extern __typeof (xmlCreateMemoryParserCtxt) xmlCreateMemoryParserCtxt__internal_alias __attribute((visibility("hidden"))); +#define xmlCreateMemoryParserCtxt xmlCreateMemoryParserCtxt__internal_alias +#endif +#endif + +#if defined(LIBXML_PUSH_ENABLED) +#ifdef bottom_parser +#undef xmlCreatePushParserCtxt +extern __typeof (xmlCreatePushParserCtxt) xmlCreatePushParserCtxt __attribute((alias("xmlCreatePushParserCtxt__internal_alias"))); +#else +#ifndef xmlCreatePushParserCtxt +extern __typeof (xmlCreatePushParserCtxt) xmlCreatePushParserCtxt__internal_alias __attribute((visibility("hidden"))); +#define xmlCreatePushParserCtxt xmlCreatePushParserCtxt__internal_alias +#endif +#endif +#endif + +#ifdef bottom_uri +#undef xmlCreateURI +extern __typeof (xmlCreateURI) xmlCreateURI __attribute((alias("xmlCreateURI__internal_alias"))); +#else +#ifndef xmlCreateURI +extern __typeof (xmlCreateURI) xmlCreateURI__internal_alias __attribute((visibility("hidden"))); +#define xmlCreateURI xmlCreateURI__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlCreateURLParserCtxt +extern __typeof (xmlCreateURLParserCtxt) xmlCreateURLParserCtxt __attribute((alias("xmlCreateURLParserCtxt__internal_alias"))); +#else +#ifndef xmlCreateURLParserCtxt +extern __typeof (xmlCreateURLParserCtxt) xmlCreateURLParserCtxt__internal_alias __attribute((visibility("hidden"))); +#define xmlCreateURLParserCtxt xmlCreateURLParserCtxt__internal_alias +#endif +#endif + +#ifdef bottom_error +#undef xmlCtxtGetLastError +extern __typeof (xmlCtxtGetLastError) xmlCtxtGetLastError __attribute((alias("xmlCtxtGetLastError__internal_alias"))); +#else +#ifndef xmlCtxtGetLastError +extern __typeof (xmlCtxtGetLastError) xmlCtxtGetLastError__internal_alias __attribute((visibility("hidden"))); +#define xmlCtxtGetLastError xmlCtxtGetLastError__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlCtxtReadDoc +extern __typeof (xmlCtxtReadDoc) xmlCtxtReadDoc __attribute((alias("xmlCtxtReadDoc__internal_alias"))); +#else +#ifndef xmlCtxtReadDoc +extern __typeof (xmlCtxtReadDoc) xmlCtxtReadDoc__internal_alias __attribute((visibility("hidden"))); +#define xmlCtxtReadDoc xmlCtxtReadDoc__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlCtxtReadFd +extern __typeof (xmlCtxtReadFd) xmlCtxtReadFd __attribute((alias("xmlCtxtReadFd__internal_alias"))); +#else +#ifndef xmlCtxtReadFd +extern __typeof (xmlCtxtReadFd) xmlCtxtReadFd__internal_alias __attribute((visibility("hidden"))); +#define xmlCtxtReadFd xmlCtxtReadFd__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlCtxtReadFile +extern __typeof (xmlCtxtReadFile) xmlCtxtReadFile __attribute((alias("xmlCtxtReadFile__internal_alias"))); +#else +#ifndef xmlCtxtReadFile +extern __typeof (xmlCtxtReadFile) xmlCtxtReadFile__internal_alias __attribute((visibility("hidden"))); +#define xmlCtxtReadFile xmlCtxtReadFile__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlCtxtReadIO +extern __typeof (xmlCtxtReadIO) xmlCtxtReadIO __attribute((alias("xmlCtxtReadIO__internal_alias"))); +#else +#ifndef xmlCtxtReadIO +extern __typeof (xmlCtxtReadIO) xmlCtxtReadIO__internal_alias __attribute((visibility("hidden"))); +#define xmlCtxtReadIO xmlCtxtReadIO__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlCtxtReadMemory +extern __typeof (xmlCtxtReadMemory) xmlCtxtReadMemory __attribute((alias("xmlCtxtReadMemory__internal_alias"))); +#else +#ifndef xmlCtxtReadMemory +extern __typeof (xmlCtxtReadMemory) xmlCtxtReadMemory__internal_alias __attribute((visibility("hidden"))); +#define xmlCtxtReadMemory xmlCtxtReadMemory__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlCtxtReset +extern __typeof (xmlCtxtReset) xmlCtxtReset __attribute((alias("xmlCtxtReset__internal_alias"))); +#else +#ifndef xmlCtxtReset +extern __typeof (xmlCtxtReset) xmlCtxtReset__internal_alias __attribute((visibility("hidden"))); +#define xmlCtxtReset xmlCtxtReset__internal_alias +#endif +#endif + +#ifdef bottom_error +#undef xmlCtxtResetLastError +extern __typeof (xmlCtxtResetLastError) xmlCtxtResetLastError __attribute((alias("xmlCtxtResetLastError__internal_alias"))); +#else +#ifndef xmlCtxtResetLastError +extern __typeof (xmlCtxtResetLastError) xmlCtxtResetLastError__internal_alias __attribute((visibility("hidden"))); +#define xmlCtxtResetLastError xmlCtxtResetLastError__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlCtxtResetPush +extern __typeof (xmlCtxtResetPush) xmlCtxtResetPush __attribute((alias("xmlCtxtResetPush__internal_alias"))); +#else +#ifndef xmlCtxtResetPush +extern __typeof (xmlCtxtResetPush) xmlCtxtResetPush__internal_alias __attribute((visibility("hidden"))); +#define xmlCtxtResetPush xmlCtxtResetPush__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlCtxtUseOptions +extern __typeof (xmlCtxtUseOptions) xmlCtxtUseOptions __attribute((alias("xmlCtxtUseOptions__internal_alias"))); +#else +#ifndef xmlCtxtUseOptions +extern __typeof (xmlCtxtUseOptions) xmlCtxtUseOptions__internal_alias __attribute((visibility("hidden"))); +#define xmlCtxtUseOptions xmlCtxtUseOptions__internal_alias +#endif +#endif + +#ifdef bottom_parserInternals +#undef xmlCurrentChar +extern __typeof (xmlCurrentChar) xmlCurrentChar __attribute((alias("xmlCurrentChar__internal_alias"))); +#else +#ifndef xmlCurrentChar +extern __typeof (xmlCurrentChar) xmlCurrentChar__internal_alias __attribute((visibility("hidden"))); +#define xmlCurrentChar xmlCurrentChar__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlDOMWrapAdoptNode +extern __typeof (xmlDOMWrapAdoptNode) xmlDOMWrapAdoptNode __attribute((alias("xmlDOMWrapAdoptNode__internal_alias"))); +#else +#ifndef xmlDOMWrapAdoptNode +extern __typeof (xmlDOMWrapAdoptNode) xmlDOMWrapAdoptNode__internal_alias __attribute((visibility("hidden"))); +#define xmlDOMWrapAdoptNode xmlDOMWrapAdoptNode__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlDOMWrapCloneNode +extern __typeof (xmlDOMWrapCloneNode) xmlDOMWrapCloneNode __attribute((alias("xmlDOMWrapCloneNode__internal_alias"))); +#else +#ifndef xmlDOMWrapCloneNode +extern __typeof (xmlDOMWrapCloneNode) xmlDOMWrapCloneNode__internal_alias __attribute((visibility("hidden"))); +#define xmlDOMWrapCloneNode xmlDOMWrapCloneNode__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlDOMWrapFreeCtxt +extern __typeof (xmlDOMWrapFreeCtxt) xmlDOMWrapFreeCtxt __attribute((alias("xmlDOMWrapFreeCtxt__internal_alias"))); +#else +#ifndef xmlDOMWrapFreeCtxt +extern __typeof (xmlDOMWrapFreeCtxt) xmlDOMWrapFreeCtxt__internal_alias __attribute((visibility("hidden"))); +#define xmlDOMWrapFreeCtxt xmlDOMWrapFreeCtxt__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlDOMWrapNewCtxt +extern __typeof (xmlDOMWrapNewCtxt) xmlDOMWrapNewCtxt __attribute((alias("xmlDOMWrapNewCtxt__internal_alias"))); +#else +#ifndef xmlDOMWrapNewCtxt +extern __typeof (xmlDOMWrapNewCtxt) xmlDOMWrapNewCtxt__internal_alias __attribute((visibility("hidden"))); +#define xmlDOMWrapNewCtxt xmlDOMWrapNewCtxt__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlDOMWrapReconcileNamespaces +extern __typeof (xmlDOMWrapReconcileNamespaces) xmlDOMWrapReconcileNamespaces __attribute((alias("xmlDOMWrapReconcileNamespaces__internal_alias"))); +#else +#ifndef xmlDOMWrapReconcileNamespaces +extern __typeof (xmlDOMWrapReconcileNamespaces) xmlDOMWrapReconcileNamespaces__internal_alias __attribute((visibility("hidden"))); +#define xmlDOMWrapReconcileNamespaces xmlDOMWrapReconcileNamespaces__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlDOMWrapRemoveNode +extern __typeof (xmlDOMWrapRemoveNode) xmlDOMWrapRemoveNode __attribute((alias("xmlDOMWrapRemoveNode__internal_alias"))); +#else +#ifndef xmlDOMWrapRemoveNode +extern __typeof (xmlDOMWrapRemoveNode) xmlDOMWrapRemoveNode__internal_alias __attribute((visibility("hidden"))); +#define xmlDOMWrapRemoveNode xmlDOMWrapRemoveNode__internal_alias +#endif +#endif + +#if defined(LIBXML_DEBUG_ENABLED) +#ifdef bottom_debugXML +#undef xmlDebugCheckDocument +extern __typeof (xmlDebugCheckDocument) xmlDebugCheckDocument __attribute((alias("xmlDebugCheckDocument__internal_alias"))); +#else +#ifndef xmlDebugCheckDocument +extern __typeof (xmlDebugCheckDocument) xmlDebugCheckDocument__internal_alias __attribute((visibility("hidden"))); +#define xmlDebugCheckDocument xmlDebugCheckDocument__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_DEBUG_ENABLED) +#ifdef bottom_debugXML +#undef xmlDebugDumpAttr +extern __typeof (xmlDebugDumpAttr) xmlDebugDumpAttr __attribute((alias("xmlDebugDumpAttr__internal_alias"))); +#else +#ifndef xmlDebugDumpAttr +extern __typeof (xmlDebugDumpAttr) xmlDebugDumpAttr__internal_alias __attribute((visibility("hidden"))); +#define xmlDebugDumpAttr xmlDebugDumpAttr__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_DEBUG_ENABLED) +#ifdef bottom_debugXML +#undef xmlDebugDumpAttrList +extern __typeof (xmlDebugDumpAttrList) xmlDebugDumpAttrList __attribute((alias("xmlDebugDumpAttrList__internal_alias"))); +#else +#ifndef xmlDebugDumpAttrList +extern __typeof (xmlDebugDumpAttrList) xmlDebugDumpAttrList__internal_alias __attribute((visibility("hidden"))); +#define xmlDebugDumpAttrList xmlDebugDumpAttrList__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_DEBUG_ENABLED) +#ifdef bottom_debugXML +#undef xmlDebugDumpDTD +extern __typeof (xmlDebugDumpDTD) xmlDebugDumpDTD __attribute((alias("xmlDebugDumpDTD__internal_alias"))); +#else +#ifndef xmlDebugDumpDTD +extern __typeof (xmlDebugDumpDTD) xmlDebugDumpDTD__internal_alias __attribute((visibility("hidden"))); +#define xmlDebugDumpDTD xmlDebugDumpDTD__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_DEBUG_ENABLED) +#ifdef bottom_debugXML +#undef xmlDebugDumpDocument +extern __typeof (xmlDebugDumpDocument) xmlDebugDumpDocument __attribute((alias("xmlDebugDumpDocument__internal_alias"))); +#else +#ifndef xmlDebugDumpDocument +extern __typeof (xmlDebugDumpDocument) xmlDebugDumpDocument__internal_alias __attribute((visibility("hidden"))); +#define xmlDebugDumpDocument xmlDebugDumpDocument__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_DEBUG_ENABLED) +#ifdef bottom_debugXML +#undef xmlDebugDumpDocumentHead +extern __typeof (xmlDebugDumpDocumentHead) xmlDebugDumpDocumentHead __attribute((alias("xmlDebugDumpDocumentHead__internal_alias"))); +#else +#ifndef xmlDebugDumpDocumentHead +extern __typeof (xmlDebugDumpDocumentHead) xmlDebugDumpDocumentHead__internal_alias __attribute((visibility("hidden"))); +#define xmlDebugDumpDocumentHead xmlDebugDumpDocumentHead__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_DEBUG_ENABLED) +#ifdef bottom_debugXML +#undef xmlDebugDumpEntities +extern __typeof (xmlDebugDumpEntities) xmlDebugDumpEntities __attribute((alias("xmlDebugDumpEntities__internal_alias"))); +#else +#ifndef xmlDebugDumpEntities +extern __typeof (xmlDebugDumpEntities) xmlDebugDumpEntities__internal_alias __attribute((visibility("hidden"))); +#define xmlDebugDumpEntities xmlDebugDumpEntities__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_DEBUG_ENABLED) +#ifdef bottom_debugXML +#undef xmlDebugDumpNode +extern __typeof (xmlDebugDumpNode) xmlDebugDumpNode __attribute((alias("xmlDebugDumpNode__internal_alias"))); +#else +#ifndef xmlDebugDumpNode +extern __typeof (xmlDebugDumpNode) xmlDebugDumpNode__internal_alias __attribute((visibility("hidden"))); +#define xmlDebugDumpNode xmlDebugDumpNode__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_DEBUG_ENABLED) +#ifdef bottom_debugXML +#undef xmlDebugDumpNodeList +extern __typeof (xmlDebugDumpNodeList) xmlDebugDumpNodeList __attribute((alias("xmlDebugDumpNodeList__internal_alias"))); +#else +#ifndef xmlDebugDumpNodeList +extern __typeof (xmlDebugDumpNodeList) xmlDebugDumpNodeList__internal_alias __attribute((visibility("hidden"))); +#define xmlDebugDumpNodeList xmlDebugDumpNodeList__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_DEBUG_ENABLED) +#ifdef bottom_debugXML +#undef xmlDebugDumpOneNode +extern __typeof (xmlDebugDumpOneNode) xmlDebugDumpOneNode __attribute((alias("xmlDebugDumpOneNode__internal_alias"))); +#else +#ifndef xmlDebugDumpOneNode +extern __typeof (xmlDebugDumpOneNode) xmlDebugDumpOneNode__internal_alias __attribute((visibility("hidden"))); +#define xmlDebugDumpOneNode xmlDebugDumpOneNode__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_DEBUG_ENABLED) +#ifdef bottom_debugXML +#undef xmlDebugDumpString +extern __typeof (xmlDebugDumpString) xmlDebugDumpString __attribute((alias("xmlDebugDumpString__internal_alias"))); +#else +#ifndef xmlDebugDumpString +extern __typeof (xmlDebugDumpString) xmlDebugDumpString__internal_alias __attribute((visibility("hidden"))); +#define xmlDebugDumpString xmlDebugDumpString__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_LEGACY_ENABLED) +#ifdef bottom_legacy +#undef xmlDecodeEntities +extern __typeof (xmlDecodeEntities) xmlDecodeEntities __attribute((alias("xmlDecodeEntities__internal_alias"))); +#else +#ifndef xmlDecodeEntities +extern __typeof (xmlDecodeEntities) xmlDecodeEntities__internal_alias __attribute((visibility("hidden"))); +#define xmlDecodeEntities xmlDecodeEntities__internal_alias +#endif +#endif +#endif + +#ifdef bottom_SAX2 +#undef xmlDefaultSAXHandlerInit +extern __typeof (xmlDefaultSAXHandlerInit) xmlDefaultSAXHandlerInit __attribute((alias("xmlDefaultSAXHandlerInit__internal_alias"))); +#else +#ifndef xmlDefaultSAXHandlerInit +extern __typeof (xmlDefaultSAXHandlerInit) xmlDefaultSAXHandlerInit__internal_alias __attribute((visibility("hidden"))); +#define xmlDefaultSAXHandlerInit xmlDefaultSAXHandlerInit__internal_alias +#endif +#endif + +#ifdef bottom_encoding +#undef xmlDelEncodingAlias +extern __typeof (xmlDelEncodingAlias) xmlDelEncodingAlias __attribute((alias("xmlDelEncodingAlias__internal_alias"))); +#else +#ifndef xmlDelEncodingAlias +extern __typeof (xmlDelEncodingAlias) xmlDelEncodingAlias__internal_alias __attribute((visibility("hidden"))); +#define xmlDelEncodingAlias xmlDelEncodingAlias__internal_alias +#endif +#endif + +#ifdef bottom_globals +#undef xmlDeregisterNodeDefault +extern __typeof (xmlDeregisterNodeDefault) xmlDeregisterNodeDefault __attribute((alias("xmlDeregisterNodeDefault__internal_alias"))); +#else +#ifndef xmlDeregisterNodeDefault +extern __typeof (xmlDeregisterNodeDefault) xmlDeregisterNodeDefault__internal_alias __attribute((visibility("hidden"))); +#define xmlDeregisterNodeDefault xmlDeregisterNodeDefault__internal_alias +#endif +#endif + +#ifdef bottom_encoding +#undef xmlDetectCharEncoding +extern __typeof (xmlDetectCharEncoding) xmlDetectCharEncoding __attribute((alias("xmlDetectCharEncoding__internal_alias"))); +#else +#ifndef xmlDetectCharEncoding +extern __typeof (xmlDetectCharEncoding) xmlDetectCharEncoding__internal_alias __attribute((visibility("hidden"))); +#define xmlDetectCharEncoding xmlDetectCharEncoding__internal_alias +#endif +#endif + +#ifdef bottom_dict +#undef xmlDictCleanup +extern __typeof (xmlDictCleanup) xmlDictCleanup __attribute((alias("xmlDictCleanup__internal_alias"))); +#else +#ifndef xmlDictCleanup +extern __typeof (xmlDictCleanup) xmlDictCleanup__internal_alias __attribute((visibility("hidden"))); +#define xmlDictCleanup xmlDictCleanup__internal_alias +#endif +#endif + +#ifdef bottom_dict +#undef xmlDictCreate +extern __typeof (xmlDictCreate) xmlDictCreate __attribute((alias("xmlDictCreate__internal_alias"))); +#else +#ifndef xmlDictCreate +extern __typeof (xmlDictCreate) xmlDictCreate__internal_alias __attribute((visibility("hidden"))); +#define xmlDictCreate xmlDictCreate__internal_alias +#endif +#endif + +#ifdef bottom_dict +#undef xmlDictCreateSub +extern __typeof (xmlDictCreateSub) xmlDictCreateSub __attribute((alias("xmlDictCreateSub__internal_alias"))); +#else +#ifndef xmlDictCreateSub +extern __typeof (xmlDictCreateSub) xmlDictCreateSub__internal_alias __attribute((visibility("hidden"))); +#define xmlDictCreateSub xmlDictCreateSub__internal_alias +#endif +#endif + +#ifdef bottom_dict +#undef xmlDictExists +extern __typeof (xmlDictExists) xmlDictExists __attribute((alias("xmlDictExists__internal_alias"))); +#else +#ifndef xmlDictExists +extern __typeof (xmlDictExists) xmlDictExists__internal_alias __attribute((visibility("hidden"))); +#define xmlDictExists xmlDictExists__internal_alias +#endif +#endif + +#ifdef bottom_dict +#undef xmlDictFree +extern __typeof (xmlDictFree) xmlDictFree __attribute((alias("xmlDictFree__internal_alias"))); +#else +#ifndef xmlDictFree +extern __typeof (xmlDictFree) xmlDictFree__internal_alias __attribute((visibility("hidden"))); +#define xmlDictFree xmlDictFree__internal_alias +#endif +#endif + +#ifdef bottom_dict +#undef xmlDictLookup +extern __typeof (xmlDictLookup) xmlDictLookup __attribute((alias("xmlDictLookup__internal_alias"))); +#else +#ifndef xmlDictLookup +extern __typeof (xmlDictLookup) xmlDictLookup__internal_alias __attribute((visibility("hidden"))); +#define xmlDictLookup xmlDictLookup__internal_alias +#endif +#endif + +#ifdef bottom_dict +#undef xmlDictOwns +extern __typeof (xmlDictOwns) xmlDictOwns __attribute((alias("xmlDictOwns__internal_alias"))); +#else +#ifndef xmlDictOwns +extern __typeof (xmlDictOwns) xmlDictOwns__internal_alias __attribute((visibility("hidden"))); +#define xmlDictOwns xmlDictOwns__internal_alias +#endif +#endif + +#ifdef bottom_dict +#undef xmlDictQLookup +extern __typeof (xmlDictQLookup) xmlDictQLookup __attribute((alias("xmlDictQLookup__internal_alias"))); +#else +#ifndef xmlDictQLookup +extern __typeof (xmlDictQLookup) xmlDictQLookup__internal_alias __attribute((visibility("hidden"))); +#define xmlDictQLookup xmlDictQLookup__internal_alias +#endif +#endif + +#ifdef bottom_dict +#undef xmlDictReference +extern __typeof (xmlDictReference) xmlDictReference __attribute((alias("xmlDictReference__internal_alias"))); +#else +#ifndef xmlDictReference +extern __typeof (xmlDictReference) xmlDictReference__internal_alias __attribute((visibility("hidden"))); +#define xmlDictReference xmlDictReference__internal_alias +#endif +#endif + +#ifdef bottom_dict +#undef xmlDictSize +extern __typeof (xmlDictSize) xmlDictSize __attribute((alias("xmlDictSize__internal_alias"))); +#else +#ifndef xmlDictSize +extern __typeof (xmlDictSize) xmlDictSize__internal_alias __attribute((visibility("hidden"))); +#define xmlDictSize xmlDictSize__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlDocCopyNode +extern __typeof (xmlDocCopyNode) xmlDocCopyNode __attribute((alias("xmlDocCopyNode__internal_alias"))); +#else +#ifndef xmlDocCopyNode +extern __typeof (xmlDocCopyNode) xmlDocCopyNode__internal_alias __attribute((visibility("hidden"))); +#define xmlDocCopyNode xmlDocCopyNode__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlDocCopyNodeList +extern __typeof (xmlDocCopyNodeList) xmlDocCopyNodeList __attribute((alias("xmlDocCopyNodeList__internal_alias"))); +#else +#ifndef xmlDocCopyNodeList +extern __typeof (xmlDocCopyNodeList) xmlDocCopyNodeList__internal_alias __attribute((visibility("hidden"))); +#define xmlDocCopyNodeList xmlDocCopyNodeList__internal_alias +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_xmlsave +#undef xmlDocDump +extern __typeof (xmlDocDump) xmlDocDump __attribute((alias("xmlDocDump__internal_alias"))); +#else +#ifndef xmlDocDump +extern __typeof (xmlDocDump) xmlDocDump__internal_alias __attribute((visibility("hidden"))); +#define xmlDocDump xmlDocDump__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_xmlsave +#undef xmlDocDumpFormatMemory +extern __typeof (xmlDocDumpFormatMemory) xmlDocDumpFormatMemory __attribute((alias("xmlDocDumpFormatMemory__internal_alias"))); +#else +#ifndef xmlDocDumpFormatMemory +extern __typeof (xmlDocDumpFormatMemory) xmlDocDumpFormatMemory__internal_alias __attribute((visibility("hidden"))); +#define xmlDocDumpFormatMemory xmlDocDumpFormatMemory__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_xmlsave +#undef xmlDocDumpFormatMemoryEnc +extern __typeof (xmlDocDumpFormatMemoryEnc) xmlDocDumpFormatMemoryEnc __attribute((alias("xmlDocDumpFormatMemoryEnc__internal_alias"))); +#else +#ifndef xmlDocDumpFormatMemoryEnc +extern __typeof (xmlDocDumpFormatMemoryEnc) xmlDocDumpFormatMemoryEnc__internal_alias __attribute((visibility("hidden"))); +#define xmlDocDumpFormatMemoryEnc xmlDocDumpFormatMemoryEnc__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_xmlsave +#undef xmlDocDumpMemory +extern __typeof (xmlDocDumpMemory) xmlDocDumpMemory __attribute((alias("xmlDocDumpMemory__internal_alias"))); +#else +#ifndef xmlDocDumpMemory +extern __typeof (xmlDocDumpMemory) xmlDocDumpMemory__internal_alias __attribute((visibility("hidden"))); +#define xmlDocDumpMemory xmlDocDumpMemory__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_xmlsave +#undef xmlDocDumpMemoryEnc +extern __typeof (xmlDocDumpMemoryEnc) xmlDocDumpMemoryEnc __attribute((alias("xmlDocDumpMemoryEnc__internal_alias"))); +#else +#ifndef xmlDocDumpMemoryEnc +extern __typeof (xmlDocDumpMemoryEnc) xmlDocDumpMemoryEnc__internal_alias __attribute((visibility("hidden"))); +#define xmlDocDumpMemoryEnc xmlDocDumpMemoryEnc__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_xmlsave +#undef xmlDocFormatDump +extern __typeof (xmlDocFormatDump) xmlDocFormatDump __attribute((alias("xmlDocFormatDump__internal_alias"))); +#else +#ifndef xmlDocFormatDump +extern __typeof (xmlDocFormatDump) xmlDocFormatDump__internal_alias __attribute((visibility("hidden"))); +#define xmlDocFormatDump xmlDocFormatDump__internal_alias +#endif +#endif +#endif + +#ifdef bottom_tree +#undef xmlDocGetRootElement +extern __typeof (xmlDocGetRootElement) xmlDocGetRootElement __attribute((alias("xmlDocGetRootElement__internal_alias"))); +#else +#ifndef xmlDocGetRootElement +extern __typeof (xmlDocGetRootElement) xmlDocGetRootElement__internal_alias __attribute((visibility("hidden"))); +#define xmlDocGetRootElement xmlDocGetRootElement__internal_alias +#endif +#endif + +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_tree +#undef xmlDocSetRootElement +extern __typeof (xmlDocSetRootElement) xmlDocSetRootElement __attribute((alias("xmlDocSetRootElement__internal_alias"))); +#else +#ifndef xmlDocSetRootElement +extern __typeof (xmlDocSetRootElement) xmlDocSetRootElement__internal_alias __attribute((visibility("hidden"))); +#define xmlDocSetRootElement xmlDocSetRootElement__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_valid +#undef xmlDumpAttributeDecl +extern __typeof (xmlDumpAttributeDecl) xmlDumpAttributeDecl __attribute((alias("xmlDumpAttributeDecl__internal_alias"))); +#else +#ifndef xmlDumpAttributeDecl +extern __typeof (xmlDumpAttributeDecl) xmlDumpAttributeDecl__internal_alias __attribute((visibility("hidden"))); +#define xmlDumpAttributeDecl xmlDumpAttributeDecl__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_valid +#undef xmlDumpAttributeTable +extern __typeof (xmlDumpAttributeTable) xmlDumpAttributeTable __attribute((alias("xmlDumpAttributeTable__internal_alias"))); +#else +#ifndef xmlDumpAttributeTable +extern __typeof (xmlDumpAttributeTable) xmlDumpAttributeTable__internal_alias __attribute((visibility("hidden"))); +#define xmlDumpAttributeTable xmlDumpAttributeTable__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_valid +#undef xmlDumpElementDecl +extern __typeof (xmlDumpElementDecl) xmlDumpElementDecl __attribute((alias("xmlDumpElementDecl__internal_alias"))); +#else +#ifndef xmlDumpElementDecl +extern __typeof (xmlDumpElementDecl) xmlDumpElementDecl__internal_alias __attribute((visibility("hidden"))); +#define xmlDumpElementDecl xmlDumpElementDecl__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_valid +#undef xmlDumpElementTable +extern __typeof (xmlDumpElementTable) xmlDumpElementTable __attribute((alias("xmlDumpElementTable__internal_alias"))); +#else +#ifndef xmlDumpElementTable +extern __typeof (xmlDumpElementTable) xmlDumpElementTable__internal_alias __attribute((visibility("hidden"))); +#define xmlDumpElementTable xmlDumpElementTable__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_entities +#undef xmlDumpEntitiesTable +extern __typeof (xmlDumpEntitiesTable) xmlDumpEntitiesTable __attribute((alias("xmlDumpEntitiesTable__internal_alias"))); +#else +#ifndef xmlDumpEntitiesTable +extern __typeof (xmlDumpEntitiesTable) xmlDumpEntitiesTable__internal_alias __attribute((visibility("hidden"))); +#define xmlDumpEntitiesTable xmlDumpEntitiesTable__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_entities +#undef xmlDumpEntityDecl +extern __typeof (xmlDumpEntityDecl) xmlDumpEntityDecl __attribute((alias("xmlDumpEntityDecl__internal_alias"))); +#else +#ifndef xmlDumpEntityDecl +extern __typeof (xmlDumpEntityDecl) xmlDumpEntityDecl__internal_alias __attribute((visibility("hidden"))); +#define xmlDumpEntityDecl xmlDumpEntityDecl__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_valid +#undef xmlDumpNotationDecl +extern __typeof (xmlDumpNotationDecl) xmlDumpNotationDecl __attribute((alias("xmlDumpNotationDecl__internal_alias"))); +#else +#ifndef xmlDumpNotationDecl +extern __typeof (xmlDumpNotationDecl) xmlDumpNotationDecl__internal_alias __attribute((visibility("hidden"))); +#define xmlDumpNotationDecl xmlDumpNotationDecl__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_valid +#undef xmlDumpNotationTable +extern __typeof (xmlDumpNotationTable) xmlDumpNotationTable __attribute((alias("xmlDumpNotationTable__internal_alias"))); +#else +#ifndef xmlDumpNotationTable +extern __typeof (xmlDumpNotationTable) xmlDumpNotationTable__internal_alias __attribute((visibility("hidden"))); +#define xmlDumpNotationTable xmlDumpNotationTable__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_xmlsave +#undef xmlElemDump +extern __typeof (xmlElemDump) xmlElemDump __attribute((alias("xmlElemDump__internal_alias"))); +#else +#ifndef xmlElemDump +extern __typeof (xmlElemDump) xmlElemDump__internal_alias __attribute((visibility("hidden"))); +#define xmlElemDump xmlElemDump__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_LEGACY_ENABLED) +#ifdef bottom_legacy +#undef xmlEncodeEntities +extern __typeof (xmlEncodeEntities) xmlEncodeEntities __attribute((alias("xmlEncodeEntities__internal_alias"))); +#else +#ifndef xmlEncodeEntities +extern __typeof (xmlEncodeEntities) xmlEncodeEntities__internal_alias __attribute((visibility("hidden"))); +#define xmlEncodeEntities xmlEncodeEntities__internal_alias +#endif +#endif +#endif + +#ifdef bottom_entities +#undef xmlEncodeEntitiesReentrant +extern __typeof (xmlEncodeEntitiesReentrant) xmlEncodeEntitiesReentrant __attribute((alias("xmlEncodeEntitiesReentrant__internal_alias"))); +#else +#ifndef xmlEncodeEntitiesReentrant +extern __typeof (xmlEncodeEntitiesReentrant) xmlEncodeEntitiesReentrant__internal_alias __attribute((visibility("hidden"))); +#define xmlEncodeEntitiesReentrant xmlEncodeEntitiesReentrant__internal_alias +#endif +#endif + +#ifdef bottom_entities +#undef xmlEncodeSpecialChars +extern __typeof (xmlEncodeSpecialChars) xmlEncodeSpecialChars __attribute((alias("xmlEncodeSpecialChars__internal_alias"))); +#else +#ifndef xmlEncodeSpecialChars +extern __typeof (xmlEncodeSpecialChars) xmlEncodeSpecialChars__internal_alias __attribute((visibility("hidden"))); +#define xmlEncodeSpecialChars xmlEncodeSpecialChars__internal_alias +#endif +#endif + +#ifdef bottom_parserInternals +#undef xmlErrMemory +extern __typeof (xmlErrMemory) xmlErrMemory __attribute((alias("xmlErrMemory__internal_alias"))); +#else +#ifndef xmlErrMemory +extern __typeof (xmlErrMemory) xmlErrMemory__internal_alias __attribute((visibility("hidden"))); +#define xmlErrMemory xmlErrMemory__internal_alias +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) && defined(LIBXML_EXPR_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlExpCtxtNbCons +extern __typeof (xmlExpCtxtNbCons) xmlExpCtxtNbCons __attribute((alias("xmlExpCtxtNbCons__internal_alias"))); +#else +#ifndef xmlExpCtxtNbCons +extern __typeof (xmlExpCtxtNbCons) xmlExpCtxtNbCons__internal_alias __attribute((visibility("hidden"))); +#define xmlExpCtxtNbCons xmlExpCtxtNbCons__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) && defined(LIBXML_EXPR_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlExpCtxtNbNodes +extern __typeof (xmlExpCtxtNbNodes) xmlExpCtxtNbNodes __attribute((alias("xmlExpCtxtNbNodes__internal_alias"))); +#else +#ifndef xmlExpCtxtNbNodes +extern __typeof (xmlExpCtxtNbNodes) xmlExpCtxtNbNodes__internal_alias __attribute((visibility("hidden"))); +#define xmlExpCtxtNbNodes xmlExpCtxtNbNodes__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) && defined(LIBXML_EXPR_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlExpDump +extern __typeof (xmlExpDump) xmlExpDump __attribute((alias("xmlExpDump__internal_alias"))); +#else +#ifndef xmlExpDump +extern __typeof (xmlExpDump) xmlExpDump__internal_alias __attribute((visibility("hidden"))); +#define xmlExpDump xmlExpDump__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) && defined(LIBXML_EXPR_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlExpExpDerive +extern __typeof (xmlExpExpDerive) xmlExpExpDerive __attribute((alias("xmlExpExpDerive__internal_alias"))); +#else +#ifndef xmlExpExpDerive +extern __typeof (xmlExpExpDerive) xmlExpExpDerive__internal_alias __attribute((visibility("hidden"))); +#define xmlExpExpDerive xmlExpExpDerive__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) && defined(LIBXML_EXPR_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlExpFree +extern __typeof (xmlExpFree) xmlExpFree __attribute((alias("xmlExpFree__internal_alias"))); +#else +#ifndef xmlExpFree +extern __typeof (xmlExpFree) xmlExpFree__internal_alias __attribute((visibility("hidden"))); +#define xmlExpFree xmlExpFree__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) && defined(LIBXML_EXPR_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlExpFreeCtxt +extern __typeof (xmlExpFreeCtxt) xmlExpFreeCtxt __attribute((alias("xmlExpFreeCtxt__internal_alias"))); +#else +#ifndef xmlExpFreeCtxt +extern __typeof (xmlExpFreeCtxt) xmlExpFreeCtxt__internal_alias __attribute((visibility("hidden"))); +#define xmlExpFreeCtxt xmlExpFreeCtxt__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) && defined(LIBXML_EXPR_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlExpGetLanguage +extern __typeof (xmlExpGetLanguage) xmlExpGetLanguage __attribute((alias("xmlExpGetLanguage__internal_alias"))); +#else +#ifndef xmlExpGetLanguage +extern __typeof (xmlExpGetLanguage) xmlExpGetLanguage__internal_alias __attribute((visibility("hidden"))); +#define xmlExpGetLanguage xmlExpGetLanguage__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) && defined(LIBXML_EXPR_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlExpGetStart +extern __typeof (xmlExpGetStart) xmlExpGetStart __attribute((alias("xmlExpGetStart__internal_alias"))); +#else +#ifndef xmlExpGetStart +extern __typeof (xmlExpGetStart) xmlExpGetStart__internal_alias __attribute((visibility("hidden"))); +#define xmlExpGetStart xmlExpGetStart__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) && defined(LIBXML_EXPR_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlExpIsNillable +extern __typeof (xmlExpIsNillable) xmlExpIsNillable __attribute((alias("xmlExpIsNillable__internal_alias"))); +#else +#ifndef xmlExpIsNillable +extern __typeof (xmlExpIsNillable) xmlExpIsNillable__internal_alias __attribute((visibility("hidden"))); +#define xmlExpIsNillable xmlExpIsNillable__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) && defined(LIBXML_EXPR_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlExpMaxToken +extern __typeof (xmlExpMaxToken) xmlExpMaxToken __attribute((alias("xmlExpMaxToken__internal_alias"))); +#else +#ifndef xmlExpMaxToken +extern __typeof (xmlExpMaxToken) xmlExpMaxToken__internal_alias __attribute((visibility("hidden"))); +#define xmlExpMaxToken xmlExpMaxToken__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) && defined(LIBXML_EXPR_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlExpNewAtom +extern __typeof (xmlExpNewAtom) xmlExpNewAtom __attribute((alias("xmlExpNewAtom__internal_alias"))); +#else +#ifndef xmlExpNewAtom +extern __typeof (xmlExpNewAtom) xmlExpNewAtom__internal_alias __attribute((visibility("hidden"))); +#define xmlExpNewAtom xmlExpNewAtom__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) && defined(LIBXML_EXPR_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlExpNewCtxt +extern __typeof (xmlExpNewCtxt) xmlExpNewCtxt __attribute((alias("xmlExpNewCtxt__internal_alias"))); +#else +#ifndef xmlExpNewCtxt +extern __typeof (xmlExpNewCtxt) xmlExpNewCtxt__internal_alias __attribute((visibility("hidden"))); +#define xmlExpNewCtxt xmlExpNewCtxt__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) && defined(LIBXML_EXPR_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlExpNewOr +extern __typeof (xmlExpNewOr) xmlExpNewOr __attribute((alias("xmlExpNewOr__internal_alias"))); +#else +#ifndef xmlExpNewOr +extern __typeof (xmlExpNewOr) xmlExpNewOr__internal_alias __attribute((visibility("hidden"))); +#define xmlExpNewOr xmlExpNewOr__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) && defined(LIBXML_EXPR_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlExpNewRange +extern __typeof (xmlExpNewRange) xmlExpNewRange __attribute((alias("xmlExpNewRange__internal_alias"))); +#else +#ifndef xmlExpNewRange +extern __typeof (xmlExpNewRange) xmlExpNewRange__internal_alias __attribute((visibility("hidden"))); +#define xmlExpNewRange xmlExpNewRange__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) && defined(LIBXML_EXPR_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlExpNewSeq +extern __typeof (xmlExpNewSeq) xmlExpNewSeq __attribute((alias("xmlExpNewSeq__internal_alias"))); +#else +#ifndef xmlExpNewSeq +extern __typeof (xmlExpNewSeq) xmlExpNewSeq__internal_alias __attribute((visibility("hidden"))); +#define xmlExpNewSeq xmlExpNewSeq__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) && defined(LIBXML_EXPR_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlExpParse +extern __typeof (xmlExpParse) xmlExpParse __attribute((alias("xmlExpParse__internal_alias"))); +#else +#ifndef xmlExpParse +extern __typeof (xmlExpParse) xmlExpParse__internal_alias __attribute((visibility("hidden"))); +#define xmlExpParse xmlExpParse__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) && defined(LIBXML_EXPR_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlExpRef +extern __typeof (xmlExpRef) xmlExpRef __attribute((alias("xmlExpRef__internal_alias"))); +#else +#ifndef xmlExpRef +extern __typeof (xmlExpRef) xmlExpRef__internal_alias __attribute((visibility("hidden"))); +#define xmlExpRef xmlExpRef__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) && defined(LIBXML_EXPR_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlExpStringDerive +extern __typeof (xmlExpStringDerive) xmlExpStringDerive __attribute((alias("xmlExpStringDerive__internal_alias"))); +#else +#ifndef xmlExpStringDerive +extern __typeof (xmlExpStringDerive) xmlExpStringDerive__internal_alias __attribute((visibility("hidden"))); +#define xmlExpStringDerive xmlExpStringDerive__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) && defined(LIBXML_EXPR_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlExpSubsume +extern __typeof (xmlExpSubsume) xmlExpSubsume __attribute((alias("xmlExpSubsume__internal_alias"))); +#else +#ifndef xmlExpSubsume +extern __typeof (xmlExpSubsume) xmlExpSubsume__internal_alias __attribute((visibility("hidden"))); +#define xmlExpSubsume xmlExpSubsume__internal_alias +#endif +#endif +#endif + +#ifdef bottom_xmlIO +#undef xmlFileClose +extern __typeof (xmlFileClose) xmlFileClose __attribute((alias("xmlFileClose__internal_alias"))); +#else +#ifndef xmlFileClose +extern __typeof (xmlFileClose) xmlFileClose__internal_alias __attribute((visibility("hidden"))); +#define xmlFileClose xmlFileClose__internal_alias +#endif +#endif + +#ifdef bottom_xmlIO +#undef xmlFileMatch +extern __typeof (xmlFileMatch) xmlFileMatch __attribute((alias("xmlFileMatch__internal_alias"))); +#else +#ifndef xmlFileMatch +extern __typeof (xmlFileMatch) xmlFileMatch__internal_alias __attribute((visibility("hidden"))); +#define xmlFileMatch xmlFileMatch__internal_alias +#endif +#endif + +#ifdef bottom_xmlIO +#undef xmlFileOpen +extern __typeof (xmlFileOpen) xmlFileOpen __attribute((alias("xmlFileOpen__internal_alias"))); +#else +#ifndef xmlFileOpen +extern __typeof (xmlFileOpen) xmlFileOpen__internal_alias __attribute((visibility("hidden"))); +#define xmlFileOpen xmlFileOpen__internal_alias +#endif +#endif + +#ifdef bottom_xmlIO +#undef xmlFileRead +extern __typeof (xmlFileRead) xmlFileRead __attribute((alias("xmlFileRead__internal_alias"))); +#else +#ifndef xmlFileRead +extern __typeof (xmlFileRead) xmlFileRead__internal_alias __attribute((visibility("hidden"))); +#define xmlFileRead xmlFileRead__internal_alias +#endif +#endif + +#ifdef bottom_encoding +#undef xmlFindCharEncodingHandler +extern __typeof (xmlFindCharEncodingHandler) xmlFindCharEncodingHandler __attribute((alias("xmlFindCharEncodingHandler__internal_alias"))); +#else +#ifndef xmlFindCharEncodingHandler +extern __typeof (xmlFindCharEncodingHandler) xmlFindCharEncodingHandler__internal_alias __attribute((visibility("hidden"))); +#define xmlFindCharEncodingHandler xmlFindCharEncodingHandler__internal_alias +#endif +#endif + +#if defined(LIBXML_TREE_ENABLED) +#ifdef bottom_tree +#undef xmlFirstElementChild +extern __typeof (xmlFirstElementChild) xmlFirstElementChild __attribute((alias("xmlFirstElementChild__internal_alias"))); +#else +#ifndef xmlFirstElementChild +extern __typeof (xmlFirstElementChild) xmlFirstElementChild__internal_alias __attribute((visibility("hidden"))); +#define xmlFirstElementChild xmlFirstElementChild__internal_alias +#endif +#endif +#endif + +#ifdef bottom_valid +#undef xmlFreeAttributeTable +extern __typeof (xmlFreeAttributeTable) xmlFreeAttributeTable __attribute((alias("xmlFreeAttributeTable__internal_alias"))); +#else +#ifndef xmlFreeAttributeTable +extern __typeof (xmlFreeAttributeTable) xmlFreeAttributeTable__internal_alias __attribute((visibility("hidden"))); +#define xmlFreeAttributeTable xmlFreeAttributeTable__internal_alias +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) && defined(LIBXML_AUTOMATA_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlFreeAutomata +extern __typeof (xmlFreeAutomata) xmlFreeAutomata __attribute((alias("xmlFreeAutomata__internal_alias"))); +#else +#ifndef xmlFreeAutomata +extern __typeof (xmlFreeAutomata) xmlFreeAutomata__internal_alias __attribute((visibility("hidden"))); +#define xmlFreeAutomata xmlFreeAutomata__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_CATALOG_ENABLED) +#ifdef bottom_catalog +#undef xmlFreeCatalog +extern __typeof (xmlFreeCatalog) xmlFreeCatalog __attribute((alias("xmlFreeCatalog__internal_alias"))); +#else +#ifndef xmlFreeCatalog +extern __typeof (xmlFreeCatalog) xmlFreeCatalog__internal_alias __attribute((visibility("hidden"))); +#define xmlFreeCatalog xmlFreeCatalog__internal_alias +#endif +#endif +#endif + +#ifdef bottom_tree +#undef xmlFreeDoc +extern __typeof (xmlFreeDoc) xmlFreeDoc __attribute((alias("xmlFreeDoc__internal_alias"))); +#else +#ifndef xmlFreeDoc +extern __typeof (xmlFreeDoc) xmlFreeDoc__internal_alias __attribute((visibility("hidden"))); +#define xmlFreeDoc xmlFreeDoc__internal_alias +#endif +#endif + +#ifdef bottom_valid +#undef xmlFreeDocElementContent +extern __typeof (xmlFreeDocElementContent) xmlFreeDocElementContent __attribute((alias("xmlFreeDocElementContent__internal_alias"))); +#else +#ifndef xmlFreeDocElementContent +extern __typeof (xmlFreeDocElementContent) xmlFreeDocElementContent__internal_alias __attribute((visibility("hidden"))); +#define xmlFreeDocElementContent xmlFreeDocElementContent__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlFreeDtd +extern __typeof (xmlFreeDtd) xmlFreeDtd __attribute((alias("xmlFreeDtd__internal_alias"))); +#else +#ifndef xmlFreeDtd +extern __typeof (xmlFreeDtd) xmlFreeDtd__internal_alias __attribute((visibility("hidden"))); +#define xmlFreeDtd xmlFreeDtd__internal_alias +#endif +#endif + +#ifdef bottom_valid +#undef xmlFreeElementContent +extern __typeof (xmlFreeElementContent) xmlFreeElementContent __attribute((alias("xmlFreeElementContent__internal_alias"))); +#else +#ifndef xmlFreeElementContent +extern __typeof (xmlFreeElementContent) xmlFreeElementContent__internal_alias __attribute((visibility("hidden"))); +#define xmlFreeElementContent xmlFreeElementContent__internal_alias +#endif +#endif + +#ifdef bottom_valid +#undef xmlFreeElementTable +extern __typeof (xmlFreeElementTable) xmlFreeElementTable __attribute((alias("xmlFreeElementTable__internal_alias"))); +#else +#ifndef xmlFreeElementTable +extern __typeof (xmlFreeElementTable) xmlFreeElementTable__internal_alias __attribute((visibility("hidden"))); +#define xmlFreeElementTable xmlFreeElementTable__internal_alias +#endif +#endif + +#ifdef bottom_entities +#undef xmlFreeEntitiesTable +extern __typeof (xmlFreeEntitiesTable) xmlFreeEntitiesTable __attribute((alias("xmlFreeEntitiesTable__internal_alias"))); +#else +#ifndef xmlFreeEntitiesTable +extern __typeof (xmlFreeEntitiesTable) xmlFreeEntitiesTable__internal_alias __attribute((visibility("hidden"))); +#define xmlFreeEntitiesTable xmlFreeEntitiesTable__internal_alias +#endif +#endif + +#ifdef bottom_valid +#undef xmlFreeEnumeration +extern __typeof (xmlFreeEnumeration) xmlFreeEnumeration __attribute((alias("xmlFreeEnumeration__internal_alias"))); +#else +#ifndef xmlFreeEnumeration +extern __typeof (xmlFreeEnumeration) xmlFreeEnumeration__internal_alias __attribute((visibility("hidden"))); +#define xmlFreeEnumeration xmlFreeEnumeration__internal_alias +#endif +#endif + +#ifdef bottom_valid +#undef xmlFreeIDTable +extern __typeof (xmlFreeIDTable) xmlFreeIDTable __attribute((alias("xmlFreeIDTable__internal_alias"))); +#else +#ifndef xmlFreeIDTable +extern __typeof (xmlFreeIDTable) xmlFreeIDTable__internal_alias __attribute((visibility("hidden"))); +#define xmlFreeIDTable xmlFreeIDTable__internal_alias +#endif +#endif + +#ifdef bottom_parserInternals +#undef xmlFreeInputStream +extern __typeof (xmlFreeInputStream) xmlFreeInputStream __attribute((alias("xmlFreeInputStream__internal_alias"))); +#else +#ifndef xmlFreeInputStream +extern __typeof (xmlFreeInputStream) xmlFreeInputStream__internal_alias __attribute((visibility("hidden"))); +#define xmlFreeInputStream xmlFreeInputStream__internal_alias +#endif +#endif + +#ifdef bottom_threads +#undef xmlFreeMutex +extern __typeof (xmlFreeMutex) xmlFreeMutex __attribute((alias("xmlFreeMutex__internal_alias"))); +#else +#ifndef xmlFreeMutex +extern __typeof (xmlFreeMutex) xmlFreeMutex__internal_alias __attribute((visibility("hidden"))); +#define xmlFreeMutex xmlFreeMutex__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlFreeNode +extern __typeof (xmlFreeNode) xmlFreeNode __attribute((alias("xmlFreeNode__internal_alias"))); +#else +#ifndef xmlFreeNode +extern __typeof (xmlFreeNode) xmlFreeNode__internal_alias __attribute((visibility("hidden"))); +#define xmlFreeNode xmlFreeNode__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlFreeNodeList +extern __typeof (xmlFreeNodeList) xmlFreeNodeList __attribute((alias("xmlFreeNodeList__internal_alias"))); +#else +#ifndef xmlFreeNodeList +extern __typeof (xmlFreeNodeList) xmlFreeNodeList__internal_alias __attribute((visibility("hidden"))); +#define xmlFreeNodeList xmlFreeNodeList__internal_alias +#endif +#endif + +#ifdef bottom_valid +#undef xmlFreeNotationTable +extern __typeof (xmlFreeNotationTable) xmlFreeNotationTable __attribute((alias("xmlFreeNotationTable__internal_alias"))); +#else +#ifndef xmlFreeNotationTable +extern __typeof (xmlFreeNotationTable) xmlFreeNotationTable__internal_alias __attribute((visibility("hidden"))); +#define xmlFreeNotationTable xmlFreeNotationTable__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlFreeNs +extern __typeof (xmlFreeNs) xmlFreeNs __attribute((alias("xmlFreeNs__internal_alias"))); +#else +#ifndef xmlFreeNs +extern __typeof (xmlFreeNs) xmlFreeNs__internal_alias __attribute((visibility("hidden"))); +#define xmlFreeNs xmlFreeNs__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlFreeNsList +extern __typeof (xmlFreeNsList) xmlFreeNsList __attribute((alias("xmlFreeNsList__internal_alias"))); +#else +#ifndef xmlFreeNsList +extern __typeof (xmlFreeNsList) xmlFreeNsList__internal_alias __attribute((visibility("hidden"))); +#define xmlFreeNsList xmlFreeNsList__internal_alias +#endif +#endif + +#ifdef bottom_parserInternals +#undef xmlFreeParserCtxt +extern __typeof (xmlFreeParserCtxt) xmlFreeParserCtxt __attribute((alias("xmlFreeParserCtxt__internal_alias"))); +#else +#ifndef xmlFreeParserCtxt +extern __typeof (xmlFreeParserCtxt) xmlFreeParserCtxt__internal_alias __attribute((visibility("hidden"))); +#define xmlFreeParserCtxt xmlFreeParserCtxt__internal_alias +#endif +#endif + +#ifdef bottom_xmlIO +#undef xmlFreeParserInputBuffer +extern __typeof (xmlFreeParserInputBuffer) xmlFreeParserInputBuffer __attribute((alias("xmlFreeParserInputBuffer__internal_alias"))); +#else +#ifndef xmlFreeParserInputBuffer +extern __typeof (xmlFreeParserInputBuffer) xmlFreeParserInputBuffer__internal_alias __attribute((visibility("hidden"))); +#define xmlFreeParserInputBuffer xmlFreeParserInputBuffer__internal_alias +#endif +#endif + +#if defined(LIBXML_PATTERN_ENABLED) +#ifdef bottom_pattern +#undef xmlFreePattern +extern __typeof (xmlFreePattern) xmlFreePattern __attribute((alias("xmlFreePattern__internal_alias"))); +#else +#ifndef xmlFreePattern +extern __typeof (xmlFreePattern) xmlFreePattern__internal_alias __attribute((visibility("hidden"))); +#define xmlFreePattern xmlFreePattern__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_PATTERN_ENABLED) +#ifdef bottom_pattern +#undef xmlFreePatternList +extern __typeof (xmlFreePatternList) xmlFreePatternList __attribute((alias("xmlFreePatternList__internal_alias"))); +#else +#ifndef xmlFreePatternList +extern __typeof (xmlFreePatternList) xmlFreePatternList__internal_alias __attribute((visibility("hidden"))); +#define xmlFreePatternList xmlFreePatternList__internal_alias +#endif +#endif +#endif + +#ifdef bottom_tree +#undef xmlFreeProp +extern __typeof (xmlFreeProp) xmlFreeProp __attribute((alias("xmlFreeProp__internal_alias"))); +#else +#ifndef xmlFreeProp +extern __typeof (xmlFreeProp) xmlFreeProp__internal_alias __attribute((visibility("hidden"))); +#define xmlFreeProp xmlFreeProp__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlFreePropList +extern __typeof (xmlFreePropList) xmlFreePropList __attribute((alias("xmlFreePropList__internal_alias"))); +#else +#ifndef xmlFreePropList +extern __typeof (xmlFreePropList) xmlFreePropList__internal_alias __attribute((visibility("hidden"))); +#define xmlFreePropList xmlFreePropList__internal_alias +#endif +#endif + +#ifdef bottom_threads +#undef xmlFreeRMutex +extern __typeof (xmlFreeRMutex) xmlFreeRMutex __attribute((alias("xmlFreeRMutex__internal_alias"))); +#else +#ifndef xmlFreeRMutex +extern __typeof (xmlFreeRMutex) xmlFreeRMutex__internal_alias __attribute((visibility("hidden"))); +#define xmlFreeRMutex xmlFreeRMutex__internal_alias +#endif +#endif + +#ifdef bottom_valid +#undef xmlFreeRefTable +extern __typeof (xmlFreeRefTable) xmlFreeRefTable __attribute((alias("xmlFreeRefTable__internal_alias"))); +#else +#ifndef xmlFreeRefTable +extern __typeof (xmlFreeRefTable) xmlFreeRefTable__internal_alias __attribute((visibility("hidden"))); +#define xmlFreeRefTable xmlFreeRefTable__internal_alias +#endif +#endif + +#if defined(LIBXML_PATTERN_ENABLED) +#ifdef bottom_pattern +#undef xmlFreeStreamCtxt +extern __typeof (xmlFreeStreamCtxt) xmlFreeStreamCtxt __attribute((alias("xmlFreeStreamCtxt__internal_alias"))); +#else +#ifndef xmlFreeStreamCtxt +extern __typeof (xmlFreeStreamCtxt) xmlFreeStreamCtxt__internal_alias __attribute((visibility("hidden"))); +#define xmlFreeStreamCtxt xmlFreeStreamCtxt__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlFreeTextReader +extern __typeof (xmlFreeTextReader) xmlFreeTextReader __attribute((alias("xmlFreeTextReader__internal_alias"))); +#else +#ifndef xmlFreeTextReader +extern __typeof (xmlFreeTextReader) xmlFreeTextReader__internal_alias __attribute((visibility("hidden"))); +#define xmlFreeTextReader xmlFreeTextReader__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlFreeTextWriter +extern __typeof (xmlFreeTextWriter) xmlFreeTextWriter __attribute((alias("xmlFreeTextWriter__internal_alias"))); +#else +#ifndef xmlFreeTextWriter +extern __typeof (xmlFreeTextWriter) xmlFreeTextWriter__internal_alias __attribute((visibility("hidden"))); +#define xmlFreeTextWriter xmlFreeTextWriter__internal_alias +#endif +#endif +#endif + +#ifdef bottom_uri +#undef xmlFreeURI +extern __typeof (xmlFreeURI) xmlFreeURI __attribute((alias("xmlFreeURI__internal_alias"))); +#else +#ifndef xmlFreeURI +extern __typeof (xmlFreeURI) xmlFreeURI__internal_alias __attribute((visibility("hidden"))); +#define xmlFreeURI xmlFreeURI__internal_alias +#endif +#endif + +#if defined(LIBXML_VALID_ENABLED) +#ifdef bottom_valid +#undef xmlFreeValidCtxt +extern __typeof (xmlFreeValidCtxt) xmlFreeValidCtxt __attribute((alias("xmlFreeValidCtxt__internal_alias"))); +#else +#ifndef xmlFreeValidCtxt +extern __typeof (xmlFreeValidCtxt) xmlFreeValidCtxt__internal_alias __attribute((visibility("hidden"))); +#define xmlFreeValidCtxt xmlFreeValidCtxt__internal_alias +#endif +#endif +#endif + +#ifdef bottom_xmlmemory +#undef xmlGcMemGet +extern __typeof (xmlGcMemGet) xmlGcMemGet __attribute((alias("xmlGcMemGet__internal_alias"))); +#else +#ifndef xmlGcMemGet +extern __typeof (xmlGcMemGet) xmlGcMemGet__internal_alias __attribute((visibility("hidden"))); +#define xmlGcMemGet xmlGcMemGet__internal_alias +#endif +#endif + +#ifdef bottom_xmlmemory +#undef xmlGcMemSetup +extern __typeof (xmlGcMemSetup) xmlGcMemSetup __attribute((alias("xmlGcMemSetup__internal_alias"))); +#else +#ifndef xmlGcMemSetup +extern __typeof (xmlGcMemSetup) xmlGcMemSetup__internal_alias __attribute((visibility("hidden"))); +#define xmlGcMemSetup xmlGcMemSetup__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlGetBufferAllocationScheme +extern __typeof (xmlGetBufferAllocationScheme) xmlGetBufferAllocationScheme __attribute((alias("xmlGetBufferAllocationScheme__internal_alias"))); +#else +#ifndef xmlGetBufferAllocationScheme +extern __typeof (xmlGetBufferAllocationScheme) xmlGetBufferAllocationScheme__internal_alias __attribute((visibility("hidden"))); +#define xmlGetBufferAllocationScheme xmlGetBufferAllocationScheme__internal_alias +#endif +#endif + +#ifdef bottom_encoding +#undef xmlGetCharEncodingHandler +extern __typeof (xmlGetCharEncodingHandler) xmlGetCharEncodingHandler __attribute((alias("xmlGetCharEncodingHandler__internal_alias"))); +#else +#ifndef xmlGetCharEncodingHandler +extern __typeof (xmlGetCharEncodingHandler) xmlGetCharEncodingHandler__internal_alias __attribute((visibility("hidden"))); +#define xmlGetCharEncodingHandler xmlGetCharEncodingHandler__internal_alias +#endif +#endif + +#ifdef bottom_encoding +#undef xmlGetCharEncodingName +extern __typeof (xmlGetCharEncodingName) xmlGetCharEncodingName __attribute((alias("xmlGetCharEncodingName__internal_alias"))); +#else +#ifndef xmlGetCharEncodingName +extern __typeof (xmlGetCharEncodingName) xmlGetCharEncodingName__internal_alias __attribute((visibility("hidden"))); +#define xmlGetCharEncodingName xmlGetCharEncodingName__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlGetCompressMode +extern __typeof (xmlGetCompressMode) xmlGetCompressMode __attribute((alias("xmlGetCompressMode__internal_alias"))); +#else +#ifndef xmlGetCompressMode +extern __typeof (xmlGetCompressMode) xmlGetCompressMode__internal_alias __attribute((visibility("hidden"))); +#define xmlGetCompressMode xmlGetCompressMode__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlGetDocCompressMode +extern __typeof (xmlGetDocCompressMode) xmlGetDocCompressMode __attribute((alias("xmlGetDocCompressMode__internal_alias"))); +#else +#ifndef xmlGetDocCompressMode +extern __typeof (xmlGetDocCompressMode) xmlGetDocCompressMode__internal_alias __attribute((visibility("hidden"))); +#define xmlGetDocCompressMode xmlGetDocCompressMode__internal_alias +#endif +#endif + +#ifdef bottom_entities +#undef xmlGetDocEntity +extern __typeof (xmlGetDocEntity) xmlGetDocEntity __attribute((alias("xmlGetDocEntity__internal_alias"))); +#else +#ifndef xmlGetDocEntity +extern __typeof (xmlGetDocEntity) xmlGetDocEntity__internal_alias __attribute((visibility("hidden"))); +#define xmlGetDocEntity xmlGetDocEntity__internal_alias +#endif +#endif + +#ifdef bottom_valid +#undef xmlGetDtdAttrDesc +extern __typeof (xmlGetDtdAttrDesc) xmlGetDtdAttrDesc __attribute((alias("xmlGetDtdAttrDesc__internal_alias"))); +#else +#ifndef xmlGetDtdAttrDesc +extern __typeof (xmlGetDtdAttrDesc) xmlGetDtdAttrDesc__internal_alias __attribute((visibility("hidden"))); +#define xmlGetDtdAttrDesc xmlGetDtdAttrDesc__internal_alias +#endif +#endif + +#ifdef bottom_valid +#undef xmlGetDtdElementDesc +extern __typeof (xmlGetDtdElementDesc) xmlGetDtdElementDesc __attribute((alias("xmlGetDtdElementDesc__internal_alias"))); +#else +#ifndef xmlGetDtdElementDesc +extern __typeof (xmlGetDtdElementDesc) xmlGetDtdElementDesc__internal_alias __attribute((visibility("hidden"))); +#define xmlGetDtdElementDesc xmlGetDtdElementDesc__internal_alias +#endif +#endif + +#ifdef bottom_entities +#undef xmlGetDtdEntity +extern __typeof (xmlGetDtdEntity) xmlGetDtdEntity __attribute((alias("xmlGetDtdEntity__internal_alias"))); +#else +#ifndef xmlGetDtdEntity +extern __typeof (xmlGetDtdEntity) xmlGetDtdEntity__internal_alias __attribute((visibility("hidden"))); +#define xmlGetDtdEntity xmlGetDtdEntity__internal_alias +#endif +#endif + +#ifdef bottom_valid +#undef xmlGetDtdNotationDesc +extern __typeof (xmlGetDtdNotationDesc) xmlGetDtdNotationDesc __attribute((alias("xmlGetDtdNotationDesc__internal_alias"))); +#else +#ifndef xmlGetDtdNotationDesc +extern __typeof (xmlGetDtdNotationDesc) xmlGetDtdNotationDesc__internal_alias __attribute((visibility("hidden"))); +#define xmlGetDtdNotationDesc xmlGetDtdNotationDesc__internal_alias +#endif +#endif + +#ifdef bottom_valid +#undef xmlGetDtdQAttrDesc +extern __typeof (xmlGetDtdQAttrDesc) xmlGetDtdQAttrDesc __attribute((alias("xmlGetDtdQAttrDesc__internal_alias"))); +#else +#ifndef xmlGetDtdQAttrDesc +extern __typeof (xmlGetDtdQAttrDesc) xmlGetDtdQAttrDesc__internal_alias __attribute((visibility("hidden"))); +#define xmlGetDtdQAttrDesc xmlGetDtdQAttrDesc__internal_alias +#endif +#endif + +#ifdef bottom_valid +#undef xmlGetDtdQElementDesc +extern __typeof (xmlGetDtdQElementDesc) xmlGetDtdQElementDesc __attribute((alias("xmlGetDtdQElementDesc__internal_alias"))); +#else +#ifndef xmlGetDtdQElementDesc +extern __typeof (xmlGetDtdQElementDesc) xmlGetDtdQElementDesc__internal_alias __attribute((visibility("hidden"))); +#define xmlGetDtdQElementDesc xmlGetDtdQElementDesc__internal_alias +#endif +#endif + +#ifdef bottom_encoding +#undef xmlGetEncodingAlias +extern __typeof (xmlGetEncodingAlias) xmlGetEncodingAlias __attribute((alias("xmlGetEncodingAlias__internal_alias"))); +#else +#ifndef xmlGetEncodingAlias +extern __typeof (xmlGetEncodingAlias) xmlGetEncodingAlias__internal_alias __attribute((visibility("hidden"))); +#define xmlGetEncodingAlias xmlGetEncodingAlias__internal_alias +#endif +#endif + +#ifdef bottom_xmlIO +#undef xmlGetExternalEntityLoader +extern __typeof (xmlGetExternalEntityLoader) xmlGetExternalEntityLoader __attribute((alias("xmlGetExternalEntityLoader__internal_alias"))); +#else +#ifndef xmlGetExternalEntityLoader +extern __typeof (xmlGetExternalEntityLoader) xmlGetExternalEntityLoader__internal_alias __attribute((visibility("hidden"))); +#define xmlGetExternalEntityLoader xmlGetExternalEntityLoader__internal_alias +#endif +#endif + +#if defined(LIBXML_LEGACY_ENABLED) +#ifdef bottom_legacy +#undef xmlGetFeature +extern __typeof (xmlGetFeature) xmlGetFeature __attribute((alias("xmlGetFeature__internal_alias"))); +#else +#ifndef xmlGetFeature +extern __typeof (xmlGetFeature) xmlGetFeature__internal_alias __attribute((visibility("hidden"))); +#define xmlGetFeature xmlGetFeature__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_LEGACY_ENABLED) +#ifdef bottom_legacy +#undef xmlGetFeaturesList +extern __typeof (xmlGetFeaturesList) xmlGetFeaturesList __attribute((alias("xmlGetFeaturesList__internal_alias"))); +#else +#ifndef xmlGetFeaturesList +extern __typeof (xmlGetFeaturesList) xmlGetFeaturesList__internal_alias __attribute((visibility("hidden"))); +#define xmlGetFeaturesList xmlGetFeaturesList__internal_alias +#endif +#endif +#endif + +#ifdef bottom_threads +#undef xmlGetGlobalState +extern __typeof (xmlGetGlobalState) xmlGetGlobalState __attribute((alias("xmlGetGlobalState__internal_alias"))); +#else +#ifndef xmlGetGlobalState +extern __typeof (xmlGetGlobalState) xmlGetGlobalState__internal_alias __attribute((visibility("hidden"))); +#define xmlGetGlobalState xmlGetGlobalState__internal_alias +#endif +#endif + +#ifdef bottom_valid +#undef xmlGetID +extern __typeof (xmlGetID) xmlGetID __attribute((alias("xmlGetID__internal_alias"))); +#else +#ifndef xmlGetID +extern __typeof (xmlGetID) xmlGetID__internal_alias __attribute((visibility("hidden"))); +#define xmlGetID xmlGetID__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlGetIntSubset +extern __typeof (xmlGetIntSubset) xmlGetIntSubset __attribute((alias("xmlGetIntSubset__internal_alias"))); +#else +#ifndef xmlGetIntSubset +extern __typeof (xmlGetIntSubset) xmlGetIntSubset__internal_alias __attribute((visibility("hidden"))); +#define xmlGetIntSubset xmlGetIntSubset__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlGetLastChild +extern __typeof (xmlGetLastChild) xmlGetLastChild __attribute((alias("xmlGetLastChild__internal_alias"))); +#else +#ifndef xmlGetLastChild +extern __typeof (xmlGetLastChild) xmlGetLastChild__internal_alias __attribute((visibility("hidden"))); +#define xmlGetLastChild xmlGetLastChild__internal_alias +#endif +#endif + +#ifdef bottom_error +#undef xmlGetLastError +extern __typeof (xmlGetLastError) xmlGetLastError __attribute((alias("xmlGetLastError__internal_alias"))); +#else +#ifndef xmlGetLastError +extern __typeof (xmlGetLastError) xmlGetLastError__internal_alias __attribute((visibility("hidden"))); +#define xmlGetLastError xmlGetLastError__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlGetLineNo +extern __typeof (xmlGetLineNo) xmlGetLineNo __attribute((alias("xmlGetLineNo__internal_alias"))); +#else +#ifndef xmlGetLineNo +extern __typeof (xmlGetLineNo) xmlGetLineNo__internal_alias __attribute((visibility("hidden"))); +#define xmlGetLineNo xmlGetLineNo__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlGetNoNsProp +extern __typeof (xmlGetNoNsProp) xmlGetNoNsProp __attribute((alias("xmlGetNoNsProp__internal_alias"))); +#else +#ifndef xmlGetNoNsProp +extern __typeof (xmlGetNoNsProp) xmlGetNoNsProp__internal_alias __attribute((visibility("hidden"))); +#define xmlGetNoNsProp xmlGetNoNsProp__internal_alias +#endif +#endif + +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED) +#ifdef bottom_tree +#undef xmlGetNodePath +extern __typeof (xmlGetNodePath) xmlGetNodePath __attribute((alias("xmlGetNodePath__internal_alias"))); +#else +#ifndef xmlGetNodePath +extern __typeof (xmlGetNodePath) xmlGetNodePath__internal_alias __attribute((visibility("hidden"))); +#define xmlGetNodePath xmlGetNodePath__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_tree +#undef xmlGetNsList +extern __typeof (xmlGetNsList) xmlGetNsList __attribute((alias("xmlGetNsList__internal_alias"))); +#else +#ifndef xmlGetNsList +extern __typeof (xmlGetNsList) xmlGetNsList__internal_alias __attribute((visibility("hidden"))); +#define xmlGetNsList xmlGetNsList__internal_alias +#endif +#endif +#endif + +#ifdef bottom_tree +#undef xmlGetNsProp +extern __typeof (xmlGetNsProp) xmlGetNsProp __attribute((alias("xmlGetNsProp__internal_alias"))); +#else +#ifndef xmlGetNsProp +extern __typeof (xmlGetNsProp) xmlGetNsProp__internal_alias __attribute((visibility("hidden"))); +#define xmlGetNsProp xmlGetNsProp__internal_alias +#endif +#endif + +#ifdef bottom_entities +#undef xmlGetParameterEntity +extern __typeof (xmlGetParameterEntity) xmlGetParameterEntity __attribute((alias("xmlGetParameterEntity__internal_alias"))); +#else +#ifndef xmlGetParameterEntity +extern __typeof (xmlGetParameterEntity) xmlGetParameterEntity__internal_alias __attribute((visibility("hidden"))); +#define xmlGetParameterEntity xmlGetParameterEntity__internal_alias +#endif +#endif + +#ifdef bottom_entities +#undef xmlGetPredefinedEntity +extern __typeof (xmlGetPredefinedEntity) xmlGetPredefinedEntity __attribute((alias("xmlGetPredefinedEntity__internal_alias"))); +#else +#ifndef xmlGetPredefinedEntity +extern __typeof (xmlGetPredefinedEntity) xmlGetPredefinedEntity__internal_alias __attribute((visibility("hidden"))); +#define xmlGetPredefinedEntity xmlGetPredefinedEntity__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlGetProp +extern __typeof (xmlGetProp) xmlGetProp __attribute((alias("xmlGetProp__internal_alias"))); +#else +#ifndef xmlGetProp +extern __typeof (xmlGetProp) xmlGetProp__internal_alias __attribute((visibility("hidden"))); +#define xmlGetProp xmlGetProp__internal_alias +#endif +#endif + +#ifdef bottom_valid +#undef xmlGetRefs +extern __typeof (xmlGetRefs) xmlGetRefs __attribute((alias("xmlGetRefs__internal_alias"))); +#else +#ifndef xmlGetRefs +extern __typeof (xmlGetRefs) xmlGetRefs__internal_alias __attribute((visibility("hidden"))); +#define xmlGetRefs xmlGetRefs__internal_alias +#endif +#endif + +#ifdef bottom_threads +#undef xmlGetThreadId +extern __typeof (xmlGetThreadId) xmlGetThreadId __attribute((alias("xmlGetThreadId__internal_alias"))); +#else +#ifndef xmlGetThreadId +extern __typeof (xmlGetThreadId) xmlGetThreadId__internal_alias __attribute((visibility("hidden"))); +#define xmlGetThreadId xmlGetThreadId__internal_alias +#endif +#endif + +#ifdef bottom_xmlstring +#undef xmlGetUTF8Char +extern __typeof (xmlGetUTF8Char) xmlGetUTF8Char __attribute((alias("xmlGetUTF8Char__internal_alias"))); +#else +#ifndef xmlGetUTF8Char +extern __typeof (xmlGetUTF8Char) xmlGetUTF8Char__internal_alias __attribute((visibility("hidden"))); +#define xmlGetUTF8Char xmlGetUTF8Char__internal_alias +#endif +#endif + +#if defined(LIBXML_LEGACY_ENABLED) +#ifdef bottom_legacy +#undef xmlHandleEntity +extern __typeof (xmlHandleEntity) xmlHandleEntity __attribute((alias("xmlHandleEntity__internal_alias"))); +#else +#ifndef xmlHandleEntity +extern __typeof (xmlHandleEntity) xmlHandleEntity__internal_alias __attribute((visibility("hidden"))); +#define xmlHandleEntity xmlHandleEntity__internal_alias +#endif +#endif +#endif + +#ifdef bottom_parser +#undef xmlHasFeature +extern __typeof (xmlHasFeature) xmlHasFeature __attribute((alias("xmlHasFeature__internal_alias"))); +#else +#ifndef xmlHasFeature +extern __typeof (xmlHasFeature) xmlHasFeature__internal_alias __attribute((visibility("hidden"))); +#define xmlHasFeature xmlHasFeature__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlHasNsProp +extern __typeof (xmlHasNsProp) xmlHasNsProp __attribute((alias("xmlHasNsProp__internal_alias"))); +#else +#ifndef xmlHasNsProp +extern __typeof (xmlHasNsProp) xmlHasNsProp__internal_alias __attribute((visibility("hidden"))); +#define xmlHasNsProp xmlHasNsProp__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlHasProp +extern __typeof (xmlHasProp) xmlHasProp __attribute((alias("xmlHasProp__internal_alias"))); +#else +#ifndef xmlHasProp +extern __typeof (xmlHasProp) xmlHasProp__internal_alias __attribute((visibility("hidden"))); +#define xmlHasProp xmlHasProp__internal_alias +#endif +#endif + +#ifdef bottom_hash +#undef xmlHashAddEntry +extern __typeof (xmlHashAddEntry) xmlHashAddEntry __attribute((alias("xmlHashAddEntry__internal_alias"))); +#else +#ifndef xmlHashAddEntry +extern __typeof (xmlHashAddEntry) xmlHashAddEntry__internal_alias __attribute((visibility("hidden"))); +#define xmlHashAddEntry xmlHashAddEntry__internal_alias +#endif +#endif + +#ifdef bottom_hash +#undef xmlHashAddEntry2 +extern __typeof (xmlHashAddEntry2) xmlHashAddEntry2 __attribute((alias("xmlHashAddEntry2__internal_alias"))); +#else +#ifndef xmlHashAddEntry2 +extern __typeof (xmlHashAddEntry2) xmlHashAddEntry2__internal_alias __attribute((visibility("hidden"))); +#define xmlHashAddEntry2 xmlHashAddEntry2__internal_alias +#endif +#endif + +#ifdef bottom_hash +#undef xmlHashAddEntry3 +extern __typeof (xmlHashAddEntry3) xmlHashAddEntry3 __attribute((alias("xmlHashAddEntry3__internal_alias"))); +#else +#ifndef xmlHashAddEntry3 +extern __typeof (xmlHashAddEntry3) xmlHashAddEntry3__internal_alias __attribute((visibility("hidden"))); +#define xmlHashAddEntry3 xmlHashAddEntry3__internal_alias +#endif +#endif + +#ifdef bottom_hash +#undef xmlHashCopy +extern __typeof (xmlHashCopy) xmlHashCopy __attribute((alias("xmlHashCopy__internal_alias"))); +#else +#ifndef xmlHashCopy +extern __typeof (xmlHashCopy) xmlHashCopy__internal_alias __attribute((visibility("hidden"))); +#define xmlHashCopy xmlHashCopy__internal_alias +#endif +#endif + +#ifdef bottom_hash +#undef xmlHashCreate +extern __typeof (xmlHashCreate) xmlHashCreate __attribute((alias("xmlHashCreate__internal_alias"))); +#else +#ifndef xmlHashCreate +extern __typeof (xmlHashCreate) xmlHashCreate__internal_alias __attribute((visibility("hidden"))); +#define xmlHashCreate xmlHashCreate__internal_alias +#endif +#endif + +#ifdef bottom_hash +#undef xmlHashCreateDict +extern __typeof (xmlHashCreateDict) xmlHashCreateDict __attribute((alias("xmlHashCreateDict__internal_alias"))); +#else +#ifndef xmlHashCreateDict +extern __typeof (xmlHashCreateDict) xmlHashCreateDict__internal_alias __attribute((visibility("hidden"))); +#define xmlHashCreateDict xmlHashCreateDict__internal_alias +#endif +#endif + +#ifdef bottom_hash +#undef xmlHashFree +extern __typeof (xmlHashFree) xmlHashFree __attribute((alias("xmlHashFree__internal_alias"))); +#else +#ifndef xmlHashFree +extern __typeof (xmlHashFree) xmlHashFree__internal_alias __attribute((visibility("hidden"))); +#define xmlHashFree xmlHashFree__internal_alias +#endif +#endif + +#ifdef bottom_hash +#undef xmlHashLookup +extern __typeof (xmlHashLookup) xmlHashLookup __attribute((alias("xmlHashLookup__internal_alias"))); +#else +#ifndef xmlHashLookup +extern __typeof (xmlHashLookup) xmlHashLookup__internal_alias __attribute((visibility("hidden"))); +#define xmlHashLookup xmlHashLookup__internal_alias +#endif +#endif + +#ifdef bottom_hash +#undef xmlHashLookup2 +extern __typeof (xmlHashLookup2) xmlHashLookup2 __attribute((alias("xmlHashLookup2__internal_alias"))); +#else +#ifndef xmlHashLookup2 +extern __typeof (xmlHashLookup2) xmlHashLookup2__internal_alias __attribute((visibility("hidden"))); +#define xmlHashLookup2 xmlHashLookup2__internal_alias +#endif +#endif + +#ifdef bottom_hash +#undef xmlHashLookup3 +extern __typeof (xmlHashLookup3) xmlHashLookup3 __attribute((alias("xmlHashLookup3__internal_alias"))); +#else +#ifndef xmlHashLookup3 +extern __typeof (xmlHashLookup3) xmlHashLookup3__internal_alias __attribute((visibility("hidden"))); +#define xmlHashLookup3 xmlHashLookup3__internal_alias +#endif +#endif + +#ifdef bottom_hash +#undef xmlHashQLookup +extern __typeof (xmlHashQLookup) xmlHashQLookup __attribute((alias("xmlHashQLookup__internal_alias"))); +#else +#ifndef xmlHashQLookup +extern __typeof (xmlHashQLookup) xmlHashQLookup__internal_alias __attribute((visibility("hidden"))); +#define xmlHashQLookup xmlHashQLookup__internal_alias +#endif +#endif + +#ifdef bottom_hash +#undef xmlHashQLookup2 +extern __typeof (xmlHashQLookup2) xmlHashQLookup2 __attribute((alias("xmlHashQLookup2__internal_alias"))); +#else +#ifndef xmlHashQLookup2 +extern __typeof (xmlHashQLookup2) xmlHashQLookup2__internal_alias __attribute((visibility("hidden"))); +#define xmlHashQLookup2 xmlHashQLookup2__internal_alias +#endif +#endif + +#ifdef bottom_hash +#undef xmlHashQLookup3 +extern __typeof (xmlHashQLookup3) xmlHashQLookup3 __attribute((alias("xmlHashQLookup3__internal_alias"))); +#else +#ifndef xmlHashQLookup3 +extern __typeof (xmlHashQLookup3) xmlHashQLookup3__internal_alias __attribute((visibility("hidden"))); +#define xmlHashQLookup3 xmlHashQLookup3__internal_alias +#endif +#endif + +#ifdef bottom_hash +#undef xmlHashRemoveEntry +extern __typeof (xmlHashRemoveEntry) xmlHashRemoveEntry __attribute((alias("xmlHashRemoveEntry__internal_alias"))); +#else +#ifndef xmlHashRemoveEntry +extern __typeof (xmlHashRemoveEntry) xmlHashRemoveEntry__internal_alias __attribute((visibility("hidden"))); +#define xmlHashRemoveEntry xmlHashRemoveEntry__internal_alias +#endif +#endif + +#ifdef bottom_hash +#undef xmlHashRemoveEntry2 +extern __typeof (xmlHashRemoveEntry2) xmlHashRemoveEntry2 __attribute((alias("xmlHashRemoveEntry2__internal_alias"))); +#else +#ifndef xmlHashRemoveEntry2 +extern __typeof (xmlHashRemoveEntry2) xmlHashRemoveEntry2__internal_alias __attribute((visibility("hidden"))); +#define xmlHashRemoveEntry2 xmlHashRemoveEntry2__internal_alias +#endif +#endif + +#ifdef bottom_hash +#undef xmlHashRemoveEntry3 +extern __typeof (xmlHashRemoveEntry3) xmlHashRemoveEntry3 __attribute((alias("xmlHashRemoveEntry3__internal_alias"))); +#else +#ifndef xmlHashRemoveEntry3 +extern __typeof (xmlHashRemoveEntry3) xmlHashRemoveEntry3__internal_alias __attribute((visibility("hidden"))); +#define xmlHashRemoveEntry3 xmlHashRemoveEntry3__internal_alias +#endif +#endif + +#ifdef bottom_hash +#undef xmlHashScan +extern __typeof (xmlHashScan) xmlHashScan __attribute((alias("xmlHashScan__internal_alias"))); +#else +#ifndef xmlHashScan +extern __typeof (xmlHashScan) xmlHashScan__internal_alias __attribute((visibility("hidden"))); +#define xmlHashScan xmlHashScan__internal_alias +#endif +#endif + +#ifdef bottom_hash +#undef xmlHashScan3 +extern __typeof (xmlHashScan3) xmlHashScan3 __attribute((alias("xmlHashScan3__internal_alias"))); +#else +#ifndef xmlHashScan3 +extern __typeof (xmlHashScan3) xmlHashScan3__internal_alias __attribute((visibility("hidden"))); +#define xmlHashScan3 xmlHashScan3__internal_alias +#endif +#endif + +#ifdef bottom_hash +#undef xmlHashScanFull +extern __typeof (xmlHashScanFull) xmlHashScanFull __attribute((alias("xmlHashScanFull__internal_alias"))); +#else +#ifndef xmlHashScanFull +extern __typeof (xmlHashScanFull) xmlHashScanFull__internal_alias __attribute((visibility("hidden"))); +#define xmlHashScanFull xmlHashScanFull__internal_alias +#endif +#endif + +#ifdef bottom_hash +#undef xmlHashScanFull3 +extern __typeof (xmlHashScanFull3) xmlHashScanFull3 __attribute((alias("xmlHashScanFull3__internal_alias"))); +#else +#ifndef xmlHashScanFull3 +extern __typeof (xmlHashScanFull3) xmlHashScanFull3__internal_alias __attribute((visibility("hidden"))); +#define xmlHashScanFull3 xmlHashScanFull3__internal_alias +#endif +#endif + +#ifdef bottom_hash +#undef xmlHashSize +extern __typeof (xmlHashSize) xmlHashSize __attribute((alias("xmlHashSize__internal_alias"))); +#else +#ifndef xmlHashSize +extern __typeof (xmlHashSize) xmlHashSize__internal_alias __attribute((visibility("hidden"))); +#define xmlHashSize xmlHashSize__internal_alias +#endif +#endif + +#ifdef bottom_hash +#undef xmlHashUpdateEntry +extern __typeof (xmlHashUpdateEntry) xmlHashUpdateEntry __attribute((alias("xmlHashUpdateEntry__internal_alias"))); +#else +#ifndef xmlHashUpdateEntry +extern __typeof (xmlHashUpdateEntry) xmlHashUpdateEntry__internal_alias __attribute((visibility("hidden"))); +#define xmlHashUpdateEntry xmlHashUpdateEntry__internal_alias +#endif +#endif + +#ifdef bottom_hash +#undef xmlHashUpdateEntry2 +extern __typeof (xmlHashUpdateEntry2) xmlHashUpdateEntry2 __attribute((alias("xmlHashUpdateEntry2__internal_alias"))); +#else +#ifndef xmlHashUpdateEntry2 +extern __typeof (xmlHashUpdateEntry2) xmlHashUpdateEntry2__internal_alias __attribute((visibility("hidden"))); +#define xmlHashUpdateEntry2 xmlHashUpdateEntry2__internal_alias +#endif +#endif + +#ifdef bottom_hash +#undef xmlHashUpdateEntry3 +extern __typeof (xmlHashUpdateEntry3) xmlHashUpdateEntry3 __attribute((alias("xmlHashUpdateEntry3__internal_alias"))); +#else +#ifndef xmlHashUpdateEntry3 +extern __typeof (xmlHashUpdateEntry3) xmlHashUpdateEntry3__internal_alias __attribute((visibility("hidden"))); +#define xmlHashUpdateEntry3 xmlHashUpdateEntry3__internal_alias +#endif +#endif + +#if defined(LIBXML_VALID_ENABLED) +#ifdef bottom_parser +#undef xmlIOParseDTD +extern __typeof (xmlIOParseDTD) xmlIOParseDTD __attribute((alias("xmlIOParseDTD__internal_alias"))); +#else +#ifndef xmlIOParseDTD +extern __typeof (xmlIOParseDTD) xmlIOParseDTD__internal_alias __attribute((visibility("hidden"))); +#define xmlIOParseDTD xmlIOParseDTD__internal_alias +#endif +#endif +#endif + +#ifdef bottom_encoding +#undef xmlInitCharEncodingHandlers +extern __typeof (xmlInitCharEncodingHandlers) xmlInitCharEncodingHandlers __attribute((alias("xmlInitCharEncodingHandlers__internal_alias"))); +#else +#ifndef xmlInitCharEncodingHandlers +extern __typeof (xmlInitCharEncodingHandlers) xmlInitCharEncodingHandlers__internal_alias __attribute((visibility("hidden"))); +#define xmlInitCharEncodingHandlers xmlInitCharEncodingHandlers__internal_alias +#endif +#endif + +#ifdef bottom_globals +#undef xmlInitGlobals +extern __typeof (xmlInitGlobals) xmlInitGlobals __attribute((alias("xmlInitGlobals__internal_alias"))); +#else +#ifndef xmlInitGlobals +extern __typeof (xmlInitGlobals) xmlInitGlobals__internal_alias __attribute((visibility("hidden"))); +#define xmlInitGlobals xmlInitGlobals__internal_alias +#endif +#endif + +#ifdef bottom_xmlmemory +#undef xmlInitMemory +extern __typeof (xmlInitMemory) xmlInitMemory __attribute((alias("xmlInitMemory__internal_alias"))); +#else +#ifndef xmlInitMemory +extern __typeof (xmlInitMemory) xmlInitMemory__internal_alias __attribute((visibility("hidden"))); +#define xmlInitMemory xmlInitMemory__internal_alias +#endif +#endif + +#ifdef bottom_parserInternals +#undef xmlInitNodeInfoSeq +extern __typeof (xmlInitNodeInfoSeq) xmlInitNodeInfoSeq __attribute((alias("xmlInitNodeInfoSeq__internal_alias"))); +#else +#ifndef xmlInitNodeInfoSeq +extern __typeof (xmlInitNodeInfoSeq) xmlInitNodeInfoSeq__internal_alias __attribute((visibility("hidden"))); +#define xmlInitNodeInfoSeq xmlInitNodeInfoSeq__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlInitParser +extern __typeof (xmlInitParser) xmlInitParser __attribute((alias("xmlInitParser__internal_alias"))); +#else +#ifndef xmlInitParser +extern __typeof (xmlInitParser) xmlInitParser__internal_alias __attribute((visibility("hidden"))); +#define xmlInitParser xmlInitParser__internal_alias +#endif +#endif + +#ifdef bottom_parserInternals +#undef xmlInitParserCtxt +extern __typeof (xmlInitParserCtxt) xmlInitParserCtxt __attribute((alias("xmlInitParserCtxt__internal_alias"))); +#else +#ifndef xmlInitParserCtxt +extern __typeof (xmlInitParserCtxt) xmlInitParserCtxt__internal_alias __attribute((visibility("hidden"))); +#define xmlInitParserCtxt xmlInitParserCtxt__internal_alias +#endif +#endif + +#ifdef bottom_threads +#undef xmlInitThreads +extern __typeof (xmlInitThreads) xmlInitThreads __attribute((alias("xmlInitThreads__internal_alias"))); +#else +#ifndef xmlInitThreads +extern __typeof (xmlInitThreads) xmlInitThreads__internal_alias __attribute((visibility("hidden"))); +#define xmlInitThreads xmlInitThreads__internal_alias +#endif +#endif + +#if defined(LIBXML_CATALOG_ENABLED) +#ifdef bottom_catalog +#undef xmlInitializeCatalog +extern __typeof (xmlInitializeCatalog) xmlInitializeCatalog __attribute((alias("xmlInitializeCatalog__internal_alias"))); +#else +#ifndef xmlInitializeCatalog +extern __typeof (xmlInitializeCatalog) xmlInitializeCatalog__internal_alias __attribute((visibility("hidden"))); +#define xmlInitializeCatalog xmlInitializeCatalog__internal_alias +#endif +#endif +#endif + +#ifdef bottom_globals +#undef xmlInitializeGlobalState +extern __typeof (xmlInitializeGlobalState) xmlInitializeGlobalState __attribute((alias("xmlInitializeGlobalState__internal_alias"))); +#else +#ifndef xmlInitializeGlobalState +extern __typeof (xmlInitializeGlobalState) xmlInitializeGlobalState__internal_alias __attribute((visibility("hidden"))); +#define xmlInitializeGlobalState xmlInitializeGlobalState__internal_alias +#endif +#endif + +#if defined(LIBXML_LEGACY_ENABLED) +#ifdef bottom_legacy +#undef xmlInitializePredefinedEntities +extern __typeof (xmlInitializePredefinedEntities) xmlInitializePredefinedEntities __attribute((alias("xmlInitializePredefinedEntities__internal_alias"))); +#else +#ifndef xmlInitializePredefinedEntities +extern __typeof (xmlInitializePredefinedEntities) xmlInitializePredefinedEntities__internal_alias __attribute((visibility("hidden"))); +#define xmlInitializePredefinedEntities xmlInitializePredefinedEntities__internal_alias +#endif +#endif +#endif + +#ifdef bottom_chvalid +#undef xmlIsBaseChar +extern __typeof (xmlIsBaseChar) xmlIsBaseChar __attribute((alias("xmlIsBaseChar__internal_alias"))); +#else +#ifndef xmlIsBaseChar +extern __typeof (xmlIsBaseChar) xmlIsBaseChar__internal_alias __attribute((visibility("hidden"))); +#define xmlIsBaseChar xmlIsBaseChar__internal_alias +#endif +#endif + +#ifdef bottom_chvalid +#undef xmlIsBlank +extern __typeof (xmlIsBlank) xmlIsBlank __attribute((alias("xmlIsBlank__internal_alias"))); +#else +#ifndef xmlIsBlank +extern __typeof (xmlIsBlank) xmlIsBlank__internal_alias __attribute((visibility("hidden"))); +#define xmlIsBlank xmlIsBlank__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlIsBlankNode +extern __typeof (xmlIsBlankNode) xmlIsBlankNode __attribute((alias("xmlIsBlankNode__internal_alias"))); +#else +#ifndef xmlIsBlankNode +extern __typeof (xmlIsBlankNode) xmlIsBlankNode__internal_alias __attribute((visibility("hidden"))); +#define xmlIsBlankNode xmlIsBlankNode__internal_alias +#endif +#endif + +#ifdef bottom_chvalid +#undef xmlIsChar +extern __typeof (xmlIsChar) xmlIsChar __attribute((alias("xmlIsChar__internal_alias"))); +#else +#ifndef xmlIsChar +extern __typeof (xmlIsChar) xmlIsChar__internal_alias __attribute((visibility("hidden"))); +#define xmlIsChar xmlIsChar__internal_alias +#endif +#endif + +#ifdef bottom_chvalid +#undef xmlIsCombining +extern __typeof (xmlIsCombining) xmlIsCombining __attribute((alias("xmlIsCombining__internal_alias"))); +#else +#ifndef xmlIsCombining +extern __typeof (xmlIsCombining) xmlIsCombining__internal_alias __attribute((visibility("hidden"))); +#define xmlIsCombining xmlIsCombining__internal_alias +#endif +#endif + +#ifdef bottom_chvalid +#undef xmlIsDigit +extern __typeof (xmlIsDigit) xmlIsDigit __attribute((alias("xmlIsDigit__internal_alias"))); +#else +#ifndef xmlIsDigit +extern __typeof (xmlIsDigit) xmlIsDigit__internal_alias __attribute((visibility("hidden"))); +#define xmlIsDigit xmlIsDigit__internal_alias +#endif +#endif + +#ifdef bottom_chvalid +#undef xmlIsExtender +extern __typeof (xmlIsExtender) xmlIsExtender __attribute((alias("xmlIsExtender__internal_alias"))); +#else +#ifndef xmlIsExtender +extern __typeof (xmlIsExtender) xmlIsExtender__internal_alias __attribute((visibility("hidden"))); +#define xmlIsExtender xmlIsExtender__internal_alias +#endif +#endif + +#ifdef bottom_valid +#undef xmlIsID +extern __typeof (xmlIsID) xmlIsID __attribute((alias("xmlIsID__internal_alias"))); +#else +#ifndef xmlIsID +extern __typeof (xmlIsID) xmlIsID__internal_alias __attribute((visibility("hidden"))); +#define xmlIsID xmlIsID__internal_alias +#endif +#endif + +#ifdef bottom_chvalid +#undef xmlIsIdeographic +extern __typeof (xmlIsIdeographic) xmlIsIdeographic __attribute((alias("xmlIsIdeographic__internal_alias"))); +#else +#ifndef xmlIsIdeographic +extern __typeof (xmlIsIdeographic) xmlIsIdeographic__internal_alias __attribute((visibility("hidden"))); +#define xmlIsIdeographic xmlIsIdeographic__internal_alias +#endif +#endif + +#ifdef bottom_parserInternals +#undef xmlIsLetter +extern __typeof (xmlIsLetter) xmlIsLetter __attribute((alias("xmlIsLetter__internal_alias"))); +#else +#ifndef xmlIsLetter +extern __typeof (xmlIsLetter) xmlIsLetter__internal_alias __attribute((visibility("hidden"))); +#define xmlIsLetter xmlIsLetter__internal_alias +#endif +#endif + +#ifdef bottom_threads +#undef xmlIsMainThread +extern __typeof (xmlIsMainThread) xmlIsMainThread __attribute((alias("xmlIsMainThread__internal_alias"))); +#else +#ifndef xmlIsMainThread +extern __typeof (xmlIsMainThread) xmlIsMainThread__internal_alias __attribute((visibility("hidden"))); +#define xmlIsMainThread xmlIsMainThread__internal_alias +#endif +#endif + +#ifdef bottom_valid +#undef xmlIsMixedElement +extern __typeof (xmlIsMixedElement) xmlIsMixedElement __attribute((alias("xmlIsMixedElement__internal_alias"))); +#else +#ifndef xmlIsMixedElement +extern __typeof (xmlIsMixedElement) xmlIsMixedElement__internal_alias __attribute((visibility("hidden"))); +#define xmlIsMixedElement xmlIsMixedElement__internal_alias +#endif +#endif + +#ifdef bottom_chvalid +#undef xmlIsPubidChar +extern __typeof (xmlIsPubidChar) xmlIsPubidChar __attribute((alias("xmlIsPubidChar__internal_alias"))); +#else +#ifndef xmlIsPubidChar +extern __typeof (xmlIsPubidChar) xmlIsPubidChar__internal_alias __attribute((visibility("hidden"))); +#define xmlIsPubidChar xmlIsPubidChar__internal_alias +#endif +#endif + +#ifdef bottom_valid +#undef xmlIsRef +extern __typeof (xmlIsRef) xmlIsRef __attribute((alias("xmlIsRef__internal_alias"))); +#else +#ifndef xmlIsRef +extern __typeof (xmlIsRef) xmlIsRef__internal_alias __attribute((visibility("hidden"))); +#define xmlIsRef xmlIsRef__internal_alias +#endif +#endif + +#ifdef bottom_xmlsave +#undef xmlIsXHTML +extern __typeof (xmlIsXHTML) xmlIsXHTML __attribute((alias("xmlIsXHTML__internal_alias"))); +#else +#ifndef xmlIsXHTML +extern __typeof (xmlIsXHTML) xmlIsXHTML__internal_alias __attribute((visibility("hidden"))); +#define xmlIsXHTML xmlIsXHTML__internal_alias +#endif +#endif + +#ifdef bottom_parserInternals +#undef xmlKeepBlanksDefault +extern __typeof (xmlKeepBlanksDefault) xmlKeepBlanksDefault __attribute((alias("xmlKeepBlanksDefault__internal_alias"))); +#else +#ifndef xmlKeepBlanksDefault +extern __typeof (xmlKeepBlanksDefault) xmlKeepBlanksDefault__internal_alias __attribute((visibility("hidden"))); +#define xmlKeepBlanksDefault xmlKeepBlanksDefault__internal_alias +#endif +#endif + +#if defined(LIBXML_TREE_ENABLED) +#ifdef bottom_tree +#undef xmlLastElementChild +extern __typeof (xmlLastElementChild) xmlLastElementChild __attribute((alias("xmlLastElementChild__internal_alias"))); +#else +#ifndef xmlLastElementChild +extern __typeof (xmlLastElementChild) xmlLastElementChild__internal_alias __attribute((visibility("hidden"))); +#define xmlLastElementChild xmlLastElementChild__internal_alias +#endif +#endif +#endif + +#ifdef bottom_parserInternals +#undef xmlLineNumbersDefault +extern __typeof (xmlLineNumbersDefault) xmlLineNumbersDefault __attribute((alias("xmlLineNumbersDefault__internal_alias"))); +#else +#ifndef xmlLineNumbersDefault +extern __typeof (xmlLineNumbersDefault) xmlLineNumbersDefault__internal_alias __attribute((visibility("hidden"))); +#define xmlLineNumbersDefault xmlLineNumbersDefault__internal_alias +#endif +#endif + +#ifdef bottom_list +#undef xmlLinkGetData +extern __typeof (xmlLinkGetData) xmlLinkGetData __attribute((alias("xmlLinkGetData__internal_alias"))); +#else +#ifndef xmlLinkGetData +extern __typeof (xmlLinkGetData) xmlLinkGetData__internal_alias __attribute((visibility("hidden"))); +#define xmlLinkGetData xmlLinkGetData__internal_alias +#endif +#endif + +#ifdef bottom_list +#undef xmlListAppend +extern __typeof (xmlListAppend) xmlListAppend __attribute((alias("xmlListAppend__internal_alias"))); +#else +#ifndef xmlListAppend +extern __typeof (xmlListAppend) xmlListAppend__internal_alias __attribute((visibility("hidden"))); +#define xmlListAppend xmlListAppend__internal_alias +#endif +#endif + +#ifdef bottom_list +#undef xmlListClear +extern __typeof (xmlListClear) xmlListClear __attribute((alias("xmlListClear__internal_alias"))); +#else +#ifndef xmlListClear +extern __typeof (xmlListClear) xmlListClear__internal_alias __attribute((visibility("hidden"))); +#define xmlListClear xmlListClear__internal_alias +#endif +#endif + +#ifdef bottom_list +#undef xmlListCopy +extern __typeof (xmlListCopy) xmlListCopy __attribute((alias("xmlListCopy__internal_alias"))); +#else +#ifndef xmlListCopy +extern __typeof (xmlListCopy) xmlListCopy__internal_alias __attribute((visibility("hidden"))); +#define xmlListCopy xmlListCopy__internal_alias +#endif +#endif + +#ifdef bottom_list +#undef xmlListCreate +extern __typeof (xmlListCreate) xmlListCreate __attribute((alias("xmlListCreate__internal_alias"))); +#else +#ifndef xmlListCreate +extern __typeof (xmlListCreate) xmlListCreate__internal_alias __attribute((visibility("hidden"))); +#define xmlListCreate xmlListCreate__internal_alias +#endif +#endif + +#ifdef bottom_list +#undef xmlListDelete +extern __typeof (xmlListDelete) xmlListDelete __attribute((alias("xmlListDelete__internal_alias"))); +#else +#ifndef xmlListDelete +extern __typeof (xmlListDelete) xmlListDelete__internal_alias __attribute((visibility("hidden"))); +#define xmlListDelete xmlListDelete__internal_alias +#endif +#endif + +#ifdef bottom_list +#undef xmlListDup +extern __typeof (xmlListDup) xmlListDup __attribute((alias("xmlListDup__internal_alias"))); +#else +#ifndef xmlListDup +extern __typeof (xmlListDup) xmlListDup__internal_alias __attribute((visibility("hidden"))); +#define xmlListDup xmlListDup__internal_alias +#endif +#endif + +#ifdef bottom_list +#undef xmlListEmpty +extern __typeof (xmlListEmpty) xmlListEmpty __attribute((alias("xmlListEmpty__internal_alias"))); +#else +#ifndef xmlListEmpty +extern __typeof (xmlListEmpty) xmlListEmpty__internal_alias __attribute((visibility("hidden"))); +#define xmlListEmpty xmlListEmpty__internal_alias +#endif +#endif + +#ifdef bottom_list +#undef xmlListEnd +extern __typeof (xmlListEnd) xmlListEnd __attribute((alias("xmlListEnd__internal_alias"))); +#else +#ifndef xmlListEnd +extern __typeof (xmlListEnd) xmlListEnd__internal_alias __attribute((visibility("hidden"))); +#define xmlListEnd xmlListEnd__internal_alias +#endif +#endif + +#ifdef bottom_list +#undef xmlListFront +extern __typeof (xmlListFront) xmlListFront __attribute((alias("xmlListFront__internal_alias"))); +#else +#ifndef xmlListFront +extern __typeof (xmlListFront) xmlListFront__internal_alias __attribute((visibility("hidden"))); +#define xmlListFront xmlListFront__internal_alias +#endif +#endif + +#ifdef bottom_list +#undef xmlListInsert +extern __typeof (xmlListInsert) xmlListInsert __attribute((alias("xmlListInsert__internal_alias"))); +#else +#ifndef xmlListInsert +extern __typeof (xmlListInsert) xmlListInsert__internal_alias __attribute((visibility("hidden"))); +#define xmlListInsert xmlListInsert__internal_alias +#endif +#endif + +#ifdef bottom_list +#undef xmlListMerge +extern __typeof (xmlListMerge) xmlListMerge __attribute((alias("xmlListMerge__internal_alias"))); +#else +#ifndef xmlListMerge +extern __typeof (xmlListMerge) xmlListMerge__internal_alias __attribute((visibility("hidden"))); +#define xmlListMerge xmlListMerge__internal_alias +#endif +#endif + +#ifdef bottom_list +#undef xmlListPopBack +extern __typeof (xmlListPopBack) xmlListPopBack __attribute((alias("xmlListPopBack__internal_alias"))); +#else +#ifndef xmlListPopBack +extern __typeof (xmlListPopBack) xmlListPopBack__internal_alias __attribute((visibility("hidden"))); +#define xmlListPopBack xmlListPopBack__internal_alias +#endif +#endif + +#ifdef bottom_list +#undef xmlListPopFront +extern __typeof (xmlListPopFront) xmlListPopFront __attribute((alias("xmlListPopFront__internal_alias"))); +#else +#ifndef xmlListPopFront +extern __typeof (xmlListPopFront) xmlListPopFront__internal_alias __attribute((visibility("hidden"))); +#define xmlListPopFront xmlListPopFront__internal_alias +#endif +#endif + +#ifdef bottom_list +#undef xmlListPushBack +extern __typeof (xmlListPushBack) xmlListPushBack __attribute((alias("xmlListPushBack__internal_alias"))); +#else +#ifndef xmlListPushBack +extern __typeof (xmlListPushBack) xmlListPushBack__internal_alias __attribute((visibility("hidden"))); +#define xmlListPushBack xmlListPushBack__internal_alias +#endif +#endif + +#ifdef bottom_list +#undef xmlListPushFront +extern __typeof (xmlListPushFront) xmlListPushFront __attribute((alias("xmlListPushFront__internal_alias"))); +#else +#ifndef xmlListPushFront +extern __typeof (xmlListPushFront) xmlListPushFront__internal_alias __attribute((visibility("hidden"))); +#define xmlListPushFront xmlListPushFront__internal_alias +#endif +#endif + +#ifdef bottom_list +#undef xmlListRemoveAll +extern __typeof (xmlListRemoveAll) xmlListRemoveAll __attribute((alias("xmlListRemoveAll__internal_alias"))); +#else +#ifndef xmlListRemoveAll +extern __typeof (xmlListRemoveAll) xmlListRemoveAll__internal_alias __attribute((visibility("hidden"))); +#define xmlListRemoveAll xmlListRemoveAll__internal_alias +#endif +#endif + +#ifdef bottom_list +#undef xmlListRemoveFirst +extern __typeof (xmlListRemoveFirst) xmlListRemoveFirst __attribute((alias("xmlListRemoveFirst__internal_alias"))); +#else +#ifndef xmlListRemoveFirst +extern __typeof (xmlListRemoveFirst) xmlListRemoveFirst__internal_alias __attribute((visibility("hidden"))); +#define xmlListRemoveFirst xmlListRemoveFirst__internal_alias +#endif +#endif + +#ifdef bottom_list +#undef xmlListRemoveLast +extern __typeof (xmlListRemoveLast) xmlListRemoveLast __attribute((alias("xmlListRemoveLast__internal_alias"))); +#else +#ifndef xmlListRemoveLast +extern __typeof (xmlListRemoveLast) xmlListRemoveLast__internal_alias __attribute((visibility("hidden"))); +#define xmlListRemoveLast xmlListRemoveLast__internal_alias +#endif +#endif + +#ifdef bottom_list +#undef xmlListReverse +extern __typeof (xmlListReverse) xmlListReverse __attribute((alias("xmlListReverse__internal_alias"))); +#else +#ifndef xmlListReverse +extern __typeof (xmlListReverse) xmlListReverse__internal_alias __attribute((visibility("hidden"))); +#define xmlListReverse xmlListReverse__internal_alias +#endif +#endif + +#ifdef bottom_list +#undef xmlListReverseSearch +extern __typeof (xmlListReverseSearch) xmlListReverseSearch __attribute((alias("xmlListReverseSearch__internal_alias"))); +#else +#ifndef xmlListReverseSearch +extern __typeof (xmlListReverseSearch) xmlListReverseSearch__internal_alias __attribute((visibility("hidden"))); +#define xmlListReverseSearch xmlListReverseSearch__internal_alias +#endif +#endif + +#ifdef bottom_list +#undef xmlListReverseWalk +extern __typeof (xmlListReverseWalk) xmlListReverseWalk __attribute((alias("xmlListReverseWalk__internal_alias"))); +#else +#ifndef xmlListReverseWalk +extern __typeof (xmlListReverseWalk) xmlListReverseWalk__internal_alias __attribute((visibility("hidden"))); +#define xmlListReverseWalk xmlListReverseWalk__internal_alias +#endif +#endif + +#ifdef bottom_list +#undef xmlListSearch +extern __typeof (xmlListSearch) xmlListSearch __attribute((alias("xmlListSearch__internal_alias"))); +#else +#ifndef xmlListSearch +extern __typeof (xmlListSearch) xmlListSearch__internal_alias __attribute((visibility("hidden"))); +#define xmlListSearch xmlListSearch__internal_alias +#endif +#endif + +#ifdef bottom_list +#undef xmlListSize +extern __typeof (xmlListSize) xmlListSize __attribute((alias("xmlListSize__internal_alias"))); +#else +#ifndef xmlListSize +extern __typeof (xmlListSize) xmlListSize__internal_alias __attribute((visibility("hidden"))); +#define xmlListSize xmlListSize__internal_alias +#endif +#endif + +#ifdef bottom_list +#undef xmlListSort +extern __typeof (xmlListSort) xmlListSort __attribute((alias("xmlListSort__internal_alias"))); +#else +#ifndef xmlListSort +extern __typeof (xmlListSort) xmlListSort__internal_alias __attribute((visibility("hidden"))); +#define xmlListSort xmlListSort__internal_alias +#endif +#endif + +#ifdef bottom_list +#undef xmlListWalk +extern __typeof (xmlListWalk) xmlListWalk __attribute((alias("xmlListWalk__internal_alias"))); +#else +#ifndef xmlListWalk +extern __typeof (xmlListWalk) xmlListWalk__internal_alias __attribute((visibility("hidden"))); +#define xmlListWalk xmlListWalk__internal_alias +#endif +#endif + +#if defined(LIBXML_CATALOG_ENABLED) +#ifdef bottom_catalog +#undef xmlLoadACatalog +extern __typeof (xmlLoadACatalog) xmlLoadACatalog __attribute((alias("xmlLoadACatalog__internal_alias"))); +#else +#ifndef xmlLoadACatalog +extern __typeof (xmlLoadACatalog) xmlLoadACatalog__internal_alias __attribute((visibility("hidden"))); +#define xmlLoadACatalog xmlLoadACatalog__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_CATALOG_ENABLED) +#ifdef bottom_catalog +#undef xmlLoadCatalog +extern __typeof (xmlLoadCatalog) xmlLoadCatalog __attribute((alias("xmlLoadCatalog__internal_alias"))); +#else +#ifndef xmlLoadCatalog +extern __typeof (xmlLoadCatalog) xmlLoadCatalog__internal_alias __attribute((visibility("hidden"))); +#define xmlLoadCatalog xmlLoadCatalog__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_CATALOG_ENABLED) +#ifdef bottom_catalog +#undef xmlLoadCatalogs +extern __typeof (xmlLoadCatalogs) xmlLoadCatalogs __attribute((alias("xmlLoadCatalogs__internal_alias"))); +#else +#ifndef xmlLoadCatalogs +extern __typeof (xmlLoadCatalogs) xmlLoadCatalogs__internal_alias __attribute((visibility("hidden"))); +#define xmlLoadCatalogs xmlLoadCatalogs__internal_alias +#endif +#endif +#endif + +#ifdef bottom_xmlIO +#undef xmlLoadExternalEntity +extern __typeof (xmlLoadExternalEntity) xmlLoadExternalEntity __attribute((alias("xmlLoadExternalEntity__internal_alias"))); +#else +#ifndef xmlLoadExternalEntity +extern __typeof (xmlLoadExternalEntity) xmlLoadExternalEntity__internal_alias __attribute((visibility("hidden"))); +#define xmlLoadExternalEntity xmlLoadExternalEntity__internal_alias +#endif +#endif + +#if defined(LIBXML_CATALOG_ENABLED) +#ifdef bottom_catalog +#undef xmlLoadSGMLSuperCatalog +extern __typeof (xmlLoadSGMLSuperCatalog) xmlLoadSGMLSuperCatalog __attribute((alias("xmlLoadSGMLSuperCatalog__internal_alias"))); +#else +#ifndef xmlLoadSGMLSuperCatalog +extern __typeof (xmlLoadSGMLSuperCatalog) xmlLoadSGMLSuperCatalog__internal_alias __attribute((visibility("hidden"))); +#define xmlLoadSGMLSuperCatalog xmlLoadSGMLSuperCatalog__internal_alias +#endif +#endif +#endif + +#ifdef bottom_threads +#undef xmlLockLibrary +extern __typeof (xmlLockLibrary) xmlLockLibrary __attribute((alias("xmlLockLibrary__internal_alias"))); +#else +#ifndef xmlLockLibrary +extern __typeof (xmlLockLibrary) xmlLockLibrary__internal_alias __attribute((visibility("hidden"))); +#define xmlLockLibrary xmlLockLibrary__internal_alias +#endif +#endif + +#if defined(LIBXML_DEBUG_ENABLED) +#ifdef bottom_debugXML +#undef xmlLsCountNode +extern __typeof (xmlLsCountNode) xmlLsCountNode __attribute((alias("xmlLsCountNode__internal_alias"))); +#else +#ifndef xmlLsCountNode +extern __typeof (xmlLsCountNode) xmlLsCountNode__internal_alias __attribute((visibility("hidden"))); +#define xmlLsCountNode xmlLsCountNode__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_DEBUG_ENABLED) +#ifdef bottom_debugXML +#undef xmlLsOneNode +extern __typeof (xmlLsOneNode) xmlLsOneNode __attribute((alias("xmlLsOneNode__internal_alias"))); +#else +#ifndef xmlLsOneNode +extern __typeof (xmlLsOneNode) xmlLsOneNode__internal_alias __attribute((visibility("hidden"))); +#define xmlLsOneNode xmlLsOneNode__internal_alias +#endif +#endif +#endif + +#ifdef bottom_xmlmemory +#undef xmlMallocAtomicLoc +extern __typeof (xmlMallocAtomicLoc) xmlMallocAtomicLoc __attribute((alias("xmlMallocAtomicLoc__internal_alias"))); +#else +#ifndef xmlMallocAtomicLoc +extern __typeof (xmlMallocAtomicLoc) xmlMallocAtomicLoc__internal_alias __attribute((visibility("hidden"))); +#define xmlMallocAtomicLoc xmlMallocAtomicLoc__internal_alias +#endif +#endif + +#ifdef bottom_xmlmemory +#undef xmlMallocLoc +extern __typeof (xmlMallocLoc) xmlMallocLoc __attribute((alias("xmlMallocLoc__internal_alias"))); +#else +#ifndef xmlMallocLoc +extern __typeof (xmlMallocLoc) xmlMallocLoc__internal_alias __attribute((visibility("hidden"))); +#define xmlMallocLoc xmlMallocLoc__internal_alias +#endif +#endif + +#ifdef bottom_xmlmemory +#undef xmlMemBlocks +extern __typeof (xmlMemBlocks) xmlMemBlocks __attribute((alias("xmlMemBlocks__internal_alias"))); +#else +#ifndef xmlMemBlocks +extern __typeof (xmlMemBlocks) xmlMemBlocks__internal_alias __attribute((visibility("hidden"))); +#define xmlMemBlocks xmlMemBlocks__internal_alias +#endif +#endif + +#ifdef bottom_xmlmemory +#undef xmlMemDisplay +extern __typeof (xmlMemDisplay) xmlMemDisplay __attribute((alias("xmlMemDisplay__internal_alias"))); +#else +#ifndef xmlMemDisplay +extern __typeof (xmlMemDisplay) xmlMemDisplay__internal_alias __attribute((visibility("hidden"))); +#define xmlMemDisplay xmlMemDisplay__internal_alias +#endif +#endif + +#ifdef bottom_xmlmemory +#undef xmlMemDisplayLast +extern __typeof (xmlMemDisplayLast) xmlMemDisplayLast __attribute((alias("xmlMemDisplayLast__internal_alias"))); +#else +#ifndef xmlMemDisplayLast +extern __typeof (xmlMemDisplayLast) xmlMemDisplayLast__internal_alias __attribute((visibility("hidden"))); +#define xmlMemDisplayLast xmlMemDisplayLast__internal_alias +#endif +#endif + +#ifdef bottom_xmlmemory +#undef xmlMemFree +extern __typeof (xmlMemFree) xmlMemFree __attribute((alias("xmlMemFree__internal_alias"))); +#else +#ifndef xmlMemFree +extern __typeof (xmlMemFree) xmlMemFree__internal_alias __attribute((visibility("hidden"))); +#define xmlMemFree xmlMemFree__internal_alias +#endif +#endif + +#ifdef bottom_xmlmemory +#undef xmlMemGet +extern __typeof (xmlMemGet) xmlMemGet __attribute((alias("xmlMemGet__internal_alias"))); +#else +#ifndef xmlMemGet +extern __typeof (xmlMemGet) xmlMemGet__internal_alias __attribute((visibility("hidden"))); +#define xmlMemGet xmlMemGet__internal_alias +#endif +#endif + +#ifdef bottom_xmlmemory +#undef xmlMemMalloc +extern __typeof (xmlMemMalloc) xmlMemMalloc __attribute((alias("xmlMemMalloc__internal_alias"))); +#else +#ifndef xmlMemMalloc +extern __typeof (xmlMemMalloc) xmlMemMalloc__internal_alias __attribute((visibility("hidden"))); +#define xmlMemMalloc xmlMemMalloc__internal_alias +#endif +#endif + +#ifdef bottom_xmlmemory +#undef xmlMemRealloc +extern __typeof (xmlMemRealloc) xmlMemRealloc __attribute((alias("xmlMemRealloc__internal_alias"))); +#else +#ifndef xmlMemRealloc +extern __typeof (xmlMemRealloc) xmlMemRealloc__internal_alias __attribute((visibility("hidden"))); +#define xmlMemRealloc xmlMemRealloc__internal_alias +#endif +#endif + +#ifdef bottom_xmlmemory +#undef xmlMemSetup +extern __typeof (xmlMemSetup) xmlMemSetup __attribute((alias("xmlMemSetup__internal_alias"))); +#else +#ifndef xmlMemSetup +extern __typeof (xmlMemSetup) xmlMemSetup__internal_alias __attribute((visibility("hidden"))); +#define xmlMemSetup xmlMemSetup__internal_alias +#endif +#endif + +#ifdef bottom_xmlmemory +#undef xmlMemShow +extern __typeof (xmlMemShow) xmlMemShow __attribute((alias("xmlMemShow__internal_alias"))); +#else +#ifndef xmlMemShow +extern __typeof (xmlMemShow) xmlMemShow__internal_alias __attribute((visibility("hidden"))); +#define xmlMemShow xmlMemShow__internal_alias +#endif +#endif + +#ifdef bottom_xmlmemory +#undef xmlMemStrdupLoc +extern __typeof (xmlMemStrdupLoc) xmlMemStrdupLoc __attribute((alias("xmlMemStrdupLoc__internal_alias"))); +#else +#ifndef xmlMemStrdupLoc +extern __typeof (xmlMemStrdupLoc) xmlMemStrdupLoc__internal_alias __attribute((visibility("hidden"))); +#define xmlMemStrdupLoc xmlMemStrdupLoc__internal_alias +#endif +#endif + +#ifdef bottom_xmlmemory +#undef xmlMemUsed +extern __typeof (xmlMemUsed) xmlMemUsed __attribute((alias("xmlMemUsed__internal_alias"))); +#else +#ifndef xmlMemUsed +extern __typeof (xmlMemUsed) xmlMemUsed__internal_alias __attribute((visibility("hidden"))); +#define xmlMemUsed xmlMemUsed__internal_alias +#endif +#endif + +#ifdef bottom_xmlmemory +#undef xmlMemoryDump +extern __typeof (xmlMemoryDump) xmlMemoryDump __attribute((alias("xmlMemoryDump__internal_alias"))); +#else +#ifndef xmlMemoryDump +extern __typeof (xmlMemoryDump) xmlMemoryDump__internal_alias __attribute((visibility("hidden"))); +#define xmlMemoryDump xmlMemoryDump__internal_alias +#endif +#endif + +#ifdef bottom_xmlmemory +#undef xmlMemoryStrdup +extern __typeof (xmlMemoryStrdup) xmlMemoryStrdup __attribute((alias("xmlMemoryStrdup__internal_alias"))); +#else +#ifndef xmlMemoryStrdup +extern __typeof (xmlMemoryStrdup) xmlMemoryStrdup__internal_alias __attribute((visibility("hidden"))); +#define xmlMemoryStrdup xmlMemoryStrdup__internal_alias +#endif +#endif + +#if defined(LIBXML_MODULES_ENABLED) +#ifdef bottom_xmlmodule +#undef xmlModuleClose +extern __typeof (xmlModuleClose) xmlModuleClose __attribute((alias("xmlModuleClose__internal_alias"))); +#else +#ifndef xmlModuleClose +extern __typeof (xmlModuleClose) xmlModuleClose__internal_alias __attribute((visibility("hidden"))); +#define xmlModuleClose xmlModuleClose__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_MODULES_ENABLED) +#ifdef bottom_xmlmodule +#undef xmlModuleFree +extern __typeof (xmlModuleFree) xmlModuleFree __attribute((alias("xmlModuleFree__internal_alias"))); +#else +#ifndef xmlModuleFree +extern __typeof (xmlModuleFree) xmlModuleFree__internal_alias __attribute((visibility("hidden"))); +#define xmlModuleFree xmlModuleFree__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_MODULES_ENABLED) +#ifdef bottom_xmlmodule +#undef xmlModuleOpen +extern __typeof (xmlModuleOpen) xmlModuleOpen __attribute((alias("xmlModuleOpen__internal_alias"))); +#else +#ifndef xmlModuleOpen +extern __typeof (xmlModuleOpen) xmlModuleOpen__internal_alias __attribute((visibility("hidden"))); +#define xmlModuleOpen xmlModuleOpen__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_MODULES_ENABLED) +#ifdef bottom_xmlmodule +#undef xmlModuleSymbol +extern __typeof (xmlModuleSymbol) xmlModuleSymbol __attribute((alias("xmlModuleSymbol__internal_alias"))); +#else +#ifndef xmlModuleSymbol +extern __typeof (xmlModuleSymbol) xmlModuleSymbol__internal_alias __attribute((visibility("hidden"))); +#define xmlModuleSymbol xmlModuleSymbol__internal_alias +#endif +#endif +#endif + +#ifdef bottom_threads +#undef xmlMutexLock +extern __typeof (xmlMutexLock) xmlMutexLock __attribute((alias("xmlMutexLock__internal_alias"))); +#else +#ifndef xmlMutexLock +extern __typeof (xmlMutexLock) xmlMutexLock__internal_alias __attribute((visibility("hidden"))); +#define xmlMutexLock xmlMutexLock__internal_alias +#endif +#endif + +#ifdef bottom_threads +#undef xmlMutexUnlock +extern __typeof (xmlMutexUnlock) xmlMutexUnlock __attribute((alias("xmlMutexUnlock__internal_alias"))); +#else +#ifndef xmlMutexUnlock +extern __typeof (xmlMutexUnlock) xmlMutexUnlock__internal_alias __attribute((visibility("hidden"))); +#define xmlMutexUnlock xmlMutexUnlock__internal_alias +#endif +#endif + +#if defined(LIBXML_LEGACY_ENABLED) +#ifdef bottom_legacy +#undef xmlNamespaceParseNCName +extern __typeof (xmlNamespaceParseNCName) xmlNamespaceParseNCName __attribute((alias("xmlNamespaceParseNCName__internal_alias"))); +#else +#ifndef xmlNamespaceParseNCName +extern __typeof (xmlNamespaceParseNCName) xmlNamespaceParseNCName__internal_alias __attribute((visibility("hidden"))); +#define xmlNamespaceParseNCName xmlNamespaceParseNCName__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_LEGACY_ENABLED) +#ifdef bottom_legacy +#undef xmlNamespaceParseNSDef +extern __typeof (xmlNamespaceParseNSDef) xmlNamespaceParseNSDef __attribute((alias("xmlNamespaceParseNSDef__internal_alias"))); +#else +#ifndef xmlNamespaceParseNSDef +extern __typeof (xmlNamespaceParseNSDef) xmlNamespaceParseNSDef__internal_alias __attribute((visibility("hidden"))); +#define xmlNamespaceParseNSDef xmlNamespaceParseNSDef__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_LEGACY_ENABLED) +#ifdef bottom_legacy +#undef xmlNamespaceParseQName +extern __typeof (xmlNamespaceParseQName) xmlNamespaceParseQName __attribute((alias("xmlNamespaceParseQName__internal_alias"))); +#else +#ifndef xmlNamespaceParseQName +extern __typeof (xmlNamespaceParseQName) xmlNamespaceParseQName__internal_alias __attribute((visibility("hidden"))); +#define xmlNamespaceParseQName xmlNamespaceParseQName__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) && defined(LIBXML_AUTOMATA_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlNewAutomata +extern __typeof (xmlNewAutomata) xmlNewAutomata __attribute((alias("xmlNewAutomata__internal_alias"))); +#else +#ifndef xmlNewAutomata +extern __typeof (xmlNewAutomata) xmlNewAutomata__internal_alias __attribute((visibility("hidden"))); +#define xmlNewAutomata xmlNewAutomata__internal_alias +#endif +#endif +#endif + +#ifdef bottom_tree +#undef xmlNewCDataBlock +extern __typeof (xmlNewCDataBlock) xmlNewCDataBlock __attribute((alias("xmlNewCDataBlock__internal_alias"))); +#else +#ifndef xmlNewCDataBlock +extern __typeof (xmlNewCDataBlock) xmlNewCDataBlock__internal_alias __attribute((visibility("hidden"))); +#define xmlNewCDataBlock xmlNewCDataBlock__internal_alias +#endif +#endif + +#if defined(LIBXML_CATALOG_ENABLED) +#ifdef bottom_catalog +#undef xmlNewCatalog +extern __typeof (xmlNewCatalog) xmlNewCatalog __attribute((alias("xmlNewCatalog__internal_alias"))); +#else +#ifndef xmlNewCatalog +extern __typeof (xmlNewCatalog) xmlNewCatalog__internal_alias __attribute((visibility("hidden"))); +#define xmlNewCatalog xmlNewCatalog__internal_alias +#endif +#endif +#endif + +#ifdef bottom_encoding +#undef xmlNewCharEncodingHandler +extern __typeof (xmlNewCharEncodingHandler) xmlNewCharEncodingHandler __attribute((alias("xmlNewCharEncodingHandler__internal_alias"))); +#else +#ifndef xmlNewCharEncodingHandler +extern __typeof (xmlNewCharEncodingHandler) xmlNewCharEncodingHandler__internal_alias __attribute((visibility("hidden"))); +#define xmlNewCharEncodingHandler xmlNewCharEncodingHandler__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlNewCharRef +extern __typeof (xmlNewCharRef) xmlNewCharRef __attribute((alias("xmlNewCharRef__internal_alias"))); +#else +#ifndef xmlNewCharRef +extern __typeof (xmlNewCharRef) xmlNewCharRef__internal_alias __attribute((visibility("hidden"))); +#define xmlNewCharRef xmlNewCharRef__internal_alias +#endif +#endif + +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_tree +#undef xmlNewChild +extern __typeof (xmlNewChild) xmlNewChild __attribute((alias("xmlNewChild__internal_alias"))); +#else +#ifndef xmlNewChild +extern __typeof (xmlNewChild) xmlNewChild__internal_alias __attribute((visibility("hidden"))); +#define xmlNewChild xmlNewChild__internal_alias +#endif +#endif +#endif + +#ifdef bottom_tree +#undef xmlNewComment +extern __typeof (xmlNewComment) xmlNewComment __attribute((alias("xmlNewComment__internal_alias"))); +#else +#ifndef xmlNewComment +extern __typeof (xmlNewComment) xmlNewComment__internal_alias __attribute((visibility("hidden"))); +#define xmlNewComment xmlNewComment__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlNewDoc +extern __typeof (xmlNewDoc) xmlNewDoc __attribute((alias("xmlNewDoc__internal_alias"))); +#else +#ifndef xmlNewDoc +extern __typeof (xmlNewDoc) xmlNewDoc__internal_alias __attribute((visibility("hidden"))); +#define xmlNewDoc xmlNewDoc__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlNewDocComment +extern __typeof (xmlNewDocComment) xmlNewDocComment __attribute((alias("xmlNewDocComment__internal_alias"))); +#else +#ifndef xmlNewDocComment +extern __typeof (xmlNewDocComment) xmlNewDocComment__internal_alias __attribute((visibility("hidden"))); +#define xmlNewDocComment xmlNewDocComment__internal_alias +#endif +#endif + +#ifdef bottom_valid +#undef xmlNewDocElementContent +extern __typeof (xmlNewDocElementContent) xmlNewDocElementContent __attribute((alias("xmlNewDocElementContent__internal_alias"))); +#else +#ifndef xmlNewDocElementContent +extern __typeof (xmlNewDocElementContent) xmlNewDocElementContent__internal_alias __attribute((visibility("hidden"))); +#define xmlNewDocElementContent xmlNewDocElementContent__internal_alias +#endif +#endif + +#if defined(LIBXML_TREE_ENABLED) +#ifdef bottom_tree +#undef xmlNewDocFragment +extern __typeof (xmlNewDocFragment) xmlNewDocFragment __attribute((alias("xmlNewDocFragment__internal_alias"))); +#else +#ifndef xmlNewDocFragment +extern __typeof (xmlNewDocFragment) xmlNewDocFragment__internal_alias __attribute((visibility("hidden"))); +#define xmlNewDocFragment xmlNewDocFragment__internal_alias +#endif +#endif +#endif + +#ifdef bottom_tree +#undef xmlNewDocNode +extern __typeof (xmlNewDocNode) xmlNewDocNode __attribute((alias("xmlNewDocNode__internal_alias"))); +#else +#ifndef xmlNewDocNode +extern __typeof (xmlNewDocNode) xmlNewDocNode__internal_alias __attribute((visibility("hidden"))); +#define xmlNewDocNode xmlNewDocNode__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlNewDocNodeEatName +extern __typeof (xmlNewDocNodeEatName) xmlNewDocNodeEatName __attribute((alias("xmlNewDocNodeEatName__internal_alias"))); +#else +#ifndef xmlNewDocNodeEatName +extern __typeof (xmlNewDocNodeEatName) xmlNewDocNodeEatName__internal_alias __attribute((visibility("hidden"))); +#define xmlNewDocNodeEatName xmlNewDocNodeEatName__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlNewDocPI +extern __typeof (xmlNewDocPI) xmlNewDocPI __attribute((alias("xmlNewDocPI__internal_alias"))); +#else +#ifndef xmlNewDocPI +extern __typeof (xmlNewDocPI) xmlNewDocPI__internal_alias __attribute((visibility("hidden"))); +#define xmlNewDocPI xmlNewDocPI__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlNewDocProp +extern __typeof (xmlNewDocProp) xmlNewDocProp __attribute((alias("xmlNewDocProp__internal_alias"))); +#else +#ifndef xmlNewDocProp +extern __typeof (xmlNewDocProp) xmlNewDocProp__internal_alias __attribute((visibility("hidden"))); +#define xmlNewDocProp xmlNewDocProp__internal_alias +#endif +#endif + +#if defined(LIBXML_TREE_ENABLED) +#ifdef bottom_tree +#undef xmlNewDocRawNode +extern __typeof (xmlNewDocRawNode) xmlNewDocRawNode __attribute((alias("xmlNewDocRawNode__internal_alias"))); +#else +#ifndef xmlNewDocRawNode +extern __typeof (xmlNewDocRawNode) xmlNewDocRawNode__internal_alias __attribute((visibility("hidden"))); +#define xmlNewDocRawNode xmlNewDocRawNode__internal_alias +#endif +#endif +#endif + +#ifdef bottom_tree +#undef xmlNewDocText +extern __typeof (xmlNewDocText) xmlNewDocText __attribute((alias("xmlNewDocText__internal_alias"))); +#else +#ifndef xmlNewDocText +extern __typeof (xmlNewDocText) xmlNewDocText__internal_alias __attribute((visibility("hidden"))); +#define xmlNewDocText xmlNewDocText__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlNewDocTextLen +extern __typeof (xmlNewDocTextLen) xmlNewDocTextLen __attribute((alias("xmlNewDocTextLen__internal_alias"))); +#else +#ifndef xmlNewDocTextLen +extern __typeof (xmlNewDocTextLen) xmlNewDocTextLen__internal_alias __attribute((visibility("hidden"))); +#define xmlNewDocTextLen xmlNewDocTextLen__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlNewDtd +extern __typeof (xmlNewDtd) xmlNewDtd __attribute((alias("xmlNewDtd__internal_alias"))); +#else +#ifndef xmlNewDtd +extern __typeof (xmlNewDtd) xmlNewDtd__internal_alias __attribute((visibility("hidden"))); +#define xmlNewDtd xmlNewDtd__internal_alias +#endif +#endif + +#ifdef bottom_valid +#undef xmlNewElementContent +extern __typeof (xmlNewElementContent) xmlNewElementContent __attribute((alias("xmlNewElementContent__internal_alias"))); +#else +#ifndef xmlNewElementContent +extern __typeof (xmlNewElementContent) xmlNewElementContent__internal_alias __attribute((visibility("hidden"))); +#define xmlNewElementContent xmlNewElementContent__internal_alias +#endif +#endif + +#ifdef bottom_entities +#undef xmlNewEntity +extern __typeof (xmlNewEntity) xmlNewEntity __attribute((alias("xmlNewEntity__internal_alias"))); +#else +#ifndef xmlNewEntity +extern __typeof (xmlNewEntity) xmlNewEntity__internal_alias __attribute((visibility("hidden"))); +#define xmlNewEntity xmlNewEntity__internal_alias +#endif +#endif + +#ifdef bottom_parserInternals +#undef xmlNewEntityInputStream +extern __typeof (xmlNewEntityInputStream) xmlNewEntityInputStream __attribute((alias("xmlNewEntityInputStream__internal_alias"))); +#else +#ifndef xmlNewEntityInputStream +extern __typeof (xmlNewEntityInputStream) xmlNewEntityInputStream__internal_alias __attribute((visibility("hidden"))); +#define xmlNewEntityInputStream xmlNewEntityInputStream__internal_alias +#endif +#endif + +#if defined(LIBXML_LEGACY_ENABLED) +#ifdef bottom_legacy +#undef xmlNewGlobalNs +extern __typeof (xmlNewGlobalNs) xmlNewGlobalNs __attribute((alias("xmlNewGlobalNs__internal_alias"))); +#else +#ifndef xmlNewGlobalNs +extern __typeof (xmlNewGlobalNs) xmlNewGlobalNs__internal_alias __attribute((visibility("hidden"))); +#define xmlNewGlobalNs xmlNewGlobalNs__internal_alias +#endif +#endif +#endif + +#ifdef bottom_parserInternals +#undef xmlNewIOInputStream +extern __typeof (xmlNewIOInputStream) xmlNewIOInputStream __attribute((alias("xmlNewIOInputStream__internal_alias"))); +#else +#ifndef xmlNewIOInputStream +extern __typeof (xmlNewIOInputStream) xmlNewIOInputStream__internal_alias __attribute((visibility("hidden"))); +#define xmlNewIOInputStream xmlNewIOInputStream__internal_alias +#endif +#endif + +#ifdef bottom_parserInternals +#undef xmlNewInputFromFile +extern __typeof (xmlNewInputFromFile) xmlNewInputFromFile __attribute((alias("xmlNewInputFromFile__internal_alias"))); +#else +#ifndef xmlNewInputFromFile +extern __typeof (xmlNewInputFromFile) xmlNewInputFromFile__internal_alias __attribute((visibility("hidden"))); +#define xmlNewInputFromFile xmlNewInputFromFile__internal_alias +#endif +#endif + +#ifdef bottom_parserInternals +#undef xmlNewInputStream +extern __typeof (xmlNewInputStream) xmlNewInputStream __attribute((alias("xmlNewInputStream__internal_alias"))); +#else +#ifndef xmlNewInputStream +extern __typeof (xmlNewInputStream) xmlNewInputStream__internal_alias __attribute((visibility("hidden"))); +#define xmlNewInputStream xmlNewInputStream__internal_alias +#endif +#endif + +#ifdef bottom_threads +#undef xmlNewMutex +extern __typeof (xmlNewMutex) xmlNewMutex __attribute((alias("xmlNewMutex__internal_alias"))); +#else +#ifndef xmlNewMutex +extern __typeof (xmlNewMutex) xmlNewMutex__internal_alias __attribute((visibility("hidden"))); +#define xmlNewMutex xmlNewMutex__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlNewNode +extern __typeof (xmlNewNode) xmlNewNode __attribute((alias("xmlNewNode__internal_alias"))); +#else +#ifndef xmlNewNode +extern __typeof (xmlNewNode) xmlNewNode__internal_alias __attribute((visibility("hidden"))); +#define xmlNewNode xmlNewNode__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlNewNodeEatName +extern __typeof (xmlNewNodeEatName) xmlNewNodeEatName __attribute((alias("xmlNewNodeEatName__internal_alias"))); +#else +#ifndef xmlNewNodeEatName +extern __typeof (xmlNewNodeEatName) xmlNewNodeEatName__internal_alias __attribute((visibility("hidden"))); +#define xmlNewNodeEatName xmlNewNodeEatName__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlNewNs +extern __typeof (xmlNewNs) xmlNewNs __attribute((alias("xmlNewNs__internal_alias"))); +#else +#ifndef xmlNewNs +extern __typeof (xmlNewNs) xmlNewNs__internal_alias __attribute((visibility("hidden"))); +#define xmlNewNs xmlNewNs__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlNewNsProp +extern __typeof (xmlNewNsProp) xmlNewNsProp __attribute((alias("xmlNewNsProp__internal_alias"))); +#else +#ifndef xmlNewNsProp +extern __typeof (xmlNewNsProp) xmlNewNsProp__internal_alias __attribute((visibility("hidden"))); +#define xmlNewNsProp xmlNewNsProp__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlNewNsPropEatName +extern __typeof (xmlNewNsPropEatName) xmlNewNsPropEatName __attribute((alias("xmlNewNsPropEatName__internal_alias"))); +#else +#ifndef xmlNewNsPropEatName +extern __typeof (xmlNewNsPropEatName) xmlNewNsPropEatName__internal_alias __attribute((visibility("hidden"))); +#define xmlNewNsPropEatName xmlNewNsPropEatName__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlNewPI +extern __typeof (xmlNewPI) xmlNewPI __attribute((alias("xmlNewPI__internal_alias"))); +#else +#ifndef xmlNewPI +extern __typeof (xmlNewPI) xmlNewPI__internal_alias __attribute((visibility("hidden"))); +#define xmlNewPI xmlNewPI__internal_alias +#endif +#endif + +#ifdef bottom_parserInternals +#undef xmlNewParserCtxt +extern __typeof (xmlNewParserCtxt) xmlNewParserCtxt __attribute((alias("xmlNewParserCtxt__internal_alias"))); +#else +#ifndef xmlNewParserCtxt +extern __typeof (xmlNewParserCtxt) xmlNewParserCtxt__internal_alias __attribute((visibility("hidden"))); +#define xmlNewParserCtxt xmlNewParserCtxt__internal_alias +#endif +#endif + +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_tree +#undef xmlNewProp +extern __typeof (xmlNewProp) xmlNewProp __attribute((alias("xmlNewProp__internal_alias"))); +#else +#ifndef xmlNewProp +extern __typeof (xmlNewProp) xmlNewProp__internal_alias __attribute((visibility("hidden"))); +#define xmlNewProp xmlNewProp__internal_alias +#endif +#endif +#endif + +#ifdef bottom_threads +#undef xmlNewRMutex +extern __typeof (xmlNewRMutex) xmlNewRMutex __attribute((alias("xmlNewRMutex__internal_alias"))); +#else +#ifndef xmlNewRMutex +extern __typeof (xmlNewRMutex) xmlNewRMutex__internal_alias __attribute((visibility("hidden"))); +#define xmlNewRMutex xmlNewRMutex__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlNewReference +extern __typeof (xmlNewReference) xmlNewReference __attribute((alias("xmlNewReference__internal_alias"))); +#else +#ifndef xmlNewReference +extern __typeof (xmlNewReference) xmlNewReference__internal_alias __attribute((visibility("hidden"))); +#define xmlNewReference xmlNewReference__internal_alias +#endif +#endif + +#ifdef bottom_parserInternals +#undef xmlNewStringInputStream +extern __typeof (xmlNewStringInputStream) xmlNewStringInputStream __attribute((alias("xmlNewStringInputStream__internal_alias"))); +#else +#ifndef xmlNewStringInputStream +extern __typeof (xmlNewStringInputStream) xmlNewStringInputStream__internal_alias __attribute((visibility("hidden"))); +#define xmlNewStringInputStream xmlNewStringInputStream__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlNewText +extern __typeof (xmlNewText) xmlNewText __attribute((alias("xmlNewText__internal_alias"))); +#else +#ifndef xmlNewText +extern __typeof (xmlNewText) xmlNewText__internal_alias __attribute((visibility("hidden"))); +#define xmlNewText xmlNewText__internal_alias +#endif +#endif + +#if defined(LIBXML_TREE_ENABLED) +#ifdef bottom_tree +#undef xmlNewTextChild +extern __typeof (xmlNewTextChild) xmlNewTextChild __attribute((alias("xmlNewTextChild__internal_alias"))); +#else +#ifndef xmlNewTextChild +extern __typeof (xmlNewTextChild) xmlNewTextChild__internal_alias __attribute((visibility("hidden"))); +#define xmlNewTextChild xmlNewTextChild__internal_alias +#endif +#endif +#endif + +#ifdef bottom_tree +#undef xmlNewTextLen +extern __typeof (xmlNewTextLen) xmlNewTextLen __attribute((alias("xmlNewTextLen__internal_alias"))); +#else +#ifndef xmlNewTextLen +extern __typeof (xmlNewTextLen) xmlNewTextLen__internal_alias __attribute((visibility("hidden"))); +#define xmlNewTextLen xmlNewTextLen__internal_alias +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlNewTextReader +extern __typeof (xmlNewTextReader) xmlNewTextReader __attribute((alias("xmlNewTextReader__internal_alias"))); +#else +#ifndef xmlNewTextReader +extern __typeof (xmlNewTextReader) xmlNewTextReader__internal_alias __attribute((visibility("hidden"))); +#define xmlNewTextReader xmlNewTextReader__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlNewTextReaderFilename +extern __typeof (xmlNewTextReaderFilename) xmlNewTextReaderFilename __attribute((alias("xmlNewTextReaderFilename__internal_alias"))); +#else +#ifndef xmlNewTextReaderFilename +extern __typeof (xmlNewTextReaderFilename) xmlNewTextReaderFilename__internal_alias __attribute((visibility("hidden"))); +#define xmlNewTextReaderFilename xmlNewTextReaderFilename__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlNewTextWriter +extern __typeof (xmlNewTextWriter) xmlNewTextWriter __attribute((alias("xmlNewTextWriter__internal_alias"))); +#else +#ifndef xmlNewTextWriter +extern __typeof (xmlNewTextWriter) xmlNewTextWriter__internal_alias __attribute((visibility("hidden"))); +#define xmlNewTextWriter xmlNewTextWriter__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlNewTextWriterDoc +extern __typeof (xmlNewTextWriterDoc) xmlNewTextWriterDoc __attribute((alias("xmlNewTextWriterDoc__internal_alias"))); +#else +#ifndef xmlNewTextWriterDoc +extern __typeof (xmlNewTextWriterDoc) xmlNewTextWriterDoc__internal_alias __attribute((visibility("hidden"))); +#define xmlNewTextWriterDoc xmlNewTextWriterDoc__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlNewTextWriterFilename +extern __typeof (xmlNewTextWriterFilename) xmlNewTextWriterFilename __attribute((alias("xmlNewTextWriterFilename__internal_alias"))); +#else +#ifndef xmlNewTextWriterFilename +extern __typeof (xmlNewTextWriterFilename) xmlNewTextWriterFilename__internal_alias __attribute((visibility("hidden"))); +#define xmlNewTextWriterFilename xmlNewTextWriterFilename__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlNewTextWriterMemory +extern __typeof (xmlNewTextWriterMemory) xmlNewTextWriterMemory __attribute((alias("xmlNewTextWriterMemory__internal_alias"))); +#else +#ifndef xmlNewTextWriterMemory +extern __typeof (xmlNewTextWriterMemory) xmlNewTextWriterMemory__internal_alias __attribute((visibility("hidden"))); +#define xmlNewTextWriterMemory xmlNewTextWriterMemory__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlNewTextWriterPushParser +extern __typeof (xmlNewTextWriterPushParser) xmlNewTextWriterPushParser __attribute((alias("xmlNewTextWriterPushParser__internal_alias"))); +#else +#ifndef xmlNewTextWriterPushParser +extern __typeof (xmlNewTextWriterPushParser) xmlNewTextWriterPushParser__internal_alias __attribute((visibility("hidden"))); +#define xmlNewTextWriterPushParser xmlNewTextWriterPushParser__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlNewTextWriterTree +extern __typeof (xmlNewTextWriterTree) xmlNewTextWriterTree __attribute((alias("xmlNewTextWriterTree__internal_alias"))); +#else +#ifndef xmlNewTextWriterTree +extern __typeof (xmlNewTextWriterTree) xmlNewTextWriterTree__internal_alias __attribute((visibility("hidden"))); +#define xmlNewTextWriterTree xmlNewTextWriterTree__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_VALID_ENABLED) +#ifdef bottom_valid +#undef xmlNewValidCtxt +extern __typeof (xmlNewValidCtxt) xmlNewValidCtxt __attribute((alias("xmlNewValidCtxt__internal_alias"))); +#else +#ifndef xmlNewValidCtxt +extern __typeof (xmlNewValidCtxt) xmlNewValidCtxt__internal_alias __attribute((visibility("hidden"))); +#define xmlNewValidCtxt xmlNewValidCtxt__internal_alias +#endif +#endif +#endif + +#ifdef bottom_parserInternals +#undef xmlNextChar +extern __typeof (xmlNextChar) xmlNextChar __attribute((alias("xmlNextChar__internal_alias"))); +#else +#ifndef xmlNextChar +extern __typeof (xmlNextChar) xmlNextChar__internal_alias __attribute((visibility("hidden"))); +#define xmlNextChar xmlNextChar__internal_alias +#endif +#endif + +#if defined(LIBXML_TREE_ENABLED) +#ifdef bottom_tree +#undef xmlNextElementSibling +extern __typeof (xmlNextElementSibling) xmlNextElementSibling __attribute((alias("xmlNextElementSibling__internal_alias"))); +#else +#ifndef xmlNextElementSibling +extern __typeof (xmlNextElementSibling) xmlNextElementSibling__internal_alias __attribute((visibility("hidden"))); +#define xmlNextElementSibling xmlNextElementSibling__internal_alias +#endif +#endif +#endif + +#ifdef bottom_xmlIO +#undef xmlNoNetExternalEntityLoader +extern __typeof (xmlNoNetExternalEntityLoader) xmlNoNetExternalEntityLoader __attribute((alias("xmlNoNetExternalEntityLoader__internal_alias"))); +#else +#ifndef xmlNoNetExternalEntityLoader +extern __typeof (xmlNoNetExternalEntityLoader) xmlNoNetExternalEntityLoader__internal_alias __attribute((visibility("hidden"))); +#define xmlNoNetExternalEntityLoader xmlNoNetExternalEntityLoader__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlNodeAddContent +extern __typeof (xmlNodeAddContent) xmlNodeAddContent __attribute((alias("xmlNodeAddContent__internal_alias"))); +#else +#ifndef xmlNodeAddContent +extern __typeof (xmlNodeAddContent) xmlNodeAddContent__internal_alias __attribute((visibility("hidden"))); +#define xmlNodeAddContent xmlNodeAddContent__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlNodeAddContentLen +extern __typeof (xmlNodeAddContentLen) xmlNodeAddContentLen __attribute((alias("xmlNodeAddContentLen__internal_alias"))); +#else +#ifndef xmlNodeAddContentLen +extern __typeof (xmlNodeAddContentLen) xmlNodeAddContentLen__internal_alias __attribute((visibility("hidden"))); +#define xmlNodeAddContentLen xmlNodeAddContentLen__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlNodeBufGetContent +extern __typeof (xmlNodeBufGetContent) xmlNodeBufGetContent __attribute((alias("xmlNodeBufGetContent__internal_alias"))); +#else +#ifndef xmlNodeBufGetContent +extern __typeof (xmlNodeBufGetContent) xmlNodeBufGetContent__internal_alias __attribute((visibility("hidden"))); +#define xmlNodeBufGetContent xmlNodeBufGetContent__internal_alias +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_xmlsave +#undef xmlNodeDump +extern __typeof (xmlNodeDump) xmlNodeDump __attribute((alias("xmlNodeDump__internal_alias"))); +#else +#ifndef xmlNodeDump +extern __typeof (xmlNodeDump) xmlNodeDump__internal_alias __attribute((visibility("hidden"))); +#define xmlNodeDump xmlNodeDump__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_xmlsave +#undef xmlNodeDumpOutput +extern __typeof (xmlNodeDumpOutput) xmlNodeDumpOutput __attribute((alias("xmlNodeDumpOutput__internal_alias"))); +#else +#ifndef xmlNodeDumpOutput +extern __typeof (xmlNodeDumpOutput) xmlNodeDumpOutput__internal_alias __attribute((visibility("hidden"))); +#define xmlNodeDumpOutput xmlNodeDumpOutput__internal_alias +#endif +#endif +#endif + +#ifdef bottom_tree +#undef xmlNodeGetBase +extern __typeof (xmlNodeGetBase) xmlNodeGetBase __attribute((alias("xmlNodeGetBase__internal_alias"))); +#else +#ifndef xmlNodeGetBase +extern __typeof (xmlNodeGetBase) xmlNodeGetBase__internal_alias __attribute((visibility("hidden"))); +#define xmlNodeGetBase xmlNodeGetBase__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlNodeGetContent +extern __typeof (xmlNodeGetContent) xmlNodeGetContent __attribute((alias("xmlNodeGetContent__internal_alias"))); +#else +#ifndef xmlNodeGetContent +extern __typeof (xmlNodeGetContent) xmlNodeGetContent__internal_alias __attribute((visibility("hidden"))); +#define xmlNodeGetContent xmlNodeGetContent__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlNodeGetLang +extern __typeof (xmlNodeGetLang) xmlNodeGetLang __attribute((alias("xmlNodeGetLang__internal_alias"))); +#else +#ifndef xmlNodeGetLang +extern __typeof (xmlNodeGetLang) xmlNodeGetLang__internal_alias __attribute((visibility("hidden"))); +#define xmlNodeGetLang xmlNodeGetLang__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlNodeGetSpacePreserve +extern __typeof (xmlNodeGetSpacePreserve) xmlNodeGetSpacePreserve __attribute((alias("xmlNodeGetSpacePreserve__internal_alias"))); +#else +#ifndef xmlNodeGetSpacePreserve +extern __typeof (xmlNodeGetSpacePreserve) xmlNodeGetSpacePreserve__internal_alias __attribute((visibility("hidden"))); +#define xmlNodeGetSpacePreserve xmlNodeGetSpacePreserve__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlNodeIsText +extern __typeof (xmlNodeIsText) xmlNodeIsText __attribute((alias("xmlNodeIsText__internal_alias"))); +#else +#ifndef xmlNodeIsText +extern __typeof (xmlNodeIsText) xmlNodeIsText__internal_alias __attribute((visibility("hidden"))); +#define xmlNodeIsText xmlNodeIsText__internal_alias +#endif +#endif + +#if defined(LIBXML_TREE_ENABLED) +#ifdef bottom_tree +#undef xmlNodeListGetRawString +extern __typeof (xmlNodeListGetRawString) xmlNodeListGetRawString __attribute((alias("xmlNodeListGetRawString__internal_alias"))); +#else +#ifndef xmlNodeListGetRawString +extern __typeof (xmlNodeListGetRawString) xmlNodeListGetRawString__internal_alias __attribute((visibility("hidden"))); +#define xmlNodeListGetRawString xmlNodeListGetRawString__internal_alias +#endif +#endif +#endif + +#ifdef bottom_tree +#undef xmlNodeListGetString +extern __typeof (xmlNodeListGetString) xmlNodeListGetString __attribute((alias("xmlNodeListGetString__internal_alias"))); +#else +#ifndef xmlNodeListGetString +extern __typeof (xmlNodeListGetString) xmlNodeListGetString__internal_alias __attribute((visibility("hidden"))); +#define xmlNodeListGetString xmlNodeListGetString__internal_alias +#endif +#endif + +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) +#ifdef bottom_tree +#undef xmlNodeSetBase +extern __typeof (xmlNodeSetBase) xmlNodeSetBase __attribute((alias("xmlNodeSetBase__internal_alias"))); +#else +#ifndef xmlNodeSetBase +extern __typeof (xmlNodeSetBase) xmlNodeSetBase__internal_alias __attribute((visibility("hidden"))); +#define xmlNodeSetBase xmlNodeSetBase__internal_alias +#endif +#endif +#endif + +#ifdef bottom_tree +#undef xmlNodeSetContent +extern __typeof (xmlNodeSetContent) xmlNodeSetContent __attribute((alias("xmlNodeSetContent__internal_alias"))); +#else +#ifndef xmlNodeSetContent +extern __typeof (xmlNodeSetContent) xmlNodeSetContent__internal_alias __attribute((visibility("hidden"))); +#define xmlNodeSetContent xmlNodeSetContent__internal_alias +#endif +#endif + +#if defined(LIBXML_TREE_ENABLED) +#ifdef bottom_tree +#undef xmlNodeSetContentLen +extern __typeof (xmlNodeSetContentLen) xmlNodeSetContentLen __attribute((alias("xmlNodeSetContentLen__internal_alias"))); +#else +#ifndef xmlNodeSetContentLen +extern __typeof (xmlNodeSetContentLen) xmlNodeSetContentLen__internal_alias __attribute((visibility("hidden"))); +#define xmlNodeSetContentLen xmlNodeSetContentLen__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_TREE_ENABLED) +#ifdef bottom_tree +#undef xmlNodeSetLang +extern __typeof (xmlNodeSetLang) xmlNodeSetLang __attribute((alias("xmlNodeSetLang__internal_alias"))); +#else +#ifndef xmlNodeSetLang +extern __typeof (xmlNodeSetLang) xmlNodeSetLang__internal_alias __attribute((visibility("hidden"))); +#define xmlNodeSetLang xmlNodeSetLang__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_TREE_ENABLED) +#ifdef bottom_tree +#undef xmlNodeSetName +extern __typeof (xmlNodeSetName) xmlNodeSetName __attribute((alias("xmlNodeSetName__internal_alias"))); +#else +#ifndef xmlNodeSetName +extern __typeof (xmlNodeSetName) xmlNodeSetName__internal_alias __attribute((visibility("hidden"))); +#define xmlNodeSetName xmlNodeSetName__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_TREE_ENABLED) +#ifdef bottom_tree +#undef xmlNodeSetSpacePreserve +extern __typeof (xmlNodeSetSpacePreserve) xmlNodeSetSpacePreserve __attribute((alias("xmlNodeSetSpacePreserve__internal_alias"))); +#else +#ifndef xmlNodeSetSpacePreserve +extern __typeof (xmlNodeSetSpacePreserve) xmlNodeSetSpacePreserve__internal_alias __attribute((visibility("hidden"))); +#define xmlNodeSetSpacePreserve xmlNodeSetSpacePreserve__internal_alias +#endif +#endif +#endif + +#ifdef bottom_uri +#undef xmlNormalizeURIPath +extern __typeof (xmlNormalizeURIPath) xmlNormalizeURIPath __attribute((alias("xmlNormalizeURIPath__internal_alias"))); +#else +#ifndef xmlNormalizeURIPath +extern __typeof (xmlNormalizeURIPath) xmlNormalizeURIPath__internal_alias __attribute((visibility("hidden"))); +#define xmlNormalizeURIPath xmlNormalizeURIPath__internal_alias +#endif +#endif + +#ifdef bottom_xmlIO +#undef xmlNormalizeWindowsPath +extern __typeof (xmlNormalizeWindowsPath) xmlNormalizeWindowsPath __attribute((alias("xmlNormalizeWindowsPath__internal_alias"))); +#else +#ifndef xmlNormalizeWindowsPath +extern __typeof (xmlNormalizeWindowsPath) xmlNormalizeWindowsPath__internal_alias __attribute((visibility("hidden"))); +#define xmlNormalizeWindowsPath xmlNormalizeWindowsPath__internal_alias +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_xmlIO +#undef xmlOutputBufferClose +extern __typeof (xmlOutputBufferClose) xmlOutputBufferClose __attribute((alias("xmlOutputBufferClose__internal_alias"))); +#else +#ifndef xmlOutputBufferClose +extern __typeof (xmlOutputBufferClose) xmlOutputBufferClose__internal_alias __attribute((visibility("hidden"))); +#define xmlOutputBufferClose xmlOutputBufferClose__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_xmlIO +#undef xmlOutputBufferCreateBuffer +extern __typeof (xmlOutputBufferCreateBuffer) xmlOutputBufferCreateBuffer __attribute((alias("xmlOutputBufferCreateBuffer__internal_alias"))); +#else +#ifndef xmlOutputBufferCreateBuffer +extern __typeof (xmlOutputBufferCreateBuffer) xmlOutputBufferCreateBuffer__internal_alias __attribute((visibility("hidden"))); +#define xmlOutputBufferCreateBuffer xmlOutputBufferCreateBuffer__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_xmlIO +#undef xmlOutputBufferCreateFd +extern __typeof (xmlOutputBufferCreateFd) xmlOutputBufferCreateFd __attribute((alias("xmlOutputBufferCreateFd__internal_alias"))); +#else +#ifndef xmlOutputBufferCreateFd +extern __typeof (xmlOutputBufferCreateFd) xmlOutputBufferCreateFd__internal_alias __attribute((visibility("hidden"))); +#define xmlOutputBufferCreateFd xmlOutputBufferCreateFd__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_xmlIO +#undef xmlOutputBufferCreateFile +extern __typeof (xmlOutputBufferCreateFile) xmlOutputBufferCreateFile __attribute((alias("xmlOutputBufferCreateFile__internal_alias"))); +#else +#ifndef xmlOutputBufferCreateFile +extern __typeof (xmlOutputBufferCreateFile) xmlOutputBufferCreateFile__internal_alias __attribute((visibility("hidden"))); +#define xmlOutputBufferCreateFile xmlOutputBufferCreateFile__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_xmlIO +#undef xmlOutputBufferCreateFilename +extern __typeof (xmlOutputBufferCreateFilename) xmlOutputBufferCreateFilename __attribute((alias("xmlOutputBufferCreateFilename__internal_alias"))); +#else +#ifndef xmlOutputBufferCreateFilename +extern __typeof (xmlOutputBufferCreateFilename) xmlOutputBufferCreateFilename__internal_alias __attribute((visibility("hidden"))); +#define xmlOutputBufferCreateFilename xmlOutputBufferCreateFilename__internal_alias +#endif +#endif +#endif + +#ifdef bottom_xmlIO +#undef xmlOutputBufferCreateFilenameDefault +extern __typeof (xmlOutputBufferCreateFilenameDefault) xmlOutputBufferCreateFilenameDefault __attribute((alias("xmlOutputBufferCreateFilenameDefault__internal_alias"))); +#else +#ifndef xmlOutputBufferCreateFilenameDefault +extern __typeof (xmlOutputBufferCreateFilenameDefault) xmlOutputBufferCreateFilenameDefault__internal_alias __attribute((visibility("hidden"))); +#define xmlOutputBufferCreateFilenameDefault xmlOutputBufferCreateFilenameDefault__internal_alias +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_xmlIO +#undef xmlOutputBufferCreateIO +extern __typeof (xmlOutputBufferCreateIO) xmlOutputBufferCreateIO __attribute((alias("xmlOutputBufferCreateIO__internal_alias"))); +#else +#ifndef xmlOutputBufferCreateIO +extern __typeof (xmlOutputBufferCreateIO) xmlOutputBufferCreateIO__internal_alias __attribute((visibility("hidden"))); +#define xmlOutputBufferCreateIO xmlOutputBufferCreateIO__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_xmlIO +#undef xmlOutputBufferFlush +extern __typeof (xmlOutputBufferFlush) xmlOutputBufferFlush __attribute((alias("xmlOutputBufferFlush__internal_alias"))); +#else +#ifndef xmlOutputBufferFlush +extern __typeof (xmlOutputBufferFlush) xmlOutputBufferFlush__internal_alias __attribute((visibility("hidden"))); +#define xmlOutputBufferFlush xmlOutputBufferFlush__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_xmlIO +#undef xmlOutputBufferWrite +extern __typeof (xmlOutputBufferWrite) xmlOutputBufferWrite __attribute((alias("xmlOutputBufferWrite__internal_alias"))); +#else +#ifndef xmlOutputBufferWrite +extern __typeof (xmlOutputBufferWrite) xmlOutputBufferWrite__internal_alias __attribute((visibility("hidden"))); +#define xmlOutputBufferWrite xmlOutputBufferWrite__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_xmlIO +#undef xmlOutputBufferWriteEscape +extern __typeof (xmlOutputBufferWriteEscape) xmlOutputBufferWriteEscape __attribute((alias("xmlOutputBufferWriteEscape__internal_alias"))); +#else +#ifndef xmlOutputBufferWriteEscape +extern __typeof (xmlOutputBufferWriteEscape) xmlOutputBufferWriteEscape__internal_alias __attribute((visibility("hidden"))); +#define xmlOutputBufferWriteEscape xmlOutputBufferWriteEscape__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_xmlIO +#undef xmlOutputBufferWriteString +extern __typeof (xmlOutputBufferWriteString) xmlOutputBufferWriteString __attribute((alias("xmlOutputBufferWriteString__internal_alias"))); +#else +#ifndef xmlOutputBufferWriteString +extern __typeof (xmlOutputBufferWriteString) xmlOutputBufferWriteString__internal_alias __attribute((visibility("hidden"))); +#define xmlOutputBufferWriteString xmlOutputBufferWriteString__internal_alias +#endif +#endif +#endif + +#ifdef bottom_parser +#undef xmlParseAttValue +extern __typeof (xmlParseAttValue) xmlParseAttValue __attribute((alias("xmlParseAttValue__internal_alias"))); +#else +#ifndef xmlParseAttValue +extern __typeof (xmlParseAttValue) xmlParseAttValue__internal_alias __attribute((visibility("hidden"))); +#define xmlParseAttValue xmlParseAttValue__internal_alias +#endif +#endif + +#if defined(LIBXML_SAX1_ENABLED) +#ifdef bottom_parser +#undef xmlParseAttribute +extern __typeof (xmlParseAttribute) xmlParseAttribute __attribute((alias("xmlParseAttribute__internal_alias"))); +#else +#ifndef xmlParseAttribute +extern __typeof (xmlParseAttribute) xmlParseAttribute__internal_alias __attribute((visibility("hidden"))); +#define xmlParseAttribute xmlParseAttribute__internal_alias +#endif +#endif +#endif + +#ifdef bottom_parser +#undef xmlParseAttributeListDecl +extern __typeof (xmlParseAttributeListDecl) xmlParseAttributeListDecl __attribute((alias("xmlParseAttributeListDecl__internal_alias"))); +#else +#ifndef xmlParseAttributeListDecl +extern __typeof (xmlParseAttributeListDecl) xmlParseAttributeListDecl__internal_alias __attribute((visibility("hidden"))); +#define xmlParseAttributeListDecl xmlParseAttributeListDecl__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlParseAttributeType +extern __typeof (xmlParseAttributeType) xmlParseAttributeType __attribute((alias("xmlParseAttributeType__internal_alias"))); +#else +#ifndef xmlParseAttributeType +extern __typeof (xmlParseAttributeType) xmlParseAttributeType__internal_alias __attribute((visibility("hidden"))); +#define xmlParseAttributeType xmlParseAttributeType__internal_alias +#endif +#endif + +#if defined(LIBXML_SAX1_ENABLED) +#ifdef bottom_parser +#undef xmlParseBalancedChunkMemory +extern __typeof (xmlParseBalancedChunkMemory) xmlParseBalancedChunkMemory __attribute((alias("xmlParseBalancedChunkMemory__internal_alias"))); +#else +#ifndef xmlParseBalancedChunkMemory +extern __typeof (xmlParseBalancedChunkMemory) xmlParseBalancedChunkMemory__internal_alias __attribute((visibility("hidden"))); +#define xmlParseBalancedChunkMemory xmlParseBalancedChunkMemory__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SAX1_ENABLED) +#ifdef bottom_parser +#undef xmlParseBalancedChunkMemoryRecover +extern __typeof (xmlParseBalancedChunkMemoryRecover) xmlParseBalancedChunkMemoryRecover __attribute((alias("xmlParseBalancedChunkMemoryRecover__internal_alias"))); +#else +#ifndef xmlParseBalancedChunkMemoryRecover +extern __typeof (xmlParseBalancedChunkMemoryRecover) xmlParseBalancedChunkMemoryRecover__internal_alias __attribute((visibility("hidden"))); +#define xmlParseBalancedChunkMemoryRecover xmlParseBalancedChunkMemoryRecover__internal_alias +#endif +#endif +#endif + +#ifdef bottom_parser +#undef xmlParseCDSect +extern __typeof (xmlParseCDSect) xmlParseCDSect __attribute((alias("xmlParseCDSect__internal_alias"))); +#else +#ifndef xmlParseCDSect +extern __typeof (xmlParseCDSect) xmlParseCDSect__internal_alias __attribute((visibility("hidden"))); +#define xmlParseCDSect xmlParseCDSect__internal_alias +#endif +#endif + +#if defined(LIBXML_CATALOG_ENABLED) +#ifdef bottom_catalog +#undef xmlParseCatalogFile +extern __typeof (xmlParseCatalogFile) xmlParseCatalogFile __attribute((alias("xmlParseCatalogFile__internal_alias"))); +#else +#ifndef xmlParseCatalogFile +extern __typeof (xmlParseCatalogFile) xmlParseCatalogFile__internal_alias __attribute((visibility("hidden"))); +#define xmlParseCatalogFile xmlParseCatalogFile__internal_alias +#endif +#endif +#endif + +#ifdef bottom_parser +#undef xmlParseCharData +extern __typeof (xmlParseCharData) xmlParseCharData __attribute((alias("xmlParseCharData__internal_alias"))); +#else +#ifndef xmlParseCharData +extern __typeof (xmlParseCharData) xmlParseCharData__internal_alias __attribute((visibility("hidden"))); +#define xmlParseCharData xmlParseCharData__internal_alias +#endif +#endif + +#ifdef bottom_encoding +#undef xmlParseCharEncoding +extern __typeof (xmlParseCharEncoding) xmlParseCharEncoding __attribute((alias("xmlParseCharEncoding__internal_alias"))); +#else +#ifndef xmlParseCharEncoding +extern __typeof (xmlParseCharEncoding) xmlParseCharEncoding__internal_alias __attribute((visibility("hidden"))); +#define xmlParseCharEncoding xmlParseCharEncoding__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlParseCharRef +extern __typeof (xmlParseCharRef) xmlParseCharRef __attribute((alias("xmlParseCharRef__internal_alias"))); +#else +#ifndef xmlParseCharRef +extern __typeof (xmlParseCharRef) xmlParseCharRef__internal_alias __attribute((visibility("hidden"))); +#define xmlParseCharRef xmlParseCharRef__internal_alias +#endif +#endif + +#if defined(LIBXML_PUSH_ENABLED) +#ifdef bottom_parser +#undef xmlParseChunk +extern __typeof (xmlParseChunk) xmlParseChunk __attribute((alias("xmlParseChunk__internal_alias"))); +#else +#ifndef xmlParseChunk +extern __typeof (xmlParseChunk) xmlParseChunk__internal_alias __attribute((visibility("hidden"))); +#define xmlParseChunk xmlParseChunk__internal_alias +#endif +#endif +#endif + +#ifdef bottom_parser +#undef xmlParseComment +extern __typeof (xmlParseComment) xmlParseComment __attribute((alias("xmlParseComment__internal_alias"))); +#else +#ifndef xmlParseComment +extern __typeof (xmlParseComment) xmlParseComment__internal_alias __attribute((visibility("hidden"))); +#define xmlParseComment xmlParseComment__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlParseContent +extern __typeof (xmlParseContent) xmlParseContent __attribute((alias("xmlParseContent__internal_alias"))); +#else +#ifndef xmlParseContent +extern __typeof (xmlParseContent) xmlParseContent__internal_alias __attribute((visibility("hidden"))); +#define xmlParseContent xmlParseContent__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlParseCtxtExternalEntity +extern __typeof (xmlParseCtxtExternalEntity) xmlParseCtxtExternalEntity __attribute((alias("xmlParseCtxtExternalEntity__internal_alias"))); +#else +#ifndef xmlParseCtxtExternalEntity +extern __typeof (xmlParseCtxtExternalEntity) xmlParseCtxtExternalEntity__internal_alias __attribute((visibility("hidden"))); +#define xmlParseCtxtExternalEntity xmlParseCtxtExternalEntity__internal_alias +#endif +#endif + +#if defined(LIBXML_VALID_ENABLED) +#ifdef bottom_parser +#undef xmlParseDTD +extern __typeof (xmlParseDTD) xmlParseDTD __attribute((alias("xmlParseDTD__internal_alias"))); +#else +#ifndef xmlParseDTD +extern __typeof (xmlParseDTD) xmlParseDTD__internal_alias __attribute((visibility("hidden"))); +#define xmlParseDTD xmlParseDTD__internal_alias +#endif +#endif +#endif + +#ifdef bottom_parser +#undef xmlParseDefaultDecl +extern __typeof (xmlParseDefaultDecl) xmlParseDefaultDecl __attribute((alias("xmlParseDefaultDecl__internal_alias"))); +#else +#ifndef xmlParseDefaultDecl +extern __typeof (xmlParseDefaultDecl) xmlParseDefaultDecl__internal_alias __attribute((visibility("hidden"))); +#define xmlParseDefaultDecl xmlParseDefaultDecl__internal_alias +#endif +#endif + +#if defined(LIBXML_SAX1_ENABLED) +#ifdef bottom_parser +#undef xmlParseDoc +extern __typeof (xmlParseDoc) xmlParseDoc __attribute((alias("xmlParseDoc__internal_alias"))); +#else +#ifndef xmlParseDoc +extern __typeof (xmlParseDoc) xmlParseDoc__internal_alias __attribute((visibility("hidden"))); +#define xmlParseDoc xmlParseDoc__internal_alias +#endif +#endif +#endif + +#ifdef bottom_parser +#undef xmlParseDocTypeDecl +extern __typeof (xmlParseDocTypeDecl) xmlParseDocTypeDecl __attribute((alias("xmlParseDocTypeDecl__internal_alias"))); +#else +#ifndef xmlParseDocTypeDecl +extern __typeof (xmlParseDocTypeDecl) xmlParseDocTypeDecl__internal_alias __attribute((visibility("hidden"))); +#define xmlParseDocTypeDecl xmlParseDocTypeDecl__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlParseDocument +extern __typeof (xmlParseDocument) xmlParseDocument __attribute((alias("xmlParseDocument__internal_alias"))); +#else +#ifndef xmlParseDocument +extern __typeof (xmlParseDocument) xmlParseDocument__internal_alias __attribute((visibility("hidden"))); +#define xmlParseDocument xmlParseDocument__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlParseElement +extern __typeof (xmlParseElement) xmlParseElement __attribute((alias("xmlParseElement__internal_alias"))); +#else +#ifndef xmlParseElement +extern __typeof (xmlParseElement) xmlParseElement__internal_alias __attribute((visibility("hidden"))); +#define xmlParseElement xmlParseElement__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlParseElementChildrenContentDecl +extern __typeof (xmlParseElementChildrenContentDecl) xmlParseElementChildrenContentDecl __attribute((alias("xmlParseElementChildrenContentDecl__internal_alias"))); +#else +#ifndef xmlParseElementChildrenContentDecl +extern __typeof (xmlParseElementChildrenContentDecl) xmlParseElementChildrenContentDecl__internal_alias __attribute((visibility("hidden"))); +#define xmlParseElementChildrenContentDecl xmlParseElementChildrenContentDecl__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlParseElementContentDecl +extern __typeof (xmlParseElementContentDecl) xmlParseElementContentDecl __attribute((alias("xmlParseElementContentDecl__internal_alias"))); +#else +#ifndef xmlParseElementContentDecl +extern __typeof (xmlParseElementContentDecl) xmlParseElementContentDecl__internal_alias __attribute((visibility("hidden"))); +#define xmlParseElementContentDecl xmlParseElementContentDecl__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlParseElementDecl +extern __typeof (xmlParseElementDecl) xmlParseElementDecl __attribute((alias("xmlParseElementDecl__internal_alias"))); +#else +#ifndef xmlParseElementDecl +extern __typeof (xmlParseElementDecl) xmlParseElementDecl__internal_alias __attribute((visibility("hidden"))); +#define xmlParseElementDecl xmlParseElementDecl__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlParseElementMixedContentDecl +extern __typeof (xmlParseElementMixedContentDecl) xmlParseElementMixedContentDecl __attribute((alias("xmlParseElementMixedContentDecl__internal_alias"))); +#else +#ifndef xmlParseElementMixedContentDecl +extern __typeof (xmlParseElementMixedContentDecl) xmlParseElementMixedContentDecl__internal_alias __attribute((visibility("hidden"))); +#define xmlParseElementMixedContentDecl xmlParseElementMixedContentDecl__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlParseEncName +extern __typeof (xmlParseEncName) xmlParseEncName __attribute((alias("xmlParseEncName__internal_alias"))); +#else +#ifndef xmlParseEncName +extern __typeof (xmlParseEncName) xmlParseEncName__internal_alias __attribute((visibility("hidden"))); +#define xmlParseEncName xmlParseEncName__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlParseEncodingDecl +extern __typeof (xmlParseEncodingDecl) xmlParseEncodingDecl __attribute((alias("xmlParseEncodingDecl__internal_alias"))); +#else +#ifndef xmlParseEncodingDecl +extern __typeof (xmlParseEncodingDecl) xmlParseEncodingDecl__internal_alias __attribute((visibility("hidden"))); +#define xmlParseEncodingDecl xmlParseEncodingDecl__internal_alias +#endif +#endif + +#if defined(LIBXML_SAX1_ENABLED) +#ifdef bottom_parser +#undef xmlParseEndTag +extern __typeof (xmlParseEndTag) xmlParseEndTag __attribute((alias("xmlParseEndTag__internal_alias"))); +#else +#ifndef xmlParseEndTag +extern __typeof (xmlParseEndTag) xmlParseEndTag__internal_alias __attribute((visibility("hidden"))); +#define xmlParseEndTag xmlParseEndTag__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SAX1_ENABLED) +#ifdef bottom_parser +#undef xmlParseEntity +extern __typeof (xmlParseEntity) xmlParseEntity __attribute((alias("xmlParseEntity__internal_alias"))); +#else +#ifndef xmlParseEntity +extern __typeof (xmlParseEntity) xmlParseEntity__internal_alias __attribute((visibility("hidden"))); +#define xmlParseEntity xmlParseEntity__internal_alias +#endif +#endif +#endif + +#ifdef bottom_parser +#undef xmlParseEntityDecl +extern __typeof (xmlParseEntityDecl) xmlParseEntityDecl __attribute((alias("xmlParseEntityDecl__internal_alias"))); +#else +#ifndef xmlParseEntityDecl +extern __typeof (xmlParseEntityDecl) xmlParseEntityDecl__internal_alias __attribute((visibility("hidden"))); +#define xmlParseEntityDecl xmlParseEntityDecl__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlParseEntityRef +extern __typeof (xmlParseEntityRef) xmlParseEntityRef __attribute((alias("xmlParseEntityRef__internal_alias"))); +#else +#ifndef xmlParseEntityRef +extern __typeof (xmlParseEntityRef) xmlParseEntityRef__internal_alias __attribute((visibility("hidden"))); +#define xmlParseEntityRef xmlParseEntityRef__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlParseEntityValue +extern __typeof (xmlParseEntityValue) xmlParseEntityValue __attribute((alias("xmlParseEntityValue__internal_alias"))); +#else +#ifndef xmlParseEntityValue +extern __typeof (xmlParseEntityValue) xmlParseEntityValue__internal_alias __attribute((visibility("hidden"))); +#define xmlParseEntityValue xmlParseEntityValue__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlParseEnumeratedType +extern __typeof (xmlParseEnumeratedType) xmlParseEnumeratedType __attribute((alias("xmlParseEnumeratedType__internal_alias"))); +#else +#ifndef xmlParseEnumeratedType +extern __typeof (xmlParseEnumeratedType) xmlParseEnumeratedType__internal_alias __attribute((visibility("hidden"))); +#define xmlParseEnumeratedType xmlParseEnumeratedType__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlParseEnumerationType +extern __typeof (xmlParseEnumerationType) xmlParseEnumerationType __attribute((alias("xmlParseEnumerationType__internal_alias"))); +#else +#ifndef xmlParseEnumerationType +extern __typeof (xmlParseEnumerationType) xmlParseEnumerationType__internal_alias __attribute((visibility("hidden"))); +#define xmlParseEnumerationType xmlParseEnumerationType__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlParseExtParsedEnt +extern __typeof (xmlParseExtParsedEnt) xmlParseExtParsedEnt __attribute((alias("xmlParseExtParsedEnt__internal_alias"))); +#else +#ifndef xmlParseExtParsedEnt +extern __typeof (xmlParseExtParsedEnt) xmlParseExtParsedEnt__internal_alias __attribute((visibility("hidden"))); +#define xmlParseExtParsedEnt xmlParseExtParsedEnt__internal_alias +#endif +#endif + +#if defined(LIBXML_SAX1_ENABLED) +#ifdef bottom_parser +#undef xmlParseExternalEntity +extern __typeof (xmlParseExternalEntity) xmlParseExternalEntity __attribute((alias("xmlParseExternalEntity__internal_alias"))); +#else +#ifndef xmlParseExternalEntity +extern __typeof (xmlParseExternalEntity) xmlParseExternalEntity__internal_alias __attribute((visibility("hidden"))); +#define xmlParseExternalEntity xmlParseExternalEntity__internal_alias +#endif +#endif +#endif + +#ifdef bottom_parser +#undef xmlParseExternalID +extern __typeof (xmlParseExternalID) xmlParseExternalID __attribute((alias("xmlParseExternalID__internal_alias"))); +#else +#ifndef xmlParseExternalID +extern __typeof (xmlParseExternalID) xmlParseExternalID__internal_alias __attribute((visibility("hidden"))); +#define xmlParseExternalID xmlParseExternalID__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlParseExternalSubset +extern __typeof (xmlParseExternalSubset) xmlParseExternalSubset __attribute((alias("xmlParseExternalSubset__internal_alias"))); +#else +#ifndef xmlParseExternalSubset +extern __typeof (xmlParseExternalSubset) xmlParseExternalSubset__internal_alias __attribute((visibility("hidden"))); +#define xmlParseExternalSubset xmlParseExternalSubset__internal_alias +#endif +#endif + +#if defined(LIBXML_SAX1_ENABLED) +#ifdef bottom_parser +#undef xmlParseFile +extern __typeof (xmlParseFile) xmlParseFile __attribute((alias("xmlParseFile__internal_alias"))); +#else +#ifndef xmlParseFile +extern __typeof (xmlParseFile) xmlParseFile__internal_alias __attribute((visibility("hidden"))); +#define xmlParseFile xmlParseFile__internal_alias +#endif +#endif +#endif + +#ifdef bottom_parser +#undef xmlParseInNodeContext +extern __typeof (xmlParseInNodeContext) xmlParseInNodeContext __attribute((alias("xmlParseInNodeContext__internal_alias"))); +#else +#ifndef xmlParseInNodeContext +extern __typeof (xmlParseInNodeContext) xmlParseInNodeContext__internal_alias __attribute((visibility("hidden"))); +#define xmlParseInNodeContext xmlParseInNodeContext__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlParseMarkupDecl +extern __typeof (xmlParseMarkupDecl) xmlParseMarkupDecl __attribute((alias("xmlParseMarkupDecl__internal_alias"))); +#else +#ifndef xmlParseMarkupDecl +extern __typeof (xmlParseMarkupDecl) xmlParseMarkupDecl__internal_alias __attribute((visibility("hidden"))); +#define xmlParseMarkupDecl xmlParseMarkupDecl__internal_alias +#endif +#endif + +#if defined(LIBXML_SAX1_ENABLED) +#ifdef bottom_parser +#undef xmlParseMemory +extern __typeof (xmlParseMemory) xmlParseMemory __attribute((alias("xmlParseMemory__internal_alias"))); +#else +#ifndef xmlParseMemory +extern __typeof (xmlParseMemory) xmlParseMemory__internal_alias __attribute((visibility("hidden"))); +#define xmlParseMemory xmlParseMemory__internal_alias +#endif +#endif +#endif + +#ifdef bottom_parser +#undef xmlParseMisc +extern __typeof (xmlParseMisc) xmlParseMisc __attribute((alias("xmlParseMisc__internal_alias"))); +#else +#ifndef xmlParseMisc +extern __typeof (xmlParseMisc) xmlParseMisc__internal_alias __attribute((visibility("hidden"))); +#define xmlParseMisc xmlParseMisc__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlParseName +extern __typeof (xmlParseName) xmlParseName __attribute((alias("xmlParseName__internal_alias"))); +#else +#ifndef xmlParseName +extern __typeof (xmlParseName) xmlParseName__internal_alias __attribute((visibility("hidden"))); +#define xmlParseName xmlParseName__internal_alias +#endif +#endif + +#if defined(LIBXML_LEGACY_ENABLED) +#ifdef bottom_legacy +#undef xmlParseNamespace +extern __typeof (xmlParseNamespace) xmlParseNamespace __attribute((alias("xmlParseNamespace__internal_alias"))); +#else +#ifndef xmlParseNamespace +extern __typeof (xmlParseNamespace) xmlParseNamespace__internal_alias __attribute((visibility("hidden"))); +#define xmlParseNamespace xmlParseNamespace__internal_alias +#endif +#endif +#endif + +#ifdef bottom_parser +#undef xmlParseNmtoken +extern __typeof (xmlParseNmtoken) xmlParseNmtoken __attribute((alias("xmlParseNmtoken__internal_alias"))); +#else +#ifndef xmlParseNmtoken +extern __typeof (xmlParseNmtoken) xmlParseNmtoken__internal_alias __attribute((visibility("hidden"))); +#define xmlParseNmtoken xmlParseNmtoken__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlParseNotationDecl +extern __typeof (xmlParseNotationDecl) xmlParseNotationDecl __attribute((alias("xmlParseNotationDecl__internal_alias"))); +#else +#ifndef xmlParseNotationDecl +extern __typeof (xmlParseNotationDecl) xmlParseNotationDecl__internal_alias __attribute((visibility("hidden"))); +#define xmlParseNotationDecl xmlParseNotationDecl__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlParseNotationType +extern __typeof (xmlParseNotationType) xmlParseNotationType __attribute((alias("xmlParseNotationType__internal_alias"))); +#else +#ifndef xmlParseNotationType +extern __typeof (xmlParseNotationType) xmlParseNotationType__internal_alias __attribute((visibility("hidden"))); +#define xmlParseNotationType xmlParseNotationType__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlParsePEReference +extern __typeof (xmlParsePEReference) xmlParsePEReference __attribute((alias("xmlParsePEReference__internal_alias"))); +#else +#ifndef xmlParsePEReference +extern __typeof (xmlParsePEReference) xmlParsePEReference__internal_alias __attribute((visibility("hidden"))); +#define xmlParsePEReference xmlParsePEReference__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlParsePI +extern __typeof (xmlParsePI) xmlParsePI __attribute((alias("xmlParsePI__internal_alias"))); +#else +#ifndef xmlParsePI +extern __typeof (xmlParsePI) xmlParsePI__internal_alias __attribute((visibility("hidden"))); +#define xmlParsePI xmlParsePI__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlParsePITarget +extern __typeof (xmlParsePITarget) xmlParsePITarget __attribute((alias("xmlParsePITarget__internal_alias"))); +#else +#ifndef xmlParsePITarget +extern __typeof (xmlParsePITarget) xmlParsePITarget__internal_alias __attribute((visibility("hidden"))); +#define xmlParsePITarget xmlParsePITarget__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlParsePubidLiteral +extern __typeof (xmlParsePubidLiteral) xmlParsePubidLiteral __attribute((alias("xmlParsePubidLiteral__internal_alias"))); +#else +#ifndef xmlParsePubidLiteral +extern __typeof (xmlParsePubidLiteral) xmlParsePubidLiteral__internal_alias __attribute((visibility("hidden"))); +#define xmlParsePubidLiteral xmlParsePubidLiteral__internal_alias +#endif +#endif + +#if defined(LIBXML_LEGACY_ENABLED) +#ifdef bottom_legacy +#undef xmlParseQuotedString +extern __typeof (xmlParseQuotedString) xmlParseQuotedString __attribute((alias("xmlParseQuotedString__internal_alias"))); +#else +#ifndef xmlParseQuotedString +extern __typeof (xmlParseQuotedString) xmlParseQuotedString__internal_alias __attribute((visibility("hidden"))); +#define xmlParseQuotedString xmlParseQuotedString__internal_alias +#endif +#endif +#endif + +#ifdef bottom_parser +#undef xmlParseReference +extern __typeof (xmlParseReference) xmlParseReference __attribute((alias("xmlParseReference__internal_alias"))); +#else +#ifndef xmlParseReference +extern __typeof (xmlParseReference) xmlParseReference__internal_alias __attribute((visibility("hidden"))); +#define xmlParseReference xmlParseReference__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlParseSDDecl +extern __typeof (xmlParseSDDecl) xmlParseSDDecl __attribute((alias("xmlParseSDDecl__internal_alias"))); +#else +#ifndef xmlParseSDDecl +extern __typeof (xmlParseSDDecl) xmlParseSDDecl__internal_alias __attribute((visibility("hidden"))); +#define xmlParseSDDecl xmlParseSDDecl__internal_alias +#endif +#endif + +#if defined(LIBXML_SAX1_ENABLED) +#ifdef bottom_parser +#undef xmlParseStartTag +extern __typeof (xmlParseStartTag) xmlParseStartTag __attribute((alias("xmlParseStartTag__internal_alias"))); +#else +#ifndef xmlParseStartTag +extern __typeof (xmlParseStartTag) xmlParseStartTag__internal_alias __attribute((visibility("hidden"))); +#define xmlParseStartTag xmlParseStartTag__internal_alias +#endif +#endif +#endif + +#ifdef bottom_parser +#undef xmlParseSystemLiteral +extern __typeof (xmlParseSystemLiteral) xmlParseSystemLiteral __attribute((alias("xmlParseSystemLiteral__internal_alias"))); +#else +#ifndef xmlParseSystemLiteral +extern __typeof (xmlParseSystemLiteral) xmlParseSystemLiteral__internal_alias __attribute((visibility("hidden"))); +#define xmlParseSystemLiteral xmlParseSystemLiteral__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlParseTextDecl +extern __typeof (xmlParseTextDecl) xmlParseTextDecl __attribute((alias("xmlParseTextDecl__internal_alias"))); +#else +#ifndef xmlParseTextDecl +extern __typeof (xmlParseTextDecl) xmlParseTextDecl__internal_alias __attribute((visibility("hidden"))); +#define xmlParseTextDecl xmlParseTextDecl__internal_alias +#endif +#endif + +#ifdef bottom_uri +#undef xmlParseURI +extern __typeof (xmlParseURI) xmlParseURI __attribute((alias("xmlParseURI__internal_alias"))); +#else +#ifndef xmlParseURI +extern __typeof (xmlParseURI) xmlParseURI__internal_alias __attribute((visibility("hidden"))); +#define xmlParseURI xmlParseURI__internal_alias +#endif +#endif + +#ifdef bottom_uri +#undef xmlParseURIRaw +extern __typeof (xmlParseURIRaw) xmlParseURIRaw __attribute((alias("xmlParseURIRaw__internal_alias"))); +#else +#ifndef xmlParseURIRaw +extern __typeof (xmlParseURIRaw) xmlParseURIRaw__internal_alias __attribute((visibility("hidden"))); +#define xmlParseURIRaw xmlParseURIRaw__internal_alias +#endif +#endif + +#ifdef bottom_uri +#undef xmlParseURIReference +extern __typeof (xmlParseURIReference) xmlParseURIReference __attribute((alias("xmlParseURIReference__internal_alias"))); +#else +#ifndef xmlParseURIReference +extern __typeof (xmlParseURIReference) xmlParseURIReference__internal_alias __attribute((visibility("hidden"))); +#define xmlParseURIReference xmlParseURIReference__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlParseVersionInfo +extern __typeof (xmlParseVersionInfo) xmlParseVersionInfo __attribute((alias("xmlParseVersionInfo__internal_alias"))); +#else +#ifndef xmlParseVersionInfo +extern __typeof (xmlParseVersionInfo) xmlParseVersionInfo__internal_alias __attribute((visibility("hidden"))); +#define xmlParseVersionInfo xmlParseVersionInfo__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlParseVersionNum +extern __typeof (xmlParseVersionNum) xmlParseVersionNum __attribute((alias("xmlParseVersionNum__internal_alias"))); +#else +#ifndef xmlParseVersionNum +extern __typeof (xmlParseVersionNum) xmlParseVersionNum__internal_alias __attribute((visibility("hidden"))); +#define xmlParseVersionNum xmlParseVersionNum__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlParseXMLDecl +extern __typeof (xmlParseXMLDecl) xmlParseXMLDecl __attribute((alias("xmlParseXMLDecl__internal_alias"))); +#else +#ifndef xmlParseXMLDecl +extern __typeof (xmlParseXMLDecl) xmlParseXMLDecl__internal_alias __attribute((visibility("hidden"))); +#define xmlParseXMLDecl xmlParseXMLDecl__internal_alias +#endif +#endif + +#ifdef bottom_parserInternals +#undef xmlParserAddNodeInfo +extern __typeof (xmlParserAddNodeInfo) xmlParserAddNodeInfo __attribute((alias("xmlParserAddNodeInfo__internal_alias"))); +#else +#ifndef xmlParserAddNodeInfo +extern __typeof (xmlParserAddNodeInfo) xmlParserAddNodeInfo__internal_alias __attribute((visibility("hidden"))); +#define xmlParserAddNodeInfo xmlParserAddNodeInfo__internal_alias +#endif +#endif + +#ifdef bottom_error +#undef xmlParserError +extern __typeof (xmlParserError) xmlParserError __attribute((alias("xmlParserError__internal_alias"))); +#else +#ifndef xmlParserError +extern __typeof (xmlParserError) xmlParserError__internal_alias __attribute((visibility("hidden"))); +#define xmlParserError xmlParserError__internal_alias +#endif +#endif + +#ifdef bottom_parserInternals +#undef xmlParserFindNodeInfo +extern __typeof (xmlParserFindNodeInfo) xmlParserFindNodeInfo __attribute((alias("xmlParserFindNodeInfo__internal_alias"))); +#else +#ifndef xmlParserFindNodeInfo +extern __typeof (xmlParserFindNodeInfo) xmlParserFindNodeInfo__internal_alias __attribute((visibility("hidden"))); +#define xmlParserFindNodeInfo xmlParserFindNodeInfo__internal_alias +#endif +#endif + +#ifdef bottom_parserInternals +#undef xmlParserFindNodeInfoIndex +extern __typeof (xmlParserFindNodeInfoIndex) xmlParserFindNodeInfoIndex __attribute((alias("xmlParserFindNodeInfoIndex__internal_alias"))); +#else +#ifndef xmlParserFindNodeInfoIndex +extern __typeof (xmlParserFindNodeInfoIndex) xmlParserFindNodeInfoIndex__internal_alias __attribute((visibility("hidden"))); +#define xmlParserFindNodeInfoIndex xmlParserFindNodeInfoIndex__internal_alias +#endif +#endif + +#ifdef bottom_xmlIO +#undef xmlParserGetDirectory +extern __typeof (xmlParserGetDirectory) xmlParserGetDirectory __attribute((alias("xmlParserGetDirectory__internal_alias"))); +#else +#ifndef xmlParserGetDirectory +extern __typeof (xmlParserGetDirectory) xmlParserGetDirectory__internal_alias __attribute((visibility("hidden"))); +#define xmlParserGetDirectory xmlParserGetDirectory__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlParserHandlePEReference +extern __typeof (xmlParserHandlePEReference) xmlParserHandlePEReference __attribute((alias("xmlParserHandlePEReference__internal_alias"))); +#else +#ifndef xmlParserHandlePEReference +extern __typeof (xmlParserHandlePEReference) xmlParserHandlePEReference__internal_alias __attribute((visibility("hidden"))); +#define xmlParserHandlePEReference xmlParserHandlePEReference__internal_alias +#endif +#endif + +#if defined(LIBXML_LEGACY_ENABLED) +#ifdef bottom_legacy +#undef xmlParserHandleReference +extern __typeof (xmlParserHandleReference) xmlParserHandleReference __attribute((alias("xmlParserHandleReference__internal_alias"))); +#else +#ifndef xmlParserHandleReference +extern __typeof (xmlParserHandleReference) xmlParserHandleReference__internal_alias __attribute((visibility("hidden"))); +#define xmlParserHandleReference xmlParserHandleReference__internal_alias +#endif +#endif +#endif + +#ifdef bottom_xmlIO +#undef xmlParserInputBufferCreateFd +extern __typeof (xmlParserInputBufferCreateFd) xmlParserInputBufferCreateFd __attribute((alias("xmlParserInputBufferCreateFd__internal_alias"))); +#else +#ifndef xmlParserInputBufferCreateFd +extern __typeof (xmlParserInputBufferCreateFd) xmlParserInputBufferCreateFd__internal_alias __attribute((visibility("hidden"))); +#define xmlParserInputBufferCreateFd xmlParserInputBufferCreateFd__internal_alias +#endif +#endif + +#ifdef bottom_xmlIO +#undef xmlParserInputBufferCreateFile +extern __typeof (xmlParserInputBufferCreateFile) xmlParserInputBufferCreateFile __attribute((alias("xmlParserInputBufferCreateFile__internal_alias"))); +#else +#ifndef xmlParserInputBufferCreateFile +extern __typeof (xmlParserInputBufferCreateFile) xmlParserInputBufferCreateFile__internal_alias __attribute((visibility("hidden"))); +#define xmlParserInputBufferCreateFile xmlParserInputBufferCreateFile__internal_alias +#endif +#endif + +#ifdef bottom_xmlIO +#undef xmlParserInputBufferCreateFilename +extern __typeof (xmlParserInputBufferCreateFilename) xmlParserInputBufferCreateFilename __attribute((alias("xmlParserInputBufferCreateFilename__internal_alias"))); +#else +#ifndef xmlParserInputBufferCreateFilename +extern __typeof (xmlParserInputBufferCreateFilename) xmlParserInputBufferCreateFilename__internal_alias __attribute((visibility("hidden"))); +#define xmlParserInputBufferCreateFilename xmlParserInputBufferCreateFilename__internal_alias +#endif +#endif + +#ifdef bottom_xmlIO +#undef xmlParserInputBufferCreateFilenameDefault +extern __typeof (xmlParserInputBufferCreateFilenameDefault) xmlParserInputBufferCreateFilenameDefault __attribute((alias("xmlParserInputBufferCreateFilenameDefault__internal_alias"))); +#else +#ifndef xmlParserInputBufferCreateFilenameDefault +extern __typeof (xmlParserInputBufferCreateFilenameDefault) xmlParserInputBufferCreateFilenameDefault__internal_alias __attribute((visibility("hidden"))); +#define xmlParserInputBufferCreateFilenameDefault xmlParserInputBufferCreateFilenameDefault__internal_alias +#endif +#endif + +#ifdef bottom_xmlIO +#undef xmlParserInputBufferCreateIO +extern __typeof (xmlParserInputBufferCreateIO) xmlParserInputBufferCreateIO __attribute((alias("xmlParserInputBufferCreateIO__internal_alias"))); +#else +#ifndef xmlParserInputBufferCreateIO +extern __typeof (xmlParserInputBufferCreateIO) xmlParserInputBufferCreateIO__internal_alias __attribute((visibility("hidden"))); +#define xmlParserInputBufferCreateIO xmlParserInputBufferCreateIO__internal_alias +#endif +#endif + +#ifdef bottom_xmlIO +#undef xmlParserInputBufferCreateMem +extern __typeof (xmlParserInputBufferCreateMem) xmlParserInputBufferCreateMem __attribute((alias("xmlParserInputBufferCreateMem__internal_alias"))); +#else +#ifndef xmlParserInputBufferCreateMem +extern __typeof (xmlParserInputBufferCreateMem) xmlParserInputBufferCreateMem__internal_alias __attribute((visibility("hidden"))); +#define xmlParserInputBufferCreateMem xmlParserInputBufferCreateMem__internal_alias +#endif +#endif + +#ifdef bottom_xmlIO +#undef xmlParserInputBufferCreateStatic +extern __typeof (xmlParserInputBufferCreateStatic) xmlParserInputBufferCreateStatic __attribute((alias("xmlParserInputBufferCreateStatic__internal_alias"))); +#else +#ifndef xmlParserInputBufferCreateStatic +extern __typeof (xmlParserInputBufferCreateStatic) xmlParserInputBufferCreateStatic__internal_alias __attribute((visibility("hidden"))); +#define xmlParserInputBufferCreateStatic xmlParserInputBufferCreateStatic__internal_alias +#endif +#endif + +#ifdef bottom_xmlIO +#undef xmlParserInputBufferGrow +extern __typeof (xmlParserInputBufferGrow) xmlParserInputBufferGrow __attribute((alias("xmlParserInputBufferGrow__internal_alias"))); +#else +#ifndef xmlParserInputBufferGrow +extern __typeof (xmlParserInputBufferGrow) xmlParserInputBufferGrow__internal_alias __attribute((visibility("hidden"))); +#define xmlParserInputBufferGrow xmlParserInputBufferGrow__internal_alias +#endif +#endif + +#ifdef bottom_xmlIO +#undef xmlParserInputBufferPush +extern __typeof (xmlParserInputBufferPush) xmlParserInputBufferPush __attribute((alias("xmlParserInputBufferPush__internal_alias"))); +#else +#ifndef xmlParserInputBufferPush +extern __typeof (xmlParserInputBufferPush) xmlParserInputBufferPush__internal_alias __attribute((visibility("hidden"))); +#define xmlParserInputBufferPush xmlParserInputBufferPush__internal_alias +#endif +#endif + +#ifdef bottom_xmlIO +#undef xmlParserInputBufferRead +extern __typeof (xmlParserInputBufferRead) xmlParserInputBufferRead __attribute((alias("xmlParserInputBufferRead__internal_alias"))); +#else +#ifndef xmlParserInputBufferRead +extern __typeof (xmlParserInputBufferRead) xmlParserInputBufferRead__internal_alias __attribute((visibility("hidden"))); +#define xmlParserInputBufferRead xmlParserInputBufferRead__internal_alias +#endif +#endif + +#ifdef bottom_parserInternals +#undef xmlParserInputGrow +extern __typeof (xmlParserInputGrow) xmlParserInputGrow __attribute((alias("xmlParserInputGrow__internal_alias"))); +#else +#ifndef xmlParserInputGrow +extern __typeof (xmlParserInputGrow) xmlParserInputGrow__internal_alias __attribute((visibility("hidden"))); +#define xmlParserInputGrow xmlParserInputGrow__internal_alias +#endif +#endif + +#ifdef bottom_parserInternals +#undef xmlParserInputRead +extern __typeof (xmlParserInputRead) xmlParserInputRead __attribute((alias("xmlParserInputRead__internal_alias"))); +#else +#ifndef xmlParserInputRead +extern __typeof (xmlParserInputRead) xmlParserInputRead__internal_alias __attribute((visibility("hidden"))); +#define xmlParserInputRead xmlParserInputRead__internal_alias +#endif +#endif + +#ifdef bottom_parserInternals +#undef xmlParserInputShrink +extern __typeof (xmlParserInputShrink) xmlParserInputShrink __attribute((alias("xmlParserInputShrink__internal_alias"))); +#else +#ifndef xmlParserInputShrink +extern __typeof (xmlParserInputShrink) xmlParserInputShrink__internal_alias __attribute((visibility("hidden"))); +#define xmlParserInputShrink xmlParserInputShrink__internal_alias +#endif +#endif + +#ifdef bottom_error +#undef xmlParserPrintFileContext +extern __typeof (xmlParserPrintFileContext) xmlParserPrintFileContext __attribute((alias("xmlParserPrintFileContext__internal_alias"))); +#else +#ifndef xmlParserPrintFileContext +extern __typeof (xmlParserPrintFileContext) xmlParserPrintFileContext__internal_alias __attribute((visibility("hidden"))); +#define xmlParserPrintFileContext xmlParserPrintFileContext__internal_alias +#endif +#endif + +#ifdef bottom_error +#undef xmlParserPrintFileInfo +extern __typeof (xmlParserPrintFileInfo) xmlParserPrintFileInfo __attribute((alias("xmlParserPrintFileInfo__internal_alias"))); +#else +#ifndef xmlParserPrintFileInfo +extern __typeof (xmlParserPrintFileInfo) xmlParserPrintFileInfo__internal_alias __attribute((visibility("hidden"))); +#define xmlParserPrintFileInfo xmlParserPrintFileInfo__internal_alias +#endif +#endif + +#ifdef bottom_error +#undef xmlParserValidityError +extern __typeof (xmlParserValidityError) xmlParserValidityError __attribute((alias("xmlParserValidityError__internal_alias"))); +#else +#ifndef xmlParserValidityError +extern __typeof (xmlParserValidityError) xmlParserValidityError__internal_alias __attribute((visibility("hidden"))); +#define xmlParserValidityError xmlParserValidityError__internal_alias +#endif +#endif + +#ifdef bottom_error +#undef xmlParserValidityWarning +extern __typeof (xmlParserValidityWarning) xmlParserValidityWarning __attribute((alias("xmlParserValidityWarning__internal_alias"))); +#else +#ifndef xmlParserValidityWarning +extern __typeof (xmlParserValidityWarning) xmlParserValidityWarning__internal_alias __attribute((visibility("hidden"))); +#define xmlParserValidityWarning xmlParserValidityWarning__internal_alias +#endif +#endif + +#ifdef bottom_error +#undef xmlParserWarning +extern __typeof (xmlParserWarning) xmlParserWarning __attribute((alias("xmlParserWarning__internal_alias"))); +#else +#ifndef xmlParserWarning +extern __typeof (xmlParserWarning) xmlParserWarning__internal_alias __attribute((visibility("hidden"))); +#define xmlParserWarning xmlParserWarning__internal_alias +#endif +#endif + +#ifdef bottom_uri +#undef xmlPathToURI +extern __typeof (xmlPathToURI) xmlPathToURI __attribute((alias("xmlPathToURI__internal_alias"))); +#else +#ifndef xmlPathToURI +extern __typeof (xmlPathToURI) xmlPathToURI__internal_alias __attribute((visibility("hidden"))); +#define xmlPathToURI xmlPathToURI__internal_alias +#endif +#endif + +#if defined(LIBXML_PATTERN_ENABLED) +#ifdef bottom_pattern +#undef xmlPatternFromRoot +extern __typeof (xmlPatternFromRoot) xmlPatternFromRoot __attribute((alias("xmlPatternFromRoot__internal_alias"))); +#else +#ifndef xmlPatternFromRoot +extern __typeof (xmlPatternFromRoot) xmlPatternFromRoot__internal_alias __attribute((visibility("hidden"))); +#define xmlPatternFromRoot xmlPatternFromRoot__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_PATTERN_ENABLED) +#ifdef bottom_pattern +#undef xmlPatternGetStreamCtxt +extern __typeof (xmlPatternGetStreamCtxt) xmlPatternGetStreamCtxt __attribute((alias("xmlPatternGetStreamCtxt__internal_alias"))); +#else +#ifndef xmlPatternGetStreamCtxt +extern __typeof (xmlPatternGetStreamCtxt) xmlPatternGetStreamCtxt__internal_alias __attribute((visibility("hidden"))); +#define xmlPatternGetStreamCtxt xmlPatternGetStreamCtxt__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_PATTERN_ENABLED) +#ifdef bottom_pattern +#undef xmlPatternMatch +extern __typeof (xmlPatternMatch) xmlPatternMatch __attribute((alias("xmlPatternMatch__internal_alias"))); +#else +#ifndef xmlPatternMatch +extern __typeof (xmlPatternMatch) xmlPatternMatch__internal_alias __attribute((visibility("hidden"))); +#define xmlPatternMatch xmlPatternMatch__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_PATTERN_ENABLED) +#ifdef bottom_pattern +#undef xmlPatternMaxDepth +extern __typeof (xmlPatternMaxDepth) xmlPatternMaxDepth __attribute((alias("xmlPatternMaxDepth__internal_alias"))); +#else +#ifndef xmlPatternMaxDepth +extern __typeof (xmlPatternMaxDepth) xmlPatternMaxDepth__internal_alias __attribute((visibility("hidden"))); +#define xmlPatternMaxDepth xmlPatternMaxDepth__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_PATTERN_ENABLED) +#ifdef bottom_pattern +#undef xmlPatternMinDepth +extern __typeof (xmlPatternMinDepth) xmlPatternMinDepth __attribute((alias("xmlPatternMinDepth__internal_alias"))); +#else +#ifndef xmlPatternMinDepth +extern __typeof (xmlPatternMinDepth) xmlPatternMinDepth__internal_alias __attribute((visibility("hidden"))); +#define xmlPatternMinDepth xmlPatternMinDepth__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_PATTERN_ENABLED) +#ifdef bottom_pattern +#undef xmlPatternStreamable +extern __typeof (xmlPatternStreamable) xmlPatternStreamable __attribute((alias("xmlPatternStreamable__internal_alias"))); +#else +#ifndef xmlPatternStreamable +extern __typeof (xmlPatternStreamable) xmlPatternStreamable__internal_alias __attribute((visibility("hidden"))); +#define xmlPatternStreamable xmlPatternStreamable__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_PATTERN_ENABLED) +#ifdef bottom_pattern +#undef xmlPatterncompile +extern __typeof (xmlPatterncompile) xmlPatterncompile __attribute((alias("xmlPatterncompile__internal_alias"))); +#else +#ifndef xmlPatterncompile +extern __typeof (xmlPatterncompile) xmlPatterncompile__internal_alias __attribute((visibility("hidden"))); +#define xmlPatterncompile xmlPatterncompile__internal_alias +#endif +#endif +#endif + +#ifdef bottom_parserInternals +#undef xmlPedanticParserDefault +extern __typeof (xmlPedanticParserDefault) xmlPedanticParserDefault __attribute((alias("xmlPedanticParserDefault__internal_alias"))); +#else +#ifndef xmlPedanticParserDefault +extern __typeof (xmlPedanticParserDefault) xmlPedanticParserDefault__internal_alias __attribute((visibility("hidden"))); +#define xmlPedanticParserDefault xmlPedanticParserDefault__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlPopInput +extern __typeof (xmlPopInput) xmlPopInput __attribute((alias("xmlPopInput__internal_alias"))); +#else +#ifndef xmlPopInput +extern __typeof (xmlPopInput) xmlPopInput__internal_alias __attribute((visibility("hidden"))); +#define xmlPopInput xmlPopInput__internal_alias +#endif +#endif + +#ifdef bottom_xmlIO +#undef xmlPopInputCallbacks +extern __typeof (xmlPopInputCallbacks) xmlPopInputCallbacks __attribute((alias("xmlPopInputCallbacks__internal_alias"))); +#else +#ifndef xmlPopInputCallbacks +extern __typeof (xmlPopInputCallbacks) xmlPopInputCallbacks__internal_alias __attribute((visibility("hidden"))); +#define xmlPopInputCallbacks xmlPopInputCallbacks__internal_alias +#endif +#endif + +#if defined(LIBXML_TREE_ENABLED) +#ifdef bottom_tree +#undef xmlPreviousElementSibling +extern __typeof (xmlPreviousElementSibling) xmlPreviousElementSibling __attribute((alias("xmlPreviousElementSibling__internal_alias"))); +#else +#ifndef xmlPreviousElementSibling +extern __typeof (xmlPreviousElementSibling) xmlPreviousElementSibling__internal_alias __attribute((visibility("hidden"))); +#define xmlPreviousElementSibling xmlPreviousElementSibling__internal_alias +#endif +#endif +#endif + +#ifdef bottom_uri +#undef xmlPrintURI +extern __typeof (xmlPrintURI) xmlPrintURI __attribute((alias("xmlPrintURI__internal_alias"))); +#else +#ifndef xmlPrintURI +extern __typeof (xmlPrintURI) xmlPrintURI__internal_alias __attribute((visibility("hidden"))); +#define xmlPrintURI xmlPrintURI__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlPushInput +extern __typeof (xmlPushInput) xmlPushInput __attribute((alias("xmlPushInput__internal_alias"))); +#else +#ifndef xmlPushInput +extern __typeof (xmlPushInput) xmlPushInput__internal_alias __attribute((visibility("hidden"))); +#define xmlPushInput xmlPushInput__internal_alias +#endif +#endif + +#ifdef bottom_threads +#undef xmlRMutexLock +extern __typeof (xmlRMutexLock) xmlRMutexLock __attribute((alias("xmlRMutexLock__internal_alias"))); +#else +#ifndef xmlRMutexLock +extern __typeof (xmlRMutexLock) xmlRMutexLock__internal_alias __attribute((visibility("hidden"))); +#define xmlRMutexLock xmlRMutexLock__internal_alias +#endif +#endif + +#ifdef bottom_threads +#undef xmlRMutexUnlock +extern __typeof (xmlRMutexUnlock) xmlRMutexUnlock __attribute((alias("xmlRMutexUnlock__internal_alias"))); +#else +#ifndef xmlRMutexUnlock +extern __typeof (xmlRMutexUnlock) xmlRMutexUnlock__internal_alias __attribute((visibility("hidden"))); +#define xmlRMutexUnlock xmlRMutexUnlock__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlReadDoc +extern __typeof (xmlReadDoc) xmlReadDoc __attribute((alias("xmlReadDoc__internal_alias"))); +#else +#ifndef xmlReadDoc +extern __typeof (xmlReadDoc) xmlReadDoc__internal_alias __attribute((visibility("hidden"))); +#define xmlReadDoc xmlReadDoc__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlReadFd +extern __typeof (xmlReadFd) xmlReadFd __attribute((alias("xmlReadFd__internal_alias"))); +#else +#ifndef xmlReadFd +extern __typeof (xmlReadFd) xmlReadFd__internal_alias __attribute((visibility("hidden"))); +#define xmlReadFd xmlReadFd__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlReadFile +extern __typeof (xmlReadFile) xmlReadFile __attribute((alias("xmlReadFile__internal_alias"))); +#else +#ifndef xmlReadFile +extern __typeof (xmlReadFile) xmlReadFile__internal_alias __attribute((visibility("hidden"))); +#define xmlReadFile xmlReadFile__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlReadIO +extern __typeof (xmlReadIO) xmlReadIO __attribute((alias("xmlReadIO__internal_alias"))); +#else +#ifndef xmlReadIO +extern __typeof (xmlReadIO) xmlReadIO__internal_alias __attribute((visibility("hidden"))); +#define xmlReadIO xmlReadIO__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlReadMemory +extern __typeof (xmlReadMemory) xmlReadMemory __attribute((alias("xmlReadMemory__internal_alias"))); +#else +#ifndef xmlReadMemory +extern __typeof (xmlReadMemory) xmlReadMemory__internal_alias __attribute((visibility("hidden"))); +#define xmlReadMemory xmlReadMemory__internal_alias +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlReaderForDoc +extern __typeof (xmlReaderForDoc) xmlReaderForDoc __attribute((alias("xmlReaderForDoc__internal_alias"))); +#else +#ifndef xmlReaderForDoc +extern __typeof (xmlReaderForDoc) xmlReaderForDoc__internal_alias __attribute((visibility("hidden"))); +#define xmlReaderForDoc xmlReaderForDoc__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlReaderForFd +extern __typeof (xmlReaderForFd) xmlReaderForFd __attribute((alias("xmlReaderForFd__internal_alias"))); +#else +#ifndef xmlReaderForFd +extern __typeof (xmlReaderForFd) xmlReaderForFd__internal_alias __attribute((visibility("hidden"))); +#define xmlReaderForFd xmlReaderForFd__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlReaderForFile +extern __typeof (xmlReaderForFile) xmlReaderForFile __attribute((alias("xmlReaderForFile__internal_alias"))); +#else +#ifndef xmlReaderForFile +extern __typeof (xmlReaderForFile) xmlReaderForFile__internal_alias __attribute((visibility("hidden"))); +#define xmlReaderForFile xmlReaderForFile__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlReaderForIO +extern __typeof (xmlReaderForIO) xmlReaderForIO __attribute((alias("xmlReaderForIO__internal_alias"))); +#else +#ifndef xmlReaderForIO +extern __typeof (xmlReaderForIO) xmlReaderForIO__internal_alias __attribute((visibility("hidden"))); +#define xmlReaderForIO xmlReaderForIO__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlReaderForMemory +extern __typeof (xmlReaderForMemory) xmlReaderForMemory __attribute((alias("xmlReaderForMemory__internal_alias"))); +#else +#ifndef xmlReaderForMemory +extern __typeof (xmlReaderForMemory) xmlReaderForMemory__internal_alias __attribute((visibility("hidden"))); +#define xmlReaderForMemory xmlReaderForMemory__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlReaderNewDoc +extern __typeof (xmlReaderNewDoc) xmlReaderNewDoc __attribute((alias("xmlReaderNewDoc__internal_alias"))); +#else +#ifndef xmlReaderNewDoc +extern __typeof (xmlReaderNewDoc) xmlReaderNewDoc__internal_alias __attribute((visibility("hidden"))); +#define xmlReaderNewDoc xmlReaderNewDoc__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlReaderNewFd +extern __typeof (xmlReaderNewFd) xmlReaderNewFd __attribute((alias("xmlReaderNewFd__internal_alias"))); +#else +#ifndef xmlReaderNewFd +extern __typeof (xmlReaderNewFd) xmlReaderNewFd__internal_alias __attribute((visibility("hidden"))); +#define xmlReaderNewFd xmlReaderNewFd__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlReaderNewFile +extern __typeof (xmlReaderNewFile) xmlReaderNewFile __attribute((alias("xmlReaderNewFile__internal_alias"))); +#else +#ifndef xmlReaderNewFile +extern __typeof (xmlReaderNewFile) xmlReaderNewFile__internal_alias __attribute((visibility("hidden"))); +#define xmlReaderNewFile xmlReaderNewFile__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlReaderNewIO +extern __typeof (xmlReaderNewIO) xmlReaderNewIO __attribute((alias("xmlReaderNewIO__internal_alias"))); +#else +#ifndef xmlReaderNewIO +extern __typeof (xmlReaderNewIO) xmlReaderNewIO__internal_alias __attribute((visibility("hidden"))); +#define xmlReaderNewIO xmlReaderNewIO__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlReaderNewMemory +extern __typeof (xmlReaderNewMemory) xmlReaderNewMemory __attribute((alias("xmlReaderNewMemory__internal_alias"))); +#else +#ifndef xmlReaderNewMemory +extern __typeof (xmlReaderNewMemory) xmlReaderNewMemory__internal_alias __attribute((visibility("hidden"))); +#define xmlReaderNewMemory xmlReaderNewMemory__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlReaderNewWalker +extern __typeof (xmlReaderNewWalker) xmlReaderNewWalker __attribute((alias("xmlReaderNewWalker__internal_alias"))); +#else +#ifndef xmlReaderNewWalker +extern __typeof (xmlReaderNewWalker) xmlReaderNewWalker__internal_alias __attribute((visibility("hidden"))); +#define xmlReaderNewWalker xmlReaderNewWalker__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlReaderWalker +extern __typeof (xmlReaderWalker) xmlReaderWalker __attribute((alias("xmlReaderWalker__internal_alias"))); +#else +#ifndef xmlReaderWalker +extern __typeof (xmlReaderWalker) xmlReaderWalker__internal_alias __attribute((visibility("hidden"))); +#define xmlReaderWalker xmlReaderWalker__internal_alias +#endif +#endif +#endif + +#ifdef bottom_xmlmemory +#undef xmlReallocLoc +extern __typeof (xmlReallocLoc) xmlReallocLoc __attribute((alias("xmlReallocLoc__internal_alias"))); +#else +#ifndef xmlReallocLoc +extern __typeof (xmlReallocLoc) xmlReallocLoc__internal_alias __attribute((visibility("hidden"))); +#define xmlReallocLoc xmlReallocLoc__internal_alias +#endif +#endif + +#if defined(LIBXML_TREE_ENABLED) +#ifdef bottom_tree +#undef xmlReconciliateNs +extern __typeof (xmlReconciliateNs) xmlReconciliateNs __attribute((alias("xmlReconciliateNs__internal_alias"))); +#else +#ifndef xmlReconciliateNs +extern __typeof (xmlReconciliateNs) xmlReconciliateNs__internal_alias __attribute((visibility("hidden"))); +#define xmlReconciliateNs xmlReconciliateNs__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SAX1_ENABLED) +#ifdef bottom_parser +#undef xmlRecoverDoc +extern __typeof (xmlRecoverDoc) xmlRecoverDoc __attribute((alias("xmlRecoverDoc__internal_alias"))); +#else +#ifndef xmlRecoverDoc +extern __typeof (xmlRecoverDoc) xmlRecoverDoc__internal_alias __attribute((visibility("hidden"))); +#define xmlRecoverDoc xmlRecoverDoc__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SAX1_ENABLED) +#ifdef bottom_parser +#undef xmlRecoverFile +extern __typeof (xmlRecoverFile) xmlRecoverFile __attribute((alias("xmlRecoverFile__internal_alias"))); +#else +#ifndef xmlRecoverFile +extern __typeof (xmlRecoverFile) xmlRecoverFile__internal_alias __attribute((visibility("hidden"))); +#define xmlRecoverFile xmlRecoverFile__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SAX1_ENABLED) +#ifdef bottom_parser +#undef xmlRecoverMemory +extern __typeof (xmlRecoverMemory) xmlRecoverMemory __attribute((alias("xmlRecoverMemory__internal_alias"))); +#else +#ifndef xmlRecoverMemory +extern __typeof (xmlRecoverMemory) xmlRecoverMemory__internal_alias __attribute((visibility("hidden"))); +#define xmlRecoverMemory xmlRecoverMemory__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlRegExecErrInfo +extern __typeof (xmlRegExecErrInfo) xmlRegExecErrInfo __attribute((alias("xmlRegExecErrInfo__internal_alias"))); +#else +#ifndef xmlRegExecErrInfo +extern __typeof (xmlRegExecErrInfo) xmlRegExecErrInfo__internal_alias __attribute((visibility("hidden"))); +#define xmlRegExecErrInfo xmlRegExecErrInfo__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlRegExecNextValues +extern __typeof (xmlRegExecNextValues) xmlRegExecNextValues __attribute((alias("xmlRegExecNextValues__internal_alias"))); +#else +#ifndef xmlRegExecNextValues +extern __typeof (xmlRegExecNextValues) xmlRegExecNextValues__internal_alias __attribute((visibility("hidden"))); +#define xmlRegExecNextValues xmlRegExecNextValues__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlRegExecPushString +extern __typeof (xmlRegExecPushString) xmlRegExecPushString __attribute((alias("xmlRegExecPushString__internal_alias"))); +#else +#ifndef xmlRegExecPushString +extern __typeof (xmlRegExecPushString) xmlRegExecPushString__internal_alias __attribute((visibility("hidden"))); +#define xmlRegExecPushString xmlRegExecPushString__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlRegExecPushString2 +extern __typeof (xmlRegExecPushString2) xmlRegExecPushString2 __attribute((alias("xmlRegExecPushString2__internal_alias"))); +#else +#ifndef xmlRegExecPushString2 +extern __typeof (xmlRegExecPushString2) xmlRegExecPushString2__internal_alias __attribute((visibility("hidden"))); +#define xmlRegExecPushString2 xmlRegExecPushString2__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlRegFreeExecCtxt +extern __typeof (xmlRegFreeExecCtxt) xmlRegFreeExecCtxt __attribute((alias("xmlRegFreeExecCtxt__internal_alias"))); +#else +#ifndef xmlRegFreeExecCtxt +extern __typeof (xmlRegFreeExecCtxt) xmlRegFreeExecCtxt__internal_alias __attribute((visibility("hidden"))); +#define xmlRegFreeExecCtxt xmlRegFreeExecCtxt__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlRegFreeRegexp +extern __typeof (xmlRegFreeRegexp) xmlRegFreeRegexp __attribute((alias("xmlRegFreeRegexp__internal_alias"))); +#else +#ifndef xmlRegFreeRegexp +extern __typeof (xmlRegFreeRegexp) xmlRegFreeRegexp__internal_alias __attribute((visibility("hidden"))); +#define xmlRegFreeRegexp xmlRegFreeRegexp__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlRegNewExecCtxt +extern __typeof (xmlRegNewExecCtxt) xmlRegNewExecCtxt __attribute((alias("xmlRegNewExecCtxt__internal_alias"))); +#else +#ifndef xmlRegNewExecCtxt +extern __typeof (xmlRegNewExecCtxt) xmlRegNewExecCtxt__internal_alias __attribute((visibility("hidden"))); +#define xmlRegNewExecCtxt xmlRegNewExecCtxt__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlRegexpCompile +extern __typeof (xmlRegexpCompile) xmlRegexpCompile __attribute((alias("xmlRegexpCompile__internal_alias"))); +#else +#ifndef xmlRegexpCompile +extern __typeof (xmlRegexpCompile) xmlRegexpCompile__internal_alias __attribute((visibility("hidden"))); +#define xmlRegexpCompile xmlRegexpCompile__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlRegexpExec +extern __typeof (xmlRegexpExec) xmlRegexpExec __attribute((alias("xmlRegexpExec__internal_alias"))); +#else +#ifndef xmlRegexpExec +extern __typeof (xmlRegexpExec) xmlRegexpExec__internal_alias __attribute((visibility("hidden"))); +#define xmlRegexpExec xmlRegexpExec__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlRegexpIsDeterminist +extern __typeof (xmlRegexpIsDeterminist) xmlRegexpIsDeterminist __attribute((alias("xmlRegexpIsDeterminist__internal_alias"))); +#else +#ifndef xmlRegexpIsDeterminist +extern __typeof (xmlRegexpIsDeterminist) xmlRegexpIsDeterminist__internal_alias __attribute((visibility("hidden"))); +#define xmlRegexpIsDeterminist xmlRegexpIsDeterminist__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_REGEXP_ENABLED) +#ifdef bottom_xmlregexp +#undef xmlRegexpPrint +extern __typeof (xmlRegexpPrint) xmlRegexpPrint __attribute((alias("xmlRegexpPrint__internal_alias"))); +#else +#ifndef xmlRegexpPrint +extern __typeof (xmlRegexpPrint) xmlRegexpPrint__internal_alias __attribute((visibility("hidden"))); +#define xmlRegexpPrint xmlRegexpPrint__internal_alias +#endif +#endif +#endif + +#ifdef bottom_encoding +#undef xmlRegisterCharEncodingHandler +extern __typeof (xmlRegisterCharEncodingHandler) xmlRegisterCharEncodingHandler __attribute((alias("xmlRegisterCharEncodingHandler__internal_alias"))); +#else +#ifndef xmlRegisterCharEncodingHandler +extern __typeof (xmlRegisterCharEncodingHandler) xmlRegisterCharEncodingHandler__internal_alias __attribute((visibility("hidden"))); +#define xmlRegisterCharEncodingHandler xmlRegisterCharEncodingHandler__internal_alias +#endif +#endif + +#ifdef bottom_xmlIO +#undef xmlRegisterDefaultInputCallbacks +extern __typeof (xmlRegisterDefaultInputCallbacks) xmlRegisterDefaultInputCallbacks __attribute((alias("xmlRegisterDefaultInputCallbacks__internal_alias"))); +#else +#ifndef xmlRegisterDefaultInputCallbacks +extern __typeof (xmlRegisterDefaultInputCallbacks) xmlRegisterDefaultInputCallbacks__internal_alias __attribute((visibility("hidden"))); +#define xmlRegisterDefaultInputCallbacks xmlRegisterDefaultInputCallbacks__internal_alias +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_xmlIO +#undef xmlRegisterDefaultOutputCallbacks +extern __typeof (xmlRegisterDefaultOutputCallbacks) xmlRegisterDefaultOutputCallbacks __attribute((alias("xmlRegisterDefaultOutputCallbacks__internal_alias"))); +#else +#ifndef xmlRegisterDefaultOutputCallbacks +extern __typeof (xmlRegisterDefaultOutputCallbacks) xmlRegisterDefaultOutputCallbacks__internal_alias __attribute((visibility("hidden"))); +#define xmlRegisterDefaultOutputCallbacks xmlRegisterDefaultOutputCallbacks__internal_alias +#endif +#endif +#endif + +#ifdef bottom_xmlIO +#undef xmlRegisterInputCallbacks +extern __typeof (xmlRegisterInputCallbacks) xmlRegisterInputCallbacks __attribute((alias("xmlRegisterInputCallbacks__internal_alias"))); +#else +#ifndef xmlRegisterInputCallbacks +extern __typeof (xmlRegisterInputCallbacks) xmlRegisterInputCallbacks__internal_alias __attribute((visibility("hidden"))); +#define xmlRegisterInputCallbacks xmlRegisterInputCallbacks__internal_alias +#endif +#endif + +#ifdef bottom_globals +#undef xmlRegisterNodeDefault +extern __typeof (xmlRegisterNodeDefault) xmlRegisterNodeDefault __attribute((alias("xmlRegisterNodeDefault__internal_alias"))); +#else +#ifndef xmlRegisterNodeDefault +extern __typeof (xmlRegisterNodeDefault) xmlRegisterNodeDefault__internal_alias __attribute((visibility("hidden"))); +#define xmlRegisterNodeDefault xmlRegisterNodeDefault__internal_alias +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_xmlIO +#undef xmlRegisterOutputCallbacks +extern __typeof (xmlRegisterOutputCallbacks) xmlRegisterOutputCallbacks __attribute((alias("xmlRegisterOutputCallbacks__internal_alias"))); +#else +#ifndef xmlRegisterOutputCallbacks +extern __typeof (xmlRegisterOutputCallbacks) xmlRegisterOutputCallbacks__internal_alias __attribute((visibility("hidden"))); +#define xmlRegisterOutputCallbacks xmlRegisterOutputCallbacks__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_relaxng +#undef xmlRelaxNGCleanupTypes +extern __typeof (xmlRelaxNGCleanupTypes) xmlRelaxNGCleanupTypes __attribute((alias("xmlRelaxNGCleanupTypes__internal_alias"))); +#else +#ifndef xmlRelaxNGCleanupTypes +extern __typeof (xmlRelaxNGCleanupTypes) xmlRelaxNGCleanupTypes__internal_alias __attribute((visibility("hidden"))); +#define xmlRelaxNGCleanupTypes xmlRelaxNGCleanupTypes__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) && defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_relaxng +#undef xmlRelaxNGDump +extern __typeof (xmlRelaxNGDump) xmlRelaxNGDump __attribute((alias("xmlRelaxNGDump__internal_alias"))); +#else +#ifndef xmlRelaxNGDump +extern __typeof (xmlRelaxNGDump) xmlRelaxNGDump__internal_alias __attribute((visibility("hidden"))); +#define xmlRelaxNGDump xmlRelaxNGDump__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) && defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_relaxng +#undef xmlRelaxNGDumpTree +extern __typeof (xmlRelaxNGDumpTree) xmlRelaxNGDumpTree __attribute((alias("xmlRelaxNGDumpTree__internal_alias"))); +#else +#ifndef xmlRelaxNGDumpTree +extern __typeof (xmlRelaxNGDumpTree) xmlRelaxNGDumpTree__internal_alias __attribute((visibility("hidden"))); +#define xmlRelaxNGDumpTree xmlRelaxNGDumpTree__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_relaxng +#undef xmlRelaxNGFree +extern __typeof (xmlRelaxNGFree) xmlRelaxNGFree __attribute((alias("xmlRelaxNGFree__internal_alias"))); +#else +#ifndef xmlRelaxNGFree +extern __typeof (xmlRelaxNGFree) xmlRelaxNGFree__internal_alias __attribute((visibility("hidden"))); +#define xmlRelaxNGFree xmlRelaxNGFree__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_relaxng +#undef xmlRelaxNGFreeParserCtxt +extern __typeof (xmlRelaxNGFreeParserCtxt) xmlRelaxNGFreeParserCtxt __attribute((alias("xmlRelaxNGFreeParserCtxt__internal_alias"))); +#else +#ifndef xmlRelaxNGFreeParserCtxt +extern __typeof (xmlRelaxNGFreeParserCtxt) xmlRelaxNGFreeParserCtxt__internal_alias __attribute((visibility("hidden"))); +#define xmlRelaxNGFreeParserCtxt xmlRelaxNGFreeParserCtxt__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_relaxng +#undef xmlRelaxNGFreeValidCtxt +extern __typeof (xmlRelaxNGFreeValidCtxt) xmlRelaxNGFreeValidCtxt __attribute((alias("xmlRelaxNGFreeValidCtxt__internal_alias"))); +#else +#ifndef xmlRelaxNGFreeValidCtxt +extern __typeof (xmlRelaxNGFreeValidCtxt) xmlRelaxNGFreeValidCtxt__internal_alias __attribute((visibility("hidden"))); +#define xmlRelaxNGFreeValidCtxt xmlRelaxNGFreeValidCtxt__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_relaxng +#undef xmlRelaxNGGetParserErrors +extern __typeof (xmlRelaxNGGetParserErrors) xmlRelaxNGGetParserErrors __attribute((alias("xmlRelaxNGGetParserErrors__internal_alias"))); +#else +#ifndef xmlRelaxNGGetParserErrors +extern __typeof (xmlRelaxNGGetParserErrors) xmlRelaxNGGetParserErrors__internal_alias __attribute((visibility("hidden"))); +#define xmlRelaxNGGetParserErrors xmlRelaxNGGetParserErrors__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_relaxng +#undef xmlRelaxNGGetValidErrors +extern __typeof (xmlRelaxNGGetValidErrors) xmlRelaxNGGetValidErrors __attribute((alias("xmlRelaxNGGetValidErrors__internal_alias"))); +#else +#ifndef xmlRelaxNGGetValidErrors +extern __typeof (xmlRelaxNGGetValidErrors) xmlRelaxNGGetValidErrors__internal_alias __attribute((visibility("hidden"))); +#define xmlRelaxNGGetValidErrors xmlRelaxNGGetValidErrors__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_relaxng +#undef xmlRelaxNGInitTypes +extern __typeof (xmlRelaxNGInitTypes) xmlRelaxNGInitTypes __attribute((alias("xmlRelaxNGInitTypes__internal_alias"))); +#else +#ifndef xmlRelaxNGInitTypes +extern __typeof (xmlRelaxNGInitTypes) xmlRelaxNGInitTypes__internal_alias __attribute((visibility("hidden"))); +#define xmlRelaxNGInitTypes xmlRelaxNGInitTypes__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_relaxng +#undef xmlRelaxNGNewDocParserCtxt +extern __typeof (xmlRelaxNGNewDocParserCtxt) xmlRelaxNGNewDocParserCtxt __attribute((alias("xmlRelaxNGNewDocParserCtxt__internal_alias"))); +#else +#ifndef xmlRelaxNGNewDocParserCtxt +extern __typeof (xmlRelaxNGNewDocParserCtxt) xmlRelaxNGNewDocParserCtxt__internal_alias __attribute((visibility("hidden"))); +#define xmlRelaxNGNewDocParserCtxt xmlRelaxNGNewDocParserCtxt__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_relaxng +#undef xmlRelaxNGNewMemParserCtxt +extern __typeof (xmlRelaxNGNewMemParserCtxt) xmlRelaxNGNewMemParserCtxt __attribute((alias("xmlRelaxNGNewMemParserCtxt__internal_alias"))); +#else +#ifndef xmlRelaxNGNewMemParserCtxt +extern __typeof (xmlRelaxNGNewMemParserCtxt) xmlRelaxNGNewMemParserCtxt__internal_alias __attribute((visibility("hidden"))); +#define xmlRelaxNGNewMemParserCtxt xmlRelaxNGNewMemParserCtxt__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_relaxng +#undef xmlRelaxNGNewParserCtxt +extern __typeof (xmlRelaxNGNewParserCtxt) xmlRelaxNGNewParserCtxt __attribute((alias("xmlRelaxNGNewParserCtxt__internal_alias"))); +#else +#ifndef xmlRelaxNGNewParserCtxt +extern __typeof (xmlRelaxNGNewParserCtxt) xmlRelaxNGNewParserCtxt__internal_alias __attribute((visibility("hidden"))); +#define xmlRelaxNGNewParserCtxt xmlRelaxNGNewParserCtxt__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_relaxng +#undef xmlRelaxNGNewValidCtxt +extern __typeof (xmlRelaxNGNewValidCtxt) xmlRelaxNGNewValidCtxt __attribute((alias("xmlRelaxNGNewValidCtxt__internal_alias"))); +#else +#ifndef xmlRelaxNGNewValidCtxt +extern __typeof (xmlRelaxNGNewValidCtxt) xmlRelaxNGNewValidCtxt__internal_alias __attribute((visibility("hidden"))); +#define xmlRelaxNGNewValidCtxt xmlRelaxNGNewValidCtxt__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_relaxng +#undef xmlRelaxNGParse +extern __typeof (xmlRelaxNGParse) xmlRelaxNGParse __attribute((alias("xmlRelaxNGParse__internal_alias"))); +#else +#ifndef xmlRelaxNGParse +extern __typeof (xmlRelaxNGParse) xmlRelaxNGParse__internal_alias __attribute((visibility("hidden"))); +#define xmlRelaxNGParse xmlRelaxNGParse__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_relaxng +#undef xmlRelaxNGSetParserErrors +extern __typeof (xmlRelaxNGSetParserErrors) xmlRelaxNGSetParserErrors __attribute((alias("xmlRelaxNGSetParserErrors__internal_alias"))); +#else +#ifndef xmlRelaxNGSetParserErrors +extern __typeof (xmlRelaxNGSetParserErrors) xmlRelaxNGSetParserErrors__internal_alias __attribute((visibility("hidden"))); +#define xmlRelaxNGSetParserErrors xmlRelaxNGSetParserErrors__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_relaxng +#undef xmlRelaxNGSetParserStructuredErrors +extern __typeof (xmlRelaxNGSetParserStructuredErrors) xmlRelaxNGSetParserStructuredErrors __attribute((alias("xmlRelaxNGSetParserStructuredErrors__internal_alias"))); +#else +#ifndef xmlRelaxNGSetParserStructuredErrors +extern __typeof (xmlRelaxNGSetParserStructuredErrors) xmlRelaxNGSetParserStructuredErrors__internal_alias __attribute((visibility("hidden"))); +#define xmlRelaxNGSetParserStructuredErrors xmlRelaxNGSetParserStructuredErrors__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_relaxng +#undef xmlRelaxNGSetValidErrors +extern __typeof (xmlRelaxNGSetValidErrors) xmlRelaxNGSetValidErrors __attribute((alias("xmlRelaxNGSetValidErrors__internal_alias"))); +#else +#ifndef xmlRelaxNGSetValidErrors +extern __typeof (xmlRelaxNGSetValidErrors) xmlRelaxNGSetValidErrors__internal_alias __attribute((visibility("hidden"))); +#define xmlRelaxNGSetValidErrors xmlRelaxNGSetValidErrors__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_relaxng +#undef xmlRelaxNGSetValidStructuredErrors +extern __typeof (xmlRelaxNGSetValidStructuredErrors) xmlRelaxNGSetValidStructuredErrors __attribute((alias("xmlRelaxNGSetValidStructuredErrors__internal_alias"))); +#else +#ifndef xmlRelaxNGSetValidStructuredErrors +extern __typeof (xmlRelaxNGSetValidStructuredErrors) xmlRelaxNGSetValidStructuredErrors__internal_alias __attribute((visibility("hidden"))); +#define xmlRelaxNGSetValidStructuredErrors xmlRelaxNGSetValidStructuredErrors__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_relaxng +#undef xmlRelaxNGValidateDoc +extern __typeof (xmlRelaxNGValidateDoc) xmlRelaxNGValidateDoc __attribute((alias("xmlRelaxNGValidateDoc__internal_alias"))); +#else +#ifndef xmlRelaxNGValidateDoc +extern __typeof (xmlRelaxNGValidateDoc) xmlRelaxNGValidateDoc__internal_alias __attribute((visibility("hidden"))); +#define xmlRelaxNGValidateDoc xmlRelaxNGValidateDoc__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_relaxng +#undef xmlRelaxNGValidateFullElement +extern __typeof (xmlRelaxNGValidateFullElement) xmlRelaxNGValidateFullElement __attribute((alias("xmlRelaxNGValidateFullElement__internal_alias"))); +#else +#ifndef xmlRelaxNGValidateFullElement +extern __typeof (xmlRelaxNGValidateFullElement) xmlRelaxNGValidateFullElement__internal_alias __attribute((visibility("hidden"))); +#define xmlRelaxNGValidateFullElement xmlRelaxNGValidateFullElement__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_relaxng +#undef xmlRelaxNGValidatePopElement +extern __typeof (xmlRelaxNGValidatePopElement) xmlRelaxNGValidatePopElement __attribute((alias("xmlRelaxNGValidatePopElement__internal_alias"))); +#else +#ifndef xmlRelaxNGValidatePopElement +extern __typeof (xmlRelaxNGValidatePopElement) xmlRelaxNGValidatePopElement__internal_alias __attribute((visibility("hidden"))); +#define xmlRelaxNGValidatePopElement xmlRelaxNGValidatePopElement__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_relaxng +#undef xmlRelaxNGValidatePushCData +extern __typeof (xmlRelaxNGValidatePushCData) xmlRelaxNGValidatePushCData __attribute((alias("xmlRelaxNGValidatePushCData__internal_alias"))); +#else +#ifndef xmlRelaxNGValidatePushCData +extern __typeof (xmlRelaxNGValidatePushCData) xmlRelaxNGValidatePushCData__internal_alias __attribute((visibility("hidden"))); +#define xmlRelaxNGValidatePushCData xmlRelaxNGValidatePushCData__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_relaxng +#undef xmlRelaxNGValidatePushElement +extern __typeof (xmlRelaxNGValidatePushElement) xmlRelaxNGValidatePushElement __attribute((alias("xmlRelaxNGValidatePushElement__internal_alias"))); +#else +#ifndef xmlRelaxNGValidatePushElement +extern __typeof (xmlRelaxNGValidatePushElement) xmlRelaxNGValidatePushElement__internal_alias __attribute((visibility("hidden"))); +#define xmlRelaxNGValidatePushElement xmlRelaxNGValidatePushElement__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_relaxng +#undef xmlRelaxParserSetFlag +extern __typeof (xmlRelaxParserSetFlag) xmlRelaxParserSetFlag __attribute((alias("xmlRelaxParserSetFlag__internal_alias"))); +#else +#ifndef xmlRelaxParserSetFlag +extern __typeof (xmlRelaxParserSetFlag) xmlRelaxParserSetFlag__internal_alias __attribute((visibility("hidden"))); +#define xmlRelaxParserSetFlag xmlRelaxParserSetFlag__internal_alias +#endif +#endif +#endif + +#ifdef bottom_valid +#undef xmlRemoveID +extern __typeof (xmlRemoveID) xmlRemoveID __attribute((alias("xmlRemoveID__internal_alias"))); +#else +#ifndef xmlRemoveID +extern __typeof (xmlRemoveID) xmlRemoveID__internal_alias __attribute((visibility("hidden"))); +#define xmlRemoveID xmlRemoveID__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlRemoveProp +extern __typeof (xmlRemoveProp) xmlRemoveProp __attribute((alias("xmlRemoveProp__internal_alias"))); +#else +#ifndef xmlRemoveProp +extern __typeof (xmlRemoveProp) xmlRemoveProp__internal_alias __attribute((visibility("hidden"))); +#define xmlRemoveProp xmlRemoveProp__internal_alias +#endif +#endif + +#ifdef bottom_valid +#undef xmlRemoveRef +extern __typeof (xmlRemoveRef) xmlRemoveRef __attribute((alias("xmlRemoveRef__internal_alias"))); +#else +#ifndef xmlRemoveRef +extern __typeof (xmlRemoveRef) xmlRemoveRef__internal_alias __attribute((visibility("hidden"))); +#define xmlRemoveRef xmlRemoveRef__internal_alias +#endif +#endif + +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_tree +#undef xmlReplaceNode +extern __typeof (xmlReplaceNode) xmlReplaceNode __attribute((alias("xmlReplaceNode__internal_alias"))); +#else +#ifndef xmlReplaceNode +extern __typeof (xmlReplaceNode) xmlReplaceNode__internal_alias __attribute((visibility("hidden"))); +#define xmlReplaceNode xmlReplaceNode__internal_alias +#endif +#endif +#endif + +#ifdef bottom_error +#undef xmlResetError +extern __typeof (xmlResetError) xmlResetError __attribute((alias("xmlResetError__internal_alias"))); +#else +#ifndef xmlResetError +extern __typeof (xmlResetError) xmlResetError__internal_alias __attribute((visibility("hidden"))); +#define xmlResetError xmlResetError__internal_alias +#endif +#endif + +#ifdef bottom_error +#undef xmlResetLastError +extern __typeof (xmlResetLastError) xmlResetLastError __attribute((alias("xmlResetLastError__internal_alias"))); +#else +#ifndef xmlResetLastError +extern __typeof (xmlResetLastError) xmlResetLastError__internal_alias __attribute((visibility("hidden"))); +#define xmlResetLastError xmlResetLastError__internal_alias +#endif +#endif + +#ifdef bottom_SAX2 +#undef xmlSAX2AttributeDecl +extern __typeof (xmlSAX2AttributeDecl) xmlSAX2AttributeDecl __attribute((alias("xmlSAX2AttributeDecl__internal_alias"))); +#else +#ifndef xmlSAX2AttributeDecl +extern __typeof (xmlSAX2AttributeDecl) xmlSAX2AttributeDecl__internal_alias __attribute((visibility("hidden"))); +#define xmlSAX2AttributeDecl xmlSAX2AttributeDecl__internal_alias +#endif +#endif + +#ifdef bottom_SAX2 +#undef xmlSAX2CDataBlock +extern __typeof (xmlSAX2CDataBlock) xmlSAX2CDataBlock __attribute((alias("xmlSAX2CDataBlock__internal_alias"))); +#else +#ifndef xmlSAX2CDataBlock +extern __typeof (xmlSAX2CDataBlock) xmlSAX2CDataBlock__internal_alias __attribute((visibility("hidden"))); +#define xmlSAX2CDataBlock xmlSAX2CDataBlock__internal_alias +#endif +#endif + +#ifdef bottom_SAX2 +#undef xmlSAX2Characters +extern __typeof (xmlSAX2Characters) xmlSAX2Characters __attribute((alias("xmlSAX2Characters__internal_alias"))); +#else +#ifndef xmlSAX2Characters +extern __typeof (xmlSAX2Characters) xmlSAX2Characters__internal_alias __attribute((visibility("hidden"))); +#define xmlSAX2Characters xmlSAX2Characters__internal_alias +#endif +#endif + +#ifdef bottom_SAX2 +#undef xmlSAX2Comment +extern __typeof (xmlSAX2Comment) xmlSAX2Comment __attribute((alias("xmlSAX2Comment__internal_alias"))); +#else +#ifndef xmlSAX2Comment +extern __typeof (xmlSAX2Comment) xmlSAX2Comment__internal_alias __attribute((visibility("hidden"))); +#define xmlSAX2Comment xmlSAX2Comment__internal_alias +#endif +#endif + +#ifdef bottom_SAX2 +#undef xmlSAX2ElementDecl +extern __typeof (xmlSAX2ElementDecl) xmlSAX2ElementDecl __attribute((alias("xmlSAX2ElementDecl__internal_alias"))); +#else +#ifndef xmlSAX2ElementDecl +extern __typeof (xmlSAX2ElementDecl) xmlSAX2ElementDecl__internal_alias __attribute((visibility("hidden"))); +#define xmlSAX2ElementDecl xmlSAX2ElementDecl__internal_alias +#endif +#endif + +#ifdef bottom_SAX2 +#undef xmlSAX2EndDocument +extern __typeof (xmlSAX2EndDocument) xmlSAX2EndDocument __attribute((alias("xmlSAX2EndDocument__internal_alias"))); +#else +#ifndef xmlSAX2EndDocument +extern __typeof (xmlSAX2EndDocument) xmlSAX2EndDocument__internal_alias __attribute((visibility("hidden"))); +#define xmlSAX2EndDocument xmlSAX2EndDocument__internal_alias +#endif +#endif + +#if defined(LIBXML_SAX1_ENABLED) || defined(LIBXML_WRITER_ENABLED) || defined(LIBXML_DOCB_ENABLED) +#ifdef bottom_SAX2 +#undef xmlSAX2EndElement +extern __typeof (xmlSAX2EndElement) xmlSAX2EndElement __attribute((alias("xmlSAX2EndElement__internal_alias"))); +#else +#ifndef xmlSAX2EndElement +extern __typeof (xmlSAX2EndElement) xmlSAX2EndElement__internal_alias __attribute((visibility("hidden"))); +#define xmlSAX2EndElement xmlSAX2EndElement__internal_alias +#endif +#endif +#endif + +#ifdef bottom_SAX2 +#undef xmlSAX2EndElementNs +extern __typeof (xmlSAX2EndElementNs) xmlSAX2EndElementNs __attribute((alias("xmlSAX2EndElementNs__internal_alias"))); +#else +#ifndef xmlSAX2EndElementNs +extern __typeof (xmlSAX2EndElementNs) xmlSAX2EndElementNs__internal_alias __attribute((visibility("hidden"))); +#define xmlSAX2EndElementNs xmlSAX2EndElementNs__internal_alias +#endif +#endif + +#ifdef bottom_SAX2 +#undef xmlSAX2EntityDecl +extern __typeof (xmlSAX2EntityDecl) xmlSAX2EntityDecl __attribute((alias("xmlSAX2EntityDecl__internal_alias"))); +#else +#ifndef xmlSAX2EntityDecl +extern __typeof (xmlSAX2EntityDecl) xmlSAX2EntityDecl__internal_alias __attribute((visibility("hidden"))); +#define xmlSAX2EntityDecl xmlSAX2EntityDecl__internal_alias +#endif +#endif + +#ifdef bottom_SAX2 +#undef xmlSAX2ExternalSubset +extern __typeof (xmlSAX2ExternalSubset) xmlSAX2ExternalSubset __attribute((alias("xmlSAX2ExternalSubset__internal_alias"))); +#else +#ifndef xmlSAX2ExternalSubset +extern __typeof (xmlSAX2ExternalSubset) xmlSAX2ExternalSubset__internal_alias __attribute((visibility("hidden"))); +#define xmlSAX2ExternalSubset xmlSAX2ExternalSubset__internal_alias +#endif +#endif + +#ifdef bottom_SAX2 +#undef xmlSAX2GetColumnNumber +extern __typeof (xmlSAX2GetColumnNumber) xmlSAX2GetColumnNumber __attribute((alias("xmlSAX2GetColumnNumber__internal_alias"))); +#else +#ifndef xmlSAX2GetColumnNumber +extern __typeof (xmlSAX2GetColumnNumber) xmlSAX2GetColumnNumber__internal_alias __attribute((visibility("hidden"))); +#define xmlSAX2GetColumnNumber xmlSAX2GetColumnNumber__internal_alias +#endif +#endif + +#ifdef bottom_SAX2 +#undef xmlSAX2GetEntity +extern __typeof (xmlSAX2GetEntity) xmlSAX2GetEntity __attribute((alias("xmlSAX2GetEntity__internal_alias"))); +#else +#ifndef xmlSAX2GetEntity +extern __typeof (xmlSAX2GetEntity) xmlSAX2GetEntity__internal_alias __attribute((visibility("hidden"))); +#define xmlSAX2GetEntity xmlSAX2GetEntity__internal_alias +#endif +#endif + +#ifdef bottom_SAX2 +#undef xmlSAX2GetLineNumber +extern __typeof (xmlSAX2GetLineNumber) xmlSAX2GetLineNumber __attribute((alias("xmlSAX2GetLineNumber__internal_alias"))); +#else +#ifndef xmlSAX2GetLineNumber +extern __typeof (xmlSAX2GetLineNumber) xmlSAX2GetLineNumber__internal_alias __attribute((visibility("hidden"))); +#define xmlSAX2GetLineNumber xmlSAX2GetLineNumber__internal_alias +#endif +#endif + +#ifdef bottom_SAX2 +#undef xmlSAX2GetParameterEntity +extern __typeof (xmlSAX2GetParameterEntity) xmlSAX2GetParameterEntity __attribute((alias("xmlSAX2GetParameterEntity__internal_alias"))); +#else +#ifndef xmlSAX2GetParameterEntity +extern __typeof (xmlSAX2GetParameterEntity) xmlSAX2GetParameterEntity__internal_alias __attribute((visibility("hidden"))); +#define xmlSAX2GetParameterEntity xmlSAX2GetParameterEntity__internal_alias +#endif +#endif + +#ifdef bottom_SAX2 +#undef xmlSAX2GetPublicId +extern __typeof (xmlSAX2GetPublicId) xmlSAX2GetPublicId __attribute((alias("xmlSAX2GetPublicId__internal_alias"))); +#else +#ifndef xmlSAX2GetPublicId +extern __typeof (xmlSAX2GetPublicId) xmlSAX2GetPublicId__internal_alias __attribute((visibility("hidden"))); +#define xmlSAX2GetPublicId xmlSAX2GetPublicId__internal_alias +#endif +#endif + +#ifdef bottom_SAX2 +#undef xmlSAX2GetSystemId +extern __typeof (xmlSAX2GetSystemId) xmlSAX2GetSystemId __attribute((alias("xmlSAX2GetSystemId__internal_alias"))); +#else +#ifndef xmlSAX2GetSystemId +extern __typeof (xmlSAX2GetSystemId) xmlSAX2GetSystemId__internal_alias __attribute((visibility("hidden"))); +#define xmlSAX2GetSystemId xmlSAX2GetSystemId__internal_alias +#endif +#endif + +#ifdef bottom_SAX2 +#undef xmlSAX2HasExternalSubset +extern __typeof (xmlSAX2HasExternalSubset) xmlSAX2HasExternalSubset __attribute((alias("xmlSAX2HasExternalSubset__internal_alias"))); +#else +#ifndef xmlSAX2HasExternalSubset +extern __typeof (xmlSAX2HasExternalSubset) xmlSAX2HasExternalSubset__internal_alias __attribute((visibility("hidden"))); +#define xmlSAX2HasExternalSubset xmlSAX2HasExternalSubset__internal_alias +#endif +#endif + +#ifdef bottom_SAX2 +#undef xmlSAX2HasInternalSubset +extern __typeof (xmlSAX2HasInternalSubset) xmlSAX2HasInternalSubset __attribute((alias("xmlSAX2HasInternalSubset__internal_alias"))); +#else +#ifndef xmlSAX2HasInternalSubset +extern __typeof (xmlSAX2HasInternalSubset) xmlSAX2HasInternalSubset__internal_alias __attribute((visibility("hidden"))); +#define xmlSAX2HasInternalSubset xmlSAX2HasInternalSubset__internal_alias +#endif +#endif + +#ifdef bottom_SAX2 +#undef xmlSAX2IgnorableWhitespace +extern __typeof (xmlSAX2IgnorableWhitespace) xmlSAX2IgnorableWhitespace __attribute((alias("xmlSAX2IgnorableWhitespace__internal_alias"))); +#else +#ifndef xmlSAX2IgnorableWhitespace +extern __typeof (xmlSAX2IgnorableWhitespace) xmlSAX2IgnorableWhitespace__internal_alias __attribute((visibility("hidden"))); +#define xmlSAX2IgnorableWhitespace xmlSAX2IgnorableWhitespace__internal_alias +#endif +#endif + +#ifdef bottom_SAX2 +#undef xmlSAX2InitDefaultSAXHandler +extern __typeof (xmlSAX2InitDefaultSAXHandler) xmlSAX2InitDefaultSAXHandler __attribute((alias("xmlSAX2InitDefaultSAXHandler__internal_alias"))); +#else +#ifndef xmlSAX2InitDefaultSAXHandler +extern __typeof (xmlSAX2InitDefaultSAXHandler) xmlSAX2InitDefaultSAXHandler__internal_alias __attribute((visibility("hidden"))); +#define xmlSAX2InitDefaultSAXHandler xmlSAX2InitDefaultSAXHandler__internal_alias +#endif +#endif + +#if defined(LIBXML_DOCB_ENABLED) +#ifdef bottom_SAX2 +#undef xmlSAX2InitDocbDefaultSAXHandler +extern __typeof (xmlSAX2InitDocbDefaultSAXHandler) xmlSAX2InitDocbDefaultSAXHandler __attribute((alias("xmlSAX2InitDocbDefaultSAXHandler__internal_alias"))); +#else +#ifndef xmlSAX2InitDocbDefaultSAXHandler +extern __typeof (xmlSAX2InitDocbDefaultSAXHandler) xmlSAX2InitDocbDefaultSAXHandler__internal_alias __attribute((visibility("hidden"))); +#define xmlSAX2InitDocbDefaultSAXHandler xmlSAX2InitDocbDefaultSAXHandler__internal_alias +#endif +#endif +#endif + +#ifdef bottom_SAX2 +#undef xmlSAX2InternalSubset +extern __typeof (xmlSAX2InternalSubset) xmlSAX2InternalSubset __attribute((alias("xmlSAX2InternalSubset__internal_alias"))); +#else +#ifndef xmlSAX2InternalSubset +extern __typeof (xmlSAX2InternalSubset) xmlSAX2InternalSubset__internal_alias __attribute((visibility("hidden"))); +#define xmlSAX2InternalSubset xmlSAX2InternalSubset__internal_alias +#endif +#endif + +#ifdef bottom_SAX2 +#undef xmlSAX2IsStandalone +extern __typeof (xmlSAX2IsStandalone) xmlSAX2IsStandalone __attribute((alias("xmlSAX2IsStandalone__internal_alias"))); +#else +#ifndef xmlSAX2IsStandalone +extern __typeof (xmlSAX2IsStandalone) xmlSAX2IsStandalone__internal_alias __attribute((visibility("hidden"))); +#define xmlSAX2IsStandalone xmlSAX2IsStandalone__internal_alias +#endif +#endif + +#ifdef bottom_SAX2 +#undef xmlSAX2NotationDecl +extern __typeof (xmlSAX2NotationDecl) xmlSAX2NotationDecl __attribute((alias("xmlSAX2NotationDecl__internal_alias"))); +#else +#ifndef xmlSAX2NotationDecl +extern __typeof (xmlSAX2NotationDecl) xmlSAX2NotationDecl__internal_alias __attribute((visibility("hidden"))); +#define xmlSAX2NotationDecl xmlSAX2NotationDecl__internal_alias +#endif +#endif + +#ifdef bottom_SAX2 +#undef xmlSAX2ProcessingInstruction +extern __typeof (xmlSAX2ProcessingInstruction) xmlSAX2ProcessingInstruction __attribute((alias("xmlSAX2ProcessingInstruction__internal_alias"))); +#else +#ifndef xmlSAX2ProcessingInstruction +extern __typeof (xmlSAX2ProcessingInstruction) xmlSAX2ProcessingInstruction__internal_alias __attribute((visibility("hidden"))); +#define xmlSAX2ProcessingInstruction xmlSAX2ProcessingInstruction__internal_alias +#endif +#endif + +#ifdef bottom_SAX2 +#undef xmlSAX2Reference +extern __typeof (xmlSAX2Reference) xmlSAX2Reference __attribute((alias("xmlSAX2Reference__internal_alias"))); +#else +#ifndef xmlSAX2Reference +extern __typeof (xmlSAX2Reference) xmlSAX2Reference__internal_alias __attribute((visibility("hidden"))); +#define xmlSAX2Reference xmlSAX2Reference__internal_alias +#endif +#endif + +#ifdef bottom_SAX2 +#undef xmlSAX2ResolveEntity +extern __typeof (xmlSAX2ResolveEntity) xmlSAX2ResolveEntity __attribute((alias("xmlSAX2ResolveEntity__internal_alias"))); +#else +#ifndef xmlSAX2ResolveEntity +extern __typeof (xmlSAX2ResolveEntity) xmlSAX2ResolveEntity__internal_alias __attribute((visibility("hidden"))); +#define xmlSAX2ResolveEntity xmlSAX2ResolveEntity__internal_alias +#endif +#endif + +#ifdef bottom_SAX2 +#undef xmlSAX2SetDocumentLocator +extern __typeof (xmlSAX2SetDocumentLocator) xmlSAX2SetDocumentLocator __attribute((alias("xmlSAX2SetDocumentLocator__internal_alias"))); +#else +#ifndef xmlSAX2SetDocumentLocator +extern __typeof (xmlSAX2SetDocumentLocator) xmlSAX2SetDocumentLocator__internal_alias __attribute((visibility("hidden"))); +#define xmlSAX2SetDocumentLocator xmlSAX2SetDocumentLocator__internal_alias +#endif +#endif + +#ifdef bottom_SAX2 +#undef xmlSAX2StartDocument +extern __typeof (xmlSAX2StartDocument) xmlSAX2StartDocument __attribute((alias("xmlSAX2StartDocument__internal_alias"))); +#else +#ifndef xmlSAX2StartDocument +extern __typeof (xmlSAX2StartDocument) xmlSAX2StartDocument__internal_alias __attribute((visibility("hidden"))); +#define xmlSAX2StartDocument xmlSAX2StartDocument__internal_alias +#endif +#endif + +#if defined(LIBXML_SAX1_ENABLED) || defined(LIBXML_WRITER_ENABLED) || defined(LIBXML_DOCB_ENABLED) +#ifdef bottom_SAX2 +#undef xmlSAX2StartElement +extern __typeof (xmlSAX2StartElement) xmlSAX2StartElement __attribute((alias("xmlSAX2StartElement__internal_alias"))); +#else +#ifndef xmlSAX2StartElement +extern __typeof (xmlSAX2StartElement) xmlSAX2StartElement__internal_alias __attribute((visibility("hidden"))); +#define xmlSAX2StartElement xmlSAX2StartElement__internal_alias +#endif +#endif +#endif + +#ifdef bottom_SAX2 +#undef xmlSAX2StartElementNs +extern __typeof (xmlSAX2StartElementNs) xmlSAX2StartElementNs __attribute((alias("xmlSAX2StartElementNs__internal_alias"))); +#else +#ifndef xmlSAX2StartElementNs +extern __typeof (xmlSAX2StartElementNs) xmlSAX2StartElementNs__internal_alias __attribute((visibility("hidden"))); +#define xmlSAX2StartElementNs xmlSAX2StartElementNs__internal_alias +#endif +#endif + +#ifdef bottom_SAX2 +#undef xmlSAX2UnparsedEntityDecl +extern __typeof (xmlSAX2UnparsedEntityDecl) xmlSAX2UnparsedEntityDecl __attribute((alias("xmlSAX2UnparsedEntityDecl__internal_alias"))); +#else +#ifndef xmlSAX2UnparsedEntityDecl +extern __typeof (xmlSAX2UnparsedEntityDecl) xmlSAX2UnparsedEntityDecl__internal_alias __attribute((visibility("hidden"))); +#define xmlSAX2UnparsedEntityDecl xmlSAX2UnparsedEntityDecl__internal_alias +#endif +#endif + +#if defined(LIBXML_SAX1_ENABLED) +#ifdef bottom_SAX2 +#undef xmlSAXDefaultVersion +extern __typeof (xmlSAXDefaultVersion) xmlSAXDefaultVersion __attribute((alias("xmlSAXDefaultVersion__internal_alias"))); +#else +#ifndef xmlSAXDefaultVersion +extern __typeof (xmlSAXDefaultVersion) xmlSAXDefaultVersion__internal_alias __attribute((visibility("hidden"))); +#define xmlSAXDefaultVersion xmlSAXDefaultVersion__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_VALID_ENABLED) +#ifdef bottom_parser +#undef xmlSAXParseDTD +extern __typeof (xmlSAXParseDTD) xmlSAXParseDTD __attribute((alias("xmlSAXParseDTD__internal_alias"))); +#else +#ifndef xmlSAXParseDTD +extern __typeof (xmlSAXParseDTD) xmlSAXParseDTD__internal_alias __attribute((visibility("hidden"))); +#define xmlSAXParseDTD xmlSAXParseDTD__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SAX1_ENABLED) +#ifdef bottom_parser +#undef xmlSAXParseDoc +extern __typeof (xmlSAXParseDoc) xmlSAXParseDoc __attribute((alias("xmlSAXParseDoc__internal_alias"))); +#else +#ifndef xmlSAXParseDoc +extern __typeof (xmlSAXParseDoc) xmlSAXParseDoc__internal_alias __attribute((visibility("hidden"))); +#define xmlSAXParseDoc xmlSAXParseDoc__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SAX1_ENABLED) +#ifdef bottom_parser +#undef xmlSAXParseEntity +extern __typeof (xmlSAXParseEntity) xmlSAXParseEntity __attribute((alias("xmlSAXParseEntity__internal_alias"))); +#else +#ifndef xmlSAXParseEntity +extern __typeof (xmlSAXParseEntity) xmlSAXParseEntity__internal_alias __attribute((visibility("hidden"))); +#define xmlSAXParseEntity xmlSAXParseEntity__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SAX1_ENABLED) +#ifdef bottom_parser +#undef xmlSAXParseFile +extern __typeof (xmlSAXParseFile) xmlSAXParseFile __attribute((alias("xmlSAXParseFile__internal_alias"))); +#else +#ifndef xmlSAXParseFile +extern __typeof (xmlSAXParseFile) xmlSAXParseFile__internal_alias __attribute((visibility("hidden"))); +#define xmlSAXParseFile xmlSAXParseFile__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SAX1_ENABLED) +#ifdef bottom_parser +#undef xmlSAXParseFileWithData +extern __typeof (xmlSAXParseFileWithData) xmlSAXParseFileWithData __attribute((alias("xmlSAXParseFileWithData__internal_alias"))); +#else +#ifndef xmlSAXParseFileWithData +extern __typeof (xmlSAXParseFileWithData) xmlSAXParseFileWithData__internal_alias __attribute((visibility("hidden"))); +#define xmlSAXParseFileWithData xmlSAXParseFileWithData__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SAX1_ENABLED) +#ifdef bottom_parser +#undef xmlSAXParseMemory +extern __typeof (xmlSAXParseMemory) xmlSAXParseMemory __attribute((alias("xmlSAXParseMemory__internal_alias"))); +#else +#ifndef xmlSAXParseMemory +extern __typeof (xmlSAXParseMemory) xmlSAXParseMemory__internal_alias __attribute((visibility("hidden"))); +#define xmlSAXParseMemory xmlSAXParseMemory__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SAX1_ENABLED) +#ifdef bottom_parser +#undef xmlSAXParseMemoryWithData +extern __typeof (xmlSAXParseMemoryWithData) xmlSAXParseMemoryWithData __attribute((alias("xmlSAXParseMemoryWithData__internal_alias"))); +#else +#ifndef xmlSAXParseMemoryWithData +extern __typeof (xmlSAXParseMemoryWithData) xmlSAXParseMemoryWithData__internal_alias __attribute((visibility("hidden"))); +#define xmlSAXParseMemoryWithData xmlSAXParseMemoryWithData__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SAX1_ENABLED) +#ifdef bottom_parser +#undef xmlSAXUserParseFile +extern __typeof (xmlSAXUserParseFile) xmlSAXUserParseFile __attribute((alias("xmlSAXUserParseFile__internal_alias"))); +#else +#ifndef xmlSAXUserParseFile +extern __typeof (xmlSAXUserParseFile) xmlSAXUserParseFile__internal_alias __attribute((visibility("hidden"))); +#define xmlSAXUserParseFile xmlSAXUserParseFile__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SAX1_ENABLED) +#ifdef bottom_parser +#undef xmlSAXUserParseMemory +extern __typeof (xmlSAXUserParseMemory) xmlSAXUserParseMemory __attribute((alias("xmlSAXUserParseMemory__internal_alias"))); +#else +#ifndef xmlSAXUserParseMemory +extern __typeof (xmlSAXUserParseMemory) xmlSAXUserParseMemory__internal_alias __attribute((visibility("hidden"))); +#define xmlSAXUserParseMemory xmlSAXUserParseMemory__internal_alias +#endif +#endif +#endif + +#ifdef bottom_SAX2 +#undef xmlSAXVersion +extern __typeof (xmlSAXVersion) xmlSAXVersion __attribute((alias("xmlSAXVersion__internal_alias"))); +#else +#ifndef xmlSAXVersion +extern __typeof (xmlSAXVersion) xmlSAXVersion__internal_alias __attribute((visibility("hidden"))); +#define xmlSAXVersion xmlSAXVersion__internal_alias +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_xmlsave +#undef xmlSaveClose +extern __typeof (xmlSaveClose) xmlSaveClose __attribute((alias("xmlSaveClose__internal_alias"))); +#else +#ifndef xmlSaveClose +extern __typeof (xmlSaveClose) xmlSaveClose__internal_alias __attribute((visibility("hidden"))); +#define xmlSaveClose xmlSaveClose__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_xmlsave +#undef xmlSaveDoc +extern __typeof (xmlSaveDoc) xmlSaveDoc __attribute((alias("xmlSaveDoc__internal_alias"))); +#else +#ifndef xmlSaveDoc +extern __typeof (xmlSaveDoc) xmlSaveDoc__internal_alias __attribute((visibility("hidden"))); +#define xmlSaveDoc xmlSaveDoc__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_xmlsave +#undef xmlSaveFile +extern __typeof (xmlSaveFile) xmlSaveFile __attribute((alias("xmlSaveFile__internal_alias"))); +#else +#ifndef xmlSaveFile +extern __typeof (xmlSaveFile) xmlSaveFile__internal_alias __attribute((visibility("hidden"))); +#define xmlSaveFile xmlSaveFile__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_xmlsave +#undef xmlSaveFileEnc +extern __typeof (xmlSaveFileEnc) xmlSaveFileEnc __attribute((alias("xmlSaveFileEnc__internal_alias"))); +#else +#ifndef xmlSaveFileEnc +extern __typeof (xmlSaveFileEnc) xmlSaveFileEnc__internal_alias __attribute((visibility("hidden"))); +#define xmlSaveFileEnc xmlSaveFileEnc__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_xmlsave +#undef xmlSaveFileTo +extern __typeof (xmlSaveFileTo) xmlSaveFileTo __attribute((alias("xmlSaveFileTo__internal_alias"))); +#else +#ifndef xmlSaveFileTo +extern __typeof (xmlSaveFileTo) xmlSaveFileTo__internal_alias __attribute((visibility("hidden"))); +#define xmlSaveFileTo xmlSaveFileTo__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_xmlsave +#undef xmlSaveFlush +extern __typeof (xmlSaveFlush) xmlSaveFlush __attribute((alias("xmlSaveFlush__internal_alias"))); +#else +#ifndef xmlSaveFlush +extern __typeof (xmlSaveFlush) xmlSaveFlush__internal_alias __attribute((visibility("hidden"))); +#define xmlSaveFlush xmlSaveFlush__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_xmlsave +#undef xmlSaveFormatFile +extern __typeof (xmlSaveFormatFile) xmlSaveFormatFile __attribute((alias("xmlSaveFormatFile__internal_alias"))); +#else +#ifndef xmlSaveFormatFile +extern __typeof (xmlSaveFormatFile) xmlSaveFormatFile__internal_alias __attribute((visibility("hidden"))); +#define xmlSaveFormatFile xmlSaveFormatFile__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_xmlsave +#undef xmlSaveFormatFileEnc +extern __typeof (xmlSaveFormatFileEnc) xmlSaveFormatFileEnc __attribute((alias("xmlSaveFormatFileEnc__internal_alias"))); +#else +#ifndef xmlSaveFormatFileEnc +extern __typeof (xmlSaveFormatFileEnc) xmlSaveFormatFileEnc__internal_alias __attribute((visibility("hidden"))); +#define xmlSaveFormatFileEnc xmlSaveFormatFileEnc__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_xmlsave +#undef xmlSaveFormatFileTo +extern __typeof (xmlSaveFormatFileTo) xmlSaveFormatFileTo __attribute((alias("xmlSaveFormatFileTo__internal_alias"))); +#else +#ifndef xmlSaveFormatFileTo +extern __typeof (xmlSaveFormatFileTo) xmlSaveFormatFileTo__internal_alias __attribute((visibility("hidden"))); +#define xmlSaveFormatFileTo xmlSaveFormatFileTo__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_xmlsave +#undef xmlSaveSetAttrEscape +extern __typeof (xmlSaveSetAttrEscape) xmlSaveSetAttrEscape __attribute((alias("xmlSaveSetAttrEscape__internal_alias"))); +#else +#ifndef xmlSaveSetAttrEscape +extern __typeof (xmlSaveSetAttrEscape) xmlSaveSetAttrEscape__internal_alias __attribute((visibility("hidden"))); +#define xmlSaveSetAttrEscape xmlSaveSetAttrEscape__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_xmlsave +#undef xmlSaveSetEscape +extern __typeof (xmlSaveSetEscape) xmlSaveSetEscape __attribute((alias("xmlSaveSetEscape__internal_alias"))); +#else +#ifndef xmlSaveSetEscape +extern __typeof (xmlSaveSetEscape) xmlSaveSetEscape__internal_alias __attribute((visibility("hidden"))); +#define xmlSaveSetEscape xmlSaveSetEscape__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_xmlsave +#undef xmlSaveToBuffer +extern __typeof (xmlSaveToBuffer) xmlSaveToBuffer __attribute((alias("xmlSaveToBuffer__internal_alias"))); +#else +#ifndef xmlSaveToBuffer +extern __typeof (xmlSaveToBuffer) xmlSaveToBuffer__internal_alias __attribute((visibility("hidden"))); +#define xmlSaveToBuffer xmlSaveToBuffer__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_xmlsave +#undef xmlSaveToFd +extern __typeof (xmlSaveToFd) xmlSaveToFd __attribute((alias("xmlSaveToFd__internal_alias"))); +#else +#ifndef xmlSaveToFd +extern __typeof (xmlSaveToFd) xmlSaveToFd__internal_alias __attribute((visibility("hidden"))); +#define xmlSaveToFd xmlSaveToFd__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_xmlsave +#undef xmlSaveToFilename +extern __typeof (xmlSaveToFilename) xmlSaveToFilename __attribute((alias("xmlSaveToFilename__internal_alias"))); +#else +#ifndef xmlSaveToFilename +extern __typeof (xmlSaveToFilename) xmlSaveToFilename__internal_alias __attribute((visibility("hidden"))); +#define xmlSaveToFilename xmlSaveToFilename__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_xmlsave +#undef xmlSaveToIO +extern __typeof (xmlSaveToIO) xmlSaveToIO __attribute((alias("xmlSaveToIO__internal_alias"))); +#else +#ifndef xmlSaveToIO +extern __typeof (xmlSaveToIO) xmlSaveToIO__internal_alias __attribute((visibility("hidden"))); +#define xmlSaveToIO xmlSaveToIO__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_xmlsave +#undef xmlSaveTree +extern __typeof (xmlSaveTree) xmlSaveTree __attribute((alias("xmlSaveTree__internal_alias"))); +#else +#ifndef xmlSaveTree +extern __typeof (xmlSaveTree) xmlSaveTree__internal_alias __attribute((visibility("hidden"))); +#define xmlSaveTree xmlSaveTree__internal_alias +#endif +#endif +#endif + +#ifdef bottom_uri +#undef xmlSaveUri +extern __typeof (xmlSaveUri) xmlSaveUri __attribute((alias("xmlSaveUri__internal_alias"))); +#else +#ifndef xmlSaveUri +extern __typeof (xmlSaveUri) xmlSaveUri__internal_alias __attribute((visibility("hidden"))); +#define xmlSaveUri xmlSaveUri__internal_alias +#endif +#endif + +#if defined(LIBXML_LEGACY_ENABLED) +#ifdef bottom_legacy +#undef xmlScanName +extern __typeof (xmlScanName) xmlScanName __attribute((alias("xmlScanName__internal_alias"))); +#else +#ifndef xmlScanName +extern __typeof (xmlScanName) xmlScanName__internal_alias __attribute((visibility("hidden"))); +#define xmlScanName xmlScanName__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemas +#undef xmlSchemaCheckFacet +extern __typeof (xmlSchemaCheckFacet) xmlSchemaCheckFacet __attribute((alias("xmlSchemaCheckFacet__internal_alias"))); +#else +#ifndef xmlSchemaCheckFacet +extern __typeof (xmlSchemaCheckFacet) xmlSchemaCheckFacet__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaCheckFacet xmlSchemaCheckFacet__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemastypes +#undef xmlSchemaCleanupTypes +extern __typeof (xmlSchemaCleanupTypes) xmlSchemaCleanupTypes __attribute((alias("xmlSchemaCleanupTypes__internal_alias"))); +#else +#ifndef xmlSchemaCleanupTypes +extern __typeof (xmlSchemaCleanupTypes) xmlSchemaCleanupTypes__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaCleanupTypes xmlSchemaCleanupTypes__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemastypes +#undef xmlSchemaCollapseString +extern __typeof (xmlSchemaCollapseString) xmlSchemaCollapseString __attribute((alias("xmlSchemaCollapseString__internal_alias"))); +#else +#ifndef xmlSchemaCollapseString +extern __typeof (xmlSchemaCollapseString) xmlSchemaCollapseString__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaCollapseString xmlSchemaCollapseString__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemastypes +#undef xmlSchemaCompareValues +extern __typeof (xmlSchemaCompareValues) xmlSchemaCompareValues __attribute((alias("xmlSchemaCompareValues__internal_alias"))); +#else +#ifndef xmlSchemaCompareValues +extern __typeof (xmlSchemaCompareValues) xmlSchemaCompareValues__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaCompareValues xmlSchemaCompareValues__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemastypes +#undef xmlSchemaCompareValuesWhtsp +extern __typeof (xmlSchemaCompareValuesWhtsp) xmlSchemaCompareValuesWhtsp __attribute((alias("xmlSchemaCompareValuesWhtsp__internal_alias"))); +#else +#ifndef xmlSchemaCompareValuesWhtsp +extern __typeof (xmlSchemaCompareValuesWhtsp) xmlSchemaCompareValuesWhtsp__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaCompareValuesWhtsp xmlSchemaCompareValuesWhtsp__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemastypes +#undef xmlSchemaCopyValue +extern __typeof (xmlSchemaCopyValue) xmlSchemaCopyValue __attribute((alias("xmlSchemaCopyValue__internal_alias"))); +#else +#ifndef xmlSchemaCopyValue +extern __typeof (xmlSchemaCopyValue) xmlSchemaCopyValue__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaCopyValue xmlSchemaCopyValue__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) && defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_xmlschemas +#undef xmlSchemaDump +extern __typeof (xmlSchemaDump) xmlSchemaDump __attribute((alias("xmlSchemaDump__internal_alias"))); +#else +#ifndef xmlSchemaDump +extern __typeof (xmlSchemaDump) xmlSchemaDump__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaDump xmlSchemaDump__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemas +#undef xmlSchemaFree +extern __typeof (xmlSchemaFree) xmlSchemaFree __attribute((alias("xmlSchemaFree__internal_alias"))); +#else +#ifndef xmlSchemaFree +extern __typeof (xmlSchemaFree) xmlSchemaFree__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaFree xmlSchemaFree__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemas +#undef xmlSchemaFreeFacet +extern __typeof (xmlSchemaFreeFacet) xmlSchemaFreeFacet __attribute((alias("xmlSchemaFreeFacet__internal_alias"))); +#else +#ifndef xmlSchemaFreeFacet +extern __typeof (xmlSchemaFreeFacet) xmlSchemaFreeFacet__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaFreeFacet xmlSchemaFreeFacet__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemas +#undef xmlSchemaFreeParserCtxt +extern __typeof (xmlSchemaFreeParserCtxt) xmlSchemaFreeParserCtxt __attribute((alias("xmlSchemaFreeParserCtxt__internal_alias"))); +#else +#ifndef xmlSchemaFreeParserCtxt +extern __typeof (xmlSchemaFreeParserCtxt) xmlSchemaFreeParserCtxt__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaFreeParserCtxt xmlSchemaFreeParserCtxt__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemas +#undef xmlSchemaFreeType +extern __typeof (xmlSchemaFreeType) xmlSchemaFreeType __attribute((alias("xmlSchemaFreeType__internal_alias"))); +#else +#ifndef xmlSchemaFreeType +extern __typeof (xmlSchemaFreeType) xmlSchemaFreeType__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaFreeType xmlSchemaFreeType__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemas +#undef xmlSchemaFreeValidCtxt +extern __typeof (xmlSchemaFreeValidCtxt) xmlSchemaFreeValidCtxt __attribute((alias("xmlSchemaFreeValidCtxt__internal_alias"))); +#else +#ifndef xmlSchemaFreeValidCtxt +extern __typeof (xmlSchemaFreeValidCtxt) xmlSchemaFreeValidCtxt__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaFreeValidCtxt xmlSchemaFreeValidCtxt__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemastypes +#undef xmlSchemaFreeValue +extern __typeof (xmlSchemaFreeValue) xmlSchemaFreeValue __attribute((alias("xmlSchemaFreeValue__internal_alias"))); +#else +#ifndef xmlSchemaFreeValue +extern __typeof (xmlSchemaFreeValue) xmlSchemaFreeValue__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaFreeValue xmlSchemaFreeValue__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemas +#undef xmlSchemaFreeWildcard +extern __typeof (xmlSchemaFreeWildcard) xmlSchemaFreeWildcard __attribute((alias("xmlSchemaFreeWildcard__internal_alias"))); +#else +#ifndef xmlSchemaFreeWildcard +extern __typeof (xmlSchemaFreeWildcard) xmlSchemaFreeWildcard__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaFreeWildcard xmlSchemaFreeWildcard__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemastypes +#undef xmlSchemaGetBuiltInListSimpleTypeItemType +extern __typeof (xmlSchemaGetBuiltInListSimpleTypeItemType) xmlSchemaGetBuiltInListSimpleTypeItemType __attribute((alias("xmlSchemaGetBuiltInListSimpleTypeItemType__internal_alias"))); +#else +#ifndef xmlSchemaGetBuiltInListSimpleTypeItemType +extern __typeof (xmlSchemaGetBuiltInListSimpleTypeItemType) xmlSchemaGetBuiltInListSimpleTypeItemType__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaGetBuiltInListSimpleTypeItemType xmlSchemaGetBuiltInListSimpleTypeItemType__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemastypes +#undef xmlSchemaGetBuiltInType +extern __typeof (xmlSchemaGetBuiltInType) xmlSchemaGetBuiltInType __attribute((alias("xmlSchemaGetBuiltInType__internal_alias"))); +#else +#ifndef xmlSchemaGetBuiltInType +extern __typeof (xmlSchemaGetBuiltInType) xmlSchemaGetBuiltInType__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaGetBuiltInType xmlSchemaGetBuiltInType__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemastypes +#undef xmlSchemaGetCanonValue +extern __typeof (xmlSchemaGetCanonValue) xmlSchemaGetCanonValue __attribute((alias("xmlSchemaGetCanonValue__internal_alias"))); +#else +#ifndef xmlSchemaGetCanonValue +extern __typeof (xmlSchemaGetCanonValue) xmlSchemaGetCanonValue__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaGetCanonValue xmlSchemaGetCanonValue__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemastypes +#undef xmlSchemaGetCanonValueWhtsp +extern __typeof (xmlSchemaGetCanonValueWhtsp) xmlSchemaGetCanonValueWhtsp __attribute((alias("xmlSchemaGetCanonValueWhtsp__internal_alias"))); +#else +#ifndef xmlSchemaGetCanonValueWhtsp +extern __typeof (xmlSchemaGetCanonValueWhtsp) xmlSchemaGetCanonValueWhtsp__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaGetCanonValueWhtsp xmlSchemaGetCanonValueWhtsp__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemastypes +#undef xmlSchemaGetFacetValueAsULong +extern __typeof (xmlSchemaGetFacetValueAsULong) xmlSchemaGetFacetValueAsULong __attribute((alias("xmlSchemaGetFacetValueAsULong__internal_alias"))); +#else +#ifndef xmlSchemaGetFacetValueAsULong +extern __typeof (xmlSchemaGetFacetValueAsULong) xmlSchemaGetFacetValueAsULong__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaGetFacetValueAsULong xmlSchemaGetFacetValueAsULong__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemas +#undef xmlSchemaGetParserErrors +extern __typeof (xmlSchemaGetParserErrors) xmlSchemaGetParserErrors __attribute((alias("xmlSchemaGetParserErrors__internal_alias"))); +#else +#ifndef xmlSchemaGetParserErrors +extern __typeof (xmlSchemaGetParserErrors) xmlSchemaGetParserErrors__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaGetParserErrors xmlSchemaGetParserErrors__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemastypes +#undef xmlSchemaGetPredefinedType +extern __typeof (xmlSchemaGetPredefinedType) xmlSchemaGetPredefinedType __attribute((alias("xmlSchemaGetPredefinedType__internal_alias"))); +#else +#ifndef xmlSchemaGetPredefinedType +extern __typeof (xmlSchemaGetPredefinedType) xmlSchemaGetPredefinedType__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaGetPredefinedType xmlSchemaGetPredefinedType__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemastypes +#undef xmlSchemaGetValType +extern __typeof (xmlSchemaGetValType) xmlSchemaGetValType __attribute((alias("xmlSchemaGetValType__internal_alias"))); +#else +#ifndef xmlSchemaGetValType +extern __typeof (xmlSchemaGetValType) xmlSchemaGetValType__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaGetValType xmlSchemaGetValType__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemas +#undef xmlSchemaGetValidErrors +extern __typeof (xmlSchemaGetValidErrors) xmlSchemaGetValidErrors __attribute((alias("xmlSchemaGetValidErrors__internal_alias"))); +#else +#ifndef xmlSchemaGetValidErrors +extern __typeof (xmlSchemaGetValidErrors) xmlSchemaGetValidErrors__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaGetValidErrors xmlSchemaGetValidErrors__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemastypes +#undef xmlSchemaInitTypes +extern __typeof (xmlSchemaInitTypes) xmlSchemaInitTypes __attribute((alias("xmlSchemaInitTypes__internal_alias"))); +#else +#ifndef xmlSchemaInitTypes +extern __typeof (xmlSchemaInitTypes) xmlSchemaInitTypes__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaInitTypes xmlSchemaInitTypes__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemastypes +#undef xmlSchemaIsBuiltInTypeFacet +extern __typeof (xmlSchemaIsBuiltInTypeFacet) xmlSchemaIsBuiltInTypeFacet __attribute((alias("xmlSchemaIsBuiltInTypeFacet__internal_alias"))); +#else +#ifndef xmlSchemaIsBuiltInTypeFacet +extern __typeof (xmlSchemaIsBuiltInTypeFacet) xmlSchemaIsBuiltInTypeFacet__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaIsBuiltInTypeFacet xmlSchemaIsBuiltInTypeFacet__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemas +#undef xmlSchemaIsValid +extern __typeof (xmlSchemaIsValid) xmlSchemaIsValid __attribute((alias("xmlSchemaIsValid__internal_alias"))); +#else +#ifndef xmlSchemaIsValid +extern __typeof (xmlSchemaIsValid) xmlSchemaIsValid__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaIsValid xmlSchemaIsValid__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemas +#undef xmlSchemaNewDocParserCtxt +extern __typeof (xmlSchemaNewDocParserCtxt) xmlSchemaNewDocParserCtxt __attribute((alias("xmlSchemaNewDocParserCtxt__internal_alias"))); +#else +#ifndef xmlSchemaNewDocParserCtxt +extern __typeof (xmlSchemaNewDocParserCtxt) xmlSchemaNewDocParserCtxt__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaNewDocParserCtxt xmlSchemaNewDocParserCtxt__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemas +#undef xmlSchemaNewFacet +extern __typeof (xmlSchemaNewFacet) xmlSchemaNewFacet __attribute((alias("xmlSchemaNewFacet__internal_alias"))); +#else +#ifndef xmlSchemaNewFacet +extern __typeof (xmlSchemaNewFacet) xmlSchemaNewFacet__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaNewFacet xmlSchemaNewFacet__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemas +#undef xmlSchemaNewMemParserCtxt +extern __typeof (xmlSchemaNewMemParserCtxt) xmlSchemaNewMemParserCtxt __attribute((alias("xmlSchemaNewMemParserCtxt__internal_alias"))); +#else +#ifndef xmlSchemaNewMemParserCtxt +extern __typeof (xmlSchemaNewMemParserCtxt) xmlSchemaNewMemParserCtxt__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaNewMemParserCtxt xmlSchemaNewMemParserCtxt__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemastypes +#undef xmlSchemaNewNOTATIONValue +extern __typeof (xmlSchemaNewNOTATIONValue) xmlSchemaNewNOTATIONValue __attribute((alias("xmlSchemaNewNOTATIONValue__internal_alias"))); +#else +#ifndef xmlSchemaNewNOTATIONValue +extern __typeof (xmlSchemaNewNOTATIONValue) xmlSchemaNewNOTATIONValue__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaNewNOTATIONValue xmlSchemaNewNOTATIONValue__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemas +#undef xmlSchemaNewParserCtxt +extern __typeof (xmlSchemaNewParserCtxt) xmlSchemaNewParserCtxt __attribute((alias("xmlSchemaNewParserCtxt__internal_alias"))); +#else +#ifndef xmlSchemaNewParserCtxt +extern __typeof (xmlSchemaNewParserCtxt) xmlSchemaNewParserCtxt__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaNewParserCtxt xmlSchemaNewParserCtxt__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemastypes +#undef xmlSchemaNewQNameValue +extern __typeof (xmlSchemaNewQNameValue) xmlSchemaNewQNameValue __attribute((alias("xmlSchemaNewQNameValue__internal_alias"))); +#else +#ifndef xmlSchemaNewQNameValue +extern __typeof (xmlSchemaNewQNameValue) xmlSchemaNewQNameValue__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaNewQNameValue xmlSchemaNewQNameValue__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemastypes +#undef xmlSchemaNewStringValue +extern __typeof (xmlSchemaNewStringValue) xmlSchemaNewStringValue __attribute((alias("xmlSchemaNewStringValue__internal_alias"))); +#else +#ifndef xmlSchemaNewStringValue +extern __typeof (xmlSchemaNewStringValue) xmlSchemaNewStringValue__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaNewStringValue xmlSchemaNewStringValue__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemas +#undef xmlSchemaNewValidCtxt +extern __typeof (xmlSchemaNewValidCtxt) xmlSchemaNewValidCtxt __attribute((alias("xmlSchemaNewValidCtxt__internal_alias"))); +#else +#ifndef xmlSchemaNewValidCtxt +extern __typeof (xmlSchemaNewValidCtxt) xmlSchemaNewValidCtxt__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaNewValidCtxt xmlSchemaNewValidCtxt__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemas +#undef xmlSchemaParse +extern __typeof (xmlSchemaParse) xmlSchemaParse __attribute((alias("xmlSchemaParse__internal_alias"))); +#else +#ifndef xmlSchemaParse +extern __typeof (xmlSchemaParse) xmlSchemaParse__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaParse xmlSchemaParse__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemas +#undef xmlSchemaSAXPlug +extern __typeof (xmlSchemaSAXPlug) xmlSchemaSAXPlug __attribute((alias("xmlSchemaSAXPlug__internal_alias"))); +#else +#ifndef xmlSchemaSAXPlug +extern __typeof (xmlSchemaSAXPlug) xmlSchemaSAXPlug__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaSAXPlug xmlSchemaSAXPlug__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemas +#undef xmlSchemaSAXUnplug +extern __typeof (xmlSchemaSAXUnplug) xmlSchemaSAXUnplug __attribute((alias("xmlSchemaSAXUnplug__internal_alias"))); +#else +#ifndef xmlSchemaSAXUnplug +extern __typeof (xmlSchemaSAXUnplug) xmlSchemaSAXUnplug__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaSAXUnplug xmlSchemaSAXUnplug__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemas +#undef xmlSchemaSetParserErrors +extern __typeof (xmlSchemaSetParserErrors) xmlSchemaSetParserErrors __attribute((alias("xmlSchemaSetParserErrors__internal_alias"))); +#else +#ifndef xmlSchemaSetParserErrors +extern __typeof (xmlSchemaSetParserErrors) xmlSchemaSetParserErrors__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaSetParserErrors xmlSchemaSetParserErrors__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemas +#undef xmlSchemaSetParserStructuredErrors +extern __typeof (xmlSchemaSetParserStructuredErrors) xmlSchemaSetParserStructuredErrors __attribute((alias("xmlSchemaSetParserStructuredErrors__internal_alias"))); +#else +#ifndef xmlSchemaSetParserStructuredErrors +extern __typeof (xmlSchemaSetParserStructuredErrors) xmlSchemaSetParserStructuredErrors__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaSetParserStructuredErrors xmlSchemaSetParserStructuredErrors__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemas +#undef xmlSchemaSetValidErrors +extern __typeof (xmlSchemaSetValidErrors) xmlSchemaSetValidErrors __attribute((alias("xmlSchemaSetValidErrors__internal_alias"))); +#else +#ifndef xmlSchemaSetValidErrors +extern __typeof (xmlSchemaSetValidErrors) xmlSchemaSetValidErrors__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaSetValidErrors xmlSchemaSetValidErrors__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemas +#undef xmlSchemaSetValidOptions +extern __typeof (xmlSchemaSetValidOptions) xmlSchemaSetValidOptions __attribute((alias("xmlSchemaSetValidOptions__internal_alias"))); +#else +#ifndef xmlSchemaSetValidOptions +extern __typeof (xmlSchemaSetValidOptions) xmlSchemaSetValidOptions__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaSetValidOptions xmlSchemaSetValidOptions__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemas +#undef xmlSchemaSetValidStructuredErrors +extern __typeof (xmlSchemaSetValidStructuredErrors) xmlSchemaSetValidStructuredErrors __attribute((alias("xmlSchemaSetValidStructuredErrors__internal_alias"))); +#else +#ifndef xmlSchemaSetValidStructuredErrors +extern __typeof (xmlSchemaSetValidStructuredErrors) xmlSchemaSetValidStructuredErrors__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaSetValidStructuredErrors xmlSchemaSetValidStructuredErrors__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemastypes +#undef xmlSchemaValPredefTypeNode +extern __typeof (xmlSchemaValPredefTypeNode) xmlSchemaValPredefTypeNode __attribute((alias("xmlSchemaValPredefTypeNode__internal_alias"))); +#else +#ifndef xmlSchemaValPredefTypeNode +extern __typeof (xmlSchemaValPredefTypeNode) xmlSchemaValPredefTypeNode__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaValPredefTypeNode xmlSchemaValPredefTypeNode__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemastypes +#undef xmlSchemaValPredefTypeNodeNoNorm +extern __typeof (xmlSchemaValPredefTypeNodeNoNorm) xmlSchemaValPredefTypeNodeNoNorm __attribute((alias("xmlSchemaValPredefTypeNodeNoNorm__internal_alias"))); +#else +#ifndef xmlSchemaValPredefTypeNodeNoNorm +extern __typeof (xmlSchemaValPredefTypeNodeNoNorm) xmlSchemaValPredefTypeNodeNoNorm__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaValPredefTypeNodeNoNorm xmlSchemaValPredefTypeNodeNoNorm__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemas +#undef xmlSchemaValidCtxtGetOptions +extern __typeof (xmlSchemaValidCtxtGetOptions) xmlSchemaValidCtxtGetOptions __attribute((alias("xmlSchemaValidCtxtGetOptions__internal_alias"))); +#else +#ifndef xmlSchemaValidCtxtGetOptions +extern __typeof (xmlSchemaValidCtxtGetOptions) xmlSchemaValidCtxtGetOptions__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaValidCtxtGetOptions xmlSchemaValidCtxtGetOptions__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemas +#undef xmlSchemaValidCtxtGetParserCtxt +extern __typeof (xmlSchemaValidCtxtGetParserCtxt) xmlSchemaValidCtxtGetParserCtxt __attribute((alias("xmlSchemaValidCtxtGetParserCtxt__internal_alias"))); +#else +#ifndef xmlSchemaValidCtxtGetParserCtxt +extern __typeof (xmlSchemaValidCtxtGetParserCtxt) xmlSchemaValidCtxtGetParserCtxt__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaValidCtxtGetParserCtxt xmlSchemaValidCtxtGetParserCtxt__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemas +#undef xmlSchemaValidateDoc +extern __typeof (xmlSchemaValidateDoc) xmlSchemaValidateDoc __attribute((alias("xmlSchemaValidateDoc__internal_alias"))); +#else +#ifndef xmlSchemaValidateDoc +extern __typeof (xmlSchemaValidateDoc) xmlSchemaValidateDoc__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaValidateDoc xmlSchemaValidateDoc__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemastypes +#undef xmlSchemaValidateFacet +extern __typeof (xmlSchemaValidateFacet) xmlSchemaValidateFacet __attribute((alias("xmlSchemaValidateFacet__internal_alias"))); +#else +#ifndef xmlSchemaValidateFacet +extern __typeof (xmlSchemaValidateFacet) xmlSchemaValidateFacet__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaValidateFacet xmlSchemaValidateFacet__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemastypes +#undef xmlSchemaValidateFacetWhtsp +extern __typeof (xmlSchemaValidateFacetWhtsp) xmlSchemaValidateFacetWhtsp __attribute((alias("xmlSchemaValidateFacetWhtsp__internal_alias"))); +#else +#ifndef xmlSchemaValidateFacetWhtsp +extern __typeof (xmlSchemaValidateFacetWhtsp) xmlSchemaValidateFacetWhtsp__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaValidateFacetWhtsp xmlSchemaValidateFacetWhtsp__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemas +#undef xmlSchemaValidateFile +extern __typeof (xmlSchemaValidateFile) xmlSchemaValidateFile __attribute((alias("xmlSchemaValidateFile__internal_alias"))); +#else +#ifndef xmlSchemaValidateFile +extern __typeof (xmlSchemaValidateFile) xmlSchemaValidateFile__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaValidateFile xmlSchemaValidateFile__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemastypes +#undef xmlSchemaValidateLengthFacet +extern __typeof (xmlSchemaValidateLengthFacet) xmlSchemaValidateLengthFacet __attribute((alias("xmlSchemaValidateLengthFacet__internal_alias"))); +#else +#ifndef xmlSchemaValidateLengthFacet +extern __typeof (xmlSchemaValidateLengthFacet) xmlSchemaValidateLengthFacet__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaValidateLengthFacet xmlSchemaValidateLengthFacet__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemastypes +#undef xmlSchemaValidateLengthFacetWhtsp +extern __typeof (xmlSchemaValidateLengthFacetWhtsp) xmlSchemaValidateLengthFacetWhtsp __attribute((alias("xmlSchemaValidateLengthFacetWhtsp__internal_alias"))); +#else +#ifndef xmlSchemaValidateLengthFacetWhtsp +extern __typeof (xmlSchemaValidateLengthFacetWhtsp) xmlSchemaValidateLengthFacetWhtsp__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaValidateLengthFacetWhtsp xmlSchemaValidateLengthFacetWhtsp__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemastypes +#undef xmlSchemaValidateListSimpleTypeFacet +extern __typeof (xmlSchemaValidateListSimpleTypeFacet) xmlSchemaValidateListSimpleTypeFacet __attribute((alias("xmlSchemaValidateListSimpleTypeFacet__internal_alias"))); +#else +#ifndef xmlSchemaValidateListSimpleTypeFacet +extern __typeof (xmlSchemaValidateListSimpleTypeFacet) xmlSchemaValidateListSimpleTypeFacet__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaValidateListSimpleTypeFacet xmlSchemaValidateListSimpleTypeFacet__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemas +#undef xmlSchemaValidateOneElement +extern __typeof (xmlSchemaValidateOneElement) xmlSchemaValidateOneElement __attribute((alias("xmlSchemaValidateOneElement__internal_alias"))); +#else +#ifndef xmlSchemaValidateOneElement +extern __typeof (xmlSchemaValidateOneElement) xmlSchemaValidateOneElement__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaValidateOneElement xmlSchemaValidateOneElement__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemastypes +#undef xmlSchemaValidatePredefinedType +extern __typeof (xmlSchemaValidatePredefinedType) xmlSchemaValidatePredefinedType __attribute((alias("xmlSchemaValidatePredefinedType__internal_alias"))); +#else +#ifndef xmlSchemaValidatePredefinedType +extern __typeof (xmlSchemaValidatePredefinedType) xmlSchemaValidatePredefinedType__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaValidatePredefinedType xmlSchemaValidatePredefinedType__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemas +#undef xmlSchemaValidateStream +extern __typeof (xmlSchemaValidateStream) xmlSchemaValidateStream __attribute((alias("xmlSchemaValidateStream__internal_alias"))); +#else +#ifndef xmlSchemaValidateStream +extern __typeof (xmlSchemaValidateStream) xmlSchemaValidateStream__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaValidateStream xmlSchemaValidateStream__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemastypes +#undef xmlSchemaValueAppend +extern __typeof (xmlSchemaValueAppend) xmlSchemaValueAppend __attribute((alias("xmlSchemaValueAppend__internal_alias"))); +#else +#ifndef xmlSchemaValueAppend +extern __typeof (xmlSchemaValueAppend) xmlSchemaValueAppend__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaValueAppend xmlSchemaValueAppend__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemastypes +#undef xmlSchemaValueGetAsBoolean +extern __typeof (xmlSchemaValueGetAsBoolean) xmlSchemaValueGetAsBoolean __attribute((alias("xmlSchemaValueGetAsBoolean__internal_alias"))); +#else +#ifndef xmlSchemaValueGetAsBoolean +extern __typeof (xmlSchemaValueGetAsBoolean) xmlSchemaValueGetAsBoolean__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaValueGetAsBoolean xmlSchemaValueGetAsBoolean__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemastypes +#undef xmlSchemaValueGetAsString +extern __typeof (xmlSchemaValueGetAsString) xmlSchemaValueGetAsString __attribute((alias("xmlSchemaValueGetAsString__internal_alias"))); +#else +#ifndef xmlSchemaValueGetAsString +extern __typeof (xmlSchemaValueGetAsString) xmlSchemaValueGetAsString__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaValueGetAsString xmlSchemaValueGetAsString__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemastypes +#undef xmlSchemaValueGetNext +extern __typeof (xmlSchemaValueGetNext) xmlSchemaValueGetNext __attribute((alias("xmlSchemaValueGetNext__internal_alias"))); +#else +#ifndef xmlSchemaValueGetNext +extern __typeof (xmlSchemaValueGetNext) xmlSchemaValueGetNext__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaValueGetNext xmlSchemaValueGetNext__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlschemastypes +#undef xmlSchemaWhiteSpaceReplace +extern __typeof (xmlSchemaWhiteSpaceReplace) xmlSchemaWhiteSpaceReplace __attribute((alias("xmlSchemaWhiteSpaceReplace__internal_alias"))); +#else +#ifndef xmlSchemaWhiteSpaceReplace +extern __typeof (xmlSchemaWhiteSpaceReplace) xmlSchemaWhiteSpaceReplace__internal_alias __attribute((visibility("hidden"))); +#define xmlSchemaWhiteSpaceReplace xmlSchemaWhiteSpaceReplace__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMATRON_ENABLED) +#ifdef bottom_schematron +#undef xmlSchematronFree +extern __typeof (xmlSchematronFree) xmlSchematronFree __attribute((alias("xmlSchematronFree__internal_alias"))); +#else +#ifndef xmlSchematronFree +extern __typeof (xmlSchematronFree) xmlSchematronFree__internal_alias __attribute((visibility("hidden"))); +#define xmlSchematronFree xmlSchematronFree__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMATRON_ENABLED) +#ifdef bottom_schematron +#undef xmlSchematronFreeParserCtxt +extern __typeof (xmlSchematronFreeParserCtxt) xmlSchematronFreeParserCtxt __attribute((alias("xmlSchematronFreeParserCtxt__internal_alias"))); +#else +#ifndef xmlSchematronFreeParserCtxt +extern __typeof (xmlSchematronFreeParserCtxt) xmlSchematronFreeParserCtxt__internal_alias __attribute((visibility("hidden"))); +#define xmlSchematronFreeParserCtxt xmlSchematronFreeParserCtxt__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMATRON_ENABLED) +#ifdef bottom_schematron +#undef xmlSchematronFreeValidCtxt +extern __typeof (xmlSchematronFreeValidCtxt) xmlSchematronFreeValidCtxt __attribute((alias("xmlSchematronFreeValidCtxt__internal_alias"))); +#else +#ifndef xmlSchematronFreeValidCtxt +extern __typeof (xmlSchematronFreeValidCtxt) xmlSchematronFreeValidCtxt__internal_alias __attribute((visibility("hidden"))); +#define xmlSchematronFreeValidCtxt xmlSchematronFreeValidCtxt__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMATRON_ENABLED) +#ifdef bottom_schematron +#undef xmlSchematronNewDocParserCtxt +extern __typeof (xmlSchematronNewDocParserCtxt) xmlSchematronNewDocParserCtxt __attribute((alias("xmlSchematronNewDocParserCtxt__internal_alias"))); +#else +#ifndef xmlSchematronNewDocParserCtxt +extern __typeof (xmlSchematronNewDocParserCtxt) xmlSchematronNewDocParserCtxt__internal_alias __attribute((visibility("hidden"))); +#define xmlSchematronNewDocParserCtxt xmlSchematronNewDocParserCtxt__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMATRON_ENABLED) +#ifdef bottom_schematron +#undef xmlSchematronNewMemParserCtxt +extern __typeof (xmlSchematronNewMemParserCtxt) xmlSchematronNewMemParserCtxt __attribute((alias("xmlSchematronNewMemParserCtxt__internal_alias"))); +#else +#ifndef xmlSchematronNewMemParserCtxt +extern __typeof (xmlSchematronNewMemParserCtxt) xmlSchematronNewMemParserCtxt__internal_alias __attribute((visibility("hidden"))); +#define xmlSchematronNewMemParserCtxt xmlSchematronNewMemParserCtxt__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMATRON_ENABLED) +#ifdef bottom_schematron +#undef xmlSchematronNewParserCtxt +extern __typeof (xmlSchematronNewParserCtxt) xmlSchematronNewParserCtxt __attribute((alias("xmlSchematronNewParserCtxt__internal_alias"))); +#else +#ifndef xmlSchematronNewParserCtxt +extern __typeof (xmlSchematronNewParserCtxt) xmlSchematronNewParserCtxt__internal_alias __attribute((visibility("hidden"))); +#define xmlSchematronNewParserCtxt xmlSchematronNewParserCtxt__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMATRON_ENABLED) +#ifdef bottom_schematron +#undef xmlSchematronNewValidCtxt +extern __typeof (xmlSchematronNewValidCtxt) xmlSchematronNewValidCtxt __attribute((alias("xmlSchematronNewValidCtxt__internal_alias"))); +#else +#ifndef xmlSchematronNewValidCtxt +extern __typeof (xmlSchematronNewValidCtxt) xmlSchematronNewValidCtxt__internal_alias __attribute((visibility("hidden"))); +#define xmlSchematronNewValidCtxt xmlSchematronNewValidCtxt__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMATRON_ENABLED) +#ifdef bottom_schematron +#undef xmlSchematronParse +extern __typeof (xmlSchematronParse) xmlSchematronParse __attribute((alias("xmlSchematronParse__internal_alias"))); +#else +#ifndef xmlSchematronParse +extern __typeof (xmlSchematronParse) xmlSchematronParse__internal_alias __attribute((visibility("hidden"))); +#define xmlSchematronParse xmlSchematronParse__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMATRON_ENABLED) +#ifdef bottom_schematron +#undef xmlSchematronSetValidStructuredErrors +extern __typeof (xmlSchematronSetValidStructuredErrors) xmlSchematronSetValidStructuredErrors __attribute((alias("xmlSchematronSetValidStructuredErrors__internal_alias"))); +#else +#ifndef xmlSchematronSetValidStructuredErrors +extern __typeof (xmlSchematronSetValidStructuredErrors) xmlSchematronSetValidStructuredErrors__internal_alias __attribute((visibility("hidden"))); +#define xmlSchematronSetValidStructuredErrors xmlSchematronSetValidStructuredErrors__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_SCHEMATRON_ENABLED) +#ifdef bottom_schematron +#undef xmlSchematronValidateDoc +extern __typeof (xmlSchematronValidateDoc) xmlSchematronValidateDoc __attribute((alias("xmlSchematronValidateDoc__internal_alias"))); +#else +#ifndef xmlSchematronValidateDoc +extern __typeof (xmlSchematronValidateDoc) xmlSchematronValidateDoc__internal_alias __attribute((visibility("hidden"))); +#define xmlSchematronValidateDoc xmlSchematronValidateDoc__internal_alias +#endif +#endif +#endif + +#ifdef bottom_tree +#undef xmlSearchNs +extern __typeof (xmlSearchNs) xmlSearchNs __attribute((alias("xmlSearchNs__internal_alias"))); +#else +#ifndef xmlSearchNs +extern __typeof (xmlSearchNs) xmlSearchNs__internal_alias __attribute((visibility("hidden"))); +#define xmlSearchNs xmlSearchNs__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlSearchNsByHref +extern __typeof (xmlSearchNsByHref) xmlSearchNsByHref __attribute((alias("xmlSearchNsByHref__internal_alias"))); +#else +#ifndef xmlSearchNsByHref +extern __typeof (xmlSearchNsByHref) xmlSearchNsByHref__internal_alias __attribute((visibility("hidden"))); +#define xmlSearchNsByHref xmlSearchNsByHref__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlSetBufferAllocationScheme +extern __typeof (xmlSetBufferAllocationScheme) xmlSetBufferAllocationScheme __attribute((alias("xmlSetBufferAllocationScheme__internal_alias"))); +#else +#ifndef xmlSetBufferAllocationScheme +extern __typeof (xmlSetBufferAllocationScheme) xmlSetBufferAllocationScheme__internal_alias __attribute((visibility("hidden"))); +#define xmlSetBufferAllocationScheme xmlSetBufferAllocationScheme__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlSetCompressMode +extern __typeof (xmlSetCompressMode) xmlSetCompressMode __attribute((alias("xmlSetCompressMode__internal_alias"))); +#else +#ifndef xmlSetCompressMode +extern __typeof (xmlSetCompressMode) xmlSetCompressMode__internal_alias __attribute((visibility("hidden"))); +#define xmlSetCompressMode xmlSetCompressMode__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlSetDocCompressMode +extern __typeof (xmlSetDocCompressMode) xmlSetDocCompressMode __attribute((alias("xmlSetDocCompressMode__internal_alias"))); +#else +#ifndef xmlSetDocCompressMode +extern __typeof (xmlSetDocCompressMode) xmlSetDocCompressMode__internal_alias __attribute((visibility("hidden"))); +#define xmlSetDocCompressMode xmlSetDocCompressMode__internal_alias +#endif +#endif + +#if defined(LIBXML_LEGACY_ENABLED) +#ifdef bottom_parser +#undef xmlSetEntityReferenceFunc +extern __typeof (xmlSetEntityReferenceFunc) xmlSetEntityReferenceFunc __attribute((alias("xmlSetEntityReferenceFunc__internal_alias"))); +#else +#ifndef xmlSetEntityReferenceFunc +extern __typeof (xmlSetEntityReferenceFunc) xmlSetEntityReferenceFunc__internal_alias __attribute((visibility("hidden"))); +#define xmlSetEntityReferenceFunc xmlSetEntityReferenceFunc__internal_alias +#endif +#endif +#endif + +#ifdef bottom_xmlIO +#undef xmlSetExternalEntityLoader +extern __typeof (xmlSetExternalEntityLoader) xmlSetExternalEntityLoader __attribute((alias("xmlSetExternalEntityLoader__internal_alias"))); +#else +#ifndef xmlSetExternalEntityLoader +extern __typeof (xmlSetExternalEntityLoader) xmlSetExternalEntityLoader__internal_alias __attribute((visibility("hidden"))); +#define xmlSetExternalEntityLoader xmlSetExternalEntityLoader__internal_alias +#endif +#endif + +#if defined(LIBXML_LEGACY_ENABLED) +#ifdef bottom_legacy +#undef xmlSetFeature +extern __typeof (xmlSetFeature) xmlSetFeature __attribute((alias("xmlSetFeature__internal_alias"))); +#else +#ifndef xmlSetFeature +extern __typeof (xmlSetFeature) xmlSetFeature__internal_alias __attribute((visibility("hidden"))); +#define xmlSetFeature xmlSetFeature__internal_alias +#endif +#endif +#endif + +#ifdef bottom_error +#undef xmlSetGenericErrorFunc +extern __typeof (xmlSetGenericErrorFunc) xmlSetGenericErrorFunc __attribute((alias("xmlSetGenericErrorFunc__internal_alias"))); +#else +#ifndef xmlSetGenericErrorFunc +extern __typeof (xmlSetGenericErrorFunc) xmlSetGenericErrorFunc__internal_alias __attribute((visibility("hidden"))); +#define xmlSetGenericErrorFunc xmlSetGenericErrorFunc__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlSetListDoc +extern __typeof (xmlSetListDoc) xmlSetListDoc __attribute((alias("xmlSetListDoc__internal_alias"))); +#else +#ifndef xmlSetListDoc +extern __typeof (xmlSetListDoc) xmlSetListDoc__internal_alias __attribute((visibility("hidden"))); +#define xmlSetListDoc xmlSetListDoc__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlSetNs +extern __typeof (xmlSetNs) xmlSetNs __attribute((alias("xmlSetNs__internal_alias"))); +#else +#ifndef xmlSetNs +extern __typeof (xmlSetNs) xmlSetNs__internal_alias __attribute((visibility("hidden"))); +#define xmlSetNs xmlSetNs__internal_alias +#endif +#endif + +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_tree +#undef xmlSetNsProp +extern __typeof (xmlSetNsProp) xmlSetNsProp __attribute((alias("xmlSetNsProp__internal_alias"))); +#else +#ifndef xmlSetNsProp +extern __typeof (xmlSetNsProp) xmlSetNsProp__internal_alias __attribute((visibility("hidden"))); +#define xmlSetNsProp xmlSetNsProp__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_tree +#undef xmlSetProp +extern __typeof (xmlSetProp) xmlSetProp __attribute((alias("xmlSetProp__internal_alias"))); +#else +#ifndef xmlSetProp +extern __typeof (xmlSetProp) xmlSetProp__internal_alias __attribute((visibility("hidden"))); +#define xmlSetProp xmlSetProp__internal_alias +#endif +#endif +#endif + +#ifdef bottom_error +#undef xmlSetStructuredErrorFunc +extern __typeof (xmlSetStructuredErrorFunc) xmlSetStructuredErrorFunc __attribute((alias("xmlSetStructuredErrorFunc__internal_alias"))); +#else +#ifndef xmlSetStructuredErrorFunc +extern __typeof (xmlSetStructuredErrorFunc) xmlSetStructuredErrorFunc__internal_alias __attribute((visibility("hidden"))); +#define xmlSetStructuredErrorFunc xmlSetStructuredErrorFunc__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlSetTreeDoc +extern __typeof (xmlSetTreeDoc) xmlSetTreeDoc __attribute((alias("xmlSetTreeDoc__internal_alias"))); +#else +#ifndef xmlSetTreeDoc +extern __typeof (xmlSetTreeDoc) xmlSetTreeDoc__internal_alias __attribute((visibility("hidden"))); +#define xmlSetTreeDoc xmlSetTreeDoc__internal_alias +#endif +#endif + +#if defined(LIBXML_SAX1_ENABLED) +#ifdef bottom_parser +#undef xmlSetupParserForBuffer +extern __typeof (xmlSetupParserForBuffer) xmlSetupParserForBuffer __attribute((alias("xmlSetupParserForBuffer__internal_alias"))); +#else +#ifndef xmlSetupParserForBuffer +extern __typeof (xmlSetupParserForBuffer) xmlSetupParserForBuffer__internal_alias __attribute((visibility("hidden"))); +#define xmlSetupParserForBuffer xmlSetupParserForBuffer__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_DEBUG_ENABLED) && defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_debugXML +#undef xmlShell +extern __typeof (xmlShell) xmlShell __attribute((alias("xmlShell__internal_alias"))); +#else +#ifndef xmlShell +extern __typeof (xmlShell) xmlShell__internal_alias __attribute((visibility("hidden"))); +#define xmlShell xmlShell__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_DEBUG_ENABLED) && defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_debugXML +#undef xmlShellBase +extern __typeof (xmlShellBase) xmlShellBase __attribute((alias("xmlShellBase__internal_alias"))); +#else +#ifndef xmlShellBase +extern __typeof (xmlShellBase) xmlShellBase__internal_alias __attribute((visibility("hidden"))); +#define xmlShellBase xmlShellBase__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_DEBUG_ENABLED) && defined(LIBXML_XPATH_ENABLED) && defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_debugXML +#undef xmlShellCat +extern __typeof (xmlShellCat) xmlShellCat __attribute((alias("xmlShellCat__internal_alias"))); +#else +#ifndef xmlShellCat +extern __typeof (xmlShellCat) xmlShellCat__internal_alias __attribute((visibility("hidden"))); +#define xmlShellCat xmlShellCat__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_DEBUG_ENABLED) && defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_debugXML +#undef xmlShellDir +extern __typeof (xmlShellDir) xmlShellDir __attribute((alias("xmlShellDir__internal_alias"))); +#else +#ifndef xmlShellDir +extern __typeof (xmlShellDir) xmlShellDir__internal_alias __attribute((visibility("hidden"))); +#define xmlShellDir xmlShellDir__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_DEBUG_ENABLED) && defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_debugXML +#undef xmlShellDu +extern __typeof (xmlShellDu) xmlShellDu __attribute((alias("xmlShellDu__internal_alias"))); +#else +#ifndef xmlShellDu +extern __typeof (xmlShellDu) xmlShellDu__internal_alias __attribute((visibility("hidden"))); +#define xmlShellDu xmlShellDu__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_DEBUG_ENABLED) && defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_debugXML +#undef xmlShellList +extern __typeof (xmlShellList) xmlShellList __attribute((alias("xmlShellList__internal_alias"))); +#else +#ifndef xmlShellList +extern __typeof (xmlShellList) xmlShellList__internal_alias __attribute((visibility("hidden"))); +#define xmlShellList xmlShellList__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_DEBUG_ENABLED) && defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_debugXML +#undef xmlShellLoad +extern __typeof (xmlShellLoad) xmlShellLoad __attribute((alias("xmlShellLoad__internal_alias"))); +#else +#ifndef xmlShellLoad +extern __typeof (xmlShellLoad) xmlShellLoad__internal_alias __attribute((visibility("hidden"))); +#define xmlShellLoad xmlShellLoad__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_DEBUG_ENABLED) && defined(LIBXML_XPATH_ENABLED) && defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_debugXML +#undef xmlShellPrintNode +extern __typeof (xmlShellPrintNode) xmlShellPrintNode __attribute((alias("xmlShellPrintNode__internal_alias"))); +#else +#ifndef xmlShellPrintNode +extern __typeof (xmlShellPrintNode) xmlShellPrintNode__internal_alias __attribute((visibility("hidden"))); +#define xmlShellPrintNode xmlShellPrintNode__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_DEBUG_ENABLED) && defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_debugXML +#undef xmlShellPrintXPathError +extern __typeof (xmlShellPrintXPathError) xmlShellPrintXPathError __attribute((alias("xmlShellPrintXPathError__internal_alias"))); +#else +#ifndef xmlShellPrintXPathError +extern __typeof (xmlShellPrintXPathError) xmlShellPrintXPathError__internal_alias __attribute((visibility("hidden"))); +#define xmlShellPrintXPathError xmlShellPrintXPathError__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_DEBUG_ENABLED) && defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_debugXML +#undef xmlShellPrintXPathResult +extern __typeof (xmlShellPrintXPathResult) xmlShellPrintXPathResult __attribute((alias("xmlShellPrintXPathResult__internal_alias"))); +#else +#ifndef xmlShellPrintXPathResult +extern __typeof (xmlShellPrintXPathResult) xmlShellPrintXPathResult__internal_alias __attribute((visibility("hidden"))); +#define xmlShellPrintXPathResult xmlShellPrintXPathResult__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_DEBUG_ENABLED) && defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_debugXML +#undef xmlShellPwd +extern __typeof (xmlShellPwd) xmlShellPwd __attribute((alias("xmlShellPwd__internal_alias"))); +#else +#ifndef xmlShellPwd +extern __typeof (xmlShellPwd) xmlShellPwd__internal_alias __attribute((visibility("hidden"))); +#define xmlShellPwd xmlShellPwd__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_DEBUG_ENABLED) && defined(LIBXML_XPATH_ENABLED) && defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_debugXML +#undef xmlShellSave +extern __typeof (xmlShellSave) xmlShellSave __attribute((alias("xmlShellSave__internal_alias"))); +#else +#ifndef xmlShellSave +extern __typeof (xmlShellSave) xmlShellSave__internal_alias __attribute((visibility("hidden"))); +#define xmlShellSave xmlShellSave__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_DEBUG_ENABLED) && defined(LIBXML_XPATH_ENABLED) && defined(LIBXML_VALID_ENABLED) +#ifdef bottom_debugXML +#undef xmlShellValidate +extern __typeof (xmlShellValidate) xmlShellValidate __attribute((alias("xmlShellValidate__internal_alias"))); +#else +#ifndef xmlShellValidate +extern __typeof (xmlShellValidate) xmlShellValidate__internal_alias __attribute((visibility("hidden"))); +#define xmlShellValidate xmlShellValidate__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_DEBUG_ENABLED) && defined(LIBXML_XPATH_ENABLED) && defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_debugXML +#undef xmlShellWrite +extern __typeof (xmlShellWrite) xmlShellWrite __attribute((alias("xmlShellWrite__internal_alias"))); +#else +#ifndef xmlShellWrite +extern __typeof (xmlShellWrite) xmlShellWrite__internal_alias __attribute((visibility("hidden"))); +#define xmlShellWrite xmlShellWrite__internal_alias +#endif +#endif +#endif + +#ifdef bottom_parser +#undef xmlSkipBlankChars +extern __typeof (xmlSkipBlankChars) xmlSkipBlankChars __attribute((alias("xmlSkipBlankChars__internal_alias"))); +#else +#ifndef xmlSkipBlankChars +extern __typeof (xmlSkipBlankChars) xmlSkipBlankChars__internal_alias __attribute((visibility("hidden"))); +#define xmlSkipBlankChars xmlSkipBlankChars__internal_alias +#endif +#endif + +#ifdef bottom_valid +#undef xmlSnprintfElementContent +extern __typeof (xmlSnprintfElementContent) xmlSnprintfElementContent __attribute((alias("xmlSnprintfElementContent__internal_alias"))); +#else +#ifndef xmlSnprintfElementContent +extern __typeof (xmlSnprintfElementContent) xmlSnprintfElementContent__internal_alias __attribute((visibility("hidden"))); +#define xmlSnprintfElementContent xmlSnprintfElementContent__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlSplitQName +extern __typeof (xmlSplitQName) xmlSplitQName __attribute((alias("xmlSplitQName__internal_alias"))); +#else +#ifndef xmlSplitQName +extern __typeof (xmlSplitQName) xmlSplitQName__internal_alias __attribute((visibility("hidden"))); +#define xmlSplitQName xmlSplitQName__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlSplitQName2 +extern __typeof (xmlSplitQName2) xmlSplitQName2 __attribute((alias("xmlSplitQName2__internal_alias"))); +#else +#ifndef xmlSplitQName2 +extern __typeof (xmlSplitQName2) xmlSplitQName2__internal_alias __attribute((visibility("hidden"))); +#define xmlSplitQName2 xmlSplitQName2__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlSplitQName3 +extern __typeof (xmlSplitQName3) xmlSplitQName3 __attribute((alias("xmlSplitQName3__internal_alias"))); +#else +#ifndef xmlSplitQName3 +extern __typeof (xmlSplitQName3) xmlSplitQName3__internal_alias __attribute((visibility("hidden"))); +#define xmlSplitQName3 xmlSplitQName3__internal_alias +#endif +#endif + +#if defined(LIBXML_OUTPUT_ENABLED) +#ifdef bottom_valid +#undef xmlSprintfElementContent +extern __typeof (xmlSprintfElementContent) xmlSprintfElementContent __attribute((alias("xmlSprintfElementContent__internal_alias"))); +#else +#ifndef xmlSprintfElementContent +extern __typeof (xmlSprintfElementContent) xmlSprintfElementContent__internal_alias __attribute((visibility("hidden"))); +#define xmlSprintfElementContent xmlSprintfElementContent__internal_alias +#endif +#endif +#endif + +#ifdef bottom_parser +#undef xmlStopParser +extern __typeof (xmlStopParser) xmlStopParser __attribute((alias("xmlStopParser__internal_alias"))); +#else +#ifndef xmlStopParser +extern __typeof (xmlStopParser) xmlStopParser__internal_alias __attribute((visibility("hidden"))); +#define xmlStopParser xmlStopParser__internal_alias +#endif +#endif + +#ifdef bottom_xmlstring +#undef xmlStrEqual +extern __typeof (xmlStrEqual) xmlStrEqual __attribute((alias("xmlStrEqual__internal_alias"))); +#else +#ifndef xmlStrEqual +extern __typeof (xmlStrEqual) xmlStrEqual__internal_alias __attribute((visibility("hidden"))); +#define xmlStrEqual xmlStrEqual__internal_alias +#endif +#endif + +#ifdef bottom_xmlstring +#undef xmlStrPrintf +extern __typeof (xmlStrPrintf) xmlStrPrintf __attribute((alias("xmlStrPrintf__internal_alias"))); +#else +#ifndef xmlStrPrintf +extern __typeof (xmlStrPrintf) xmlStrPrintf__internal_alias __attribute((visibility("hidden"))); +#define xmlStrPrintf xmlStrPrintf__internal_alias +#endif +#endif + +#ifdef bottom_xmlstring +#undef xmlStrQEqual +extern __typeof (xmlStrQEqual) xmlStrQEqual __attribute((alias("xmlStrQEqual__internal_alias"))); +#else +#ifndef xmlStrQEqual +extern __typeof (xmlStrQEqual) xmlStrQEqual__internal_alias __attribute((visibility("hidden"))); +#define xmlStrQEqual xmlStrQEqual__internal_alias +#endif +#endif + +#ifdef bottom_xmlstring +#undef xmlStrVPrintf +extern __typeof (xmlStrVPrintf) xmlStrVPrintf __attribute((alias("xmlStrVPrintf__internal_alias"))); +#else +#ifndef xmlStrVPrintf +extern __typeof (xmlStrVPrintf) xmlStrVPrintf__internal_alias __attribute((visibility("hidden"))); +#define xmlStrVPrintf xmlStrVPrintf__internal_alias +#endif +#endif + +#ifdef bottom_xmlstring +#undef xmlStrcasecmp +extern __typeof (xmlStrcasecmp) xmlStrcasecmp __attribute((alias("xmlStrcasecmp__internal_alias"))); +#else +#ifndef xmlStrcasecmp +extern __typeof (xmlStrcasecmp) xmlStrcasecmp__internal_alias __attribute((visibility("hidden"))); +#define xmlStrcasecmp xmlStrcasecmp__internal_alias +#endif +#endif + +#ifdef bottom_xmlstring +#undef xmlStrcasestr +extern __typeof (xmlStrcasestr) xmlStrcasestr __attribute((alias("xmlStrcasestr__internal_alias"))); +#else +#ifndef xmlStrcasestr +extern __typeof (xmlStrcasestr) xmlStrcasestr__internal_alias __attribute((visibility("hidden"))); +#define xmlStrcasestr xmlStrcasestr__internal_alias +#endif +#endif + +#ifdef bottom_xmlstring +#undef xmlStrcat +extern __typeof (xmlStrcat) xmlStrcat __attribute((alias("xmlStrcat__internal_alias"))); +#else +#ifndef xmlStrcat +extern __typeof (xmlStrcat) xmlStrcat__internal_alias __attribute((visibility("hidden"))); +#define xmlStrcat xmlStrcat__internal_alias +#endif +#endif + +#ifdef bottom_xmlstring +#undef xmlStrchr +extern __typeof (xmlStrchr) xmlStrchr __attribute((alias("xmlStrchr__internal_alias"))); +#else +#ifndef xmlStrchr +extern __typeof (xmlStrchr) xmlStrchr__internal_alias __attribute((visibility("hidden"))); +#define xmlStrchr xmlStrchr__internal_alias +#endif +#endif + +#ifdef bottom_xmlstring +#undef xmlStrcmp +extern __typeof (xmlStrcmp) xmlStrcmp __attribute((alias("xmlStrcmp__internal_alias"))); +#else +#ifndef xmlStrcmp +extern __typeof (xmlStrcmp) xmlStrcmp__internal_alias __attribute((visibility("hidden"))); +#define xmlStrcmp xmlStrcmp__internal_alias +#endif +#endif + +#ifdef bottom_xmlstring +#undef xmlStrdup +extern __typeof (xmlStrdup) xmlStrdup __attribute((alias("xmlStrdup__internal_alias"))); +#else +#ifndef xmlStrdup +extern __typeof (xmlStrdup) xmlStrdup__internal_alias __attribute((visibility("hidden"))); +#define xmlStrdup xmlStrdup__internal_alias +#endif +#endif + +#if defined(LIBXML_PATTERN_ENABLED) +#ifdef bottom_pattern +#undef xmlStreamPop +extern __typeof (xmlStreamPop) xmlStreamPop __attribute((alias("xmlStreamPop__internal_alias"))); +#else +#ifndef xmlStreamPop +extern __typeof (xmlStreamPop) xmlStreamPop__internal_alias __attribute((visibility("hidden"))); +#define xmlStreamPop xmlStreamPop__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_PATTERN_ENABLED) +#ifdef bottom_pattern +#undef xmlStreamPush +extern __typeof (xmlStreamPush) xmlStreamPush __attribute((alias("xmlStreamPush__internal_alias"))); +#else +#ifndef xmlStreamPush +extern __typeof (xmlStreamPush) xmlStreamPush__internal_alias __attribute((visibility("hidden"))); +#define xmlStreamPush xmlStreamPush__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_PATTERN_ENABLED) +#ifdef bottom_pattern +#undef xmlStreamPushAttr +extern __typeof (xmlStreamPushAttr) xmlStreamPushAttr __attribute((alias("xmlStreamPushAttr__internal_alias"))); +#else +#ifndef xmlStreamPushAttr +extern __typeof (xmlStreamPushAttr) xmlStreamPushAttr__internal_alias __attribute((visibility("hidden"))); +#define xmlStreamPushAttr xmlStreamPushAttr__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_PATTERN_ENABLED) +#ifdef bottom_pattern +#undef xmlStreamPushNode +extern __typeof (xmlStreamPushNode) xmlStreamPushNode __attribute((alias("xmlStreamPushNode__internal_alias"))); +#else +#ifndef xmlStreamPushNode +extern __typeof (xmlStreamPushNode) xmlStreamPushNode__internal_alias __attribute((visibility("hidden"))); +#define xmlStreamPushNode xmlStreamPushNode__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_PATTERN_ENABLED) +#ifdef bottom_pattern +#undef xmlStreamWantsAnyNode +extern __typeof (xmlStreamWantsAnyNode) xmlStreamWantsAnyNode __attribute((alias("xmlStreamWantsAnyNode__internal_alias"))); +#else +#ifndef xmlStreamWantsAnyNode +extern __typeof (xmlStreamWantsAnyNode) xmlStreamWantsAnyNode__internal_alias __attribute((visibility("hidden"))); +#define xmlStreamWantsAnyNode xmlStreamWantsAnyNode__internal_alias +#endif +#endif +#endif + +#ifdef bottom_parserInternals +#undef xmlStringCurrentChar +extern __typeof (xmlStringCurrentChar) xmlStringCurrentChar __attribute((alias("xmlStringCurrentChar__internal_alias"))); +#else +#ifndef xmlStringCurrentChar +extern __typeof (xmlStringCurrentChar) xmlStringCurrentChar__internal_alias __attribute((visibility("hidden"))); +#define xmlStringCurrentChar xmlStringCurrentChar__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlStringDecodeEntities +extern __typeof (xmlStringDecodeEntities) xmlStringDecodeEntities __attribute((alias("xmlStringDecodeEntities__internal_alias"))); +#else +#ifndef xmlStringDecodeEntities +extern __typeof (xmlStringDecodeEntities) xmlStringDecodeEntities__internal_alias __attribute((visibility("hidden"))); +#define xmlStringDecodeEntities xmlStringDecodeEntities__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlStringGetNodeList +extern __typeof (xmlStringGetNodeList) xmlStringGetNodeList __attribute((alias("xmlStringGetNodeList__internal_alias"))); +#else +#ifndef xmlStringGetNodeList +extern __typeof (xmlStringGetNodeList) xmlStringGetNodeList__internal_alias __attribute((visibility("hidden"))); +#define xmlStringGetNodeList xmlStringGetNodeList__internal_alias +#endif +#endif + +#ifdef bottom_parser +#undef xmlStringLenDecodeEntities +extern __typeof (xmlStringLenDecodeEntities) xmlStringLenDecodeEntities __attribute((alias("xmlStringLenDecodeEntities__internal_alias"))); +#else +#ifndef xmlStringLenDecodeEntities +extern __typeof (xmlStringLenDecodeEntities) xmlStringLenDecodeEntities__internal_alias __attribute((visibility("hidden"))); +#define xmlStringLenDecodeEntities xmlStringLenDecodeEntities__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlStringLenGetNodeList +extern __typeof (xmlStringLenGetNodeList) xmlStringLenGetNodeList __attribute((alias("xmlStringLenGetNodeList__internal_alias"))); +#else +#ifndef xmlStringLenGetNodeList +extern __typeof (xmlStringLenGetNodeList) xmlStringLenGetNodeList__internal_alias __attribute((visibility("hidden"))); +#define xmlStringLenGetNodeList xmlStringLenGetNodeList__internal_alias +#endif +#endif + +#ifdef bottom_xmlstring +#undef xmlStrlen +extern __typeof (xmlStrlen) xmlStrlen __attribute((alias("xmlStrlen__internal_alias"))); +#else +#ifndef xmlStrlen +extern __typeof (xmlStrlen) xmlStrlen__internal_alias __attribute((visibility("hidden"))); +#define xmlStrlen xmlStrlen__internal_alias +#endif +#endif + +#ifdef bottom_xmlstring +#undef xmlStrncasecmp +extern __typeof (xmlStrncasecmp) xmlStrncasecmp __attribute((alias("xmlStrncasecmp__internal_alias"))); +#else +#ifndef xmlStrncasecmp +extern __typeof (xmlStrncasecmp) xmlStrncasecmp__internal_alias __attribute((visibility("hidden"))); +#define xmlStrncasecmp xmlStrncasecmp__internal_alias +#endif +#endif + +#ifdef bottom_xmlstring +#undef xmlStrncat +extern __typeof (xmlStrncat) xmlStrncat __attribute((alias("xmlStrncat__internal_alias"))); +#else +#ifndef xmlStrncat +extern __typeof (xmlStrncat) xmlStrncat__internal_alias __attribute((visibility("hidden"))); +#define xmlStrncat xmlStrncat__internal_alias +#endif +#endif + +#ifdef bottom_xmlstring +#undef xmlStrncatNew +extern __typeof (xmlStrncatNew) xmlStrncatNew __attribute((alias("xmlStrncatNew__internal_alias"))); +#else +#ifndef xmlStrncatNew +extern __typeof (xmlStrncatNew) xmlStrncatNew__internal_alias __attribute((visibility("hidden"))); +#define xmlStrncatNew xmlStrncatNew__internal_alias +#endif +#endif + +#ifdef bottom_xmlstring +#undef xmlStrncmp +extern __typeof (xmlStrncmp) xmlStrncmp __attribute((alias("xmlStrncmp__internal_alias"))); +#else +#ifndef xmlStrncmp +extern __typeof (xmlStrncmp) xmlStrncmp__internal_alias __attribute((visibility("hidden"))); +#define xmlStrncmp xmlStrncmp__internal_alias +#endif +#endif + +#ifdef bottom_xmlstring +#undef xmlStrndup +extern __typeof (xmlStrndup) xmlStrndup __attribute((alias("xmlStrndup__internal_alias"))); +#else +#ifndef xmlStrndup +extern __typeof (xmlStrndup) xmlStrndup__internal_alias __attribute((visibility("hidden"))); +#define xmlStrndup xmlStrndup__internal_alias +#endif +#endif + +#ifdef bottom_xmlstring +#undef xmlStrstr +extern __typeof (xmlStrstr) xmlStrstr __attribute((alias("xmlStrstr__internal_alias"))); +#else +#ifndef xmlStrstr +extern __typeof (xmlStrstr) xmlStrstr__internal_alias __attribute((visibility("hidden"))); +#define xmlStrstr xmlStrstr__internal_alias +#endif +#endif + +#ifdef bottom_xmlstring +#undef xmlStrsub +extern __typeof (xmlStrsub) xmlStrsub __attribute((alias("xmlStrsub__internal_alias"))); +#else +#ifndef xmlStrsub +extern __typeof (xmlStrsub) xmlStrsub__internal_alias __attribute((visibility("hidden"))); +#define xmlStrsub xmlStrsub__internal_alias +#endif +#endif + +#ifdef bottom_parserInternals +#undef xmlSubstituteEntitiesDefault +extern __typeof (xmlSubstituteEntitiesDefault) xmlSubstituteEntitiesDefault __attribute((alias("xmlSubstituteEntitiesDefault__internal_alias"))); +#else +#ifndef xmlSubstituteEntitiesDefault +extern __typeof (xmlSubstituteEntitiesDefault) xmlSubstituteEntitiesDefault__internal_alias __attribute((visibility("hidden"))); +#define xmlSubstituteEntitiesDefault xmlSubstituteEntitiesDefault__internal_alias +#endif +#endif + +#ifdef bottom_parserInternals +#undef xmlSwitchEncoding +extern __typeof (xmlSwitchEncoding) xmlSwitchEncoding __attribute((alias("xmlSwitchEncoding__internal_alias"))); +#else +#ifndef xmlSwitchEncoding +extern __typeof (xmlSwitchEncoding) xmlSwitchEncoding__internal_alias __attribute((visibility("hidden"))); +#define xmlSwitchEncoding xmlSwitchEncoding__internal_alias +#endif +#endif + +#ifdef bottom_parserInternals +#undef xmlSwitchInputEncoding +extern __typeof (xmlSwitchInputEncoding) xmlSwitchInputEncoding __attribute((alias("xmlSwitchInputEncoding__internal_alias"))); +#else +#ifndef xmlSwitchInputEncoding +extern __typeof (xmlSwitchInputEncoding) xmlSwitchInputEncoding__internal_alias __attribute((visibility("hidden"))); +#define xmlSwitchInputEncoding xmlSwitchInputEncoding__internal_alias +#endif +#endif + +#ifdef bottom_parserInternals +#undef xmlSwitchToEncoding +extern __typeof (xmlSwitchToEncoding) xmlSwitchToEncoding __attribute((alias("xmlSwitchToEncoding__internal_alias"))); +#else +#ifndef xmlSwitchToEncoding +extern __typeof (xmlSwitchToEncoding) xmlSwitchToEncoding__internal_alias __attribute((visibility("hidden"))); +#define xmlSwitchToEncoding xmlSwitchToEncoding__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlTextConcat +extern __typeof (xmlTextConcat) xmlTextConcat __attribute((alias("xmlTextConcat__internal_alias"))); +#else +#ifndef xmlTextConcat +extern __typeof (xmlTextConcat) xmlTextConcat__internal_alias __attribute((visibility("hidden"))); +#define xmlTextConcat xmlTextConcat__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlTextMerge +extern __typeof (xmlTextMerge) xmlTextMerge __attribute((alias("xmlTextMerge__internal_alias"))); +#else +#ifndef xmlTextMerge +extern __typeof (xmlTextMerge) xmlTextMerge__internal_alias __attribute((visibility("hidden"))); +#define xmlTextMerge xmlTextMerge__internal_alias +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderAttributeCount +extern __typeof (xmlTextReaderAttributeCount) xmlTextReaderAttributeCount __attribute((alias("xmlTextReaderAttributeCount__internal_alias"))); +#else +#ifndef xmlTextReaderAttributeCount +extern __typeof (xmlTextReaderAttributeCount) xmlTextReaderAttributeCount__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderAttributeCount xmlTextReaderAttributeCount__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderBaseUri +extern __typeof (xmlTextReaderBaseUri) xmlTextReaderBaseUri __attribute((alias("xmlTextReaderBaseUri__internal_alias"))); +#else +#ifndef xmlTextReaderBaseUri +extern __typeof (xmlTextReaderBaseUri) xmlTextReaderBaseUri__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderBaseUri xmlTextReaderBaseUri__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderByteConsumed +extern __typeof (xmlTextReaderByteConsumed) xmlTextReaderByteConsumed __attribute((alias("xmlTextReaderByteConsumed__internal_alias"))); +#else +#ifndef xmlTextReaderByteConsumed +extern __typeof (xmlTextReaderByteConsumed) xmlTextReaderByteConsumed__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderByteConsumed xmlTextReaderByteConsumed__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderClose +extern __typeof (xmlTextReaderClose) xmlTextReaderClose __attribute((alias("xmlTextReaderClose__internal_alias"))); +#else +#ifndef xmlTextReaderClose +extern __typeof (xmlTextReaderClose) xmlTextReaderClose__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderClose xmlTextReaderClose__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderConstBaseUri +extern __typeof (xmlTextReaderConstBaseUri) xmlTextReaderConstBaseUri __attribute((alias("xmlTextReaderConstBaseUri__internal_alias"))); +#else +#ifndef xmlTextReaderConstBaseUri +extern __typeof (xmlTextReaderConstBaseUri) xmlTextReaderConstBaseUri__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderConstBaseUri xmlTextReaderConstBaseUri__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderConstEncoding +extern __typeof (xmlTextReaderConstEncoding) xmlTextReaderConstEncoding __attribute((alias("xmlTextReaderConstEncoding__internal_alias"))); +#else +#ifndef xmlTextReaderConstEncoding +extern __typeof (xmlTextReaderConstEncoding) xmlTextReaderConstEncoding__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderConstEncoding xmlTextReaderConstEncoding__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderConstLocalName +extern __typeof (xmlTextReaderConstLocalName) xmlTextReaderConstLocalName __attribute((alias("xmlTextReaderConstLocalName__internal_alias"))); +#else +#ifndef xmlTextReaderConstLocalName +extern __typeof (xmlTextReaderConstLocalName) xmlTextReaderConstLocalName__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderConstLocalName xmlTextReaderConstLocalName__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderConstName +extern __typeof (xmlTextReaderConstName) xmlTextReaderConstName __attribute((alias("xmlTextReaderConstName__internal_alias"))); +#else +#ifndef xmlTextReaderConstName +extern __typeof (xmlTextReaderConstName) xmlTextReaderConstName__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderConstName xmlTextReaderConstName__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderConstNamespaceUri +extern __typeof (xmlTextReaderConstNamespaceUri) xmlTextReaderConstNamespaceUri __attribute((alias("xmlTextReaderConstNamespaceUri__internal_alias"))); +#else +#ifndef xmlTextReaderConstNamespaceUri +extern __typeof (xmlTextReaderConstNamespaceUri) xmlTextReaderConstNamespaceUri__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderConstNamespaceUri xmlTextReaderConstNamespaceUri__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderConstPrefix +extern __typeof (xmlTextReaderConstPrefix) xmlTextReaderConstPrefix __attribute((alias("xmlTextReaderConstPrefix__internal_alias"))); +#else +#ifndef xmlTextReaderConstPrefix +extern __typeof (xmlTextReaderConstPrefix) xmlTextReaderConstPrefix__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderConstPrefix xmlTextReaderConstPrefix__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderConstString +extern __typeof (xmlTextReaderConstString) xmlTextReaderConstString __attribute((alias("xmlTextReaderConstString__internal_alias"))); +#else +#ifndef xmlTextReaderConstString +extern __typeof (xmlTextReaderConstString) xmlTextReaderConstString__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderConstString xmlTextReaderConstString__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderConstValue +extern __typeof (xmlTextReaderConstValue) xmlTextReaderConstValue __attribute((alias("xmlTextReaderConstValue__internal_alias"))); +#else +#ifndef xmlTextReaderConstValue +extern __typeof (xmlTextReaderConstValue) xmlTextReaderConstValue__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderConstValue xmlTextReaderConstValue__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderConstXmlLang +extern __typeof (xmlTextReaderConstXmlLang) xmlTextReaderConstXmlLang __attribute((alias("xmlTextReaderConstXmlLang__internal_alias"))); +#else +#ifndef xmlTextReaderConstXmlLang +extern __typeof (xmlTextReaderConstXmlLang) xmlTextReaderConstXmlLang__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderConstXmlLang xmlTextReaderConstXmlLang__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderConstXmlVersion +extern __typeof (xmlTextReaderConstXmlVersion) xmlTextReaderConstXmlVersion __attribute((alias("xmlTextReaderConstXmlVersion__internal_alias"))); +#else +#ifndef xmlTextReaderConstXmlVersion +extern __typeof (xmlTextReaderConstXmlVersion) xmlTextReaderConstXmlVersion__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderConstXmlVersion xmlTextReaderConstXmlVersion__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderCurrentDoc +extern __typeof (xmlTextReaderCurrentDoc) xmlTextReaderCurrentDoc __attribute((alias("xmlTextReaderCurrentDoc__internal_alias"))); +#else +#ifndef xmlTextReaderCurrentDoc +extern __typeof (xmlTextReaderCurrentDoc) xmlTextReaderCurrentDoc__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderCurrentDoc xmlTextReaderCurrentDoc__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderCurrentNode +extern __typeof (xmlTextReaderCurrentNode) xmlTextReaderCurrentNode __attribute((alias("xmlTextReaderCurrentNode__internal_alias"))); +#else +#ifndef xmlTextReaderCurrentNode +extern __typeof (xmlTextReaderCurrentNode) xmlTextReaderCurrentNode__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderCurrentNode xmlTextReaderCurrentNode__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderDepth +extern __typeof (xmlTextReaderDepth) xmlTextReaderDepth __attribute((alias("xmlTextReaderDepth__internal_alias"))); +#else +#ifndef xmlTextReaderDepth +extern __typeof (xmlTextReaderDepth) xmlTextReaderDepth__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderDepth xmlTextReaderDepth__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderExpand +extern __typeof (xmlTextReaderExpand) xmlTextReaderExpand __attribute((alias("xmlTextReaderExpand__internal_alias"))); +#else +#ifndef xmlTextReaderExpand +extern __typeof (xmlTextReaderExpand) xmlTextReaderExpand__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderExpand xmlTextReaderExpand__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderGetAttribute +extern __typeof (xmlTextReaderGetAttribute) xmlTextReaderGetAttribute __attribute((alias("xmlTextReaderGetAttribute__internal_alias"))); +#else +#ifndef xmlTextReaderGetAttribute +extern __typeof (xmlTextReaderGetAttribute) xmlTextReaderGetAttribute__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderGetAttribute xmlTextReaderGetAttribute__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderGetAttributeNo +extern __typeof (xmlTextReaderGetAttributeNo) xmlTextReaderGetAttributeNo __attribute((alias("xmlTextReaderGetAttributeNo__internal_alias"))); +#else +#ifndef xmlTextReaderGetAttributeNo +extern __typeof (xmlTextReaderGetAttributeNo) xmlTextReaderGetAttributeNo__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderGetAttributeNo xmlTextReaderGetAttributeNo__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderGetAttributeNs +extern __typeof (xmlTextReaderGetAttributeNs) xmlTextReaderGetAttributeNs __attribute((alias("xmlTextReaderGetAttributeNs__internal_alias"))); +#else +#ifndef xmlTextReaderGetAttributeNs +extern __typeof (xmlTextReaderGetAttributeNs) xmlTextReaderGetAttributeNs__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderGetAttributeNs xmlTextReaderGetAttributeNs__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderGetErrorHandler +extern __typeof (xmlTextReaderGetErrorHandler) xmlTextReaderGetErrorHandler __attribute((alias("xmlTextReaderGetErrorHandler__internal_alias"))); +#else +#ifndef xmlTextReaderGetErrorHandler +extern __typeof (xmlTextReaderGetErrorHandler) xmlTextReaderGetErrorHandler__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderGetErrorHandler xmlTextReaderGetErrorHandler__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderGetParserColumnNumber +extern __typeof (xmlTextReaderGetParserColumnNumber) xmlTextReaderGetParserColumnNumber __attribute((alias("xmlTextReaderGetParserColumnNumber__internal_alias"))); +#else +#ifndef xmlTextReaderGetParserColumnNumber +extern __typeof (xmlTextReaderGetParserColumnNumber) xmlTextReaderGetParserColumnNumber__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderGetParserColumnNumber xmlTextReaderGetParserColumnNumber__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderGetParserLineNumber +extern __typeof (xmlTextReaderGetParserLineNumber) xmlTextReaderGetParserLineNumber __attribute((alias("xmlTextReaderGetParserLineNumber__internal_alias"))); +#else +#ifndef xmlTextReaderGetParserLineNumber +extern __typeof (xmlTextReaderGetParserLineNumber) xmlTextReaderGetParserLineNumber__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderGetParserLineNumber xmlTextReaderGetParserLineNumber__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderGetParserProp +extern __typeof (xmlTextReaderGetParserProp) xmlTextReaderGetParserProp __attribute((alias("xmlTextReaderGetParserProp__internal_alias"))); +#else +#ifndef xmlTextReaderGetParserProp +extern __typeof (xmlTextReaderGetParserProp) xmlTextReaderGetParserProp__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderGetParserProp xmlTextReaderGetParserProp__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderGetRemainder +extern __typeof (xmlTextReaderGetRemainder) xmlTextReaderGetRemainder __attribute((alias("xmlTextReaderGetRemainder__internal_alias"))); +#else +#ifndef xmlTextReaderGetRemainder +extern __typeof (xmlTextReaderGetRemainder) xmlTextReaderGetRemainder__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderGetRemainder xmlTextReaderGetRemainder__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderHasAttributes +extern __typeof (xmlTextReaderHasAttributes) xmlTextReaderHasAttributes __attribute((alias("xmlTextReaderHasAttributes__internal_alias"))); +#else +#ifndef xmlTextReaderHasAttributes +extern __typeof (xmlTextReaderHasAttributes) xmlTextReaderHasAttributes__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderHasAttributes xmlTextReaderHasAttributes__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderHasValue +extern __typeof (xmlTextReaderHasValue) xmlTextReaderHasValue __attribute((alias("xmlTextReaderHasValue__internal_alias"))); +#else +#ifndef xmlTextReaderHasValue +extern __typeof (xmlTextReaderHasValue) xmlTextReaderHasValue__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderHasValue xmlTextReaderHasValue__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderIsDefault +extern __typeof (xmlTextReaderIsDefault) xmlTextReaderIsDefault __attribute((alias("xmlTextReaderIsDefault__internal_alias"))); +#else +#ifndef xmlTextReaderIsDefault +extern __typeof (xmlTextReaderIsDefault) xmlTextReaderIsDefault__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderIsDefault xmlTextReaderIsDefault__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderIsEmptyElement +extern __typeof (xmlTextReaderIsEmptyElement) xmlTextReaderIsEmptyElement __attribute((alias("xmlTextReaderIsEmptyElement__internal_alias"))); +#else +#ifndef xmlTextReaderIsEmptyElement +extern __typeof (xmlTextReaderIsEmptyElement) xmlTextReaderIsEmptyElement__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderIsEmptyElement xmlTextReaderIsEmptyElement__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderIsNamespaceDecl +extern __typeof (xmlTextReaderIsNamespaceDecl) xmlTextReaderIsNamespaceDecl __attribute((alias("xmlTextReaderIsNamespaceDecl__internal_alias"))); +#else +#ifndef xmlTextReaderIsNamespaceDecl +extern __typeof (xmlTextReaderIsNamespaceDecl) xmlTextReaderIsNamespaceDecl__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderIsNamespaceDecl xmlTextReaderIsNamespaceDecl__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderIsValid +extern __typeof (xmlTextReaderIsValid) xmlTextReaderIsValid __attribute((alias("xmlTextReaderIsValid__internal_alias"))); +#else +#ifndef xmlTextReaderIsValid +extern __typeof (xmlTextReaderIsValid) xmlTextReaderIsValid__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderIsValid xmlTextReaderIsValid__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderLocalName +extern __typeof (xmlTextReaderLocalName) xmlTextReaderLocalName __attribute((alias("xmlTextReaderLocalName__internal_alias"))); +#else +#ifndef xmlTextReaderLocalName +extern __typeof (xmlTextReaderLocalName) xmlTextReaderLocalName__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderLocalName xmlTextReaderLocalName__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderLocatorBaseURI +extern __typeof (xmlTextReaderLocatorBaseURI) xmlTextReaderLocatorBaseURI __attribute((alias("xmlTextReaderLocatorBaseURI__internal_alias"))); +#else +#ifndef xmlTextReaderLocatorBaseURI +extern __typeof (xmlTextReaderLocatorBaseURI) xmlTextReaderLocatorBaseURI__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderLocatorBaseURI xmlTextReaderLocatorBaseURI__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderLocatorLineNumber +extern __typeof (xmlTextReaderLocatorLineNumber) xmlTextReaderLocatorLineNumber __attribute((alias("xmlTextReaderLocatorLineNumber__internal_alias"))); +#else +#ifndef xmlTextReaderLocatorLineNumber +extern __typeof (xmlTextReaderLocatorLineNumber) xmlTextReaderLocatorLineNumber__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderLocatorLineNumber xmlTextReaderLocatorLineNumber__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderLookupNamespace +extern __typeof (xmlTextReaderLookupNamespace) xmlTextReaderLookupNamespace __attribute((alias("xmlTextReaderLookupNamespace__internal_alias"))); +#else +#ifndef xmlTextReaderLookupNamespace +extern __typeof (xmlTextReaderLookupNamespace) xmlTextReaderLookupNamespace__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderLookupNamespace xmlTextReaderLookupNamespace__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderMoveToAttribute +extern __typeof (xmlTextReaderMoveToAttribute) xmlTextReaderMoveToAttribute __attribute((alias("xmlTextReaderMoveToAttribute__internal_alias"))); +#else +#ifndef xmlTextReaderMoveToAttribute +extern __typeof (xmlTextReaderMoveToAttribute) xmlTextReaderMoveToAttribute__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderMoveToAttribute xmlTextReaderMoveToAttribute__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderMoveToAttributeNo +extern __typeof (xmlTextReaderMoveToAttributeNo) xmlTextReaderMoveToAttributeNo __attribute((alias("xmlTextReaderMoveToAttributeNo__internal_alias"))); +#else +#ifndef xmlTextReaderMoveToAttributeNo +extern __typeof (xmlTextReaderMoveToAttributeNo) xmlTextReaderMoveToAttributeNo__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderMoveToAttributeNo xmlTextReaderMoveToAttributeNo__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderMoveToAttributeNs +extern __typeof (xmlTextReaderMoveToAttributeNs) xmlTextReaderMoveToAttributeNs __attribute((alias("xmlTextReaderMoveToAttributeNs__internal_alias"))); +#else +#ifndef xmlTextReaderMoveToAttributeNs +extern __typeof (xmlTextReaderMoveToAttributeNs) xmlTextReaderMoveToAttributeNs__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderMoveToAttributeNs xmlTextReaderMoveToAttributeNs__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderMoveToElement +extern __typeof (xmlTextReaderMoveToElement) xmlTextReaderMoveToElement __attribute((alias("xmlTextReaderMoveToElement__internal_alias"))); +#else +#ifndef xmlTextReaderMoveToElement +extern __typeof (xmlTextReaderMoveToElement) xmlTextReaderMoveToElement__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderMoveToElement xmlTextReaderMoveToElement__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderMoveToFirstAttribute +extern __typeof (xmlTextReaderMoveToFirstAttribute) xmlTextReaderMoveToFirstAttribute __attribute((alias("xmlTextReaderMoveToFirstAttribute__internal_alias"))); +#else +#ifndef xmlTextReaderMoveToFirstAttribute +extern __typeof (xmlTextReaderMoveToFirstAttribute) xmlTextReaderMoveToFirstAttribute__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderMoveToFirstAttribute xmlTextReaderMoveToFirstAttribute__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderMoveToNextAttribute +extern __typeof (xmlTextReaderMoveToNextAttribute) xmlTextReaderMoveToNextAttribute __attribute((alias("xmlTextReaderMoveToNextAttribute__internal_alias"))); +#else +#ifndef xmlTextReaderMoveToNextAttribute +extern __typeof (xmlTextReaderMoveToNextAttribute) xmlTextReaderMoveToNextAttribute__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderMoveToNextAttribute xmlTextReaderMoveToNextAttribute__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderName +extern __typeof (xmlTextReaderName) xmlTextReaderName __attribute((alias("xmlTextReaderName__internal_alias"))); +#else +#ifndef xmlTextReaderName +extern __typeof (xmlTextReaderName) xmlTextReaderName__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderName xmlTextReaderName__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderNamespaceUri +extern __typeof (xmlTextReaderNamespaceUri) xmlTextReaderNamespaceUri __attribute((alias("xmlTextReaderNamespaceUri__internal_alias"))); +#else +#ifndef xmlTextReaderNamespaceUri +extern __typeof (xmlTextReaderNamespaceUri) xmlTextReaderNamespaceUri__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderNamespaceUri xmlTextReaderNamespaceUri__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderNext +extern __typeof (xmlTextReaderNext) xmlTextReaderNext __attribute((alias("xmlTextReaderNext__internal_alias"))); +#else +#ifndef xmlTextReaderNext +extern __typeof (xmlTextReaderNext) xmlTextReaderNext__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderNext xmlTextReaderNext__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderNextSibling +extern __typeof (xmlTextReaderNextSibling) xmlTextReaderNextSibling __attribute((alias("xmlTextReaderNextSibling__internal_alias"))); +#else +#ifndef xmlTextReaderNextSibling +extern __typeof (xmlTextReaderNextSibling) xmlTextReaderNextSibling__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderNextSibling xmlTextReaderNextSibling__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderNodeType +extern __typeof (xmlTextReaderNodeType) xmlTextReaderNodeType __attribute((alias("xmlTextReaderNodeType__internal_alias"))); +#else +#ifndef xmlTextReaderNodeType +extern __typeof (xmlTextReaderNodeType) xmlTextReaderNodeType__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderNodeType xmlTextReaderNodeType__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderNormalization +extern __typeof (xmlTextReaderNormalization) xmlTextReaderNormalization __attribute((alias("xmlTextReaderNormalization__internal_alias"))); +#else +#ifndef xmlTextReaderNormalization +extern __typeof (xmlTextReaderNormalization) xmlTextReaderNormalization__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderNormalization xmlTextReaderNormalization__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderPrefix +extern __typeof (xmlTextReaderPrefix) xmlTextReaderPrefix __attribute((alias("xmlTextReaderPrefix__internal_alias"))); +#else +#ifndef xmlTextReaderPrefix +extern __typeof (xmlTextReaderPrefix) xmlTextReaderPrefix__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderPrefix xmlTextReaderPrefix__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderPreserve +extern __typeof (xmlTextReaderPreserve) xmlTextReaderPreserve __attribute((alias("xmlTextReaderPreserve__internal_alias"))); +#else +#ifndef xmlTextReaderPreserve +extern __typeof (xmlTextReaderPreserve) xmlTextReaderPreserve__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderPreserve xmlTextReaderPreserve__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) && defined(LIBXML_PATTERN_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderPreservePattern +extern __typeof (xmlTextReaderPreservePattern) xmlTextReaderPreservePattern __attribute((alias("xmlTextReaderPreservePattern__internal_alias"))); +#else +#ifndef xmlTextReaderPreservePattern +extern __typeof (xmlTextReaderPreservePattern) xmlTextReaderPreservePattern__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderPreservePattern xmlTextReaderPreservePattern__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderQuoteChar +extern __typeof (xmlTextReaderQuoteChar) xmlTextReaderQuoteChar __attribute((alias("xmlTextReaderQuoteChar__internal_alias"))); +#else +#ifndef xmlTextReaderQuoteChar +extern __typeof (xmlTextReaderQuoteChar) xmlTextReaderQuoteChar__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderQuoteChar xmlTextReaderQuoteChar__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderRead +extern __typeof (xmlTextReaderRead) xmlTextReaderRead __attribute((alias("xmlTextReaderRead__internal_alias"))); +#else +#ifndef xmlTextReaderRead +extern __typeof (xmlTextReaderRead) xmlTextReaderRead__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderRead xmlTextReaderRead__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderReadAttributeValue +extern __typeof (xmlTextReaderReadAttributeValue) xmlTextReaderReadAttributeValue __attribute((alias("xmlTextReaderReadAttributeValue__internal_alias"))); +#else +#ifndef xmlTextReaderReadAttributeValue +extern __typeof (xmlTextReaderReadAttributeValue) xmlTextReaderReadAttributeValue__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderReadAttributeValue xmlTextReaderReadAttributeValue__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) && defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderReadInnerXml +extern __typeof (xmlTextReaderReadInnerXml) xmlTextReaderReadInnerXml __attribute((alias("xmlTextReaderReadInnerXml__internal_alias"))); +#else +#ifndef xmlTextReaderReadInnerXml +extern __typeof (xmlTextReaderReadInnerXml) xmlTextReaderReadInnerXml__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderReadInnerXml xmlTextReaderReadInnerXml__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) && defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderReadOuterXml +extern __typeof (xmlTextReaderReadOuterXml) xmlTextReaderReadOuterXml __attribute((alias("xmlTextReaderReadOuterXml__internal_alias"))); +#else +#ifndef xmlTextReaderReadOuterXml +extern __typeof (xmlTextReaderReadOuterXml) xmlTextReaderReadOuterXml__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderReadOuterXml xmlTextReaderReadOuterXml__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderReadState +extern __typeof (xmlTextReaderReadState) xmlTextReaderReadState __attribute((alias("xmlTextReaderReadState__internal_alias"))); +#else +#ifndef xmlTextReaderReadState +extern __typeof (xmlTextReaderReadState) xmlTextReaderReadState__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderReadState xmlTextReaderReadState__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderReadString +extern __typeof (xmlTextReaderReadString) xmlTextReaderReadString __attribute((alias("xmlTextReaderReadString__internal_alias"))); +#else +#ifndef xmlTextReaderReadString +extern __typeof (xmlTextReaderReadString) xmlTextReaderReadString__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderReadString xmlTextReaderReadString__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) && defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderRelaxNGSetSchema +extern __typeof (xmlTextReaderRelaxNGSetSchema) xmlTextReaderRelaxNGSetSchema __attribute((alias("xmlTextReaderRelaxNGSetSchema__internal_alias"))); +#else +#ifndef xmlTextReaderRelaxNGSetSchema +extern __typeof (xmlTextReaderRelaxNGSetSchema) xmlTextReaderRelaxNGSetSchema__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderRelaxNGSetSchema xmlTextReaderRelaxNGSetSchema__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) && defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderRelaxNGValidate +extern __typeof (xmlTextReaderRelaxNGValidate) xmlTextReaderRelaxNGValidate __attribute((alias("xmlTextReaderRelaxNGValidate__internal_alias"))); +#else +#ifndef xmlTextReaderRelaxNGValidate +extern __typeof (xmlTextReaderRelaxNGValidate) xmlTextReaderRelaxNGValidate__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderRelaxNGValidate xmlTextReaderRelaxNGValidate__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) && defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderSchemaValidate +extern __typeof (xmlTextReaderSchemaValidate) xmlTextReaderSchemaValidate __attribute((alias("xmlTextReaderSchemaValidate__internal_alias"))); +#else +#ifndef xmlTextReaderSchemaValidate +extern __typeof (xmlTextReaderSchemaValidate) xmlTextReaderSchemaValidate__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderSchemaValidate xmlTextReaderSchemaValidate__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) && defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderSchemaValidateCtxt +extern __typeof (xmlTextReaderSchemaValidateCtxt) xmlTextReaderSchemaValidateCtxt __attribute((alias("xmlTextReaderSchemaValidateCtxt__internal_alias"))); +#else +#ifndef xmlTextReaderSchemaValidateCtxt +extern __typeof (xmlTextReaderSchemaValidateCtxt) xmlTextReaderSchemaValidateCtxt__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderSchemaValidateCtxt xmlTextReaderSchemaValidateCtxt__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderSetErrorHandler +extern __typeof (xmlTextReaderSetErrorHandler) xmlTextReaderSetErrorHandler __attribute((alias("xmlTextReaderSetErrorHandler__internal_alias"))); +#else +#ifndef xmlTextReaderSetErrorHandler +extern __typeof (xmlTextReaderSetErrorHandler) xmlTextReaderSetErrorHandler__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderSetErrorHandler xmlTextReaderSetErrorHandler__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderSetParserProp +extern __typeof (xmlTextReaderSetParserProp) xmlTextReaderSetParserProp __attribute((alias("xmlTextReaderSetParserProp__internal_alias"))); +#else +#ifndef xmlTextReaderSetParserProp +extern __typeof (xmlTextReaderSetParserProp) xmlTextReaderSetParserProp__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderSetParserProp xmlTextReaderSetParserProp__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) && defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderSetSchema +extern __typeof (xmlTextReaderSetSchema) xmlTextReaderSetSchema __attribute((alias("xmlTextReaderSetSchema__internal_alias"))); +#else +#ifndef xmlTextReaderSetSchema +extern __typeof (xmlTextReaderSetSchema) xmlTextReaderSetSchema__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderSetSchema xmlTextReaderSetSchema__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderSetStructuredErrorHandler +extern __typeof (xmlTextReaderSetStructuredErrorHandler) xmlTextReaderSetStructuredErrorHandler __attribute((alias("xmlTextReaderSetStructuredErrorHandler__internal_alias"))); +#else +#ifndef xmlTextReaderSetStructuredErrorHandler +extern __typeof (xmlTextReaderSetStructuredErrorHandler) xmlTextReaderSetStructuredErrorHandler__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderSetStructuredErrorHandler xmlTextReaderSetStructuredErrorHandler__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderSetup +extern __typeof (xmlTextReaderSetup) xmlTextReaderSetup __attribute((alias("xmlTextReaderSetup__internal_alias"))); +#else +#ifndef xmlTextReaderSetup +extern __typeof (xmlTextReaderSetup) xmlTextReaderSetup__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderSetup xmlTextReaderSetup__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderStandalone +extern __typeof (xmlTextReaderStandalone) xmlTextReaderStandalone __attribute((alias("xmlTextReaderStandalone__internal_alias"))); +#else +#ifndef xmlTextReaderStandalone +extern __typeof (xmlTextReaderStandalone) xmlTextReaderStandalone__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderStandalone xmlTextReaderStandalone__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderValue +extern __typeof (xmlTextReaderValue) xmlTextReaderValue __attribute((alias("xmlTextReaderValue__internal_alias"))); +#else +#ifndef xmlTextReaderValue +extern __typeof (xmlTextReaderValue) xmlTextReaderValue__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderValue xmlTextReaderValue__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_READER_ENABLED) +#ifdef bottom_xmlreader +#undef xmlTextReaderXmlLang +extern __typeof (xmlTextReaderXmlLang) xmlTextReaderXmlLang __attribute((alias("xmlTextReaderXmlLang__internal_alias"))); +#else +#ifndef xmlTextReaderXmlLang +extern __typeof (xmlTextReaderXmlLang) xmlTextReaderXmlLang__internal_alias __attribute((visibility("hidden"))); +#define xmlTextReaderXmlLang xmlTextReaderXmlLang__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterEndAttribute +extern __typeof (xmlTextWriterEndAttribute) xmlTextWriterEndAttribute __attribute((alias("xmlTextWriterEndAttribute__internal_alias"))); +#else +#ifndef xmlTextWriterEndAttribute +extern __typeof (xmlTextWriterEndAttribute) xmlTextWriterEndAttribute__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterEndAttribute xmlTextWriterEndAttribute__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterEndCDATA +extern __typeof (xmlTextWriterEndCDATA) xmlTextWriterEndCDATA __attribute((alias("xmlTextWriterEndCDATA__internal_alias"))); +#else +#ifndef xmlTextWriterEndCDATA +extern __typeof (xmlTextWriterEndCDATA) xmlTextWriterEndCDATA__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterEndCDATA xmlTextWriterEndCDATA__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterEndComment +extern __typeof (xmlTextWriterEndComment) xmlTextWriterEndComment __attribute((alias("xmlTextWriterEndComment__internal_alias"))); +#else +#ifndef xmlTextWriterEndComment +extern __typeof (xmlTextWriterEndComment) xmlTextWriterEndComment__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterEndComment xmlTextWriterEndComment__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterEndDTD +extern __typeof (xmlTextWriterEndDTD) xmlTextWriterEndDTD __attribute((alias("xmlTextWriterEndDTD__internal_alias"))); +#else +#ifndef xmlTextWriterEndDTD +extern __typeof (xmlTextWriterEndDTD) xmlTextWriterEndDTD__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterEndDTD xmlTextWriterEndDTD__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterEndDTDAttlist +extern __typeof (xmlTextWriterEndDTDAttlist) xmlTextWriterEndDTDAttlist __attribute((alias("xmlTextWriterEndDTDAttlist__internal_alias"))); +#else +#ifndef xmlTextWriterEndDTDAttlist +extern __typeof (xmlTextWriterEndDTDAttlist) xmlTextWriterEndDTDAttlist__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterEndDTDAttlist xmlTextWriterEndDTDAttlist__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterEndDTDElement +extern __typeof (xmlTextWriterEndDTDElement) xmlTextWriterEndDTDElement __attribute((alias("xmlTextWriterEndDTDElement__internal_alias"))); +#else +#ifndef xmlTextWriterEndDTDElement +extern __typeof (xmlTextWriterEndDTDElement) xmlTextWriterEndDTDElement__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterEndDTDElement xmlTextWriterEndDTDElement__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterEndDTDEntity +extern __typeof (xmlTextWriterEndDTDEntity) xmlTextWriterEndDTDEntity __attribute((alias("xmlTextWriterEndDTDEntity__internal_alias"))); +#else +#ifndef xmlTextWriterEndDTDEntity +extern __typeof (xmlTextWriterEndDTDEntity) xmlTextWriterEndDTDEntity__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterEndDTDEntity xmlTextWriterEndDTDEntity__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterEndDocument +extern __typeof (xmlTextWriterEndDocument) xmlTextWriterEndDocument __attribute((alias("xmlTextWriterEndDocument__internal_alias"))); +#else +#ifndef xmlTextWriterEndDocument +extern __typeof (xmlTextWriterEndDocument) xmlTextWriterEndDocument__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterEndDocument xmlTextWriterEndDocument__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterEndElement +extern __typeof (xmlTextWriterEndElement) xmlTextWriterEndElement __attribute((alias("xmlTextWriterEndElement__internal_alias"))); +#else +#ifndef xmlTextWriterEndElement +extern __typeof (xmlTextWriterEndElement) xmlTextWriterEndElement__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterEndElement xmlTextWriterEndElement__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterEndPI +extern __typeof (xmlTextWriterEndPI) xmlTextWriterEndPI __attribute((alias("xmlTextWriterEndPI__internal_alias"))); +#else +#ifndef xmlTextWriterEndPI +extern __typeof (xmlTextWriterEndPI) xmlTextWriterEndPI__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterEndPI xmlTextWriterEndPI__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterFlush +extern __typeof (xmlTextWriterFlush) xmlTextWriterFlush __attribute((alias("xmlTextWriterFlush__internal_alias"))); +#else +#ifndef xmlTextWriterFlush +extern __typeof (xmlTextWriterFlush) xmlTextWriterFlush__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterFlush xmlTextWriterFlush__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterFullEndElement +extern __typeof (xmlTextWriterFullEndElement) xmlTextWriterFullEndElement __attribute((alias("xmlTextWriterFullEndElement__internal_alias"))); +#else +#ifndef xmlTextWriterFullEndElement +extern __typeof (xmlTextWriterFullEndElement) xmlTextWriterFullEndElement__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterFullEndElement xmlTextWriterFullEndElement__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterSetIndent +extern __typeof (xmlTextWriterSetIndent) xmlTextWriterSetIndent __attribute((alias("xmlTextWriterSetIndent__internal_alias"))); +#else +#ifndef xmlTextWriterSetIndent +extern __typeof (xmlTextWriterSetIndent) xmlTextWriterSetIndent__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterSetIndent xmlTextWriterSetIndent__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterSetIndentString +extern __typeof (xmlTextWriterSetIndentString) xmlTextWriterSetIndentString __attribute((alias("xmlTextWriterSetIndentString__internal_alias"))); +#else +#ifndef xmlTextWriterSetIndentString +extern __typeof (xmlTextWriterSetIndentString) xmlTextWriterSetIndentString__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterSetIndentString xmlTextWriterSetIndentString__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterStartAttribute +extern __typeof (xmlTextWriterStartAttribute) xmlTextWriterStartAttribute __attribute((alias("xmlTextWriterStartAttribute__internal_alias"))); +#else +#ifndef xmlTextWriterStartAttribute +extern __typeof (xmlTextWriterStartAttribute) xmlTextWriterStartAttribute__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterStartAttribute xmlTextWriterStartAttribute__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterStartAttributeNS +extern __typeof (xmlTextWriterStartAttributeNS) xmlTextWriterStartAttributeNS __attribute((alias("xmlTextWriterStartAttributeNS__internal_alias"))); +#else +#ifndef xmlTextWriterStartAttributeNS +extern __typeof (xmlTextWriterStartAttributeNS) xmlTextWriterStartAttributeNS__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterStartAttributeNS xmlTextWriterStartAttributeNS__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterStartCDATA +extern __typeof (xmlTextWriterStartCDATA) xmlTextWriterStartCDATA __attribute((alias("xmlTextWriterStartCDATA__internal_alias"))); +#else +#ifndef xmlTextWriterStartCDATA +extern __typeof (xmlTextWriterStartCDATA) xmlTextWriterStartCDATA__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterStartCDATA xmlTextWriterStartCDATA__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterStartComment +extern __typeof (xmlTextWriterStartComment) xmlTextWriterStartComment __attribute((alias("xmlTextWriterStartComment__internal_alias"))); +#else +#ifndef xmlTextWriterStartComment +extern __typeof (xmlTextWriterStartComment) xmlTextWriterStartComment__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterStartComment xmlTextWriterStartComment__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterStartDTD +extern __typeof (xmlTextWriterStartDTD) xmlTextWriterStartDTD __attribute((alias("xmlTextWriterStartDTD__internal_alias"))); +#else +#ifndef xmlTextWriterStartDTD +extern __typeof (xmlTextWriterStartDTD) xmlTextWriterStartDTD__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterStartDTD xmlTextWriterStartDTD__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterStartDTDAttlist +extern __typeof (xmlTextWriterStartDTDAttlist) xmlTextWriterStartDTDAttlist __attribute((alias("xmlTextWriterStartDTDAttlist__internal_alias"))); +#else +#ifndef xmlTextWriterStartDTDAttlist +extern __typeof (xmlTextWriterStartDTDAttlist) xmlTextWriterStartDTDAttlist__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterStartDTDAttlist xmlTextWriterStartDTDAttlist__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterStartDTDElement +extern __typeof (xmlTextWriterStartDTDElement) xmlTextWriterStartDTDElement __attribute((alias("xmlTextWriterStartDTDElement__internal_alias"))); +#else +#ifndef xmlTextWriterStartDTDElement +extern __typeof (xmlTextWriterStartDTDElement) xmlTextWriterStartDTDElement__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterStartDTDElement xmlTextWriterStartDTDElement__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterStartDTDEntity +extern __typeof (xmlTextWriterStartDTDEntity) xmlTextWriterStartDTDEntity __attribute((alias("xmlTextWriterStartDTDEntity__internal_alias"))); +#else +#ifndef xmlTextWriterStartDTDEntity +extern __typeof (xmlTextWriterStartDTDEntity) xmlTextWriterStartDTDEntity__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterStartDTDEntity xmlTextWriterStartDTDEntity__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterStartDocument +extern __typeof (xmlTextWriterStartDocument) xmlTextWriterStartDocument __attribute((alias("xmlTextWriterStartDocument__internal_alias"))); +#else +#ifndef xmlTextWriterStartDocument +extern __typeof (xmlTextWriterStartDocument) xmlTextWriterStartDocument__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterStartDocument xmlTextWriterStartDocument__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterStartElement +extern __typeof (xmlTextWriterStartElement) xmlTextWriterStartElement __attribute((alias("xmlTextWriterStartElement__internal_alias"))); +#else +#ifndef xmlTextWriterStartElement +extern __typeof (xmlTextWriterStartElement) xmlTextWriterStartElement__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterStartElement xmlTextWriterStartElement__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterStartElementNS +extern __typeof (xmlTextWriterStartElementNS) xmlTextWriterStartElementNS __attribute((alias("xmlTextWriterStartElementNS__internal_alias"))); +#else +#ifndef xmlTextWriterStartElementNS +extern __typeof (xmlTextWriterStartElementNS) xmlTextWriterStartElementNS__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterStartElementNS xmlTextWriterStartElementNS__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterStartPI +extern __typeof (xmlTextWriterStartPI) xmlTextWriterStartPI __attribute((alias("xmlTextWriterStartPI__internal_alias"))); +#else +#ifndef xmlTextWriterStartPI +extern __typeof (xmlTextWriterStartPI) xmlTextWriterStartPI__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterStartPI xmlTextWriterStartPI__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterWriteAttribute +extern __typeof (xmlTextWriterWriteAttribute) xmlTextWriterWriteAttribute __attribute((alias("xmlTextWriterWriteAttribute__internal_alias"))); +#else +#ifndef xmlTextWriterWriteAttribute +extern __typeof (xmlTextWriterWriteAttribute) xmlTextWriterWriteAttribute__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterWriteAttribute xmlTextWriterWriteAttribute__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterWriteAttributeNS +extern __typeof (xmlTextWriterWriteAttributeNS) xmlTextWriterWriteAttributeNS __attribute((alias("xmlTextWriterWriteAttributeNS__internal_alias"))); +#else +#ifndef xmlTextWriterWriteAttributeNS +extern __typeof (xmlTextWriterWriteAttributeNS) xmlTextWriterWriteAttributeNS__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterWriteAttributeNS xmlTextWriterWriteAttributeNS__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterWriteBase64 +extern __typeof (xmlTextWriterWriteBase64) xmlTextWriterWriteBase64 __attribute((alias("xmlTextWriterWriteBase64__internal_alias"))); +#else +#ifndef xmlTextWriterWriteBase64 +extern __typeof (xmlTextWriterWriteBase64) xmlTextWriterWriteBase64__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterWriteBase64 xmlTextWriterWriteBase64__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterWriteBinHex +extern __typeof (xmlTextWriterWriteBinHex) xmlTextWriterWriteBinHex __attribute((alias("xmlTextWriterWriteBinHex__internal_alias"))); +#else +#ifndef xmlTextWriterWriteBinHex +extern __typeof (xmlTextWriterWriteBinHex) xmlTextWriterWriteBinHex__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterWriteBinHex xmlTextWriterWriteBinHex__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterWriteCDATA +extern __typeof (xmlTextWriterWriteCDATA) xmlTextWriterWriteCDATA __attribute((alias("xmlTextWriterWriteCDATA__internal_alias"))); +#else +#ifndef xmlTextWriterWriteCDATA +extern __typeof (xmlTextWriterWriteCDATA) xmlTextWriterWriteCDATA__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterWriteCDATA xmlTextWriterWriteCDATA__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterWriteComment +extern __typeof (xmlTextWriterWriteComment) xmlTextWriterWriteComment __attribute((alias("xmlTextWriterWriteComment__internal_alias"))); +#else +#ifndef xmlTextWriterWriteComment +extern __typeof (xmlTextWriterWriteComment) xmlTextWriterWriteComment__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterWriteComment xmlTextWriterWriteComment__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterWriteDTD +extern __typeof (xmlTextWriterWriteDTD) xmlTextWriterWriteDTD __attribute((alias("xmlTextWriterWriteDTD__internal_alias"))); +#else +#ifndef xmlTextWriterWriteDTD +extern __typeof (xmlTextWriterWriteDTD) xmlTextWriterWriteDTD__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterWriteDTD xmlTextWriterWriteDTD__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterWriteDTDAttlist +extern __typeof (xmlTextWriterWriteDTDAttlist) xmlTextWriterWriteDTDAttlist __attribute((alias("xmlTextWriterWriteDTDAttlist__internal_alias"))); +#else +#ifndef xmlTextWriterWriteDTDAttlist +extern __typeof (xmlTextWriterWriteDTDAttlist) xmlTextWriterWriteDTDAttlist__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterWriteDTDAttlist xmlTextWriterWriteDTDAttlist__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterWriteDTDElement +extern __typeof (xmlTextWriterWriteDTDElement) xmlTextWriterWriteDTDElement __attribute((alias("xmlTextWriterWriteDTDElement__internal_alias"))); +#else +#ifndef xmlTextWriterWriteDTDElement +extern __typeof (xmlTextWriterWriteDTDElement) xmlTextWriterWriteDTDElement__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterWriteDTDElement xmlTextWriterWriteDTDElement__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterWriteDTDEntity +extern __typeof (xmlTextWriterWriteDTDEntity) xmlTextWriterWriteDTDEntity __attribute((alias("xmlTextWriterWriteDTDEntity__internal_alias"))); +#else +#ifndef xmlTextWriterWriteDTDEntity +extern __typeof (xmlTextWriterWriteDTDEntity) xmlTextWriterWriteDTDEntity__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterWriteDTDEntity xmlTextWriterWriteDTDEntity__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterWriteDTDExternalEntity +extern __typeof (xmlTextWriterWriteDTDExternalEntity) xmlTextWriterWriteDTDExternalEntity __attribute((alias("xmlTextWriterWriteDTDExternalEntity__internal_alias"))); +#else +#ifndef xmlTextWriterWriteDTDExternalEntity +extern __typeof (xmlTextWriterWriteDTDExternalEntity) xmlTextWriterWriteDTDExternalEntity__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterWriteDTDExternalEntity xmlTextWriterWriteDTDExternalEntity__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterWriteDTDExternalEntityContents +extern __typeof (xmlTextWriterWriteDTDExternalEntityContents) xmlTextWriterWriteDTDExternalEntityContents __attribute((alias("xmlTextWriterWriteDTDExternalEntityContents__internal_alias"))); +#else +#ifndef xmlTextWriterWriteDTDExternalEntityContents +extern __typeof (xmlTextWriterWriteDTDExternalEntityContents) xmlTextWriterWriteDTDExternalEntityContents__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterWriteDTDExternalEntityContents xmlTextWriterWriteDTDExternalEntityContents__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterWriteDTDInternalEntity +extern __typeof (xmlTextWriterWriteDTDInternalEntity) xmlTextWriterWriteDTDInternalEntity __attribute((alias("xmlTextWriterWriteDTDInternalEntity__internal_alias"))); +#else +#ifndef xmlTextWriterWriteDTDInternalEntity +extern __typeof (xmlTextWriterWriteDTDInternalEntity) xmlTextWriterWriteDTDInternalEntity__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterWriteDTDInternalEntity xmlTextWriterWriteDTDInternalEntity__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterWriteDTDNotation +extern __typeof (xmlTextWriterWriteDTDNotation) xmlTextWriterWriteDTDNotation __attribute((alias("xmlTextWriterWriteDTDNotation__internal_alias"))); +#else +#ifndef xmlTextWriterWriteDTDNotation +extern __typeof (xmlTextWriterWriteDTDNotation) xmlTextWriterWriteDTDNotation__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterWriteDTDNotation xmlTextWriterWriteDTDNotation__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterWriteElement +extern __typeof (xmlTextWriterWriteElement) xmlTextWriterWriteElement __attribute((alias("xmlTextWriterWriteElement__internal_alias"))); +#else +#ifndef xmlTextWriterWriteElement +extern __typeof (xmlTextWriterWriteElement) xmlTextWriterWriteElement__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterWriteElement xmlTextWriterWriteElement__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterWriteElementNS +extern __typeof (xmlTextWriterWriteElementNS) xmlTextWriterWriteElementNS __attribute((alias("xmlTextWriterWriteElementNS__internal_alias"))); +#else +#ifndef xmlTextWriterWriteElementNS +extern __typeof (xmlTextWriterWriteElementNS) xmlTextWriterWriteElementNS__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterWriteElementNS xmlTextWriterWriteElementNS__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterWriteFormatAttribute +extern __typeof (xmlTextWriterWriteFormatAttribute) xmlTextWriterWriteFormatAttribute __attribute((alias("xmlTextWriterWriteFormatAttribute__internal_alias"))); +#else +#ifndef xmlTextWriterWriteFormatAttribute +extern __typeof (xmlTextWriterWriteFormatAttribute) xmlTextWriterWriteFormatAttribute__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterWriteFormatAttribute xmlTextWriterWriteFormatAttribute__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterWriteFormatAttributeNS +extern __typeof (xmlTextWriterWriteFormatAttributeNS) xmlTextWriterWriteFormatAttributeNS __attribute((alias("xmlTextWriterWriteFormatAttributeNS__internal_alias"))); +#else +#ifndef xmlTextWriterWriteFormatAttributeNS +extern __typeof (xmlTextWriterWriteFormatAttributeNS) xmlTextWriterWriteFormatAttributeNS__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterWriteFormatAttributeNS xmlTextWriterWriteFormatAttributeNS__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterWriteFormatCDATA +extern __typeof (xmlTextWriterWriteFormatCDATA) xmlTextWriterWriteFormatCDATA __attribute((alias("xmlTextWriterWriteFormatCDATA__internal_alias"))); +#else +#ifndef xmlTextWriterWriteFormatCDATA +extern __typeof (xmlTextWriterWriteFormatCDATA) xmlTextWriterWriteFormatCDATA__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterWriteFormatCDATA xmlTextWriterWriteFormatCDATA__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterWriteFormatComment +extern __typeof (xmlTextWriterWriteFormatComment) xmlTextWriterWriteFormatComment __attribute((alias("xmlTextWriterWriteFormatComment__internal_alias"))); +#else +#ifndef xmlTextWriterWriteFormatComment +extern __typeof (xmlTextWriterWriteFormatComment) xmlTextWriterWriteFormatComment__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterWriteFormatComment xmlTextWriterWriteFormatComment__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterWriteFormatDTD +extern __typeof (xmlTextWriterWriteFormatDTD) xmlTextWriterWriteFormatDTD __attribute((alias("xmlTextWriterWriteFormatDTD__internal_alias"))); +#else +#ifndef xmlTextWriterWriteFormatDTD +extern __typeof (xmlTextWriterWriteFormatDTD) xmlTextWriterWriteFormatDTD__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterWriteFormatDTD xmlTextWriterWriteFormatDTD__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterWriteFormatDTDAttlist +extern __typeof (xmlTextWriterWriteFormatDTDAttlist) xmlTextWriterWriteFormatDTDAttlist __attribute((alias("xmlTextWriterWriteFormatDTDAttlist__internal_alias"))); +#else +#ifndef xmlTextWriterWriteFormatDTDAttlist +extern __typeof (xmlTextWriterWriteFormatDTDAttlist) xmlTextWriterWriteFormatDTDAttlist__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterWriteFormatDTDAttlist xmlTextWriterWriteFormatDTDAttlist__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterWriteFormatDTDElement +extern __typeof (xmlTextWriterWriteFormatDTDElement) xmlTextWriterWriteFormatDTDElement __attribute((alias("xmlTextWriterWriteFormatDTDElement__internal_alias"))); +#else +#ifndef xmlTextWriterWriteFormatDTDElement +extern __typeof (xmlTextWriterWriteFormatDTDElement) xmlTextWriterWriteFormatDTDElement__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterWriteFormatDTDElement xmlTextWriterWriteFormatDTDElement__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterWriteFormatDTDInternalEntity +extern __typeof (xmlTextWriterWriteFormatDTDInternalEntity) xmlTextWriterWriteFormatDTDInternalEntity __attribute((alias("xmlTextWriterWriteFormatDTDInternalEntity__internal_alias"))); +#else +#ifndef xmlTextWriterWriteFormatDTDInternalEntity +extern __typeof (xmlTextWriterWriteFormatDTDInternalEntity) xmlTextWriterWriteFormatDTDInternalEntity__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterWriteFormatDTDInternalEntity xmlTextWriterWriteFormatDTDInternalEntity__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterWriteFormatElement +extern __typeof (xmlTextWriterWriteFormatElement) xmlTextWriterWriteFormatElement __attribute((alias("xmlTextWriterWriteFormatElement__internal_alias"))); +#else +#ifndef xmlTextWriterWriteFormatElement +extern __typeof (xmlTextWriterWriteFormatElement) xmlTextWriterWriteFormatElement__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterWriteFormatElement xmlTextWriterWriteFormatElement__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterWriteFormatElementNS +extern __typeof (xmlTextWriterWriteFormatElementNS) xmlTextWriterWriteFormatElementNS __attribute((alias("xmlTextWriterWriteFormatElementNS__internal_alias"))); +#else +#ifndef xmlTextWriterWriteFormatElementNS +extern __typeof (xmlTextWriterWriteFormatElementNS) xmlTextWriterWriteFormatElementNS__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterWriteFormatElementNS xmlTextWriterWriteFormatElementNS__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterWriteFormatPI +extern __typeof (xmlTextWriterWriteFormatPI) xmlTextWriterWriteFormatPI __attribute((alias("xmlTextWriterWriteFormatPI__internal_alias"))); +#else +#ifndef xmlTextWriterWriteFormatPI +extern __typeof (xmlTextWriterWriteFormatPI) xmlTextWriterWriteFormatPI__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterWriteFormatPI xmlTextWriterWriteFormatPI__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterWriteFormatRaw +extern __typeof (xmlTextWriterWriteFormatRaw) xmlTextWriterWriteFormatRaw __attribute((alias("xmlTextWriterWriteFormatRaw__internal_alias"))); +#else +#ifndef xmlTextWriterWriteFormatRaw +extern __typeof (xmlTextWriterWriteFormatRaw) xmlTextWriterWriteFormatRaw__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterWriteFormatRaw xmlTextWriterWriteFormatRaw__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterWriteFormatString +extern __typeof (xmlTextWriterWriteFormatString) xmlTextWriterWriteFormatString __attribute((alias("xmlTextWriterWriteFormatString__internal_alias"))); +#else +#ifndef xmlTextWriterWriteFormatString +extern __typeof (xmlTextWriterWriteFormatString) xmlTextWriterWriteFormatString__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterWriteFormatString xmlTextWriterWriteFormatString__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterWritePI +extern __typeof (xmlTextWriterWritePI) xmlTextWriterWritePI __attribute((alias("xmlTextWriterWritePI__internal_alias"))); +#else +#ifndef xmlTextWriterWritePI +extern __typeof (xmlTextWriterWritePI) xmlTextWriterWritePI__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterWritePI xmlTextWriterWritePI__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterWriteRaw +extern __typeof (xmlTextWriterWriteRaw) xmlTextWriterWriteRaw __attribute((alias("xmlTextWriterWriteRaw__internal_alias"))); +#else +#ifndef xmlTextWriterWriteRaw +extern __typeof (xmlTextWriterWriteRaw) xmlTextWriterWriteRaw__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterWriteRaw xmlTextWriterWriteRaw__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterWriteRawLen +extern __typeof (xmlTextWriterWriteRawLen) xmlTextWriterWriteRawLen __attribute((alias("xmlTextWriterWriteRawLen__internal_alias"))); +#else +#ifndef xmlTextWriterWriteRawLen +extern __typeof (xmlTextWriterWriteRawLen) xmlTextWriterWriteRawLen__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterWriteRawLen xmlTextWriterWriteRawLen__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterWriteString +extern __typeof (xmlTextWriterWriteString) xmlTextWriterWriteString __attribute((alias("xmlTextWriterWriteString__internal_alias"))); +#else +#ifndef xmlTextWriterWriteString +extern __typeof (xmlTextWriterWriteString) xmlTextWriterWriteString__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterWriteString xmlTextWriterWriteString__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterWriteVFormatAttribute +extern __typeof (xmlTextWriterWriteVFormatAttribute) xmlTextWriterWriteVFormatAttribute __attribute((alias("xmlTextWriterWriteVFormatAttribute__internal_alias"))); +#else +#ifndef xmlTextWriterWriteVFormatAttribute +extern __typeof (xmlTextWriterWriteVFormatAttribute) xmlTextWriterWriteVFormatAttribute__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterWriteVFormatAttribute xmlTextWriterWriteVFormatAttribute__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterWriteVFormatAttributeNS +extern __typeof (xmlTextWriterWriteVFormatAttributeNS) xmlTextWriterWriteVFormatAttributeNS __attribute((alias("xmlTextWriterWriteVFormatAttributeNS__internal_alias"))); +#else +#ifndef xmlTextWriterWriteVFormatAttributeNS +extern __typeof (xmlTextWriterWriteVFormatAttributeNS) xmlTextWriterWriteVFormatAttributeNS__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterWriteVFormatAttributeNS xmlTextWriterWriteVFormatAttributeNS__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterWriteVFormatCDATA +extern __typeof (xmlTextWriterWriteVFormatCDATA) xmlTextWriterWriteVFormatCDATA __attribute((alias("xmlTextWriterWriteVFormatCDATA__internal_alias"))); +#else +#ifndef xmlTextWriterWriteVFormatCDATA +extern __typeof (xmlTextWriterWriteVFormatCDATA) xmlTextWriterWriteVFormatCDATA__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterWriteVFormatCDATA xmlTextWriterWriteVFormatCDATA__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterWriteVFormatComment +extern __typeof (xmlTextWriterWriteVFormatComment) xmlTextWriterWriteVFormatComment __attribute((alias("xmlTextWriterWriteVFormatComment__internal_alias"))); +#else +#ifndef xmlTextWriterWriteVFormatComment +extern __typeof (xmlTextWriterWriteVFormatComment) xmlTextWriterWriteVFormatComment__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterWriteVFormatComment xmlTextWriterWriteVFormatComment__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterWriteVFormatDTD +extern __typeof (xmlTextWriterWriteVFormatDTD) xmlTextWriterWriteVFormatDTD __attribute((alias("xmlTextWriterWriteVFormatDTD__internal_alias"))); +#else +#ifndef xmlTextWriterWriteVFormatDTD +extern __typeof (xmlTextWriterWriteVFormatDTD) xmlTextWriterWriteVFormatDTD__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterWriteVFormatDTD xmlTextWriterWriteVFormatDTD__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterWriteVFormatDTDAttlist +extern __typeof (xmlTextWriterWriteVFormatDTDAttlist) xmlTextWriterWriteVFormatDTDAttlist __attribute((alias("xmlTextWriterWriteVFormatDTDAttlist__internal_alias"))); +#else +#ifndef xmlTextWriterWriteVFormatDTDAttlist +extern __typeof (xmlTextWriterWriteVFormatDTDAttlist) xmlTextWriterWriteVFormatDTDAttlist__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterWriteVFormatDTDAttlist xmlTextWriterWriteVFormatDTDAttlist__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterWriteVFormatDTDElement +extern __typeof (xmlTextWriterWriteVFormatDTDElement) xmlTextWriterWriteVFormatDTDElement __attribute((alias("xmlTextWriterWriteVFormatDTDElement__internal_alias"))); +#else +#ifndef xmlTextWriterWriteVFormatDTDElement +extern __typeof (xmlTextWriterWriteVFormatDTDElement) xmlTextWriterWriteVFormatDTDElement__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterWriteVFormatDTDElement xmlTextWriterWriteVFormatDTDElement__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterWriteVFormatDTDInternalEntity +extern __typeof (xmlTextWriterWriteVFormatDTDInternalEntity) xmlTextWriterWriteVFormatDTDInternalEntity __attribute((alias("xmlTextWriterWriteVFormatDTDInternalEntity__internal_alias"))); +#else +#ifndef xmlTextWriterWriteVFormatDTDInternalEntity +extern __typeof (xmlTextWriterWriteVFormatDTDInternalEntity) xmlTextWriterWriteVFormatDTDInternalEntity__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterWriteVFormatDTDInternalEntity xmlTextWriterWriteVFormatDTDInternalEntity__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterWriteVFormatElement +extern __typeof (xmlTextWriterWriteVFormatElement) xmlTextWriterWriteVFormatElement __attribute((alias("xmlTextWriterWriteVFormatElement__internal_alias"))); +#else +#ifndef xmlTextWriterWriteVFormatElement +extern __typeof (xmlTextWriterWriteVFormatElement) xmlTextWriterWriteVFormatElement__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterWriteVFormatElement xmlTextWriterWriteVFormatElement__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterWriteVFormatElementNS +extern __typeof (xmlTextWriterWriteVFormatElementNS) xmlTextWriterWriteVFormatElementNS __attribute((alias("xmlTextWriterWriteVFormatElementNS__internal_alias"))); +#else +#ifndef xmlTextWriterWriteVFormatElementNS +extern __typeof (xmlTextWriterWriteVFormatElementNS) xmlTextWriterWriteVFormatElementNS__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterWriteVFormatElementNS xmlTextWriterWriteVFormatElementNS__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterWriteVFormatPI +extern __typeof (xmlTextWriterWriteVFormatPI) xmlTextWriterWriteVFormatPI __attribute((alias("xmlTextWriterWriteVFormatPI__internal_alias"))); +#else +#ifndef xmlTextWriterWriteVFormatPI +extern __typeof (xmlTextWriterWriteVFormatPI) xmlTextWriterWriteVFormatPI__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterWriteVFormatPI xmlTextWriterWriteVFormatPI__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterWriteVFormatRaw +extern __typeof (xmlTextWriterWriteVFormatRaw) xmlTextWriterWriteVFormatRaw __attribute((alias("xmlTextWriterWriteVFormatRaw__internal_alias"))); +#else +#ifndef xmlTextWriterWriteVFormatRaw +extern __typeof (xmlTextWriterWriteVFormatRaw) xmlTextWriterWriteVFormatRaw__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterWriteVFormatRaw xmlTextWriterWriteVFormatRaw__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_WRITER_ENABLED) +#ifdef bottom_xmlwriter +#undef xmlTextWriterWriteVFormatString +extern __typeof (xmlTextWriterWriteVFormatString) xmlTextWriterWriteVFormatString __attribute((alias("xmlTextWriterWriteVFormatString__internal_alias"))); +#else +#ifndef xmlTextWriterWriteVFormatString +extern __typeof (xmlTextWriterWriteVFormatString) xmlTextWriterWriteVFormatString__internal_alias __attribute((visibility("hidden"))); +#define xmlTextWriterWriteVFormatString xmlTextWriterWriteVFormatString__internal_alias +#endif +#endif +#endif + +#ifdef bottom_globals +#undef xmlThrDefBufferAllocScheme +extern __typeof (xmlThrDefBufferAllocScheme) xmlThrDefBufferAllocScheme __attribute((alias("xmlThrDefBufferAllocScheme__internal_alias"))); +#else +#ifndef xmlThrDefBufferAllocScheme +extern __typeof (xmlThrDefBufferAllocScheme) xmlThrDefBufferAllocScheme__internal_alias __attribute((visibility("hidden"))); +#define xmlThrDefBufferAllocScheme xmlThrDefBufferAllocScheme__internal_alias +#endif +#endif + +#ifdef bottom_globals +#undef xmlThrDefDefaultBufferSize +extern __typeof (xmlThrDefDefaultBufferSize) xmlThrDefDefaultBufferSize __attribute((alias("xmlThrDefDefaultBufferSize__internal_alias"))); +#else +#ifndef xmlThrDefDefaultBufferSize +extern __typeof (xmlThrDefDefaultBufferSize) xmlThrDefDefaultBufferSize__internal_alias __attribute((visibility("hidden"))); +#define xmlThrDefDefaultBufferSize xmlThrDefDefaultBufferSize__internal_alias +#endif +#endif + +#ifdef bottom_globals +#undef xmlThrDefDeregisterNodeDefault +extern __typeof (xmlThrDefDeregisterNodeDefault) xmlThrDefDeregisterNodeDefault __attribute((alias("xmlThrDefDeregisterNodeDefault__internal_alias"))); +#else +#ifndef xmlThrDefDeregisterNodeDefault +extern __typeof (xmlThrDefDeregisterNodeDefault) xmlThrDefDeregisterNodeDefault__internal_alias __attribute((visibility("hidden"))); +#define xmlThrDefDeregisterNodeDefault xmlThrDefDeregisterNodeDefault__internal_alias +#endif +#endif + +#ifdef bottom_globals +#undef xmlThrDefDoValidityCheckingDefaultValue +extern __typeof (xmlThrDefDoValidityCheckingDefaultValue) xmlThrDefDoValidityCheckingDefaultValue __attribute((alias("xmlThrDefDoValidityCheckingDefaultValue__internal_alias"))); +#else +#ifndef xmlThrDefDoValidityCheckingDefaultValue +extern __typeof (xmlThrDefDoValidityCheckingDefaultValue) xmlThrDefDoValidityCheckingDefaultValue__internal_alias __attribute((visibility("hidden"))); +#define xmlThrDefDoValidityCheckingDefaultValue xmlThrDefDoValidityCheckingDefaultValue__internal_alias +#endif +#endif + +#ifdef bottom_globals +#undef xmlThrDefGetWarningsDefaultValue +extern __typeof (xmlThrDefGetWarningsDefaultValue) xmlThrDefGetWarningsDefaultValue __attribute((alias("xmlThrDefGetWarningsDefaultValue__internal_alias"))); +#else +#ifndef xmlThrDefGetWarningsDefaultValue +extern __typeof (xmlThrDefGetWarningsDefaultValue) xmlThrDefGetWarningsDefaultValue__internal_alias __attribute((visibility("hidden"))); +#define xmlThrDefGetWarningsDefaultValue xmlThrDefGetWarningsDefaultValue__internal_alias +#endif +#endif + +#ifdef bottom_globals +#undef xmlThrDefIndentTreeOutput +extern __typeof (xmlThrDefIndentTreeOutput) xmlThrDefIndentTreeOutput __attribute((alias("xmlThrDefIndentTreeOutput__internal_alias"))); +#else +#ifndef xmlThrDefIndentTreeOutput +extern __typeof (xmlThrDefIndentTreeOutput) xmlThrDefIndentTreeOutput__internal_alias __attribute((visibility("hidden"))); +#define xmlThrDefIndentTreeOutput xmlThrDefIndentTreeOutput__internal_alias +#endif +#endif + +#ifdef bottom_globals +#undef xmlThrDefKeepBlanksDefaultValue +extern __typeof (xmlThrDefKeepBlanksDefaultValue) xmlThrDefKeepBlanksDefaultValue __attribute((alias("xmlThrDefKeepBlanksDefaultValue__internal_alias"))); +#else +#ifndef xmlThrDefKeepBlanksDefaultValue +extern __typeof (xmlThrDefKeepBlanksDefaultValue) xmlThrDefKeepBlanksDefaultValue__internal_alias __attribute((visibility("hidden"))); +#define xmlThrDefKeepBlanksDefaultValue xmlThrDefKeepBlanksDefaultValue__internal_alias +#endif +#endif + +#ifdef bottom_globals +#undef xmlThrDefLineNumbersDefaultValue +extern __typeof (xmlThrDefLineNumbersDefaultValue) xmlThrDefLineNumbersDefaultValue __attribute((alias("xmlThrDefLineNumbersDefaultValue__internal_alias"))); +#else +#ifndef xmlThrDefLineNumbersDefaultValue +extern __typeof (xmlThrDefLineNumbersDefaultValue) xmlThrDefLineNumbersDefaultValue__internal_alias __attribute((visibility("hidden"))); +#define xmlThrDefLineNumbersDefaultValue xmlThrDefLineNumbersDefaultValue__internal_alias +#endif +#endif + +#ifdef bottom_globals +#undef xmlThrDefLoadExtDtdDefaultValue +extern __typeof (xmlThrDefLoadExtDtdDefaultValue) xmlThrDefLoadExtDtdDefaultValue __attribute((alias("xmlThrDefLoadExtDtdDefaultValue__internal_alias"))); +#else +#ifndef xmlThrDefLoadExtDtdDefaultValue +extern __typeof (xmlThrDefLoadExtDtdDefaultValue) xmlThrDefLoadExtDtdDefaultValue__internal_alias __attribute((visibility("hidden"))); +#define xmlThrDefLoadExtDtdDefaultValue xmlThrDefLoadExtDtdDefaultValue__internal_alias +#endif +#endif + +#ifdef bottom_globals +#undef xmlThrDefOutputBufferCreateFilenameDefault +extern __typeof (xmlThrDefOutputBufferCreateFilenameDefault) xmlThrDefOutputBufferCreateFilenameDefault __attribute((alias("xmlThrDefOutputBufferCreateFilenameDefault__internal_alias"))); +#else +#ifndef xmlThrDefOutputBufferCreateFilenameDefault +extern __typeof (xmlThrDefOutputBufferCreateFilenameDefault) xmlThrDefOutputBufferCreateFilenameDefault__internal_alias __attribute((visibility("hidden"))); +#define xmlThrDefOutputBufferCreateFilenameDefault xmlThrDefOutputBufferCreateFilenameDefault__internal_alias +#endif +#endif + +#ifdef bottom_globals +#undef xmlThrDefParserDebugEntities +extern __typeof (xmlThrDefParserDebugEntities) xmlThrDefParserDebugEntities __attribute((alias("xmlThrDefParserDebugEntities__internal_alias"))); +#else +#ifndef xmlThrDefParserDebugEntities +extern __typeof (xmlThrDefParserDebugEntities) xmlThrDefParserDebugEntities__internal_alias __attribute((visibility("hidden"))); +#define xmlThrDefParserDebugEntities xmlThrDefParserDebugEntities__internal_alias +#endif +#endif + +#ifdef bottom_globals +#undef xmlThrDefParserInputBufferCreateFilenameDefault +extern __typeof (xmlThrDefParserInputBufferCreateFilenameDefault) xmlThrDefParserInputBufferCreateFilenameDefault __attribute((alias("xmlThrDefParserInputBufferCreateFilenameDefault__internal_alias"))); +#else +#ifndef xmlThrDefParserInputBufferCreateFilenameDefault +extern __typeof (xmlThrDefParserInputBufferCreateFilenameDefault) xmlThrDefParserInputBufferCreateFilenameDefault__internal_alias __attribute((visibility("hidden"))); +#define xmlThrDefParserInputBufferCreateFilenameDefault xmlThrDefParserInputBufferCreateFilenameDefault__internal_alias +#endif +#endif + +#ifdef bottom_globals +#undef xmlThrDefPedanticParserDefaultValue +extern __typeof (xmlThrDefPedanticParserDefaultValue) xmlThrDefPedanticParserDefaultValue __attribute((alias("xmlThrDefPedanticParserDefaultValue__internal_alias"))); +#else +#ifndef xmlThrDefPedanticParserDefaultValue +extern __typeof (xmlThrDefPedanticParserDefaultValue) xmlThrDefPedanticParserDefaultValue__internal_alias __attribute((visibility("hidden"))); +#define xmlThrDefPedanticParserDefaultValue xmlThrDefPedanticParserDefaultValue__internal_alias +#endif +#endif + +#ifdef bottom_globals +#undef xmlThrDefRegisterNodeDefault +extern __typeof (xmlThrDefRegisterNodeDefault) xmlThrDefRegisterNodeDefault __attribute((alias("xmlThrDefRegisterNodeDefault__internal_alias"))); +#else +#ifndef xmlThrDefRegisterNodeDefault +extern __typeof (xmlThrDefRegisterNodeDefault) xmlThrDefRegisterNodeDefault__internal_alias __attribute((visibility("hidden"))); +#define xmlThrDefRegisterNodeDefault xmlThrDefRegisterNodeDefault__internal_alias +#endif +#endif + +#ifdef bottom_globals +#undef xmlThrDefSaveNoEmptyTags +extern __typeof (xmlThrDefSaveNoEmptyTags) xmlThrDefSaveNoEmptyTags __attribute((alias("xmlThrDefSaveNoEmptyTags__internal_alias"))); +#else +#ifndef xmlThrDefSaveNoEmptyTags +extern __typeof (xmlThrDefSaveNoEmptyTags) xmlThrDefSaveNoEmptyTags__internal_alias __attribute((visibility("hidden"))); +#define xmlThrDefSaveNoEmptyTags xmlThrDefSaveNoEmptyTags__internal_alias +#endif +#endif + +#ifdef bottom_globals +#undef xmlThrDefSetGenericErrorFunc +extern __typeof (xmlThrDefSetGenericErrorFunc) xmlThrDefSetGenericErrorFunc __attribute((alias("xmlThrDefSetGenericErrorFunc__internal_alias"))); +#else +#ifndef xmlThrDefSetGenericErrorFunc +extern __typeof (xmlThrDefSetGenericErrorFunc) xmlThrDefSetGenericErrorFunc__internal_alias __attribute((visibility("hidden"))); +#define xmlThrDefSetGenericErrorFunc xmlThrDefSetGenericErrorFunc__internal_alias +#endif +#endif + +#ifdef bottom_globals +#undef xmlThrDefSetStructuredErrorFunc +extern __typeof (xmlThrDefSetStructuredErrorFunc) xmlThrDefSetStructuredErrorFunc __attribute((alias("xmlThrDefSetStructuredErrorFunc__internal_alias"))); +#else +#ifndef xmlThrDefSetStructuredErrorFunc +extern __typeof (xmlThrDefSetStructuredErrorFunc) xmlThrDefSetStructuredErrorFunc__internal_alias __attribute((visibility("hidden"))); +#define xmlThrDefSetStructuredErrorFunc xmlThrDefSetStructuredErrorFunc__internal_alias +#endif +#endif + +#ifdef bottom_globals +#undef xmlThrDefSubstituteEntitiesDefaultValue +extern __typeof (xmlThrDefSubstituteEntitiesDefaultValue) xmlThrDefSubstituteEntitiesDefaultValue __attribute((alias("xmlThrDefSubstituteEntitiesDefaultValue__internal_alias"))); +#else +#ifndef xmlThrDefSubstituteEntitiesDefaultValue +extern __typeof (xmlThrDefSubstituteEntitiesDefaultValue) xmlThrDefSubstituteEntitiesDefaultValue__internal_alias __attribute((visibility("hidden"))); +#define xmlThrDefSubstituteEntitiesDefaultValue xmlThrDefSubstituteEntitiesDefaultValue__internal_alias +#endif +#endif + +#ifdef bottom_globals +#undef xmlThrDefTreeIndentString +extern __typeof (xmlThrDefTreeIndentString) xmlThrDefTreeIndentString __attribute((alias("xmlThrDefTreeIndentString__internal_alias"))); +#else +#ifndef xmlThrDefTreeIndentString +extern __typeof (xmlThrDefTreeIndentString) xmlThrDefTreeIndentString__internal_alias __attribute((visibility("hidden"))); +#define xmlThrDefTreeIndentString xmlThrDefTreeIndentString__internal_alias +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsAegeanNumbers +extern __typeof (xmlUCSIsAegeanNumbers) xmlUCSIsAegeanNumbers __attribute((alias("xmlUCSIsAegeanNumbers__internal_alias"))); +#else +#ifndef xmlUCSIsAegeanNumbers +extern __typeof (xmlUCSIsAegeanNumbers) xmlUCSIsAegeanNumbers__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsAegeanNumbers xmlUCSIsAegeanNumbers__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsAlphabeticPresentationForms +extern __typeof (xmlUCSIsAlphabeticPresentationForms) xmlUCSIsAlphabeticPresentationForms __attribute((alias("xmlUCSIsAlphabeticPresentationForms__internal_alias"))); +#else +#ifndef xmlUCSIsAlphabeticPresentationForms +extern __typeof (xmlUCSIsAlphabeticPresentationForms) xmlUCSIsAlphabeticPresentationForms__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsAlphabeticPresentationForms xmlUCSIsAlphabeticPresentationForms__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsArabic +extern __typeof (xmlUCSIsArabic) xmlUCSIsArabic __attribute((alias("xmlUCSIsArabic__internal_alias"))); +#else +#ifndef xmlUCSIsArabic +extern __typeof (xmlUCSIsArabic) xmlUCSIsArabic__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsArabic xmlUCSIsArabic__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsArabicPresentationFormsA +extern __typeof (xmlUCSIsArabicPresentationFormsA) xmlUCSIsArabicPresentationFormsA __attribute((alias("xmlUCSIsArabicPresentationFormsA__internal_alias"))); +#else +#ifndef xmlUCSIsArabicPresentationFormsA +extern __typeof (xmlUCSIsArabicPresentationFormsA) xmlUCSIsArabicPresentationFormsA__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsArabicPresentationFormsA xmlUCSIsArabicPresentationFormsA__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsArabicPresentationFormsB +extern __typeof (xmlUCSIsArabicPresentationFormsB) xmlUCSIsArabicPresentationFormsB __attribute((alias("xmlUCSIsArabicPresentationFormsB__internal_alias"))); +#else +#ifndef xmlUCSIsArabicPresentationFormsB +extern __typeof (xmlUCSIsArabicPresentationFormsB) xmlUCSIsArabicPresentationFormsB__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsArabicPresentationFormsB xmlUCSIsArabicPresentationFormsB__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsArmenian +extern __typeof (xmlUCSIsArmenian) xmlUCSIsArmenian __attribute((alias("xmlUCSIsArmenian__internal_alias"))); +#else +#ifndef xmlUCSIsArmenian +extern __typeof (xmlUCSIsArmenian) xmlUCSIsArmenian__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsArmenian xmlUCSIsArmenian__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsArrows +extern __typeof (xmlUCSIsArrows) xmlUCSIsArrows __attribute((alias("xmlUCSIsArrows__internal_alias"))); +#else +#ifndef xmlUCSIsArrows +extern __typeof (xmlUCSIsArrows) xmlUCSIsArrows__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsArrows xmlUCSIsArrows__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsBasicLatin +extern __typeof (xmlUCSIsBasicLatin) xmlUCSIsBasicLatin __attribute((alias("xmlUCSIsBasicLatin__internal_alias"))); +#else +#ifndef xmlUCSIsBasicLatin +extern __typeof (xmlUCSIsBasicLatin) xmlUCSIsBasicLatin__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsBasicLatin xmlUCSIsBasicLatin__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsBengali +extern __typeof (xmlUCSIsBengali) xmlUCSIsBengali __attribute((alias("xmlUCSIsBengali__internal_alias"))); +#else +#ifndef xmlUCSIsBengali +extern __typeof (xmlUCSIsBengali) xmlUCSIsBengali__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsBengali xmlUCSIsBengali__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsBlock +extern __typeof (xmlUCSIsBlock) xmlUCSIsBlock __attribute((alias("xmlUCSIsBlock__internal_alias"))); +#else +#ifndef xmlUCSIsBlock +extern __typeof (xmlUCSIsBlock) xmlUCSIsBlock__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsBlock xmlUCSIsBlock__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsBlockElements +extern __typeof (xmlUCSIsBlockElements) xmlUCSIsBlockElements __attribute((alias("xmlUCSIsBlockElements__internal_alias"))); +#else +#ifndef xmlUCSIsBlockElements +extern __typeof (xmlUCSIsBlockElements) xmlUCSIsBlockElements__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsBlockElements xmlUCSIsBlockElements__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsBopomofo +extern __typeof (xmlUCSIsBopomofo) xmlUCSIsBopomofo __attribute((alias("xmlUCSIsBopomofo__internal_alias"))); +#else +#ifndef xmlUCSIsBopomofo +extern __typeof (xmlUCSIsBopomofo) xmlUCSIsBopomofo__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsBopomofo xmlUCSIsBopomofo__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsBopomofoExtended +extern __typeof (xmlUCSIsBopomofoExtended) xmlUCSIsBopomofoExtended __attribute((alias("xmlUCSIsBopomofoExtended__internal_alias"))); +#else +#ifndef xmlUCSIsBopomofoExtended +extern __typeof (xmlUCSIsBopomofoExtended) xmlUCSIsBopomofoExtended__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsBopomofoExtended xmlUCSIsBopomofoExtended__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsBoxDrawing +extern __typeof (xmlUCSIsBoxDrawing) xmlUCSIsBoxDrawing __attribute((alias("xmlUCSIsBoxDrawing__internal_alias"))); +#else +#ifndef xmlUCSIsBoxDrawing +extern __typeof (xmlUCSIsBoxDrawing) xmlUCSIsBoxDrawing__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsBoxDrawing xmlUCSIsBoxDrawing__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsBraillePatterns +extern __typeof (xmlUCSIsBraillePatterns) xmlUCSIsBraillePatterns __attribute((alias("xmlUCSIsBraillePatterns__internal_alias"))); +#else +#ifndef xmlUCSIsBraillePatterns +extern __typeof (xmlUCSIsBraillePatterns) xmlUCSIsBraillePatterns__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsBraillePatterns xmlUCSIsBraillePatterns__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsBuhid +extern __typeof (xmlUCSIsBuhid) xmlUCSIsBuhid __attribute((alias("xmlUCSIsBuhid__internal_alias"))); +#else +#ifndef xmlUCSIsBuhid +extern __typeof (xmlUCSIsBuhid) xmlUCSIsBuhid__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsBuhid xmlUCSIsBuhid__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsByzantineMusicalSymbols +extern __typeof (xmlUCSIsByzantineMusicalSymbols) xmlUCSIsByzantineMusicalSymbols __attribute((alias("xmlUCSIsByzantineMusicalSymbols__internal_alias"))); +#else +#ifndef xmlUCSIsByzantineMusicalSymbols +extern __typeof (xmlUCSIsByzantineMusicalSymbols) xmlUCSIsByzantineMusicalSymbols__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsByzantineMusicalSymbols xmlUCSIsByzantineMusicalSymbols__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCJKCompatibility +extern __typeof (xmlUCSIsCJKCompatibility) xmlUCSIsCJKCompatibility __attribute((alias("xmlUCSIsCJKCompatibility__internal_alias"))); +#else +#ifndef xmlUCSIsCJKCompatibility +extern __typeof (xmlUCSIsCJKCompatibility) xmlUCSIsCJKCompatibility__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCJKCompatibility xmlUCSIsCJKCompatibility__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCJKCompatibilityForms +extern __typeof (xmlUCSIsCJKCompatibilityForms) xmlUCSIsCJKCompatibilityForms __attribute((alias("xmlUCSIsCJKCompatibilityForms__internal_alias"))); +#else +#ifndef xmlUCSIsCJKCompatibilityForms +extern __typeof (xmlUCSIsCJKCompatibilityForms) xmlUCSIsCJKCompatibilityForms__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCJKCompatibilityForms xmlUCSIsCJKCompatibilityForms__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCJKCompatibilityIdeographs +extern __typeof (xmlUCSIsCJKCompatibilityIdeographs) xmlUCSIsCJKCompatibilityIdeographs __attribute((alias("xmlUCSIsCJKCompatibilityIdeographs__internal_alias"))); +#else +#ifndef xmlUCSIsCJKCompatibilityIdeographs +extern __typeof (xmlUCSIsCJKCompatibilityIdeographs) xmlUCSIsCJKCompatibilityIdeographs__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCJKCompatibilityIdeographs xmlUCSIsCJKCompatibilityIdeographs__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCJKCompatibilityIdeographsSupplement +extern __typeof (xmlUCSIsCJKCompatibilityIdeographsSupplement) xmlUCSIsCJKCompatibilityIdeographsSupplement __attribute((alias("xmlUCSIsCJKCompatibilityIdeographsSupplement__internal_alias"))); +#else +#ifndef xmlUCSIsCJKCompatibilityIdeographsSupplement +extern __typeof (xmlUCSIsCJKCompatibilityIdeographsSupplement) xmlUCSIsCJKCompatibilityIdeographsSupplement__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCJKCompatibilityIdeographsSupplement xmlUCSIsCJKCompatibilityIdeographsSupplement__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCJKRadicalsSupplement +extern __typeof (xmlUCSIsCJKRadicalsSupplement) xmlUCSIsCJKRadicalsSupplement __attribute((alias("xmlUCSIsCJKRadicalsSupplement__internal_alias"))); +#else +#ifndef xmlUCSIsCJKRadicalsSupplement +extern __typeof (xmlUCSIsCJKRadicalsSupplement) xmlUCSIsCJKRadicalsSupplement__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCJKRadicalsSupplement xmlUCSIsCJKRadicalsSupplement__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCJKSymbolsandPunctuation +extern __typeof (xmlUCSIsCJKSymbolsandPunctuation) xmlUCSIsCJKSymbolsandPunctuation __attribute((alias("xmlUCSIsCJKSymbolsandPunctuation__internal_alias"))); +#else +#ifndef xmlUCSIsCJKSymbolsandPunctuation +extern __typeof (xmlUCSIsCJKSymbolsandPunctuation) xmlUCSIsCJKSymbolsandPunctuation__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCJKSymbolsandPunctuation xmlUCSIsCJKSymbolsandPunctuation__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCJKUnifiedIdeographs +extern __typeof (xmlUCSIsCJKUnifiedIdeographs) xmlUCSIsCJKUnifiedIdeographs __attribute((alias("xmlUCSIsCJKUnifiedIdeographs__internal_alias"))); +#else +#ifndef xmlUCSIsCJKUnifiedIdeographs +extern __typeof (xmlUCSIsCJKUnifiedIdeographs) xmlUCSIsCJKUnifiedIdeographs__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCJKUnifiedIdeographs xmlUCSIsCJKUnifiedIdeographs__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCJKUnifiedIdeographsExtensionA +extern __typeof (xmlUCSIsCJKUnifiedIdeographsExtensionA) xmlUCSIsCJKUnifiedIdeographsExtensionA __attribute((alias("xmlUCSIsCJKUnifiedIdeographsExtensionA__internal_alias"))); +#else +#ifndef xmlUCSIsCJKUnifiedIdeographsExtensionA +extern __typeof (xmlUCSIsCJKUnifiedIdeographsExtensionA) xmlUCSIsCJKUnifiedIdeographsExtensionA__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCJKUnifiedIdeographsExtensionA xmlUCSIsCJKUnifiedIdeographsExtensionA__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCJKUnifiedIdeographsExtensionB +extern __typeof (xmlUCSIsCJKUnifiedIdeographsExtensionB) xmlUCSIsCJKUnifiedIdeographsExtensionB __attribute((alias("xmlUCSIsCJKUnifiedIdeographsExtensionB__internal_alias"))); +#else +#ifndef xmlUCSIsCJKUnifiedIdeographsExtensionB +extern __typeof (xmlUCSIsCJKUnifiedIdeographsExtensionB) xmlUCSIsCJKUnifiedIdeographsExtensionB__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCJKUnifiedIdeographsExtensionB xmlUCSIsCJKUnifiedIdeographsExtensionB__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCat +extern __typeof (xmlUCSIsCat) xmlUCSIsCat __attribute((alias("xmlUCSIsCat__internal_alias"))); +#else +#ifndef xmlUCSIsCat +extern __typeof (xmlUCSIsCat) xmlUCSIsCat__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCat xmlUCSIsCat__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCatC +extern __typeof (xmlUCSIsCatC) xmlUCSIsCatC __attribute((alias("xmlUCSIsCatC__internal_alias"))); +#else +#ifndef xmlUCSIsCatC +extern __typeof (xmlUCSIsCatC) xmlUCSIsCatC__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCatC xmlUCSIsCatC__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCatCc +extern __typeof (xmlUCSIsCatCc) xmlUCSIsCatCc __attribute((alias("xmlUCSIsCatCc__internal_alias"))); +#else +#ifndef xmlUCSIsCatCc +extern __typeof (xmlUCSIsCatCc) xmlUCSIsCatCc__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCatCc xmlUCSIsCatCc__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCatCf +extern __typeof (xmlUCSIsCatCf) xmlUCSIsCatCf __attribute((alias("xmlUCSIsCatCf__internal_alias"))); +#else +#ifndef xmlUCSIsCatCf +extern __typeof (xmlUCSIsCatCf) xmlUCSIsCatCf__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCatCf xmlUCSIsCatCf__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCatCo +extern __typeof (xmlUCSIsCatCo) xmlUCSIsCatCo __attribute((alias("xmlUCSIsCatCo__internal_alias"))); +#else +#ifndef xmlUCSIsCatCo +extern __typeof (xmlUCSIsCatCo) xmlUCSIsCatCo__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCatCo xmlUCSIsCatCo__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCatCs +extern __typeof (xmlUCSIsCatCs) xmlUCSIsCatCs __attribute((alias("xmlUCSIsCatCs__internal_alias"))); +#else +#ifndef xmlUCSIsCatCs +extern __typeof (xmlUCSIsCatCs) xmlUCSIsCatCs__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCatCs xmlUCSIsCatCs__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCatL +extern __typeof (xmlUCSIsCatL) xmlUCSIsCatL __attribute((alias("xmlUCSIsCatL__internal_alias"))); +#else +#ifndef xmlUCSIsCatL +extern __typeof (xmlUCSIsCatL) xmlUCSIsCatL__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCatL xmlUCSIsCatL__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCatLl +extern __typeof (xmlUCSIsCatLl) xmlUCSIsCatLl __attribute((alias("xmlUCSIsCatLl__internal_alias"))); +#else +#ifndef xmlUCSIsCatLl +extern __typeof (xmlUCSIsCatLl) xmlUCSIsCatLl__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCatLl xmlUCSIsCatLl__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCatLm +extern __typeof (xmlUCSIsCatLm) xmlUCSIsCatLm __attribute((alias("xmlUCSIsCatLm__internal_alias"))); +#else +#ifndef xmlUCSIsCatLm +extern __typeof (xmlUCSIsCatLm) xmlUCSIsCatLm__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCatLm xmlUCSIsCatLm__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCatLo +extern __typeof (xmlUCSIsCatLo) xmlUCSIsCatLo __attribute((alias("xmlUCSIsCatLo__internal_alias"))); +#else +#ifndef xmlUCSIsCatLo +extern __typeof (xmlUCSIsCatLo) xmlUCSIsCatLo__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCatLo xmlUCSIsCatLo__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCatLt +extern __typeof (xmlUCSIsCatLt) xmlUCSIsCatLt __attribute((alias("xmlUCSIsCatLt__internal_alias"))); +#else +#ifndef xmlUCSIsCatLt +extern __typeof (xmlUCSIsCatLt) xmlUCSIsCatLt__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCatLt xmlUCSIsCatLt__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCatLu +extern __typeof (xmlUCSIsCatLu) xmlUCSIsCatLu __attribute((alias("xmlUCSIsCatLu__internal_alias"))); +#else +#ifndef xmlUCSIsCatLu +extern __typeof (xmlUCSIsCatLu) xmlUCSIsCatLu__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCatLu xmlUCSIsCatLu__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCatM +extern __typeof (xmlUCSIsCatM) xmlUCSIsCatM __attribute((alias("xmlUCSIsCatM__internal_alias"))); +#else +#ifndef xmlUCSIsCatM +extern __typeof (xmlUCSIsCatM) xmlUCSIsCatM__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCatM xmlUCSIsCatM__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCatMc +extern __typeof (xmlUCSIsCatMc) xmlUCSIsCatMc __attribute((alias("xmlUCSIsCatMc__internal_alias"))); +#else +#ifndef xmlUCSIsCatMc +extern __typeof (xmlUCSIsCatMc) xmlUCSIsCatMc__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCatMc xmlUCSIsCatMc__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCatMe +extern __typeof (xmlUCSIsCatMe) xmlUCSIsCatMe __attribute((alias("xmlUCSIsCatMe__internal_alias"))); +#else +#ifndef xmlUCSIsCatMe +extern __typeof (xmlUCSIsCatMe) xmlUCSIsCatMe__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCatMe xmlUCSIsCatMe__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCatMn +extern __typeof (xmlUCSIsCatMn) xmlUCSIsCatMn __attribute((alias("xmlUCSIsCatMn__internal_alias"))); +#else +#ifndef xmlUCSIsCatMn +extern __typeof (xmlUCSIsCatMn) xmlUCSIsCatMn__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCatMn xmlUCSIsCatMn__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCatN +extern __typeof (xmlUCSIsCatN) xmlUCSIsCatN __attribute((alias("xmlUCSIsCatN__internal_alias"))); +#else +#ifndef xmlUCSIsCatN +extern __typeof (xmlUCSIsCatN) xmlUCSIsCatN__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCatN xmlUCSIsCatN__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCatNd +extern __typeof (xmlUCSIsCatNd) xmlUCSIsCatNd __attribute((alias("xmlUCSIsCatNd__internal_alias"))); +#else +#ifndef xmlUCSIsCatNd +extern __typeof (xmlUCSIsCatNd) xmlUCSIsCatNd__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCatNd xmlUCSIsCatNd__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCatNl +extern __typeof (xmlUCSIsCatNl) xmlUCSIsCatNl __attribute((alias("xmlUCSIsCatNl__internal_alias"))); +#else +#ifndef xmlUCSIsCatNl +extern __typeof (xmlUCSIsCatNl) xmlUCSIsCatNl__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCatNl xmlUCSIsCatNl__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCatNo +extern __typeof (xmlUCSIsCatNo) xmlUCSIsCatNo __attribute((alias("xmlUCSIsCatNo__internal_alias"))); +#else +#ifndef xmlUCSIsCatNo +extern __typeof (xmlUCSIsCatNo) xmlUCSIsCatNo__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCatNo xmlUCSIsCatNo__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCatP +extern __typeof (xmlUCSIsCatP) xmlUCSIsCatP __attribute((alias("xmlUCSIsCatP__internal_alias"))); +#else +#ifndef xmlUCSIsCatP +extern __typeof (xmlUCSIsCatP) xmlUCSIsCatP__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCatP xmlUCSIsCatP__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCatPc +extern __typeof (xmlUCSIsCatPc) xmlUCSIsCatPc __attribute((alias("xmlUCSIsCatPc__internal_alias"))); +#else +#ifndef xmlUCSIsCatPc +extern __typeof (xmlUCSIsCatPc) xmlUCSIsCatPc__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCatPc xmlUCSIsCatPc__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCatPd +extern __typeof (xmlUCSIsCatPd) xmlUCSIsCatPd __attribute((alias("xmlUCSIsCatPd__internal_alias"))); +#else +#ifndef xmlUCSIsCatPd +extern __typeof (xmlUCSIsCatPd) xmlUCSIsCatPd__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCatPd xmlUCSIsCatPd__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCatPe +extern __typeof (xmlUCSIsCatPe) xmlUCSIsCatPe __attribute((alias("xmlUCSIsCatPe__internal_alias"))); +#else +#ifndef xmlUCSIsCatPe +extern __typeof (xmlUCSIsCatPe) xmlUCSIsCatPe__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCatPe xmlUCSIsCatPe__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCatPf +extern __typeof (xmlUCSIsCatPf) xmlUCSIsCatPf __attribute((alias("xmlUCSIsCatPf__internal_alias"))); +#else +#ifndef xmlUCSIsCatPf +extern __typeof (xmlUCSIsCatPf) xmlUCSIsCatPf__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCatPf xmlUCSIsCatPf__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCatPi +extern __typeof (xmlUCSIsCatPi) xmlUCSIsCatPi __attribute((alias("xmlUCSIsCatPi__internal_alias"))); +#else +#ifndef xmlUCSIsCatPi +extern __typeof (xmlUCSIsCatPi) xmlUCSIsCatPi__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCatPi xmlUCSIsCatPi__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCatPo +extern __typeof (xmlUCSIsCatPo) xmlUCSIsCatPo __attribute((alias("xmlUCSIsCatPo__internal_alias"))); +#else +#ifndef xmlUCSIsCatPo +extern __typeof (xmlUCSIsCatPo) xmlUCSIsCatPo__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCatPo xmlUCSIsCatPo__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCatPs +extern __typeof (xmlUCSIsCatPs) xmlUCSIsCatPs __attribute((alias("xmlUCSIsCatPs__internal_alias"))); +#else +#ifndef xmlUCSIsCatPs +extern __typeof (xmlUCSIsCatPs) xmlUCSIsCatPs__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCatPs xmlUCSIsCatPs__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCatS +extern __typeof (xmlUCSIsCatS) xmlUCSIsCatS __attribute((alias("xmlUCSIsCatS__internal_alias"))); +#else +#ifndef xmlUCSIsCatS +extern __typeof (xmlUCSIsCatS) xmlUCSIsCatS__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCatS xmlUCSIsCatS__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCatSc +extern __typeof (xmlUCSIsCatSc) xmlUCSIsCatSc __attribute((alias("xmlUCSIsCatSc__internal_alias"))); +#else +#ifndef xmlUCSIsCatSc +extern __typeof (xmlUCSIsCatSc) xmlUCSIsCatSc__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCatSc xmlUCSIsCatSc__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCatSk +extern __typeof (xmlUCSIsCatSk) xmlUCSIsCatSk __attribute((alias("xmlUCSIsCatSk__internal_alias"))); +#else +#ifndef xmlUCSIsCatSk +extern __typeof (xmlUCSIsCatSk) xmlUCSIsCatSk__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCatSk xmlUCSIsCatSk__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCatSm +extern __typeof (xmlUCSIsCatSm) xmlUCSIsCatSm __attribute((alias("xmlUCSIsCatSm__internal_alias"))); +#else +#ifndef xmlUCSIsCatSm +extern __typeof (xmlUCSIsCatSm) xmlUCSIsCatSm__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCatSm xmlUCSIsCatSm__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCatSo +extern __typeof (xmlUCSIsCatSo) xmlUCSIsCatSo __attribute((alias("xmlUCSIsCatSo__internal_alias"))); +#else +#ifndef xmlUCSIsCatSo +extern __typeof (xmlUCSIsCatSo) xmlUCSIsCatSo__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCatSo xmlUCSIsCatSo__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCatZ +extern __typeof (xmlUCSIsCatZ) xmlUCSIsCatZ __attribute((alias("xmlUCSIsCatZ__internal_alias"))); +#else +#ifndef xmlUCSIsCatZ +extern __typeof (xmlUCSIsCatZ) xmlUCSIsCatZ__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCatZ xmlUCSIsCatZ__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCatZl +extern __typeof (xmlUCSIsCatZl) xmlUCSIsCatZl __attribute((alias("xmlUCSIsCatZl__internal_alias"))); +#else +#ifndef xmlUCSIsCatZl +extern __typeof (xmlUCSIsCatZl) xmlUCSIsCatZl__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCatZl xmlUCSIsCatZl__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCatZp +extern __typeof (xmlUCSIsCatZp) xmlUCSIsCatZp __attribute((alias("xmlUCSIsCatZp__internal_alias"))); +#else +#ifndef xmlUCSIsCatZp +extern __typeof (xmlUCSIsCatZp) xmlUCSIsCatZp__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCatZp xmlUCSIsCatZp__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCatZs +extern __typeof (xmlUCSIsCatZs) xmlUCSIsCatZs __attribute((alias("xmlUCSIsCatZs__internal_alias"))); +#else +#ifndef xmlUCSIsCatZs +extern __typeof (xmlUCSIsCatZs) xmlUCSIsCatZs__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCatZs xmlUCSIsCatZs__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCherokee +extern __typeof (xmlUCSIsCherokee) xmlUCSIsCherokee __attribute((alias("xmlUCSIsCherokee__internal_alias"))); +#else +#ifndef xmlUCSIsCherokee +extern __typeof (xmlUCSIsCherokee) xmlUCSIsCherokee__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCherokee xmlUCSIsCherokee__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCombiningDiacriticalMarks +extern __typeof (xmlUCSIsCombiningDiacriticalMarks) xmlUCSIsCombiningDiacriticalMarks __attribute((alias("xmlUCSIsCombiningDiacriticalMarks__internal_alias"))); +#else +#ifndef xmlUCSIsCombiningDiacriticalMarks +extern __typeof (xmlUCSIsCombiningDiacriticalMarks) xmlUCSIsCombiningDiacriticalMarks__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCombiningDiacriticalMarks xmlUCSIsCombiningDiacriticalMarks__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCombiningDiacriticalMarksforSymbols +extern __typeof (xmlUCSIsCombiningDiacriticalMarksforSymbols) xmlUCSIsCombiningDiacriticalMarksforSymbols __attribute((alias("xmlUCSIsCombiningDiacriticalMarksforSymbols__internal_alias"))); +#else +#ifndef xmlUCSIsCombiningDiacriticalMarksforSymbols +extern __typeof (xmlUCSIsCombiningDiacriticalMarksforSymbols) xmlUCSIsCombiningDiacriticalMarksforSymbols__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCombiningDiacriticalMarksforSymbols xmlUCSIsCombiningDiacriticalMarksforSymbols__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCombiningHalfMarks +extern __typeof (xmlUCSIsCombiningHalfMarks) xmlUCSIsCombiningHalfMarks __attribute((alias("xmlUCSIsCombiningHalfMarks__internal_alias"))); +#else +#ifndef xmlUCSIsCombiningHalfMarks +extern __typeof (xmlUCSIsCombiningHalfMarks) xmlUCSIsCombiningHalfMarks__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCombiningHalfMarks xmlUCSIsCombiningHalfMarks__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCombiningMarksforSymbols +extern __typeof (xmlUCSIsCombiningMarksforSymbols) xmlUCSIsCombiningMarksforSymbols __attribute((alias("xmlUCSIsCombiningMarksforSymbols__internal_alias"))); +#else +#ifndef xmlUCSIsCombiningMarksforSymbols +extern __typeof (xmlUCSIsCombiningMarksforSymbols) xmlUCSIsCombiningMarksforSymbols__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCombiningMarksforSymbols xmlUCSIsCombiningMarksforSymbols__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsControlPictures +extern __typeof (xmlUCSIsControlPictures) xmlUCSIsControlPictures __attribute((alias("xmlUCSIsControlPictures__internal_alias"))); +#else +#ifndef xmlUCSIsControlPictures +extern __typeof (xmlUCSIsControlPictures) xmlUCSIsControlPictures__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsControlPictures xmlUCSIsControlPictures__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCurrencySymbols +extern __typeof (xmlUCSIsCurrencySymbols) xmlUCSIsCurrencySymbols __attribute((alias("xmlUCSIsCurrencySymbols__internal_alias"))); +#else +#ifndef xmlUCSIsCurrencySymbols +extern __typeof (xmlUCSIsCurrencySymbols) xmlUCSIsCurrencySymbols__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCurrencySymbols xmlUCSIsCurrencySymbols__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCypriotSyllabary +extern __typeof (xmlUCSIsCypriotSyllabary) xmlUCSIsCypriotSyllabary __attribute((alias("xmlUCSIsCypriotSyllabary__internal_alias"))); +#else +#ifndef xmlUCSIsCypriotSyllabary +extern __typeof (xmlUCSIsCypriotSyllabary) xmlUCSIsCypriotSyllabary__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCypriotSyllabary xmlUCSIsCypriotSyllabary__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCyrillic +extern __typeof (xmlUCSIsCyrillic) xmlUCSIsCyrillic __attribute((alias("xmlUCSIsCyrillic__internal_alias"))); +#else +#ifndef xmlUCSIsCyrillic +extern __typeof (xmlUCSIsCyrillic) xmlUCSIsCyrillic__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCyrillic xmlUCSIsCyrillic__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsCyrillicSupplement +extern __typeof (xmlUCSIsCyrillicSupplement) xmlUCSIsCyrillicSupplement __attribute((alias("xmlUCSIsCyrillicSupplement__internal_alias"))); +#else +#ifndef xmlUCSIsCyrillicSupplement +extern __typeof (xmlUCSIsCyrillicSupplement) xmlUCSIsCyrillicSupplement__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsCyrillicSupplement xmlUCSIsCyrillicSupplement__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsDeseret +extern __typeof (xmlUCSIsDeseret) xmlUCSIsDeseret __attribute((alias("xmlUCSIsDeseret__internal_alias"))); +#else +#ifndef xmlUCSIsDeseret +extern __typeof (xmlUCSIsDeseret) xmlUCSIsDeseret__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsDeseret xmlUCSIsDeseret__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsDevanagari +extern __typeof (xmlUCSIsDevanagari) xmlUCSIsDevanagari __attribute((alias("xmlUCSIsDevanagari__internal_alias"))); +#else +#ifndef xmlUCSIsDevanagari +extern __typeof (xmlUCSIsDevanagari) xmlUCSIsDevanagari__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsDevanagari xmlUCSIsDevanagari__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsDingbats +extern __typeof (xmlUCSIsDingbats) xmlUCSIsDingbats __attribute((alias("xmlUCSIsDingbats__internal_alias"))); +#else +#ifndef xmlUCSIsDingbats +extern __typeof (xmlUCSIsDingbats) xmlUCSIsDingbats__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsDingbats xmlUCSIsDingbats__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsEnclosedAlphanumerics +extern __typeof (xmlUCSIsEnclosedAlphanumerics) xmlUCSIsEnclosedAlphanumerics __attribute((alias("xmlUCSIsEnclosedAlphanumerics__internal_alias"))); +#else +#ifndef xmlUCSIsEnclosedAlphanumerics +extern __typeof (xmlUCSIsEnclosedAlphanumerics) xmlUCSIsEnclosedAlphanumerics__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsEnclosedAlphanumerics xmlUCSIsEnclosedAlphanumerics__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsEnclosedCJKLettersandMonths +extern __typeof (xmlUCSIsEnclosedCJKLettersandMonths) xmlUCSIsEnclosedCJKLettersandMonths __attribute((alias("xmlUCSIsEnclosedCJKLettersandMonths__internal_alias"))); +#else +#ifndef xmlUCSIsEnclosedCJKLettersandMonths +extern __typeof (xmlUCSIsEnclosedCJKLettersandMonths) xmlUCSIsEnclosedCJKLettersandMonths__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsEnclosedCJKLettersandMonths xmlUCSIsEnclosedCJKLettersandMonths__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsEthiopic +extern __typeof (xmlUCSIsEthiopic) xmlUCSIsEthiopic __attribute((alias("xmlUCSIsEthiopic__internal_alias"))); +#else +#ifndef xmlUCSIsEthiopic +extern __typeof (xmlUCSIsEthiopic) xmlUCSIsEthiopic__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsEthiopic xmlUCSIsEthiopic__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsGeneralPunctuation +extern __typeof (xmlUCSIsGeneralPunctuation) xmlUCSIsGeneralPunctuation __attribute((alias("xmlUCSIsGeneralPunctuation__internal_alias"))); +#else +#ifndef xmlUCSIsGeneralPunctuation +extern __typeof (xmlUCSIsGeneralPunctuation) xmlUCSIsGeneralPunctuation__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsGeneralPunctuation xmlUCSIsGeneralPunctuation__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsGeometricShapes +extern __typeof (xmlUCSIsGeometricShapes) xmlUCSIsGeometricShapes __attribute((alias("xmlUCSIsGeometricShapes__internal_alias"))); +#else +#ifndef xmlUCSIsGeometricShapes +extern __typeof (xmlUCSIsGeometricShapes) xmlUCSIsGeometricShapes__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsGeometricShapes xmlUCSIsGeometricShapes__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsGeorgian +extern __typeof (xmlUCSIsGeorgian) xmlUCSIsGeorgian __attribute((alias("xmlUCSIsGeorgian__internal_alias"))); +#else +#ifndef xmlUCSIsGeorgian +extern __typeof (xmlUCSIsGeorgian) xmlUCSIsGeorgian__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsGeorgian xmlUCSIsGeorgian__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsGothic +extern __typeof (xmlUCSIsGothic) xmlUCSIsGothic __attribute((alias("xmlUCSIsGothic__internal_alias"))); +#else +#ifndef xmlUCSIsGothic +extern __typeof (xmlUCSIsGothic) xmlUCSIsGothic__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsGothic xmlUCSIsGothic__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsGreek +extern __typeof (xmlUCSIsGreek) xmlUCSIsGreek __attribute((alias("xmlUCSIsGreek__internal_alias"))); +#else +#ifndef xmlUCSIsGreek +extern __typeof (xmlUCSIsGreek) xmlUCSIsGreek__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsGreek xmlUCSIsGreek__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsGreekExtended +extern __typeof (xmlUCSIsGreekExtended) xmlUCSIsGreekExtended __attribute((alias("xmlUCSIsGreekExtended__internal_alias"))); +#else +#ifndef xmlUCSIsGreekExtended +extern __typeof (xmlUCSIsGreekExtended) xmlUCSIsGreekExtended__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsGreekExtended xmlUCSIsGreekExtended__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsGreekandCoptic +extern __typeof (xmlUCSIsGreekandCoptic) xmlUCSIsGreekandCoptic __attribute((alias("xmlUCSIsGreekandCoptic__internal_alias"))); +#else +#ifndef xmlUCSIsGreekandCoptic +extern __typeof (xmlUCSIsGreekandCoptic) xmlUCSIsGreekandCoptic__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsGreekandCoptic xmlUCSIsGreekandCoptic__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsGujarati +extern __typeof (xmlUCSIsGujarati) xmlUCSIsGujarati __attribute((alias("xmlUCSIsGujarati__internal_alias"))); +#else +#ifndef xmlUCSIsGujarati +extern __typeof (xmlUCSIsGujarati) xmlUCSIsGujarati__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsGujarati xmlUCSIsGujarati__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsGurmukhi +extern __typeof (xmlUCSIsGurmukhi) xmlUCSIsGurmukhi __attribute((alias("xmlUCSIsGurmukhi__internal_alias"))); +#else +#ifndef xmlUCSIsGurmukhi +extern __typeof (xmlUCSIsGurmukhi) xmlUCSIsGurmukhi__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsGurmukhi xmlUCSIsGurmukhi__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsHalfwidthandFullwidthForms +extern __typeof (xmlUCSIsHalfwidthandFullwidthForms) xmlUCSIsHalfwidthandFullwidthForms __attribute((alias("xmlUCSIsHalfwidthandFullwidthForms__internal_alias"))); +#else +#ifndef xmlUCSIsHalfwidthandFullwidthForms +extern __typeof (xmlUCSIsHalfwidthandFullwidthForms) xmlUCSIsHalfwidthandFullwidthForms__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsHalfwidthandFullwidthForms xmlUCSIsHalfwidthandFullwidthForms__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsHangulCompatibilityJamo +extern __typeof (xmlUCSIsHangulCompatibilityJamo) xmlUCSIsHangulCompatibilityJamo __attribute((alias("xmlUCSIsHangulCompatibilityJamo__internal_alias"))); +#else +#ifndef xmlUCSIsHangulCompatibilityJamo +extern __typeof (xmlUCSIsHangulCompatibilityJamo) xmlUCSIsHangulCompatibilityJamo__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsHangulCompatibilityJamo xmlUCSIsHangulCompatibilityJamo__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsHangulJamo +extern __typeof (xmlUCSIsHangulJamo) xmlUCSIsHangulJamo __attribute((alias("xmlUCSIsHangulJamo__internal_alias"))); +#else +#ifndef xmlUCSIsHangulJamo +extern __typeof (xmlUCSIsHangulJamo) xmlUCSIsHangulJamo__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsHangulJamo xmlUCSIsHangulJamo__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsHangulSyllables +extern __typeof (xmlUCSIsHangulSyllables) xmlUCSIsHangulSyllables __attribute((alias("xmlUCSIsHangulSyllables__internal_alias"))); +#else +#ifndef xmlUCSIsHangulSyllables +extern __typeof (xmlUCSIsHangulSyllables) xmlUCSIsHangulSyllables__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsHangulSyllables xmlUCSIsHangulSyllables__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsHanunoo +extern __typeof (xmlUCSIsHanunoo) xmlUCSIsHanunoo __attribute((alias("xmlUCSIsHanunoo__internal_alias"))); +#else +#ifndef xmlUCSIsHanunoo +extern __typeof (xmlUCSIsHanunoo) xmlUCSIsHanunoo__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsHanunoo xmlUCSIsHanunoo__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsHebrew +extern __typeof (xmlUCSIsHebrew) xmlUCSIsHebrew __attribute((alias("xmlUCSIsHebrew__internal_alias"))); +#else +#ifndef xmlUCSIsHebrew +extern __typeof (xmlUCSIsHebrew) xmlUCSIsHebrew__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsHebrew xmlUCSIsHebrew__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsHighPrivateUseSurrogates +extern __typeof (xmlUCSIsHighPrivateUseSurrogates) xmlUCSIsHighPrivateUseSurrogates __attribute((alias("xmlUCSIsHighPrivateUseSurrogates__internal_alias"))); +#else +#ifndef xmlUCSIsHighPrivateUseSurrogates +extern __typeof (xmlUCSIsHighPrivateUseSurrogates) xmlUCSIsHighPrivateUseSurrogates__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsHighPrivateUseSurrogates xmlUCSIsHighPrivateUseSurrogates__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsHighSurrogates +extern __typeof (xmlUCSIsHighSurrogates) xmlUCSIsHighSurrogates __attribute((alias("xmlUCSIsHighSurrogates__internal_alias"))); +#else +#ifndef xmlUCSIsHighSurrogates +extern __typeof (xmlUCSIsHighSurrogates) xmlUCSIsHighSurrogates__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsHighSurrogates xmlUCSIsHighSurrogates__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsHiragana +extern __typeof (xmlUCSIsHiragana) xmlUCSIsHiragana __attribute((alias("xmlUCSIsHiragana__internal_alias"))); +#else +#ifndef xmlUCSIsHiragana +extern __typeof (xmlUCSIsHiragana) xmlUCSIsHiragana__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsHiragana xmlUCSIsHiragana__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsIPAExtensions +extern __typeof (xmlUCSIsIPAExtensions) xmlUCSIsIPAExtensions __attribute((alias("xmlUCSIsIPAExtensions__internal_alias"))); +#else +#ifndef xmlUCSIsIPAExtensions +extern __typeof (xmlUCSIsIPAExtensions) xmlUCSIsIPAExtensions__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsIPAExtensions xmlUCSIsIPAExtensions__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsIdeographicDescriptionCharacters +extern __typeof (xmlUCSIsIdeographicDescriptionCharacters) xmlUCSIsIdeographicDescriptionCharacters __attribute((alias("xmlUCSIsIdeographicDescriptionCharacters__internal_alias"))); +#else +#ifndef xmlUCSIsIdeographicDescriptionCharacters +extern __typeof (xmlUCSIsIdeographicDescriptionCharacters) xmlUCSIsIdeographicDescriptionCharacters__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsIdeographicDescriptionCharacters xmlUCSIsIdeographicDescriptionCharacters__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsKanbun +extern __typeof (xmlUCSIsKanbun) xmlUCSIsKanbun __attribute((alias("xmlUCSIsKanbun__internal_alias"))); +#else +#ifndef xmlUCSIsKanbun +extern __typeof (xmlUCSIsKanbun) xmlUCSIsKanbun__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsKanbun xmlUCSIsKanbun__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsKangxiRadicals +extern __typeof (xmlUCSIsKangxiRadicals) xmlUCSIsKangxiRadicals __attribute((alias("xmlUCSIsKangxiRadicals__internal_alias"))); +#else +#ifndef xmlUCSIsKangxiRadicals +extern __typeof (xmlUCSIsKangxiRadicals) xmlUCSIsKangxiRadicals__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsKangxiRadicals xmlUCSIsKangxiRadicals__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsKannada +extern __typeof (xmlUCSIsKannada) xmlUCSIsKannada __attribute((alias("xmlUCSIsKannada__internal_alias"))); +#else +#ifndef xmlUCSIsKannada +extern __typeof (xmlUCSIsKannada) xmlUCSIsKannada__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsKannada xmlUCSIsKannada__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsKatakana +extern __typeof (xmlUCSIsKatakana) xmlUCSIsKatakana __attribute((alias("xmlUCSIsKatakana__internal_alias"))); +#else +#ifndef xmlUCSIsKatakana +extern __typeof (xmlUCSIsKatakana) xmlUCSIsKatakana__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsKatakana xmlUCSIsKatakana__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsKatakanaPhoneticExtensions +extern __typeof (xmlUCSIsKatakanaPhoneticExtensions) xmlUCSIsKatakanaPhoneticExtensions __attribute((alias("xmlUCSIsKatakanaPhoneticExtensions__internal_alias"))); +#else +#ifndef xmlUCSIsKatakanaPhoneticExtensions +extern __typeof (xmlUCSIsKatakanaPhoneticExtensions) xmlUCSIsKatakanaPhoneticExtensions__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsKatakanaPhoneticExtensions xmlUCSIsKatakanaPhoneticExtensions__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsKhmer +extern __typeof (xmlUCSIsKhmer) xmlUCSIsKhmer __attribute((alias("xmlUCSIsKhmer__internal_alias"))); +#else +#ifndef xmlUCSIsKhmer +extern __typeof (xmlUCSIsKhmer) xmlUCSIsKhmer__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsKhmer xmlUCSIsKhmer__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsKhmerSymbols +extern __typeof (xmlUCSIsKhmerSymbols) xmlUCSIsKhmerSymbols __attribute((alias("xmlUCSIsKhmerSymbols__internal_alias"))); +#else +#ifndef xmlUCSIsKhmerSymbols +extern __typeof (xmlUCSIsKhmerSymbols) xmlUCSIsKhmerSymbols__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsKhmerSymbols xmlUCSIsKhmerSymbols__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsLao +extern __typeof (xmlUCSIsLao) xmlUCSIsLao __attribute((alias("xmlUCSIsLao__internal_alias"))); +#else +#ifndef xmlUCSIsLao +extern __typeof (xmlUCSIsLao) xmlUCSIsLao__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsLao xmlUCSIsLao__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsLatin1Supplement +extern __typeof (xmlUCSIsLatin1Supplement) xmlUCSIsLatin1Supplement __attribute((alias("xmlUCSIsLatin1Supplement__internal_alias"))); +#else +#ifndef xmlUCSIsLatin1Supplement +extern __typeof (xmlUCSIsLatin1Supplement) xmlUCSIsLatin1Supplement__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsLatin1Supplement xmlUCSIsLatin1Supplement__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsLatinExtendedA +extern __typeof (xmlUCSIsLatinExtendedA) xmlUCSIsLatinExtendedA __attribute((alias("xmlUCSIsLatinExtendedA__internal_alias"))); +#else +#ifndef xmlUCSIsLatinExtendedA +extern __typeof (xmlUCSIsLatinExtendedA) xmlUCSIsLatinExtendedA__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsLatinExtendedA xmlUCSIsLatinExtendedA__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsLatinExtendedAdditional +extern __typeof (xmlUCSIsLatinExtendedAdditional) xmlUCSIsLatinExtendedAdditional __attribute((alias("xmlUCSIsLatinExtendedAdditional__internal_alias"))); +#else +#ifndef xmlUCSIsLatinExtendedAdditional +extern __typeof (xmlUCSIsLatinExtendedAdditional) xmlUCSIsLatinExtendedAdditional__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsLatinExtendedAdditional xmlUCSIsLatinExtendedAdditional__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsLatinExtendedB +extern __typeof (xmlUCSIsLatinExtendedB) xmlUCSIsLatinExtendedB __attribute((alias("xmlUCSIsLatinExtendedB__internal_alias"))); +#else +#ifndef xmlUCSIsLatinExtendedB +extern __typeof (xmlUCSIsLatinExtendedB) xmlUCSIsLatinExtendedB__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsLatinExtendedB xmlUCSIsLatinExtendedB__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsLetterlikeSymbols +extern __typeof (xmlUCSIsLetterlikeSymbols) xmlUCSIsLetterlikeSymbols __attribute((alias("xmlUCSIsLetterlikeSymbols__internal_alias"))); +#else +#ifndef xmlUCSIsLetterlikeSymbols +extern __typeof (xmlUCSIsLetterlikeSymbols) xmlUCSIsLetterlikeSymbols__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsLetterlikeSymbols xmlUCSIsLetterlikeSymbols__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsLimbu +extern __typeof (xmlUCSIsLimbu) xmlUCSIsLimbu __attribute((alias("xmlUCSIsLimbu__internal_alias"))); +#else +#ifndef xmlUCSIsLimbu +extern __typeof (xmlUCSIsLimbu) xmlUCSIsLimbu__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsLimbu xmlUCSIsLimbu__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsLinearBIdeograms +extern __typeof (xmlUCSIsLinearBIdeograms) xmlUCSIsLinearBIdeograms __attribute((alias("xmlUCSIsLinearBIdeograms__internal_alias"))); +#else +#ifndef xmlUCSIsLinearBIdeograms +extern __typeof (xmlUCSIsLinearBIdeograms) xmlUCSIsLinearBIdeograms__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsLinearBIdeograms xmlUCSIsLinearBIdeograms__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsLinearBSyllabary +extern __typeof (xmlUCSIsLinearBSyllabary) xmlUCSIsLinearBSyllabary __attribute((alias("xmlUCSIsLinearBSyllabary__internal_alias"))); +#else +#ifndef xmlUCSIsLinearBSyllabary +extern __typeof (xmlUCSIsLinearBSyllabary) xmlUCSIsLinearBSyllabary__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsLinearBSyllabary xmlUCSIsLinearBSyllabary__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsLowSurrogates +extern __typeof (xmlUCSIsLowSurrogates) xmlUCSIsLowSurrogates __attribute((alias("xmlUCSIsLowSurrogates__internal_alias"))); +#else +#ifndef xmlUCSIsLowSurrogates +extern __typeof (xmlUCSIsLowSurrogates) xmlUCSIsLowSurrogates__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsLowSurrogates xmlUCSIsLowSurrogates__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsMalayalam +extern __typeof (xmlUCSIsMalayalam) xmlUCSIsMalayalam __attribute((alias("xmlUCSIsMalayalam__internal_alias"))); +#else +#ifndef xmlUCSIsMalayalam +extern __typeof (xmlUCSIsMalayalam) xmlUCSIsMalayalam__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsMalayalam xmlUCSIsMalayalam__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsMathematicalAlphanumericSymbols +extern __typeof (xmlUCSIsMathematicalAlphanumericSymbols) xmlUCSIsMathematicalAlphanumericSymbols __attribute((alias("xmlUCSIsMathematicalAlphanumericSymbols__internal_alias"))); +#else +#ifndef xmlUCSIsMathematicalAlphanumericSymbols +extern __typeof (xmlUCSIsMathematicalAlphanumericSymbols) xmlUCSIsMathematicalAlphanumericSymbols__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsMathematicalAlphanumericSymbols xmlUCSIsMathematicalAlphanumericSymbols__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsMathematicalOperators +extern __typeof (xmlUCSIsMathematicalOperators) xmlUCSIsMathematicalOperators __attribute((alias("xmlUCSIsMathematicalOperators__internal_alias"))); +#else +#ifndef xmlUCSIsMathematicalOperators +extern __typeof (xmlUCSIsMathematicalOperators) xmlUCSIsMathematicalOperators__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsMathematicalOperators xmlUCSIsMathematicalOperators__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsMiscellaneousMathematicalSymbolsA +extern __typeof (xmlUCSIsMiscellaneousMathematicalSymbolsA) xmlUCSIsMiscellaneousMathematicalSymbolsA __attribute((alias("xmlUCSIsMiscellaneousMathematicalSymbolsA__internal_alias"))); +#else +#ifndef xmlUCSIsMiscellaneousMathematicalSymbolsA +extern __typeof (xmlUCSIsMiscellaneousMathematicalSymbolsA) xmlUCSIsMiscellaneousMathematicalSymbolsA__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsMiscellaneousMathematicalSymbolsA xmlUCSIsMiscellaneousMathematicalSymbolsA__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsMiscellaneousMathematicalSymbolsB +extern __typeof (xmlUCSIsMiscellaneousMathematicalSymbolsB) xmlUCSIsMiscellaneousMathematicalSymbolsB __attribute((alias("xmlUCSIsMiscellaneousMathematicalSymbolsB__internal_alias"))); +#else +#ifndef xmlUCSIsMiscellaneousMathematicalSymbolsB +extern __typeof (xmlUCSIsMiscellaneousMathematicalSymbolsB) xmlUCSIsMiscellaneousMathematicalSymbolsB__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsMiscellaneousMathematicalSymbolsB xmlUCSIsMiscellaneousMathematicalSymbolsB__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsMiscellaneousSymbols +extern __typeof (xmlUCSIsMiscellaneousSymbols) xmlUCSIsMiscellaneousSymbols __attribute((alias("xmlUCSIsMiscellaneousSymbols__internal_alias"))); +#else +#ifndef xmlUCSIsMiscellaneousSymbols +extern __typeof (xmlUCSIsMiscellaneousSymbols) xmlUCSIsMiscellaneousSymbols__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsMiscellaneousSymbols xmlUCSIsMiscellaneousSymbols__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsMiscellaneousSymbolsandArrows +extern __typeof (xmlUCSIsMiscellaneousSymbolsandArrows) xmlUCSIsMiscellaneousSymbolsandArrows __attribute((alias("xmlUCSIsMiscellaneousSymbolsandArrows__internal_alias"))); +#else +#ifndef xmlUCSIsMiscellaneousSymbolsandArrows +extern __typeof (xmlUCSIsMiscellaneousSymbolsandArrows) xmlUCSIsMiscellaneousSymbolsandArrows__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsMiscellaneousSymbolsandArrows xmlUCSIsMiscellaneousSymbolsandArrows__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsMiscellaneousTechnical +extern __typeof (xmlUCSIsMiscellaneousTechnical) xmlUCSIsMiscellaneousTechnical __attribute((alias("xmlUCSIsMiscellaneousTechnical__internal_alias"))); +#else +#ifndef xmlUCSIsMiscellaneousTechnical +extern __typeof (xmlUCSIsMiscellaneousTechnical) xmlUCSIsMiscellaneousTechnical__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsMiscellaneousTechnical xmlUCSIsMiscellaneousTechnical__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsMongolian +extern __typeof (xmlUCSIsMongolian) xmlUCSIsMongolian __attribute((alias("xmlUCSIsMongolian__internal_alias"))); +#else +#ifndef xmlUCSIsMongolian +extern __typeof (xmlUCSIsMongolian) xmlUCSIsMongolian__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsMongolian xmlUCSIsMongolian__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsMusicalSymbols +extern __typeof (xmlUCSIsMusicalSymbols) xmlUCSIsMusicalSymbols __attribute((alias("xmlUCSIsMusicalSymbols__internal_alias"))); +#else +#ifndef xmlUCSIsMusicalSymbols +extern __typeof (xmlUCSIsMusicalSymbols) xmlUCSIsMusicalSymbols__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsMusicalSymbols xmlUCSIsMusicalSymbols__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsMyanmar +extern __typeof (xmlUCSIsMyanmar) xmlUCSIsMyanmar __attribute((alias("xmlUCSIsMyanmar__internal_alias"))); +#else +#ifndef xmlUCSIsMyanmar +extern __typeof (xmlUCSIsMyanmar) xmlUCSIsMyanmar__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsMyanmar xmlUCSIsMyanmar__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsNumberForms +extern __typeof (xmlUCSIsNumberForms) xmlUCSIsNumberForms __attribute((alias("xmlUCSIsNumberForms__internal_alias"))); +#else +#ifndef xmlUCSIsNumberForms +extern __typeof (xmlUCSIsNumberForms) xmlUCSIsNumberForms__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsNumberForms xmlUCSIsNumberForms__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsOgham +extern __typeof (xmlUCSIsOgham) xmlUCSIsOgham __attribute((alias("xmlUCSIsOgham__internal_alias"))); +#else +#ifndef xmlUCSIsOgham +extern __typeof (xmlUCSIsOgham) xmlUCSIsOgham__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsOgham xmlUCSIsOgham__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsOldItalic +extern __typeof (xmlUCSIsOldItalic) xmlUCSIsOldItalic __attribute((alias("xmlUCSIsOldItalic__internal_alias"))); +#else +#ifndef xmlUCSIsOldItalic +extern __typeof (xmlUCSIsOldItalic) xmlUCSIsOldItalic__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsOldItalic xmlUCSIsOldItalic__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsOpticalCharacterRecognition +extern __typeof (xmlUCSIsOpticalCharacterRecognition) xmlUCSIsOpticalCharacterRecognition __attribute((alias("xmlUCSIsOpticalCharacterRecognition__internal_alias"))); +#else +#ifndef xmlUCSIsOpticalCharacterRecognition +extern __typeof (xmlUCSIsOpticalCharacterRecognition) xmlUCSIsOpticalCharacterRecognition__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsOpticalCharacterRecognition xmlUCSIsOpticalCharacterRecognition__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsOriya +extern __typeof (xmlUCSIsOriya) xmlUCSIsOriya __attribute((alias("xmlUCSIsOriya__internal_alias"))); +#else +#ifndef xmlUCSIsOriya +extern __typeof (xmlUCSIsOriya) xmlUCSIsOriya__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsOriya xmlUCSIsOriya__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsOsmanya +extern __typeof (xmlUCSIsOsmanya) xmlUCSIsOsmanya __attribute((alias("xmlUCSIsOsmanya__internal_alias"))); +#else +#ifndef xmlUCSIsOsmanya +extern __typeof (xmlUCSIsOsmanya) xmlUCSIsOsmanya__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsOsmanya xmlUCSIsOsmanya__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsPhoneticExtensions +extern __typeof (xmlUCSIsPhoneticExtensions) xmlUCSIsPhoneticExtensions __attribute((alias("xmlUCSIsPhoneticExtensions__internal_alias"))); +#else +#ifndef xmlUCSIsPhoneticExtensions +extern __typeof (xmlUCSIsPhoneticExtensions) xmlUCSIsPhoneticExtensions__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsPhoneticExtensions xmlUCSIsPhoneticExtensions__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsPrivateUse +extern __typeof (xmlUCSIsPrivateUse) xmlUCSIsPrivateUse __attribute((alias("xmlUCSIsPrivateUse__internal_alias"))); +#else +#ifndef xmlUCSIsPrivateUse +extern __typeof (xmlUCSIsPrivateUse) xmlUCSIsPrivateUse__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsPrivateUse xmlUCSIsPrivateUse__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsPrivateUseArea +extern __typeof (xmlUCSIsPrivateUseArea) xmlUCSIsPrivateUseArea __attribute((alias("xmlUCSIsPrivateUseArea__internal_alias"))); +#else +#ifndef xmlUCSIsPrivateUseArea +extern __typeof (xmlUCSIsPrivateUseArea) xmlUCSIsPrivateUseArea__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsPrivateUseArea xmlUCSIsPrivateUseArea__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsRunic +extern __typeof (xmlUCSIsRunic) xmlUCSIsRunic __attribute((alias("xmlUCSIsRunic__internal_alias"))); +#else +#ifndef xmlUCSIsRunic +extern __typeof (xmlUCSIsRunic) xmlUCSIsRunic__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsRunic xmlUCSIsRunic__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsShavian +extern __typeof (xmlUCSIsShavian) xmlUCSIsShavian __attribute((alias("xmlUCSIsShavian__internal_alias"))); +#else +#ifndef xmlUCSIsShavian +extern __typeof (xmlUCSIsShavian) xmlUCSIsShavian__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsShavian xmlUCSIsShavian__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsSinhala +extern __typeof (xmlUCSIsSinhala) xmlUCSIsSinhala __attribute((alias("xmlUCSIsSinhala__internal_alias"))); +#else +#ifndef xmlUCSIsSinhala +extern __typeof (xmlUCSIsSinhala) xmlUCSIsSinhala__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsSinhala xmlUCSIsSinhala__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsSmallFormVariants +extern __typeof (xmlUCSIsSmallFormVariants) xmlUCSIsSmallFormVariants __attribute((alias("xmlUCSIsSmallFormVariants__internal_alias"))); +#else +#ifndef xmlUCSIsSmallFormVariants +extern __typeof (xmlUCSIsSmallFormVariants) xmlUCSIsSmallFormVariants__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsSmallFormVariants xmlUCSIsSmallFormVariants__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsSpacingModifierLetters +extern __typeof (xmlUCSIsSpacingModifierLetters) xmlUCSIsSpacingModifierLetters __attribute((alias("xmlUCSIsSpacingModifierLetters__internal_alias"))); +#else +#ifndef xmlUCSIsSpacingModifierLetters +extern __typeof (xmlUCSIsSpacingModifierLetters) xmlUCSIsSpacingModifierLetters__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsSpacingModifierLetters xmlUCSIsSpacingModifierLetters__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsSpecials +extern __typeof (xmlUCSIsSpecials) xmlUCSIsSpecials __attribute((alias("xmlUCSIsSpecials__internal_alias"))); +#else +#ifndef xmlUCSIsSpecials +extern __typeof (xmlUCSIsSpecials) xmlUCSIsSpecials__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsSpecials xmlUCSIsSpecials__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsSuperscriptsandSubscripts +extern __typeof (xmlUCSIsSuperscriptsandSubscripts) xmlUCSIsSuperscriptsandSubscripts __attribute((alias("xmlUCSIsSuperscriptsandSubscripts__internal_alias"))); +#else +#ifndef xmlUCSIsSuperscriptsandSubscripts +extern __typeof (xmlUCSIsSuperscriptsandSubscripts) xmlUCSIsSuperscriptsandSubscripts__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsSuperscriptsandSubscripts xmlUCSIsSuperscriptsandSubscripts__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsSupplementalArrowsA +extern __typeof (xmlUCSIsSupplementalArrowsA) xmlUCSIsSupplementalArrowsA __attribute((alias("xmlUCSIsSupplementalArrowsA__internal_alias"))); +#else +#ifndef xmlUCSIsSupplementalArrowsA +extern __typeof (xmlUCSIsSupplementalArrowsA) xmlUCSIsSupplementalArrowsA__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsSupplementalArrowsA xmlUCSIsSupplementalArrowsA__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsSupplementalArrowsB +extern __typeof (xmlUCSIsSupplementalArrowsB) xmlUCSIsSupplementalArrowsB __attribute((alias("xmlUCSIsSupplementalArrowsB__internal_alias"))); +#else +#ifndef xmlUCSIsSupplementalArrowsB +extern __typeof (xmlUCSIsSupplementalArrowsB) xmlUCSIsSupplementalArrowsB__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsSupplementalArrowsB xmlUCSIsSupplementalArrowsB__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsSupplementalMathematicalOperators +extern __typeof (xmlUCSIsSupplementalMathematicalOperators) xmlUCSIsSupplementalMathematicalOperators __attribute((alias("xmlUCSIsSupplementalMathematicalOperators__internal_alias"))); +#else +#ifndef xmlUCSIsSupplementalMathematicalOperators +extern __typeof (xmlUCSIsSupplementalMathematicalOperators) xmlUCSIsSupplementalMathematicalOperators__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsSupplementalMathematicalOperators xmlUCSIsSupplementalMathematicalOperators__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsSupplementaryPrivateUseAreaA +extern __typeof (xmlUCSIsSupplementaryPrivateUseAreaA) xmlUCSIsSupplementaryPrivateUseAreaA __attribute((alias("xmlUCSIsSupplementaryPrivateUseAreaA__internal_alias"))); +#else +#ifndef xmlUCSIsSupplementaryPrivateUseAreaA +extern __typeof (xmlUCSIsSupplementaryPrivateUseAreaA) xmlUCSIsSupplementaryPrivateUseAreaA__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsSupplementaryPrivateUseAreaA xmlUCSIsSupplementaryPrivateUseAreaA__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsSupplementaryPrivateUseAreaB +extern __typeof (xmlUCSIsSupplementaryPrivateUseAreaB) xmlUCSIsSupplementaryPrivateUseAreaB __attribute((alias("xmlUCSIsSupplementaryPrivateUseAreaB__internal_alias"))); +#else +#ifndef xmlUCSIsSupplementaryPrivateUseAreaB +extern __typeof (xmlUCSIsSupplementaryPrivateUseAreaB) xmlUCSIsSupplementaryPrivateUseAreaB__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsSupplementaryPrivateUseAreaB xmlUCSIsSupplementaryPrivateUseAreaB__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsSyriac +extern __typeof (xmlUCSIsSyriac) xmlUCSIsSyriac __attribute((alias("xmlUCSIsSyriac__internal_alias"))); +#else +#ifndef xmlUCSIsSyriac +extern __typeof (xmlUCSIsSyriac) xmlUCSIsSyriac__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsSyriac xmlUCSIsSyriac__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsTagalog +extern __typeof (xmlUCSIsTagalog) xmlUCSIsTagalog __attribute((alias("xmlUCSIsTagalog__internal_alias"))); +#else +#ifndef xmlUCSIsTagalog +extern __typeof (xmlUCSIsTagalog) xmlUCSIsTagalog__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsTagalog xmlUCSIsTagalog__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsTagbanwa +extern __typeof (xmlUCSIsTagbanwa) xmlUCSIsTagbanwa __attribute((alias("xmlUCSIsTagbanwa__internal_alias"))); +#else +#ifndef xmlUCSIsTagbanwa +extern __typeof (xmlUCSIsTagbanwa) xmlUCSIsTagbanwa__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsTagbanwa xmlUCSIsTagbanwa__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsTags +extern __typeof (xmlUCSIsTags) xmlUCSIsTags __attribute((alias("xmlUCSIsTags__internal_alias"))); +#else +#ifndef xmlUCSIsTags +extern __typeof (xmlUCSIsTags) xmlUCSIsTags__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsTags xmlUCSIsTags__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsTaiLe +extern __typeof (xmlUCSIsTaiLe) xmlUCSIsTaiLe __attribute((alias("xmlUCSIsTaiLe__internal_alias"))); +#else +#ifndef xmlUCSIsTaiLe +extern __typeof (xmlUCSIsTaiLe) xmlUCSIsTaiLe__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsTaiLe xmlUCSIsTaiLe__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsTaiXuanJingSymbols +extern __typeof (xmlUCSIsTaiXuanJingSymbols) xmlUCSIsTaiXuanJingSymbols __attribute((alias("xmlUCSIsTaiXuanJingSymbols__internal_alias"))); +#else +#ifndef xmlUCSIsTaiXuanJingSymbols +extern __typeof (xmlUCSIsTaiXuanJingSymbols) xmlUCSIsTaiXuanJingSymbols__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsTaiXuanJingSymbols xmlUCSIsTaiXuanJingSymbols__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsTamil +extern __typeof (xmlUCSIsTamil) xmlUCSIsTamil __attribute((alias("xmlUCSIsTamil__internal_alias"))); +#else +#ifndef xmlUCSIsTamil +extern __typeof (xmlUCSIsTamil) xmlUCSIsTamil__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsTamil xmlUCSIsTamil__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsTelugu +extern __typeof (xmlUCSIsTelugu) xmlUCSIsTelugu __attribute((alias("xmlUCSIsTelugu__internal_alias"))); +#else +#ifndef xmlUCSIsTelugu +extern __typeof (xmlUCSIsTelugu) xmlUCSIsTelugu__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsTelugu xmlUCSIsTelugu__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsThaana +extern __typeof (xmlUCSIsThaana) xmlUCSIsThaana __attribute((alias("xmlUCSIsThaana__internal_alias"))); +#else +#ifndef xmlUCSIsThaana +extern __typeof (xmlUCSIsThaana) xmlUCSIsThaana__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsThaana xmlUCSIsThaana__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsThai +extern __typeof (xmlUCSIsThai) xmlUCSIsThai __attribute((alias("xmlUCSIsThai__internal_alias"))); +#else +#ifndef xmlUCSIsThai +extern __typeof (xmlUCSIsThai) xmlUCSIsThai__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsThai xmlUCSIsThai__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsTibetan +extern __typeof (xmlUCSIsTibetan) xmlUCSIsTibetan __attribute((alias("xmlUCSIsTibetan__internal_alias"))); +#else +#ifndef xmlUCSIsTibetan +extern __typeof (xmlUCSIsTibetan) xmlUCSIsTibetan__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsTibetan xmlUCSIsTibetan__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsUgaritic +extern __typeof (xmlUCSIsUgaritic) xmlUCSIsUgaritic __attribute((alias("xmlUCSIsUgaritic__internal_alias"))); +#else +#ifndef xmlUCSIsUgaritic +extern __typeof (xmlUCSIsUgaritic) xmlUCSIsUgaritic__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsUgaritic xmlUCSIsUgaritic__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsUnifiedCanadianAboriginalSyllabics +extern __typeof (xmlUCSIsUnifiedCanadianAboriginalSyllabics) xmlUCSIsUnifiedCanadianAboriginalSyllabics __attribute((alias("xmlUCSIsUnifiedCanadianAboriginalSyllabics__internal_alias"))); +#else +#ifndef xmlUCSIsUnifiedCanadianAboriginalSyllabics +extern __typeof (xmlUCSIsUnifiedCanadianAboriginalSyllabics) xmlUCSIsUnifiedCanadianAboriginalSyllabics__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsUnifiedCanadianAboriginalSyllabics xmlUCSIsUnifiedCanadianAboriginalSyllabics__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsVariationSelectors +extern __typeof (xmlUCSIsVariationSelectors) xmlUCSIsVariationSelectors __attribute((alias("xmlUCSIsVariationSelectors__internal_alias"))); +#else +#ifndef xmlUCSIsVariationSelectors +extern __typeof (xmlUCSIsVariationSelectors) xmlUCSIsVariationSelectors__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsVariationSelectors xmlUCSIsVariationSelectors__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsVariationSelectorsSupplement +extern __typeof (xmlUCSIsVariationSelectorsSupplement) xmlUCSIsVariationSelectorsSupplement __attribute((alias("xmlUCSIsVariationSelectorsSupplement__internal_alias"))); +#else +#ifndef xmlUCSIsVariationSelectorsSupplement +extern __typeof (xmlUCSIsVariationSelectorsSupplement) xmlUCSIsVariationSelectorsSupplement__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsVariationSelectorsSupplement xmlUCSIsVariationSelectorsSupplement__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsYiRadicals +extern __typeof (xmlUCSIsYiRadicals) xmlUCSIsYiRadicals __attribute((alias("xmlUCSIsYiRadicals__internal_alias"))); +#else +#ifndef xmlUCSIsYiRadicals +extern __typeof (xmlUCSIsYiRadicals) xmlUCSIsYiRadicals__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsYiRadicals xmlUCSIsYiRadicals__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsYiSyllables +extern __typeof (xmlUCSIsYiSyllables) xmlUCSIsYiSyllables __attribute((alias("xmlUCSIsYiSyllables__internal_alias"))); +#else +#ifndef xmlUCSIsYiSyllables +extern __typeof (xmlUCSIsYiSyllables) xmlUCSIsYiSyllables__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsYiSyllables xmlUCSIsYiSyllables__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_UNICODE_ENABLED) +#ifdef bottom_xmlunicode +#undef xmlUCSIsYijingHexagramSymbols +extern __typeof (xmlUCSIsYijingHexagramSymbols) xmlUCSIsYijingHexagramSymbols __attribute((alias("xmlUCSIsYijingHexagramSymbols__internal_alias"))); +#else +#ifndef xmlUCSIsYijingHexagramSymbols +extern __typeof (xmlUCSIsYijingHexagramSymbols) xmlUCSIsYijingHexagramSymbols__internal_alias __attribute((visibility("hidden"))); +#define xmlUCSIsYijingHexagramSymbols xmlUCSIsYijingHexagramSymbols__internal_alias +#endif +#endif +#endif + +#ifdef bottom_uri +#undef xmlURIEscape +extern __typeof (xmlURIEscape) xmlURIEscape __attribute((alias("xmlURIEscape__internal_alias"))); +#else +#ifndef xmlURIEscape +extern __typeof (xmlURIEscape) xmlURIEscape__internal_alias __attribute((visibility("hidden"))); +#define xmlURIEscape xmlURIEscape__internal_alias +#endif +#endif + +#ifdef bottom_uri +#undef xmlURIEscapeStr +extern __typeof (xmlURIEscapeStr) xmlURIEscapeStr __attribute((alias("xmlURIEscapeStr__internal_alias"))); +#else +#ifndef xmlURIEscapeStr +extern __typeof (xmlURIEscapeStr) xmlURIEscapeStr__internal_alias __attribute((visibility("hidden"))); +#define xmlURIEscapeStr xmlURIEscapeStr__internal_alias +#endif +#endif + +#ifdef bottom_uri +#undef xmlURIUnescapeString +extern __typeof (xmlURIUnescapeString) xmlURIUnescapeString __attribute((alias("xmlURIUnescapeString__internal_alias"))); +#else +#ifndef xmlURIUnescapeString +extern __typeof (xmlURIUnescapeString) xmlURIUnescapeString__internal_alias __attribute((visibility("hidden"))); +#define xmlURIUnescapeString xmlURIUnescapeString__internal_alias +#endif +#endif + +#ifdef bottom_xmlstring +#undef xmlUTF8Charcmp +extern __typeof (xmlUTF8Charcmp) xmlUTF8Charcmp __attribute((alias("xmlUTF8Charcmp__internal_alias"))); +#else +#ifndef xmlUTF8Charcmp +extern __typeof (xmlUTF8Charcmp) xmlUTF8Charcmp__internal_alias __attribute((visibility("hidden"))); +#define xmlUTF8Charcmp xmlUTF8Charcmp__internal_alias +#endif +#endif + +#ifdef bottom_xmlstring +#undef xmlUTF8Size +extern __typeof (xmlUTF8Size) xmlUTF8Size __attribute((alias("xmlUTF8Size__internal_alias"))); +#else +#ifndef xmlUTF8Size +extern __typeof (xmlUTF8Size) xmlUTF8Size__internal_alias __attribute((visibility("hidden"))); +#define xmlUTF8Size xmlUTF8Size__internal_alias +#endif +#endif + +#ifdef bottom_xmlstring +#undef xmlUTF8Strlen +extern __typeof (xmlUTF8Strlen) xmlUTF8Strlen __attribute((alias("xmlUTF8Strlen__internal_alias"))); +#else +#ifndef xmlUTF8Strlen +extern __typeof (xmlUTF8Strlen) xmlUTF8Strlen__internal_alias __attribute((visibility("hidden"))); +#define xmlUTF8Strlen xmlUTF8Strlen__internal_alias +#endif +#endif + +#ifdef bottom_xmlstring +#undef xmlUTF8Strloc +extern __typeof (xmlUTF8Strloc) xmlUTF8Strloc __attribute((alias("xmlUTF8Strloc__internal_alias"))); +#else +#ifndef xmlUTF8Strloc +extern __typeof (xmlUTF8Strloc) xmlUTF8Strloc__internal_alias __attribute((visibility("hidden"))); +#define xmlUTF8Strloc xmlUTF8Strloc__internal_alias +#endif +#endif + +#ifdef bottom_xmlstring +#undef xmlUTF8Strndup +extern __typeof (xmlUTF8Strndup) xmlUTF8Strndup __attribute((alias("xmlUTF8Strndup__internal_alias"))); +#else +#ifndef xmlUTF8Strndup +extern __typeof (xmlUTF8Strndup) xmlUTF8Strndup__internal_alias __attribute((visibility("hidden"))); +#define xmlUTF8Strndup xmlUTF8Strndup__internal_alias +#endif +#endif + +#ifdef bottom_xmlstring +#undef xmlUTF8Strpos +extern __typeof (xmlUTF8Strpos) xmlUTF8Strpos __attribute((alias("xmlUTF8Strpos__internal_alias"))); +#else +#ifndef xmlUTF8Strpos +extern __typeof (xmlUTF8Strpos) xmlUTF8Strpos__internal_alias __attribute((visibility("hidden"))); +#define xmlUTF8Strpos xmlUTF8Strpos__internal_alias +#endif +#endif + +#ifdef bottom_xmlstring +#undef xmlUTF8Strsize +extern __typeof (xmlUTF8Strsize) xmlUTF8Strsize __attribute((alias("xmlUTF8Strsize__internal_alias"))); +#else +#ifndef xmlUTF8Strsize +extern __typeof (xmlUTF8Strsize) xmlUTF8Strsize__internal_alias __attribute((visibility("hidden"))); +#define xmlUTF8Strsize xmlUTF8Strsize__internal_alias +#endif +#endif + +#ifdef bottom_xmlstring +#undef xmlUTF8Strsub +extern __typeof (xmlUTF8Strsub) xmlUTF8Strsub __attribute((alias("xmlUTF8Strsub__internal_alias"))); +#else +#ifndef xmlUTF8Strsub +extern __typeof (xmlUTF8Strsub) xmlUTF8Strsub__internal_alias __attribute((visibility("hidden"))); +#define xmlUTF8Strsub xmlUTF8Strsub__internal_alias +#endif +#endif + +#ifdef bottom_tree +#undef xmlUnlinkNode +extern __typeof (xmlUnlinkNode) xmlUnlinkNode __attribute((alias("xmlUnlinkNode__internal_alias"))); +#else +#ifndef xmlUnlinkNode +extern __typeof (xmlUnlinkNode) xmlUnlinkNode__internal_alias __attribute((visibility("hidden"))); +#define xmlUnlinkNode xmlUnlinkNode__internal_alias +#endif +#endif + +#ifdef bottom_threads +#undef xmlUnlockLibrary +extern __typeof (xmlUnlockLibrary) xmlUnlockLibrary __attribute((alias("xmlUnlockLibrary__internal_alias"))); +#else +#ifndef xmlUnlockLibrary +extern __typeof (xmlUnlockLibrary) xmlUnlockLibrary__internal_alias __attribute((visibility("hidden"))); +#define xmlUnlockLibrary xmlUnlockLibrary__internal_alias +#endif +#endif + +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_tree +#undef xmlUnsetNsProp +extern __typeof (xmlUnsetNsProp) xmlUnsetNsProp __attribute((alias("xmlUnsetNsProp__internal_alias"))); +#else +#ifndef xmlUnsetNsProp +extern __typeof (xmlUnsetNsProp) xmlUnsetNsProp__internal_alias __attribute((visibility("hidden"))); +#define xmlUnsetNsProp xmlUnsetNsProp__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_tree +#undef xmlUnsetProp +extern __typeof (xmlUnsetProp) xmlUnsetProp __attribute((alias("xmlUnsetProp__internal_alias"))); +#else +#ifndef xmlUnsetProp +extern __typeof (xmlUnsetProp) xmlUnsetProp__internal_alias __attribute((visibility("hidden"))); +#define xmlUnsetProp xmlUnsetProp__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_VALID_ENABLED) && defined(LIBXML_REGEXP_ENABLED) +#ifdef bottom_valid +#undef xmlValidBuildContentModel +extern __typeof (xmlValidBuildContentModel) xmlValidBuildContentModel __attribute((alias("xmlValidBuildContentModel__internal_alias"))); +#else +#ifndef xmlValidBuildContentModel +extern __typeof (xmlValidBuildContentModel) xmlValidBuildContentModel__internal_alias __attribute((visibility("hidden"))); +#define xmlValidBuildContentModel xmlValidBuildContentModel__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_VALID_ENABLED) +#ifdef bottom_valid +#undef xmlValidCtxtNormalizeAttributeValue +extern __typeof (xmlValidCtxtNormalizeAttributeValue) xmlValidCtxtNormalizeAttributeValue __attribute((alias("xmlValidCtxtNormalizeAttributeValue__internal_alias"))); +#else +#ifndef xmlValidCtxtNormalizeAttributeValue +extern __typeof (xmlValidCtxtNormalizeAttributeValue) xmlValidCtxtNormalizeAttributeValue__internal_alias __attribute((visibility("hidden"))); +#define xmlValidCtxtNormalizeAttributeValue xmlValidCtxtNormalizeAttributeValue__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_VALID_ENABLED) +#ifdef bottom_valid +#undef xmlValidGetPotentialChildren +extern __typeof (xmlValidGetPotentialChildren) xmlValidGetPotentialChildren __attribute((alias("xmlValidGetPotentialChildren__internal_alias"))); +#else +#ifndef xmlValidGetPotentialChildren +extern __typeof (xmlValidGetPotentialChildren) xmlValidGetPotentialChildren__internal_alias __attribute((visibility("hidden"))); +#define xmlValidGetPotentialChildren xmlValidGetPotentialChildren__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_VALID_ENABLED) +#ifdef bottom_valid +#undef xmlValidGetValidElements +extern __typeof (xmlValidGetValidElements) xmlValidGetValidElements __attribute((alias("xmlValidGetValidElements__internal_alias"))); +#else +#ifndef xmlValidGetValidElements +extern __typeof (xmlValidGetValidElements) xmlValidGetValidElements__internal_alias __attribute((visibility("hidden"))); +#define xmlValidGetValidElements xmlValidGetValidElements__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_VALID_ENABLED) +#ifdef bottom_valid +#undef xmlValidNormalizeAttributeValue +extern __typeof (xmlValidNormalizeAttributeValue) xmlValidNormalizeAttributeValue __attribute((alias("xmlValidNormalizeAttributeValue__internal_alias"))); +#else +#ifndef xmlValidNormalizeAttributeValue +extern __typeof (xmlValidNormalizeAttributeValue) xmlValidNormalizeAttributeValue__internal_alias __attribute((visibility("hidden"))); +#define xmlValidNormalizeAttributeValue xmlValidNormalizeAttributeValue__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_VALID_ENABLED) +#ifdef bottom_valid +#undef xmlValidateAttributeDecl +extern __typeof (xmlValidateAttributeDecl) xmlValidateAttributeDecl __attribute((alias("xmlValidateAttributeDecl__internal_alias"))); +#else +#ifndef xmlValidateAttributeDecl +extern __typeof (xmlValidateAttributeDecl) xmlValidateAttributeDecl__internal_alias __attribute((visibility("hidden"))); +#define xmlValidateAttributeDecl xmlValidateAttributeDecl__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_VALID_ENABLED) +#ifdef bottom_valid +#undef xmlValidateAttributeValue +extern __typeof (xmlValidateAttributeValue) xmlValidateAttributeValue __attribute((alias("xmlValidateAttributeValue__internal_alias"))); +#else +#ifndef xmlValidateAttributeValue +extern __typeof (xmlValidateAttributeValue) xmlValidateAttributeValue__internal_alias __attribute((visibility("hidden"))); +#define xmlValidateAttributeValue xmlValidateAttributeValue__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_VALID_ENABLED) +#ifdef bottom_valid +#undef xmlValidateDocument +extern __typeof (xmlValidateDocument) xmlValidateDocument __attribute((alias("xmlValidateDocument__internal_alias"))); +#else +#ifndef xmlValidateDocument +extern __typeof (xmlValidateDocument) xmlValidateDocument__internal_alias __attribute((visibility("hidden"))); +#define xmlValidateDocument xmlValidateDocument__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_VALID_ENABLED) +#ifdef bottom_valid +#undef xmlValidateDocumentFinal +extern __typeof (xmlValidateDocumentFinal) xmlValidateDocumentFinal __attribute((alias("xmlValidateDocumentFinal__internal_alias"))); +#else +#ifndef xmlValidateDocumentFinal +extern __typeof (xmlValidateDocumentFinal) xmlValidateDocumentFinal__internal_alias __attribute((visibility("hidden"))); +#define xmlValidateDocumentFinal xmlValidateDocumentFinal__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_VALID_ENABLED) +#ifdef bottom_valid +#undef xmlValidateDtd +extern __typeof (xmlValidateDtd) xmlValidateDtd __attribute((alias("xmlValidateDtd__internal_alias"))); +#else +#ifndef xmlValidateDtd +extern __typeof (xmlValidateDtd) xmlValidateDtd__internal_alias __attribute((visibility("hidden"))); +#define xmlValidateDtd xmlValidateDtd__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_VALID_ENABLED) +#ifdef bottom_valid +#undef xmlValidateDtdFinal +extern __typeof (xmlValidateDtdFinal) xmlValidateDtdFinal __attribute((alias("xmlValidateDtdFinal__internal_alias"))); +#else +#ifndef xmlValidateDtdFinal +extern __typeof (xmlValidateDtdFinal) xmlValidateDtdFinal__internal_alias __attribute((visibility("hidden"))); +#define xmlValidateDtdFinal xmlValidateDtdFinal__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_VALID_ENABLED) +#ifdef bottom_valid +#undef xmlValidateElement +extern __typeof (xmlValidateElement) xmlValidateElement __attribute((alias("xmlValidateElement__internal_alias"))); +#else +#ifndef xmlValidateElement +extern __typeof (xmlValidateElement) xmlValidateElement__internal_alias __attribute((visibility("hidden"))); +#define xmlValidateElement xmlValidateElement__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_VALID_ENABLED) +#ifdef bottom_valid +#undef xmlValidateElementDecl +extern __typeof (xmlValidateElementDecl) xmlValidateElementDecl __attribute((alias("xmlValidateElementDecl__internal_alias"))); +#else +#ifndef xmlValidateElementDecl +extern __typeof (xmlValidateElementDecl) xmlValidateElementDecl__internal_alias __attribute((visibility("hidden"))); +#define xmlValidateElementDecl xmlValidateElementDecl__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_DEBUG_ENABLED) || defined(LIBXML_SAX1_ENABLED) || defined(LIBXML_WRITER_ENABLED) || defined(LIBXML_DOCB_ENABLED) +#ifdef bottom_tree +#undef xmlValidateNCName +extern __typeof (xmlValidateNCName) xmlValidateNCName __attribute((alias("xmlValidateNCName__internal_alias"))); +#else +#ifndef xmlValidateNCName +extern __typeof (xmlValidateNCName) xmlValidateNCName__internal_alias __attribute((visibility("hidden"))); +#define xmlValidateNCName xmlValidateNCName__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_tree +#undef xmlValidateNMToken +extern __typeof (xmlValidateNMToken) xmlValidateNMToken __attribute((alias("xmlValidateNMToken__internal_alias"))); +#else +#ifndef xmlValidateNMToken +extern __typeof (xmlValidateNMToken) xmlValidateNMToken__internal_alias __attribute((visibility("hidden"))); +#define xmlValidateNMToken xmlValidateNMToken__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_tree +#undef xmlValidateName +extern __typeof (xmlValidateName) xmlValidateName __attribute((alias("xmlValidateName__internal_alias"))); +#else +#ifndef xmlValidateName +extern __typeof (xmlValidateName) xmlValidateName__internal_alias __attribute((visibility("hidden"))); +#define xmlValidateName xmlValidateName__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_VALID_ENABLED) +#ifdef bottom_valid +#undef xmlValidateNameValue +extern __typeof (xmlValidateNameValue) xmlValidateNameValue __attribute((alias("xmlValidateNameValue__internal_alias"))); +#else +#ifndef xmlValidateNameValue +extern __typeof (xmlValidateNameValue) xmlValidateNameValue__internal_alias __attribute((visibility("hidden"))); +#define xmlValidateNameValue xmlValidateNameValue__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_VALID_ENABLED) +#ifdef bottom_valid +#undef xmlValidateNamesValue +extern __typeof (xmlValidateNamesValue) xmlValidateNamesValue __attribute((alias("xmlValidateNamesValue__internal_alias"))); +#else +#ifndef xmlValidateNamesValue +extern __typeof (xmlValidateNamesValue) xmlValidateNamesValue__internal_alias __attribute((visibility("hidden"))); +#define xmlValidateNamesValue xmlValidateNamesValue__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_VALID_ENABLED) +#ifdef bottom_valid +#undef xmlValidateNmtokenValue +extern __typeof (xmlValidateNmtokenValue) xmlValidateNmtokenValue __attribute((alias("xmlValidateNmtokenValue__internal_alias"))); +#else +#ifndef xmlValidateNmtokenValue +extern __typeof (xmlValidateNmtokenValue) xmlValidateNmtokenValue__internal_alias __attribute((visibility("hidden"))); +#define xmlValidateNmtokenValue xmlValidateNmtokenValue__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_VALID_ENABLED) +#ifdef bottom_valid +#undef xmlValidateNmtokensValue +extern __typeof (xmlValidateNmtokensValue) xmlValidateNmtokensValue __attribute((alias("xmlValidateNmtokensValue__internal_alias"))); +#else +#ifndef xmlValidateNmtokensValue +extern __typeof (xmlValidateNmtokensValue) xmlValidateNmtokensValue__internal_alias __attribute((visibility("hidden"))); +#define xmlValidateNmtokensValue xmlValidateNmtokensValue__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_VALID_ENABLED) +#ifdef bottom_valid +#undef xmlValidateNotationDecl +extern __typeof (xmlValidateNotationDecl) xmlValidateNotationDecl __attribute((alias("xmlValidateNotationDecl__internal_alias"))); +#else +#ifndef xmlValidateNotationDecl +extern __typeof (xmlValidateNotationDecl) xmlValidateNotationDecl__internal_alias __attribute((visibility("hidden"))); +#define xmlValidateNotationDecl xmlValidateNotationDecl__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_valid +#undef xmlValidateNotationUse +extern __typeof (xmlValidateNotationUse) xmlValidateNotationUse __attribute((alias("xmlValidateNotationUse__internal_alias"))); +#else +#ifndef xmlValidateNotationUse +extern __typeof (xmlValidateNotationUse) xmlValidateNotationUse__internal_alias __attribute((visibility("hidden"))); +#define xmlValidateNotationUse xmlValidateNotationUse__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_VALID_ENABLED) +#ifdef bottom_valid +#undef xmlValidateOneAttribute +extern __typeof (xmlValidateOneAttribute) xmlValidateOneAttribute __attribute((alias("xmlValidateOneAttribute__internal_alias"))); +#else +#ifndef xmlValidateOneAttribute +extern __typeof (xmlValidateOneAttribute) xmlValidateOneAttribute__internal_alias __attribute((visibility("hidden"))); +#define xmlValidateOneAttribute xmlValidateOneAttribute__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_VALID_ENABLED) +#ifdef bottom_valid +#undef xmlValidateOneElement +extern __typeof (xmlValidateOneElement) xmlValidateOneElement __attribute((alias("xmlValidateOneElement__internal_alias"))); +#else +#ifndef xmlValidateOneElement +extern __typeof (xmlValidateOneElement) xmlValidateOneElement__internal_alias __attribute((visibility("hidden"))); +#define xmlValidateOneElement xmlValidateOneElement__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_VALID_ENABLED) +#ifdef bottom_valid +#undef xmlValidateOneNamespace +extern __typeof (xmlValidateOneNamespace) xmlValidateOneNamespace __attribute((alias("xmlValidateOneNamespace__internal_alias"))); +#else +#ifndef xmlValidateOneNamespace +extern __typeof (xmlValidateOneNamespace) xmlValidateOneNamespace__internal_alias __attribute((visibility("hidden"))); +#define xmlValidateOneNamespace xmlValidateOneNamespace__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_VALID_ENABLED) && defined(LIBXML_REGEXP_ENABLED) +#ifdef bottom_valid +#undef xmlValidatePopElement +extern __typeof (xmlValidatePopElement) xmlValidatePopElement __attribute((alias("xmlValidatePopElement__internal_alias"))); +#else +#ifndef xmlValidatePopElement +extern __typeof (xmlValidatePopElement) xmlValidatePopElement__internal_alias __attribute((visibility("hidden"))); +#define xmlValidatePopElement xmlValidatePopElement__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_VALID_ENABLED) && defined(LIBXML_REGEXP_ENABLED) +#ifdef bottom_valid +#undef xmlValidatePushCData +extern __typeof (xmlValidatePushCData) xmlValidatePushCData __attribute((alias("xmlValidatePushCData__internal_alias"))); +#else +#ifndef xmlValidatePushCData +extern __typeof (xmlValidatePushCData) xmlValidatePushCData__internal_alias __attribute((visibility("hidden"))); +#define xmlValidatePushCData xmlValidatePushCData__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_VALID_ENABLED) && defined(LIBXML_REGEXP_ENABLED) +#ifdef bottom_valid +#undef xmlValidatePushElement +extern __typeof (xmlValidatePushElement) xmlValidatePushElement __attribute((alias("xmlValidatePushElement__internal_alias"))); +#else +#ifndef xmlValidatePushElement +extern __typeof (xmlValidatePushElement) xmlValidatePushElement__internal_alias __attribute((visibility("hidden"))); +#define xmlValidatePushElement xmlValidatePushElement__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_tree +#undef xmlValidateQName +extern __typeof (xmlValidateQName) xmlValidateQName __attribute((alias("xmlValidateQName__internal_alias"))); +#else +#ifndef xmlValidateQName +extern __typeof (xmlValidateQName) xmlValidateQName__internal_alias __attribute((visibility("hidden"))); +#define xmlValidateQName xmlValidateQName__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_VALID_ENABLED) +#ifdef bottom_valid +#undef xmlValidateRoot +extern __typeof (xmlValidateRoot) xmlValidateRoot __attribute((alias("xmlValidateRoot__internal_alias"))); +#else +#ifndef xmlValidateRoot +extern __typeof (xmlValidateRoot) xmlValidateRoot__internal_alias __attribute((visibility("hidden"))); +#define xmlValidateRoot xmlValidateRoot__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XINCLUDE_ENABLED) +#ifdef bottom_xinclude +#undef xmlXIncludeFreeContext +extern __typeof (xmlXIncludeFreeContext) xmlXIncludeFreeContext __attribute((alias("xmlXIncludeFreeContext__internal_alias"))); +#else +#ifndef xmlXIncludeFreeContext +extern __typeof (xmlXIncludeFreeContext) xmlXIncludeFreeContext__internal_alias __attribute((visibility("hidden"))); +#define xmlXIncludeFreeContext xmlXIncludeFreeContext__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XINCLUDE_ENABLED) +#ifdef bottom_xinclude +#undef xmlXIncludeNewContext +extern __typeof (xmlXIncludeNewContext) xmlXIncludeNewContext __attribute((alias("xmlXIncludeNewContext__internal_alias"))); +#else +#ifndef xmlXIncludeNewContext +extern __typeof (xmlXIncludeNewContext) xmlXIncludeNewContext__internal_alias __attribute((visibility("hidden"))); +#define xmlXIncludeNewContext xmlXIncludeNewContext__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XINCLUDE_ENABLED) +#ifdef bottom_xinclude +#undef xmlXIncludeProcess +extern __typeof (xmlXIncludeProcess) xmlXIncludeProcess __attribute((alias("xmlXIncludeProcess__internal_alias"))); +#else +#ifndef xmlXIncludeProcess +extern __typeof (xmlXIncludeProcess) xmlXIncludeProcess__internal_alias __attribute((visibility("hidden"))); +#define xmlXIncludeProcess xmlXIncludeProcess__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XINCLUDE_ENABLED) +#ifdef bottom_xinclude +#undef xmlXIncludeProcessFlags +extern __typeof (xmlXIncludeProcessFlags) xmlXIncludeProcessFlags __attribute((alias("xmlXIncludeProcessFlags__internal_alias"))); +#else +#ifndef xmlXIncludeProcessFlags +extern __typeof (xmlXIncludeProcessFlags) xmlXIncludeProcessFlags__internal_alias __attribute((visibility("hidden"))); +#define xmlXIncludeProcessFlags xmlXIncludeProcessFlags__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XINCLUDE_ENABLED) +#ifdef bottom_xinclude +#undef xmlXIncludeProcessFlagsData +extern __typeof (xmlXIncludeProcessFlagsData) xmlXIncludeProcessFlagsData __attribute((alias("xmlXIncludeProcessFlagsData__internal_alias"))); +#else +#ifndef xmlXIncludeProcessFlagsData +extern __typeof (xmlXIncludeProcessFlagsData) xmlXIncludeProcessFlagsData__internal_alias __attribute((visibility("hidden"))); +#define xmlXIncludeProcessFlagsData xmlXIncludeProcessFlagsData__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XINCLUDE_ENABLED) +#ifdef bottom_xinclude +#undef xmlXIncludeProcessNode +extern __typeof (xmlXIncludeProcessNode) xmlXIncludeProcessNode __attribute((alias("xmlXIncludeProcessNode__internal_alias"))); +#else +#ifndef xmlXIncludeProcessNode +extern __typeof (xmlXIncludeProcessNode) xmlXIncludeProcessNode__internal_alias __attribute((visibility("hidden"))); +#define xmlXIncludeProcessNode xmlXIncludeProcessNode__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XINCLUDE_ENABLED) +#ifdef bottom_xinclude +#undef xmlXIncludeProcessTree +extern __typeof (xmlXIncludeProcessTree) xmlXIncludeProcessTree __attribute((alias("xmlXIncludeProcessTree__internal_alias"))); +#else +#ifndef xmlXIncludeProcessTree +extern __typeof (xmlXIncludeProcessTree) xmlXIncludeProcessTree__internal_alias __attribute((visibility("hidden"))); +#define xmlXIncludeProcessTree xmlXIncludeProcessTree__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XINCLUDE_ENABLED) +#ifdef bottom_xinclude +#undef xmlXIncludeProcessTreeFlags +extern __typeof (xmlXIncludeProcessTreeFlags) xmlXIncludeProcessTreeFlags __attribute((alias("xmlXIncludeProcessTreeFlags__internal_alias"))); +#else +#ifndef xmlXIncludeProcessTreeFlags +extern __typeof (xmlXIncludeProcessTreeFlags) xmlXIncludeProcessTreeFlags__internal_alias __attribute((visibility("hidden"))); +#define xmlXIncludeProcessTreeFlags xmlXIncludeProcessTreeFlags__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XINCLUDE_ENABLED) +#ifdef bottom_xinclude +#undef xmlXIncludeProcessTreeFlagsData +extern __typeof (xmlXIncludeProcessTreeFlagsData) xmlXIncludeProcessTreeFlagsData __attribute((alias("xmlXIncludeProcessTreeFlagsData__internal_alias"))); +#else +#ifndef xmlXIncludeProcessTreeFlagsData +extern __typeof (xmlXIncludeProcessTreeFlagsData) xmlXIncludeProcessTreeFlagsData__internal_alias __attribute((visibility("hidden"))); +#define xmlXIncludeProcessTreeFlagsData xmlXIncludeProcessTreeFlagsData__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XINCLUDE_ENABLED) +#ifdef bottom_xinclude +#undef xmlXIncludeSetFlags +extern __typeof (xmlXIncludeSetFlags) xmlXIncludeSetFlags __attribute((alias("xmlXIncludeSetFlags__internal_alias"))); +#else +#ifndef xmlXIncludeSetFlags +extern __typeof (xmlXIncludeSetFlags) xmlXIncludeSetFlags__internal_alias __attribute((visibility("hidden"))); +#define xmlXIncludeSetFlags xmlXIncludeSetFlags__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathAddValues +extern __typeof (xmlXPathAddValues) xmlXPathAddValues __attribute((alias("xmlXPathAddValues__internal_alias"))); +#else +#ifndef xmlXPathAddValues +extern __typeof (xmlXPathAddValues) xmlXPathAddValues__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathAddValues xmlXPathAddValues__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathBooleanFunction +extern __typeof (xmlXPathBooleanFunction) xmlXPathBooleanFunction __attribute((alias("xmlXPathBooleanFunction__internal_alias"))); +#else +#ifndef xmlXPathBooleanFunction +extern __typeof (xmlXPathBooleanFunction) xmlXPathBooleanFunction__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathBooleanFunction xmlXPathBooleanFunction__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathCastBooleanToNumber +extern __typeof (xmlXPathCastBooleanToNumber) xmlXPathCastBooleanToNumber __attribute((alias("xmlXPathCastBooleanToNumber__internal_alias"))); +#else +#ifndef xmlXPathCastBooleanToNumber +extern __typeof (xmlXPathCastBooleanToNumber) xmlXPathCastBooleanToNumber__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathCastBooleanToNumber xmlXPathCastBooleanToNumber__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathCastBooleanToString +extern __typeof (xmlXPathCastBooleanToString) xmlXPathCastBooleanToString __attribute((alias("xmlXPathCastBooleanToString__internal_alias"))); +#else +#ifndef xmlXPathCastBooleanToString +extern __typeof (xmlXPathCastBooleanToString) xmlXPathCastBooleanToString__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathCastBooleanToString xmlXPathCastBooleanToString__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathCastNodeSetToBoolean +extern __typeof (xmlXPathCastNodeSetToBoolean) xmlXPathCastNodeSetToBoolean __attribute((alias("xmlXPathCastNodeSetToBoolean__internal_alias"))); +#else +#ifndef xmlXPathCastNodeSetToBoolean +extern __typeof (xmlXPathCastNodeSetToBoolean) xmlXPathCastNodeSetToBoolean__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathCastNodeSetToBoolean xmlXPathCastNodeSetToBoolean__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathCastNodeSetToNumber +extern __typeof (xmlXPathCastNodeSetToNumber) xmlXPathCastNodeSetToNumber __attribute((alias("xmlXPathCastNodeSetToNumber__internal_alias"))); +#else +#ifndef xmlXPathCastNodeSetToNumber +extern __typeof (xmlXPathCastNodeSetToNumber) xmlXPathCastNodeSetToNumber__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathCastNodeSetToNumber xmlXPathCastNodeSetToNumber__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathCastNodeSetToString +extern __typeof (xmlXPathCastNodeSetToString) xmlXPathCastNodeSetToString __attribute((alias("xmlXPathCastNodeSetToString__internal_alias"))); +#else +#ifndef xmlXPathCastNodeSetToString +extern __typeof (xmlXPathCastNodeSetToString) xmlXPathCastNodeSetToString__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathCastNodeSetToString xmlXPathCastNodeSetToString__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathCastNodeToNumber +extern __typeof (xmlXPathCastNodeToNumber) xmlXPathCastNodeToNumber __attribute((alias("xmlXPathCastNodeToNumber__internal_alias"))); +#else +#ifndef xmlXPathCastNodeToNumber +extern __typeof (xmlXPathCastNodeToNumber) xmlXPathCastNodeToNumber__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathCastNodeToNumber xmlXPathCastNodeToNumber__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathCastNodeToString +extern __typeof (xmlXPathCastNodeToString) xmlXPathCastNodeToString __attribute((alias("xmlXPathCastNodeToString__internal_alias"))); +#else +#ifndef xmlXPathCastNodeToString +extern __typeof (xmlXPathCastNodeToString) xmlXPathCastNodeToString__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathCastNodeToString xmlXPathCastNodeToString__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathCastNumberToBoolean +extern __typeof (xmlXPathCastNumberToBoolean) xmlXPathCastNumberToBoolean __attribute((alias("xmlXPathCastNumberToBoolean__internal_alias"))); +#else +#ifndef xmlXPathCastNumberToBoolean +extern __typeof (xmlXPathCastNumberToBoolean) xmlXPathCastNumberToBoolean__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathCastNumberToBoolean xmlXPathCastNumberToBoolean__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathCastNumberToString +extern __typeof (xmlXPathCastNumberToString) xmlXPathCastNumberToString __attribute((alias("xmlXPathCastNumberToString__internal_alias"))); +#else +#ifndef xmlXPathCastNumberToString +extern __typeof (xmlXPathCastNumberToString) xmlXPathCastNumberToString__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathCastNumberToString xmlXPathCastNumberToString__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathCastStringToBoolean +extern __typeof (xmlXPathCastStringToBoolean) xmlXPathCastStringToBoolean __attribute((alias("xmlXPathCastStringToBoolean__internal_alias"))); +#else +#ifndef xmlXPathCastStringToBoolean +extern __typeof (xmlXPathCastStringToBoolean) xmlXPathCastStringToBoolean__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathCastStringToBoolean xmlXPathCastStringToBoolean__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathCastStringToNumber +extern __typeof (xmlXPathCastStringToNumber) xmlXPathCastStringToNumber __attribute((alias("xmlXPathCastStringToNumber__internal_alias"))); +#else +#ifndef xmlXPathCastStringToNumber +extern __typeof (xmlXPathCastStringToNumber) xmlXPathCastStringToNumber__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathCastStringToNumber xmlXPathCastStringToNumber__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathCastToBoolean +extern __typeof (xmlXPathCastToBoolean) xmlXPathCastToBoolean __attribute((alias("xmlXPathCastToBoolean__internal_alias"))); +#else +#ifndef xmlXPathCastToBoolean +extern __typeof (xmlXPathCastToBoolean) xmlXPathCastToBoolean__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathCastToBoolean xmlXPathCastToBoolean__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathCastToNumber +extern __typeof (xmlXPathCastToNumber) xmlXPathCastToNumber __attribute((alias("xmlXPathCastToNumber__internal_alias"))); +#else +#ifndef xmlXPathCastToNumber +extern __typeof (xmlXPathCastToNumber) xmlXPathCastToNumber__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathCastToNumber xmlXPathCastToNumber__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathCastToString +extern __typeof (xmlXPathCastToString) xmlXPathCastToString __attribute((alias("xmlXPathCastToString__internal_alias"))); +#else +#ifndef xmlXPathCastToString +extern __typeof (xmlXPathCastToString) xmlXPathCastToString__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathCastToString xmlXPathCastToString__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathCeilingFunction +extern __typeof (xmlXPathCeilingFunction) xmlXPathCeilingFunction __attribute((alias("xmlXPathCeilingFunction__internal_alias"))); +#else +#ifndef xmlXPathCeilingFunction +extern __typeof (xmlXPathCeilingFunction) xmlXPathCeilingFunction__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathCeilingFunction xmlXPathCeilingFunction__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathCmpNodes +extern __typeof (xmlXPathCmpNodes) xmlXPathCmpNodes __attribute((alias("xmlXPathCmpNodes__internal_alias"))); +#else +#ifndef xmlXPathCmpNodes +extern __typeof (xmlXPathCmpNodes) xmlXPathCmpNodes__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathCmpNodes xmlXPathCmpNodes__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathCompareValues +extern __typeof (xmlXPathCompareValues) xmlXPathCompareValues __attribute((alias("xmlXPathCompareValues__internal_alias"))); +#else +#ifndef xmlXPathCompareValues +extern __typeof (xmlXPathCompareValues) xmlXPathCompareValues__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathCompareValues xmlXPathCompareValues__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathCompile +extern __typeof (xmlXPathCompile) xmlXPathCompile __attribute((alias("xmlXPathCompile__internal_alias"))); +#else +#ifndef xmlXPathCompile +extern __typeof (xmlXPathCompile) xmlXPathCompile__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathCompile xmlXPathCompile__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathCompiledEval +extern __typeof (xmlXPathCompiledEval) xmlXPathCompiledEval __attribute((alias("xmlXPathCompiledEval__internal_alias"))); +#else +#ifndef xmlXPathCompiledEval +extern __typeof (xmlXPathCompiledEval) xmlXPathCompiledEval__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathCompiledEval xmlXPathCompiledEval__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathCompiledEvalToBoolean +extern __typeof (xmlXPathCompiledEvalToBoolean) xmlXPathCompiledEvalToBoolean __attribute((alias("xmlXPathCompiledEvalToBoolean__internal_alias"))); +#else +#ifndef xmlXPathCompiledEvalToBoolean +extern __typeof (xmlXPathCompiledEvalToBoolean) xmlXPathCompiledEvalToBoolean__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathCompiledEvalToBoolean xmlXPathCompiledEvalToBoolean__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathConcatFunction +extern __typeof (xmlXPathConcatFunction) xmlXPathConcatFunction __attribute((alias("xmlXPathConcatFunction__internal_alias"))); +#else +#ifndef xmlXPathConcatFunction +extern __typeof (xmlXPathConcatFunction) xmlXPathConcatFunction__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathConcatFunction xmlXPathConcatFunction__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathContainsFunction +extern __typeof (xmlXPathContainsFunction) xmlXPathContainsFunction __attribute((alias("xmlXPathContainsFunction__internal_alias"))); +#else +#ifndef xmlXPathContainsFunction +extern __typeof (xmlXPathContainsFunction) xmlXPathContainsFunction__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathContainsFunction xmlXPathContainsFunction__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathContextSetCache +extern __typeof (xmlXPathContextSetCache) xmlXPathContextSetCache __attribute((alias("xmlXPathContextSetCache__internal_alias"))); +#else +#ifndef xmlXPathContextSetCache +extern __typeof (xmlXPathContextSetCache) xmlXPathContextSetCache__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathContextSetCache xmlXPathContextSetCache__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathConvertBoolean +extern __typeof (xmlXPathConvertBoolean) xmlXPathConvertBoolean __attribute((alias("xmlXPathConvertBoolean__internal_alias"))); +#else +#ifndef xmlXPathConvertBoolean +extern __typeof (xmlXPathConvertBoolean) xmlXPathConvertBoolean__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathConvertBoolean xmlXPathConvertBoolean__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathConvertNumber +extern __typeof (xmlXPathConvertNumber) xmlXPathConvertNumber __attribute((alias("xmlXPathConvertNumber__internal_alias"))); +#else +#ifndef xmlXPathConvertNumber +extern __typeof (xmlXPathConvertNumber) xmlXPathConvertNumber__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathConvertNumber xmlXPathConvertNumber__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathConvertString +extern __typeof (xmlXPathConvertString) xmlXPathConvertString __attribute((alias("xmlXPathConvertString__internal_alias"))); +#else +#ifndef xmlXPathConvertString +extern __typeof (xmlXPathConvertString) xmlXPathConvertString__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathConvertString xmlXPathConvertString__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathCountFunction +extern __typeof (xmlXPathCountFunction) xmlXPathCountFunction __attribute((alias("xmlXPathCountFunction__internal_alias"))); +#else +#ifndef xmlXPathCountFunction +extern __typeof (xmlXPathCountFunction) xmlXPathCountFunction__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathCountFunction xmlXPathCountFunction__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathCtxtCompile +extern __typeof (xmlXPathCtxtCompile) xmlXPathCtxtCompile __attribute((alias("xmlXPathCtxtCompile__internal_alias"))); +#else +#ifndef xmlXPathCtxtCompile +extern __typeof (xmlXPathCtxtCompile) xmlXPathCtxtCompile__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathCtxtCompile xmlXPathCtxtCompile__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) && defined(LIBXML_DEBUG_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathDebugDumpCompExpr +extern __typeof (xmlXPathDebugDumpCompExpr) xmlXPathDebugDumpCompExpr __attribute((alias("xmlXPathDebugDumpCompExpr__internal_alias"))); +#else +#ifndef xmlXPathDebugDumpCompExpr +extern __typeof (xmlXPathDebugDumpCompExpr) xmlXPathDebugDumpCompExpr__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathDebugDumpCompExpr xmlXPathDebugDumpCompExpr__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) && defined(LIBXML_DEBUG_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathDebugDumpObject +extern __typeof (xmlXPathDebugDumpObject) xmlXPathDebugDumpObject __attribute((alias("xmlXPathDebugDumpObject__internal_alias"))); +#else +#ifndef xmlXPathDebugDumpObject +extern __typeof (xmlXPathDebugDumpObject) xmlXPathDebugDumpObject__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathDebugDumpObject xmlXPathDebugDumpObject__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathDifference +extern __typeof (xmlXPathDifference) xmlXPathDifference __attribute((alias("xmlXPathDifference__internal_alias"))); +#else +#ifndef xmlXPathDifference +extern __typeof (xmlXPathDifference) xmlXPathDifference__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathDifference xmlXPathDifference__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathDistinct +extern __typeof (xmlXPathDistinct) xmlXPathDistinct __attribute((alias("xmlXPathDistinct__internal_alias"))); +#else +#ifndef xmlXPathDistinct +extern __typeof (xmlXPathDistinct) xmlXPathDistinct__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathDistinct xmlXPathDistinct__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathDistinctSorted +extern __typeof (xmlXPathDistinctSorted) xmlXPathDistinctSorted __attribute((alias("xmlXPathDistinctSorted__internal_alias"))); +#else +#ifndef xmlXPathDistinctSorted +extern __typeof (xmlXPathDistinctSorted) xmlXPathDistinctSorted__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathDistinctSorted xmlXPathDistinctSorted__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathDivValues +extern __typeof (xmlXPathDivValues) xmlXPathDivValues __attribute((alias("xmlXPathDivValues__internal_alias"))); +#else +#ifndef xmlXPathDivValues +extern __typeof (xmlXPathDivValues) xmlXPathDivValues__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathDivValues xmlXPathDivValues__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathEqualValues +extern __typeof (xmlXPathEqualValues) xmlXPathEqualValues __attribute((alias("xmlXPathEqualValues__internal_alias"))); +#else +#ifndef xmlXPathEqualValues +extern __typeof (xmlXPathEqualValues) xmlXPathEqualValues__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathEqualValues xmlXPathEqualValues__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathErr +extern __typeof (xmlXPathErr) xmlXPathErr __attribute((alias("xmlXPathErr__internal_alias"))); +#else +#ifndef xmlXPathErr +extern __typeof (xmlXPathErr) xmlXPathErr__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathErr xmlXPathErr__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathEval +extern __typeof (xmlXPathEval) xmlXPathEval __attribute((alias("xmlXPathEval__internal_alias"))); +#else +#ifndef xmlXPathEval +extern __typeof (xmlXPathEval) xmlXPathEval__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathEval xmlXPathEval__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathEvalExpr +extern __typeof (xmlXPathEvalExpr) xmlXPathEvalExpr __attribute((alias("xmlXPathEvalExpr__internal_alias"))); +#else +#ifndef xmlXPathEvalExpr +extern __typeof (xmlXPathEvalExpr) xmlXPathEvalExpr__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathEvalExpr xmlXPathEvalExpr__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathEvalExpression +extern __typeof (xmlXPathEvalExpression) xmlXPathEvalExpression __attribute((alias("xmlXPathEvalExpression__internal_alias"))); +#else +#ifndef xmlXPathEvalExpression +extern __typeof (xmlXPathEvalExpression) xmlXPathEvalExpression__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathEvalExpression xmlXPathEvalExpression__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathEvalPredicate +extern __typeof (xmlXPathEvalPredicate) xmlXPathEvalPredicate __attribute((alias("xmlXPathEvalPredicate__internal_alias"))); +#else +#ifndef xmlXPathEvalPredicate +extern __typeof (xmlXPathEvalPredicate) xmlXPathEvalPredicate__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathEvalPredicate xmlXPathEvalPredicate__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathEvaluatePredicateResult +extern __typeof (xmlXPathEvaluatePredicateResult) xmlXPathEvaluatePredicateResult __attribute((alias("xmlXPathEvaluatePredicateResult__internal_alias"))); +#else +#ifndef xmlXPathEvaluatePredicateResult +extern __typeof (xmlXPathEvaluatePredicateResult) xmlXPathEvaluatePredicateResult__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathEvaluatePredicateResult xmlXPathEvaluatePredicateResult__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathFalseFunction +extern __typeof (xmlXPathFalseFunction) xmlXPathFalseFunction __attribute((alias("xmlXPathFalseFunction__internal_alias"))); +#else +#ifndef xmlXPathFalseFunction +extern __typeof (xmlXPathFalseFunction) xmlXPathFalseFunction__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathFalseFunction xmlXPathFalseFunction__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathFloorFunction +extern __typeof (xmlXPathFloorFunction) xmlXPathFloorFunction __attribute((alias("xmlXPathFloorFunction__internal_alias"))); +#else +#ifndef xmlXPathFloorFunction +extern __typeof (xmlXPathFloorFunction) xmlXPathFloorFunction__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathFloorFunction xmlXPathFloorFunction__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathFreeCompExpr +extern __typeof (xmlXPathFreeCompExpr) xmlXPathFreeCompExpr __attribute((alias("xmlXPathFreeCompExpr__internal_alias"))); +#else +#ifndef xmlXPathFreeCompExpr +extern __typeof (xmlXPathFreeCompExpr) xmlXPathFreeCompExpr__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathFreeCompExpr xmlXPathFreeCompExpr__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathFreeContext +extern __typeof (xmlXPathFreeContext) xmlXPathFreeContext __attribute((alias("xmlXPathFreeContext__internal_alias"))); +#else +#ifndef xmlXPathFreeContext +extern __typeof (xmlXPathFreeContext) xmlXPathFreeContext__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathFreeContext xmlXPathFreeContext__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathFreeNodeSet +extern __typeof (xmlXPathFreeNodeSet) xmlXPathFreeNodeSet __attribute((alias("xmlXPathFreeNodeSet__internal_alias"))); +#else +#ifndef xmlXPathFreeNodeSet +extern __typeof (xmlXPathFreeNodeSet) xmlXPathFreeNodeSet__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathFreeNodeSet xmlXPathFreeNodeSet__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathFreeNodeSetList +extern __typeof (xmlXPathFreeNodeSetList) xmlXPathFreeNodeSetList __attribute((alias("xmlXPathFreeNodeSetList__internal_alias"))); +#else +#ifndef xmlXPathFreeNodeSetList +extern __typeof (xmlXPathFreeNodeSetList) xmlXPathFreeNodeSetList__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathFreeNodeSetList xmlXPathFreeNodeSetList__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathFreeObject +extern __typeof (xmlXPathFreeObject) xmlXPathFreeObject __attribute((alias("xmlXPathFreeObject__internal_alias"))); +#else +#ifndef xmlXPathFreeObject +extern __typeof (xmlXPathFreeObject) xmlXPathFreeObject__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathFreeObject xmlXPathFreeObject__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathFreeParserContext +extern __typeof (xmlXPathFreeParserContext) xmlXPathFreeParserContext __attribute((alias("xmlXPathFreeParserContext__internal_alias"))); +#else +#ifndef xmlXPathFreeParserContext +extern __typeof (xmlXPathFreeParserContext) xmlXPathFreeParserContext__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathFreeParserContext xmlXPathFreeParserContext__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathFunctionLookup +extern __typeof (xmlXPathFunctionLookup) xmlXPathFunctionLookup __attribute((alias("xmlXPathFunctionLookup__internal_alias"))); +#else +#ifndef xmlXPathFunctionLookup +extern __typeof (xmlXPathFunctionLookup) xmlXPathFunctionLookup__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathFunctionLookup xmlXPathFunctionLookup__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathFunctionLookupNS +extern __typeof (xmlXPathFunctionLookupNS) xmlXPathFunctionLookupNS __attribute((alias("xmlXPathFunctionLookupNS__internal_alias"))); +#else +#ifndef xmlXPathFunctionLookupNS +extern __typeof (xmlXPathFunctionLookupNS) xmlXPathFunctionLookupNS__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathFunctionLookupNS xmlXPathFunctionLookupNS__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathHasSameNodes +extern __typeof (xmlXPathHasSameNodes) xmlXPathHasSameNodes __attribute((alias("xmlXPathHasSameNodes__internal_alias"))); +#else +#ifndef xmlXPathHasSameNodes +extern __typeof (xmlXPathHasSameNodes) xmlXPathHasSameNodes__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathHasSameNodes xmlXPathHasSameNodes__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathIdFunction +extern __typeof (xmlXPathIdFunction) xmlXPathIdFunction __attribute((alias("xmlXPathIdFunction__internal_alias"))); +#else +#ifndef xmlXPathIdFunction +extern __typeof (xmlXPathIdFunction) xmlXPathIdFunction__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathIdFunction xmlXPathIdFunction__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathInit +extern __typeof (xmlXPathInit) xmlXPathInit __attribute((alias("xmlXPathInit__internal_alias"))); +#else +#ifndef xmlXPathInit +extern __typeof (xmlXPathInit) xmlXPathInit__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathInit xmlXPathInit__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathIntersection +extern __typeof (xmlXPathIntersection) xmlXPathIntersection __attribute((alias("xmlXPathIntersection__internal_alias"))); +#else +#ifndef xmlXPathIntersection +extern __typeof (xmlXPathIntersection) xmlXPathIntersection__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathIntersection xmlXPathIntersection__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathIsInf +extern __typeof (xmlXPathIsInf) xmlXPathIsInf __attribute((alias("xmlXPathIsInf__internal_alias"))); +#else +#ifndef xmlXPathIsInf +extern __typeof (xmlXPathIsInf) xmlXPathIsInf__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathIsInf xmlXPathIsInf__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathIsNaN +extern __typeof (xmlXPathIsNaN) xmlXPathIsNaN __attribute((alias("xmlXPathIsNaN__internal_alias"))); +#else +#ifndef xmlXPathIsNaN +extern __typeof (xmlXPathIsNaN) xmlXPathIsNaN__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathIsNaN xmlXPathIsNaN__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathIsNodeType +extern __typeof (xmlXPathIsNodeType) xmlXPathIsNodeType __attribute((alias("xmlXPathIsNodeType__internal_alias"))); +#else +#ifndef xmlXPathIsNodeType +extern __typeof (xmlXPathIsNodeType) xmlXPathIsNodeType__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathIsNodeType xmlXPathIsNodeType__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathLangFunction +extern __typeof (xmlXPathLangFunction) xmlXPathLangFunction __attribute((alias("xmlXPathLangFunction__internal_alias"))); +#else +#ifndef xmlXPathLangFunction +extern __typeof (xmlXPathLangFunction) xmlXPathLangFunction__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathLangFunction xmlXPathLangFunction__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathLastFunction +extern __typeof (xmlXPathLastFunction) xmlXPathLastFunction __attribute((alias("xmlXPathLastFunction__internal_alias"))); +#else +#ifndef xmlXPathLastFunction +extern __typeof (xmlXPathLastFunction) xmlXPathLastFunction__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathLastFunction xmlXPathLastFunction__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathLeading +extern __typeof (xmlXPathLeading) xmlXPathLeading __attribute((alias("xmlXPathLeading__internal_alias"))); +#else +#ifndef xmlXPathLeading +extern __typeof (xmlXPathLeading) xmlXPathLeading__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathLeading xmlXPathLeading__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathLeadingSorted +extern __typeof (xmlXPathLeadingSorted) xmlXPathLeadingSorted __attribute((alias("xmlXPathLeadingSorted__internal_alias"))); +#else +#ifndef xmlXPathLeadingSorted +extern __typeof (xmlXPathLeadingSorted) xmlXPathLeadingSorted__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathLeadingSorted xmlXPathLeadingSorted__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathLocalNameFunction +extern __typeof (xmlXPathLocalNameFunction) xmlXPathLocalNameFunction __attribute((alias("xmlXPathLocalNameFunction__internal_alias"))); +#else +#ifndef xmlXPathLocalNameFunction +extern __typeof (xmlXPathLocalNameFunction) xmlXPathLocalNameFunction__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathLocalNameFunction xmlXPathLocalNameFunction__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathModValues +extern __typeof (xmlXPathModValues) xmlXPathModValues __attribute((alias("xmlXPathModValues__internal_alias"))); +#else +#ifndef xmlXPathModValues +extern __typeof (xmlXPathModValues) xmlXPathModValues__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathModValues xmlXPathModValues__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathMultValues +extern __typeof (xmlXPathMultValues) xmlXPathMultValues __attribute((alias("xmlXPathMultValues__internal_alias"))); +#else +#ifndef xmlXPathMultValues +extern __typeof (xmlXPathMultValues) xmlXPathMultValues__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathMultValues xmlXPathMultValues__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathNamespaceURIFunction +extern __typeof (xmlXPathNamespaceURIFunction) xmlXPathNamespaceURIFunction __attribute((alias("xmlXPathNamespaceURIFunction__internal_alias"))); +#else +#ifndef xmlXPathNamespaceURIFunction +extern __typeof (xmlXPathNamespaceURIFunction) xmlXPathNamespaceURIFunction__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathNamespaceURIFunction xmlXPathNamespaceURIFunction__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathNewBoolean +extern __typeof (xmlXPathNewBoolean) xmlXPathNewBoolean __attribute((alias("xmlXPathNewBoolean__internal_alias"))); +#else +#ifndef xmlXPathNewBoolean +extern __typeof (xmlXPathNewBoolean) xmlXPathNewBoolean__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathNewBoolean xmlXPathNewBoolean__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathNewCString +extern __typeof (xmlXPathNewCString) xmlXPathNewCString __attribute((alias("xmlXPathNewCString__internal_alias"))); +#else +#ifndef xmlXPathNewCString +extern __typeof (xmlXPathNewCString) xmlXPathNewCString__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathNewCString xmlXPathNewCString__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathNewContext +extern __typeof (xmlXPathNewContext) xmlXPathNewContext __attribute((alias("xmlXPathNewContext__internal_alias"))); +#else +#ifndef xmlXPathNewContext +extern __typeof (xmlXPathNewContext) xmlXPathNewContext__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathNewContext xmlXPathNewContext__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathNewFloat +extern __typeof (xmlXPathNewFloat) xmlXPathNewFloat __attribute((alias("xmlXPathNewFloat__internal_alias"))); +#else +#ifndef xmlXPathNewFloat +extern __typeof (xmlXPathNewFloat) xmlXPathNewFloat__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathNewFloat xmlXPathNewFloat__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathNewNodeSet +extern __typeof (xmlXPathNewNodeSet) xmlXPathNewNodeSet __attribute((alias("xmlXPathNewNodeSet__internal_alias"))); +#else +#ifndef xmlXPathNewNodeSet +extern __typeof (xmlXPathNewNodeSet) xmlXPathNewNodeSet__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathNewNodeSet xmlXPathNewNodeSet__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathNewNodeSetList +extern __typeof (xmlXPathNewNodeSetList) xmlXPathNewNodeSetList __attribute((alias("xmlXPathNewNodeSetList__internal_alias"))); +#else +#ifndef xmlXPathNewNodeSetList +extern __typeof (xmlXPathNewNodeSetList) xmlXPathNewNodeSetList__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathNewNodeSetList xmlXPathNewNodeSetList__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathNewParserContext +extern __typeof (xmlXPathNewParserContext) xmlXPathNewParserContext __attribute((alias("xmlXPathNewParserContext__internal_alias"))); +#else +#ifndef xmlXPathNewParserContext +extern __typeof (xmlXPathNewParserContext) xmlXPathNewParserContext__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathNewParserContext xmlXPathNewParserContext__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathNewString +extern __typeof (xmlXPathNewString) xmlXPathNewString __attribute((alias("xmlXPathNewString__internal_alias"))); +#else +#ifndef xmlXPathNewString +extern __typeof (xmlXPathNewString) xmlXPathNewString__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathNewString xmlXPathNewString__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathNewValueTree +extern __typeof (xmlXPathNewValueTree) xmlXPathNewValueTree __attribute((alias("xmlXPathNewValueTree__internal_alias"))); +#else +#ifndef xmlXPathNewValueTree +extern __typeof (xmlXPathNewValueTree) xmlXPathNewValueTree__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathNewValueTree xmlXPathNewValueTree__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathNextAncestor +extern __typeof (xmlXPathNextAncestor) xmlXPathNextAncestor __attribute((alias("xmlXPathNextAncestor__internal_alias"))); +#else +#ifndef xmlXPathNextAncestor +extern __typeof (xmlXPathNextAncestor) xmlXPathNextAncestor__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathNextAncestor xmlXPathNextAncestor__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathNextAncestorOrSelf +extern __typeof (xmlXPathNextAncestorOrSelf) xmlXPathNextAncestorOrSelf __attribute((alias("xmlXPathNextAncestorOrSelf__internal_alias"))); +#else +#ifndef xmlXPathNextAncestorOrSelf +extern __typeof (xmlXPathNextAncestorOrSelf) xmlXPathNextAncestorOrSelf__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathNextAncestorOrSelf xmlXPathNextAncestorOrSelf__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathNextAttribute +extern __typeof (xmlXPathNextAttribute) xmlXPathNextAttribute __attribute((alias("xmlXPathNextAttribute__internal_alias"))); +#else +#ifndef xmlXPathNextAttribute +extern __typeof (xmlXPathNextAttribute) xmlXPathNextAttribute__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathNextAttribute xmlXPathNextAttribute__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathNextChild +extern __typeof (xmlXPathNextChild) xmlXPathNextChild __attribute((alias("xmlXPathNextChild__internal_alias"))); +#else +#ifndef xmlXPathNextChild +extern __typeof (xmlXPathNextChild) xmlXPathNextChild__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathNextChild xmlXPathNextChild__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathNextDescendant +extern __typeof (xmlXPathNextDescendant) xmlXPathNextDescendant __attribute((alias("xmlXPathNextDescendant__internal_alias"))); +#else +#ifndef xmlXPathNextDescendant +extern __typeof (xmlXPathNextDescendant) xmlXPathNextDescendant__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathNextDescendant xmlXPathNextDescendant__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathNextDescendantOrSelf +extern __typeof (xmlXPathNextDescendantOrSelf) xmlXPathNextDescendantOrSelf __attribute((alias("xmlXPathNextDescendantOrSelf__internal_alias"))); +#else +#ifndef xmlXPathNextDescendantOrSelf +extern __typeof (xmlXPathNextDescendantOrSelf) xmlXPathNextDescendantOrSelf__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathNextDescendantOrSelf xmlXPathNextDescendantOrSelf__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathNextFollowing +extern __typeof (xmlXPathNextFollowing) xmlXPathNextFollowing __attribute((alias("xmlXPathNextFollowing__internal_alias"))); +#else +#ifndef xmlXPathNextFollowing +extern __typeof (xmlXPathNextFollowing) xmlXPathNextFollowing__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathNextFollowing xmlXPathNextFollowing__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathNextFollowingSibling +extern __typeof (xmlXPathNextFollowingSibling) xmlXPathNextFollowingSibling __attribute((alias("xmlXPathNextFollowingSibling__internal_alias"))); +#else +#ifndef xmlXPathNextFollowingSibling +extern __typeof (xmlXPathNextFollowingSibling) xmlXPathNextFollowingSibling__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathNextFollowingSibling xmlXPathNextFollowingSibling__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathNextNamespace +extern __typeof (xmlXPathNextNamespace) xmlXPathNextNamespace __attribute((alias("xmlXPathNextNamespace__internal_alias"))); +#else +#ifndef xmlXPathNextNamespace +extern __typeof (xmlXPathNextNamespace) xmlXPathNextNamespace__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathNextNamespace xmlXPathNextNamespace__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathNextParent +extern __typeof (xmlXPathNextParent) xmlXPathNextParent __attribute((alias("xmlXPathNextParent__internal_alias"))); +#else +#ifndef xmlXPathNextParent +extern __typeof (xmlXPathNextParent) xmlXPathNextParent__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathNextParent xmlXPathNextParent__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathNextPreceding +extern __typeof (xmlXPathNextPreceding) xmlXPathNextPreceding __attribute((alias("xmlXPathNextPreceding__internal_alias"))); +#else +#ifndef xmlXPathNextPreceding +extern __typeof (xmlXPathNextPreceding) xmlXPathNextPreceding__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathNextPreceding xmlXPathNextPreceding__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathNextPrecedingSibling +extern __typeof (xmlXPathNextPrecedingSibling) xmlXPathNextPrecedingSibling __attribute((alias("xmlXPathNextPrecedingSibling__internal_alias"))); +#else +#ifndef xmlXPathNextPrecedingSibling +extern __typeof (xmlXPathNextPrecedingSibling) xmlXPathNextPrecedingSibling__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathNextPrecedingSibling xmlXPathNextPrecedingSibling__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathNextSelf +extern __typeof (xmlXPathNextSelf) xmlXPathNextSelf __attribute((alias("xmlXPathNextSelf__internal_alias"))); +#else +#ifndef xmlXPathNextSelf +extern __typeof (xmlXPathNextSelf) xmlXPathNextSelf__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathNextSelf xmlXPathNextSelf__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathNodeLeading +extern __typeof (xmlXPathNodeLeading) xmlXPathNodeLeading __attribute((alias("xmlXPathNodeLeading__internal_alias"))); +#else +#ifndef xmlXPathNodeLeading +extern __typeof (xmlXPathNodeLeading) xmlXPathNodeLeading__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathNodeLeading xmlXPathNodeLeading__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathNodeLeadingSorted +extern __typeof (xmlXPathNodeLeadingSorted) xmlXPathNodeLeadingSorted __attribute((alias("xmlXPathNodeLeadingSorted__internal_alias"))); +#else +#ifndef xmlXPathNodeLeadingSorted +extern __typeof (xmlXPathNodeLeadingSorted) xmlXPathNodeLeadingSorted__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathNodeLeadingSorted xmlXPathNodeLeadingSorted__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathNodeSetAdd +extern __typeof (xmlXPathNodeSetAdd) xmlXPathNodeSetAdd __attribute((alias("xmlXPathNodeSetAdd__internal_alias"))); +#else +#ifndef xmlXPathNodeSetAdd +extern __typeof (xmlXPathNodeSetAdd) xmlXPathNodeSetAdd__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathNodeSetAdd xmlXPathNodeSetAdd__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathNodeSetAddNs +extern __typeof (xmlXPathNodeSetAddNs) xmlXPathNodeSetAddNs __attribute((alias("xmlXPathNodeSetAddNs__internal_alias"))); +#else +#ifndef xmlXPathNodeSetAddNs +extern __typeof (xmlXPathNodeSetAddNs) xmlXPathNodeSetAddNs__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathNodeSetAddNs xmlXPathNodeSetAddNs__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathNodeSetAddUnique +extern __typeof (xmlXPathNodeSetAddUnique) xmlXPathNodeSetAddUnique __attribute((alias("xmlXPathNodeSetAddUnique__internal_alias"))); +#else +#ifndef xmlXPathNodeSetAddUnique +extern __typeof (xmlXPathNodeSetAddUnique) xmlXPathNodeSetAddUnique__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathNodeSetAddUnique xmlXPathNodeSetAddUnique__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathNodeSetContains +extern __typeof (xmlXPathNodeSetContains) xmlXPathNodeSetContains __attribute((alias("xmlXPathNodeSetContains__internal_alias"))); +#else +#ifndef xmlXPathNodeSetContains +extern __typeof (xmlXPathNodeSetContains) xmlXPathNodeSetContains__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathNodeSetContains xmlXPathNodeSetContains__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathNodeSetCreate +extern __typeof (xmlXPathNodeSetCreate) xmlXPathNodeSetCreate __attribute((alias("xmlXPathNodeSetCreate__internal_alias"))); +#else +#ifndef xmlXPathNodeSetCreate +extern __typeof (xmlXPathNodeSetCreate) xmlXPathNodeSetCreate__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathNodeSetCreate xmlXPathNodeSetCreate__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathNodeSetDel +extern __typeof (xmlXPathNodeSetDel) xmlXPathNodeSetDel __attribute((alias("xmlXPathNodeSetDel__internal_alias"))); +#else +#ifndef xmlXPathNodeSetDel +extern __typeof (xmlXPathNodeSetDel) xmlXPathNodeSetDel__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathNodeSetDel xmlXPathNodeSetDel__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathNodeSetFreeNs +extern __typeof (xmlXPathNodeSetFreeNs) xmlXPathNodeSetFreeNs __attribute((alias("xmlXPathNodeSetFreeNs__internal_alias"))); +#else +#ifndef xmlXPathNodeSetFreeNs +extern __typeof (xmlXPathNodeSetFreeNs) xmlXPathNodeSetFreeNs__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathNodeSetFreeNs xmlXPathNodeSetFreeNs__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathNodeSetMerge +extern __typeof (xmlXPathNodeSetMerge) xmlXPathNodeSetMerge __attribute((alias("xmlXPathNodeSetMerge__internal_alias"))); +#else +#ifndef xmlXPathNodeSetMerge +extern __typeof (xmlXPathNodeSetMerge) xmlXPathNodeSetMerge__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathNodeSetMerge xmlXPathNodeSetMerge__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathNodeSetRemove +extern __typeof (xmlXPathNodeSetRemove) xmlXPathNodeSetRemove __attribute((alias("xmlXPathNodeSetRemove__internal_alias"))); +#else +#ifndef xmlXPathNodeSetRemove +extern __typeof (xmlXPathNodeSetRemove) xmlXPathNodeSetRemove__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathNodeSetRemove xmlXPathNodeSetRemove__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathNodeSetSort +extern __typeof (xmlXPathNodeSetSort) xmlXPathNodeSetSort __attribute((alias("xmlXPathNodeSetSort__internal_alias"))); +#else +#ifndef xmlXPathNodeSetSort +extern __typeof (xmlXPathNodeSetSort) xmlXPathNodeSetSort__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathNodeSetSort xmlXPathNodeSetSort__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathNodeTrailing +extern __typeof (xmlXPathNodeTrailing) xmlXPathNodeTrailing __attribute((alias("xmlXPathNodeTrailing__internal_alias"))); +#else +#ifndef xmlXPathNodeTrailing +extern __typeof (xmlXPathNodeTrailing) xmlXPathNodeTrailing__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathNodeTrailing xmlXPathNodeTrailing__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathNodeTrailingSorted +extern __typeof (xmlXPathNodeTrailingSorted) xmlXPathNodeTrailingSorted __attribute((alias("xmlXPathNodeTrailingSorted__internal_alias"))); +#else +#ifndef xmlXPathNodeTrailingSorted +extern __typeof (xmlXPathNodeTrailingSorted) xmlXPathNodeTrailingSorted__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathNodeTrailingSorted xmlXPathNodeTrailingSorted__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathNormalizeFunction +extern __typeof (xmlXPathNormalizeFunction) xmlXPathNormalizeFunction __attribute((alias("xmlXPathNormalizeFunction__internal_alias"))); +#else +#ifndef xmlXPathNormalizeFunction +extern __typeof (xmlXPathNormalizeFunction) xmlXPathNormalizeFunction__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathNormalizeFunction xmlXPathNormalizeFunction__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathNotEqualValues +extern __typeof (xmlXPathNotEqualValues) xmlXPathNotEqualValues __attribute((alias("xmlXPathNotEqualValues__internal_alias"))); +#else +#ifndef xmlXPathNotEqualValues +extern __typeof (xmlXPathNotEqualValues) xmlXPathNotEqualValues__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathNotEqualValues xmlXPathNotEqualValues__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathNotFunction +extern __typeof (xmlXPathNotFunction) xmlXPathNotFunction __attribute((alias("xmlXPathNotFunction__internal_alias"))); +#else +#ifndef xmlXPathNotFunction +extern __typeof (xmlXPathNotFunction) xmlXPathNotFunction__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathNotFunction xmlXPathNotFunction__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathNsLookup +extern __typeof (xmlXPathNsLookup) xmlXPathNsLookup __attribute((alias("xmlXPathNsLookup__internal_alias"))); +#else +#ifndef xmlXPathNsLookup +extern __typeof (xmlXPathNsLookup) xmlXPathNsLookup__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathNsLookup xmlXPathNsLookup__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathNumberFunction +extern __typeof (xmlXPathNumberFunction) xmlXPathNumberFunction __attribute((alias("xmlXPathNumberFunction__internal_alias"))); +#else +#ifndef xmlXPathNumberFunction +extern __typeof (xmlXPathNumberFunction) xmlXPathNumberFunction__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathNumberFunction xmlXPathNumberFunction__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathObjectCopy +extern __typeof (xmlXPathObjectCopy) xmlXPathObjectCopy __attribute((alias("xmlXPathObjectCopy__internal_alias"))); +#else +#ifndef xmlXPathObjectCopy +extern __typeof (xmlXPathObjectCopy) xmlXPathObjectCopy__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathObjectCopy xmlXPathObjectCopy__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathOrderDocElems +extern __typeof (xmlXPathOrderDocElems) xmlXPathOrderDocElems __attribute((alias("xmlXPathOrderDocElems__internal_alias"))); +#else +#ifndef xmlXPathOrderDocElems +extern __typeof (xmlXPathOrderDocElems) xmlXPathOrderDocElems__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathOrderDocElems xmlXPathOrderDocElems__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathParseNCName +extern __typeof (xmlXPathParseNCName) xmlXPathParseNCName __attribute((alias("xmlXPathParseNCName__internal_alias"))); +#else +#ifndef xmlXPathParseNCName +extern __typeof (xmlXPathParseNCName) xmlXPathParseNCName__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathParseNCName xmlXPathParseNCName__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathParseName +extern __typeof (xmlXPathParseName) xmlXPathParseName __attribute((alias("xmlXPathParseName__internal_alias"))); +#else +#ifndef xmlXPathParseName +extern __typeof (xmlXPathParseName) xmlXPathParseName__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathParseName xmlXPathParseName__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathPopBoolean +extern __typeof (xmlXPathPopBoolean) xmlXPathPopBoolean __attribute((alias("xmlXPathPopBoolean__internal_alias"))); +#else +#ifndef xmlXPathPopBoolean +extern __typeof (xmlXPathPopBoolean) xmlXPathPopBoolean__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathPopBoolean xmlXPathPopBoolean__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathPopExternal +extern __typeof (xmlXPathPopExternal) xmlXPathPopExternal __attribute((alias("xmlXPathPopExternal__internal_alias"))); +#else +#ifndef xmlXPathPopExternal +extern __typeof (xmlXPathPopExternal) xmlXPathPopExternal__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathPopExternal xmlXPathPopExternal__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathPopNodeSet +extern __typeof (xmlXPathPopNodeSet) xmlXPathPopNodeSet __attribute((alias("xmlXPathPopNodeSet__internal_alias"))); +#else +#ifndef xmlXPathPopNodeSet +extern __typeof (xmlXPathPopNodeSet) xmlXPathPopNodeSet__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathPopNodeSet xmlXPathPopNodeSet__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathPopNumber +extern __typeof (xmlXPathPopNumber) xmlXPathPopNumber __attribute((alias("xmlXPathPopNumber__internal_alias"))); +#else +#ifndef xmlXPathPopNumber +extern __typeof (xmlXPathPopNumber) xmlXPathPopNumber__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathPopNumber xmlXPathPopNumber__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathPopString +extern __typeof (xmlXPathPopString) xmlXPathPopString __attribute((alias("xmlXPathPopString__internal_alias"))); +#else +#ifndef xmlXPathPopString +extern __typeof (xmlXPathPopString) xmlXPathPopString__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathPopString xmlXPathPopString__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathPositionFunction +extern __typeof (xmlXPathPositionFunction) xmlXPathPositionFunction __attribute((alias("xmlXPathPositionFunction__internal_alias"))); +#else +#ifndef xmlXPathPositionFunction +extern __typeof (xmlXPathPositionFunction) xmlXPathPositionFunction__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathPositionFunction xmlXPathPositionFunction__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathRegisterAllFunctions +extern __typeof (xmlXPathRegisterAllFunctions) xmlXPathRegisterAllFunctions __attribute((alias("xmlXPathRegisterAllFunctions__internal_alias"))); +#else +#ifndef xmlXPathRegisterAllFunctions +extern __typeof (xmlXPathRegisterAllFunctions) xmlXPathRegisterAllFunctions__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathRegisterAllFunctions xmlXPathRegisterAllFunctions__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathRegisterFunc +extern __typeof (xmlXPathRegisterFunc) xmlXPathRegisterFunc __attribute((alias("xmlXPathRegisterFunc__internal_alias"))); +#else +#ifndef xmlXPathRegisterFunc +extern __typeof (xmlXPathRegisterFunc) xmlXPathRegisterFunc__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathRegisterFunc xmlXPathRegisterFunc__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathRegisterFuncLookup +extern __typeof (xmlXPathRegisterFuncLookup) xmlXPathRegisterFuncLookup __attribute((alias("xmlXPathRegisterFuncLookup__internal_alias"))); +#else +#ifndef xmlXPathRegisterFuncLookup +extern __typeof (xmlXPathRegisterFuncLookup) xmlXPathRegisterFuncLookup__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathRegisterFuncLookup xmlXPathRegisterFuncLookup__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathRegisterFuncNS +extern __typeof (xmlXPathRegisterFuncNS) xmlXPathRegisterFuncNS __attribute((alias("xmlXPathRegisterFuncNS__internal_alias"))); +#else +#ifndef xmlXPathRegisterFuncNS +extern __typeof (xmlXPathRegisterFuncNS) xmlXPathRegisterFuncNS__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathRegisterFuncNS xmlXPathRegisterFuncNS__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathRegisterNs +extern __typeof (xmlXPathRegisterNs) xmlXPathRegisterNs __attribute((alias("xmlXPathRegisterNs__internal_alias"))); +#else +#ifndef xmlXPathRegisterNs +extern __typeof (xmlXPathRegisterNs) xmlXPathRegisterNs__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathRegisterNs xmlXPathRegisterNs__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathRegisterVariable +extern __typeof (xmlXPathRegisterVariable) xmlXPathRegisterVariable __attribute((alias("xmlXPathRegisterVariable__internal_alias"))); +#else +#ifndef xmlXPathRegisterVariable +extern __typeof (xmlXPathRegisterVariable) xmlXPathRegisterVariable__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathRegisterVariable xmlXPathRegisterVariable__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathRegisterVariableLookup +extern __typeof (xmlXPathRegisterVariableLookup) xmlXPathRegisterVariableLookup __attribute((alias("xmlXPathRegisterVariableLookup__internal_alias"))); +#else +#ifndef xmlXPathRegisterVariableLookup +extern __typeof (xmlXPathRegisterVariableLookup) xmlXPathRegisterVariableLookup__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathRegisterVariableLookup xmlXPathRegisterVariableLookup__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathRegisterVariableNS +extern __typeof (xmlXPathRegisterVariableNS) xmlXPathRegisterVariableNS __attribute((alias("xmlXPathRegisterVariableNS__internal_alias"))); +#else +#ifndef xmlXPathRegisterVariableNS +extern __typeof (xmlXPathRegisterVariableNS) xmlXPathRegisterVariableNS__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathRegisterVariableNS xmlXPathRegisterVariableNS__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathRegisteredFuncsCleanup +extern __typeof (xmlXPathRegisteredFuncsCleanup) xmlXPathRegisteredFuncsCleanup __attribute((alias("xmlXPathRegisteredFuncsCleanup__internal_alias"))); +#else +#ifndef xmlXPathRegisteredFuncsCleanup +extern __typeof (xmlXPathRegisteredFuncsCleanup) xmlXPathRegisteredFuncsCleanup__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathRegisteredFuncsCleanup xmlXPathRegisteredFuncsCleanup__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathRegisteredNsCleanup +extern __typeof (xmlXPathRegisteredNsCleanup) xmlXPathRegisteredNsCleanup __attribute((alias("xmlXPathRegisteredNsCleanup__internal_alias"))); +#else +#ifndef xmlXPathRegisteredNsCleanup +extern __typeof (xmlXPathRegisteredNsCleanup) xmlXPathRegisteredNsCleanup__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathRegisteredNsCleanup xmlXPathRegisteredNsCleanup__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathRegisteredVariablesCleanup +extern __typeof (xmlXPathRegisteredVariablesCleanup) xmlXPathRegisteredVariablesCleanup __attribute((alias("xmlXPathRegisteredVariablesCleanup__internal_alias"))); +#else +#ifndef xmlXPathRegisteredVariablesCleanup +extern __typeof (xmlXPathRegisteredVariablesCleanup) xmlXPathRegisteredVariablesCleanup__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathRegisteredVariablesCleanup xmlXPathRegisteredVariablesCleanup__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathRoot +extern __typeof (xmlXPathRoot) xmlXPathRoot __attribute((alias("xmlXPathRoot__internal_alias"))); +#else +#ifndef xmlXPathRoot +extern __typeof (xmlXPathRoot) xmlXPathRoot__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathRoot xmlXPathRoot__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathRoundFunction +extern __typeof (xmlXPathRoundFunction) xmlXPathRoundFunction __attribute((alias("xmlXPathRoundFunction__internal_alias"))); +#else +#ifndef xmlXPathRoundFunction +extern __typeof (xmlXPathRoundFunction) xmlXPathRoundFunction__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathRoundFunction xmlXPathRoundFunction__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathStartsWithFunction +extern __typeof (xmlXPathStartsWithFunction) xmlXPathStartsWithFunction __attribute((alias("xmlXPathStartsWithFunction__internal_alias"))); +#else +#ifndef xmlXPathStartsWithFunction +extern __typeof (xmlXPathStartsWithFunction) xmlXPathStartsWithFunction__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathStartsWithFunction xmlXPathStartsWithFunction__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathStringEvalNumber +extern __typeof (xmlXPathStringEvalNumber) xmlXPathStringEvalNumber __attribute((alias("xmlXPathStringEvalNumber__internal_alias"))); +#else +#ifndef xmlXPathStringEvalNumber +extern __typeof (xmlXPathStringEvalNumber) xmlXPathStringEvalNumber__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathStringEvalNumber xmlXPathStringEvalNumber__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathStringFunction +extern __typeof (xmlXPathStringFunction) xmlXPathStringFunction __attribute((alias("xmlXPathStringFunction__internal_alias"))); +#else +#ifndef xmlXPathStringFunction +extern __typeof (xmlXPathStringFunction) xmlXPathStringFunction__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathStringFunction xmlXPathStringFunction__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathStringLengthFunction +extern __typeof (xmlXPathStringLengthFunction) xmlXPathStringLengthFunction __attribute((alias("xmlXPathStringLengthFunction__internal_alias"))); +#else +#ifndef xmlXPathStringLengthFunction +extern __typeof (xmlXPathStringLengthFunction) xmlXPathStringLengthFunction__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathStringLengthFunction xmlXPathStringLengthFunction__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathSubValues +extern __typeof (xmlXPathSubValues) xmlXPathSubValues __attribute((alias("xmlXPathSubValues__internal_alias"))); +#else +#ifndef xmlXPathSubValues +extern __typeof (xmlXPathSubValues) xmlXPathSubValues__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathSubValues xmlXPathSubValues__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathSubstringAfterFunction +extern __typeof (xmlXPathSubstringAfterFunction) xmlXPathSubstringAfterFunction __attribute((alias("xmlXPathSubstringAfterFunction__internal_alias"))); +#else +#ifndef xmlXPathSubstringAfterFunction +extern __typeof (xmlXPathSubstringAfterFunction) xmlXPathSubstringAfterFunction__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathSubstringAfterFunction xmlXPathSubstringAfterFunction__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathSubstringBeforeFunction +extern __typeof (xmlXPathSubstringBeforeFunction) xmlXPathSubstringBeforeFunction __attribute((alias("xmlXPathSubstringBeforeFunction__internal_alias"))); +#else +#ifndef xmlXPathSubstringBeforeFunction +extern __typeof (xmlXPathSubstringBeforeFunction) xmlXPathSubstringBeforeFunction__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathSubstringBeforeFunction xmlXPathSubstringBeforeFunction__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathSubstringFunction +extern __typeof (xmlXPathSubstringFunction) xmlXPathSubstringFunction __attribute((alias("xmlXPathSubstringFunction__internal_alias"))); +#else +#ifndef xmlXPathSubstringFunction +extern __typeof (xmlXPathSubstringFunction) xmlXPathSubstringFunction__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathSubstringFunction xmlXPathSubstringFunction__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathSumFunction +extern __typeof (xmlXPathSumFunction) xmlXPathSumFunction __attribute((alias("xmlXPathSumFunction__internal_alias"))); +#else +#ifndef xmlXPathSumFunction +extern __typeof (xmlXPathSumFunction) xmlXPathSumFunction__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathSumFunction xmlXPathSumFunction__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathTrailing +extern __typeof (xmlXPathTrailing) xmlXPathTrailing __attribute((alias("xmlXPathTrailing__internal_alias"))); +#else +#ifndef xmlXPathTrailing +extern __typeof (xmlXPathTrailing) xmlXPathTrailing__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathTrailing xmlXPathTrailing__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathTrailingSorted +extern __typeof (xmlXPathTrailingSorted) xmlXPathTrailingSorted __attribute((alias("xmlXPathTrailingSorted__internal_alias"))); +#else +#ifndef xmlXPathTrailingSorted +extern __typeof (xmlXPathTrailingSorted) xmlXPathTrailingSorted__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathTrailingSorted xmlXPathTrailingSorted__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathTranslateFunction +extern __typeof (xmlXPathTranslateFunction) xmlXPathTranslateFunction __attribute((alias("xmlXPathTranslateFunction__internal_alias"))); +#else +#ifndef xmlXPathTranslateFunction +extern __typeof (xmlXPathTranslateFunction) xmlXPathTranslateFunction__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathTranslateFunction xmlXPathTranslateFunction__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathTrueFunction +extern __typeof (xmlXPathTrueFunction) xmlXPathTrueFunction __attribute((alias("xmlXPathTrueFunction__internal_alias"))); +#else +#ifndef xmlXPathTrueFunction +extern __typeof (xmlXPathTrueFunction) xmlXPathTrueFunction__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathTrueFunction xmlXPathTrueFunction__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathValueFlipSign +extern __typeof (xmlXPathValueFlipSign) xmlXPathValueFlipSign __attribute((alias("xmlXPathValueFlipSign__internal_alias"))); +#else +#ifndef xmlXPathValueFlipSign +extern __typeof (xmlXPathValueFlipSign) xmlXPathValueFlipSign__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathValueFlipSign xmlXPathValueFlipSign__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathVariableLookup +extern __typeof (xmlXPathVariableLookup) xmlXPathVariableLookup __attribute((alias("xmlXPathVariableLookup__internal_alias"))); +#else +#ifndef xmlXPathVariableLookup +extern __typeof (xmlXPathVariableLookup) xmlXPathVariableLookup__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathVariableLookup xmlXPathVariableLookup__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathVariableLookupNS +extern __typeof (xmlXPathVariableLookupNS) xmlXPathVariableLookupNS __attribute((alias("xmlXPathVariableLookupNS__internal_alias"))); +#else +#ifndef xmlXPathVariableLookupNS +extern __typeof (xmlXPathVariableLookupNS) xmlXPathVariableLookupNS__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathVariableLookupNS xmlXPathVariableLookupNS__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathWrapCString +extern __typeof (xmlXPathWrapCString) xmlXPathWrapCString __attribute((alias("xmlXPathWrapCString__internal_alias"))); +#else +#ifndef xmlXPathWrapCString +extern __typeof (xmlXPathWrapCString) xmlXPathWrapCString__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathWrapCString xmlXPathWrapCString__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathWrapExternal +extern __typeof (xmlXPathWrapExternal) xmlXPathWrapExternal __attribute((alias("xmlXPathWrapExternal__internal_alias"))); +#else +#ifndef xmlXPathWrapExternal +extern __typeof (xmlXPathWrapExternal) xmlXPathWrapExternal__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathWrapExternal xmlXPathWrapExternal__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathWrapNodeSet +extern __typeof (xmlXPathWrapNodeSet) xmlXPathWrapNodeSet __attribute((alias("xmlXPathWrapNodeSet__internal_alias"))); +#else +#ifndef xmlXPathWrapNodeSet +extern __typeof (xmlXPathWrapNodeSet) xmlXPathWrapNodeSet__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathWrapNodeSet xmlXPathWrapNodeSet__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPathWrapString +extern __typeof (xmlXPathWrapString) xmlXPathWrapString __attribute((alias("xmlXPathWrapString__internal_alias"))); +#else +#ifndef xmlXPathWrapString +extern __typeof (xmlXPathWrapString) xmlXPathWrapString__internal_alias __attribute((visibility("hidden"))); +#define xmlXPathWrapString xmlXPathWrapString__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPATH_ENABLED) +#ifdef bottom_xpath +#undef xmlXPatherror +extern __typeof (xmlXPatherror) xmlXPatherror __attribute((alias("xmlXPatherror__internal_alias"))); +#else +#ifndef xmlXPatherror +extern __typeof (xmlXPatherror) xmlXPatherror__internal_alias __attribute((visibility("hidden"))); +#define xmlXPatherror xmlXPatherror__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPTR_ENABLED) +#ifdef bottom_xpointer +#undef xmlXPtrBuildNodeList +extern __typeof (xmlXPtrBuildNodeList) xmlXPtrBuildNodeList __attribute((alias("xmlXPtrBuildNodeList__internal_alias"))); +#else +#ifndef xmlXPtrBuildNodeList +extern __typeof (xmlXPtrBuildNodeList) xmlXPtrBuildNodeList__internal_alias __attribute((visibility("hidden"))); +#define xmlXPtrBuildNodeList xmlXPtrBuildNodeList__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPTR_ENABLED) +#ifdef bottom_xpointer +#undef xmlXPtrEval +extern __typeof (xmlXPtrEval) xmlXPtrEval __attribute((alias("xmlXPtrEval__internal_alias"))); +#else +#ifndef xmlXPtrEval +extern __typeof (xmlXPtrEval) xmlXPtrEval__internal_alias __attribute((visibility("hidden"))); +#define xmlXPtrEval xmlXPtrEval__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPTR_ENABLED) +#ifdef bottom_xpointer +#undef xmlXPtrEvalRangePredicate +extern __typeof (xmlXPtrEvalRangePredicate) xmlXPtrEvalRangePredicate __attribute((alias("xmlXPtrEvalRangePredicate__internal_alias"))); +#else +#ifndef xmlXPtrEvalRangePredicate +extern __typeof (xmlXPtrEvalRangePredicate) xmlXPtrEvalRangePredicate__internal_alias __attribute((visibility("hidden"))); +#define xmlXPtrEvalRangePredicate xmlXPtrEvalRangePredicate__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPTR_ENABLED) +#ifdef bottom_xpointer +#undef xmlXPtrFreeLocationSet +extern __typeof (xmlXPtrFreeLocationSet) xmlXPtrFreeLocationSet __attribute((alias("xmlXPtrFreeLocationSet__internal_alias"))); +#else +#ifndef xmlXPtrFreeLocationSet +extern __typeof (xmlXPtrFreeLocationSet) xmlXPtrFreeLocationSet__internal_alias __attribute((visibility("hidden"))); +#define xmlXPtrFreeLocationSet xmlXPtrFreeLocationSet__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPTR_ENABLED) +#ifdef bottom_xpointer +#undef xmlXPtrLocationSetAdd +extern __typeof (xmlXPtrLocationSetAdd) xmlXPtrLocationSetAdd __attribute((alias("xmlXPtrLocationSetAdd__internal_alias"))); +#else +#ifndef xmlXPtrLocationSetAdd +extern __typeof (xmlXPtrLocationSetAdd) xmlXPtrLocationSetAdd__internal_alias __attribute((visibility("hidden"))); +#define xmlXPtrLocationSetAdd xmlXPtrLocationSetAdd__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPTR_ENABLED) +#ifdef bottom_xpointer +#undef xmlXPtrLocationSetCreate +extern __typeof (xmlXPtrLocationSetCreate) xmlXPtrLocationSetCreate __attribute((alias("xmlXPtrLocationSetCreate__internal_alias"))); +#else +#ifndef xmlXPtrLocationSetCreate +extern __typeof (xmlXPtrLocationSetCreate) xmlXPtrLocationSetCreate__internal_alias __attribute((visibility("hidden"))); +#define xmlXPtrLocationSetCreate xmlXPtrLocationSetCreate__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPTR_ENABLED) +#ifdef bottom_xpointer +#undef xmlXPtrLocationSetDel +extern __typeof (xmlXPtrLocationSetDel) xmlXPtrLocationSetDel __attribute((alias("xmlXPtrLocationSetDel__internal_alias"))); +#else +#ifndef xmlXPtrLocationSetDel +extern __typeof (xmlXPtrLocationSetDel) xmlXPtrLocationSetDel__internal_alias __attribute((visibility("hidden"))); +#define xmlXPtrLocationSetDel xmlXPtrLocationSetDel__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPTR_ENABLED) +#ifdef bottom_xpointer +#undef xmlXPtrLocationSetMerge +extern __typeof (xmlXPtrLocationSetMerge) xmlXPtrLocationSetMerge __attribute((alias("xmlXPtrLocationSetMerge__internal_alias"))); +#else +#ifndef xmlXPtrLocationSetMerge +extern __typeof (xmlXPtrLocationSetMerge) xmlXPtrLocationSetMerge__internal_alias __attribute((visibility("hidden"))); +#define xmlXPtrLocationSetMerge xmlXPtrLocationSetMerge__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPTR_ENABLED) +#ifdef bottom_xpointer +#undef xmlXPtrLocationSetRemove +extern __typeof (xmlXPtrLocationSetRemove) xmlXPtrLocationSetRemove __attribute((alias("xmlXPtrLocationSetRemove__internal_alias"))); +#else +#ifndef xmlXPtrLocationSetRemove +extern __typeof (xmlXPtrLocationSetRemove) xmlXPtrLocationSetRemove__internal_alias __attribute((visibility("hidden"))); +#define xmlXPtrLocationSetRemove xmlXPtrLocationSetRemove__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPTR_ENABLED) +#ifdef bottom_xpointer +#undef xmlXPtrNewCollapsedRange +extern __typeof (xmlXPtrNewCollapsedRange) xmlXPtrNewCollapsedRange __attribute((alias("xmlXPtrNewCollapsedRange__internal_alias"))); +#else +#ifndef xmlXPtrNewCollapsedRange +extern __typeof (xmlXPtrNewCollapsedRange) xmlXPtrNewCollapsedRange__internal_alias __attribute((visibility("hidden"))); +#define xmlXPtrNewCollapsedRange xmlXPtrNewCollapsedRange__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPTR_ENABLED) +#ifdef bottom_xpointer +#undef xmlXPtrNewContext +extern __typeof (xmlXPtrNewContext) xmlXPtrNewContext __attribute((alias("xmlXPtrNewContext__internal_alias"))); +#else +#ifndef xmlXPtrNewContext +extern __typeof (xmlXPtrNewContext) xmlXPtrNewContext__internal_alias __attribute((visibility("hidden"))); +#define xmlXPtrNewContext xmlXPtrNewContext__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPTR_ENABLED) +#ifdef bottom_xpointer +#undef xmlXPtrNewLocationSetNodeSet +extern __typeof (xmlXPtrNewLocationSetNodeSet) xmlXPtrNewLocationSetNodeSet __attribute((alias("xmlXPtrNewLocationSetNodeSet__internal_alias"))); +#else +#ifndef xmlXPtrNewLocationSetNodeSet +extern __typeof (xmlXPtrNewLocationSetNodeSet) xmlXPtrNewLocationSetNodeSet__internal_alias __attribute((visibility("hidden"))); +#define xmlXPtrNewLocationSetNodeSet xmlXPtrNewLocationSetNodeSet__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPTR_ENABLED) +#ifdef bottom_xpointer +#undef xmlXPtrNewLocationSetNodes +extern __typeof (xmlXPtrNewLocationSetNodes) xmlXPtrNewLocationSetNodes __attribute((alias("xmlXPtrNewLocationSetNodes__internal_alias"))); +#else +#ifndef xmlXPtrNewLocationSetNodes +extern __typeof (xmlXPtrNewLocationSetNodes) xmlXPtrNewLocationSetNodes__internal_alias __attribute((visibility("hidden"))); +#define xmlXPtrNewLocationSetNodes xmlXPtrNewLocationSetNodes__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPTR_ENABLED) +#ifdef bottom_xpointer +#undef xmlXPtrNewRange +extern __typeof (xmlXPtrNewRange) xmlXPtrNewRange __attribute((alias("xmlXPtrNewRange__internal_alias"))); +#else +#ifndef xmlXPtrNewRange +extern __typeof (xmlXPtrNewRange) xmlXPtrNewRange__internal_alias __attribute((visibility("hidden"))); +#define xmlXPtrNewRange xmlXPtrNewRange__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPTR_ENABLED) +#ifdef bottom_xpointer +#undef xmlXPtrNewRangeNodeObject +extern __typeof (xmlXPtrNewRangeNodeObject) xmlXPtrNewRangeNodeObject __attribute((alias("xmlXPtrNewRangeNodeObject__internal_alias"))); +#else +#ifndef xmlXPtrNewRangeNodeObject +extern __typeof (xmlXPtrNewRangeNodeObject) xmlXPtrNewRangeNodeObject__internal_alias __attribute((visibility("hidden"))); +#define xmlXPtrNewRangeNodeObject xmlXPtrNewRangeNodeObject__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPTR_ENABLED) +#ifdef bottom_xpointer +#undef xmlXPtrNewRangeNodePoint +extern __typeof (xmlXPtrNewRangeNodePoint) xmlXPtrNewRangeNodePoint __attribute((alias("xmlXPtrNewRangeNodePoint__internal_alias"))); +#else +#ifndef xmlXPtrNewRangeNodePoint +extern __typeof (xmlXPtrNewRangeNodePoint) xmlXPtrNewRangeNodePoint__internal_alias __attribute((visibility("hidden"))); +#define xmlXPtrNewRangeNodePoint xmlXPtrNewRangeNodePoint__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPTR_ENABLED) +#ifdef bottom_xpointer +#undef xmlXPtrNewRangeNodes +extern __typeof (xmlXPtrNewRangeNodes) xmlXPtrNewRangeNodes __attribute((alias("xmlXPtrNewRangeNodes__internal_alias"))); +#else +#ifndef xmlXPtrNewRangeNodes +extern __typeof (xmlXPtrNewRangeNodes) xmlXPtrNewRangeNodes__internal_alias __attribute((visibility("hidden"))); +#define xmlXPtrNewRangeNodes xmlXPtrNewRangeNodes__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPTR_ENABLED) +#ifdef bottom_xpointer +#undef xmlXPtrNewRangePointNode +extern __typeof (xmlXPtrNewRangePointNode) xmlXPtrNewRangePointNode __attribute((alias("xmlXPtrNewRangePointNode__internal_alias"))); +#else +#ifndef xmlXPtrNewRangePointNode +extern __typeof (xmlXPtrNewRangePointNode) xmlXPtrNewRangePointNode__internal_alias __attribute((visibility("hidden"))); +#define xmlXPtrNewRangePointNode xmlXPtrNewRangePointNode__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPTR_ENABLED) +#ifdef bottom_xpointer +#undef xmlXPtrNewRangePoints +extern __typeof (xmlXPtrNewRangePoints) xmlXPtrNewRangePoints __attribute((alias("xmlXPtrNewRangePoints__internal_alias"))); +#else +#ifndef xmlXPtrNewRangePoints +extern __typeof (xmlXPtrNewRangePoints) xmlXPtrNewRangePoints__internal_alias __attribute((visibility("hidden"))); +#define xmlXPtrNewRangePoints xmlXPtrNewRangePoints__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPTR_ENABLED) +#ifdef bottom_xpointer +#undef xmlXPtrRangeToFunction +extern __typeof (xmlXPtrRangeToFunction) xmlXPtrRangeToFunction __attribute((alias("xmlXPtrRangeToFunction__internal_alias"))); +#else +#ifndef xmlXPtrRangeToFunction +extern __typeof (xmlXPtrRangeToFunction) xmlXPtrRangeToFunction__internal_alias __attribute((visibility("hidden"))); +#define xmlXPtrRangeToFunction xmlXPtrRangeToFunction__internal_alias +#endif +#endif +#endif + +#if defined(LIBXML_XPTR_ENABLED) +#ifdef bottom_xpointer +#undef xmlXPtrWrapLocationSet +extern __typeof (xmlXPtrWrapLocationSet) xmlXPtrWrapLocationSet __attribute((alias("xmlXPtrWrapLocationSet__internal_alias"))); +#else +#ifndef xmlXPtrWrapLocationSet +extern __typeof (xmlXPtrWrapLocationSet) xmlXPtrWrapLocationSet__internal_alias __attribute((visibility("hidden"))); +#define xmlXPtrWrapLocationSet xmlXPtrWrapLocationSet__internal_alias +#endif +#endif +#endif + + +#endif +#endif +#endif +#endif +#endif + diff --git a/android/native/libxml2/encoding.c b/android/native/libxml2/encoding.c new file mode 100644 index 0000000000..f3198d5971 --- /dev/null +++ b/android/native/libxml2/encoding.c @@ -0,0 +1,3336 @@ +/* + * encoding.c : implements the encoding conversion functions needed for XML + * + * Related specs: + * rfc2044 (UTF-8 and UTF-16) F. Yergeau Alis Technologies + * rfc2781 UTF-16, an encoding of ISO 10646, P. Hoffman, F. Yergeau + * [ISO-10646] UTF-8 and UTF-16 in Annexes + * [ISO-8859-1] ISO Latin-1 characters codes. + * [UNICODE] The Unicode Consortium, "The Unicode Standard -- + * Worldwide Character Encoding -- Version 1.0", Addison- + * Wesley, Volume 1, 1991, Volume 2, 1992. UTF-8 is + * described in Unicode Technical Report #4. + * [US-ASCII] Coded Character Set--7-bit American Standard Code for + * Information Interchange, ANSI X3.4-1986. + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + * + * Original code for IsoLatin1 and UTF-16 by "Martin J. Duerst" + */ + +#define IN_LIBXML +#include "libxml.h" + +#include + +#ifdef HAVE_CTYPE_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef LIBXML_ICONV_ENABLED +#ifdef HAVE_ERRNO_H +#include +#endif +#endif +#include +#include +#include +#include + +static xmlCharEncodingHandlerPtr xmlUTF16LEHandler = NULL; +static xmlCharEncodingHandlerPtr xmlUTF16BEHandler = NULL; + +typedef struct _xmlCharEncodingAlias xmlCharEncodingAlias; +typedef xmlCharEncodingAlias *xmlCharEncodingAliasPtr; +struct _xmlCharEncodingAlias { + const char *name; + const char *alias; +}; + +static xmlCharEncodingAliasPtr xmlCharEncodingAliases = NULL; +static int xmlCharEncodingAliasesNb = 0; +static int xmlCharEncodingAliasesMax = 0; + +#if defined(LIBXML_ICONV_ENABLED) +#if 0 +#define DEBUG_ENCODING /* Define this to get encoding traces */ +#endif +#else +#ifdef LIBXML_ISO8859X_ENABLED +static void xmlRegisterCharEncodingHandlersISO8859x (void); +#endif +#endif + +static int xmlLittleEndian = 1; + +/** + * xmlEncodingErrMemory: + * @extra: extra informations + * + * Handle an out of memory condition + */ +static void +xmlEncodingErrMemory(const char *extra) +{ + __xmlSimpleError(XML_FROM_I18N, XML_ERR_NO_MEMORY, NULL, NULL, extra); +} + +/** + * xmlErrEncoding: + * @error: the error number + * @msg: the error message + * + * n encoding error + */ +static void +xmlEncodingErr(xmlParserErrors error, const char *msg, const char *val) +{ + __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, + XML_FROM_I18N, error, XML_ERR_FATAL, + NULL, 0, val, NULL, NULL, 0, 0, msg, val); +} + +/************************************************************************ + * * + * Conversions To/From UTF8 encoding * + * * + ************************************************************************/ + +/** + * asciiToUTF8: + * @out: a pointer to an array of bytes to store the result + * @outlen: the length of @out + * @in: a pointer to an array of ASCII chars + * @inlen: the length of @in + * + * Take a block of ASCII chars in and try to convert it to an UTF-8 + * block of chars out. + * Returns 0 if success, or -1 otherwise + * The value of @inlen after return is the number of octets consumed + * if the return value is positive, else unpredictable. + * The value of @outlen after return is the number of octets consumed. + */ +static int +asciiToUTF8(unsigned char* out, int *outlen, + const unsigned char* in, int *inlen) { + unsigned char* outstart = out; + const unsigned char* base = in; + const unsigned char* processed = in; + unsigned char* outend = out + *outlen; + const unsigned char* inend; + unsigned int c; + + inend = in + (*inlen); + while ((in < inend) && (out - outstart + 5 < *outlen)) { + c= *in++; + + if (out >= outend) + break; + if (c < 0x80) { + *out++ = c; + } else { + *outlen = out - outstart; + *inlen = processed - base; + return(-1); + } + + processed = (const unsigned char*) in; + } + *outlen = out - outstart; + *inlen = processed - base; + return(*outlen); +} + +#ifdef LIBXML_OUTPUT_ENABLED +/** + * UTF8Toascii: + * @out: a pointer to an array of bytes to store the result + * @outlen: the length of @out + * @in: a pointer to an array of UTF-8 chars + * @inlen: the length of @in + * + * Take a block of UTF-8 chars in and try to convert it to an ASCII + * block of chars out. + * + * Returns 0 if success, -2 if the transcoding fails, or -1 otherwise + * The value of @inlen after return is the number of octets consumed + * if the return value is positive, else unpredictable. + * The value of @outlen after return is the number of octets consumed. + */ +static int +UTF8Toascii(unsigned char* out, int *outlen, + const unsigned char* in, int *inlen) { + const unsigned char* processed = in; + const unsigned char* outend; + const unsigned char* outstart = out; + const unsigned char* instart = in; + const unsigned char* inend; + unsigned int c, d; + int trailing; + + if ((out == NULL) || (outlen == NULL) || (inlen == NULL)) return(-1); + if (in == NULL) { + /* + * initialization nothing to do + */ + *outlen = 0; + *inlen = 0; + return(0); + } + inend = in + (*inlen); + outend = out + (*outlen); + while (in < inend) { + d = *in++; + if (d < 0x80) { c= d; trailing= 0; } + else if (d < 0xC0) { + /* trailing byte in leading position */ + *outlen = out - outstart; + *inlen = processed - instart; + return(-2); + } else if (d < 0xE0) { c= d & 0x1F; trailing= 1; } + else if (d < 0xF0) { c= d & 0x0F; trailing= 2; } + else if (d < 0xF8) { c= d & 0x07; trailing= 3; } + else { + /* no chance for this in Ascii */ + *outlen = out - outstart; + *inlen = processed - instart; + return(-2); + } + + if (inend - in < trailing) { + break; + } + + for ( ; trailing; trailing--) { + if ((in >= inend) || (((d= *in++) & 0xC0) != 0x80)) + break; + c <<= 6; + c |= d & 0x3F; + } + + /* assertion: c is a single UTF-4 value */ + if (c < 0x80) { + if (out >= outend) + break; + *out++ = c; + } else { + /* no chance for this in Ascii */ + *outlen = out - outstart; + *inlen = processed - instart; + return(-2); + } + processed = in; + } + *outlen = out - outstart; + *inlen = processed - instart; + return(*outlen); +} +#endif /* LIBXML_OUTPUT_ENABLED */ + +/** + * isolat1ToUTF8: + * @out: a pointer to an array of bytes to store the result + * @outlen: the length of @out + * @in: a pointer to an array of ISO Latin 1 chars + * @inlen: the length of @in + * + * Take a block of ISO Latin 1 chars in and try to convert it to an UTF-8 + * block of chars out. + * Returns the number of bytes written if success, or -1 otherwise + * The value of @inlen after return is the number of octets consumed + * if the return value is positive, else unpredictable. + * The value of @outlen after return is the number of octets consumed. + */ +int +isolat1ToUTF8(unsigned char* out, int *outlen, + const unsigned char* in, int *inlen) { + unsigned char* outstart = out; + const unsigned char* base = in; + unsigned char* outend; + const unsigned char* inend; + const unsigned char* instop; + + if ((out == NULL) || (in == NULL) || (outlen == NULL) || (inlen == NULL)) + return(-1); + + outend = out + *outlen; + inend = in + (*inlen); + instop = inend; + + while ((in < inend) && (out < outend - 1)) { + if (*in >= 0x80) { + *out++ = (((*in) >> 6) & 0x1F) | 0xC0; + *out++ = ((*in) & 0x3F) | 0x80; + ++in; + } + if ((instop - in) > (outend - out)) instop = in + (outend - out); + while ((in < instop) && (*in < 0x80)) { + *out++ = *in++; + } + } + if ((in < inend) && (out < outend) && (*in < 0x80)) { + *out++ = *in++; + } + *outlen = out - outstart; + *inlen = in - base; + return(*outlen); +} + +/** + * UTF8ToUTF8: + * @out: a pointer to an array of bytes to store the result + * @outlen: the length of @out + * @inb: a pointer to an array of UTF-8 chars + * @inlenb: the length of @in in UTF-8 chars + * + * No op copy operation for UTF8 handling. + * + * Returns the number of bytes written, or -1 if lack of space. + * The value of *inlen after return is the number of octets consumed + * if the return value is positive, else unpredictable. + */ +static int +UTF8ToUTF8(unsigned char* out, int *outlen, + const unsigned char* inb, int *inlenb) +{ + int len; + + if ((out == NULL) || (inb == NULL) || (outlen == NULL) || (inlenb == NULL)) + return(-1); + if (*outlen > *inlenb) { + len = *inlenb; + } else { + len = *outlen; + } + if (len < 0) + return(-1); + + memcpy(out, inb, len); + + *outlen = len; + *inlenb = len; + return(*outlen); +} + + +#ifdef LIBXML_OUTPUT_ENABLED +/** + * UTF8Toisolat1: + * @out: a pointer to an array of bytes to store the result + * @outlen: the length of @out + * @in: a pointer to an array of UTF-8 chars + * @inlen: the length of @in + * + * Take a block of UTF-8 chars in and try to convert it to an ISO Latin 1 + * block of chars out. + * + * Returns the number of bytes written if success, -2 if the transcoding fails, + or -1 otherwise + * The value of @inlen after return is the number of octets consumed + * if the return value is positive, else unpredictable. + * The value of @outlen after return is the number of octets consumed. + */ +int +UTF8Toisolat1(unsigned char* out, int *outlen, + const unsigned char* in, int *inlen) { + const unsigned char* processed = in; + const unsigned char* outend; + const unsigned char* outstart = out; + const unsigned char* instart = in; + const unsigned char* inend; + unsigned int c, d; + int trailing; + + if ((out == NULL) || (outlen == NULL) || (inlen == NULL)) return(-1); + if (in == NULL) { + /* + * initialization nothing to do + */ + *outlen = 0; + *inlen = 0; + return(0); + } + inend = in + (*inlen); + outend = out + (*outlen); + while (in < inend) { + d = *in++; + if (d < 0x80) { c= d; trailing= 0; } + else if (d < 0xC0) { + /* trailing byte in leading position */ + *outlen = out - outstart; + *inlen = processed - instart; + return(-2); + } else if (d < 0xE0) { c= d & 0x1F; trailing= 1; } + else if (d < 0xF0) { c= d & 0x0F; trailing= 2; } + else if (d < 0xF8) { c= d & 0x07; trailing= 3; } + else { + /* no chance for this in IsoLat1 */ + *outlen = out - outstart; + *inlen = processed - instart; + return(-2); + } + + if (inend - in < trailing) { + break; + } + + for ( ; trailing; trailing--) { + if (in >= inend) + break; + if (((d= *in++) & 0xC0) != 0x80) { + *outlen = out - outstart; + *inlen = processed - instart; + return(-2); + } + c <<= 6; + c |= d & 0x3F; + } + + /* assertion: c is a single UTF-4 value */ + if (c <= 0xFF) { + if (out >= outend) + break; + *out++ = c; + } else { + /* no chance for this in IsoLat1 */ + *outlen = out - outstart; + *inlen = processed - instart; + return(-2); + } + processed = in; + } + *outlen = out - outstart; + *inlen = processed - instart; + return(*outlen); +} +#endif /* LIBXML_OUTPUT_ENABLED */ + +/** + * UTF16LEToUTF8: + * @out: a pointer to an array of bytes to store the result + * @outlen: the length of @out + * @inb: a pointer to an array of UTF-16LE passwd as a byte array + * @inlenb: the length of @in in UTF-16LE chars + * + * Take a block of UTF-16LE ushorts in and try to convert it to an UTF-8 + * block of chars out. This function assumes the endian property + * is the same between the native type of this machine and the + * inputed one. + * + * Returns the number of bytes written, or -1 if lack of space, or -2 + * if the transcoding fails (if *in is not a valid utf16 string) + * The value of *inlen after return is the number of octets consumed + * if the return value is positive, else unpredictable. + */ +static int +UTF16LEToUTF8(unsigned char* out, int *outlen, + const unsigned char* inb, int *inlenb) +{ + unsigned char* outstart = out; + const unsigned char* processed = inb; + unsigned char* outend = out + *outlen; + unsigned short* in = (unsigned short*) inb; + unsigned short* inend; + unsigned int c, d, inlen; + unsigned char *tmp; + int bits; + + if ((*inlenb % 2) == 1) + (*inlenb)--; + inlen = *inlenb / 2; + inend = in + inlen; + while ((in < inend) && (out - outstart + 5 < *outlen)) { + if (xmlLittleEndian) { + c= *in++; + } else { + tmp = (unsigned char *) in; + c = *tmp++; + c = c | (((unsigned int)*tmp) << 8); + in++; + } + if ((c & 0xFC00) == 0xD800) { /* surrogates */ + if (in >= inend) { /* (in > inend) shouldn't happens */ + break; + } + if (xmlLittleEndian) { + d = *in++; + } else { + tmp = (unsigned char *) in; + d = *tmp++; + d = d | (((unsigned int)*tmp) << 8); + in++; + } + if ((d & 0xFC00) == 0xDC00) { + c &= 0x03FF; + c <<= 10; + c |= d & 0x03FF; + c += 0x10000; + } + else { + *outlen = out - outstart; + *inlenb = processed - inb; + return(-2); + } + } + + /* assertion: c is a single UTF-4 value */ + if (out >= outend) + break; + if (c < 0x80) { *out++= c; bits= -6; } + else if (c < 0x800) { *out++= ((c >> 6) & 0x1F) | 0xC0; bits= 0; } + else if (c < 0x10000) { *out++= ((c >> 12) & 0x0F) | 0xE0; bits= 6; } + else { *out++= ((c >> 18) & 0x07) | 0xF0; bits= 12; } + + for ( ; bits >= 0; bits-= 6) { + if (out >= outend) + break; + *out++= ((c >> bits) & 0x3F) | 0x80; + } + processed = (const unsigned char*) in; + } + *outlen = out - outstart; + *inlenb = processed - inb; + return(*outlen); +} + +#ifdef LIBXML_OUTPUT_ENABLED +/** + * UTF8ToUTF16LE: + * @outb: a pointer to an array of bytes to store the result + * @outlen: the length of @outb + * @in: a pointer to an array of UTF-8 chars + * @inlen: the length of @in + * + * Take a block of UTF-8 chars in and try to convert it to an UTF-16LE + * block of chars out. + * + * Returns the number of bytes written, or -1 if lack of space, or -2 + * if the transcoding failed. + */ +static int +UTF8ToUTF16LE(unsigned char* outb, int *outlen, + const unsigned char* in, int *inlen) +{ + unsigned short* out = (unsigned short*) outb; + const unsigned char* processed = in; + const unsigned char *const instart = in; + unsigned short* outstart= out; + unsigned short* outend; + const unsigned char* inend; + unsigned int c, d; + int trailing; + unsigned char *tmp; + unsigned short tmp1, tmp2; + + /* UTF16LE encoding has no BOM */ + if ((out == NULL) || (outlen == NULL) || (inlen == NULL)) return(-1); + if (in == NULL) { + *outlen = 0; + *inlen = 0; + return(0); + } + inend= in + *inlen; + outend = out + (*outlen / 2); + while (in < inend) { + d= *in++; + if (d < 0x80) { c= d; trailing= 0; } + else if (d < 0xC0) { + /* trailing byte in leading position */ + *outlen = (out - outstart) * 2; + *inlen = processed - instart; + return(-2); + } else if (d < 0xE0) { c= d & 0x1F; trailing= 1; } + else if (d < 0xF0) { c= d & 0x0F; trailing= 2; } + else if (d < 0xF8) { c= d & 0x07; trailing= 3; } + else { + /* no chance for this in UTF-16 */ + *outlen = (out - outstart) * 2; + *inlen = processed - instart; + return(-2); + } + + if (inend - in < trailing) { + break; + } + + for ( ; trailing; trailing--) { + if ((in >= inend) || (((d= *in++) & 0xC0) != 0x80)) + break; + c <<= 6; + c |= d & 0x3F; + } + + /* assertion: c is a single UTF-4 value */ + if (c < 0x10000) { + if (out >= outend) + break; + if (xmlLittleEndian) { + *out++ = c; + } else { + tmp = (unsigned char *) out; + *tmp = c ; + *(tmp + 1) = c >> 8 ; + out++; + } + } + else if (c < 0x110000) { + if (out+1 >= outend) + break; + c -= 0x10000; + if (xmlLittleEndian) { + *out++ = 0xD800 | (c >> 10); + *out++ = 0xDC00 | (c & 0x03FF); + } else { + tmp1 = 0xD800 | (c >> 10); + tmp = (unsigned char *) out; + *tmp = (unsigned char) tmp1; + *(tmp + 1) = tmp1 >> 8; + out++; + + tmp2 = 0xDC00 | (c & 0x03FF); + tmp = (unsigned char *) out; + *tmp = (unsigned char) tmp2; + *(tmp + 1) = tmp2 >> 8; + out++; + } + } + else + break; + processed = in; + } + *outlen = (out - outstart) * 2; + *inlen = processed - instart; + return(*outlen); +} + +/** + * UTF8ToUTF16: + * @outb: a pointer to an array of bytes to store the result + * @outlen: the length of @outb + * @in: a pointer to an array of UTF-8 chars + * @inlen: the length of @in + * + * Take a block of UTF-8 chars in and try to convert it to an UTF-16 + * block of chars out. + * + * Returns the number of bytes written, or -1 if lack of space, or -2 + * if the transcoding failed. + */ +static int +UTF8ToUTF16(unsigned char* outb, int *outlen, + const unsigned char* in, int *inlen) +{ + if (in == NULL) { + /* + * initialization, add the Byte Order Mark for UTF-16LE + */ + if (*outlen >= 2) { + outb[0] = 0xFF; + outb[1] = 0xFE; + *outlen = 2; + *inlen = 0; +#ifdef DEBUG_ENCODING + xmlGenericError(xmlGenericErrorContext, + "Added FFFE Byte Order Mark\n"); +#endif + return(2); + } + *outlen = 0; + *inlen = 0; + return(0); + } + return (UTF8ToUTF16LE(outb, outlen, in, inlen)); +} +#endif /* LIBXML_OUTPUT_ENABLED */ + +/** + * UTF16BEToUTF8: + * @out: a pointer to an array of bytes to store the result + * @outlen: the length of @out + * @inb: a pointer to an array of UTF-16 passed as a byte array + * @inlenb: the length of @in in UTF-16 chars + * + * Take a block of UTF-16 ushorts in and try to convert it to an UTF-8 + * block of chars out. This function assumes the endian property + * is the same between the native type of this machine and the + * inputed one. + * + * Returns the number of bytes written, or -1 if lack of space, or -2 + * if the transcoding fails (if *in is not a valid utf16 string) + * The value of *inlen after return is the number of octets consumed + * if the return value is positive, else unpredictable. + */ +static int +UTF16BEToUTF8(unsigned char* out, int *outlen, + const unsigned char* inb, int *inlenb) +{ + unsigned char* outstart = out; + const unsigned char* processed = inb; + unsigned char* outend = out + *outlen; + unsigned short* in = (unsigned short*) inb; + unsigned short* inend; + unsigned int c, d, inlen; + unsigned char *tmp; + int bits; + + if ((*inlenb % 2) == 1) + (*inlenb)--; + inlen = *inlenb / 2; + inend= in + inlen; + while (in < inend) { + if (xmlLittleEndian) { + tmp = (unsigned char *) in; + c = *tmp++; + c = c << 8; + c = c | (unsigned int) *tmp; + in++; + } else { + c= *in++; + } + if ((c & 0xFC00) == 0xD800) { /* surrogates */ + if (in >= inend) { /* (in > inend) shouldn't happens */ + *outlen = out - outstart; + *inlenb = processed - inb; + return(-2); + } + if (xmlLittleEndian) { + tmp = (unsigned char *) in; + d = *tmp++; + d = d << 8; + d = d | (unsigned int) *tmp; + in++; + } else { + d= *in++; + } + if ((d & 0xFC00) == 0xDC00) { + c &= 0x03FF; + c <<= 10; + c |= d & 0x03FF; + c += 0x10000; + } + else { + *outlen = out - outstart; + *inlenb = processed - inb; + return(-2); + } + } + + /* assertion: c is a single UTF-4 value */ + if (out >= outend) + break; + if (c < 0x80) { *out++= c; bits= -6; } + else if (c < 0x800) { *out++= ((c >> 6) & 0x1F) | 0xC0; bits= 0; } + else if (c < 0x10000) { *out++= ((c >> 12) & 0x0F) | 0xE0; bits= 6; } + else { *out++= ((c >> 18) & 0x07) | 0xF0; bits= 12; } + + for ( ; bits >= 0; bits-= 6) { + if (out >= outend) + break; + *out++= ((c >> bits) & 0x3F) | 0x80; + } + processed = (const unsigned char*) in; + } + *outlen = out - outstart; + *inlenb = processed - inb; + return(*outlen); +} + +#ifdef LIBXML_OUTPUT_ENABLED +/** + * UTF8ToUTF16BE: + * @outb: a pointer to an array of bytes to store the result + * @outlen: the length of @outb + * @in: a pointer to an array of UTF-8 chars + * @inlen: the length of @in + * + * Take a block of UTF-8 chars in and try to convert it to an UTF-16BE + * block of chars out. + * + * Returns the number of byte written, or -1 by lack of space, or -2 + * if the transcoding failed. + */ +static int +UTF8ToUTF16BE(unsigned char* outb, int *outlen, + const unsigned char* in, int *inlen) +{ + unsigned short* out = (unsigned short*) outb; + const unsigned char* processed = in; + const unsigned char *const instart = in; + unsigned short* outstart= out; + unsigned short* outend; + const unsigned char* inend; + unsigned int c, d; + int trailing; + unsigned char *tmp; + unsigned short tmp1, tmp2; + + /* UTF-16BE has no BOM */ + if ((outb == NULL) || (outlen == NULL) || (inlen == NULL)) return(-1); + if (in == NULL) { + *outlen = 0; + *inlen = 0; + return(0); + } + inend= in + *inlen; + outend = out + (*outlen / 2); + while (in < inend) { + d= *in++; + if (d < 0x80) { c= d; trailing= 0; } + else if (d < 0xC0) { + /* trailing byte in leading position */ + *outlen = out - outstart; + *inlen = processed - instart; + return(-2); + } else if (d < 0xE0) { c= d & 0x1F; trailing= 1; } + else if (d < 0xF0) { c= d & 0x0F; trailing= 2; } + else if (d < 0xF8) { c= d & 0x07; trailing= 3; } + else { + /* no chance for this in UTF-16 */ + *outlen = out - outstart; + *inlen = processed - instart; + return(-2); + } + + if (inend - in < trailing) { + break; + } + + for ( ; trailing; trailing--) { + if ((in >= inend) || (((d= *in++) & 0xC0) != 0x80)) break; + c <<= 6; + c |= d & 0x3F; + } + + /* assertion: c is a single UTF-4 value */ + if (c < 0x10000) { + if (out >= outend) break; + if (xmlLittleEndian) { + tmp = (unsigned char *) out; + *tmp = c >> 8; + *(tmp + 1) = c; + out++; + } else { + *out++ = c; + } + } + else if (c < 0x110000) { + if (out+1 >= outend) break; + c -= 0x10000; + if (xmlLittleEndian) { + tmp1 = 0xD800 | (c >> 10); + tmp = (unsigned char *) out; + *tmp = tmp1 >> 8; + *(tmp + 1) = (unsigned char) tmp1; + out++; + + tmp2 = 0xDC00 | (c & 0x03FF); + tmp = (unsigned char *) out; + *tmp = tmp2 >> 8; + *(tmp + 1) = (unsigned char) tmp2; + out++; + } else { + *out++ = 0xD800 | (c >> 10); + *out++ = 0xDC00 | (c & 0x03FF); + } + } + else + break; + processed = in; + } + *outlen = (out - outstart) * 2; + *inlen = processed - instart; + return(*outlen); +} +#endif /* LIBXML_OUTPUT_ENABLED */ + +/************************************************************************ + * * + * Generic encoding handling routines * + * * + ************************************************************************/ + +/** + * xmlDetectCharEncoding: + * @in: a pointer to the first bytes of the XML entity, must be at least + * 2 bytes long (at least 4 if encoding is UTF4 variant). + * @len: pointer to the length of the buffer + * + * Guess the encoding of the entity using the first bytes of the entity content + * according to the non-normative appendix F of the XML-1.0 recommendation. + * + * Returns one of the XML_CHAR_ENCODING_... values. + */ +xmlCharEncoding +xmlDetectCharEncoding(const unsigned char* in, int len) +{ + if (in == NULL) + return(XML_CHAR_ENCODING_NONE); + if (len >= 4) { + if ((in[0] == 0x00) && (in[1] == 0x00) && + (in[2] == 0x00) && (in[3] == 0x3C)) + return(XML_CHAR_ENCODING_UCS4BE); + if ((in[0] == 0x3C) && (in[1] == 0x00) && + (in[2] == 0x00) && (in[3] == 0x00)) + return(XML_CHAR_ENCODING_UCS4LE); + if ((in[0] == 0x00) && (in[1] == 0x00) && + (in[2] == 0x3C) && (in[3] == 0x00)) + return(XML_CHAR_ENCODING_UCS4_2143); + if ((in[0] == 0x00) && (in[1] == 0x3C) && + (in[2] == 0x00) && (in[3] == 0x00)) + return(XML_CHAR_ENCODING_UCS4_3412); + if ((in[0] == 0x4C) && (in[1] == 0x6F) && + (in[2] == 0xA7) && (in[3] == 0x94)) + return(XML_CHAR_ENCODING_EBCDIC); + if ((in[0] == 0x3C) && (in[1] == 0x3F) && + (in[2] == 0x78) && (in[3] == 0x6D)) + return(XML_CHAR_ENCODING_UTF8); + /* + * Although not part of the recommendation, we also + * attempt an "auto-recognition" of UTF-16LE and + * UTF-16BE encodings. + */ + if ((in[0] == 0x3C) && (in[1] == 0x00) && + (in[2] == 0x3F) && (in[3] == 0x00)) + return(XML_CHAR_ENCODING_UTF16LE); + if ((in[0] == 0x00) && (in[1] == 0x3C) && + (in[2] == 0x00) && (in[3] == 0x3F)) + return(XML_CHAR_ENCODING_UTF16BE); + } + if (len >= 3) { + /* + * Errata on XML-1.0 June 20 2001 + * We now allow an UTF8 encoded BOM + */ + if ((in[0] == 0xEF) && (in[1] == 0xBB) && + (in[2] == 0xBF)) + return(XML_CHAR_ENCODING_UTF8); + } + /* For UTF-16 we can recognize by the BOM */ + if (len >= 2) { + if ((in[0] == 0xFE) && (in[1] == 0xFF)) + return(XML_CHAR_ENCODING_UTF16BE); + if ((in[0] == 0xFF) && (in[1] == 0xFE)) + return(XML_CHAR_ENCODING_UTF16LE); + } + return(XML_CHAR_ENCODING_NONE); +} + +/** + * xmlCleanupEncodingAliases: + * + * Unregisters all aliases + */ +void +xmlCleanupEncodingAliases(void) { + int i; + + if (xmlCharEncodingAliases == NULL) + return; + + for (i = 0;i < xmlCharEncodingAliasesNb;i++) { + if (xmlCharEncodingAliases[i].name != NULL) + xmlFree((char *) xmlCharEncodingAliases[i].name); + if (xmlCharEncodingAliases[i].alias != NULL) + xmlFree((char *) xmlCharEncodingAliases[i].alias); + } + xmlCharEncodingAliasesNb = 0; + xmlCharEncodingAliasesMax = 0; + xmlFree(xmlCharEncodingAliases); + xmlCharEncodingAliases = NULL; +} + +/** + * xmlGetEncodingAlias: + * @alias: the alias name as parsed, in UTF-8 format (ASCII actually) + * + * Lookup an encoding name for the given alias. + * + * Returns NULL if not found, otherwise the original name + */ +const char * +xmlGetEncodingAlias(const char *alias) { + int i; + char upper[100]; + + if (alias == NULL) + return(NULL); + + if (xmlCharEncodingAliases == NULL) + return(NULL); + + for (i = 0;i < 99;i++) { + upper[i] = toupper(alias[i]); + if (upper[i] == 0) break; + } + upper[i] = 0; + + /* + * Walk down the list looking for a definition of the alias + */ + for (i = 0;i < xmlCharEncodingAliasesNb;i++) { + if (!strcmp(xmlCharEncodingAliases[i].alias, upper)) { + return(xmlCharEncodingAliases[i].name); + } + } + return(NULL); +} + +/** + * xmlAddEncodingAlias: + * @name: the encoding name as parsed, in UTF-8 format (ASCII actually) + * @alias: the alias name as parsed, in UTF-8 format (ASCII actually) + * + * Registers an alias @alias for an encoding named @name. Existing alias + * will be overwritten. + * + * Returns 0 in case of success, -1 in case of error + */ +int +xmlAddEncodingAlias(const char *name, const char *alias) { + int i; + char upper[100]; + + if ((name == NULL) || (alias == NULL)) + return(-1); + + for (i = 0;i < 99;i++) { + upper[i] = toupper(alias[i]); + if (upper[i] == 0) break; + } + upper[i] = 0; + + if (xmlCharEncodingAliases == NULL) { + xmlCharEncodingAliasesNb = 0; + xmlCharEncodingAliasesMax = 20; + xmlCharEncodingAliases = (xmlCharEncodingAliasPtr) + xmlMalloc(xmlCharEncodingAliasesMax * sizeof(xmlCharEncodingAlias)); + if (xmlCharEncodingAliases == NULL) + return(-1); + } else if (xmlCharEncodingAliasesNb >= xmlCharEncodingAliasesMax) { + xmlCharEncodingAliasesMax *= 2; + xmlCharEncodingAliases = (xmlCharEncodingAliasPtr) + xmlRealloc(xmlCharEncodingAliases, + xmlCharEncodingAliasesMax * sizeof(xmlCharEncodingAlias)); + } + /* + * Walk down the list looking for a definition of the alias + */ + for (i = 0;i < xmlCharEncodingAliasesNb;i++) { + if (!strcmp(xmlCharEncodingAliases[i].alias, upper)) { + /* + * Replace the definition. + */ + xmlFree((char *) xmlCharEncodingAliases[i].name); + xmlCharEncodingAliases[i].name = xmlMemStrdup(name); + return(0); + } + } + /* + * Add the definition + */ + xmlCharEncodingAliases[xmlCharEncodingAliasesNb].name = xmlMemStrdup(name); + xmlCharEncodingAliases[xmlCharEncodingAliasesNb].alias = xmlMemStrdup(upper); + xmlCharEncodingAliasesNb++; + return(0); +} + +/** + * xmlDelEncodingAlias: + * @alias: the alias name as parsed, in UTF-8 format (ASCII actually) + * + * Unregisters an encoding alias @alias + * + * Returns 0 in case of success, -1 in case of error + */ +int +xmlDelEncodingAlias(const char *alias) { + int i; + + if (alias == NULL) + return(-1); + + if (xmlCharEncodingAliases == NULL) + return(-1); + /* + * Walk down the list looking for a definition of the alias + */ + for (i = 0;i < xmlCharEncodingAliasesNb;i++) { + if (!strcmp(xmlCharEncodingAliases[i].alias, alias)) { + xmlFree((char *) xmlCharEncodingAliases[i].name); + xmlFree((char *) xmlCharEncodingAliases[i].alias); + xmlCharEncodingAliasesNb--; + memmove(&xmlCharEncodingAliases[i], &xmlCharEncodingAliases[i + 1], + sizeof(xmlCharEncodingAlias) * (xmlCharEncodingAliasesNb - i)); + return(0); + } + } + return(-1); +} + +/** + * xmlParseCharEncoding: + * @name: the encoding name as parsed, in UTF-8 format (ASCII actually) + * + * Compare the string to the encoding schemes already known. Note + * that the comparison is case insensitive accordingly to the section + * [XML] 4.3.3 Character Encoding in Entities. + * + * Returns one of the XML_CHAR_ENCODING_... values or XML_CHAR_ENCODING_NONE + * if not recognized. + */ +xmlCharEncoding +xmlParseCharEncoding(const char* name) +{ + const char *alias; + char upper[500]; + int i; + + if (name == NULL) + return(XML_CHAR_ENCODING_NONE); + + /* + * Do the alias resolution + */ + alias = xmlGetEncodingAlias(name); + if (alias != NULL) + name = alias; + + for (i = 0;i < 499;i++) { + upper[i] = toupper(name[i]); + if (upper[i] == 0) break; + } + upper[i] = 0; + + if (!strcmp(upper, "")) return(XML_CHAR_ENCODING_NONE); + if (!strcmp(upper, "UTF-8")) return(XML_CHAR_ENCODING_UTF8); + if (!strcmp(upper, "UTF8")) return(XML_CHAR_ENCODING_UTF8); + + /* + * NOTE: if we were able to parse this, the endianness of UTF16 is + * already found and in use + */ + if (!strcmp(upper, "UTF-16")) return(XML_CHAR_ENCODING_UTF16LE); + if (!strcmp(upper, "UTF16")) return(XML_CHAR_ENCODING_UTF16LE); + + if (!strcmp(upper, "ISO-10646-UCS-2")) return(XML_CHAR_ENCODING_UCS2); + if (!strcmp(upper, "UCS-2")) return(XML_CHAR_ENCODING_UCS2); + if (!strcmp(upper, "UCS2")) return(XML_CHAR_ENCODING_UCS2); + + /* + * NOTE: if we were able to parse this, the endianness of UCS4 is + * already found and in use + */ + if (!strcmp(upper, "ISO-10646-UCS-4")) return(XML_CHAR_ENCODING_UCS4LE); + if (!strcmp(upper, "UCS-4")) return(XML_CHAR_ENCODING_UCS4LE); + if (!strcmp(upper, "UCS4")) return(XML_CHAR_ENCODING_UCS4LE); + + + if (!strcmp(upper, "ISO-8859-1")) return(XML_CHAR_ENCODING_8859_1); + if (!strcmp(upper, "ISO-LATIN-1")) return(XML_CHAR_ENCODING_8859_1); + if (!strcmp(upper, "ISO LATIN 1")) return(XML_CHAR_ENCODING_8859_1); + + if (!strcmp(upper, "ISO-8859-2")) return(XML_CHAR_ENCODING_8859_2); + if (!strcmp(upper, "ISO-LATIN-2")) return(XML_CHAR_ENCODING_8859_2); + if (!strcmp(upper, "ISO LATIN 2")) return(XML_CHAR_ENCODING_8859_2); + + if (!strcmp(upper, "ISO-8859-3")) return(XML_CHAR_ENCODING_8859_3); + if (!strcmp(upper, "ISO-8859-4")) return(XML_CHAR_ENCODING_8859_4); + if (!strcmp(upper, "ISO-8859-5")) return(XML_CHAR_ENCODING_8859_5); + if (!strcmp(upper, "ISO-8859-6")) return(XML_CHAR_ENCODING_8859_6); + if (!strcmp(upper, "ISO-8859-7")) return(XML_CHAR_ENCODING_8859_7); + if (!strcmp(upper, "ISO-8859-8")) return(XML_CHAR_ENCODING_8859_8); + if (!strcmp(upper, "ISO-8859-9")) return(XML_CHAR_ENCODING_8859_9); + + if (!strcmp(upper, "ISO-2022-JP")) return(XML_CHAR_ENCODING_2022_JP); + if (!strcmp(upper, "SHIFT_JIS")) return(XML_CHAR_ENCODING_SHIFT_JIS); + if (!strcmp(upper, "EUC-JP")) return(XML_CHAR_ENCODING_EUC_JP); + +#ifdef DEBUG_ENCODING + xmlGenericError(xmlGenericErrorContext, "Unknown encoding %s\n", name); +#endif + return(XML_CHAR_ENCODING_ERROR); +} + +/** + * xmlGetCharEncodingName: + * @enc: the encoding + * + * The "canonical" name for XML encoding. + * C.f. http://www.w3.org/TR/REC-xml#charencoding + * Section 4.3.3 Character Encoding in Entities + * + * Returns the canonical name for the given encoding + */ + +const char* +xmlGetCharEncodingName(xmlCharEncoding enc) { + switch (enc) { + case XML_CHAR_ENCODING_ERROR: + return(NULL); + case XML_CHAR_ENCODING_NONE: + return(NULL); + case XML_CHAR_ENCODING_UTF8: + return("UTF-8"); + case XML_CHAR_ENCODING_UTF16LE: + return("UTF-16"); + case XML_CHAR_ENCODING_UTF16BE: + return("UTF-16"); + case XML_CHAR_ENCODING_EBCDIC: + return("EBCDIC"); + case XML_CHAR_ENCODING_UCS4LE: + return("ISO-10646-UCS-4"); + case XML_CHAR_ENCODING_UCS4BE: + return("ISO-10646-UCS-4"); + case XML_CHAR_ENCODING_UCS4_2143: + return("ISO-10646-UCS-4"); + case XML_CHAR_ENCODING_UCS4_3412: + return("ISO-10646-UCS-4"); + case XML_CHAR_ENCODING_UCS2: + return("ISO-10646-UCS-2"); + case XML_CHAR_ENCODING_8859_1: + return("ISO-8859-1"); + case XML_CHAR_ENCODING_8859_2: + return("ISO-8859-2"); + case XML_CHAR_ENCODING_8859_3: + return("ISO-8859-3"); + case XML_CHAR_ENCODING_8859_4: + return("ISO-8859-4"); + case XML_CHAR_ENCODING_8859_5: + return("ISO-8859-5"); + case XML_CHAR_ENCODING_8859_6: + return("ISO-8859-6"); + case XML_CHAR_ENCODING_8859_7: + return("ISO-8859-7"); + case XML_CHAR_ENCODING_8859_8: + return("ISO-8859-8"); + case XML_CHAR_ENCODING_8859_9: + return("ISO-8859-9"); + case XML_CHAR_ENCODING_2022_JP: + return("ISO-2022-JP"); + case XML_CHAR_ENCODING_SHIFT_JIS: + return("Shift-JIS"); + case XML_CHAR_ENCODING_EUC_JP: + return("EUC-JP"); + case XML_CHAR_ENCODING_ASCII: + return(NULL); + } + return(NULL); +} + +/************************************************************************ + * * + * Char encoding handlers * + * * + ************************************************************************/ + + +/* the size should be growable, but it's not a big deal ... */ +#define MAX_ENCODING_HANDLERS 50 +static xmlCharEncodingHandlerPtr *handlers = NULL; +static int nbCharEncodingHandler = 0; + +/* + * The default is UTF-8 for XML, that's also the default used for the + * parser internals, so the default encoding handler is NULL + */ + +static xmlCharEncodingHandlerPtr xmlDefaultCharEncodingHandler = NULL; + +/** + * xmlNewCharEncodingHandler: + * @name: the encoding name, in UTF-8 format (ASCII actually) + * @input: the xmlCharEncodingInputFunc to read that encoding + * @output: the xmlCharEncodingOutputFunc to write that encoding + * + * Create and registers an xmlCharEncodingHandler. + * + * Returns the xmlCharEncodingHandlerPtr created (or NULL in case of error). + */ +xmlCharEncodingHandlerPtr +xmlNewCharEncodingHandler(const char *name, + xmlCharEncodingInputFunc input, + xmlCharEncodingOutputFunc output) { + xmlCharEncodingHandlerPtr handler; + const char *alias; + char upper[500]; + int i; + char *up = NULL; + + /* + * Do the alias resolution + */ + alias = xmlGetEncodingAlias(name); + if (alias != NULL) + name = alias; + + /* + * Keep only the uppercase version of the encoding. + */ + if (name == NULL) { + xmlEncodingErr(XML_I18N_NO_NAME, + "xmlNewCharEncodingHandler : no name !\n", NULL); + return(NULL); + } + for (i = 0;i < 499;i++) { + upper[i] = toupper(name[i]); + if (upper[i] == 0) break; + } + upper[i] = 0; + up = xmlMemStrdup(upper); + if (up == NULL) { + xmlEncodingErrMemory("xmlNewCharEncodingHandler : out of memory !\n"); + return(NULL); + } + + /* + * allocate and fill-up an handler block. + */ + handler = (xmlCharEncodingHandlerPtr) + xmlMalloc(sizeof(xmlCharEncodingHandler)); + if (handler == NULL) { + xmlFree(up); + xmlEncodingErrMemory("xmlNewCharEncodingHandler : out of memory !\n"); + return(NULL); + } + memset(handler, 0, sizeof(xmlCharEncodingHandler)); + handler->input = input; + handler->output = output; + handler->name = up; + +#ifdef LIBXML_ICONV_ENABLED + handler->iconv_in = NULL; + handler->iconv_out = NULL; +#endif + + /* + * registers and returns the handler. + */ + xmlRegisterCharEncodingHandler(handler); +#ifdef DEBUG_ENCODING + xmlGenericError(xmlGenericErrorContext, + "Registered encoding handler for %s\n", name); +#endif + return(handler); +} + +/** + * xmlInitCharEncodingHandlers: + * + * Initialize the char encoding support, it registers the default + * encoding supported. + * NOTE: while public, this function usually doesn't need to be called + * in normal processing. + */ +void +xmlInitCharEncodingHandlers(void) { + unsigned short int tst = 0x1234; + unsigned char *ptr = (unsigned char *) &tst; + + if (handlers != NULL) return; + + handlers = (xmlCharEncodingHandlerPtr *) + xmlMalloc(MAX_ENCODING_HANDLERS * sizeof(xmlCharEncodingHandlerPtr)); + + if (*ptr == 0x12) xmlLittleEndian = 0; + else if (*ptr == 0x34) xmlLittleEndian = 1; + else { + xmlEncodingErr(XML_ERR_INTERNAL_ERROR, + "Odd problem at endianness detection\n", NULL); + } + + if (handlers == NULL) { + xmlEncodingErrMemory("xmlInitCharEncodingHandlers : out of memory !\n"); + return; + } + xmlNewCharEncodingHandler("UTF-8", UTF8ToUTF8, UTF8ToUTF8); +#ifdef LIBXML_OUTPUT_ENABLED + xmlUTF16LEHandler = + xmlNewCharEncodingHandler("UTF-16LE", UTF16LEToUTF8, UTF8ToUTF16LE); + xmlUTF16BEHandler = + xmlNewCharEncodingHandler("UTF-16BE", UTF16BEToUTF8, UTF8ToUTF16BE); + xmlNewCharEncodingHandler("UTF-16", UTF16LEToUTF8, UTF8ToUTF16); + xmlNewCharEncodingHandler("ISO-8859-1", isolat1ToUTF8, UTF8Toisolat1); + xmlNewCharEncodingHandler("ASCII", asciiToUTF8, UTF8Toascii); + xmlNewCharEncodingHandler("US-ASCII", asciiToUTF8, UTF8Toascii); +#else + xmlUTF16LEHandler = + xmlNewCharEncodingHandler("UTF-16LE", UTF16LEToUTF8, NULL); + xmlUTF16BEHandler = + xmlNewCharEncodingHandler("UTF-16BE", UTF16BEToUTF8, NULL); + xmlNewCharEncodingHandler("UTF-16", UTF16LEToUTF8, NULL); + xmlNewCharEncodingHandler("ISO-8859-1", isolat1ToUTF8, NULL); + xmlNewCharEncodingHandler("ASCII", asciiToUTF8, NULL); + xmlNewCharEncodingHandler("US-ASCII", asciiToUTF8, NULL); +#endif /* LIBXML_OUTPUT_ENABLED */ +#if !defined(LIBXML_ICONV_ENABLED) +#ifdef LIBXML_ISO8859X_ENABLED + xmlRegisterCharEncodingHandlersISO8859x (); +#endif +#endif + +} + +/** + * xmlCleanupCharEncodingHandlers: + * + * Cleanup the memory allocated for the char encoding support, it + * unregisters all the encoding handlers and the aliases. + */ +void +xmlCleanupCharEncodingHandlers(void) { + xmlCleanupEncodingAliases(); + + if (handlers == NULL) return; + + for (;nbCharEncodingHandler > 0;) { + nbCharEncodingHandler--; + if (handlers[nbCharEncodingHandler] != NULL) { + if (handlers[nbCharEncodingHandler]->name != NULL) + xmlFree(handlers[nbCharEncodingHandler]->name); + xmlFree(handlers[nbCharEncodingHandler]); + } + } + xmlFree(handlers); + handlers = NULL; + nbCharEncodingHandler = 0; + xmlDefaultCharEncodingHandler = NULL; +} + +/** + * xmlRegisterCharEncodingHandler: + * @handler: the xmlCharEncodingHandlerPtr handler block + * + * Register the char encoding handler, surprising, isn't it ? + */ +void +xmlRegisterCharEncodingHandler(xmlCharEncodingHandlerPtr handler) { + if (handlers == NULL) xmlInitCharEncodingHandlers(); + if ((handler == NULL) || (handlers == NULL)) { + xmlEncodingErr(XML_I18N_NO_HANDLER, + "xmlRegisterCharEncodingHandler: NULL handler !\n", NULL); + return; + } + + if (nbCharEncodingHandler >= MAX_ENCODING_HANDLERS) { + xmlEncodingErr(XML_I18N_EXCESS_HANDLER, + "xmlRegisterCharEncodingHandler: Too many handler registered, see %s\n", + "MAX_ENCODING_HANDLERS"); + return; + } + handlers[nbCharEncodingHandler++] = handler; +} + +/** + * xmlGetCharEncodingHandler: + * @enc: an xmlCharEncoding value. + * + * Search in the registered set the handler able to read/write that encoding. + * + * Returns the handler or NULL if not found + */ +xmlCharEncodingHandlerPtr +xmlGetCharEncodingHandler(xmlCharEncoding enc) { + xmlCharEncodingHandlerPtr handler; + + if (handlers == NULL) xmlInitCharEncodingHandlers(); + switch (enc) { + case XML_CHAR_ENCODING_ERROR: + return(NULL); + case XML_CHAR_ENCODING_NONE: + return(NULL); + case XML_CHAR_ENCODING_UTF8: + return(NULL); + case XML_CHAR_ENCODING_UTF16LE: + return(xmlUTF16LEHandler); + case XML_CHAR_ENCODING_UTF16BE: + return(xmlUTF16BEHandler); + 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); + 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); + 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); + 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_8859_1: + handler = xmlFindCharEncodingHandler("ISO-8859-1"); + if (handler != NULL) return(handler); + break; + case XML_CHAR_ENCODING_8859_2: + handler = xmlFindCharEncodingHandler("ISO-8859-2"); + if (handler != NULL) return(handler); + break; + case XML_CHAR_ENCODING_8859_3: + handler = xmlFindCharEncodingHandler("ISO-8859-3"); + if (handler != NULL) return(handler); + break; + case XML_CHAR_ENCODING_8859_4: + handler = xmlFindCharEncodingHandler("ISO-8859-4"); + if (handler != NULL) return(handler); + break; + case XML_CHAR_ENCODING_8859_5: + handler = xmlFindCharEncodingHandler("ISO-8859-5"); + if (handler != NULL) return(handler); + break; + case XML_CHAR_ENCODING_8859_6: + handler = xmlFindCharEncodingHandler("ISO-8859-6"); + if (handler != NULL) return(handler); + break; + case XML_CHAR_ENCODING_8859_7: + handler = xmlFindCharEncodingHandler("ISO-8859-7"); + if (handler != NULL) return(handler); + break; + case XML_CHAR_ENCODING_8859_8: + handler = xmlFindCharEncodingHandler("ISO-8859-8"); + if (handler != NULL) return(handler); + break; + case XML_CHAR_ENCODING_8859_9: + handler = xmlFindCharEncodingHandler("ISO-8859-9"); + if (handler != NULL) return(handler); + break; + + + case XML_CHAR_ENCODING_2022_JP: + handler = xmlFindCharEncodingHandler("ISO-2022-JP"); + if (handler != NULL) return(handler); + 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); + break; + case XML_CHAR_ENCODING_EUC_JP: + handler = xmlFindCharEncodingHandler("EUC-JP"); + if (handler != NULL) return(handler); + break; + default: + break; + } + +#ifdef DEBUG_ENCODING + xmlGenericError(xmlGenericErrorContext, + "No handler found for encoding %d\n", enc); +#endif + return(NULL); +} + +/** + * xmlFindCharEncodingHandler: + * @name: a string describing the char encoding. + * + * Search in the registered set the handler able to read/write that encoding. + * + * Returns the handler or NULL if not found + */ +xmlCharEncodingHandlerPtr +xmlFindCharEncodingHandler(const char *name) { + const char *nalias; + const char *norig; + xmlCharEncoding alias; +#ifdef LIBXML_ICONV_ENABLED + xmlCharEncodingHandlerPtr enc; + iconv_t icv_in, icv_out; +#endif /* LIBXML_ICONV_ENABLED */ + char upper[100]; + int i; + + if (handlers == NULL) xmlInitCharEncodingHandlers(); + if (name == NULL) return(xmlDefaultCharEncodingHandler); + if (name[0] == 0) return(xmlDefaultCharEncodingHandler); + + /* + * Do the alias resolution + */ + norig = name; + nalias = xmlGetEncodingAlias(name); + if (nalias != NULL) + name = nalias; + + /* + * Check first for directly registered encoding names + */ + for (i = 0;i < 99;i++) { + upper[i] = toupper(name[i]); + if (upper[i] == 0) break; + } + upper[i] = 0; + + if (handlers != NULL) { + for (i = 0;i < nbCharEncodingHandler; i++) { + if (!strcmp(upper, handlers[i]->name)) { +#ifdef DEBUG_ENCODING + xmlGenericError(xmlGenericErrorContext, + "Found registered handler for encoding %s\n", name); +#endif + return(handlers[i]); + } + } + } + +#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); + enc->input = NULL; + enc->output = NULL; + enc->iconv_in = icv_in; + enc->iconv_out = icv_out; +#ifdef DEBUG_ENCODING + xmlGenericError(xmlGenericErrorContext, + "Found iconv handler for encoding %s\n", name); +#endif + return enc; + } else if ((icv_in != (iconv_t) -1) || icv_out != (iconv_t) -1) { + xmlEncodingErr(XML_ERR_INTERNAL_ERROR, + "iconv : problems with filters for '%s'\n", name); + } +#endif /* LIBXML_ICONV_ENABLED */ + +#ifdef DEBUG_ENCODING + xmlGenericError(xmlGenericErrorContext, + "No handler found for encoding %s\n", name); +#endif + + /* + * Fallback using the canonical names + */ + 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 "none of the above", give up */ + return(NULL); +} + +/************************************************************************ + * * + * ICONV based generic conversion functions * + * * + ************************************************************************/ + +#ifdef LIBXML_ICONV_ENABLED +/** + * xmlIconvWrapper: + * @cd: iconv converter data structure + * @out: a pointer to an array of bytes to store the result + * @outlen: the length of @out + * @in: a pointer to an array of ISO Latin 1 chars + * @inlen: the length of @in + * + * Returns 0 if success, or + * -1 by lack of space, or + * -2 if the transcoding fails (for *in is not valid utf8 string or + * the result of transformation can't fit into the encoding we want), or + * -3 if there the last byte can't form a single output char. + * + * The value of @inlen after return is the number of octets consumed + * as the return value is positive, else unpredictable. + * The value of @outlen after return is the number of ocetes consumed. + */ +static int +xmlIconvWrapper(iconv_t cd, unsigned char *out, int *outlen, + const unsigned char *in, int *inlen) { + size_t icv_inlen, icv_outlen; + const char *icv_in = (const char *) in; + char *icv_out = (char *) out; + int ret; + + if ((out == NULL) || (outlen == NULL) || (inlen == NULL) || (in == NULL)) { + if (outlen != NULL) *outlen = 0; + return(-1); + } + icv_inlen = *inlen; + icv_outlen = *outlen; + ret = iconv(cd, (ICONV_CONST char **) &icv_in, &icv_inlen, &icv_out, &icv_outlen); + *inlen -= icv_inlen; + *outlen -= icv_outlen; + if ((icv_inlen != 0) || (ret == -1)) { +#ifdef EILSEQ + if (errno == EILSEQ) { + return -2; + } else +#endif +#ifdef E2BIG + if (errno == E2BIG) { + return -1; + } else +#endif +#ifdef EINVAL + if (errno == EINVAL) { + return -3; + } else +#endif + { + return -3; + } + } + return 0; +} +#endif /* LIBXML_ICONV_ENABLED */ + +/************************************************************************ + * * + * The real API used by libxml for on-the-fly conversion * + * * + ************************************************************************/ +int +xmlCharEncFirstLineInt(xmlCharEncodingHandler *handler, xmlBufferPtr out, + xmlBufferPtr in, int len); + +/** + * xmlCharEncFirstLineInt: + * @handler: char enconding transformation data structure + * @out: an xmlBuffer for the output. + * @in: an xmlBuffer for the input + * @len: number of bytes to convert for the first line, or -1 + * + * Front-end for the encoding handler input function, but handle only + * the very first line, i.e. limit itself to 45 chars. + * + * Returns the number of byte written if success, or + * -1 general error + * -2 if the transcoding fails (for *in is not valid utf8 string or + * the result of transformation can't fit into the encoding we want), or + */ +int +xmlCharEncFirstLineInt(xmlCharEncodingHandler *handler, xmlBufferPtr out, + xmlBufferPtr in, int len) { + int ret = -2; + int written; + int toconv; + + if (handler == NULL) return(-1); + if (out == NULL) return(-1); + if (in == NULL) return(-1); + + /* calculate space available */ + written = out->size - out->use - 1; /* count '\0' */ + toconv = in->use; + /* + * echo '' | wc -c => 38 + * 45 chars should be sufficient to reach the end of the encoding + * declaration without going too far inside the document content. + * on UTF-16 this means 90bytes, on UCS4 this means 180 + * The actual value depending on guessed encoding is passed as @len + * if provided + */ + if (len >= 0) { + if (toconv > len) + toconv = len; + } else { + if (toconv > 180) + toconv = 180; + } + if (toconv * 2 >= written) { + xmlBufferGrow(out, toconv); + written = out->size - out->use - 1; + } + + if (handler->input != NULL) { + ret = handler->input(&out->content[out->use], &written, + in->content, &toconv); + xmlBufferShrink(in, toconv); + out->use += written; + out->content[out->use] = 0; + } +#ifdef LIBXML_ICONV_ENABLED + else if (handler->iconv_in != NULL) { + ret = xmlIconvWrapper(handler->iconv_in, &out->content[out->use], + &written, in->content, &toconv); + xmlBufferShrink(in, toconv); + out->use += written; + out->content[out->use] = 0; + if (ret == -1) ret = -3; + } +#endif /* LIBXML_ICONV_ENABLED */ +#ifdef DEBUG_ENCODING + switch (ret) { + case 0: + xmlGenericError(xmlGenericErrorContext, + "converted %d bytes to %d bytes of input\n", + toconv, written); + break; + case -1: + xmlGenericError(xmlGenericErrorContext,"converted %d bytes to %d bytes of input, %d left\n", + toconv, written, in->use); + break; + case -2: + xmlGenericError(xmlGenericErrorContext, + "input conversion failed due to input error\n"); + break; + case -3: + xmlGenericError(xmlGenericErrorContext,"converted %d bytes to %d bytes of input, %d left\n", + toconv, written, in->use); + break; + default: + xmlGenericError(xmlGenericErrorContext,"Unknown input conversion failed %d\n", ret); + } +#endif /* DEBUG_ENCODING */ + /* + * Ignore when input buffer is not on a boundary + */ + if (ret == -3) ret = 0; + if (ret == -1) ret = 0; + return(ret); +} + +/** + * xmlCharEncFirstLine: + * @handler: char enconding transformation data structure + * @out: an xmlBuffer for the output. + * @in: an xmlBuffer for the input + * + * Front-end for the encoding handler input function, but handle only + * the very first line, i.e. limit itself to 45 chars. + * + * Returns the number of byte written if success, or + * -1 general error + * -2 if the transcoding fails (for *in is not valid utf8 string or + * the result of transformation can't fit into the encoding we want), or + */ +int +xmlCharEncFirstLine(xmlCharEncodingHandler *handler, xmlBufferPtr out, + xmlBufferPtr in) { + return(xmlCharEncFirstLineInt(handler, out, in, -1)); +} + +/** + * xmlCharEncInFunc: + * @handler: char encoding transformation data structure + * @out: an xmlBuffer for the output. + * @in: an xmlBuffer for the input + * + * Generic front-end for the encoding handler input function + * + * Returns the number of byte written if success, or + * -1 general error + * -2 if the transcoding fails (for *in is not valid utf8 string or + * the result of transformation can't fit into the encoding we want), or + */ +int +xmlCharEncInFunc(xmlCharEncodingHandler * handler, xmlBufferPtr out, + xmlBufferPtr in) +{ + int ret = -2; + int written; + int toconv; + + if (handler == NULL) + return (-1); + if (out == NULL) + return (-1); + if (in == NULL) + return (-1); + + toconv = in->use; + if (toconv == 0) + return (0); + written = out->size - out->use -1; /* count '\0' */ + if (toconv * 2 >= written) { + xmlBufferGrow(out, out->size + toconv * 2); + written = out->size - out->use - 1; + } + if (handler->input != NULL) { + ret = handler->input(&out->content[out->use], &written, + in->content, &toconv); + xmlBufferShrink(in, toconv); + out->use += written; + out->content[out->use] = 0; + } +#ifdef LIBXML_ICONV_ENABLED + else if (handler->iconv_in != NULL) { + ret = xmlIconvWrapper(handler->iconv_in, &out->content[out->use], + &written, in->content, &toconv); + xmlBufferShrink(in, toconv); + out->use += written; + out->content[out->use] = 0; + if (ret == -1) + ret = -3; + } +#endif /* LIBXML_ICONV_ENABLED */ + switch (ret) { + case 0: +#ifdef DEBUG_ENCODING + xmlGenericError(xmlGenericErrorContext, + "converted %d bytes to %d bytes of input\n", + toconv, written); +#endif + break; + case -1: +#ifdef DEBUG_ENCODING + xmlGenericError(xmlGenericErrorContext, + "converted %d bytes to %d bytes of input, %d left\n", + toconv, written, in->use); +#endif + break; + case -3: +#ifdef DEBUG_ENCODING + xmlGenericError(xmlGenericErrorContext, + "converted %d bytes to %d bytes of input, %d left\n", + toconv, written, in->use); +#endif + break; + case -2: { + char buf[50]; + + snprintf(&buf[0], 49, "0x%02X 0x%02X 0x%02X 0x%02X", + in->content[0], in->content[1], + in->content[2], in->content[3]); + buf[49] = 0; + xmlEncodingErr(XML_I18N_CONV_FAILED, + "input conversion failed due to input error, bytes %s\n", + buf); + } + } + /* + * Ignore when input buffer is not on a boundary + */ + if (ret == -3) + ret = 0; + return (written? written : ret); +} + +/** + * xmlCharEncOutFunc: + * @handler: char enconding transformation data structure + * @out: an xmlBuffer for the output. + * @in: an xmlBuffer for the input + * + * Generic front-end for the encoding handler output function + * a first call with @in == NULL has to be made firs to initiate the + * output in case of non-stateless encoding needing to initiate their + * state or the output (like the BOM in UTF16). + * In case of UTF8 sequence conversion errors for the given encoder, + * the content will be automatically remapped to a CharRef sequence. + * + * Returns the number of byte written if success, or + * -1 general error + * -2 if the transcoding fails (for *in is not valid utf8 string or + * the result of transformation can't fit into the encoding we want), or + */ +int +xmlCharEncOutFunc(xmlCharEncodingHandler *handler, xmlBufferPtr out, + xmlBufferPtr in) { + int ret = -2; + int written; + int writtentot = 0; + int toconv; + int output = 0; + + if (handler == NULL) return(-1); + if (out == NULL) return(-1); + +retry: + + written = out->size - out->use; + + if (written > 0) + written--; /* Gennady: count '/0' */ + + /* + * First specific handling of in = NULL, i.e. the initialization call + */ + if (in == NULL) { + toconv = 0; + if (handler->output != NULL) { + ret = handler->output(&out->content[out->use], &written, + NULL, &toconv); + if (ret >= 0) { /* Gennady: check return value */ + out->use += written; + out->content[out->use] = 0; + } + } +#ifdef LIBXML_ICONV_ENABLED + else if (handler->iconv_out != NULL) { + ret = xmlIconvWrapper(handler->iconv_out, &out->content[out->use], + &written, NULL, &toconv); + out->use += written; + out->content[out->use] = 0; + } +#endif /* LIBXML_ICONV_ENABLED */ +#ifdef DEBUG_ENCODING + xmlGenericError(xmlGenericErrorContext, + "initialized encoder\n"); +#endif + return(0); + } + + /* + * Conversion itself. + */ + toconv = in->use; + if (toconv == 0) + return(0); + if (toconv * 4 >= written) { + xmlBufferGrow(out, toconv * 4); + written = out->size - out->use - 1; + } + if (handler->output != NULL) { + ret = handler->output(&out->content[out->use], &written, + in->content, &toconv); + if (written > 0) { + xmlBufferShrink(in, toconv); + out->use += written; + writtentot += written; + } + out->content[out->use] = 0; + } +#ifdef LIBXML_ICONV_ENABLED + else if (handler->iconv_out != NULL) { + ret = xmlIconvWrapper(handler->iconv_out, &out->content[out->use], + &written, in->content, &toconv); + xmlBufferShrink(in, toconv); + out->use += written; + writtentot += written; + out->content[out->use] = 0; + if (ret == -1) { + if (written > 0) { + /* + * Can be a limitation of iconv + */ + goto retry; + } + ret = -3; + } + } +#endif /* LIBXML_ICONV_ENABLED */ + else { + xmlEncodingErr(XML_I18N_NO_OUTPUT, + "xmlCharEncOutFunc: no output function !\n", NULL); + return(-1); + } + + if (ret >= 0) output += ret; + + /* + * Attempt to handle error cases + */ + switch (ret) { + case 0: +#ifdef DEBUG_ENCODING + xmlGenericError(xmlGenericErrorContext, + "converted %d bytes to %d bytes of output\n", + toconv, written); +#endif + break; + case -1: +#ifdef DEBUG_ENCODING + xmlGenericError(xmlGenericErrorContext, + "output conversion failed by lack of space\n"); +#endif + break; + case -3: +#ifdef DEBUG_ENCODING + xmlGenericError(xmlGenericErrorContext,"converted %d bytes to %d bytes of output %d left\n", + toconv, written, in->use); +#endif + break; + case -2: { + int len = in->use; + const xmlChar *utf = (const xmlChar *) in->content; + int cur; + + cur = xmlGetUTF8Char(utf, &len); + if (cur > 0) { + xmlChar charref[20]; + +#ifdef DEBUG_ENCODING + xmlGenericError(xmlGenericErrorContext, + "handling output conversion error\n"); + xmlGenericError(xmlGenericErrorContext, + "Bytes: 0x%02X 0x%02X 0x%02X 0x%02X\n", + in->content[0], in->content[1], + in->content[2], in->content[3]); +#endif + /* + * Removes the UTF8 sequence, and replace it by a charref + * and continue the transcoding phase, hoping the error + * did not mangle the encoder state. + */ + snprintf((char *) &charref[0], sizeof(charref), "&#%d;", cur); + xmlBufferShrink(in, len); + xmlBufferAddHead(in, charref, -1); + + goto retry; + } else { + char buf[50]; + + snprintf(&buf[0], 49, "0x%02X 0x%02X 0x%02X 0x%02X", + in->content[0], in->content[1], + in->content[2], in->content[3]); + buf[49] = 0; + xmlEncodingErr(XML_I18N_CONV_FAILED, + "output conversion failed due to conv error, bytes %s\n", + buf); + if (in->alloc != XML_BUFFER_ALLOC_IMMUTABLE) + in->content[0] = ' '; + } + break; + } + } + return(ret); +} + +/** + * xmlCharEncCloseFunc: + * @handler: char enconding transformation data structure + * + * Generic front-end for encoding handler close function + * + * Returns 0 if success, or -1 in case of error + */ +int +xmlCharEncCloseFunc(xmlCharEncodingHandler *handler) { + int ret = 0; + int tofree = 0; + if (handler == NULL) return(-1); + if (handler->name == NULL) return(-1); +#ifdef LIBXML_ICONV_ENABLED + /* + * 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)) { + tofree = 1; + if (handler->iconv_out != NULL) { + if (iconv_close(handler->iconv_out)) + ret = -1; + handler->iconv_out = NULL; + } + if (handler->iconv_in != NULL) { + if (iconv_close(handler->iconv_in)) + ret = -1; + handler->iconv_in = NULL; + } + } +#endif /* LIBXML_ICONV_ENABLED */ + if (tofree) { + /* free up only dynamic handlers iconv/uconv */ + if (handler->name != NULL) + xmlFree(handler->name); + handler->name = NULL; + xmlFree(handler); + } +#ifdef DEBUG_ENCODING + if (ret) + xmlGenericError(xmlGenericErrorContext, + "failed to close the encoding handler\n"); + else + xmlGenericError(xmlGenericErrorContext, + "closed the encoding handler\n"); +#endif + + return(ret); +} + +/** + * xmlByteConsumed: + * @ctxt: an XML parser context + * + * This function provides the current index of the parser relative + * to the start of the current entity. This function is computed in + * bytes from the beginning starting at zero and finishing at the + * size in byte of the file if parsing a file. The function is + * of constant cost if the input is UTF-8 but can be costly if run + * on non-UTF-8 input. + * + * Returns the index in bytes from the beginning of the entity or -1 + * in case the index could not be computed. + */ +long +xmlByteConsumed(xmlParserCtxtPtr ctxt) { + xmlParserInputPtr in; + + if (ctxt == NULL) return(-1); + in = ctxt->input; + if (in == NULL) return(-1); + if ((in->buf != NULL) && (in->buf->encoder != NULL)) { + unsigned int unused = 0; + xmlCharEncodingHandler * handler = in->buf->encoder; + /* + * Encoding conversion, compute the number of unused original + * bytes from the input not consumed and substract that from + * the raw consumed value, this is not a cheap operation + */ + if (in->end - in->cur > 0) { + unsigned char convbuf[32000]; + const unsigned char *cur = (const unsigned char *)in->cur; + int toconv = in->end - in->cur, written = 32000; + + int ret; + + if (handler->output != NULL) { + do { + toconv = in->end - cur; + written = 32000; + ret = handler->output(&convbuf[0], &written, + cur, &toconv); + if (ret == -1) return(-1); + unused += written; + cur += toconv; + } while (ret == -2); +#ifdef LIBXML_ICONV_ENABLED + } else if (handler->iconv_out != NULL) { + do { + toconv = in->end - cur; + written = 32000; + ret = xmlIconvWrapper(handler->iconv_out, &convbuf[0], + &written, cur, &toconv); + if (ret < 0) { + if (written > 0) + ret = -2; + else + return(-1); + } + unused += written; + cur += toconv; + } while (ret == -2); +#endif + } else { + /* could not find a converter */ + return(-1); + } + } + if (in->buf->rawconsumed < unused) + return(-1); + return(in->buf->rawconsumed - unused); + } + return(in->consumed + (in->cur - in->base)); +} + +#if !defined(LIBXML_ICONV_ENABLED) +#ifdef LIBXML_ISO8859X_ENABLED + +/** + * UTF8ToISO8859x: + * @out: a pointer to an array of bytes to store the result + * @outlen: the length of @out + * @in: a pointer to an array of UTF-8 chars + * @inlen: the length of @in + * @xlattable: the 2-level transcoding table + * + * Take a block of UTF-8 chars in and try to convert it to an ISO 8859-* + * block of chars out. + * + * Returns 0 if success, -2 if the transcoding fails, or -1 otherwise + * The value of @inlen after return is the number of octets consumed + * as the return value is positive, else unpredictable. + * The value of @outlen after return is the number of ocetes consumed. + */ +static int +UTF8ToISO8859x(unsigned char* out, int *outlen, + const unsigned char* in, int *inlen, + unsigned char const *xlattable) { + const unsigned char* outstart = out; + const unsigned char* inend; + const unsigned char* instart = in; + const unsigned char* processed = in; + + if ((out == NULL) || (outlen == NULL) || (inlen == NULL) || + (xlattable == NULL)) + return(-1); + if (in == NULL) { + /* + * initialization nothing to do + */ + *outlen = 0; + *inlen = 0; + return(0); + } + inend = in + (*inlen); + while (in < inend) { + unsigned char d = *in++; + if (d < 0x80) { + *out++ = d; + } else if (d < 0xC0) { + /* trailing byte in leading position */ + *outlen = out - outstart; + *inlen = processed - instart; + return(-2); + } else if (d < 0xE0) { + unsigned char c; + if (!(in < inend)) { + /* trailing byte not in input buffer */ + *outlen = out - outstart; + *inlen = processed - instart; + return(-3); + } + c = *in++; + if ((c & 0xC0) != 0x80) { + /* not a trailing byte */ + *outlen = out - outstart; + *inlen = processed - instart; + return(-2); + } + c = c & 0x3F; + d = d & 0x1F; + d = xlattable [48 + c + xlattable [d] * 64]; + if (d == 0) { + /* not in character set */ + *outlen = out - outstart; + *inlen = processed - instart; + return(-2); + } + *out++ = d; + } else if (d < 0xF0) { + unsigned char c1; + unsigned char c2; + if (!(in < inend - 1)) { + /* trailing bytes not in input buffer */ + *outlen = out - outstart; + *inlen = processed - instart; + return(-3); + } + c1 = *in++; + if ((c1 & 0xC0) != 0x80) { + /* not a trailing byte (c1) */ + *outlen = out - outstart; + *inlen = processed - instart; + return(-2); + } + c2 = *in++; + if ((c2 & 0xC0) != 0x80) { + /* not a trailing byte (c2) */ + *outlen = out - outstart; + *inlen = processed - instart; + return(-2); + } + c1 = c1 & 0x3F; + c2 = c2 & 0x3F; + d = d & 0x0F; + d = xlattable [48 + c2 + xlattable [48 + c1 + + xlattable [32 + d] * 64] * 64]; + if (d == 0) { + /* not in character set */ + *outlen = out - outstart; + *inlen = processed - instart; + return(-2); + } + *out++ = d; + } else { + /* cannot transcode >= U+010000 */ + *outlen = out - outstart; + *inlen = processed - instart; + return(-2); + } + processed = in; + } + *outlen = out - outstart; + *inlen = processed - instart; + return(*outlen); +} + +/** + * ISO8859xToUTF8 + * @out: a pointer to an array of bytes to store the result + * @outlen: the length of @out + * @in: a pointer to an array of ISO Latin 1 chars + * @inlen: the length of @in + * + * Take a block of ISO 8859-* chars in and try to convert it to an UTF-8 + * block of chars out. + * Returns 0 if success, or -1 otherwise + * The value of @inlen after return is the number of octets consumed + * The value of @outlen after return is the number of ocetes produced. + */ +static int +ISO8859xToUTF8(unsigned char* out, int *outlen, + const unsigned char* in, int *inlen, + unsigned short const *unicodetable) { + unsigned char* outstart = out; + unsigned char* outend; + const unsigned char* instart = in; + const unsigned char* inend; + const unsigned char* instop; + unsigned int c; + + if ((out == NULL) || (outlen == NULL) || (inlen == NULL) || + (in == NULL) || (unicodetable == NULL)) + return(-1); + outend = out + *outlen; + inend = in + *inlen; + instop = inend; + + while ((in < inend) && (out < outend - 2)) { + if (*in >= 0x80) { + c = unicodetable [*in - 0x80]; + if (c == 0) { + /* undefined code point */ + *outlen = out - outstart; + *inlen = in - instart; + return (-1); + } + if (c < 0x800) { + *out++ = ((c >> 6) & 0x1F) | 0xC0; + *out++ = (c & 0x3F) | 0x80; + } else { + *out++ = ((c >> 12) & 0x0F) | 0xE0; + *out++ = ((c >> 6) & 0x3F) | 0x80; + *out++ = (c & 0x3F) | 0x80; + } + ++in; + } + if (instop - in > outend - out) instop = in + (outend - out); + while ((*in < 0x80) && (in < instop)) { + *out++ = *in++; + } + } + if ((in < inend) && (out < outend) && (*in < 0x80)) { + *out++ = *in++; + } + if ((in < inend) && (out < outend) && (*in < 0x80)) { + *out++ = *in++; + } + *outlen = out - outstart; + *inlen = in - instart; + return (*outlen); +} + + +/************************************************************************ + * Lookup tables for ISO-8859-2..ISO-8859-16 transcoding * + ************************************************************************/ + +static unsigned short const 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, + 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, + 0x00a0, 0x0104, 0x02d8, 0x0141, 0x00a4, 0x013d, 0x015a, 0x00a7, + 0x00a8, 0x0160, 0x015e, 0x0164, 0x0179, 0x00ad, 0x017d, 0x017b, + 0x00b0, 0x0105, 0x02db, 0x0142, 0x00b4, 0x013e, 0x015b, 0x02c7, + 0x00b8, 0x0161, 0x015f, 0x0165, 0x017a, 0x02dd, 0x017e, 0x017c, + 0x0154, 0x00c1, 0x00c2, 0x0102, 0x00c4, 0x0139, 0x0106, 0x00c7, + 0x010c, 0x00c9, 0x0118, 0x00cb, 0x011a, 0x00cd, 0x00ce, 0x010e, + 0x0110, 0x0143, 0x0147, 0x00d3, 0x00d4, 0x0150, 0x00d6, 0x00d7, + 0x0158, 0x016e, 0x00da, 0x0170, 0x00dc, 0x00dd, 0x0162, 0x00df, + 0x0155, 0x00e1, 0x00e2, 0x0103, 0x00e4, 0x013a, 0x0107, 0x00e7, + 0x010d, 0x00e9, 0x0119, 0x00eb, 0x011b, 0x00ed, 0x00ee, 0x010f, + 0x0111, 0x0144, 0x0148, 0x00f3, 0x00f4, 0x0151, 0x00f6, 0x00f7, + 0x0159, 0x016f, 0x00fa, 0x0171, 0x00fc, 0x00fd, 0x0163, 0x02d9, +}; + +static unsigned char const xmltranscodetable_ISO8859_2 [48 + 6 * 64] = { + "\x00\x00\x01\x05\x02\x04\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" + "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" + "\xa0\x00\x00\x00\xa4\x00\x00\xa7\xa8\x00\x00\x00\x00\xad\x00\x00" + "\xb0\x00\x00\x00\xb4\x00\x00\x00\xb8\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\xc3\xe3\xa1\xb1\xc6\xe6\x00\x00\x00\x00\xc8\xe8\xcf\xef" + "\xd0\xf0\x00\x00\x00\x00\x00\x00\xca\xea\xcc\xec\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc5\xe5\x00\x00\xa5\xb5\x00" + "\x00\x00\x00\x00\x00\x00\x00\xb7\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\xa2\xff\x00\xb2\x00\xbd\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\xa3\xb3\xd1\xf1\x00\x00\xd2\xf2\x00\x00\x00\x00\x00\x00\x00" + "\xd5\xf5\x00\x00\xc0\xe0\x00\x00\xd8\xf8\xa6\xb6\x00\x00\xaa\xba" + "\xa9\xb9\xde\xfe\xab\xbb\x00\x00\x00\x00\x00\x00\x00\x00\xd9\xf9" + "\xdb\xfb\x00\x00\x00\x00\x00\x00\x00\xac\xbc\xaf\xbf\xae\xbe\x00" + "\x00\xc1\xc2\x00\xc4\x00\x00\xc7\x00\xc9\x00\xcb\x00\xcd\xce\x00" + "\x00\x00\x00\xd3\xd4\x00\xd6\xd7\x00\x00\xda\x00\xdc\xdd\x00\xdf" + "\x00\xe1\xe2\x00\xe4\x00\x00\xe7\x00\xe9\x00\xeb\x00\xed\xee\x00" + "\x00\x00\x00\xf3\xf4\x00\xf6\xf7\x00\x00\xfa\x00\xfc\xfd\x00\x00" +}; + +static unsigned short const 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, + 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, + 0x00a0, 0x0126, 0x02d8, 0x00a3, 0x00a4, 0x0000, 0x0124, 0x00a7, + 0x00a8, 0x0130, 0x015e, 0x011e, 0x0134, 0x00ad, 0x0000, 0x017b, + 0x00b0, 0x0127, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x0125, 0x00b7, + 0x00b8, 0x0131, 0x015f, 0x011f, 0x0135, 0x00bd, 0x0000, 0x017c, + 0x00c0, 0x00c1, 0x00c2, 0x0000, 0x00c4, 0x010a, 0x0108, 0x00c7, + 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf, + 0x0000, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x0120, 0x00d6, 0x00d7, + 0x011c, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x016c, 0x015c, 0x00df, + 0x00e0, 0x00e1, 0x00e2, 0x0000, 0x00e4, 0x010b, 0x0109, 0x00e7, + 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, + 0x0000, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x0121, 0x00f6, 0x00f7, + 0x011d, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x016d, 0x015d, 0x02d9, +}; + +static unsigned char const xmltranscodetable_ISO8859_3 [48 + 7 * 64] = { + "\x04\x00\x01\x06\x02\x05\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" + "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" + "\xa0\x00\x00\xa3\xa4\x00\x00\xa7\xa8\x00\x00\x00\x00\xad\x00\x00" + "\xb0\x00\xb2\xb3\xb4\xb5\x00\xb7\xb8\x00\x00\x00\x00\xbd\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\xc6\xe6\xc5\xe5\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd8\xf8\xab\xbb" + "\xd5\xf5\x00\x00\xa6\xb6\xa1\xb1\x00\x00\x00\x00\x00\x00\x00\x00" + "\xa9\xb9\x00\x00\xac\xbc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\xa2\xff\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xde\xfe\xaa\xba" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xdd\xfd\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xaf\xbf\x00\x00\x00" + "\xc0\xc1\xc2\x00\xc4\x00\x00\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + "\x00\xd1\xd2\xd3\xd4\x00\xd6\xd7\x00\xd9\xda\xdb\xdc\x00\x00\xdf" + "\xe0\xe1\xe2\x00\xe4\x00\x00\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef" + "\x00\xf1\xf2\xf3\xf4\x00\xf6\xf7\x00\xf9\xfa\xfb\xfc\x00\x00\x00" +}; + +static unsigned short const 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, + 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, + 0x00a0, 0x0104, 0x0138, 0x0156, 0x00a4, 0x0128, 0x013b, 0x00a7, + 0x00a8, 0x0160, 0x0112, 0x0122, 0x0166, 0x00ad, 0x017d, 0x00af, + 0x00b0, 0x0105, 0x02db, 0x0157, 0x00b4, 0x0129, 0x013c, 0x02c7, + 0x00b8, 0x0161, 0x0113, 0x0123, 0x0167, 0x014a, 0x017e, 0x014b, + 0x0100, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x012e, + 0x010c, 0x00c9, 0x0118, 0x00cb, 0x0116, 0x00cd, 0x00ce, 0x012a, + 0x0110, 0x0145, 0x014c, 0x0136, 0x00d4, 0x00d5, 0x00d6, 0x00d7, + 0x00d8, 0x0172, 0x00da, 0x00db, 0x00dc, 0x0168, 0x016a, 0x00df, + 0x0101, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x012f, + 0x010d, 0x00e9, 0x0119, 0x00eb, 0x0117, 0x00ed, 0x00ee, 0x012b, + 0x0111, 0x0146, 0x014d, 0x0137, 0x00f4, 0x00f5, 0x00f6, 0x00f7, + 0x00f8, 0x0173, 0x00fa, 0x00fb, 0x00fc, 0x0169, 0x016b, 0x02d9, +}; + +static unsigned char const xmltranscodetable_ISO8859_4 [48 + 6 * 64] = { + "\x00\x00\x01\x05\x02\x03\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" + "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" + "\xa0\x00\x00\x00\xa4\x00\x00\xa7\xa8\x00\x00\x00\x00\xad\x00\xaf" + "\xb0\x00\x00\x00\xb4\x00\x00\x00\xb8\x00\x00\x00\x00\x00\x00\x00" + "\xc0\xe0\x00\x00\xa1\xb1\x00\x00\x00\x00\x00\x00\xc8\xe8\x00\x00" + "\xd0\xf0\xaa\xba\x00\x00\xcc\xec\xca\xea\x00\x00\x00\x00\x00\x00" + "\x00\x00\xab\xbb\x00\x00\x00\x00\xa5\xb5\xcf\xef\x00\x00\xc7\xe7" + "\x00\x00\x00\x00\x00\x00\xd3\xf3\xa2\x00\x00\xa6\xb6\x00\x00\x00" + "\x00\x00\x00\x00\x00\xd1\xf1\x00\x00\x00\xbd\xbf\xd2\xf2\x00\x00" + "\x00\x00\x00\x00\x00\x00\xa3\xb3\x00\x00\x00\x00\x00\x00\x00\x00" + "\xa9\xb9\x00\x00\x00\x00\xac\xbc\xdd\xfd\xde\xfe\x00\x00\x00\x00" + "\x00\x00\xd9\xf9\x00\x00\x00\x00\x00\x00\x00\x00\x00\xae\xbe\x00" + "\x00\x00\x00\x00\x00\x00\x00\xb7\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\x00\xb2\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\xc1\xc2\xc3\xc4\xc5\xc6\x00\x00\xc9\x00\xcb\x00\xcd\xce\x00" + "\x00\x00\x00\x00\xd4\xd5\xd6\xd7\xd8\x00\xda\xdb\xdc\x00\x00\xdf" + "\x00\xe1\xe2\xe3\xe4\xe5\xe6\x00\x00\xe9\x00\xeb\x00\xed\xee\x00" + "\x00\x00\x00\x00\xf4\xf5\xf6\xf7\xf8\x00\xfa\xfb\xfc\x00\x00\x00" +}; + +static unsigned short const 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, + 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, + 0x00a0, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407, + 0x0408, 0x0409, 0x040a, 0x040b, 0x040c, 0x00ad, 0x040e, 0x040f, + 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, + 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f, + 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, + 0x0428, 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, + 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f, + 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, + 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f, + 0x2116, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457, + 0x0458, 0x0459, 0x045a, 0x045b, 0x045c, 0x00a7, 0x045e, 0x045f, +}; + +static unsigned char const xmltranscodetable_ISO8859_5 [48 + 6 * 64] = { + "\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x02\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" + "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" + "\xa0\x00\x00\x00\x00\x00\x00\xfd\x00\x00\x00\x00\x00\xad\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\x00\xae\xaf" + "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" + "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef" + "\x00\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\x00\xfe\xff" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +}; + +static unsigned short const 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, + 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, + 0x00a0, 0x0000, 0x0000, 0x0000, 0x00a4, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x060c, 0x00ad, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x061b, 0x0000, 0x0000, 0x0000, 0x061f, + 0x0000, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627, + 0x0628, 0x0629, 0x062a, 0x062b, 0x062c, 0x062d, 0x062e, 0x062f, + 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x0637, + 0x0638, 0x0639, 0x063a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0640, 0x0641, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, + 0x0648, 0x0649, 0x064a, 0x064b, 0x064c, 0x064d, 0x064e, 0x064f, + 0x0650, 0x0651, 0x0652, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +}; + +static unsigned char const xmltranscodetable_ISO8859_6 [48 + 5 * 64] = { + "\x02\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x03\x04\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" + "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" + "\xa0\x00\x00\x00\xa4\x00\x00\x00\x00\x00\x00\x00\x00\xad\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xac\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbb\x00\x00\x00\xbf" + "\x00\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\x00\x00\x00\x00\x00" + "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef" + "\xf0\xf1\xf2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +}; + +static unsigned short const 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, + 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, + 0x00a0, 0x2018, 0x2019, 0x00a3, 0x0000, 0x0000, 0x00a6, 0x00a7, + 0x00a8, 0x00a9, 0x0000, 0x00ab, 0x00ac, 0x00ad, 0x0000, 0x2015, + 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x0384, 0x0385, 0x0386, 0x00b7, + 0x0388, 0x0389, 0x038a, 0x00bb, 0x038c, 0x00bd, 0x038e, 0x038f, + 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, + 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f, + 0x03a0, 0x03a1, 0x0000, 0x03a3, 0x03a4, 0x03a5, 0x03a6, 0x03a7, + 0x03a8, 0x03a9, 0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03ae, 0x03af, + 0x03b0, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7, + 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf, + 0x03c0, 0x03c1, 0x03c2, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7, + 0x03c8, 0x03c9, 0x03ca, 0x03cb, 0x03cc, 0x03cd, 0x03ce, 0x0000, +}; + +static unsigned char const xmltranscodetable_ISO8859_7 [48 + 7 * 64] = { + "\x04\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x06" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" + "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" + "\xa0\x00\x00\xa3\x00\x00\xa6\xa7\xa8\xa9\x00\xab\xac\xad\x00\x00" + "\xb0\xb1\xb2\xb3\x00\x00\x00\xb7\x00\x00\x00\xbb\x00\xbd\x00\x00" + "\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\xaf\x00\x00\xa1\xa2\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\xb4\xb5\xb6\x00\xb8\xb9\xba\x00\xbc\x00\xbe\xbf" + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + "\xd0\xd1\x00\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" + "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef" + "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +}; + +static unsigned short const 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, + 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, + 0x00a0, 0x0000, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, + 0x00a8, 0x00a9, 0x00d7, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af, + 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7, + 0x00b8, 0x00b9, 0x00f7, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2017, + 0x05d0, 0x05d1, 0x05d2, 0x05d3, 0x05d4, 0x05d5, 0x05d6, 0x05d7, + 0x05d8, 0x05d9, 0x05da, 0x05db, 0x05dc, 0x05dd, 0x05de, 0x05df, + 0x05e0, 0x05e1, 0x05e2, 0x05e3, 0x05e4, 0x05e5, 0x05e6, 0x05e7, + 0x05e8, 0x05e9, 0x05ea, 0x0000, 0x0000, 0x200e, 0x200f, 0x0000, +}; + +static unsigned char const xmltranscodetable_ISO8859_8 [48 + 7 * 64] = { + "\x02\x00\x01\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" + "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" + "\xa0\x00\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\x00\xab\xac\xad\xae\xaf" + "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\x00\xbb\xbc\xbd\xbe\x00" + "\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\xaa\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\xba\x00\x00\x00\x00\x00\x00\x00\x00" + "\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfd\xfe" + "\x00\x00\x00\x00\x00\x00\x00\xdf\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef" + "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +}; + +static unsigned short const 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, + 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, + 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, + 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af, + 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7, + 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf, + 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, + 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf, + 0x011e, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7, + 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x0130, 0x015e, 0x00df, + 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, + 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, + 0x011f, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, + 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x0131, 0x015f, 0x00ff, +}; + +static unsigned char const xmltranscodetable_ISO8859_9 [48 + 5 * 64] = { + "\x00\x00\x01\x02\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" + "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" + "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf" + "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + "\x00\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\x00\x00\xdf" + "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef" + "\x00\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\x00\x00\xff" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd0\xf0" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\xdd\xfd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xde\xfe" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +}; + +static unsigned short const 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, + 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, + 0x00a0, 0x0104, 0x0112, 0x0122, 0x012a, 0x0128, 0x0136, 0x00a7, + 0x013b, 0x0110, 0x0160, 0x0166, 0x017d, 0x00ad, 0x016a, 0x014a, + 0x00b0, 0x0105, 0x0113, 0x0123, 0x012b, 0x0129, 0x0137, 0x00b7, + 0x013c, 0x0111, 0x0161, 0x0167, 0x017e, 0x2015, 0x016b, 0x014b, + 0x0100, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x012e, + 0x010c, 0x00c9, 0x0118, 0x00cb, 0x0116, 0x00cd, 0x00ce, 0x00cf, + 0x00d0, 0x0145, 0x014c, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x0168, + 0x00d8, 0x0172, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df, + 0x0101, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x012f, + 0x010d, 0x00e9, 0x0119, 0x00eb, 0x0117, 0x00ed, 0x00ee, 0x00ef, + 0x00f0, 0x0146, 0x014d, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x0169, + 0x00f8, 0x0173, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x0138, +}; + +static unsigned char const xmltranscodetable_ISO8859_10 [48 + 7 * 64] = { + "\x00\x00\x01\x06\x02\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" + "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" + "\xa0\x00\x00\x00\x00\x00\x00\xa7\x00\x00\x00\x00\x00\xad\x00\x00" + "\xb0\x00\x00\x00\x00\x00\x00\xb7\x00\x00\x00\x00\x00\x00\x00\x00" + "\xc0\xe0\x00\x00\xa1\xb1\x00\x00\x00\x00\x00\x00\xc8\xe8\x00\x00" + "\xa9\xb9\xa2\xb2\x00\x00\xcc\xec\xca\xea\x00\x00\x00\x00\x00\x00" + "\x00\x00\xa3\xb3\x00\x00\x00\x00\xa5\xb5\xa4\xb4\x00\x00\xc7\xe7" + "\x00\x00\x00\x00\x00\x00\xa6\xb6\xff\x00\x00\xa8\xb8\x00\x00\x00" + "\x00\x00\x00\x00\x00\xd1\xf1\x00\x00\x00\xaf\xbf\xd2\xf2\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\xaa\xba\x00\x00\x00\x00\xab\xbb\xd7\xf7\xae\xbe\x00\x00\x00\x00" + "\x00\x00\xd9\xf9\x00\x00\x00\x00\x00\x00\x00\x00\x00\xac\xbc\x00" + "\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\xbd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\xc1\xc2\xc3\xc4\xc5\xc6\x00\x00\xc9\x00\xcb\x00\xcd\xce\xcf" + "\xd0\x00\x00\xd3\xd4\xd5\xd6\x00\xd8\x00\xda\xdb\xdc\xdd\xde\xdf" + "\x00\xe1\xe2\xe3\xe4\xe5\xe6\x00\x00\xe9\x00\xeb\x00\xed\xee\xef" + "\xf0\x00\x00\xf3\xf4\xf5\xf6\x00\xf8\x00\xfa\xfb\xfc\xfd\xfe\x00" +}; + +static unsigned short const 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, + 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, + 0x00a0, 0x0e01, 0x0e02, 0x0e03, 0x0e04, 0x0e05, 0x0e06, 0x0e07, + 0x0e08, 0x0e09, 0x0e0a, 0x0e0b, 0x0e0c, 0x0e0d, 0x0e0e, 0x0e0f, + 0x0e10, 0x0e11, 0x0e12, 0x0e13, 0x0e14, 0x0e15, 0x0e16, 0x0e17, + 0x0e18, 0x0e19, 0x0e1a, 0x0e1b, 0x0e1c, 0x0e1d, 0x0e1e, 0x0e1f, + 0x0e20, 0x0e21, 0x0e22, 0x0e23, 0x0e24, 0x0e25, 0x0e26, 0x0e27, + 0x0e28, 0x0e29, 0x0e2a, 0x0e2b, 0x0e2c, 0x0e2d, 0x0e2e, 0x0e2f, + 0x0e30, 0x0e31, 0x0e32, 0x0e33, 0x0e34, 0x0e35, 0x0e36, 0x0e37, + 0x0e38, 0x0e39, 0x0e3a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0e3f, + 0x0e40, 0x0e41, 0x0e42, 0x0e43, 0x0e44, 0x0e45, 0x0e46, 0x0e47, + 0x0e48, 0x0e49, 0x0e4a, 0x0e4b, 0x0e4c, 0x0e4d, 0x0e4e, 0x0e4f, + 0x0e50, 0x0e51, 0x0e52, 0x0e53, 0x0e54, 0x0e55, 0x0e56, 0x0e57, + 0x0e58, 0x0e59, 0x0e5a, 0x0e5b, 0x0000, 0x0000, 0x0000, 0x0000, +}; + +static unsigned char const xmltranscodetable_ISO8859_11 [48 + 6 * 64] = { + "\x04\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" + "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" + "\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x03\x05\x00\x00\x00\x00\x00\x00" + "\x00\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf" + "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\x00\x00\x00\x00\xdf" + "\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef" + "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +}; + +static unsigned short const 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, + 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, + 0x00a0, 0x201d, 0x00a2, 0x00a3, 0x00a4, 0x201e, 0x00a6, 0x00a7, + 0x00d8, 0x00a9, 0x0156, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00c6, + 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x201c, 0x00b5, 0x00b6, 0x00b7, + 0x00f8, 0x00b9, 0x0157, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00e6, + 0x0104, 0x012e, 0x0100, 0x0106, 0x00c4, 0x00c5, 0x0118, 0x0112, + 0x010c, 0x00c9, 0x0179, 0x0116, 0x0122, 0x0136, 0x012a, 0x013b, + 0x0160, 0x0143, 0x0145, 0x00d3, 0x014c, 0x00d5, 0x00d6, 0x00d7, + 0x0172, 0x0141, 0x015a, 0x016a, 0x00dc, 0x017b, 0x017d, 0x00df, + 0x0105, 0x012f, 0x0101, 0x0107, 0x00e4, 0x00e5, 0x0119, 0x0113, + 0x010d, 0x00e9, 0x017a, 0x0117, 0x0123, 0x0137, 0x012b, 0x013c, + 0x0161, 0x0144, 0x0146, 0x00f3, 0x014d, 0x00f5, 0x00f6, 0x00f7, + 0x0173, 0x0142, 0x015b, 0x016b, 0x00fc, 0x017c, 0x017e, 0x2019, +}; + +static unsigned char const xmltranscodetable_ISO8859_13 [48 + 7 * 64] = { + "\x00\x00\x01\x04\x06\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" + "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" + "\xa0\x00\xa2\xa3\xa4\x00\xa6\xa7\x00\xa9\x00\xab\xac\xad\xae\x00" + "\xb0\xb1\xb2\xb3\x00\xb5\xb6\xb7\x00\xb9\x00\xbb\xbc\xbd\xbe\x00" + "\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\x00\x00\xb4\xa1\xa5\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\xc4\xc5\xaf\x00\x00\xc9\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\xd3\x00\xd5\xd6\xd7\xa8\x00\x00\x00\xdc\x00\x00\xdf" + "\x00\x00\x00\x00\xe4\xe5\xbf\x00\x00\xe9\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\xf3\x00\xf5\xf6\xf7\xb8\x00\x00\x00\xfc\x00\x00\x00" + "\x00\xd9\xf9\xd1\xf1\xd2\xf2\x00\x00\x00\x00\x00\xd4\xf4\x00\x00" + "\x00\x00\x00\x00\x00\x00\xaa\xba\x00\x00\xda\xfa\x00\x00\x00\x00" + "\xd0\xf0\x00\x00\x00\x00\x00\x00\x00\x00\xdb\xfb\x00\x00\x00\x00" + "\x00\x00\xd8\xf8\x00\x00\x00\x00\x00\xca\xea\xdd\xfd\xde\xfe\x00" + "\xc2\xe2\x00\x00\xc0\xe0\xc3\xe3\x00\x00\x00\x00\xc8\xe8\x00\x00" + "\x00\x00\xc7\xe7\x00\x00\xcb\xeb\xc6\xe6\x00\x00\x00\x00\x00\x00" + "\x00\x00\xcc\xec\x00\x00\x00\x00\x00\x00\xce\xee\x00\x00\xc1\xe1" + "\x00\x00\x00\x00\x00\x00\xcd\xed\x00\x00\x00\xcf\xef\x00\x00\x00" +}; + +static unsigned short const 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, + 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, + 0x00a0, 0x1e02, 0x1e03, 0x00a3, 0x010a, 0x010b, 0x1e0a, 0x00a7, + 0x1e80, 0x00a9, 0x1e82, 0x1e0b, 0x1ef2, 0x00ad, 0x00ae, 0x0178, + 0x1e1e, 0x1e1f, 0x0120, 0x0121, 0x1e40, 0x1e41, 0x00b6, 0x1e56, + 0x1e81, 0x1e57, 0x1e83, 0x1e60, 0x1ef3, 0x1e84, 0x1e85, 0x1e61, + 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, + 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf, + 0x0174, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x1e6a, + 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x0176, 0x00df, + 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, + 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, + 0x0175, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x1e6b, + 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x0177, 0x00ff, +}; + +static unsigned char const xmltranscodetable_ISO8859_14 [48 + 10 * 64] = { + "\x00\x00\x01\x09\x04\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" + "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" + "\xa0\x00\x00\xa3\x00\x00\x00\xa7\x00\xa9\x00\x00\x00\xad\xae\x00" + "\x00\x00\x00\x00\x00\x00\xb6\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x03\x08\x05\x06\x00\x00\x00\x00" + "\x00\x00\xa1\xa2\x00\x00\x00\x00\x00\x00\xa6\xab\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb0\xb1" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\xa5\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\xb2\xb3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\xa8\xb8\xaa\xba\xbd\xbe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\xac\xbc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\xd0\xf0\xde\xfe\xaf\x00\x00\x00\x00\x00\x00\x00" + "\xb4\xb5\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\xb7\xb9\x00\x00\x00\x00\x00\x00\x00\x00" + "\xbb\xbf\x00\x00\x00\x00\x00\x00\x00\x00\xd7\xf7\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + "\x00\xd1\xd2\xd3\xd4\xd5\xd6\x00\xd8\xd9\xda\xdb\xdc\xdd\x00\xdf" + "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef" + "\x00\xf1\xf2\xf3\xf4\xf5\xf6\x00\xf8\xf9\xfa\xfb\xfc\xfd\x00\xff" +}; + +static unsigned short const 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, + 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, + 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x20ac, 0x00a5, 0x0160, 0x00a7, + 0x0161, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af, + 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x017d, 0x00b5, 0x00b6, 0x00b7, + 0x017e, 0x00b9, 0x00ba, 0x00bb, 0x0152, 0x0153, 0x0178, 0x00bf, + 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, + 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf, + 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7, + 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df, + 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, + 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, + 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, + 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff, +}; + +static unsigned char const xmltranscodetable_ISO8859_15 [48 + 6 * 64] = { + "\x00\x00\x01\x05\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" + "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" + "\xa0\xa1\xa2\xa3\x00\xa5\x00\xa7\x00\xa9\xaa\xab\xac\xad\xae\xaf" + "\xb0\xb1\xb2\xb3\x00\xb5\xb6\xb7\x00\xb9\xba\xbb\x00\x00\x00\xbf" + "\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\xbc\xbd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\xa6\xa8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\xbe\x00\x00\x00\x00\xb4\xb8\x00" + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" + "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef" + "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff" +}; + +static unsigned short const 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, + 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, + 0x00a0, 0x0104, 0x0105, 0x0141, 0x20ac, 0x201e, 0x0160, 0x00a7, + 0x0161, 0x00a9, 0x0218, 0x00ab, 0x0179, 0x00ad, 0x017a, 0x017b, + 0x00b0, 0x00b1, 0x010c, 0x0142, 0x017d, 0x201d, 0x00b6, 0x00b7, + 0x017e, 0x010d, 0x0219, 0x00bb, 0x0152, 0x0153, 0x0178, 0x017c, + 0x00c0, 0x00c1, 0x00c2, 0x0102, 0x00c4, 0x0106, 0x00c6, 0x00c7, + 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf, + 0x0110, 0x0143, 0x00d2, 0x00d3, 0x00d4, 0x0150, 0x00d6, 0x015a, + 0x0170, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x0118, 0x021a, 0x00df, + 0x00e0, 0x00e1, 0x00e2, 0x0103, 0x00e4, 0x0107, 0x00e6, 0x00e7, + 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, + 0x0111, 0x0144, 0x00f2, 0x00f3, 0x00f4, 0x0151, 0x00f6, 0x015b, + 0x0171, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x0119, 0x021b, 0x00ff, +}; + +static unsigned char const xmltranscodetable_ISO8859_16 [48 + 9 * 64] = { + "\x00\x00\x01\x08\x02\x03\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" + "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" + "\xa0\x00\x00\x00\x00\x00\x00\xa7\x00\xa9\x00\xab\x00\xad\x00\x00" + "\xb0\xb1\x00\x00\x00\x00\xb6\xb7\x00\x00\x00\xbb\x00\x00\x00\x00" + "\x00\x00\xc3\xe3\xa1\xa2\xc5\xe5\x00\x00\x00\x00\xb2\xb9\x00\x00" + "\xd0\xf0\x00\x00\x00\x00\x00\x00\xdd\xfd\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\xa3\xb3\xd1\xf1\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\xd5\xf5\xbc\xbd\x00\x00\x00\x00\x00\x00\xd7\xf7\x00\x00\x00\x00" + "\xa6\xa8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\xd8\xf8\x00\x00\x00\x00\x00\x00\xbe\xac\xae\xaf\xbf\xb4\xb8\x00" + "\x06\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb5\xa5\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\xaa\xba\xde\xfe\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\xc0\xc1\xc2\x00\xc4\x00\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + "\x00\x00\xd2\xd3\xd4\x00\xd6\x00\x00\xd9\xda\xdb\xdc\x00\x00\xdf" + "\xe0\xe1\xe2\x00\xe4\x00\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef" + "\x00\x00\xf2\xf3\xf4\x00\xf6\x00\x00\xf9\xfa\xfb\xfc\x00\x00\xff" +}; + + +/* + * auto-generated functions for ISO-8859-2 .. ISO-8859-16 + */ + +static int ISO8859_2ToUTF8 (unsigned char* out, int *outlen, + const unsigned char* in, int *inlen) { + return ISO8859xToUTF8 (out, outlen, in, inlen, xmlunicodetable_ISO8859_2); +} +static int UTF8ToISO8859_2 (unsigned char* out, int *outlen, + const unsigned char* in, int *inlen) { + return UTF8ToISO8859x (out, outlen, in, inlen, xmltranscodetable_ISO8859_2); +} + +static int ISO8859_3ToUTF8 (unsigned char* out, int *outlen, + const unsigned char* in, int *inlen) { + return ISO8859xToUTF8 (out, outlen, in, inlen, xmlunicodetable_ISO8859_3); +} +static int UTF8ToISO8859_3 (unsigned char* out, int *outlen, + const unsigned char* in, int *inlen) { + return UTF8ToISO8859x (out, outlen, in, inlen, xmltranscodetable_ISO8859_3); +} + +static int ISO8859_4ToUTF8 (unsigned char* out, int *outlen, + const unsigned char* in, int *inlen) { + return ISO8859xToUTF8 (out, outlen, in, inlen, xmlunicodetable_ISO8859_4); +} +static int UTF8ToISO8859_4 (unsigned char* out, int *outlen, + const unsigned char* in, int *inlen) { + return UTF8ToISO8859x (out, outlen, in, inlen, xmltranscodetable_ISO8859_4); +} + +static int ISO8859_5ToUTF8 (unsigned char* out, int *outlen, + const unsigned char* in, int *inlen) { + return ISO8859xToUTF8 (out, outlen, in, inlen, xmlunicodetable_ISO8859_5); +} +static int UTF8ToISO8859_5 (unsigned char* out, int *outlen, + const unsigned char* in, int *inlen) { + return UTF8ToISO8859x (out, outlen, in, inlen, xmltranscodetable_ISO8859_5); +} + +static int ISO8859_6ToUTF8 (unsigned char* out, int *outlen, + const unsigned char* in, int *inlen) { + return ISO8859xToUTF8 (out, outlen, in, inlen, xmlunicodetable_ISO8859_6); +} +static int UTF8ToISO8859_6 (unsigned char* out, int *outlen, + const unsigned char* in, int *inlen) { + return UTF8ToISO8859x (out, outlen, in, inlen, xmltranscodetable_ISO8859_6); +} + +static int ISO8859_7ToUTF8 (unsigned char* out, int *outlen, + const unsigned char* in, int *inlen) { + return ISO8859xToUTF8 (out, outlen, in, inlen, xmlunicodetable_ISO8859_7); +} +static int UTF8ToISO8859_7 (unsigned char* out, int *outlen, + const unsigned char* in, int *inlen) { + return UTF8ToISO8859x (out, outlen, in, inlen, xmltranscodetable_ISO8859_7); +} + +static int ISO8859_8ToUTF8 (unsigned char* out, int *outlen, + const unsigned char* in, int *inlen) { + return ISO8859xToUTF8 (out, outlen, in, inlen, xmlunicodetable_ISO8859_8); +} +static int UTF8ToISO8859_8 (unsigned char* out, int *outlen, + const unsigned char* in, int *inlen) { + return UTF8ToISO8859x (out, outlen, in, inlen, xmltranscodetable_ISO8859_8); +} + +static int ISO8859_9ToUTF8 (unsigned char* out, int *outlen, + const unsigned char* in, int *inlen) { + return ISO8859xToUTF8 (out, outlen, in, inlen, xmlunicodetable_ISO8859_9); +} +static int UTF8ToISO8859_9 (unsigned char* out, int *outlen, + const unsigned char* in, int *inlen) { + return UTF8ToISO8859x (out, outlen, in, inlen, xmltranscodetable_ISO8859_9); +} + +static int ISO8859_10ToUTF8 (unsigned char* out, int *outlen, + const unsigned char* in, int *inlen) { + return ISO8859xToUTF8 (out, outlen, in, inlen, xmlunicodetable_ISO8859_10); +} +static int UTF8ToISO8859_10 (unsigned char* out, int *outlen, + const unsigned char* in, int *inlen) { + return UTF8ToISO8859x (out, outlen, in, inlen, xmltranscodetable_ISO8859_10); +} + +static int ISO8859_11ToUTF8 (unsigned char* out, int *outlen, + const unsigned char* in, int *inlen) { + return ISO8859xToUTF8 (out, outlen, in, inlen, xmlunicodetable_ISO8859_11); +} +static int UTF8ToISO8859_11 (unsigned char* out, int *outlen, + const unsigned char* in, int *inlen) { + return UTF8ToISO8859x (out, outlen, in, inlen, xmltranscodetable_ISO8859_11); +} + +static int ISO8859_13ToUTF8 (unsigned char* out, int *outlen, + const unsigned char* in, int *inlen) { + return ISO8859xToUTF8 (out, outlen, in, inlen, xmlunicodetable_ISO8859_13); +} +static int UTF8ToISO8859_13 (unsigned char* out, int *outlen, + const unsigned char* in, int *inlen) { + return UTF8ToISO8859x (out, outlen, in, inlen, xmltranscodetable_ISO8859_13); +} + +static int ISO8859_14ToUTF8 (unsigned char* out, int *outlen, + const unsigned char* in, int *inlen) { + return ISO8859xToUTF8 (out, outlen, in, inlen, xmlunicodetable_ISO8859_14); +} +static int UTF8ToISO8859_14 (unsigned char* out, int *outlen, + const unsigned char* in, int *inlen) { + return UTF8ToISO8859x (out, outlen, in, inlen, xmltranscodetable_ISO8859_14); +} + +static int ISO8859_15ToUTF8 (unsigned char* out, int *outlen, + const unsigned char* in, int *inlen) { + return ISO8859xToUTF8 (out, outlen, in, inlen, xmlunicodetable_ISO8859_15); +} +static int UTF8ToISO8859_15 (unsigned char* out, int *outlen, + const unsigned char* in, int *inlen) { + return UTF8ToISO8859x (out, outlen, in, inlen, xmltranscodetable_ISO8859_15); +} + +static int ISO8859_16ToUTF8 (unsigned char* out, int *outlen, + const unsigned char* in, int *inlen) { + return ISO8859xToUTF8 (out, outlen, in, inlen, xmlunicodetable_ISO8859_16); +} +static int UTF8ToISO8859_16 (unsigned char* out, int *outlen, + const unsigned char* in, int *inlen) { + return UTF8ToISO8859x (out, outlen, in, inlen, xmltranscodetable_ISO8859_16); +} + +static void +xmlRegisterCharEncodingHandlersISO8859x (void) { + xmlNewCharEncodingHandler ("ISO-8859-2", ISO8859_2ToUTF8, UTF8ToISO8859_2); + xmlNewCharEncodingHandler ("ISO-8859-3", ISO8859_3ToUTF8, UTF8ToISO8859_3); + xmlNewCharEncodingHandler ("ISO-8859-4", ISO8859_4ToUTF8, UTF8ToISO8859_4); + xmlNewCharEncodingHandler ("ISO-8859-5", ISO8859_5ToUTF8, UTF8ToISO8859_5); + xmlNewCharEncodingHandler ("ISO-8859-6", ISO8859_6ToUTF8, UTF8ToISO8859_6); + xmlNewCharEncodingHandler ("ISO-8859-7", ISO8859_7ToUTF8, UTF8ToISO8859_7); + xmlNewCharEncodingHandler ("ISO-8859-8", ISO8859_8ToUTF8, UTF8ToISO8859_8); + xmlNewCharEncodingHandler ("ISO-8859-9", ISO8859_9ToUTF8, UTF8ToISO8859_9); + xmlNewCharEncodingHandler ("ISO-8859-10", ISO8859_10ToUTF8, UTF8ToISO8859_10); + xmlNewCharEncodingHandler ("ISO-8859-11", ISO8859_11ToUTF8, UTF8ToISO8859_11); + xmlNewCharEncodingHandler ("ISO-8859-13", ISO8859_13ToUTF8, UTF8ToISO8859_13); + xmlNewCharEncodingHandler ("ISO-8859-14", ISO8859_14ToUTF8, UTF8ToISO8859_14); + xmlNewCharEncodingHandler ("ISO-8859-15", ISO8859_15ToUTF8, UTF8ToISO8859_15); + xmlNewCharEncodingHandler ("ISO-8859-16", ISO8859_16ToUTF8, UTF8ToISO8859_16); +} + +#endif +#endif + +#define bottom_encoding +#include "elfgcchack.h" diff --git a/android/native/libxml2/entities.c b/android/native/libxml2/entities.c new file mode 100644 index 0000000000..6aef49f435 --- /dev/null +++ b/android/native/libxml2/entities.c @@ -0,0 +1,1022 @@ +/* + * entities.c : implementation for the XML entities handling + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + */ + +#define IN_LIBXML +#include "libxml.h" + +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * The XML predefined entities. + */ + +static xmlEntity xmlEntityLt = { + NULL, XML_ENTITY_DECL, BAD_CAST "lt", + NULL, NULL, NULL, NULL, NULL, NULL, + BAD_CAST "<", BAD_CAST "<", 1, + XML_INTERNAL_PREDEFINED_ENTITY, + NULL, NULL, NULL, NULL, 0, 1 +}; +static xmlEntity xmlEntityGt = { + NULL, XML_ENTITY_DECL, BAD_CAST "gt", + NULL, NULL, NULL, NULL, NULL, NULL, + BAD_CAST ">", BAD_CAST ">", 1, + XML_INTERNAL_PREDEFINED_ENTITY, + NULL, NULL, NULL, NULL, 0, 1 +}; +static xmlEntity xmlEntityAmp = { + NULL, XML_ENTITY_DECL, BAD_CAST "amp", + NULL, NULL, NULL, NULL, NULL, NULL, + BAD_CAST "&", BAD_CAST "&", 1, + XML_INTERNAL_PREDEFINED_ENTITY, + NULL, NULL, NULL, NULL, 0, 1 +}; +static xmlEntity xmlEntityQuot = { + NULL, XML_ENTITY_DECL, BAD_CAST "quot", + NULL, NULL, NULL, NULL, NULL, NULL, + BAD_CAST "\"", BAD_CAST "\"", 1, + XML_INTERNAL_PREDEFINED_ENTITY, + NULL, NULL, NULL, NULL, 0, 1 +}; +static xmlEntity xmlEntityApos = { + NULL, XML_ENTITY_DECL, BAD_CAST "apos", + NULL, NULL, NULL, NULL, NULL, NULL, + BAD_CAST "'", BAD_CAST "'", 1, + XML_INTERNAL_PREDEFINED_ENTITY, + NULL, NULL, NULL, NULL, 0, 1 +}; + +/** + * xmlEntitiesErrMemory: + * @extra: extra informations + * + * 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 + * + * Handle an out of memory condition + */ +static void +xmlEntitiesErr(xmlParserErrors code, const char *msg) +{ + __xmlSimpleError(XML_FROM_TREE, code, NULL, msg, NULL); +} + +/* + * xmlFreeEntity : clean-up an entity record. + */ +static void +xmlFreeEntity(xmlEntityPtr entity) +{ + xmlDictPtr dict = NULL; + + if (entity == NULL) + return; + + if (entity->doc != NULL) + dict = entity->doc->dict; + + + if ((entity->children) && (entity->owner == 1) && + (entity == (xmlEntityPtr) entity->children->parent)) + xmlFreeNodeList(entity->children); + if (dict != NULL) { + if ((entity->name != NULL) && (!xmlDictOwns(dict, entity->name))) + xmlFree((char *) entity->name); + if ((entity->ExternalID != NULL) && + (!xmlDictOwns(dict, entity->ExternalID))) + xmlFree((char *) entity->ExternalID); + if ((entity->SystemID != NULL) && + (!xmlDictOwns(dict, entity->SystemID))) + xmlFree((char *) entity->SystemID); + if ((entity->URI != NULL) && (!xmlDictOwns(dict, entity->URI))) + xmlFree((char *) entity->URI); + if ((entity->content != NULL) + && (!xmlDictOwns(dict, entity->content))) + xmlFree((char *) entity->content); + if ((entity->orig != NULL) && (!xmlDictOwns(dict, entity->orig))) + xmlFree((char *) entity->orig); + } else { + if (entity->name != NULL) + xmlFree((char *) entity->name); + if (entity->ExternalID != NULL) + xmlFree((char *) entity->ExternalID); + if (entity->SystemID != NULL) + xmlFree((char *) entity->SystemID); + if (entity->URI != NULL) + xmlFree((char *) entity->URI); + if (entity->content != NULL) + xmlFree((char *) entity->content); + if (entity->orig != NULL) + xmlFree((char *) entity->orig); + } + xmlFree(entity); +} + +/* + * xmlCreateEntity: + * + * internal routine doing the entity node strutures allocations + */ +static xmlEntityPtr +xmlCreateEntity(xmlDictPtr dict, 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"); + return(NULL); + } + memset(ret, 0, sizeof(xmlEntity)); + ret->type = XML_ENTITY_DECL; + ret->checked = 0; + + /* + * fill the structure. + */ + ret->etype = (xmlEntityType) type; + if (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); + if (ExternalID != NULL) + ret->ExternalID = xmlDictLookup(dict, ExternalID, -1); + if (SystemID != NULL) + ret->SystemID = xmlDictLookup(dict, SystemID, -1); + } + if (content != NULL) { + ret->length = xmlStrlen(content); + if ((dict != NULL) && (ret->length < 5)) + ret->content = (xmlChar *) + xmlDictLookup(dict, content, ret->length); + else + ret->content = xmlStrndup(content, ret->length); + } else { + ret->length = 0; + ret->content = NULL; + } + ret->URI = NULL; /* to be computed by the layer knowing + the defining entity */ + ret->orig = NULL; + ret->owner = 0; + + return(ret); +} + +/* + * xmlAddEntity : register a new entity for an entities table. + */ +static xmlEntityPtr +xmlAddEntity(xmlDtdPtr dtd, const xmlChar *name, int type, + const xmlChar *ExternalID, const xmlChar *SystemID, + const xmlChar *content) { + xmlDictPtr dict = NULL; + xmlEntitiesTablePtr table = NULL; + xmlEntityPtr ret; + + if (name == NULL) + return(NULL); + if (dtd == NULL) + return(NULL); + if (dtd->doc != NULL) + dict = dtd->doc->dict; + + switch (type) { + case XML_INTERNAL_GENERAL_ENTITY: + case XML_EXTERNAL_GENERAL_PARSED_ENTITY: + case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY: + if (dtd->entities == NULL) + dtd->entities = xmlHashCreateDict(0, dict); + table = dtd->entities; + break; + case XML_INTERNAL_PARAMETER_ENTITY: + case XML_EXTERNAL_PARAMETER_ENTITY: + if (dtd->pentities == NULL) + dtd->pentities = xmlHashCreateDict(0, dict); + table = dtd->pentities; + break; + case XML_INTERNAL_PREDEFINED_ENTITY: + return(NULL); + } + if (table == NULL) + return(NULL); + ret = xmlCreateEntity(dict, name, type, ExternalID, SystemID, content); + if (ret == NULL) + return(NULL); + ret->doc = dtd->doc; + + if (xmlHashAddEntry(table, name, ret)) { + /* + * entity was already defined at another level. + */ + xmlFreeEntity(ret); + return(NULL); + } + return(ret); +} + +/** + * xmlGetPredefinedEntity: + * @name: the entity name + * + * Check whether this name is an predefined entity. + * + * Returns NULL if not, otherwise the entity + */ +xmlEntityPtr +xmlGetPredefinedEntity(const xmlChar *name) { + if (name == NULL) return(NULL); + switch (name[0]) { + case 'l': + if (xmlStrEqual(name, BAD_CAST "lt")) + return(&xmlEntityLt); + break; + case 'g': + if (xmlStrEqual(name, BAD_CAST "gt")) + return(&xmlEntityGt); + break; + case 'a': + if (xmlStrEqual(name, BAD_CAST "amp")) + return(&xmlEntityAmp); + if (xmlStrEqual(name, BAD_CAST "apos")) + return(&xmlEntityApos); + break; + case 'q': + if (xmlStrEqual(name, BAD_CAST "quot")) + return(&xmlEntityQuot); + break; + default: + break; + } + return(NULL); +} + +/** + * xmlAddDtdEntity: + * @doc: the document + * @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 + * + * Register a new entity for this document DTD external subset. + * + * Returns a pointer to the entity or NULL in case of error + */ +xmlEntityPtr +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; + } + return(ret); +} + +/** + * xmlAddDocEntity: + * @doc: the document + * @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 + * + * Register a new entity for this document. + * + * Returns a pointer to the entity or NULL in case of error + */ +xmlEntityPtr +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; + } + return(ret); +} + +/** + * xmlNewEntity: + * @doc: the document + * @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 + * + * Create a new entity, this differs from xmlAddDocEntity() that if + * the document is NULL or has no internal subset defined, then an + * unlinked entity structure will be returned, it is then the responsability + * of the caller to link it to the document later or free it when not needed + * anymore. + * + * Returns a pointer to the entity or NULL in case of error + */ +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) + return(NULL); + ret->doc = doc; + return(ret); +} + +/** + * xmlGetEntityFromTable: + * @table: an entity table + * @name: the entity name + * @parameter: look for parameter entities + * + * Do an entity lookup in the table. + * returns the corresponding parameter entity, if found. + * + * Returns A pointer to the entity structure or NULL if not found. + */ +static xmlEntityPtr +xmlGetEntityFromTable(xmlEntitiesTablePtr table, const xmlChar *name) { + return((xmlEntityPtr) xmlHashLookup(table, name)); +} + +/** + * xmlGetParameterEntity: + * @doc: the document referencing the entity + * @name: the entity name + * + * Do an entity lookup in the internal and external subsets and + * returns the corresponding parameter entity, if found. + * + * Returns A pointer to the entity structure or NULL if not found. + */ +xmlEntityPtr +xmlGetParameterEntity(xmlDocPtr doc, const xmlChar *name) { + xmlEntitiesTablePtr table; + xmlEntityPtr ret; + + if (doc == NULL) + return(NULL); + if ((doc->intSubset != NULL) && (doc->intSubset->pentities != NULL)) { + table = (xmlEntitiesTablePtr) doc->intSubset->pentities; + ret = xmlGetEntityFromTable(table, name); + if (ret != NULL) + return(ret); + } + if ((doc->extSubset != NULL) && (doc->extSubset->pentities != NULL)) { + table = (xmlEntitiesTablePtr) doc->extSubset->pentities; + return(xmlGetEntityFromTable(table, name)); + } + return(NULL); +} + +/** + * xmlGetDtdEntity: + * @doc: the document referencing the entity + * @name: the entity name + * + * Do an entity lookup in the DTD entity hash table and + * returns the corresponding entity, if found. + * Note: the first argument is the document node, not the DTD node. + * + * Returns A pointer to the entity structure or NULL if not found. + */ +xmlEntityPtr +xmlGetDtdEntity(xmlDocPtr doc, const xmlChar *name) { + xmlEntitiesTablePtr table; + + if (doc == NULL) + return(NULL); + if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) { + table = (xmlEntitiesTablePtr) doc->extSubset->entities; + return(xmlGetEntityFromTable(table, name)); + } + return(NULL); +} + +/** + * xmlGetDocEntity: + * @doc: the document referencing the entity + * @name: the entity name + * + * Do an entity lookup in the document entity hash table and + * returns the corresponding entity, otherwise a lookup is done + * in the predefined entities too. + * + * Returns A pointer to the entity structure or NULL if not found. + */ +xmlEntityPtr +xmlGetDocEntity(xmlDocPtr doc, const xmlChar *name) { + xmlEntityPtr cur; + xmlEntitiesTablePtr table; + + if (doc != NULL) { + if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) { + table = (xmlEntitiesTablePtr) doc->intSubset->entities; + cur = xmlGetEntityFromTable(table, name); + if (cur != NULL) + return(cur); + } + if (doc->standalone != 1) { + if ((doc->extSubset != NULL) && + (doc->extSubset->entities != NULL)) { + table = (xmlEntitiesTablePtr) doc->extSubset->entities; + cur = xmlGetEntityFromTable(table, name); + if (cur != NULL) + return(cur); + } + } + } + return(xmlGetPredefinedEntity(name)); +} + +/* + * Macro used to grow the current buffer. + */ +#define growBufferReentrant() { \ + buffer_size *= 2; \ + buffer = (xmlChar *) \ + xmlRealloc(buffer, buffer_size * sizeof(xmlChar)); \ + if (buffer == NULL) { \ + xmlEntitiesErrMemory("xmlEncodeEntitiesReentrant: realloc failed");\ + return(NULL); \ + } \ +} + + +/** + * xmlEncodeEntitiesReentrant: + * @doc: the document containing the string + * @input: A string to convert to XML. + * + * Do a global encoding of a string, replacing the predefined entities + * and non ASCII values with their entities and CharRef counterparts. + * Contrary to xmlEncodeEntities, this routine is reentrant, and result + * must be deallocated. + * + * Returns A newly allocated string with the substitution done. + */ +xmlChar * +xmlEncodeEntitiesReentrant(xmlDocPtr doc, const xmlChar *input) { + const xmlChar *cur = input; + xmlChar *buffer = NULL; + xmlChar *out = NULL; + int buffer_size = 0; + int html = 0; + + if (input == NULL) return(NULL); + if (doc != NULL) + html = (doc->type == XML_HTML_DOCUMENT_NODE); + + /* + * allocate an translation buffer. + */ + buffer_size = 1000; + buffer = (xmlChar *) xmlMalloc(buffer_size * sizeof(xmlChar)); + if (buffer == NULL) { + xmlEntitiesErrMemory("xmlEncodeEntitiesReentrant: malloc failed"); + return(NULL); + } + out = buffer; + + while (*cur != '\0') { + if (out - buffer > buffer_size - 100) { + int indx = out - buffer; + + growBufferReentrant(); + out = &buffer[indx]; + } + + /* + * By default one have to encode at least '<', '>', '"' and '&' ! + */ + if (*cur == '<') { + *out++ = '&'; + *out++ = 'l'; + *out++ = 't'; + *out++ = ';'; + } else if (*cur == '>') { + *out++ = '&'; + *out++ = 'g'; + *out++ = 't'; + *out++ = ';'; + } else if (*cur == '&') { + *out++ = '&'; + *out++ = 'a'; + *out++ = 'm'; + *out++ = 'p'; + *out++ = ';'; + } else if (((*cur >= 0x20) && (*cur < 0x80)) || + (*cur == '\n') || (*cur == '\t') || ((html) && (*cur == '\r'))) { + /* + * default case, just copy ! + */ + *out++ = *cur; + } else if (*cur >= 0x80) { + if (((doc != NULL) && (doc->encoding != NULL)) || (html)) { + /* + * Bjørn Reese provided the patch + xmlChar xc; + xc = (*cur & 0x3F) << 6; + if (cur[1] != 0) { + xc += *(++cur) & 0x3F; + *out++ = xc; + } else + */ + *out++ = *cur; + } else { + /* + * We assume we have UTF-8 input. + */ + char buf[11], *ptr; + int val = 0, l = 1; + + if (*cur < 0xC0) { + xmlEntitiesErr(XML_CHECK_NOT_UTF8, + "xmlEncodeEntitiesReentrant : input not UTF-8"); + if (doc != NULL) + doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1"); + 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, + "xmlEncodeEntitiesReentrant : char out of range\n"); + if (doc != NULL) + doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1"); + snprintf(buf, sizeof(buf), "&#%d;", *cur); + buf[sizeof(buf) - 1] = 0; + ptr = buf; + while (*ptr != 0) *out++ = *ptr++; + cur++; + continue; + } + /* + * We could do multiple things here. Just save as a char ref + */ + snprintf(buf, sizeof(buf), "&#x%X;", val); + buf[sizeof(buf) - 1] = 0; + ptr = buf; + while (*ptr != 0) *out++ = *ptr++; + cur += l; + continue; + } + } else if (IS_BYTE_CHAR(*cur)) { + char buf[11], *ptr; + + snprintf(buf, sizeof(buf), "&#%d;", *cur); + buf[sizeof(buf) - 1] = 0; + ptr = buf; + while (*ptr != 0) *out++ = *ptr++; + } + cur++; + } + *out = 0; + return(buffer); +} + +/** + * xmlEncodeSpecialChars: + * @doc: the document containing the string + * @input: A string to convert to XML. + * + * Do a global encoding of a string, replacing the predefined entities + * this routine is reentrant, and result must be deallocated. + * + * Returns A newly allocated string with the substitution done. + */ +xmlChar * +xmlEncodeSpecialChars(xmlDocPtr doc ATTRIBUTE_UNUSED, const xmlChar *input) { + const xmlChar *cur = input; + xmlChar *buffer = NULL; + xmlChar *out = NULL; + int buffer_size = 0; + if (input == NULL) return(NULL); + + /* + * allocate an translation buffer. + */ + buffer_size = 1000; + buffer = (xmlChar *) xmlMalloc(buffer_size * sizeof(xmlChar)); + if (buffer == NULL) { + xmlEntitiesErrMemory("xmlEncodeSpecialChars: malloc failed"); + return(NULL); + } + out = buffer; + + while (*cur != '\0') { + if (out - buffer > buffer_size - 10) { + int indx = out - buffer; + + growBufferReentrant(); + out = &buffer[indx]; + } + + /* + * By default one have to encode at least '<', '>', '"' and '&' ! + */ + if (*cur == '<') { + *out++ = '&'; + *out++ = 'l'; + *out++ = 't'; + *out++ = ';'; + } else if (*cur == '>') { + *out++ = '&'; + *out++ = 'g'; + *out++ = 't'; + *out++ = ';'; + } else if (*cur == '&') { + *out++ = '&'; + *out++ = 'a'; + *out++ = 'm'; + *out++ = 'p'; + *out++ = ';'; + } else if (*cur == '"') { + *out++ = '&'; + *out++ = 'q'; + *out++ = 'u'; + *out++ = 'o'; + *out++ = 't'; + *out++ = ';'; + } else if (*cur == '\r') { + *out++ = '&'; + *out++ = '#'; + *out++ = '1'; + *out++ = '3'; + *out++ = ';'; + } else { + /* + * Works because on UTF-8, all extended sequences cannot + * result in bytes in the ASCII range. + */ + *out++ = *cur; + } + cur++; + } + *out = 0; + return(buffer); +} + +/** + * xmlCreateEntitiesTable: + * + * create and initialize an empty entities hash table. + * This really doesn't make sense and should be deprecated + * + * Returns the xmlEntitiesTablePtr just created or NULL in case of error. + */ +xmlEntitiesTablePtr +xmlCreateEntitiesTable(void) { + return((xmlEntitiesTablePtr) xmlHashCreate(0)); +} + +/** + * xmlFreeEntityWrapper: + * @entity: An entity + * @name: its name + * + * Deallocate the memory used by an entities in the hash table. + */ +static void +xmlFreeEntityWrapper(xmlEntityPtr entity, + const xmlChar *name ATTRIBUTE_UNUSED) { + if (entity != NULL) + xmlFreeEntity(entity); +} + +/** + * xmlFreeEntitiesTable: + * @table: An entity table + * + * Deallocate the memory used by an entities hash table. + */ +void +xmlFreeEntitiesTable(xmlEntitiesTablePtr table) { + xmlHashFree(table, (xmlHashDeallocator) xmlFreeEntityWrapper); +} + +#ifdef LIBXML_TREE_ENABLED +/** + * xmlCopyEntity: + * @ent: An entity + * + * Build a copy of an entity + * + * Returns the new xmlEntitiesPtr or NULL in case of error. + */ +static xmlEntityPtr +xmlCopyEntity(xmlEntityPtr ent) { + xmlEntityPtr cur; + + cur = (xmlEntityPtr) xmlMalloc(sizeof(xmlEntity)); + if (cur == NULL) { + xmlEntitiesErrMemory("xmlCopyEntity:: malloc failed"); + return(NULL); + } + memset(cur, 0, sizeof(xmlEntity)); + cur->type = XML_ENTITY_DECL; + + cur->etype = ent->etype; + if (ent->name != NULL) + cur->name = xmlStrdup(ent->name); + if (ent->ExternalID != NULL) + cur->ExternalID = xmlStrdup(ent->ExternalID); + if (ent->SystemID != NULL) + cur->SystemID = xmlStrdup(ent->SystemID); + if (ent->content != NULL) + cur->content = xmlStrdup(ent->content); + if (ent->orig != NULL) + cur->orig = xmlStrdup(ent->orig); + if (ent->URI != NULL) + cur->URI = xmlStrdup(ent->URI); + return(cur); +} + +/** + * xmlCopyEntitiesTable: + * @table: An entity table + * + * Build a copy of an entity table. + * + * Returns the new xmlEntitiesTablePtr or NULL in case of error. + */ +xmlEntitiesTablePtr +xmlCopyEntitiesTable(xmlEntitiesTablePtr table) { + return(xmlHashCopy(table, (xmlHashCopier) xmlCopyEntity)); +} +#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 (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return; + 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. + * @ent: An entity table + * + * This will dump the content of the entity table as an XML DTD definition + */ +void +xmlDumpEntityDecl(xmlBufferPtr buf, xmlEntityPtr ent) { + if ((buf == NULL) || (ent == NULL)) return; + switch (ent->etype) { + case XML_INTERNAL_GENERAL_ENTITY: + xmlBufferWriteChar(buf, "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, "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, "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, "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, "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"); + } +} + +/** + * xmlDumpEntityDeclScan: + * @ent: An entity table + * @buf: An XML buffer. + * + * When using the hash table scan function, arguments need to be reversed + */ +static void +xmlDumpEntityDeclScan(xmlEntityPtr ent, xmlBufferPtr buf) { + xmlDumpEntityDecl(buf, ent); +} + +/** + * xmlDumpEntitiesTable: + * @buf: An XML buffer. + * @table: An entity table + * + * This will dump the content of the entity table as an XML DTD definition + */ +void +xmlDumpEntitiesTable(xmlBufferPtr buf, xmlEntitiesTablePtr table) { + xmlHashScan(table, (xmlHashScanner)xmlDumpEntityDeclScan, buf); +} +#endif /* LIBXML_OUTPUT_ENABLED */ +#define bottom_entities +#include "elfgcchack.h" diff --git a/android/native/libxml2/error.c b/android/native/libxml2/error.c new file mode 100644 index 0000000000..a891faa01f --- /dev/null +++ b/android/native/libxml2/error.c @@ -0,0 +1,979 @@ +/* + * error.c: module displaying/handling XML parser errors + * + * See Copyright for the status of this software. + * + * Daniel Veillard + */ + +#define IN_LIBXML +#include "libxml.h" + +#include +#include +#include +#include +#include +#include + +void XMLCDECL xmlGenericErrorDefaultFunc (void *ctx ATTRIBUTE_UNUSED, + const char *msg, + ...); + +#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; \ + }} \ +} + +/************************************************************************ + * * + * Handling of out of context errors * + * * + ************************************************************************/ + +/** + * xmlGenericErrorDefaultFunc: + * @ctx: an error context + * @msg: the message to display/transmit + * @...: extra parameters for the message display + * + * Default handler for out of context error messages. + */ +void XMLCDECL +xmlGenericErrorDefaultFunc(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) { + va_list args; + + if (xmlGenericErrorContext == NULL) + xmlGenericErrorContext = (void *) stderr; + + va_start(args, msg); + vfprintf((FILE *)xmlGenericErrorContext, msg, args); + va_end(args); +} + +/** + * initGenericErrorDefaultFunc: + * @handler: the handler + * + * Set or reset (if NULL) the default handler for generic errors + * to the builtin error function. + */ +void +initGenericErrorDefaultFunc(xmlGenericErrorFunc * handler) +{ + if (handler == NULL) + xmlGenericError = xmlGenericErrorDefaultFunc; + else + xmlGenericError = (*handler); +} + +/** + * xmlSetGenericErrorFunc: + * @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. + */ +void +xmlSetGenericErrorFunc(void *ctx, xmlGenericErrorFunc handler) { + xmlGenericErrorContext = ctx; + if (handler != NULL) + xmlGenericError = handler; + else + xmlGenericError = xmlGenericErrorDefaultFunc; +} + +/** + * xmlSetStructuredErrorFunc: + * @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. + */ +void +xmlSetStructuredErrorFunc(void *ctx, xmlStructuredErrorFunc handler) { + xmlStructuredErrorContext = ctx; + xmlStructuredError = handler; +} + +/************************************************************************ + * * + * Handling of parsing errors * + * * + ************************************************************************/ + +/** + * xmlParserPrintFileInfo: + * @input: an xmlParserInputPtr input + * + * Displays the associated file and line informations for the current input + */ + +void +xmlParserPrintFileInfo(xmlParserInputPtr input) { + if (input != NULL) { + if (input->filename) + xmlGenericError(xmlGenericErrorContext, + "%s:%d: ", input->filename, + input->line); + else + xmlGenericError(xmlGenericErrorContext, + "Entity: line %d: ", input->line); + } +} + +/** + * xmlParserPrintFileContext: + * @input: an xmlParserInputPtr input + * + * Displays current context within the input content for error tracking + */ + +static void +xmlParserPrintFileContextInternal(xmlParserInputPtr input , + xmlGenericErrorFunc channel, void *data ) { + const xmlChar *cur, *base; + unsigned int n, col; /* GCC warns if signed, because compared with sizeof() */ + xmlChar content[81]; /* space for 80 chars + line terminator */ + xmlChar *ctnt; + + if (input == NULL) return; + cur = input->cur; + base = input->base; + /* skip backwards over any end-of-lines */ + while ((cur > base) && ((*(cur) == '\n') || (*(cur) == '\r'))) { + cur--; + } + n = 0; + /* search backwards for beginning-of-line (to max buff size) */ + while ((n++ < (sizeof(content)-1)) && (cur > base) && + (*(cur) != '\n') && (*(cur) != '\r')) + cur--; + if ((*(cur) == '\n') || (*(cur) == '\r')) cur++; + /* calculate the error position in terms of the current position */ + col = input->cur - cur; + /* search forward for end-of-line (to max buff size) */ + n = 0; + ctnt = content; + /* copy selected text to our buffer */ + while ((*cur != 0) && (*(cur) != '\n') && + (*(cur) != '\r') && (n < sizeof(content)-1)) { + *ctnt++ = *cur++; + n++; + } + *ctnt = 0; + /* print out the selected text */ + channel(data ,"%s\n", content); + /* create blank line with problem pointer */ + n = 0; + ctnt = content; + /* (leave buffer space for pointer + line terminator) */ + while ((nfile; + line = err->line; + code = err->code; + domain = err->domain; + level = err->level; + node = err->node; + + if (code == XML_ERR_OK) + return; + + if ((node != NULL) && (node->type == XML_ELEMENT_NODE)) + name = node->name; + + /* + * Maintain the compatibility with the legacy error handling + */ + if (ctxt != NULL) { + input = ctxt->input; + if ((input != NULL) && (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); + } + } else { + if (file != NULL) + channel(data, "%s:%d: ", file, line); + else if ((line != 0) && (domain == XML_FROM_PARSER)) + channel(data, "Entity: line %d: ", line); + } + if (name != NULL) { + channel(data, "element %s: ", name); + } + switch (domain) { + case XML_FROM_PARSER: + channel(data, "parser "); + break; + case XML_FROM_NAMESPACE: + channel(data, "namespace "); + break; + case XML_FROM_DTD: + case XML_FROM_VALID: + channel(data, "validity "); + break; + case XML_FROM_HTML: + channel(data, "HTML parser "); + break; + case XML_FROM_MEMORY: + channel(data, "memory "); + break; + case XML_FROM_OUTPUT: + channel(data, "output "); + break; + case XML_FROM_IO: + channel(data, "I/O "); + break; + case XML_FROM_XINCLUDE: + channel(data, "XInclude "); + break; + case XML_FROM_XPATH: + channel(data, "XPath "); + break; + case XML_FROM_XPOINTER: + channel(data, "parser "); + break; + case XML_FROM_REGEXP: + channel(data, "regexp "); + break; + case XML_FROM_MODULE: + channel(data, "module "); + break; + case XML_FROM_SCHEMASV: + channel(data, "Schemas validity "); + break; + case XML_FROM_SCHEMASP: + channel(data, "Schemas parser "); + break; + case XML_FROM_RELAXNGP: + channel(data, "Relax-NG parser "); + break; + case XML_FROM_RELAXNGV: + channel(data, "Relax-NG validity "); + break; + case XML_FROM_CATALOG: + channel(data, "Catalog "); + break; + case XML_FROM_C14N: + channel(data, "C14N "); + break; + case XML_FROM_XSLT: + channel(data, "XSLT "); + break; + case XML_FROM_I18N: + channel(data, "encoding "); + break; + default: + break; + } + switch (level) { + case XML_ERR_NONE: + channel(data, ": "); + break; + case XML_ERR_WARNING: + channel(data, "warning : "); + break; + case XML_ERR_ERROR: + channel(data, "error : "); + break; + case XML_ERR_FATAL: + channel(data, "error : "); + break; + } + if (str != NULL) { + int len; + len = xmlStrlen((const xmlChar *)str); + if ((len > 0) && (str[len - 1] != '\n')) + channel(data, "%s\n", str); + else + channel(data, "%s", str); + } else { + channel(data, "%s\n", "out of memory error"); + } + + if (ctxt != NULL) { + xmlParserPrintFileContextInternal(input, channel, data); + if (cur != NULL) { + if (cur->filename) + channel(data, "%s:%d: \n", cur->filename, cur->line); + else if ((line != 0) && (domain == XML_FROM_PARSER)) + channel(data, "Entity: line %d: \n", cur->line); + xmlParserPrintFileContextInternal(cur, channel, data); + } + } + if ((domain == XML_FROM_XPATH) && (err->str1 != NULL) && + (err->int1 < 100) && + (err->int1 < xmlStrlen((const xmlChar *)err->str1))) { + xmlChar buf[150]; + int i; + + channel(data, "%s\n", err->str1); + for (i=0;i < err->int1;i++) + buf[i] = ' '; + buf[i++] = '^'; + buf[i] = 0; + channel(data, "%s\n", buf); + } +} + +/** + * __xmlRaiseError: + * @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 + * @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 + * + * Update the appropriate global or contextual error structure, + * then forward the error message down the parser or generic + * error callback handler + */ +void XMLCDECL +__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, ...) +{ + xmlParserCtxtPtr ctxt = NULL; + xmlNodePtr node = (xmlNodePtr) nod; + char *str = NULL; + xmlParserInputPtr input = NULL; + xmlErrorPtr to = &xmlLastError; + xmlNodePtr baseptr = NULL; + + if (code == XML_ERR_OK) + return; + if ((xmlGetWarningsDefaultValue == 0) && (level == XML_ERR_WARNING)) + return; + 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 ((schannel == NULL) && (ctxt != 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); + } + + /* + * 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; + } + + /* + * 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; + 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) + break; + } else if (prev->type == XML_XINCLUDE_END) + inclcount++; + } + } + if (prev != NULL) { + if (prev->type == XML_XINCLUDE_START) { + prev->type = XML_ELEMENT_NODE; + to->file = (char *) xmlGetProp(prev, BAD_CAST "href"); + prev->type = XML_XINCLUDE_START; + } else { + to->file = (char *) xmlGetProp(prev, BAD_CAST "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); + } + } + 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 + channel = ctxt->sax->error; + data = ctxt->userData; + } else if (channel == NULL) { + channel = xmlGenericError; + if (!data) + data = xmlGenericErrorContext; + } + if (channel == NULL) + return; + + if ((channel == xmlParserError) || + (channel == xmlParserWarning) || + (channel == xmlParserValidityError) || + (channel == xmlParserValidityWarning)) + xmlReportError(to, ctxt, str, NULL, NULL); + else if ((channel == (xmlGenericErrorFunc) fprintf) || + (channel == xmlGenericErrorDefaultFunc)) + xmlReportError(to, ctxt, str, channel, data); + else + channel(data, "%s", str); +} + +/** + * __xmlSimpleError: + * @domain: where the error comes from + * @code: the error code + * @node: the context node + * @extra: extra informations + * + * 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 + * @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. + */ +void XMLCDECL +xmlParserError(void *ctx, const char *msg, ...) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + xmlParserInputPtr input = NULL; + xmlParserInputPtr cur = NULL; + char * str; + + 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); + } + + xmlGenericError(xmlGenericErrorContext, "error: "); + XML_GET_VAR_STR(msg, str); + xmlGenericError(xmlGenericErrorContext, "%s", str); + if (str != NULL) + xmlFree(str); + + if (ctxt != NULL) { + xmlParserPrintFileContext(input); + if (cur != NULL) { + xmlParserPrintFileInfo(cur); + xmlGenericError(xmlGenericErrorContext, "\n"); + xmlParserPrintFileContext(cur); + } + } +} + +/** + * 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 XMLCDECL +xmlParserWarning(void *ctx, const char *msg, ...) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + xmlParserInputPtr input = NULL; + xmlParserInputPtr cur = NULL; + char * str; + + 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); + } + + xmlGenericError(xmlGenericErrorContext, "warning: "); + XML_GET_VAR_STR(msg, str); + xmlGenericError(xmlGenericErrorContext, "%s", str); + if (str != NULL) + xmlFree(str); + + if (ctxt != NULL) { + xmlParserPrintFileContext(input); + if (cur != NULL) { + xmlParserPrintFileInfo(cur); + xmlGenericError(xmlGenericErrorContext, "\n"); + xmlParserPrintFileContext(cur); + } + } +} + +/************************************************************************ + * * + * Handling of validation errors * + * * + ************************************************************************/ + +/** + * xmlParserValidityError: + * @ctx: an XML parser context + * @msg: the message to display/transmit + * @...: extra parameters for the message display + * + * Display and format an validity error messages, gives file, + * line, position and extra parameters. + */ +void XMLCDECL +xmlParserValidityError(void *ctx, const char *msg, ...) +{ + 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; + } + + XML_GET_VAR_STR(msg, str); + xmlGenericError(xmlGenericErrorContext, "%s", str); + if (str != NULL) + xmlFree(str); + + if ((ctxt != NULL) && (input != NULL)) { + xmlParserPrintFileContext(input); + } +} + +/** + * xmlParserValidityWarning: + * @ctx: an XML parser context + * @msg: the message to display/transmit + * @...: extra parameters for the message display + * + * Display and format a validity warning messages, gives file, line, + * position and extra parameters. + */ +void XMLCDECL +xmlParserValidityWarning(void *ctx, const char *msg, ...) +{ + 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); + + if (ctxt != NULL) { + xmlParserPrintFileContext(input); + } +} + + +/************************************************************************ + * * + * Extended Error Handling * + * * + ************************************************************************/ + +/** + * xmlGetLastError: + * + * Get the last global error registered. This is per thread if compiled + * with thread support. + * + * Returns NULL if no error occured or a pointer to the error + */ +xmlErrorPtr +xmlGetLastError(void) +{ + if (xmlLastError.code == XML_ERR_OK) + return (NULL); + return (&xmlLastError); +} + +/** + * xmlResetError: + * @err: pointer to the error. + * + * Cleanup the error. + */ +void +xmlResetError(xmlErrorPtr err) +{ + if (err == NULL) + return; + if (err->code == XML_ERR_OK) + return; + if (err->message != NULL) + xmlFree(err->message); + if (err->file != NULL) + xmlFree(err->file); + if (err->str1 != NULL) + xmlFree(err->str1); + if (err->str2 != NULL) + xmlFree(err->str2); + if (err->str3 != NULL) + xmlFree(err->str3); + memset(err, 0, sizeof(xmlError)); + err->code = XML_ERR_OK; +} + +/** + * xmlResetLastError: + * + * Cleanup the last global error registered. For parsing error + * this does not change the well-formedness result. + */ +void +xmlResetLastError(void) +{ + if (xmlLastError.code == XML_ERR_OK) + return; + xmlResetError(&xmlLastError); +} + +/** + * xmlCtxtGetLastError: + * @ctx: an XML parser context + * + * Get the last parsing error registered. + * + * Returns NULL if no error occured or a pointer to the error + */ +xmlErrorPtr +xmlCtxtGetLastError(void *ctx) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + + if (ctxt == NULL) + return (NULL); + if (ctxt->lastError.code == XML_ERR_OK) + return (NULL); + return (&ctxt->lastError); +} + +/** + * xmlCtxtResetLastError: + * @ctx: an XML parser context + * + * Cleanup the last global error registered. For parsing error + * this does not change the well-formedness result. + */ +void +xmlCtxtResetLastError(void *ctx) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + + if (ctxt == NULL) + return; + ctxt->errNo = XML_ERR_OK; + if (ctxt->lastError.code == XML_ERR_OK) + return; + xmlResetError(&ctxt->lastError); +} + +/** + * xmlCopyError: + * @from: a source error + * @to: a target error + * + * Save the original error to the new place. + * + * Returns 0 in case of success and -1 in case of error. + */ +int +xmlCopyError(xmlErrorPtr from, xmlErrorPtr to) { + char *message, *file, *str1, *str2, *str3; + + 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; +} + +#define bottom_error +#include "elfgcchack.h" diff --git a/android/native/libxml2/globals.c b/android/native/libxml2/globals.c new file mode 100644 index 0000000000..6a0249bc8a --- /dev/null +++ b/android/native/libxml2/globals.c @@ -0,0 +1,1062 @@ +/* + * globals.c: definition and handling of the set of global variables + * of the library + * + * The bottom of this file is automatically generated by build_glob.py + * based on the description file global.data + * + * See Copyright for the status of this software. + * + * Gary Pennington + * daniel@veillard.com + */ + +#define IN_LIBXML +#include "libxml.h" + +#ifdef HAVE_STDLIB_H +#include +#endif +#include + +#include +#include +#include + +/* #define DEBUG_GLOBALS */ + +/* + * Helpful Macro + */ +#ifdef LIBXML_THREAD_ENABLED +#define IS_MAIN_THREAD (xmlIsMainThread()) +#else +#define IS_MAIN_THREAD 1 +#endif + +/* + * Mutex to protect "ForNewThreads" variables + */ +static xmlMutexPtr xmlThrDefMutex = NULL; + +/** + * xmlInitGlobals: + * + * Additional initialisation for multi-threading + */ +void xmlInitGlobals(void) +{ + if (xmlThrDefMutex == NULL) + xmlThrDefMutex = xmlNewMutex(); +} + +/** + * xmlCleanupGlobals: + * + * Additional cleanup for multi-threading + */ +void xmlCleanupGlobals(void) +{ + if (xmlThrDefMutex != NULL) { + xmlFreeMutex(xmlThrDefMutex); + xmlThrDefMutex = NULL; + } + __xmlGlobalInitMutexDestroy(); +} + +/************************************************************************ + * * + * All the user accessible global variables of the library * + * * + ************************************************************************/ + +/* + * Memory allocation routines + */ +#undef xmlFree +#undef xmlMalloc +#undef xmlMallocAtomic +#undef xmlMemStrdup +#undef xmlRealloc + +#if defined(DEBUG_MEMORY_LOCATION) || defined(DEBUG_MEMORY) +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 + * + * The variable holding the libxml free() implementation + */ +xmlFreeFunc xmlFree = (xmlFreeFunc) free; +/** + * xmlMalloc: + * @size: the size requested in bytes + * + * The variable holding the libxml malloc() implementation + * + * Returns a pointer to the newly allocated block or NULL in case of error + */ +xmlMallocFunc xmlMalloc = (xmlMallocFunc) malloc; +/** + * xmlMallocAtomic: + * @size: the size requested in bytes + * + * The variable holding the libxml malloc() implementation for atomic + * data (i.e. blocks not containings pointers), useful when using a + * garbage collecting allocator. + * + * Returns a pointer to the newly allocated block or NULL in case of error + */ +xmlMallocFunc xmlMallocAtomic = (xmlMallocFunc) malloc; +/** + * xmlRealloc: + * @mem: an already allocated block of memory + * @size: the new size requested in bytes + * + * The variable holding the libxml realloc() implementation + * + * Returns a pointer to the newly reallocated block or NULL in case of error + */ +xmlReallocFunc xmlRealloc = (xmlReallocFunc) realloc; +/** + * xmlMemStrdup: + * @str: a zero terminated string + * + * The variable holding the libxml strdup() implementation + * + * Returns the copy of the string or NULL in case of error + */ +xmlStrdupFunc xmlMemStrdup = (xmlStrdupFunc) xmlStrdup; +#endif /* DEBUG_MEMORY_LOCATION || DEBUG_MEMORY */ + +#include +#include +#include + +#undef docbDefaultSAXHandler +#undef htmlDefaultSAXHandler +#undef oldXMLWDcompatibility +#undef xmlBufferAllocScheme +#undef xmlDefaultBufferSize +#undef xmlDefaultSAXHandler +#undef xmlDefaultSAXLocator +#undef xmlDoValidityCheckingDefaultValue +#undef xmlGenericError +#undef xmlStructuredError +#undef xmlGenericErrorContext +#undef xmlStructuredErrorContext +#undef xmlGetWarningsDefaultValue +#undef xmlIndentTreeOutput +#undef xmlTreeIndentString +#undef xmlKeepBlanksDefaultValue +#undef xmlLineNumbersDefaultValue +#undef xmlLoadExtDtdDefaultValue +#undef xmlParserDebugEntities +#undef xmlParserVersion +#undef xmlPedanticParserDefaultValue +#undef xmlSaveNoEmptyTags +#undef xmlSubstituteEntitiesDefaultValue +#undef xmlRegisterNodeDefaultValue +#undef xmlDeregisterNodeDefaultValue +#undef xmlLastError + +#undef xmlParserInputBufferCreateFilenameValue +#undef xmlOutputBufferCreateFilenameValue +/** + * xmlParserVersion: + * + * Constant string describing the internal version of the library + */ +const char *xmlParserVersion = LIBXML_VERSION_STRING LIBXML_VERSION_EXTRA; + +/** + * xmlBufferAllocScheme: + * + * Global setting, default allocation policy for buffers, default is + * XML_BUFFER_ALLOC_EXACT + */ +xmlBufferAllocationScheme xmlBufferAllocScheme = XML_BUFFER_ALLOC_EXACT; +static xmlBufferAllocationScheme xmlBufferAllocSchemeThrDef = XML_BUFFER_ALLOC_EXACT; +/** + * xmlDefaultBufferSize: + * + * Global setting, default buffer size. Default value is BASE_BUFFER_SIZE + */ +int xmlDefaultBufferSize = BASE_BUFFER_SIZE; +static int xmlDefaultBufferSizeThrDef = BASE_BUFFER_SIZE; + +/* + * Parser defaults + */ + +/** + * oldXMLWDcompatibility: + * + * Global setting, DEPRECATED. + */ +int oldXMLWDcompatibility = 0; /* DEPRECATED */ +/** + * xmlParserDebugEntities: + * + * Global setting, asking the parser to print out debugging informations. + * while handling entities. + * Disabled by default + */ +int xmlParserDebugEntities = 0; +static int xmlParserDebugEntitiesThrDef = 0; +/** + * xmlDoValidityCheckingDefaultValue: + * + * Global setting, indicate that the parser should work in validating mode. + * Disabled by default. + */ +int xmlDoValidityCheckingDefaultValue = 0; +static int xmlDoValidityCheckingDefaultValueThrDef = 0; +/** + * xmlGetWarningsDefaultValue: + * + * Global setting, indicate that the parser should provide warnings. + * Activated by default. + */ +int xmlGetWarningsDefaultValue = 1; +static int xmlGetWarningsDefaultValueThrDef = 1; +/** + * xmlLoadExtDtdDefaultValue: + * + * Global setting, indicate that the parser should load DTD while not + * validating. + * Disabled by default. + */ +int xmlLoadExtDtdDefaultValue = 0; +static int xmlLoadExtDtdDefaultValueThrDef = 0; +/** + * xmlPedanticParserDefaultValue: + * + * Global setting, indicate that the parser be pedantic + * Disabled by default. + */ +int xmlPedanticParserDefaultValue = 0; +static int xmlPedanticParserDefaultValueThrDef = 0; +/** + * xmlLineNumbersDefaultValue: + * + * Global setting, indicate that the parser should store the line number + * in the content field of elements in the DOM tree. + * Disabled by default since this may not be safe for old classes of + * applicaton. + */ +int xmlLineNumbersDefaultValue = 0; +static int xmlLineNumbersDefaultValueThrDef = 0; +/** + * xmlKeepBlanksDefaultValue: + * + * Global setting, indicate that the parser should keep all blanks + * nodes found in the content + * Activated by default, this is actually needed to have the parser + * conformant to the XML Recommendation, however the option is kept + * for some applications since this was libxml1 default behaviour. + */ +int xmlKeepBlanksDefaultValue = 1; +static int xmlKeepBlanksDefaultValueThrDef = 1; +/** + * xmlSubstituteEntitiesDefaultValue: + * + * Global setting, indicate that the parser should not generate entity + * references but replace them with the actual content of the entity + * Disabled by default, this should be activated when using XPath since + * the XPath data model requires entities replacement and the XPath + * engine does not handle entities references transparently. + */ +int xmlSubstituteEntitiesDefaultValue = 0; +static int xmlSubstituteEntitiesDefaultValueThrDef = 0; + +xmlRegisterNodeFunc xmlRegisterNodeDefaultValue = NULL; +static xmlRegisterNodeFunc xmlRegisterNodeDefaultValueThrDef = NULL; +xmlDeregisterNodeFunc xmlDeregisterNodeDefaultValue = NULL; +static xmlDeregisterNodeFunc xmlDeregisterNodeDefaultValueThrDef = NULL; + +xmlParserInputBufferCreateFilenameFunc xmlParserInputBufferCreateFilenameValue = NULL; +static xmlParserInputBufferCreateFilenameFunc xmlParserInputBufferCreateFilenameValueThrDef = NULL; + +xmlOutputBufferCreateFilenameFunc xmlOutputBufferCreateFilenameValue = NULL; +static xmlOutputBufferCreateFilenameFunc xmlOutputBufferCreateFilenameValueThrDef = NULL; + +/* + * Error handling + */ + +/* xmlGenericErrorFunc xmlGenericError = xmlGenericErrorDefaultFunc; */ +/* Must initialize xmlGenericError in xmlInitParser */ +void XMLCDECL xmlGenericErrorDefaultFunc (void *ctx ATTRIBUTE_UNUSED, + const char *msg, + ...); +/** + * xmlGenericError: + * + * Global setting: function used for generic error callbacks + */ +xmlGenericErrorFunc xmlGenericError = xmlGenericErrorDefaultFunc; +static xmlGenericErrorFunc xmlGenericErrorThrDef = xmlGenericErrorDefaultFunc; +/** + * xmlStructuredError: + * + * Global setting: function used for structured error callbacks + */ +xmlStructuredErrorFunc xmlStructuredError = NULL; +static xmlStructuredErrorFunc xmlStructuredErrorThrDef = NULL; +/** + * xmlGenericErrorContext: + * + * Global setting passed to generic error callbacks + */ +void *xmlGenericErrorContext = NULL; +static void *xmlGenericErrorContextThrDef = NULL; +/** + * xmlStructuredErrorContext: + * + * Global setting passed to structured error callbacks + */ +void *xmlStructuredErrorContext = NULL; +static void *xmlStructuredErrorContextThrDef = NULL; +xmlError xmlLastError; + +/* + * output defaults + */ +/** + * xmlIndentTreeOutput: + * + * Global setting, asking the serializer to indent the output tree by default + * Enabled by default + */ +int xmlIndentTreeOutput = 1; +static int xmlIndentTreeOutputThrDef = 1; + +/** + * xmlTreeIndentString: + * + * The string used to do one-level indent. By default is equal to " " (two spaces) + */ +const char *xmlTreeIndentString = " "; +static const char *xmlTreeIndentStringThrDef = " "; + +/** + * xmlSaveNoEmptyTags: + * + * Global setting, asking the serializer to not output empty tags + * as but . those two forms are undistinguishable + * once parsed. + * Disabled by default + */ +int xmlSaveNoEmptyTags = 0; +static int xmlSaveNoEmptyTagsThrDef = 0; + +#ifdef LIBXML_SAX1_ENABLED +/** + * xmlDefaultSAXHandler: + * + * Default SAX version1 handler for XML, builds the DOM tree + */ +xmlSAXHandlerV1 xmlDefaultSAXHandler = { + xmlSAX2InternalSubset, + xmlSAX2IsStandalone, + xmlSAX2HasInternalSubset, + xmlSAX2HasExternalSubset, + xmlSAX2ResolveEntity, + xmlSAX2GetEntity, + xmlSAX2EntityDecl, + xmlSAX2NotationDecl, + xmlSAX2AttributeDecl, + xmlSAX2ElementDecl, + xmlSAX2UnparsedEntityDecl, + xmlSAX2SetDocumentLocator, + xmlSAX2StartDocument, + xmlSAX2EndDocument, + xmlSAX2StartElement, + xmlSAX2EndElement, + xmlSAX2Reference, + xmlSAX2Characters, + xmlSAX2Characters, + xmlSAX2ProcessingInstruction, + xmlSAX2Comment, + xmlParserWarning, + xmlParserError, + xmlParserError, + xmlSAX2GetParameterEntity, + xmlSAX2CDataBlock, + xmlSAX2ExternalSubset, + 0, +}; +#endif /* LIBXML_SAX1_ENABLED */ + +/** + * xmlDefaultSAXLocator: + * + * The default SAX Locator + * { getPublicId, getSystemId, getLineNumber, getColumnNumber} + */ +xmlSAXLocator xmlDefaultSAXLocator = { + xmlSAX2GetPublicId, + xmlSAX2GetSystemId, + xmlSAX2GetLineNumber, + xmlSAX2GetColumnNumber +}; + +#ifdef LIBXML_DOCB_ENABLED +/** + * docbDefaultSAXHandler: + * + * Default old SAX v1 handler for SGML DocBook, builds the DOM tree + */ +xmlSAXHandlerV1 docbDefaultSAXHandler = { + xmlSAX2InternalSubset, + xmlSAX2IsStandalone, + xmlSAX2HasInternalSubset, + xmlSAX2HasExternalSubset, + xmlSAX2ResolveEntity, + xmlSAX2GetEntity, + xmlSAX2EntityDecl, + NULL, + NULL, + NULL, + NULL, + xmlSAX2SetDocumentLocator, + xmlSAX2StartDocument, + xmlSAX2EndDocument, + xmlSAX2StartElement, + xmlSAX2EndElement, + xmlSAX2Reference, + xmlSAX2Characters, + xmlSAX2IgnorableWhitespace, + NULL, + xmlSAX2Comment, + xmlParserWarning, + xmlParserError, + xmlParserError, + xmlSAX2GetParameterEntity, + NULL, + NULL, + 0, +}; +#endif /* LIBXML_DOCB_ENABLED */ + +/** + * xmlInitializeGlobalState: + * @gs: a pointer to a newly allocated global state + * + * xmlInitializeGlobalState() initialize a global state with all the + * default values of the library. + */ +void +xmlInitializeGlobalState(xmlGlobalStatePtr gs) +{ +#ifdef DEBUG_GLOBALS + fprintf(stderr, "Initializing globals at %lu for thread %d\n", + (unsigned long) gs, xmlGetThreadId()); +#endif + + /* + * Perform initialization as required by libxml + */ + if (xmlThrDefMutex == NULL) + xmlInitGlobals(); + + xmlMutexLock(xmlThrDefMutex); + +#if defined(LIBXML_DOCB_ENABLED) && defined(LIBXML_LEGACY_ENABLED) && defined(LIBXML_SAX1_ENABLED) + initdocbDefaultSAXHandler(&gs->docbDefaultSAXHandler); +#endif + + gs->oldXMLWDcompatibility = 0; + gs->xmlBufferAllocScheme = xmlBufferAllocSchemeThrDef; + gs->xmlDefaultBufferSize = xmlDefaultBufferSizeThrDef; +#if defined(LIBXML_SAX1_ENABLED) && defined(LIBXML_LEGACY_ENABLED) + initxmlDefaultSAXHandler(&gs->xmlDefaultSAXHandler, 1); +#endif /* LIBXML_SAX1_ENABLED */ + gs->xmlDefaultSAXLocator.getPublicId = xmlSAX2GetPublicId; + gs->xmlDefaultSAXLocator.getSystemId = xmlSAX2GetSystemId; + gs->xmlDefaultSAXLocator.getLineNumber = xmlSAX2GetLineNumber; + gs->xmlDefaultSAXLocator.getColumnNumber = xmlSAX2GetColumnNumber; + gs->xmlDoValidityCheckingDefaultValue = + xmlDoValidityCheckingDefaultValueThrDef; +#if defined(DEBUG_MEMORY_LOCATION) | defined(DEBUG_MEMORY) + gs->xmlFree = (xmlFreeFunc) xmlMemFree; + gs->xmlMalloc = (xmlMallocFunc) xmlMemMalloc; + gs->xmlMallocAtomic = (xmlMallocFunc) xmlMemMalloc; + gs->xmlRealloc = (xmlReallocFunc) xmlMemRealloc; + gs->xmlMemStrdup = (xmlStrdupFunc) xmlMemoryStrdup; +#else + gs->xmlFree = (xmlFreeFunc) free; + gs->xmlMalloc = (xmlMallocFunc) malloc; + gs->xmlMallocAtomic = (xmlMallocFunc) malloc; + gs->xmlRealloc = (xmlReallocFunc) realloc; + gs->xmlMemStrdup = (xmlStrdupFunc) xmlStrdup; +#endif + gs->xmlGetWarningsDefaultValue = xmlGetWarningsDefaultValueThrDef; + gs->xmlIndentTreeOutput = xmlIndentTreeOutputThrDef; + gs->xmlTreeIndentString = xmlTreeIndentStringThrDef; + gs->xmlKeepBlanksDefaultValue = xmlKeepBlanksDefaultValueThrDef; + gs->xmlLineNumbersDefaultValue = xmlLineNumbersDefaultValueThrDef; + gs->xmlLoadExtDtdDefaultValue = xmlLoadExtDtdDefaultValueThrDef; + gs->xmlParserDebugEntities = xmlParserDebugEntitiesThrDef; + gs->xmlParserVersion = LIBXML_VERSION_STRING; + gs->xmlPedanticParserDefaultValue = xmlPedanticParserDefaultValueThrDef; + gs->xmlSaveNoEmptyTags = xmlSaveNoEmptyTagsThrDef; + gs->xmlSubstituteEntitiesDefaultValue = + xmlSubstituteEntitiesDefaultValueThrDef; + + gs->xmlGenericError = xmlGenericErrorThrDef; + gs->xmlStructuredError = xmlStructuredErrorThrDef; + gs->xmlGenericErrorContext = xmlGenericErrorContextThrDef; + gs->xmlStructuredErrorContext = xmlStructuredErrorContextThrDef; + gs->xmlRegisterNodeDefaultValue = xmlRegisterNodeDefaultValueThrDef; + gs->xmlDeregisterNodeDefaultValue = xmlDeregisterNodeDefaultValueThrDef; + + gs->xmlParserInputBufferCreateFilenameValue = xmlParserInputBufferCreateFilenameValueThrDef; + gs->xmlOutputBufferCreateFilenameValue = xmlOutputBufferCreateFilenameValueThrDef; + memset(&gs->xmlLastError, 0, sizeof(xmlError)); + + xmlMutexUnlock(xmlThrDefMutex); +} + +/** + * DOC_DISABLE : we ignore missing doc for the xmlThrDef functions, + * those are really internal work + */ +void +xmlThrDefSetGenericErrorFunc(void *ctx, xmlGenericErrorFunc handler) { + xmlMutexLock(xmlThrDefMutex); + xmlGenericErrorContextThrDef = ctx; + if (handler != NULL) + xmlGenericErrorThrDef = handler; + else + xmlGenericErrorThrDef = xmlGenericErrorDefaultFunc; + xmlMutexUnlock(xmlThrDefMutex); +} + +void +xmlThrDefSetStructuredErrorFunc(void *ctx, xmlStructuredErrorFunc handler) { + xmlMutexLock(xmlThrDefMutex); + xmlStructuredErrorContextThrDef = ctx; + xmlStructuredErrorThrDef = handler; + xmlMutexUnlock(xmlThrDefMutex); +} + +/** + * xmlRegisterNodeDefault: + * @func: function pointer to the new RegisterNodeFunc + * + * Registers a callback for node creation + * + * Returns the old value of the registration function + */ +xmlRegisterNodeFunc +xmlRegisterNodeDefault(xmlRegisterNodeFunc func) +{ + xmlRegisterNodeFunc old = xmlRegisterNodeDefaultValue; + + __xmlRegisterCallbacks = 1; + xmlRegisterNodeDefaultValue = func; + return(old); +} + +xmlRegisterNodeFunc +xmlThrDefRegisterNodeDefault(xmlRegisterNodeFunc func) +{ + xmlRegisterNodeFunc old; + + xmlMutexLock(xmlThrDefMutex); + old = xmlRegisterNodeDefaultValueThrDef; + + __xmlRegisterCallbacks = 1; + xmlRegisterNodeDefaultValueThrDef = func; + xmlMutexUnlock(xmlThrDefMutex); + + return(old); +} + +/** + * xmlDeregisterNodeDefault: + * @func: function pointer to the new DeregisterNodeFunc + * + * Registers a callback for node destruction + * + * Returns the previous value of the deregistration function + */ +xmlDeregisterNodeFunc +xmlDeregisterNodeDefault(xmlDeregisterNodeFunc func) +{ + xmlDeregisterNodeFunc old = xmlDeregisterNodeDefaultValue; + + __xmlRegisterCallbacks = 1; + xmlDeregisterNodeDefaultValue = func; + return(old); +} + +xmlDeregisterNodeFunc +xmlThrDefDeregisterNodeDefault(xmlDeregisterNodeFunc func) +{ + xmlDeregisterNodeFunc old; + + xmlMutexLock(xmlThrDefMutex); + old = xmlDeregisterNodeDefaultValueThrDef; + + __xmlRegisterCallbacks = 1; + xmlDeregisterNodeDefaultValueThrDef = func; + xmlMutexUnlock(xmlThrDefMutex); + + return(old); +} + +xmlParserInputBufferCreateFilenameFunc +xmlThrDefParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func) +{ + xmlParserInputBufferCreateFilenameFunc old; + + xmlMutexLock(xmlThrDefMutex); + old = xmlParserInputBufferCreateFilenameValueThrDef; + if (old == NULL) { + old = __xmlParserInputBufferCreateFilename; + } + + xmlParserInputBufferCreateFilenameValueThrDef = func; + xmlMutexUnlock(xmlThrDefMutex); + + return(old); +} + +xmlOutputBufferCreateFilenameFunc +xmlThrDefOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func) +{ + xmlOutputBufferCreateFilenameFunc old; + + xmlMutexLock(xmlThrDefMutex); + old = xmlOutputBufferCreateFilenameValueThrDef; +#ifdef LIBXML_OUTPUT_ENABLED + if (old == NULL) { + old = __xmlOutputBufferCreateFilename; + } +#endif + xmlOutputBufferCreateFilenameValueThrDef = func; + xmlMutexUnlock(xmlThrDefMutex); + + return(old); +} + +#ifdef LIBXML_DOCB_ENABLED +#undef docbDefaultSAXHandler +xmlSAXHandlerV1 * +__docbDefaultSAXHandler(void) { + if (IS_MAIN_THREAD) + return (&docbDefaultSAXHandler); + else + return (&xmlGetGlobalState()->docbDefaultSAXHandler); +} +#endif + +#undef xmlLastError +xmlError * +__xmlLastError(void) { + if (IS_MAIN_THREAD) + return (&xmlLastError); + else + return (&xmlGetGlobalState()->xmlLastError); +} + +/* + * The following memory routines were apparently lost at some point, + * and were re-inserted at this point on June 10, 2004. Hope it's + * the right place for them :-) + */ +#if defined(LIBXML_THREAD_ALLOC_ENABLED) && defined(LIBXML_THREAD_ENABLED) +#undef xmlMalloc +xmlMallocFunc * +__xmlMalloc(void){ + if (IS_MAIN_THREAD) + return (&xmlMalloc); + else + return (&xmlGetGlobalState()->xmlMalloc); +} + +#undef xmlMallocAtomic +xmlMallocFunc * +__xmlMallocAtomic(void){ + if (IS_MAIN_THREAD) + return (&xmlMallocAtomic); + else + return (&xmlGetGlobalState()->xmlMallocAtomic); +} + +#undef xmlRealloc +xmlReallocFunc * +__xmlRealloc(void){ + if (IS_MAIN_THREAD) + return (&xmlRealloc); + else + return (&xmlGetGlobalState()->xmlRealloc); +} + +#undef xmlFree +xmlFreeFunc * +__xmlFree(void){ + if (IS_MAIN_THREAD) + return (&xmlFree); + else + return (&xmlGetGlobalState()->xmlFree); +} + +xmlStrdupFunc * +__xmlMemStrdup(void){ + if (IS_MAIN_THREAD) + return (&xmlMemStrdup); + else + return (&xmlGetGlobalState()->xmlMemStrdup); +} + +#endif + +/* + * Everything starting from the line below is + * Automatically generated by build_glob.py. + * Do not modify the previous line. + */ + + +#undef oldXMLWDcompatibility +int * +__oldXMLWDcompatibility(void) { + if (IS_MAIN_THREAD) + return (&oldXMLWDcompatibility); + else + return (&xmlGetGlobalState()->oldXMLWDcompatibility); +} + +#undef xmlBufferAllocScheme +xmlBufferAllocationScheme * +__xmlBufferAllocScheme(void) { + if (IS_MAIN_THREAD) + return (&xmlBufferAllocScheme); + else + return (&xmlGetGlobalState()->xmlBufferAllocScheme); +} +xmlBufferAllocationScheme xmlThrDefBufferAllocScheme(xmlBufferAllocationScheme v) { + xmlBufferAllocationScheme ret; + xmlMutexLock(xmlThrDefMutex); + ret = xmlBufferAllocSchemeThrDef; + xmlBufferAllocSchemeThrDef = v; + xmlMutexUnlock(xmlThrDefMutex); + return ret; +} + +#undef xmlDefaultBufferSize +int * +__xmlDefaultBufferSize(void) { + if (IS_MAIN_THREAD) + return (&xmlDefaultBufferSize); + else + return (&xmlGetGlobalState()->xmlDefaultBufferSize); +} +int xmlThrDefDefaultBufferSize(int v) { + int ret; + xmlMutexLock(xmlThrDefMutex); + ret = xmlDefaultBufferSizeThrDef; + xmlDefaultBufferSizeThrDef = v; + xmlMutexUnlock(xmlThrDefMutex); + return ret; +} + +#ifdef LIBXML_SAX1_ENABLED +#undef xmlDefaultSAXHandler +xmlSAXHandlerV1 * +__xmlDefaultSAXHandler(void) { + if (IS_MAIN_THREAD) + return (&xmlDefaultSAXHandler); + else + return (&xmlGetGlobalState()->xmlDefaultSAXHandler); +} +#endif /* LIBXML_SAX1_ENABLED */ + +#undef xmlDefaultSAXLocator +xmlSAXLocator * +__xmlDefaultSAXLocator(void) { + if (IS_MAIN_THREAD) + return (&xmlDefaultSAXLocator); + else + return (&xmlGetGlobalState()->xmlDefaultSAXLocator); +} + +#undef xmlDoValidityCheckingDefaultValue +int * +__xmlDoValidityCheckingDefaultValue(void) { + if (IS_MAIN_THREAD) + return (&xmlDoValidityCheckingDefaultValue); + else + return (&xmlGetGlobalState()->xmlDoValidityCheckingDefaultValue); +} +int xmlThrDefDoValidityCheckingDefaultValue(int v) { + int ret; + xmlMutexLock(xmlThrDefMutex); + ret = xmlDoValidityCheckingDefaultValueThrDef; + xmlDoValidityCheckingDefaultValueThrDef = v; + xmlMutexUnlock(xmlThrDefMutex); + return ret; +} + +#undef xmlGenericError +xmlGenericErrorFunc * +__xmlGenericError(void) { + if (IS_MAIN_THREAD) + return (&xmlGenericError); + else + return (&xmlGetGlobalState()->xmlGenericError); +} + +#undef xmlStructuredError +xmlStructuredErrorFunc * +__xmlStructuredError(void) { + if (IS_MAIN_THREAD) + return (&xmlStructuredError); + else + return (&xmlGetGlobalState()->xmlStructuredError); +} + +#undef xmlGenericErrorContext +void * * +__xmlGenericErrorContext(void) { + if (IS_MAIN_THREAD) + return (&xmlGenericErrorContext); + else + return (&xmlGetGlobalState()->xmlGenericErrorContext); +} + +#undef xmlStructuredErrorContext +void * * +__xmlStructuredErrorContext(void) { + if (IS_MAIN_THREAD) + return (&xmlStructuredErrorContext); + else + return (&xmlGetGlobalState()->xmlStructuredErrorContext); +} + +#undef xmlGetWarningsDefaultValue +int * +__xmlGetWarningsDefaultValue(void) { + if (IS_MAIN_THREAD) + return (&xmlGetWarningsDefaultValue); + else + return (&xmlGetGlobalState()->xmlGetWarningsDefaultValue); +} +int xmlThrDefGetWarningsDefaultValue(int v) { + int ret; + xmlMutexLock(xmlThrDefMutex); + ret = xmlGetWarningsDefaultValueThrDef; + xmlGetWarningsDefaultValueThrDef = v; + xmlMutexUnlock(xmlThrDefMutex); + return ret; +} + +#undef xmlIndentTreeOutput +int * +__xmlIndentTreeOutput(void) { + if (IS_MAIN_THREAD) + return (&xmlIndentTreeOutput); + else + return (&xmlGetGlobalState()->xmlIndentTreeOutput); +} +int xmlThrDefIndentTreeOutput(int v) { + int ret; + xmlMutexLock(xmlThrDefMutex); + ret = xmlIndentTreeOutputThrDef; + xmlIndentTreeOutputThrDef = v; + xmlMutexUnlock(xmlThrDefMutex); + return ret; +} + +#undef xmlTreeIndentString +const char * * +__xmlTreeIndentString(void) { + if (IS_MAIN_THREAD) + return (&xmlTreeIndentString); + else + return (&xmlGetGlobalState()->xmlTreeIndentString); +} +const char * xmlThrDefTreeIndentString(const char * v) { + const char * ret; + xmlMutexLock(xmlThrDefMutex); + ret = xmlTreeIndentStringThrDef; + xmlTreeIndentStringThrDef = v; + xmlMutexUnlock(xmlThrDefMutex); + return ret; +} + +#undef xmlKeepBlanksDefaultValue +int * +__xmlKeepBlanksDefaultValue(void) { + if (IS_MAIN_THREAD) + return (&xmlKeepBlanksDefaultValue); + else + return (&xmlGetGlobalState()->xmlKeepBlanksDefaultValue); +} +int xmlThrDefKeepBlanksDefaultValue(int v) { + int ret; + xmlMutexLock(xmlThrDefMutex); + ret = xmlKeepBlanksDefaultValueThrDef; + xmlKeepBlanksDefaultValueThrDef = v; + xmlMutexUnlock(xmlThrDefMutex); + return ret; +} + +#undef xmlLineNumbersDefaultValue +int * +__xmlLineNumbersDefaultValue(void) { + if (IS_MAIN_THREAD) + return (&xmlLineNumbersDefaultValue); + else + return (&xmlGetGlobalState()->xmlLineNumbersDefaultValue); +} +int xmlThrDefLineNumbersDefaultValue(int v) { + int ret; + xmlMutexLock(xmlThrDefMutex); + ret = xmlLineNumbersDefaultValueThrDef; + xmlLineNumbersDefaultValueThrDef = v; + xmlMutexUnlock(xmlThrDefMutex); + return ret; +} + +#undef xmlLoadExtDtdDefaultValue +int * +__xmlLoadExtDtdDefaultValue(void) { + if (IS_MAIN_THREAD) + return (&xmlLoadExtDtdDefaultValue); + else + return (&xmlGetGlobalState()->xmlLoadExtDtdDefaultValue); +} +int xmlThrDefLoadExtDtdDefaultValue(int v) { + int ret; + xmlMutexLock(xmlThrDefMutex); + ret = xmlLoadExtDtdDefaultValueThrDef; + xmlLoadExtDtdDefaultValueThrDef = v; + xmlMutexUnlock(xmlThrDefMutex); + return ret; +} + +#undef xmlParserDebugEntities +int * +__xmlParserDebugEntities(void) { + if (IS_MAIN_THREAD) + return (&xmlParserDebugEntities); + else + return (&xmlGetGlobalState()->xmlParserDebugEntities); +} +int xmlThrDefParserDebugEntities(int v) { + int ret; + xmlMutexLock(xmlThrDefMutex); + ret = xmlParserDebugEntitiesThrDef; + xmlParserDebugEntitiesThrDef = v; + xmlMutexUnlock(xmlThrDefMutex); + return ret; +} + +#undef xmlParserVersion +const char * * +__xmlParserVersion(void) { + if (IS_MAIN_THREAD) + return (&xmlParserVersion); + else + return (&xmlGetGlobalState()->xmlParserVersion); +} + +#undef xmlPedanticParserDefaultValue +int * +__xmlPedanticParserDefaultValue(void) { + if (IS_MAIN_THREAD) + return (&xmlPedanticParserDefaultValue); + else + return (&xmlGetGlobalState()->xmlPedanticParserDefaultValue); +} +int xmlThrDefPedanticParserDefaultValue(int v) { + int ret; + xmlMutexLock(xmlThrDefMutex); + ret = xmlPedanticParserDefaultValueThrDef; + xmlPedanticParserDefaultValueThrDef = v; + xmlMutexUnlock(xmlThrDefMutex); + return ret; +} + +#undef xmlSaveNoEmptyTags +int * +__xmlSaveNoEmptyTags(void) { + if (IS_MAIN_THREAD) + return (&xmlSaveNoEmptyTags); + else + return (&xmlGetGlobalState()->xmlSaveNoEmptyTags); +} +int xmlThrDefSaveNoEmptyTags(int v) { + int ret; + xmlMutexLock(xmlThrDefMutex); + ret = xmlSaveNoEmptyTagsThrDef; + xmlSaveNoEmptyTagsThrDef = v; + xmlMutexUnlock(xmlThrDefMutex); + return ret; +} + +#undef xmlSubstituteEntitiesDefaultValue +int * +__xmlSubstituteEntitiesDefaultValue(void) { + if (IS_MAIN_THREAD) + return (&xmlSubstituteEntitiesDefaultValue); + else + return (&xmlGetGlobalState()->xmlSubstituteEntitiesDefaultValue); +} +int xmlThrDefSubstituteEntitiesDefaultValue(int v) { + int ret; + xmlMutexLock(xmlThrDefMutex); + ret = xmlSubstituteEntitiesDefaultValueThrDef; + xmlSubstituteEntitiesDefaultValueThrDef = v; + xmlMutexUnlock(xmlThrDefMutex); + return ret; +} + +#undef xmlRegisterNodeDefaultValue +xmlRegisterNodeFunc * +__xmlRegisterNodeDefaultValue(void) { + if (IS_MAIN_THREAD) + return (&xmlRegisterNodeDefaultValue); + else + return (&xmlGetGlobalState()->xmlRegisterNodeDefaultValue); +} + +#undef xmlDeregisterNodeDefaultValue +xmlDeregisterNodeFunc * +__xmlDeregisterNodeDefaultValue(void) { + if (IS_MAIN_THREAD) + return (&xmlDeregisterNodeDefaultValue); + else + return (&xmlGetGlobalState()->xmlDeregisterNodeDefaultValue); +} + +#undef xmlParserInputBufferCreateFilenameValue +xmlParserInputBufferCreateFilenameFunc * +__xmlParserInputBufferCreateFilenameValue(void) { + if (IS_MAIN_THREAD) + return (&xmlParserInputBufferCreateFilenameValue); + else + return (&xmlGetGlobalState()->xmlParserInputBufferCreateFilenameValue); +} + +#undef xmlOutputBufferCreateFilenameValue +xmlOutputBufferCreateFilenameFunc * +__xmlOutputBufferCreateFilenameValue(void) { + if (IS_MAIN_THREAD) + return (&xmlOutputBufferCreateFilenameValue); + else + return (&xmlGetGlobalState()->xmlOutputBufferCreateFilenameValue); +} + +#define bottom_globals +#include "elfgcchack.h" diff --git a/android/native/libxml2/hash.c b/android/native/libxml2/hash.c new file mode 100644 index 0000000000..fe1424f291 --- /dev/null +++ b/android/native/libxml2/hash.c @@ -0,0 +1,1125 @@ +/* + * hash.c: chained hash tables + * + * Reference: Your favorite introductory book on algorithms + * + * Copyright (C) 2000,2012 Bjorn Reese and Daniel Veillard. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND + * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER. + * + * Author: breese@users.sourceforge.net + */ + +#define IN_LIBXML +#include "libxml.h" + +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_TIME_H +#include +#endif + +/* + * Following http://www.ocert.org/advisories/ocert-2011-003.html + * it seems that having hash randomization might be a good idea + * when using XML with untrusted data + */ +#if defined(HAVE_RAND) && defined(HAVE_SRAND) && defined(HAVE_TIME) +#define HASH_RANDOMIZATION +#endif + +#include +#include +#include +#include +#include + +#define MAX_HASH_LEN 8 + +/* #define DEBUG_GROW */ + +#ifdef HASH_RANDOMIZATION +static int hash_initialized = 0; +#endif + +/* + * A single entry in the hash table + */ +typedef struct _xmlHashEntry xmlHashEntry; +typedef xmlHashEntry *xmlHashEntryPtr; +struct _xmlHashEntry { + struct _xmlHashEntry *next; + xmlChar *name; + xmlChar *name2; + xmlChar *name3; + void *payload; + int valid; +}; + +/* + * The entire hash table + */ +struct _xmlHashTable { + struct _xmlHashEntry *table; + int size; + int nbElems; + xmlDictPtr dict; +#ifdef HASH_RANDOMIZATION + int random_seed; +#endif +}; + +/* + * xmlHashComputeKey: + * Calculate the hash key + */ +static unsigned long +xmlHashComputeKey(xmlHashTablePtr table, const xmlChar *name, + const xmlChar *name2, const xmlChar *name3) { + unsigned long value = 0L; + char ch; + +#ifdef HASH_RANDOMIZATION + value = table->random_seed; +#endif + if (name != NULL) { + value += 30 * (*name); + while ((ch = *name++) != 0) { + value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); + } + } + if (name2 != NULL) { + while ((ch = *name2++) != 0) { + value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); + } + } + if (name3 != NULL) { + while ((ch = *name3++) != 0) { + value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); + } + } + return (value % table->size); +} + +static unsigned long +xmlHashComputeQKey(xmlHashTablePtr table, + const xmlChar *prefix, const xmlChar *name, + const xmlChar *prefix2, const xmlChar *name2, + const xmlChar *prefix3, const xmlChar *name3) { + unsigned long value = 0L; + char ch; + +#ifdef HASH_RANDOMIZATION + value = table->random_seed; +#endif + if (prefix != NULL) + value += 30 * (*prefix); + else + value += 30 * (*name); + + if (prefix != NULL) { + while ((ch = *prefix++) != 0) { + value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); + } + value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':'); + } + if (name != NULL) { + while ((ch = *name++) != 0) { + value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); + } + } + if (prefix2 != NULL) { + while ((ch = *prefix2++) != 0) { + value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); + } + value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':'); + } + if (name2 != NULL) { + while ((ch = *name2++) != 0) { + value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); + } + } + if (prefix3 != NULL) { + while ((ch = *prefix3++) != 0) { + value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); + } + value = value ^ ((value << 5) + (value >> 3) + (unsigned long)':'); + } + if (name3 != NULL) { + while ((ch = *name3++) != 0) { + value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); + } + } + return (value % table->size); +} + +/** + * xmlHashCreate: + * @size: the size of the hash table + * + * Create a new xmlHashTablePtr. + * + * Returns the newly created object, or NULL if an error occured. + */ +xmlHashTablePtr +xmlHashCreate(int size) { + xmlHashTablePtr table; + + if (size <= 0) + size = 256; + + table = xmlMalloc(sizeof(xmlHashTable)); + if (table) { + table->dict = NULL; + table->size = size; + table->nbElems = 0; + table->table = xmlMalloc(size * sizeof(xmlHashEntry)); + if (table->table) { + memset(table->table, 0, size * sizeof(xmlHashEntry)); +#ifdef HASH_RANDOMIZATION + if (!hash_initialized) { + srand(time(NULL)); + hash_initialized = 1; + } + table->random_seed = rand(); +#endif + return(table); + } + xmlFree(table); + } + return(NULL); +} + +/** + * xmlHashCreateDict: + * @size: the size of the hash table + * @dict: a dictionary to use for the hash + * + * Create a new xmlHashTablePtr which will use @dict as the internal dictionary + * + * Returns the newly created object, or NULL if an error occured. + */ +xmlHashTablePtr +xmlHashCreateDict(int size, xmlDictPtr dict) { + xmlHashTablePtr table; + + table = xmlHashCreate(size); + if (table != NULL) { + table->dict = dict; + xmlDictReference(dict); + } + return(table); +} + +/** + * xmlHashGrow: + * @table: the hash table + * @size: the new size of the hash table + * + * resize the hash table + * + * Returns 0 in case of success, -1 in case of failure + */ +static int +xmlHashGrow(xmlHashTablePtr table, int size) { + unsigned long key; + int oldsize, i; + xmlHashEntryPtr iter, next; + struct _xmlHashEntry *oldtable; +#ifdef DEBUG_GROW + unsigned long nbElem = 0; +#endif + + if (table == NULL) + return(-1); + if (size < 8) + return(-1); + if (size > 8 * 2048) + return(-1); + + oldsize = table->size; + oldtable = table->table; + if (oldtable == NULL) + return(-1); + + table->table = xmlMalloc(size * sizeof(xmlHashEntry)); + if (table->table == NULL) { + table->table = oldtable; + return(-1); + } + memset(table->table, 0, size * sizeof(xmlHashEntry)); + table->size = size; + + /* If the two loops are merged, there would be situations where + a new entry needs to allocated and data copied into it from + the main table. So instead, we run through the array twice, first + copying all the elements in the main array (where we can't get + conflicts) and then the rest, so we only free (and don't allocate) + */ + for (i = 0; i < oldsize; i++) { + if (oldtable[i].valid == 0) + continue; + key = xmlHashComputeKey(table, oldtable[i].name, oldtable[i].name2, + oldtable[i].name3); + memcpy(&(table->table[key]), &(oldtable[i]), sizeof(xmlHashEntry)); + table->table[key].next = NULL; + } + + for (i = 0; i < oldsize; i++) { + iter = oldtable[i].next; + while (iter) { + next = iter->next; + + /* + * put back the entry in the new table + */ + + key = xmlHashComputeKey(table, iter->name, iter->name2, + iter->name3); + if (table->table[key].valid == 0) { + memcpy(&(table->table[key]), iter, sizeof(xmlHashEntry)); + table->table[key].next = NULL; + xmlFree(iter); + } else { + iter->next = table->table[key].next; + table->table[key].next = iter; + } + +#ifdef DEBUG_GROW + nbElem++; +#endif + + iter = next; + } + } + + xmlFree(oldtable); + +#ifdef DEBUG_GROW + xmlGenericError(xmlGenericErrorContext, + "xmlHashGrow : from %d to %d, %d elems\n", oldsize, size, nbElem); +#endif + + return(0); +} + +/** + * xmlHashFree: + * @table: the hash table + * @f: the deallocator function for items in the hash + * + * Free the hash @table and its contents. The userdata is + * deallocated with @f if provided. + */ +void +xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) { + int i; + xmlHashEntryPtr iter; + xmlHashEntryPtr next; + int inside_table = 0; + int nbElems; + + if (table == NULL) + return; + if (table->table) { + nbElems = table->nbElems; + for(i = 0; (i < table->size) && (nbElems > 0); i++) { + iter = &(table->table[i]); + if (iter->valid == 0) + continue; + inside_table = 1; + while (iter) { + next = iter->next; + if ((f != NULL) && (iter->payload != NULL)) + f(iter->payload, iter->name); + if (table->dict == NULL) { + if (iter->name) + xmlFree(iter->name); + if (iter->name2) + xmlFree(iter->name2); + if (iter->name3) + xmlFree(iter->name3); + } + iter->payload = NULL; + if (!inside_table) + xmlFree(iter); + nbElems--; + inside_table = 0; + iter = next; + } + } + xmlFree(table->table); + } + if (table->dict) + xmlDictFree(table->dict); + xmlFree(table); +} + +/** + * xmlHashAddEntry: + * @table: the hash table + * @name: the name of the userdata + * @userdata: a pointer to the userdata + * + * Add the @userdata to the hash @table. This can later be retrieved + * by using the @name. Duplicate names generate errors. + * + * Returns 0 the addition succeeded and -1 in case of error. + */ +int +xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata) { + return(xmlHashAddEntry3(table, name, NULL, NULL, userdata)); +} + +/** + * xmlHashAddEntry2: + * @table: the hash table + * @name: the name of the userdata + * @name2: a second name of the userdata + * @userdata: a pointer to the userdata + * + * Add the @userdata to the hash @table. This can later be retrieved + * by using the (@name, @name2) tuple. Duplicate tuples generate errors. + * + * Returns 0 the addition succeeded and -1 in case of error. + */ +int +xmlHashAddEntry2(xmlHashTablePtr table, const xmlChar *name, + const xmlChar *name2, void *userdata) { + return(xmlHashAddEntry3(table, name, name2, NULL, userdata)); +} + +/** + * xmlHashUpdateEntry: + * @table: the hash table + * @name: the name of the userdata + * @userdata: a pointer to the userdata + * @f: the deallocator function for replaced item (if any) + * + * Add the @userdata to the hash @table. This can later be retrieved + * by using the @name. Existing entry for this @name will be removed + * and freed with @f if found. + * + * Returns 0 the addition succeeded and -1 in case of error. + */ +int +xmlHashUpdateEntry(xmlHashTablePtr table, const xmlChar *name, + void *userdata, xmlHashDeallocator f) { + return(xmlHashUpdateEntry3(table, name, NULL, NULL, userdata, f)); +} + +/** + * xmlHashUpdateEntry2: + * @table: the hash table + * @name: the name of the userdata + * @name2: a second name of the userdata + * @userdata: a pointer to the userdata + * @f: the deallocator function for replaced item (if any) + * + * Add the @userdata to the hash @table. This can later be retrieved + * by using the (@name, @name2) tuple. Existing entry for this tuple will + * be removed and freed with @f if found. + * + * Returns 0 the addition succeeded and -1 in case of error. + */ +int +xmlHashUpdateEntry2(xmlHashTablePtr table, const xmlChar *name, + const xmlChar *name2, void *userdata, + xmlHashDeallocator f) { + return(xmlHashUpdateEntry3(table, name, name2, NULL, userdata, f)); +} + +/** + * xmlHashLookup: + * @table: the hash table + * @name: the name of the userdata + * + * Find the userdata specified by the @name. + * + * Returns the pointer to the userdata + */ +void * +xmlHashLookup(xmlHashTablePtr table, const xmlChar *name) { + return(xmlHashLookup3(table, name, NULL, NULL)); +} + +/** + * xmlHashLookup2: + * @table: the hash table + * @name: the name of the userdata + * @name2: a second name of the userdata + * + * Find the userdata specified by the (@name, @name2) tuple. + * + * Returns the pointer to the userdata + */ +void * +xmlHashLookup2(xmlHashTablePtr table, const xmlChar *name, + const xmlChar *name2) { + return(xmlHashLookup3(table, name, name2, NULL)); +} + +/** + * xmlHashQLookup: + * @table: the hash table + * @prefix: the prefix of the userdata + * @name: the name of the userdata + * + * Find the userdata specified by the QName @prefix:@name/@name. + * + * Returns the pointer to the userdata + */ +void * +xmlHashQLookup(xmlHashTablePtr table, const xmlChar *prefix, + const xmlChar *name) { + return(xmlHashQLookup3(table, prefix, name, NULL, NULL, NULL, NULL)); +} + +/** + * xmlHashQLookup2: + * @table: the hash table + * @prefix: the prefix of the userdata + * @name: the name of the userdata + * @prefix2: the second prefix of the userdata + * @name2: a second name of the userdata + * + * Find the userdata specified by the QNames tuple + * + * Returns the pointer to the userdata + */ +void * +xmlHashQLookup2(xmlHashTablePtr table, const xmlChar *prefix, + const xmlChar *name, const xmlChar *prefix2, + const xmlChar *name2) { + return(xmlHashQLookup3(table, prefix, name, prefix2, name2, NULL, NULL)); +} + +/** + * xmlHashAddEntry3: + * @table: the hash table + * @name: the name of the userdata + * @name2: a second name of the userdata + * @name3: a third name of the userdata + * @userdata: a pointer to the userdata + * + * Add the @userdata to the hash @table. This can later be retrieved + * by using the tuple (@name, @name2, @name3). Duplicate entries generate + * errors. + * + * Returns 0 the addition succeeded and -1 in case of error. + */ +int +xmlHashAddEntry3(xmlHashTablePtr table, const xmlChar *name, + const xmlChar *name2, const xmlChar *name3, + void *userdata) { + unsigned long key, len = 0; + xmlHashEntryPtr entry; + xmlHashEntryPtr insert; + + if ((table == NULL) || (name == NULL)) + return(-1); + + /* + * If using a dict internalize if needed + */ + if (table->dict) { + if (!xmlDictOwns(table->dict, name)) { + name = xmlDictLookup(table->dict, name, -1); + if (name == NULL) + return(-1); + } + if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) { + name2 = xmlDictLookup(table->dict, name2, -1); + if (name2 == NULL) + return(-1); + } + if ((name3 != NULL) && (!xmlDictOwns(table->dict, name3))) { + name3 = xmlDictLookup(table->dict, name3, -1); + if (name3 == NULL) + return(-1); + } + } + + /* + * Check for duplicate and insertion location. + */ + key = xmlHashComputeKey(table, name, name2, name3); + if (table->table[key].valid == 0) { + insert = NULL; + } else { + if (table->dict) { + for (insert = &(table->table[key]); insert->next != NULL; + insert = insert->next) { + if ((insert->name == name) && + (insert->name2 == name2) && + (insert->name3 == name3)) + return(-1); + len++; + } + if ((insert->name == name) && + (insert->name2 == name2) && + (insert->name3 == name3)) + return(-1); + } else { + for (insert = &(table->table[key]); insert->next != NULL; + insert = insert->next) { + if ((xmlStrEqual(insert->name, name)) && + (xmlStrEqual(insert->name2, name2)) && + (xmlStrEqual(insert->name3, name3))) + return(-1); + len++; + } + if ((xmlStrEqual(insert->name, name)) && + (xmlStrEqual(insert->name2, name2)) && + (xmlStrEqual(insert->name3, name3))) + return(-1); + } + } + + if (insert == NULL) { + entry = &(table->table[key]); + } else { + entry = xmlMalloc(sizeof(xmlHashEntry)); + if (entry == NULL) + return(-1); + } + + if (table->dict != NULL) { + entry->name = (xmlChar *) name; + entry->name2 = (xmlChar *) name2; + entry->name3 = (xmlChar *) name3; + } else { + entry->name = xmlStrdup(name); + entry->name2 = xmlStrdup(name2); + entry->name3 = xmlStrdup(name3); + } + entry->payload = userdata; + entry->next = NULL; + entry->valid = 1; + + + if (insert != NULL) + insert->next = entry; + + table->nbElems++; + + if (len > MAX_HASH_LEN) + xmlHashGrow(table, MAX_HASH_LEN * table->size); + + return(0); +} + +/** + * xmlHashUpdateEntry3: + * @table: the hash table + * @name: the name of the userdata + * @name2: a second name of the userdata + * @name3: a third name of the userdata + * @userdata: a pointer to the userdata + * @f: the deallocator function for replaced item (if any) + * + * Add the @userdata to the hash @table. This can later be retrieved + * by using the tuple (@name, @name2, @name3). Existing entry for this tuple + * will be removed and freed with @f if found. + * + * Returns 0 the addition succeeded and -1 in case of error. + */ +int +xmlHashUpdateEntry3(xmlHashTablePtr table, const xmlChar *name, + const xmlChar *name2, const xmlChar *name3, + void *userdata, xmlHashDeallocator f) { + unsigned long key; + xmlHashEntryPtr entry; + xmlHashEntryPtr insert; + + if ((table == NULL) || name == NULL) + return(-1); + + /* + * If using a dict internalize if needed + */ + if (table->dict) { + if (!xmlDictOwns(table->dict, name)) { + name = xmlDictLookup(table->dict, name, -1); + if (name == NULL) + return(-1); + } + if ((name2 != NULL) && (!xmlDictOwns(table->dict, name2))) { + name2 = xmlDictLookup(table->dict, name2, -1); + if (name2 == NULL) + return(-1); + } + if ((name3 != NULL) && (!xmlDictOwns(table->dict, name3))) { + name3 = xmlDictLookup(table->dict, name3, -1); + if (name3 == NULL) + return(-1); + } + } + + /* + * Check for duplicate and insertion location. + */ + key = xmlHashComputeKey(table, name, name2, name3); + if (table->table[key].valid == 0) { + insert = NULL; + } else { + if (table ->dict) { + for (insert = &(table->table[key]); insert->next != NULL; + insert = insert->next) { + if ((insert->name == name) && + (insert->name2 == name2) && + (insert->name3 == name3)) { + if (f) + f(insert->payload, insert->name); + insert->payload = userdata; + return(0); + } + } + if ((insert->name == name) && + (insert->name2 == name2) && + (insert->name3 == name3)) { + if (f) + f(insert->payload, insert->name); + insert->payload = userdata; + return(0); + } + } else { + for (insert = &(table->table[key]); insert->next != NULL; + insert = insert->next) { + if ((xmlStrEqual(insert->name, name)) && + (xmlStrEqual(insert->name2, name2)) && + (xmlStrEqual(insert->name3, name3))) { + if (f) + f(insert->payload, insert->name); + insert->payload = userdata; + return(0); + } + } + if ((xmlStrEqual(insert->name, name)) && + (xmlStrEqual(insert->name2, name2)) && + (xmlStrEqual(insert->name3, name3))) { + if (f) + f(insert->payload, insert->name); + insert->payload = userdata; + return(0); + } + } + } + + if (insert == NULL) { + entry = &(table->table[key]); + } else { + entry = xmlMalloc(sizeof(xmlHashEntry)); + if (entry == NULL) + return(-1); + } + + if (table->dict != NULL) { + entry->name = (xmlChar *) name; + entry->name2 = (xmlChar *) name2; + entry->name3 = (xmlChar *) name3; + } else { + entry->name = xmlStrdup(name); + entry->name2 = xmlStrdup(name2); + entry->name3 = xmlStrdup(name3); + } + entry->payload = userdata; + entry->next = NULL; + entry->valid = 1; + table->nbElems++; + + + if (insert != NULL) { + insert->next = entry; + } + return(0); +} + +/** + * xmlHashLookup3: + * @table: the hash table + * @name: the name of the userdata + * @name2: a second name of the userdata + * @name3: a third name of the userdata + * + * Find the userdata specified by the (@name, @name2, @name3) tuple. + * + * Returns the a pointer to the userdata + */ +void * +xmlHashLookup3(xmlHashTablePtr table, const xmlChar *name, + const xmlChar *name2, const xmlChar *name3) { + unsigned long key; + xmlHashEntryPtr entry; + + if (table == NULL) + return(NULL); + if (name == NULL) + return(NULL); + key = xmlHashComputeKey(table, name, name2, name3); + if (table->table[key].valid == 0) + return(NULL); + if (table->dict) { + for (entry = &(table->table[key]); entry != NULL; entry = entry->next) { + if ((entry->name == name) && + (entry->name2 == name2) && + (entry->name3 == name3)) + return(entry->payload); + } + } + for (entry = &(table->table[key]); entry != NULL; entry = entry->next) { + if ((xmlStrEqual(entry->name, name)) && + (xmlStrEqual(entry->name2, name2)) && + (xmlStrEqual(entry->name3, name3))) + return(entry->payload); + } + return(NULL); +} + +/** + * xmlHashQLookup3: + * @table: the hash table + * @prefix: the prefix of the userdata + * @name: the name of the userdata + * @prefix2: the second prefix of the userdata + * @name2: a second name of the userdata + * @prefix3: the third prefix of the userdata + * @name3: a third name of the userdata + * + * Find the userdata specified by the (@name, @name2, @name3) tuple. + * + * Returns the a pointer to the userdata + */ +void * +xmlHashQLookup3(xmlHashTablePtr table, + const xmlChar *prefix, const xmlChar *name, + const xmlChar *prefix2, const xmlChar *name2, + const xmlChar *prefix3, const xmlChar *name3) { + unsigned long key; + xmlHashEntryPtr entry; + + if (table == NULL) + return(NULL); + if (name == NULL) + return(NULL); + key = xmlHashComputeQKey(table, prefix, name, prefix2, + name2, prefix3, name3); + if (table->table[key].valid == 0) + return(NULL); + for (entry = &(table->table[key]); entry != NULL; entry = entry->next) { + if ((xmlStrQEqual(prefix, name, entry->name)) && + (xmlStrQEqual(prefix2, name2, entry->name2)) && + (xmlStrQEqual(prefix3, name3, entry->name3))) + return(entry->payload); + } + return(NULL); +} + +typedef struct { + xmlHashScanner hashscanner; + void *data; +} stubData; + +static void +stubHashScannerFull (void *payload, void *data, const xmlChar *name, + const xmlChar *name2 ATTRIBUTE_UNUSED, + const xmlChar *name3 ATTRIBUTE_UNUSED) { + stubData *stubdata = (stubData *) data; + stubdata->hashscanner (payload, stubdata->data, (xmlChar *) name); +} + +/** + * xmlHashScan: + * @table: the hash table + * @f: the scanner function for items in the hash + * @data: extra data passed to f + * + * Scan the hash @table and applied @f to each value. + */ +void +xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data) { + stubData stubdata; + stubdata.data = data; + stubdata.hashscanner = f; + xmlHashScanFull (table, stubHashScannerFull, &stubdata); +} + +/** + * xmlHashScanFull: + * @table: the hash table + * @f: the scanner function for items in the hash + * @data: extra data passed to f + * + * Scan the hash @table and applied @f to each value. + */ +void +xmlHashScanFull(xmlHashTablePtr table, xmlHashScannerFull f, void *data) { + int i, nb; + xmlHashEntryPtr iter; + xmlHashEntryPtr next; + + if (table == NULL) + return; + if (f == NULL) + return; + + if (table->table) { + for(i = 0; i < table->size; i++) { + if (table->table[i].valid == 0) + continue; + iter = &(table->table[i]); + while (iter) { + next = iter->next; + nb = table->nbElems; + if ((f != NULL) && (iter->payload != NULL)) + f(iter->payload, data, iter->name, + iter->name2, iter->name3); + if (nb != table->nbElems) { + /* table was modified by the callback, be careful */ + if (iter == &(table->table[i])) { + if (table->table[i].valid == 0) + iter = NULL; + if (table->table[i].next != next) + iter = &(table->table[i]); + } else + iter = next; + } else + iter = next; + } + } + } +} + +/** + * xmlHashScan3: + * @table: the hash table + * @name: the name of the userdata or NULL + * @name2: a second name of the userdata or NULL + * @name3: a third name of the userdata or NULL + * @f: the scanner function for items in the hash + * @data: extra data passed to f + * + * Scan the hash @table and applied @f to each value matching + * (@name, @name2, @name3) tuple. If one of the names is null, + * the comparison is considered to match. + */ +void +xmlHashScan3(xmlHashTablePtr table, const xmlChar *name, + const xmlChar *name2, const xmlChar *name3, + xmlHashScanner f, void *data) { + xmlHashScanFull3 (table, name, name2, name3, + (xmlHashScannerFull) f, data); +} + +/** + * xmlHashScanFull3: + * @table: the hash table + * @name: the name of the userdata or NULL + * @name2: a second name of the userdata or NULL + * @name3: a third name of the userdata or NULL + * @f: the scanner function for items in the hash + * @data: extra data passed to f + * + * Scan the hash @table and applied @f to each value matching + * (@name, @name2, @name3) tuple. If one of the names is null, + * the comparison is considered to match. + */ +void +xmlHashScanFull3(xmlHashTablePtr table, const xmlChar *name, + const xmlChar *name2, const xmlChar *name3, + xmlHashScannerFull f, void *data) { + int i; + xmlHashEntryPtr iter; + xmlHashEntryPtr next; + + if (table == NULL) + return; + if (f == NULL) + return; + + if (table->table) { + for(i = 0; i < table->size; i++) { + if (table->table[i].valid == 0) + continue; + iter = &(table->table[i]); + while (iter) { + next = iter->next; + if (((name == NULL) || (xmlStrEqual(name, iter->name))) && + ((name2 == NULL) || (xmlStrEqual(name2, iter->name2))) && + ((name3 == NULL) || (xmlStrEqual(name3, iter->name3))) && + (iter->payload != NULL)) { + f(iter->payload, data, iter->name, + iter->name2, iter->name3); + } + iter = next; + } + } + } +} + +/** + * xmlHashCopy: + * @table: the hash table + * @f: the copier function for items in the hash + * + * Scan the hash @table and applied @f to each value. + * + * Returns the new table or NULL in case of error. + */ +xmlHashTablePtr +xmlHashCopy(xmlHashTablePtr table, xmlHashCopier f) { + int i; + xmlHashEntryPtr iter; + xmlHashEntryPtr next; + xmlHashTablePtr ret; + + if (table == NULL) + return(NULL); + if (f == NULL) + return(NULL); + + ret = xmlHashCreate(table->size); + if (table->table) { + for(i = 0; i < table->size; i++) { + if (table->table[i].valid == 0) + continue; + iter = &(table->table[i]); + while (iter) { + next = iter->next; + xmlHashAddEntry3(ret, iter->name, iter->name2, + iter->name3, f(iter->payload, iter->name)); + iter = next; + } + } + } + ret->nbElems = table->nbElems; + return(ret); +} + +/** + * xmlHashSize: + * @table: the hash table + * + * Query the number of elements installed in the hash @table. + * + * Returns the number of elements in the hash table or + * -1 in case of error + */ +int +xmlHashSize(xmlHashTablePtr table) { + if (table == NULL) + return(-1); + return(table->nbElems); +} + +/** + * xmlHashRemoveEntry: + * @table: the hash table + * @name: the name of the userdata + * @f: the deallocator function for removed item (if any) + * + * Find the userdata specified by the @name and remove + * it from the hash @table. Existing userdata for this tuple will be removed + * and freed with @f. + * + * Returns 0 if the removal succeeded and -1 in case of error or not found. + */ +int xmlHashRemoveEntry(xmlHashTablePtr table, const xmlChar *name, + xmlHashDeallocator f) { + return(xmlHashRemoveEntry3(table, name, NULL, NULL, f)); +} + +/** + * xmlHashRemoveEntry2: + * @table: the hash table + * @name: the name of the userdata + * @name2: a second name of the userdata + * @f: the deallocator function for removed item (if any) + * + * Find the userdata specified by the (@name, @name2) tuple and remove + * it from the hash @table. Existing userdata for this tuple will be removed + * and freed with @f. + * + * Returns 0 if the removal succeeded and -1 in case of error or not found. + */ +int +xmlHashRemoveEntry2(xmlHashTablePtr table, const xmlChar *name, + const xmlChar *name2, xmlHashDeallocator f) { + return(xmlHashRemoveEntry3(table, name, name2, NULL, f)); +} + +/** + * xmlHashRemoveEntry3: + * @table: the hash table + * @name: the name of the userdata + * @name2: a second name of the userdata + * @name3: a third name of the userdata + * @f: the deallocator function for removed item (if any) + * + * Find the userdata specified by the (@name, @name2, @name3) tuple and remove + * it from the hash @table. Existing userdata for this tuple will be removed + * and freed with @f. + * + * Returns 0 if the removal succeeded and -1 in case of error or not found. + */ +int +xmlHashRemoveEntry3(xmlHashTablePtr table, const xmlChar *name, + const xmlChar *name2, const xmlChar *name3, xmlHashDeallocator f) { + unsigned long key; + xmlHashEntryPtr entry; + xmlHashEntryPtr prev = NULL; + + if (table == NULL || name == NULL) + return(-1); + + key = xmlHashComputeKey(table, name, name2, name3); + if (table->table[key].valid == 0) { + return(-1); + } else { + for (entry = &(table->table[key]); entry != NULL; entry = entry->next) { + if (xmlStrEqual(entry->name, name) && + xmlStrEqual(entry->name2, name2) && + xmlStrEqual(entry->name3, name3)) { + if ((f != NULL) && (entry->payload != NULL)) + f(entry->payload, entry->name); + entry->payload = NULL; + if (table->dict == NULL) { + if(entry->name) + xmlFree(entry->name); + if(entry->name2) + xmlFree(entry->name2); + if(entry->name3) + xmlFree(entry->name3); + } + if(prev) { + prev->next = entry->next; + xmlFree(entry); + } else { + if (entry->next == NULL) { + entry->valid = 0; + } else { + entry = entry->next; + memcpy(&(table->table[key]), entry, sizeof(xmlHashEntry)); + xmlFree(entry); + } + } + table->nbElems--; + return(0); + } + prev = entry; + } + return(-1); + } +} + +#define bottom_hash +#include "elfgcchack.h" diff --git a/android/native/libxml2/legacy.c b/android/native/libxml2/legacy.c new file mode 100644 index 0000000000..ea6cf97b4e --- /dev/null +++ b/android/native/libxml2/legacy.c @@ -0,0 +1,1307 @@ +/* + * legacy.c: set of deprecated routines, not to be used anymore but + * kept purely for ABI compatibility + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + */ + +#define IN_LIBXML +#include "libxml.h" + +#ifdef LIBXML_LEGACY_ENABLED +#include + +#include +#include +#include +#include +#include + +void xmlUpgradeOldNs(xmlDocPtr doc); + +/************************************************************************ + * * + * Deprecated functions kept for compatibility * + * * + ************************************************************************/ + +/** + * xmlInitializePredefinedEntities: + * + * Set up the predefined entities. + * Deprecated call + */ +void +xmlInitializePredefinedEntities(void) +{ +} + +/** + * xmlCleanupPredefinedEntities: + * + * Cleanup up the predefined entities table. + * Deprecated call + */ +void +xmlCleanupPredefinedEntities(void) +{ +} + +static const char *xmlFeaturesList[] = { + "validate", + "load subset", + "keep blanks", + "disable SAX", + "fetch external entities", + "substitute entities", + "gather line info", + "user data", + "is html", + "is standalone", + "stop parser", + "document", + "is well formed", + "is valid", + "SAX block", + "SAX function internalSubset", + "SAX function isStandalone", + "SAX function hasInternalSubset", + "SAX function hasExternalSubset", + "SAX function resolveEntity", + "SAX function getEntity", + "SAX function entityDecl", + "SAX function notationDecl", + "SAX function attributeDecl", + "SAX function elementDecl", + "SAX function unparsedEntityDecl", + "SAX function setDocumentLocator", + "SAX function startDocument", + "SAX function endDocument", + "SAX function startElement", + "SAX function endElement", + "SAX function reference", + "SAX function characters", + "SAX function ignorableWhitespace", + "SAX function processingInstruction", + "SAX function comment", + "SAX function warning", + "SAX function error", + "SAX function fatalError", + "SAX function getParameterEntity", + "SAX function cdataBlock", + "SAX function externalSubset", +}; + +/** + * xmlGetFeaturesList: + * @len: the length of the features name array (input/output) + * @result: an array of string to be filled with the features name. + * + * Copy at most *@len feature names into the @result array + * + * Returns -1 in case or error, or the total number of features, + * len is updated with the number of strings copied, + * strings must not be deallocated + */ +int +xmlGetFeaturesList(int *len, const char **result) +{ + int ret, i; + + ret = sizeof(xmlFeaturesList) / sizeof(xmlFeaturesList[0]); + if ((len == NULL) || (result == NULL)) + return (ret); + if ((*len < 0) || (*len >= 1000)) + return (-1); + if (*len > ret) + *len = ret; + for (i = 0; i < *len; i++) + result[i] = xmlFeaturesList[i]; + return (ret); +} + +/** + * xmlGetFeature: + * @ctxt: an XML/HTML parser context + * @name: the feature name + * @result: location to store the result + * + * Read the current value of one feature of this parser instance + * + * Returns -1 in case or error, 0 otherwise + */ +int +xmlGetFeature(xmlParserCtxtPtr ctxt, const char *name, void *result) +{ + if ((ctxt == NULL) || (name == NULL) || (result == NULL)) + return (-1); + + if (!strcmp(name, "validate")) { + *((int *) result) = ctxt->validate; + } else if (!strcmp(name, "keep blanks")) { + *((int *) result) = ctxt->keepBlanks; + } else if (!strcmp(name, "disable SAX")) { + *((int *) result) = ctxt->disableSAX; + } else if (!strcmp(name, "fetch external entities")) { + *((int *) result) = ctxt->loadsubset; + } else if (!strcmp(name, "substitute entities")) { + *((int *) result) = ctxt->replaceEntities; + } else if (!strcmp(name, "gather line info")) { + *((int *) result) = ctxt->record_info; + } else if (!strcmp(name, "user data")) { + *((void **) result) = ctxt->userData; + } else if (!strcmp(name, "is html")) { + *((int *) result) = ctxt->html; + } else if (!strcmp(name, "is standalone")) { + *((int *) result) = ctxt->standalone; + } else if (!strcmp(name, "document")) { + *((xmlDocPtr *) result) = ctxt->myDoc; + } else if (!strcmp(name, "is well formed")) { + *((int *) result) = ctxt->wellFormed; + } else if (!strcmp(name, "is valid")) { + *((int *) result) = ctxt->valid; + } else if (!strcmp(name, "SAX block")) { + *((xmlSAXHandlerPtr *) result) = ctxt->sax; + } else if (!strcmp(name, "SAX function internalSubset")) { + *((internalSubsetSAXFunc *) result) = ctxt->sax->internalSubset; + } else if (!strcmp(name, "SAX function isStandalone")) { + *((isStandaloneSAXFunc *) result) = ctxt->sax->isStandalone; + } else if (!strcmp(name, "SAX function hasInternalSubset")) { + *((hasInternalSubsetSAXFunc *) result) = + ctxt->sax->hasInternalSubset; + } else if (!strcmp(name, "SAX function hasExternalSubset")) { + *((hasExternalSubsetSAXFunc *) result) = + ctxt->sax->hasExternalSubset; + } else if (!strcmp(name, "SAX function resolveEntity")) { + *((resolveEntitySAXFunc *) result) = ctxt->sax->resolveEntity; + } else if (!strcmp(name, "SAX function getEntity")) { + *((getEntitySAXFunc *) result) = ctxt->sax->getEntity; + } else if (!strcmp(name, "SAX function entityDecl")) { + *((entityDeclSAXFunc *) result) = ctxt->sax->entityDecl; + } else if (!strcmp(name, "SAX function notationDecl")) { + *((notationDeclSAXFunc *) result) = ctxt->sax->notationDecl; + } else if (!strcmp(name, "SAX function attributeDecl")) { + *((attributeDeclSAXFunc *) result) = ctxt->sax->attributeDecl; + } else if (!strcmp(name, "SAX function elementDecl")) { + *((elementDeclSAXFunc *) result) = ctxt->sax->elementDecl; + } else if (!strcmp(name, "SAX function unparsedEntityDecl")) { + *((unparsedEntityDeclSAXFunc *) result) = + ctxt->sax->unparsedEntityDecl; + } else if (!strcmp(name, "SAX function setDocumentLocator")) { + *((setDocumentLocatorSAXFunc *) result) = + ctxt->sax->setDocumentLocator; + } else if (!strcmp(name, "SAX function startDocument")) { + *((startDocumentSAXFunc *) result) = ctxt->sax->startDocument; + } else if (!strcmp(name, "SAX function endDocument")) { + *((endDocumentSAXFunc *) result) = ctxt->sax->endDocument; + } else if (!strcmp(name, "SAX function startElement")) { + *((startElementSAXFunc *) result) = ctxt->sax->startElement; + } else if (!strcmp(name, "SAX function endElement")) { + *((endElementSAXFunc *) result) = ctxt->sax->endElement; + } else if (!strcmp(name, "SAX function reference")) { + *((referenceSAXFunc *) result) = ctxt->sax->reference; + } else if (!strcmp(name, "SAX function characters")) { + *((charactersSAXFunc *) result) = ctxt->sax->characters; + } else if (!strcmp(name, "SAX function ignorableWhitespace")) { + *((ignorableWhitespaceSAXFunc *) result) = + ctxt->sax->ignorableWhitespace; + } else if (!strcmp(name, "SAX function processingInstruction")) { + *((processingInstructionSAXFunc *) result) = + ctxt->sax->processingInstruction; + } else if (!strcmp(name, "SAX function comment")) { + *((commentSAXFunc *) result) = ctxt->sax->comment; + } else if (!strcmp(name, "SAX function warning")) { + *((warningSAXFunc *) result) = ctxt->sax->warning; + } else if (!strcmp(name, "SAX function error")) { + *((errorSAXFunc *) result) = ctxt->sax->error; + } else if (!strcmp(name, "SAX function fatalError")) { + *((fatalErrorSAXFunc *) result) = ctxt->sax->fatalError; + } else if (!strcmp(name, "SAX function getParameterEntity")) { + *((getParameterEntitySAXFunc *) result) = + ctxt->sax->getParameterEntity; + } else if (!strcmp(name, "SAX function cdataBlock")) { + *((cdataBlockSAXFunc *) result) = ctxt->sax->cdataBlock; + } else if (!strcmp(name, "SAX function externalSubset")) { + *((externalSubsetSAXFunc *) result) = ctxt->sax->externalSubset; + } else { + return (-1); + } + return (0); +} + +/** + * xmlSetFeature: + * @ctxt: an XML/HTML parser context + * @name: the feature name + * @value: pointer to the location of the new value + * + * Change the current value of one feature of this parser instance + * + * Returns -1 in case or error, 0 otherwise + */ +int +xmlSetFeature(xmlParserCtxtPtr ctxt, const char *name, void *value) +{ + if ((ctxt == NULL) || (name == NULL) || (value == NULL)) + return (-1); + + if (!strcmp(name, "validate")) { + int newvalidate = *((int *) value); + + if ((!ctxt->validate) && (newvalidate != 0)) { + if (ctxt->vctxt.warning == NULL) + ctxt->vctxt.warning = xmlParserValidityWarning; + if (ctxt->vctxt.error == NULL) + ctxt->vctxt.error = xmlParserValidityError; + ctxt->vctxt.nodeMax = 0; + } + ctxt->validate = newvalidate; + } else if (!strcmp(name, "keep blanks")) { + ctxt->keepBlanks = *((int *) value); + } else if (!strcmp(name, "disable SAX")) { + ctxt->disableSAX = *((int *) value); + } else if (!strcmp(name, "fetch external entities")) { + ctxt->loadsubset = *((int *) value); + } else if (!strcmp(name, "substitute entities")) { + ctxt->replaceEntities = *((int *) value); + } else if (!strcmp(name, "gather line info")) { + ctxt->record_info = *((int *) value); + } else if (!strcmp(name, "user data")) { + ctxt->userData = *((void **) value); + } else if (!strcmp(name, "is html")) { + ctxt->html = *((int *) value); + } else if (!strcmp(name, "is standalone")) { + ctxt->standalone = *((int *) value); + } else if (!strcmp(name, "document")) { + ctxt->myDoc = *((xmlDocPtr *) value); + } else if (!strcmp(name, "is well formed")) { + ctxt->wellFormed = *((int *) value); + } else if (!strcmp(name, "is valid")) { + ctxt->valid = *((int *) value); + } else if (!strcmp(name, "SAX block")) { + ctxt->sax = *((xmlSAXHandlerPtr *) value); + } else if (!strcmp(name, "SAX function internalSubset")) { + ctxt->sax->internalSubset = *((internalSubsetSAXFunc *) value); + } else if (!strcmp(name, "SAX function isStandalone")) { + ctxt->sax->isStandalone = *((isStandaloneSAXFunc *) value); + } else if (!strcmp(name, "SAX function hasInternalSubset")) { + ctxt->sax->hasInternalSubset = + *((hasInternalSubsetSAXFunc *) value); + } else if (!strcmp(name, "SAX function hasExternalSubset")) { + ctxt->sax->hasExternalSubset = + *((hasExternalSubsetSAXFunc *) value); + } else if (!strcmp(name, "SAX function resolveEntity")) { + ctxt->sax->resolveEntity = *((resolveEntitySAXFunc *) value); + } else if (!strcmp(name, "SAX function getEntity")) { + ctxt->sax->getEntity = *((getEntitySAXFunc *) value); + } else if (!strcmp(name, "SAX function entityDecl")) { + ctxt->sax->entityDecl = *((entityDeclSAXFunc *) value); + } else if (!strcmp(name, "SAX function notationDecl")) { + ctxt->sax->notationDecl = *((notationDeclSAXFunc *) value); + } else if (!strcmp(name, "SAX function attributeDecl")) { + ctxt->sax->attributeDecl = *((attributeDeclSAXFunc *) value); + } else if (!strcmp(name, "SAX function elementDecl")) { + ctxt->sax->elementDecl = *((elementDeclSAXFunc *) value); + } else if (!strcmp(name, "SAX function unparsedEntityDecl")) { + ctxt->sax->unparsedEntityDecl = + *((unparsedEntityDeclSAXFunc *) value); + } else if (!strcmp(name, "SAX function setDocumentLocator")) { + ctxt->sax->setDocumentLocator = + *((setDocumentLocatorSAXFunc *) value); + } else if (!strcmp(name, "SAX function startDocument")) { + ctxt->sax->startDocument = *((startDocumentSAXFunc *) value); + } else if (!strcmp(name, "SAX function endDocument")) { + ctxt->sax->endDocument = *((endDocumentSAXFunc *) value); + } else if (!strcmp(name, "SAX function startElement")) { + ctxt->sax->startElement = *((startElementSAXFunc *) value); + } else if (!strcmp(name, "SAX function endElement")) { + ctxt->sax->endElement = *((endElementSAXFunc *) value); + } else if (!strcmp(name, "SAX function reference")) { + ctxt->sax->reference = *((referenceSAXFunc *) value); + } else if (!strcmp(name, "SAX function characters")) { + ctxt->sax->characters = *((charactersSAXFunc *) value); + } else if (!strcmp(name, "SAX function ignorableWhitespace")) { + ctxt->sax->ignorableWhitespace = + *((ignorableWhitespaceSAXFunc *) value); + } else if (!strcmp(name, "SAX function processingInstruction")) { + ctxt->sax->processingInstruction = + *((processingInstructionSAXFunc *) value); + } else if (!strcmp(name, "SAX function comment")) { + ctxt->sax->comment = *((commentSAXFunc *) value); + } else if (!strcmp(name, "SAX function warning")) { + ctxt->sax->warning = *((warningSAXFunc *) value); + } else if (!strcmp(name, "SAX function error")) { + ctxt->sax->error = *((errorSAXFunc *) value); + } else if (!strcmp(name, "SAX function fatalError")) { + ctxt->sax->fatalError = *((fatalErrorSAXFunc *) value); + } else if (!strcmp(name, "SAX function getParameterEntity")) { + ctxt->sax->getParameterEntity = + *((getParameterEntitySAXFunc *) value); + } else if (!strcmp(name, "SAX function cdataBlock")) { + ctxt->sax->cdataBlock = *((cdataBlockSAXFunc *) value); + } else if (!strcmp(name, "SAX function externalSubset")) { + ctxt->sax->externalSubset = *((externalSubsetSAXFunc *) value); + } else { + return (-1); + } + return (0); +} + +/** + * xmlDecodeEntities: + * @ctxt: the parser context + * @len: the len to decode (in bytes !), -1 for no size limit + * @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 + * + * This function is deprecated, we now always process entities content + * through xmlStringDecodeEntities + * + * TODO: remove it in next major release. + * + * [67] Reference ::= EntityRef | CharRef + * + * [69] PEReference ::= '%' Name ';' + * + * Returns A newly allocated string with the substitution done. The caller + * must deallocate it ! + */ +xmlChar * +xmlDecodeEntities(xmlParserCtxtPtr ctxt ATTRIBUTE_UNUSED, + int len ATTRIBUTE_UNUSED, int what ATTRIBUTE_UNUSED, + xmlChar end ATTRIBUTE_UNUSED, + xmlChar end2 ATTRIBUTE_UNUSED, + xmlChar end3 ATTRIBUTE_UNUSED) +{ + static int deprecated = 0; + + if (!deprecated) { + xmlGenericError(xmlGenericErrorContext, + "xmlDecodeEntities() deprecated function reached\n"); + deprecated = 1; + } + return (NULL); +} + +/** + * xmlNamespaceParseNCName: + * @ctxt: an XML parser context + * + * parse an XML namespace name. + * + * TODO: this seems not in use anymore, the namespace handling is done on + * top of the SAX interfaces, i.e. not on raw input. + * + * [NS 3] NCName ::= (Letter | '_') (NCNameChar)* + * + * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' | + * CombiningChar | Extender + * + * Returns the namespace name or NULL + */ + +xmlChar * +xmlNamespaceParseNCName(xmlParserCtxtPtr ctxt ATTRIBUTE_UNUSED) +{ + static int deprecated = 0; + + if (!deprecated) { + xmlGenericError(xmlGenericErrorContext, + "xmlNamespaceParseNCName() deprecated function reached\n"); + deprecated = 1; + } + return (NULL); +} + +/** + * xmlNamespaceParseQName: + * @ctxt: an XML parser context + * @prefix: a xmlChar ** + * + * TODO: this seems not in use anymore, the namespace handling is done on + * top of the SAX interfaces, i.e. not on raw input. + * + * parse an XML qualified name + * + * [NS 5] QName ::= (Prefix ':')? LocalPart + * + * [NS 6] Prefix ::= NCName + * + * [NS 7] LocalPart ::= NCName + * + * Returns the local part, and prefix is updated + * to get the Prefix if any. + */ + +xmlChar * +xmlNamespaceParseQName(xmlParserCtxtPtr ctxt ATTRIBUTE_UNUSED, + xmlChar ** prefix ATTRIBUTE_UNUSED) +{ + + static int deprecated = 0; + + if (!deprecated) { + xmlGenericError(xmlGenericErrorContext, + "xmlNamespaceParseQName() deprecated function reached\n"); + deprecated = 1; + } + return (NULL); +} + +/** + * xmlNamespaceParseNSDef: + * @ctxt: an XML parser context + * + * parse a namespace prefix declaration + * + * TODO: this seems not in use anymore, the namespace handling is done on + * top of the SAX interfaces, i.e. not on raw input. + * + * [NS 1] NSDef ::= PrefixDef Eq SystemLiteral + * + * [NS 2] PrefixDef ::= 'xmlns' (':' NCName)? + * + * Returns the namespace name + */ + +xmlChar * +xmlNamespaceParseNSDef(xmlParserCtxtPtr ctxt ATTRIBUTE_UNUSED) +{ + static int deprecated = 0; + + if (!deprecated) { + xmlGenericError(xmlGenericErrorContext, + "xmlNamespaceParseNSDef() deprecated function reached\n"); + deprecated = 1; + } + return (NULL); +} + +/** + * xmlParseQuotedString: + * @ctxt: an XML parser context + * + * Parse and return a string between quotes or doublequotes + * + * TODO: Deprecated, to be removed at next drop of binary compatibility + * + * Returns the string parser or NULL. + */ +xmlChar * +xmlParseQuotedString(xmlParserCtxtPtr ctxt ATTRIBUTE_UNUSED) +{ + static int deprecated = 0; + + if (!deprecated) { + xmlGenericError(xmlGenericErrorContext, + "xmlParseQuotedString() deprecated function reached\n"); + deprecated = 1; + } + return (NULL); +} + +/** + * xmlParseNamespace: + * @ctxt: an XML parser context + * + * xmlParseNamespace: parse specific PI ' + +#ifndef WITH_TRIO +#include +#else +/** + * TRIO_REPLACE_STDIO: + * + * This macro is defined if teh trio string formatting functions are to + * be used instead of the default stdio ones. + */ +#define TRIO_REPLACE_STDIO +#include "trio.h" +#endif + +/* + * Internal variable indicating if a callback has been registered for + * node creation/destruction. It avoids spending a lot of time in locking + * function while checking if the callback exists. + */ +extern int __xmlRegisterCallbacks; +/* + * internal error reporting routines, shared but not partof the API. + */ +void __xmlIOErr(int domain, int code, const char *extra); +void __xmlLoaderErr(void *ctx, const char *msg, const char *filename); + +/* + * internal global initialization critical section routines. + */ +void __xmlGlobalInitMutexLock(void); +void __xmlGlobalInitMutexUnlock(void); +void __xmlGlobalInitMutexDestroy(void); + +#ifdef IN_LIBXML +#ifdef __GNUC__ +#ifdef PIC +#ifdef linux +#if (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) || (__GNUC__ > 3) +#include "elfgcchack.h" +#endif +#endif +#endif +#endif +#endif +#if !defined(PIC) && !defined(NOLIBTOOL) +# define LIBXML_STATIC +#endif +#endif /* ! __XML_LIBXML_H__ */ diff --git a/android/native/libxml2/libxml/DOCBparser.h b/android/native/libxml2/libxml/DOCBparser.h new file mode 100644 index 0000000000..461d4ee802 --- /dev/null +++ b/android/native/libxml2/libxml/DOCBparser.h @@ -0,0 +1,96 @@ +/* + * Summary: old DocBook SGML parser + * Description: interface for a DocBook SGML non-verifying parser + * This code is DEPRECATED, and should not be used anymore. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __DOCB_PARSER_H__ +#define __DOCB_PARSER_H__ +#include + +#ifdef LIBXML_DOCB_ENABLED + +#include +#include + +#ifndef IN_LIBXML +#ifdef __GNUC__ +#warning "The DOCBparser module has been deprecated in libxml2-2.6.0" +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Most of the back-end structures from XML and SGML are shared. + */ +typedef xmlParserCtxt docbParserCtxt; +typedef xmlParserCtxtPtr docbParserCtxtPtr; +typedef xmlSAXHandler docbSAXHandler; +typedef xmlSAXHandlerPtr docbSAXHandlerPtr; +typedef xmlParserInput docbParserInput; +typedef xmlParserInputPtr docbParserInputPtr; +typedef xmlDocPtr docbDocPtr; + +/* + * There is only few public functions. + */ +XMLPUBFUN int XMLCALL + docbEncodeEntities(unsigned char *out, + int *outlen, + const unsigned char *in, + int *inlen, int quoteChar); + +XMLPUBFUN docbDocPtr XMLCALL + docbSAXParseDoc (xmlChar *cur, + const char *encoding, + docbSAXHandlerPtr sax, + void *userData); +XMLPUBFUN docbDocPtr XMLCALL + docbParseDoc (xmlChar *cur, + const char *encoding); +XMLPUBFUN docbDocPtr XMLCALL + docbSAXParseFile (const char *filename, + const char *encoding, + docbSAXHandlerPtr sax, + void *userData); +XMLPUBFUN docbDocPtr XMLCALL + docbParseFile (const char *filename, + const char *encoding); + +/** + * Interfaces for the Push mode. + */ +XMLPUBFUN void XMLCALL + docbFreeParserCtxt (docbParserCtxtPtr ctxt); +XMLPUBFUN docbParserCtxtPtr XMLCALL + docbCreatePushParserCtxt(docbSAXHandlerPtr sax, + void *user_data, + const char *chunk, + int size, + const char *filename, + xmlCharEncoding enc); +XMLPUBFUN int XMLCALL + docbParseChunk (docbParserCtxtPtr ctxt, + const char *chunk, + int size, + int terminate); +XMLPUBFUN docbParserCtxtPtr XMLCALL + docbCreateFileParserCtxt(const char *filename, + const char *encoding); +XMLPUBFUN int XMLCALL + docbParseDocument (docbParserCtxtPtr ctxt); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_DOCB_ENABLED */ + +#endif /* __DOCB_PARSER_H__ */ diff --git a/android/native/libxml2/libxml/HTMLparser.h b/android/native/libxml2/libxml/HTMLparser.h new file mode 100644 index 0000000000..3818757960 --- /dev/null +++ b/android/native/libxml2/libxml/HTMLparser.h @@ -0,0 +1,18 @@ +/* + * Summary: interface for an HTML 4.0 non-verifying parser + * Description: this module implements an HTML 4.0 non-verifying parser + * with API compatible with the XML parser ones. It should + * be able to parse "real world" HTML, even if severely + * broken from a specification point of view. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __HTML_PARSER_H__ +#define __HTML_PARSER_H__ +#include +#include + +#endif /* __HTML_PARSER_H__ */ diff --git a/android/native/libxml2/libxml/HTMLtree.h b/android/native/libxml2/libxml/HTMLtree.h new file mode 100644 index 0000000000..9f4232be09 --- /dev/null +++ b/android/native/libxml2/libxml/HTMLtree.h @@ -0,0 +1,21 @@ +/* + * Summary: specific APIs to process HTML tree, especially serialization + * Description: this module implements a few function needed to process + * tree in an HTML specific way. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __HTML_TREE_H__ +#define __HTML_TREE_H__ + +#include +#include +#include +#include + + +#endif /* __HTML_TREE_H__ */ + diff --git a/android/native/libxml2/libxml/SAX.h b/android/native/libxml2/libxml/SAX.h new file mode 100644 index 0000000000..c5444d6418 --- /dev/null +++ b/android/native/libxml2/libxml/SAX.h @@ -0,0 +1,169 @@ +/* + * Summary: Old SAX version 1 handler, deprecated + * Description: DEPRECATED set of SAX version 1 interfaces used to + * build the DOM tree. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + + +#ifndef __XML_SAX_H__ +#define __XML_SAX_H__ + +#include +#include +#include +#include +#include + +#ifdef LIBXML_LEGACY_ENABLED + +#ifdef __cplusplus +extern "C" { +#endif +XMLPUBFUN const xmlChar * XMLCALL + getPublicId (void *ctx); +XMLPUBFUN const xmlChar * XMLCALL + getSystemId (void *ctx); +XMLPUBFUN void XMLCALL + setDocumentLocator (void *ctx, + xmlSAXLocatorPtr loc); + +XMLPUBFUN int XMLCALL + getLineNumber (void *ctx); +XMLPUBFUN int XMLCALL + getColumnNumber (void *ctx); + +XMLPUBFUN int XMLCALL + isStandalone (void *ctx); +XMLPUBFUN int XMLCALL + hasInternalSubset (void *ctx); +XMLPUBFUN int XMLCALL + hasExternalSubset (void *ctx); + +XMLPUBFUN void XMLCALL + internalSubset (void *ctx, + const xmlChar *name, + const xmlChar *ExternalID, + const xmlChar *SystemID); +XMLPUBFUN void XMLCALL + externalSubset (void *ctx, + const xmlChar *name, + const xmlChar *ExternalID, + const xmlChar *SystemID); +XMLPUBFUN xmlEntityPtr XMLCALL + getEntity (void *ctx, + const xmlChar *name); +XMLPUBFUN xmlEntityPtr XMLCALL + getParameterEntity (void *ctx, + const xmlChar *name); +XMLPUBFUN xmlParserInputPtr XMLCALL + resolveEntity (void *ctx, + const xmlChar *publicId, + const xmlChar *systemId); + +XMLPUBFUN void XMLCALL + entityDecl (void *ctx, + const xmlChar *name, + int type, + const xmlChar *publicId, + const xmlChar *systemId, + xmlChar *content); +XMLPUBFUN void XMLCALL + attributeDecl (void *ctx, + const xmlChar *elem, + const xmlChar *fullname, + int type, + int def, + const xmlChar *defaultValue, + xmlEnumerationPtr tree); +XMLPUBFUN void XMLCALL + elementDecl (void *ctx, + const xmlChar *name, + int type, + xmlElementContentPtr content); +XMLPUBFUN void XMLCALL + notationDecl (void *ctx, + const xmlChar *name, + const xmlChar *publicId, + const xmlChar *systemId); +XMLPUBFUN void XMLCALL + unparsedEntityDecl (void *ctx, + const xmlChar *name, + const xmlChar *publicId, + const xmlChar *systemId, + const xmlChar *notationName); + +XMLPUBFUN void XMLCALL + startDocument (void *ctx); +XMLPUBFUN void XMLCALL + endDocument (void *ctx); +XMLPUBFUN void XMLCALL + attribute (void *ctx, + const xmlChar *fullname, + const xmlChar *value); +XMLPUBFUN void XMLCALL + startElement (void *ctx, + const xmlChar *fullname, + const xmlChar **atts); +XMLPUBFUN void XMLCALL + endElement (void *ctx, + const xmlChar *name); +XMLPUBFUN void XMLCALL + reference (void *ctx, + const xmlChar *name); +XMLPUBFUN void XMLCALL + characters (void *ctx, + const xmlChar *ch, + int len); +XMLPUBFUN void XMLCALL + ignorableWhitespace (void *ctx, + const xmlChar *ch, + int len); +XMLPUBFUN void XMLCALL + processingInstruction (void *ctx, + const xmlChar *target, + const xmlChar *data); +XMLPUBFUN void XMLCALL + globalNamespace (void *ctx, + const xmlChar *href, + const xmlChar *prefix); +XMLPUBFUN void XMLCALL + setNamespace (void *ctx, + const xmlChar *name); +XMLPUBFUN xmlNsPtr XMLCALL + getNamespace (void *ctx); +XMLPUBFUN int XMLCALL + checkNamespace (void *ctx, + xmlChar *nameSpace); +XMLPUBFUN void XMLCALL + namespaceDecl (void *ctx, + const xmlChar *href, + const xmlChar *prefix); +XMLPUBFUN void XMLCALL + comment (void *ctx, + const xmlChar *value); +XMLPUBFUN void XMLCALL + cdataBlock (void *ctx, + const xmlChar *value, + int len); + +#ifdef LIBXML_SAX1_ENABLED +XMLPUBFUN void XMLCALL + initxmlDefaultSAXHandler (xmlSAXHandlerV1 *hdlr, + int warning); +#ifdef LIBXML_DOCB_ENABLED +XMLPUBFUN void XMLCALL + initdocbDefaultSAXHandler (xmlSAXHandlerV1 *hdlr); +#endif +#endif /* LIBXML_SAX1_ENABLED */ + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_LEGACY_ENABLED */ + +#endif /* __XML_SAX_H__ */ diff --git a/android/native/libxml2/libxml/SAX2.h b/android/native/libxml2/libxml/SAX2.h new file mode 100644 index 0000000000..d9f81897ee --- /dev/null +++ b/android/native/libxml2/libxml/SAX2.h @@ -0,0 +1,170 @@ +/* + * Summary: SAX2 parser interface used to build the DOM tree + * Description: those are the default SAX2 interfaces used by + * the library when building DOM tree. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + + +#ifndef __XML_SAX2_H__ +#define __XML_SAX2_H__ + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif +XMLPUBFUN const xmlChar * XMLCALL + xmlSAX2GetPublicId (void *ctx); +XMLPUBFUN const xmlChar * XMLCALL + xmlSAX2GetSystemId (void *ctx); +XMLPUBFUN void XMLCALL + xmlSAX2SetDocumentLocator (void *ctx, + xmlSAXLocatorPtr loc); + +XMLPUBFUN int XMLCALL + xmlSAX2GetLineNumber (void *ctx); +XMLPUBFUN int XMLCALL + xmlSAX2GetColumnNumber (void *ctx); + +XMLPUBFUN int XMLCALL + xmlSAX2IsStandalone (void *ctx); +XMLPUBFUN int XMLCALL + xmlSAX2HasInternalSubset (void *ctx); +XMLPUBFUN int XMLCALL + xmlSAX2HasExternalSubset (void *ctx); + +XMLPUBFUN void XMLCALL + xmlSAX2InternalSubset (void *ctx, + const xmlChar *name, + const xmlChar *ExternalID, + const xmlChar *SystemID); +XMLPUBFUN void XMLCALL + xmlSAX2ExternalSubset (void *ctx, + const xmlChar *name, + const xmlChar *ExternalID, + const xmlChar *SystemID); +XMLPUBFUN xmlEntityPtr XMLCALL + xmlSAX2GetEntity (void *ctx, + const xmlChar *name); +XMLPUBFUN xmlEntityPtr XMLCALL + xmlSAX2GetParameterEntity (void *ctx, + const xmlChar *name); +XMLPUBFUN xmlParserInputPtr XMLCALL + xmlSAX2ResolveEntity (void *ctx, + const xmlChar *publicId, + const xmlChar *systemId); + +XMLPUBFUN void XMLCALL + xmlSAX2EntityDecl (void *ctx, + const xmlChar *name, + int type, + const xmlChar *publicId, + const xmlChar *systemId, + xmlChar *content); +XMLPUBFUN void XMLCALL + xmlSAX2AttributeDecl (void *ctx, + const xmlChar *elem, + const xmlChar *fullname, + int type, + int def, + const xmlChar *defaultValue, + xmlEnumerationPtr tree); +XMLPUBFUN void XMLCALL + xmlSAX2ElementDecl (void *ctx, + const xmlChar *name, + int type, + xmlElementContentPtr content); +XMLPUBFUN void XMLCALL + xmlSAX2NotationDecl (void *ctx, + const xmlChar *name, + const xmlChar *publicId, + const xmlChar *systemId); +XMLPUBFUN void XMLCALL + xmlSAX2UnparsedEntityDecl (void *ctx, + const xmlChar *name, + const xmlChar *publicId, + const xmlChar *systemId, + const xmlChar *notationName); + +XMLPUBFUN void XMLCALL + xmlSAX2StartDocument (void *ctx); +XMLPUBFUN void XMLCALL + xmlSAX2EndDocument (void *ctx); +#if defined(LIBXML_SAX1_ENABLED) || defined(LIBXML_WRITER_ENABLED) || defined(LIBXML_DOCB_ENABLED) +XMLPUBFUN void XMLCALL + xmlSAX2StartElement (void *ctx, + const xmlChar *fullname, + const xmlChar **atts); +XMLPUBFUN void XMLCALL + xmlSAX2EndElement (void *ctx, + const xmlChar *name); +#endif /* LIBXML_SAX1_ENABLED */ +XMLPUBFUN void XMLCALL + xmlSAX2StartElementNs (void *ctx, + const xmlChar *localname, + const xmlChar *prefix, + const xmlChar *URI, + int nb_namespaces, + const xmlChar **namespaces, + int nb_attributes, + int nb_defaulted, + const xmlChar **attributes); +XMLPUBFUN void XMLCALL + xmlSAX2EndElementNs (void *ctx, + const xmlChar *localname, + const xmlChar *prefix, + const xmlChar *URI); +XMLPUBFUN void XMLCALL + xmlSAX2Reference (void *ctx, + const xmlChar *name); +XMLPUBFUN void XMLCALL + xmlSAX2Characters (void *ctx, + const xmlChar *ch, + int len); +XMLPUBFUN void XMLCALL + xmlSAX2IgnorableWhitespace (void *ctx, + const xmlChar *ch, + int len); +XMLPUBFUN void XMLCALL + xmlSAX2ProcessingInstruction (void *ctx, + const xmlChar *target, + const xmlChar *data); +XMLPUBFUN void XMLCALL + xmlSAX2Comment (void *ctx, + const xmlChar *value); +XMLPUBFUN void XMLCALL + xmlSAX2CDataBlock (void *ctx, + const xmlChar *value, + int len); + +#ifdef LIBXML_SAX1_ENABLED +XMLPUBFUN int XMLCALL + xmlSAXDefaultVersion (int version); +#endif /* LIBXML_SAX1_ENABLED */ + +XMLPUBFUN int XMLCALL + xmlSAXVersion (xmlSAXHandler *hdlr, + int version); +XMLPUBFUN void XMLCALL + xmlSAX2InitDefaultSAXHandler (xmlSAXHandler *hdlr, + int warning); +#ifdef LIBXML_DOCB_ENABLED +XMLPUBFUN void XMLCALL + xmlSAX2InitDocbDefaultSAXHandler(xmlSAXHandler *hdlr); +XMLPUBFUN void XMLCALL + docbDefaultSAXHandlerInit (void); +#endif +XMLPUBFUN void XMLCALL + xmlDefaultSAXHandlerInit (void); +#ifdef __cplusplus +} +#endif +#endif /* __XML_SAX2_H__ */ diff --git a/android/native/libxml2/libxml/c14n.h b/android/native/libxml2/libxml/c14n.h new file mode 100644 index 0000000000..3011af79eb --- /dev/null +++ b/android/native/libxml2/libxml/c14n.h @@ -0,0 +1,126 @@ +/* + * Summary: Provide Canonical XML and Exclusive XML Canonicalization + * Description: the c14n modules provides a + * + * "Canonical XML" implementation + * http://www.w3.org/TR/xml-c14n + * + * and an + * + * "Exclusive XML Canonicalization" implementation + * http://www.w3.org/TR/xml-exc-c14n + + * Copy: See Copyright for the status of this software. + * + * Author: Aleksey Sanin + */ +#ifndef __XML_C14N_H__ +#define __XML_C14N_H__ +#ifdef LIBXML_C14N_ENABLED +#ifdef LIBXML_OUTPUT_ENABLED + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include +#include +#include + +/* + * XML Canonicazation + * http://www.w3.org/TR/xml-c14n + * + * Exclusive XML Canonicazation + * http://www.w3.org/TR/xml-exc-c14n + * + * Canonical form of an XML document could be created if and only if + * a) default attributes (if any) are added to all nodes + * b) all character and parsed entity references are resolved + * In order to achive this in libxml2 the document MUST be loaded with + * following global setings: + * + * xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS; + * xmlSubstituteEntitiesDefault(1); + * + * or corresponding parser context setting: + * xmlParserCtxtPtr ctxt; + * + * ... + * ctxt->loadsubset = XML_DETECT_IDS | XML_COMPLETE_ATTRS; + * ctxt->replaceEntities = 1; + * ... + */ + +/* + * xmlC14NMode: + * + * Predefined values for C14N modes + * + */ +typedef enum { + XML_C14N_1_0 = 0, /* Origianal C14N 1.0 spec */ + XML_C14N_EXCLUSIVE_1_0 = 1, /* Exclusive C14N 1.0 spec */ + XML_C14N_1_1 = 2 /* C14N 1.1 spec */ +} xmlC14NMode; + +XMLPUBFUN int XMLCALL + xmlC14NDocSaveTo (xmlDocPtr doc, + xmlNodeSetPtr nodes, + int mode, /* a xmlC14NMode */ + xmlChar **inclusive_ns_prefixes, + int with_comments, + xmlOutputBufferPtr buf); + +XMLPUBFUN int XMLCALL + xmlC14NDocDumpMemory (xmlDocPtr doc, + xmlNodeSetPtr nodes, + int mode, /* a xmlC14NMode */ + xmlChar **inclusive_ns_prefixes, + int with_comments, + xmlChar **doc_txt_ptr); + +XMLPUBFUN int XMLCALL + xmlC14NDocSave (xmlDocPtr doc, + xmlNodeSetPtr nodes, + int mode, /* a xmlC14NMode */ + xmlChar **inclusive_ns_prefixes, + int with_comments, + const char* filename, + int compression); + + +/** + * This is the core C14N function + */ +/** + * xmlC14NIsVisibleCallback: + * @user_data: user data + * @node: the curent node + * @parent: the parent node + * + * Signature for a C14N callback on visible nodes + * + * Returns 1 if the node should be included + */ +typedef int (*xmlC14NIsVisibleCallback) (void* user_data, + xmlNodePtr node, + xmlNodePtr parent); + +XMLPUBFUN int XMLCALL + xmlC14NExecute (xmlDocPtr doc, + xmlC14NIsVisibleCallback is_visible_callback, + void* user_data, + int mode, /* a xmlC14NMode */ + xmlChar **inclusive_ns_prefixes, + int with_comments, + xmlOutputBufferPtr buf); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* LIBXML_OUTPUT_ENABLED */ +#endif /* LIBXML_C14N_ENABLED */ +#endif /* __XML_C14N_H__ */ + diff --git a/android/native/libxml2/libxml/catalog.h b/android/native/libxml2/libxml/catalog.h new file mode 100644 index 0000000000..b4441370fc --- /dev/null +++ b/android/native/libxml2/libxml/catalog.h @@ -0,0 +1,182 @@ +/** + * Summary: interfaces to the Catalog handling system + * Description: the catalog module implements the support for + * XML Catalogs and SGML catalogs + * + * SGML Open Technical Resolution TR9401:1997. + * http://www.jclark.com/sp/catalog.htm + * + * XML Catalogs Working Draft 06 August 2001 + * http://www.oasis-open.org/committees/entity/spec-2001-08-06.html + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_CATALOG_H__ +#define __XML_CATALOG_H__ + +#include + +#include +#include +#include + +#ifdef LIBXML_CATALOG_ENABLED + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * XML_CATALOGS_NAMESPACE: + * + * The namespace for the XML Catalogs elements. + */ +#define XML_CATALOGS_NAMESPACE \ + (const xmlChar *) "urn:oasis:names:tc:entity:xmlns:xml:catalog" +/** + * XML_CATALOG_PI: + * + * The specific XML Catalog Processing Instuction name. + */ +#define XML_CATALOG_PI \ + (const xmlChar *) "oasis-xml-catalog" + +/* + * The API is voluntarily limited to general cataloging. + */ +typedef enum { + XML_CATA_PREFER_NONE = 0, + XML_CATA_PREFER_PUBLIC = 1, + XML_CATA_PREFER_SYSTEM +} xmlCatalogPrefer; + +typedef enum { + XML_CATA_ALLOW_NONE = 0, + XML_CATA_ALLOW_GLOBAL = 1, + XML_CATA_ALLOW_DOCUMENT = 2, + XML_CATA_ALLOW_ALL = 3 +} xmlCatalogAllow; + +typedef struct _xmlCatalog xmlCatalog; +typedef xmlCatalog *xmlCatalogPtr; + +/* + * Operations on a given catalog. + */ +XMLPUBFUN xmlCatalogPtr XMLCALL + xmlNewCatalog (int sgml); +XMLPUBFUN xmlCatalogPtr XMLCALL + xmlLoadACatalog (const char *filename); +XMLPUBFUN xmlCatalogPtr XMLCALL + xmlLoadSGMLSuperCatalog (const char *filename); +XMLPUBFUN int XMLCALL + xmlConvertSGMLCatalog (xmlCatalogPtr catal); +XMLPUBFUN int XMLCALL + xmlACatalogAdd (xmlCatalogPtr catal, + const xmlChar *type, + const xmlChar *orig, + const xmlChar *replace); +XMLPUBFUN int XMLCALL + xmlACatalogRemove (xmlCatalogPtr catal, + const xmlChar *value); +XMLPUBFUN xmlChar * XMLCALL + xmlACatalogResolve (xmlCatalogPtr catal, + const xmlChar *pubID, + const xmlChar *sysID); +XMLPUBFUN xmlChar * XMLCALL + xmlACatalogResolveSystem(xmlCatalogPtr catal, + const xmlChar *sysID); +XMLPUBFUN xmlChar * XMLCALL + xmlACatalogResolvePublic(xmlCatalogPtr catal, + const xmlChar *pubID); +XMLPUBFUN xmlChar * XMLCALL + xmlACatalogResolveURI (xmlCatalogPtr catal, + const xmlChar *URI); +#ifdef LIBXML_OUTPUT_ENABLED +XMLPUBFUN void XMLCALL + xmlACatalogDump (xmlCatalogPtr catal, + FILE *out); +#endif /* LIBXML_OUTPUT_ENABLED */ +XMLPUBFUN void XMLCALL + xmlFreeCatalog (xmlCatalogPtr catal); +XMLPUBFUN int XMLCALL + xmlCatalogIsEmpty (xmlCatalogPtr catal); + +/* + * Global operations. + */ +XMLPUBFUN void XMLCALL + xmlInitializeCatalog (void); +XMLPUBFUN int XMLCALL + xmlLoadCatalog (const char *filename); +XMLPUBFUN void XMLCALL + xmlLoadCatalogs (const char *paths); +XMLPUBFUN void XMLCALL + xmlCatalogCleanup (void); +#ifdef LIBXML_OUTPUT_ENABLED +XMLPUBFUN void XMLCALL + xmlCatalogDump (FILE *out); +#endif /* LIBXML_OUTPUT_ENABLED */ +XMLPUBFUN xmlChar * XMLCALL + xmlCatalogResolve (const xmlChar *pubID, + const xmlChar *sysID); +XMLPUBFUN xmlChar * XMLCALL + xmlCatalogResolveSystem (const xmlChar *sysID); +XMLPUBFUN xmlChar * XMLCALL + xmlCatalogResolvePublic (const xmlChar *pubID); +XMLPUBFUN xmlChar * XMLCALL + xmlCatalogResolveURI (const xmlChar *URI); +XMLPUBFUN int XMLCALL + xmlCatalogAdd (const xmlChar *type, + const xmlChar *orig, + const xmlChar *replace); +XMLPUBFUN int XMLCALL + xmlCatalogRemove (const xmlChar *value); +XMLPUBFUN xmlDocPtr XMLCALL + xmlParseCatalogFile (const char *filename); +XMLPUBFUN int XMLCALL + xmlCatalogConvert (void); + +/* + * Strictly minimal interfaces for per-document catalogs used + * by the parser. + */ +XMLPUBFUN void XMLCALL + xmlCatalogFreeLocal (void *catalogs); +XMLPUBFUN void * XMLCALL + xmlCatalogAddLocal (void *catalogs, + const xmlChar *URL); +XMLPUBFUN xmlChar * XMLCALL + xmlCatalogLocalResolve (void *catalogs, + const xmlChar *pubID, + const xmlChar *sysID); +XMLPUBFUN xmlChar * XMLCALL + xmlCatalogLocalResolveURI(void *catalogs, + const xmlChar *URI); +/* + * Preference settings. + */ +XMLPUBFUN int XMLCALL + xmlCatalogSetDebug (int level); +XMLPUBFUN xmlCatalogPrefer XMLCALL + xmlCatalogSetDefaultPrefer(xmlCatalogPrefer prefer); +XMLPUBFUN void XMLCALL + xmlCatalogSetDefaults (xmlCatalogAllow allow); +XMLPUBFUN xmlCatalogAllow XMLCALL + xmlCatalogGetDefaults (void); + + +/* DEPRECATED interfaces */ +XMLPUBFUN const xmlChar * XMLCALL + xmlCatalogGetSystem (const xmlChar *sysID); +XMLPUBFUN const xmlChar * XMLCALL + xmlCatalogGetPublic (const xmlChar *pubID); + +#ifdef __cplusplus +} +#endif +#endif /* LIBXML_CATALOG_ENABLED */ +#endif /* __XML_CATALOG_H__ */ diff --git a/android/native/libxml2/libxml/chvalid.h b/android/native/libxml2/libxml/chvalid.h new file mode 100644 index 0000000000..fb43016982 --- /dev/null +++ b/android/native/libxml2/libxml/chvalid.h @@ -0,0 +1,230 @@ +/* + * Summary: Unicode character range checking + * Description: this module exports interfaces for the character + * range validation APIs + * + * This file is automatically generated from the cvs source + * definition files using the genChRanges.py Python script + * + * Generation date: Mon Mar 27 11:09:48 2006 + * Sources: chvalid.def + * Author: William Brack + */ + +#ifndef __XML_CHVALID_H__ +#define __XML_CHVALID_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Define our typedefs and structures + * + */ +typedef struct _xmlChSRange xmlChSRange; +typedef xmlChSRange *xmlChSRangePtr; +struct _xmlChSRange { + unsigned short low; + unsigned short high; +}; + +typedef struct _xmlChLRange xmlChLRange; +typedef xmlChLRange *xmlChLRangePtr; +struct _xmlChLRange { + unsigned int low; + unsigned int high; +}; + +typedef struct _xmlChRangeGroup xmlChRangeGroup; +typedef xmlChRangeGroup *xmlChRangeGroupPtr; +struct _xmlChRangeGroup { + int nbShortRange; + int nbLongRange; + const xmlChSRange *shortRange; /* points to an array of ranges */ + const xmlChLRange *longRange; +}; + +/** + * Range checking routine + */ +XMLPUBFUN int XMLCALL + xmlCharInRange(unsigned int val, const xmlChRangeGroup *group); + + +/** + * xmlIsBaseChar_ch: + * @c: char to validate + * + * Automatically generated by genChRanges.py + */ +#define xmlIsBaseChar_ch(c) (((0x41 <= (c)) && ((c) <= 0x5a)) || \ + ((0x61 <= (c)) && ((c) <= 0x7a)) || \ + ((0xc0 <= (c)) && ((c) <= 0xd6)) || \ + ((0xd8 <= (c)) && ((c) <= 0xf6)) || \ + (0xf8 <= (c))) + +/** + * xmlIsBaseCharQ: + * @c: char to validate + * + * Automatically generated by genChRanges.py + */ +#define xmlIsBaseCharQ(c) (((c) < 0x100) ? \ + xmlIsBaseChar_ch((c)) : \ + xmlCharInRange((c), &xmlIsBaseCharGroup)) + +XMLPUBVAR const xmlChRangeGroup xmlIsBaseCharGroup; + +/** + * xmlIsBlank_ch: + * @c: char to validate + * + * Automatically generated by genChRanges.py + */ +#define xmlIsBlank_ch(c) (((c) == 0x20) || \ + ((0x9 <= (c)) && ((c) <= 0xa)) || \ + ((c) == 0xd)) + +/** + * xmlIsBlankQ: + * @c: char to validate + * + * Automatically generated by genChRanges.py + */ +#define xmlIsBlankQ(c) (((c) < 0x100) ? \ + xmlIsBlank_ch((c)) : 0) + + +/** + * xmlIsChar_ch: + * @c: char to validate + * + * Automatically generated by genChRanges.py + */ +#define xmlIsChar_ch(c) (((0x9 <= (c)) && ((c) <= 0xa)) || \ + ((c) == 0xd) || \ + (0x20 <= (c))) + +/** + * xmlIsCharQ: + * @c: char to validate + * + * Automatically generated by genChRanges.py + */ +#define xmlIsCharQ(c) (((c) < 0x100) ? \ + xmlIsChar_ch((c)) :\ + (((0x100 <= (c)) && ((c) <= 0xd7ff)) || \ + ((0xe000 <= (c)) && ((c) <= 0xfffd)) || \ + ((0x10000 <= (c)) && ((c) <= 0x10ffff)))) + +XMLPUBVAR const xmlChRangeGroup xmlIsCharGroup; + +/** + * xmlIsCombiningQ: + * @c: char to validate + * + * Automatically generated by genChRanges.py + */ +#define xmlIsCombiningQ(c) (((c) < 0x100) ? \ + 0 : \ + xmlCharInRange((c), &xmlIsCombiningGroup)) + +XMLPUBVAR const xmlChRangeGroup xmlIsCombiningGroup; + +/** + * xmlIsDigit_ch: + * @c: char to validate + * + * Automatically generated by genChRanges.py + */ +#define xmlIsDigit_ch(c) (((0x30 <= (c)) && ((c) <= 0x39))) + +/** + * xmlIsDigitQ: + * @c: char to validate + * + * Automatically generated by genChRanges.py + */ +#define xmlIsDigitQ(c) (((c) < 0x100) ? \ + xmlIsDigit_ch((c)) : \ + xmlCharInRange((c), &xmlIsDigitGroup)) + +XMLPUBVAR const xmlChRangeGroup xmlIsDigitGroup; + +/** + * xmlIsExtender_ch: + * @c: char to validate + * + * Automatically generated by genChRanges.py + */ +#define xmlIsExtender_ch(c) (((c) == 0xb7)) + +/** + * xmlIsExtenderQ: + * @c: char to validate + * + * Automatically generated by genChRanges.py + */ +#define xmlIsExtenderQ(c) (((c) < 0x100) ? \ + xmlIsExtender_ch((c)) : \ + xmlCharInRange((c), &xmlIsExtenderGroup)) + +XMLPUBVAR const xmlChRangeGroup xmlIsExtenderGroup; + +/** + * xmlIsIdeographicQ: + * @c: char to validate + * + * Automatically generated by genChRanges.py + */ +#define xmlIsIdeographicQ(c) (((c) < 0x100) ? \ + 0 :\ + (((0x4e00 <= (c)) && ((c) <= 0x9fa5)) || \ + ((c) == 0x3007) || \ + ((0x3021 <= (c)) && ((c) <= 0x3029)))) + +XMLPUBVAR const xmlChRangeGroup xmlIsIdeographicGroup; +XMLPUBVAR const unsigned char xmlIsPubidChar_tab[256]; + +/** + * xmlIsPubidChar_ch: + * @c: char to validate + * + * Automatically generated by genChRanges.py + */ +#define xmlIsPubidChar_ch(c) (xmlIsPubidChar_tab[(c)]) + +/** + * xmlIsPubidCharQ: + * @c: char to validate + * + * Automatically generated by genChRanges.py + */ +#define xmlIsPubidCharQ(c) (((c) < 0x100) ? \ + xmlIsPubidChar_ch((c)) : 0) + +XMLPUBFUN int XMLCALL + xmlIsBaseChar(unsigned int ch); +XMLPUBFUN int XMLCALL + xmlIsBlank(unsigned int ch); +XMLPUBFUN int XMLCALL + xmlIsChar(unsigned int ch); +XMLPUBFUN int XMLCALL + xmlIsCombining(unsigned int ch); +XMLPUBFUN int XMLCALL + xmlIsDigit(unsigned int ch); +XMLPUBFUN int XMLCALL + xmlIsExtender(unsigned int ch); +XMLPUBFUN int XMLCALL + xmlIsIdeographic(unsigned int ch); +XMLPUBFUN int XMLCALL + xmlIsPubidChar(unsigned int ch); + +#ifdef __cplusplus +} +#endif +#endif /* __XML_CHVALID_H__ */ diff --git a/android/native/libxml2/libxml/debugXML.h b/android/native/libxml2/libxml/debugXML.h new file mode 100644 index 0000000000..5a9d20bcf5 --- /dev/null +++ b/android/native/libxml2/libxml/debugXML.h @@ -0,0 +1,217 @@ +/* + * Summary: Tree debugging APIs + * Description: Interfaces to a set of routines used for debugging the tree + * produced by the XML parser. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __DEBUG_XML__ +#define __DEBUG_XML__ +#include +#include +#include + +#ifdef LIBXML_DEBUG_ENABLED + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * The standard Dump routines. + */ +XMLPUBFUN void XMLCALL + xmlDebugDumpString (FILE *output, + const xmlChar *str); +XMLPUBFUN void XMLCALL + xmlDebugDumpAttr (FILE *output, + xmlAttrPtr attr, + int depth); +XMLPUBFUN void XMLCALL + xmlDebugDumpAttrList (FILE *output, + xmlAttrPtr attr, + int depth); +XMLPUBFUN void XMLCALL + xmlDebugDumpOneNode (FILE *output, + xmlNodePtr node, + int depth); +XMLPUBFUN void XMLCALL + xmlDebugDumpNode (FILE *output, + xmlNodePtr node, + int depth); +XMLPUBFUN void XMLCALL + xmlDebugDumpNodeList (FILE *output, + xmlNodePtr node, + int depth); +XMLPUBFUN void XMLCALL + xmlDebugDumpDocumentHead(FILE *output, + xmlDocPtr doc); +XMLPUBFUN void XMLCALL + xmlDebugDumpDocument (FILE *output, + xmlDocPtr doc); +XMLPUBFUN void XMLCALL + xmlDebugDumpDTD (FILE *output, + xmlDtdPtr dtd); +XMLPUBFUN void XMLCALL + xmlDebugDumpEntities (FILE *output, + xmlDocPtr doc); + +/**************************************************************** + * * + * Checking routines * + * * + ****************************************************************/ + +XMLPUBFUN int XMLCALL + xmlDebugCheckDocument (FILE * output, + xmlDocPtr doc); + +/**************************************************************** + * * + * XML shell helpers * + * * + ****************************************************************/ + +XMLPUBFUN void XMLCALL + xmlLsOneNode (FILE *output, xmlNodePtr node); +XMLPUBFUN int XMLCALL + xmlLsCountNode (xmlNodePtr node); + +XMLPUBFUN const char * XMLCALL + xmlBoolToText (int boolval); + +/**************************************************************** + * * + * The XML shell related structures and functions * + * * + ****************************************************************/ + +#ifdef LIBXML_XPATH_ENABLED +/** + * xmlShellReadlineFunc: + * @prompt: a string prompt + * + * This is a generic signature for the XML shell input function. + * + * Returns a string which will be freed by the Shell. + */ +typedef char * (* xmlShellReadlineFunc)(char *prompt); + +/** + * xmlShellCtxt: + * + * A debugging shell context. + * TODO: add the defined function tables. + */ +typedef struct _xmlShellCtxt xmlShellCtxt; +typedef xmlShellCtxt *xmlShellCtxtPtr; +struct _xmlShellCtxt { + char *filename; + xmlDocPtr doc; + xmlNodePtr node; + xmlXPathContextPtr pctxt; + int loaded; + FILE *output; + xmlShellReadlineFunc input; +}; + +/** + * xmlShellCmd: + * @ctxt: a shell context + * @arg: a string argument + * @node: a first node + * @node2: a second node + * + * This is a generic signature for the XML shell functions. + * + * Returns an int, negative returns indicating errors. + */ +typedef int (* xmlShellCmd) (xmlShellCtxtPtr ctxt, + char *arg, + xmlNodePtr node, + xmlNodePtr node2); + +XMLPUBFUN void XMLCALL + xmlShellPrintXPathError (int errorType, + const char *arg); +XMLPUBFUN void XMLCALL + xmlShellPrintXPathResult(xmlXPathObjectPtr list); +XMLPUBFUN int XMLCALL + xmlShellList (xmlShellCtxtPtr ctxt, + char *arg, + xmlNodePtr node, + xmlNodePtr node2); +XMLPUBFUN int XMLCALL + xmlShellBase (xmlShellCtxtPtr ctxt, + char *arg, + xmlNodePtr node, + xmlNodePtr node2); +XMLPUBFUN int XMLCALL + xmlShellDir (xmlShellCtxtPtr ctxt, + char *arg, + xmlNodePtr node, + xmlNodePtr node2); +XMLPUBFUN int XMLCALL + xmlShellLoad (xmlShellCtxtPtr ctxt, + char *filename, + xmlNodePtr node, + xmlNodePtr node2); +#ifdef LIBXML_OUTPUT_ENABLED +XMLPUBFUN void XMLCALL + xmlShellPrintNode (xmlNodePtr node); +XMLPUBFUN int XMLCALL + xmlShellCat (xmlShellCtxtPtr ctxt, + char *arg, + xmlNodePtr node, + xmlNodePtr node2); +XMLPUBFUN int XMLCALL + xmlShellWrite (xmlShellCtxtPtr ctxt, + char *filename, + xmlNodePtr node, + xmlNodePtr node2); +XMLPUBFUN int XMLCALL + xmlShellSave (xmlShellCtxtPtr ctxt, + char *filename, + xmlNodePtr node, + xmlNodePtr node2); +#endif /* LIBXML_OUTPUT_ENABLED */ +#ifdef LIBXML_VALID_ENABLED +XMLPUBFUN int XMLCALL + xmlShellValidate (xmlShellCtxtPtr ctxt, + char *dtd, + xmlNodePtr node, + xmlNodePtr node2); +#endif /* LIBXML_VALID_ENABLED */ +XMLPUBFUN int XMLCALL + xmlShellDu (xmlShellCtxtPtr ctxt, + char *arg, + xmlNodePtr tree, + xmlNodePtr node2); +XMLPUBFUN int XMLCALL + xmlShellPwd (xmlShellCtxtPtr ctxt, + char *buffer, + xmlNodePtr node, + xmlNodePtr node2); + +/* + * The Shell interface. + */ +XMLPUBFUN void XMLCALL + xmlShell (xmlDocPtr doc, + char *filename, + xmlShellReadlineFunc input, + FILE *output); + +#endif /* LIBXML_XPATH_ENABLED */ + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_DEBUG_ENABLED */ +#endif /* __DEBUG_XML__ */ diff --git a/android/native/libxml2/libxml/dict.h b/android/native/libxml2/libxml/dict.h new file mode 100644 index 0000000000..abb8339cb8 --- /dev/null +++ b/android/native/libxml2/libxml/dict.h @@ -0,0 +1,69 @@ +/* + * Summary: string dictionnary + * Description: dictionary of reusable strings, just used to avoid allocation + * and freeing operations. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_DICT_H__ +#define __XML_DICT_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * The dictionnary. + */ +typedef struct _xmlDict xmlDict; +typedef xmlDict *xmlDictPtr; + +/* + * Constructor and destructor. + */ +XMLPUBFUN xmlDictPtr XMLCALL + xmlDictCreate (void); +XMLPUBFUN xmlDictPtr XMLCALL + xmlDictCreateSub(xmlDictPtr sub); +XMLPUBFUN int XMLCALL + xmlDictReference(xmlDictPtr dict); +XMLPUBFUN void XMLCALL + xmlDictFree (xmlDictPtr dict); + +/* + * Lookup of entry in the dictionnary. + */ +XMLPUBFUN const xmlChar * XMLCALL + xmlDictLookup (xmlDictPtr dict, + const xmlChar *name, + int len); +XMLPUBFUN const xmlChar * XMLCALL + xmlDictExists (xmlDictPtr dict, + const xmlChar *name, + int len); +XMLPUBFUN const xmlChar * XMLCALL + xmlDictQLookup (xmlDictPtr dict, + const xmlChar *prefix, + const xmlChar *name); +XMLPUBFUN int XMLCALL + xmlDictOwns (xmlDictPtr dict, + const xmlChar *str); +XMLPUBFUN int XMLCALL + xmlDictSize (xmlDictPtr dict); + +/* + * Cleanup function + */ +XMLPUBFUN void XMLCALL + xmlDictCleanup (void); + +#ifdef __cplusplus +} +#endif +#endif /* ! __XML_DICT_H__ */ diff --git a/android/native/libxml2/libxml/encoding.h b/android/native/libxml2/libxml/encoding.h new file mode 100644 index 0000000000..c74b25f3cb --- /dev/null +++ b/android/native/libxml2/libxml/encoding.h @@ -0,0 +1,226 @@ +/* + * Summary: interface for the encoding conversion functions + * Description: interface for the encoding conversion functions needed for + * XML basic encoding and iconv() support. + * + * Related specs are + * rfc2044 (UTF-8 and UTF-16) F. Yergeau Alis Technologies + * [ISO-10646] UTF-8 and UTF-16 in Annexes + * [ISO-8859-1] ISO Latin-1 characters codes. + * [UNICODE] The Unicode Consortium, "The Unicode Standard -- + * Worldwide Character Encoding -- Version 1.0", Addison- + * Wesley, Volume 1, 1991, Volume 2, 1992. UTF-8 is + * described in Unicode Technical Report #4. + * [US-ASCII] Coded Character Set--7-bit American Standard Code for + * Information Interchange, ANSI X3.4-1986. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_CHAR_ENCODING_H__ +#define __XML_CHAR_ENCODING_H__ + +#include + +#ifdef LIBXML_ICONV_ENABLED +#include +#endif +#ifdef __cplusplus +extern "C" { +#endif + +/* + * xmlCharEncoding: + * + * Predefined values for some standard encodings. + * Libxml does not do beforehand translation on UTF8 and ISOLatinX. + * It also supports ASCII, ISO-8859-1, and UTF16 (LE and BE) by default. + * + * Anything else would have to be translated to UTF8 before being + * given to the parser itself. The BOM for UTF16 and the encoding + * declaration are looked at and a converter is looked for at that + * point. If not found the parser stops here as asked by the XML REC. A + * converter can be registered by the user using xmlRegisterCharEncodingHandler + * but the current form doesn't allow stateful transcoding (a serious + * problem agreed !). If iconv has been found it will be used + * automatically and allow stateful transcoding, the simplest is then + * to be sure to enable iconv and to provide iconv libs for the encoding + * support needed. + * + * Note that the generic "UTF-16" is not a predefined value. Instead, only + * the specific UTF-16LE and UTF-16BE are present. + */ +typedef enum { + XML_CHAR_ENCODING_ERROR= -1, /* No char encoding detected */ + XML_CHAR_ENCODING_NONE= 0, /* No char encoding detected */ + XML_CHAR_ENCODING_UTF8= 1, /* UTF-8 */ + XML_CHAR_ENCODING_UTF16LE= 2, /* UTF-16 little endian */ + XML_CHAR_ENCODING_UTF16BE= 3, /* UTF-16 big endian */ + XML_CHAR_ENCODING_UCS4LE= 4, /* UCS-4 little endian */ + XML_CHAR_ENCODING_UCS4BE= 5, /* UCS-4 big endian */ + XML_CHAR_ENCODING_EBCDIC= 6, /* EBCDIC uh! */ + XML_CHAR_ENCODING_UCS4_2143=7, /* UCS-4 unusual ordering */ + XML_CHAR_ENCODING_UCS4_3412=8, /* UCS-4 unusual ordering */ + XML_CHAR_ENCODING_UCS2= 9, /* UCS-2 */ + XML_CHAR_ENCODING_8859_1= 10,/* ISO-8859-1 ISO Latin 1 */ + XML_CHAR_ENCODING_8859_2= 11,/* ISO-8859-2 ISO Latin 2 */ + XML_CHAR_ENCODING_8859_3= 12,/* ISO-8859-3 */ + XML_CHAR_ENCODING_8859_4= 13,/* ISO-8859-4 */ + XML_CHAR_ENCODING_8859_5= 14,/* ISO-8859-5 */ + XML_CHAR_ENCODING_8859_6= 15,/* ISO-8859-6 */ + XML_CHAR_ENCODING_8859_7= 16,/* ISO-8859-7 */ + XML_CHAR_ENCODING_8859_8= 17,/* ISO-8859-8 */ + XML_CHAR_ENCODING_8859_9= 18,/* ISO-8859-9 */ + XML_CHAR_ENCODING_2022_JP= 19,/* ISO-2022-JP */ + XML_CHAR_ENCODING_SHIFT_JIS=20,/* Shift_JIS */ + XML_CHAR_ENCODING_EUC_JP= 21,/* EUC-JP */ + XML_CHAR_ENCODING_ASCII= 22 /* pure ASCII */ +} xmlCharEncoding; + +/** + * xmlCharEncodingInputFunc: + * @out: a pointer to an array of bytes to store the UTF-8 result + * @outlen: the length of @out + * @in: a pointer to an array of chars in the original encoding + * @inlen: the length of @in + * + * Take a block of chars in the original encoding and try to convert + * it to an UTF-8 block of chars out. + * + * Returns the number of bytes written, -1 if lack of space, or -2 + * if the transcoding failed. + * The value of @inlen after return is the number of octets consumed + * if the return value is positive, else unpredictiable. + * The value of @outlen after return is the number of octets consumed. + */ +typedef int (* xmlCharEncodingInputFunc)(unsigned char *out, int *outlen, + const unsigned char *in, int *inlen); + + +/** + * xmlCharEncodingOutputFunc: + * @out: a pointer to an array of bytes to store the result + * @outlen: the length of @out + * @in: a pointer to an array of UTF-8 chars + * @inlen: the length of @in + * + * Take a block of UTF-8 chars in and try to convert it to another + * encoding. + * Note: a first call designed to produce heading info is called with + * in = NULL. If stateful this should also initialize the encoder state. + * + * Returns the number of bytes written, -1 if lack of space, or -2 + * if the transcoding failed. + * The value of @inlen after return is the number of octets consumed + * if the return value is positive, else unpredictiable. + * The value of @outlen after return is the number of octets produced. + */ +typedef int (* xmlCharEncodingOutputFunc)(unsigned char *out, int *outlen, + const unsigned char *in, int *inlen); + + +/* + * Block defining the handlers for non UTF-8 encodings. + * If iconv is supported, there are two extra fields. + */ + +typedef struct _xmlCharEncodingHandler xmlCharEncodingHandler; +typedef xmlCharEncodingHandler *xmlCharEncodingHandlerPtr; +struct _xmlCharEncodingHandler { + char *name; + xmlCharEncodingInputFunc input; + xmlCharEncodingOutputFunc output; +#ifdef LIBXML_ICONV_ENABLED + iconv_t iconv_in; + iconv_t iconv_out; +#endif /* LIBXML_ICONV_ENABLED */ +}; + +#ifdef __cplusplus +} +#endif +#include +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Interfaces for encoding handlers. + */ +XMLPUBFUN void XMLCALL + xmlInitCharEncodingHandlers (void); +XMLPUBFUN void XMLCALL + xmlCleanupCharEncodingHandlers (void); +XMLPUBFUN void XMLCALL + xmlRegisterCharEncodingHandler (xmlCharEncodingHandlerPtr handler); +XMLPUBFUN xmlCharEncodingHandlerPtr XMLCALL + xmlGetCharEncodingHandler (xmlCharEncoding enc); +XMLPUBFUN xmlCharEncodingHandlerPtr XMLCALL + xmlFindCharEncodingHandler (const char *name); +XMLPUBFUN xmlCharEncodingHandlerPtr XMLCALL + xmlNewCharEncodingHandler (const char *name, + xmlCharEncodingInputFunc input, + xmlCharEncodingOutputFunc output); + +/* + * Interfaces for encoding names and aliases. + */ +XMLPUBFUN int XMLCALL + xmlAddEncodingAlias (const char *name, + const char *alias); +XMLPUBFUN int XMLCALL + xmlDelEncodingAlias (const char *alias); +XMLPUBFUN const char * XMLCALL + xmlGetEncodingAlias (const char *alias); +XMLPUBFUN void XMLCALL + xmlCleanupEncodingAliases (void); +XMLPUBFUN xmlCharEncoding XMLCALL + xmlParseCharEncoding (const char *name); +XMLPUBFUN const char * XMLCALL + xmlGetCharEncodingName (xmlCharEncoding enc); + +/* + * Interfaces directly used by the parsers. + */ +XMLPUBFUN xmlCharEncoding XMLCALL + xmlDetectCharEncoding (const unsigned char *in, + int len); + +XMLPUBFUN int XMLCALL + xmlCharEncOutFunc (xmlCharEncodingHandler *handler, + xmlBufferPtr out, + xmlBufferPtr in); + +XMLPUBFUN int XMLCALL + xmlCharEncInFunc (xmlCharEncodingHandler *handler, + xmlBufferPtr out, + xmlBufferPtr in); +XMLPUBFUN int XMLCALL + xmlCharEncFirstLine (xmlCharEncodingHandler *handler, + xmlBufferPtr out, + xmlBufferPtr in); +XMLPUBFUN int XMLCALL + xmlCharEncCloseFunc (xmlCharEncodingHandler *handler); + +/* + * Export a few useful functions + */ +#ifdef LIBXML_OUTPUT_ENABLED +XMLPUBFUN int XMLCALL + UTF8Toisolat1 (unsigned char *out, + int *outlen, + const unsigned char *in, + int *inlen); +#endif /* LIBXML_OUTPUT_ENABLED */ +XMLPUBFUN int XMLCALL + isolat1ToUTF8 (unsigned char *out, + int *outlen, + const unsigned char *in, + int *inlen); +#ifdef __cplusplus +} +#endif + +#endif /* __XML_CHAR_ENCODING_H__ */ diff --git a/android/native/libxml2/libxml/entities.h b/android/native/libxml2/libxml/entities.h new file mode 100644 index 0000000000..cefb97f780 --- /dev/null +++ b/android/native/libxml2/libxml/entities.h @@ -0,0 +1,150 @@ +/* + * Summary: interface for the XML entities handling + * Description: this module provides some of the entity API needed + * for the parser and applications. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_ENTITIES_H__ +#define __XML_ENTITIES_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * The different valid entity types. + */ +typedef enum { + XML_INTERNAL_GENERAL_ENTITY = 1, + XML_EXTERNAL_GENERAL_PARSED_ENTITY = 2, + XML_EXTERNAL_GENERAL_UNPARSED_ENTITY = 3, + XML_INTERNAL_PARAMETER_ENTITY = 4, + XML_EXTERNAL_PARAMETER_ENTITY = 5, + XML_INTERNAL_PREDEFINED_ENTITY = 6 +} xmlEntityType; + +/* + * An unit of storage for an entity, contains the string, the value + * and the linkind data needed for the linking in the hash table. + */ + +struct _xmlEntity { + void *_private; /* application data */ + xmlElementType type; /* XML_ENTITY_DECL, must be second ! */ + const xmlChar *name; /* Entity name */ + struct _xmlNode *children; /* First child link */ + struct _xmlNode *last; /* Last child link */ + struct _xmlDtd *parent; /* -> DTD */ + struct _xmlNode *next; /* next sibling link */ + struct _xmlNode *prev; /* previous sibling link */ + struct _xmlDoc *doc; /* the containing document */ + + xmlChar *orig; /* content without ref substitution */ + xmlChar *content; /* content or ndata if unparsed */ + int length; /* the content length */ + xmlEntityType etype; /* The entity type */ + const xmlChar *ExternalID; /* External identifier for PUBLIC */ + const xmlChar *SystemID; /* URI for a SYSTEM or PUBLIC Entity */ + + struct _xmlEntity *nexte; /* unused */ + const xmlChar *URI; /* the full URI as computed */ + int owner; /* does the entity own the childrens */ + int checked; /* was the entity content checked */ + /* this is also used to count entites + * references done from that entity */ +}; + +/* + * All entities are stored in an hash table. + * There is 2 separate hash tables for global and parameter entities. + */ + +typedef struct _xmlHashTable xmlEntitiesTable; +typedef xmlEntitiesTable *xmlEntitiesTablePtr; + +/* + * External functions: + */ + +#ifdef LIBXML_LEGACY_ENABLED +XMLPUBFUN void XMLCALL + xmlInitializePredefinedEntities (void); +#endif /* LIBXML_LEGACY_ENABLED */ + +XMLPUBFUN xmlEntityPtr XMLCALL + xmlNewEntity (xmlDocPtr doc, + const xmlChar *name, + int type, + const xmlChar *ExternalID, + const xmlChar *SystemID, + const xmlChar *content); +XMLPUBFUN xmlEntityPtr XMLCALL + xmlAddDocEntity (xmlDocPtr doc, + const xmlChar *name, + int type, + const xmlChar *ExternalID, + const xmlChar *SystemID, + const xmlChar *content); +XMLPUBFUN xmlEntityPtr XMLCALL + xmlAddDtdEntity (xmlDocPtr doc, + const xmlChar *name, + int type, + const xmlChar *ExternalID, + const xmlChar *SystemID, + const xmlChar *content); +XMLPUBFUN xmlEntityPtr XMLCALL + xmlGetPredefinedEntity (const xmlChar *name); +XMLPUBFUN xmlEntityPtr XMLCALL + xmlGetDocEntity (xmlDocPtr doc, + const xmlChar *name); +XMLPUBFUN xmlEntityPtr XMLCALL + xmlGetDtdEntity (xmlDocPtr doc, + const xmlChar *name); +XMLPUBFUN xmlEntityPtr XMLCALL + xmlGetParameterEntity (xmlDocPtr doc, + const xmlChar *name); +#ifdef LIBXML_LEGACY_ENABLED +XMLPUBFUN const xmlChar * XMLCALL + xmlEncodeEntities (xmlDocPtr doc, + const xmlChar *input); +#endif /* LIBXML_LEGACY_ENABLED */ +XMLPUBFUN xmlChar * XMLCALL + xmlEncodeEntitiesReentrant(xmlDocPtr doc, + const xmlChar *input); +XMLPUBFUN xmlChar * XMLCALL + xmlEncodeSpecialChars (xmlDocPtr doc, + const xmlChar *input); +XMLPUBFUN xmlEntitiesTablePtr XMLCALL + xmlCreateEntitiesTable (void); +#ifdef LIBXML_TREE_ENABLED +XMLPUBFUN xmlEntitiesTablePtr XMLCALL + xmlCopyEntitiesTable (xmlEntitiesTablePtr table); +#endif /* LIBXML_TREE_ENABLED */ +XMLPUBFUN void XMLCALL + xmlFreeEntitiesTable (xmlEntitiesTablePtr table); +#ifdef LIBXML_OUTPUT_ENABLED +XMLPUBFUN void XMLCALL + xmlDumpEntitiesTable (xmlBufferPtr buf, + xmlEntitiesTablePtr table); +XMLPUBFUN void XMLCALL + xmlDumpEntityDecl (xmlBufferPtr buf, + xmlEntityPtr ent); +#endif /* LIBXML_OUTPUT_ENABLED */ +#ifdef LIBXML_LEGACY_ENABLED +XMLPUBFUN void XMLCALL + xmlCleanupPredefinedEntities(void); +#endif /* LIBXML_LEGACY_ENABLED */ + + +#ifdef __cplusplus +} +#endif + +# endif /* __XML_ENTITIES_H__ */ diff --git a/android/native/libxml2/libxml/globals.h b/android/native/libxml2/libxml/globals.h new file mode 100644 index 0000000000..fc974b2ce1 --- /dev/null +++ b/android/native/libxml2/libxml/globals.h @@ -0,0 +1,492 @@ +/* + * Summary: interface for all global variables of the library + * Description: all the global variables and thread handling for + * those variables is handled by this module. + * + * The bottom of this file is automatically generated by build_glob.py + * based on the description file global.data + * + * Copy: See Copyright for the status of this software. + * + * Author: Gary Pennington , Daniel Veillard + */ + +#ifndef __XML_GLOBALS_H +#define __XML_GLOBALS_H + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +XMLPUBFUN void XMLCALL xmlInitGlobals(void); +XMLPUBFUN void XMLCALL xmlCleanupGlobals(void); + +/** + * xmlParserInputBufferCreateFilenameFunc: + * @URI: the URI to read from + * @enc: the requested source encoding + * + * Signature for the function doing the lookup for a suitable input method + * corresponding to an URI. + * + * Returns the new xmlParserInputBufferPtr in case of success or NULL if no + * method was found. + */ +typedef xmlParserInputBufferPtr (*xmlParserInputBufferCreateFilenameFunc) (const char *URI, xmlCharEncoding enc); + +/** + * xmlOutputBufferCreateFilenameFunc: + * @URI: the URI to write to + * @enc: the requested target encoding + * + * Signature for the function doing the lookup for a suitable output method + * corresponding to an URI. + * + * Returns the new xmlOutputBufferPtr in case of success or NULL if no + * method was found. + */ +typedef xmlOutputBufferPtr (*xmlOutputBufferCreateFilenameFunc) (const char *URI, xmlCharEncodingHandlerPtr encoder, int compression); + +XMLPUBFUN xmlParserInputBufferCreateFilenameFunc +XMLCALL xmlParserInputBufferCreateFilenameDefault (xmlParserInputBufferCreateFilenameFunc func); +XMLPUBFUN xmlOutputBufferCreateFilenameFunc +XMLCALL xmlOutputBufferCreateFilenameDefault (xmlOutputBufferCreateFilenameFunc func); + +/* + * Externally global symbols which need to be protected for backwards + * compatibility support. + */ + +#undef docbDefaultSAXHandler +#undef htmlDefaultSAXHandler +#undef oldXMLWDcompatibility +#undef xmlBufferAllocScheme +#undef xmlDefaultBufferSize +#undef xmlDefaultSAXHandler +#undef xmlDefaultSAXLocator +#undef xmlDoValidityCheckingDefaultValue +#undef xmlFree +#undef xmlGenericError +#undef xmlStructuredError +#undef xmlGenericErrorContext +#undef xmlStructuredErrorContext +#undef xmlGetWarningsDefaultValue +#undef xmlIndentTreeOutput +#undef xmlTreeIndentString +#undef xmlKeepBlanksDefaultValue +#undef xmlLineNumbersDefaultValue +#undef xmlLoadExtDtdDefaultValue +#undef xmlMalloc +#undef xmlMallocAtomic +#undef xmlMemStrdup +#undef xmlParserDebugEntities +#undef xmlParserVersion +#undef xmlPedanticParserDefaultValue +#undef xmlRealloc +#undef xmlSaveNoEmptyTags +#undef xmlSubstituteEntitiesDefaultValue +#undef xmlRegisterNodeDefaultValue +#undef xmlDeregisterNodeDefaultValue +#undef xmlLastError +#undef xmlParserInputBufferCreateFilenameValue +#undef xmlOutputBufferCreateFilenameValue + +/** + * xmlRegisterNodeFunc: + * @node: the current node + * + * Signature for the registration callback of a created node + */ +typedef void (*xmlRegisterNodeFunc) (xmlNodePtr node); +/** + * xmlDeregisterNodeFunc: + * @node: the current node + * + * Signature for the deregistration callback of a discarded node + */ +typedef void (*xmlDeregisterNodeFunc) (xmlNodePtr node); + +typedef struct _xmlGlobalState xmlGlobalState; +typedef xmlGlobalState *xmlGlobalStatePtr; +struct _xmlGlobalState +{ + const char *xmlParserVersion; + + xmlSAXLocator xmlDefaultSAXLocator; + xmlSAXHandlerV1 xmlDefaultSAXHandler; + xmlSAXHandlerV1 docbDefaultSAXHandler; + xmlSAXHandlerV1 htmlDefaultSAXHandler; + + xmlFreeFunc xmlFree; + xmlMallocFunc xmlMalloc; + xmlStrdupFunc xmlMemStrdup; + xmlReallocFunc xmlRealloc; + + xmlGenericErrorFunc xmlGenericError; + xmlStructuredErrorFunc xmlStructuredError; + void *xmlGenericErrorContext; + + int oldXMLWDcompatibility; + + xmlBufferAllocationScheme xmlBufferAllocScheme; + int xmlDefaultBufferSize; + + int xmlSubstituteEntitiesDefaultValue; + int xmlDoValidityCheckingDefaultValue; + int xmlGetWarningsDefaultValue; + int xmlKeepBlanksDefaultValue; + int xmlLineNumbersDefaultValue; + int xmlLoadExtDtdDefaultValue; + int xmlParserDebugEntities; + int xmlPedanticParserDefaultValue; + + int xmlSaveNoEmptyTags; + int xmlIndentTreeOutput; + const char *xmlTreeIndentString; + + xmlRegisterNodeFunc xmlRegisterNodeDefaultValue; + xmlDeregisterNodeFunc xmlDeregisterNodeDefaultValue; + + xmlMallocFunc xmlMallocAtomic; + xmlError xmlLastError; + + xmlParserInputBufferCreateFilenameFunc xmlParserInputBufferCreateFilenameValue; + xmlOutputBufferCreateFilenameFunc xmlOutputBufferCreateFilenameValue; + + void *xmlStructuredErrorContext; +}; + +#ifdef __cplusplus +} +#endif +#include +#ifdef __cplusplus +extern "C" { +#endif + +XMLPUBFUN void XMLCALL xmlInitializeGlobalState(xmlGlobalStatePtr gs); + +XMLPUBFUN void XMLCALL xmlThrDefSetGenericErrorFunc(void *ctx, xmlGenericErrorFunc handler); + +XMLPUBFUN void XMLCALL xmlThrDefSetStructuredErrorFunc(void *ctx, xmlStructuredErrorFunc handler); + +XMLPUBFUN xmlRegisterNodeFunc XMLCALL xmlRegisterNodeDefault(xmlRegisterNodeFunc func); +XMLPUBFUN xmlRegisterNodeFunc XMLCALL xmlThrDefRegisterNodeDefault(xmlRegisterNodeFunc func); +XMLPUBFUN xmlDeregisterNodeFunc XMLCALL xmlDeregisterNodeDefault(xmlDeregisterNodeFunc func); +XMLPUBFUN xmlDeregisterNodeFunc XMLCALL xmlThrDefDeregisterNodeDefault(xmlDeregisterNodeFunc func); + +XMLPUBFUN xmlOutputBufferCreateFilenameFunc XMLCALL + xmlThrDefOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func); +XMLPUBFUN xmlParserInputBufferCreateFilenameFunc XMLCALL + xmlThrDefParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func); + +/** DOC_DISABLE */ +/* + * In general the memory allocation entry points are not kept + * thread specific but this can be overridden by LIBXML_THREAD_ALLOC_ENABLED + * - xmlMalloc + * - xmlMallocAtomic + * - xmlRealloc + * - xmlMemStrdup + * - xmlFree + */ + +#ifdef LIBXML_THREAD_ALLOC_ENABLED +#ifdef LIBXML_THREAD_ENABLED +XMLPUBFUN xmlMallocFunc * XMLCALL __xmlMalloc(void); +#define xmlMalloc \ +(*(__xmlMalloc())) +#else +XMLPUBVAR xmlMallocFunc xmlMalloc; +#endif + +#ifdef LIBXML_THREAD_ENABLED +XMLPUBFUN xmlMallocFunc * XMLCALL __xmlMallocAtomic(void); +#define xmlMallocAtomic \ +(*(__xmlMallocAtomic())) +#else +XMLPUBVAR xmlMallocFunc xmlMallocAtomic; +#endif + +#ifdef LIBXML_THREAD_ENABLED +XMLPUBFUN xmlReallocFunc * XMLCALL __xmlRealloc(void); +#define xmlRealloc \ +(*(__xmlRealloc())) +#else +XMLPUBVAR xmlReallocFunc xmlRealloc; +#endif + +#ifdef LIBXML_THREAD_ENABLED +XMLPUBFUN xmlFreeFunc * XMLCALL __xmlFree(void); +#define xmlFree \ +(*(__xmlFree())) +#else +XMLPUBVAR xmlFreeFunc xmlFree; +#endif + +#ifdef LIBXML_THREAD_ENABLED +XMLPUBFUN xmlStrdupFunc * XMLCALL __xmlMemStrdup(void); +#define xmlMemStrdup \ +(*(__xmlMemStrdup())) +#else +XMLPUBVAR xmlStrdupFunc xmlMemStrdup; +#endif + +#else /* !LIBXML_THREAD_ALLOC_ENABLED */ +XMLPUBVAR xmlMallocFunc xmlMalloc; +XMLPUBVAR xmlMallocFunc xmlMallocAtomic; +XMLPUBVAR xmlReallocFunc xmlRealloc; +XMLPUBVAR xmlFreeFunc xmlFree; +XMLPUBVAR xmlStrdupFunc xmlMemStrdup; +#endif /* LIBXML_THREAD_ALLOC_ENABLED */ + +#ifdef LIBXML_DOCB_ENABLED +XMLPUBFUN xmlSAXHandlerV1 * XMLCALL __docbDefaultSAXHandler(void); +#ifdef LIBXML_THREAD_ENABLED +#define docbDefaultSAXHandler \ +(*(__docbDefaultSAXHandler())) +#else +XMLPUBVAR xmlSAXHandlerV1 docbDefaultSAXHandler; +#endif +#endif + +XMLPUBFUN xmlError * XMLCALL __xmlLastError(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlLastError \ +(*(__xmlLastError())) +#else +XMLPUBVAR xmlError xmlLastError; +#endif + +/* + * Everything starting from the line below is + * Automatically generated by build_glob.py. + * Do not modify the previous line. + */ + + +XMLPUBFUN int * XMLCALL __oldXMLWDcompatibility(void); +#ifdef LIBXML_THREAD_ENABLED +#define oldXMLWDcompatibility \ +(*(__oldXMLWDcompatibility())) +#else +XMLPUBVAR int oldXMLWDcompatibility; +#endif + +XMLPUBFUN xmlBufferAllocationScheme * XMLCALL __xmlBufferAllocScheme(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlBufferAllocScheme \ +(*(__xmlBufferAllocScheme())) +#else +XMLPUBVAR xmlBufferAllocationScheme xmlBufferAllocScheme; +#endif +XMLPUBFUN xmlBufferAllocationScheme XMLCALL xmlThrDefBufferAllocScheme(xmlBufferAllocationScheme v); + +XMLPUBFUN int * XMLCALL __xmlDefaultBufferSize(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlDefaultBufferSize \ +(*(__xmlDefaultBufferSize())) +#else +XMLPUBVAR int xmlDefaultBufferSize; +#endif +XMLPUBFUN int XMLCALL xmlThrDefDefaultBufferSize(int v); + +XMLPUBFUN xmlSAXHandlerV1 * XMLCALL __xmlDefaultSAXHandler(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlDefaultSAXHandler \ +(*(__xmlDefaultSAXHandler())) +#else +XMLPUBVAR xmlSAXHandlerV1 xmlDefaultSAXHandler; +#endif + +XMLPUBFUN xmlSAXLocator * XMLCALL __xmlDefaultSAXLocator(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlDefaultSAXLocator \ +(*(__xmlDefaultSAXLocator())) +#else +XMLPUBVAR xmlSAXLocator xmlDefaultSAXLocator; +#endif + +XMLPUBFUN int * XMLCALL __xmlDoValidityCheckingDefaultValue(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlDoValidityCheckingDefaultValue \ +(*(__xmlDoValidityCheckingDefaultValue())) +#else +XMLPUBVAR int xmlDoValidityCheckingDefaultValue; +#endif +XMLPUBFUN int XMLCALL xmlThrDefDoValidityCheckingDefaultValue(int v); + +XMLPUBFUN xmlGenericErrorFunc * XMLCALL __xmlGenericError(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlGenericError \ +(*(__xmlGenericError())) +#else +XMLPUBVAR xmlGenericErrorFunc xmlGenericError; +#endif + +XMLPUBFUN xmlStructuredErrorFunc * XMLCALL __xmlStructuredError(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlStructuredError \ +(*(__xmlStructuredError())) +#else +XMLPUBVAR xmlStructuredErrorFunc xmlStructuredError; +#endif + +XMLPUBFUN void * * XMLCALL __xmlGenericErrorContext(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlGenericErrorContext \ +(*(__xmlGenericErrorContext())) +#else +XMLPUBVAR void * xmlGenericErrorContext; +#endif + +XMLPUBFUN void * * XMLCALL __xmlStructuredErrorContext(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlStructuredErrorContext \ +(*(__xmlStructuredErrorContext())) +#else +XMLPUBVAR void * xmlStructuredErrorContext; +#endif + +XMLPUBFUN int * XMLCALL __xmlGetWarningsDefaultValue(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlGetWarningsDefaultValue \ +(*(__xmlGetWarningsDefaultValue())) +#else +XMLPUBVAR int xmlGetWarningsDefaultValue; +#endif +XMLPUBFUN int XMLCALL xmlThrDefGetWarningsDefaultValue(int v); + +XMLPUBFUN int * XMLCALL __xmlIndentTreeOutput(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlIndentTreeOutput \ +(*(__xmlIndentTreeOutput())) +#else +XMLPUBVAR int xmlIndentTreeOutput; +#endif +XMLPUBFUN int XMLCALL xmlThrDefIndentTreeOutput(int v); + +XMLPUBFUN const char * * XMLCALL __xmlTreeIndentString(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlTreeIndentString \ +(*(__xmlTreeIndentString())) +#else +XMLPUBVAR const char * xmlTreeIndentString; +#endif +XMLPUBFUN const char * XMLCALL xmlThrDefTreeIndentString(const char * v); + +XMLPUBFUN int * XMLCALL __xmlKeepBlanksDefaultValue(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlKeepBlanksDefaultValue \ +(*(__xmlKeepBlanksDefaultValue())) +#else +XMLPUBVAR int xmlKeepBlanksDefaultValue; +#endif +XMLPUBFUN int XMLCALL xmlThrDefKeepBlanksDefaultValue(int v); + +XMLPUBFUN int * XMLCALL __xmlLineNumbersDefaultValue(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlLineNumbersDefaultValue \ +(*(__xmlLineNumbersDefaultValue())) +#else +XMLPUBVAR int xmlLineNumbersDefaultValue; +#endif +XMLPUBFUN int XMLCALL xmlThrDefLineNumbersDefaultValue(int v); + +XMLPUBFUN int * XMLCALL __xmlLoadExtDtdDefaultValue(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlLoadExtDtdDefaultValue \ +(*(__xmlLoadExtDtdDefaultValue())) +#else +XMLPUBVAR int xmlLoadExtDtdDefaultValue; +#endif +XMLPUBFUN int XMLCALL xmlThrDefLoadExtDtdDefaultValue(int v); + +XMLPUBFUN int * XMLCALL __xmlParserDebugEntities(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlParserDebugEntities \ +(*(__xmlParserDebugEntities())) +#else +XMLPUBVAR int xmlParserDebugEntities; +#endif +XMLPUBFUN int XMLCALL xmlThrDefParserDebugEntities(int v); + +XMLPUBFUN const char * * XMLCALL __xmlParserVersion(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlParserVersion \ +(*(__xmlParserVersion())) +#else +XMLPUBVAR const char * xmlParserVersion; +#endif + +XMLPUBFUN int * XMLCALL __xmlPedanticParserDefaultValue(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlPedanticParserDefaultValue \ +(*(__xmlPedanticParserDefaultValue())) +#else +XMLPUBVAR int xmlPedanticParserDefaultValue; +#endif +XMLPUBFUN int XMLCALL xmlThrDefPedanticParserDefaultValue(int v); + +XMLPUBFUN int * XMLCALL __xmlSaveNoEmptyTags(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlSaveNoEmptyTags \ +(*(__xmlSaveNoEmptyTags())) +#else +XMLPUBVAR int xmlSaveNoEmptyTags; +#endif +XMLPUBFUN int XMLCALL xmlThrDefSaveNoEmptyTags(int v); + +XMLPUBFUN int * XMLCALL __xmlSubstituteEntitiesDefaultValue(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlSubstituteEntitiesDefaultValue \ +(*(__xmlSubstituteEntitiesDefaultValue())) +#else +XMLPUBVAR int xmlSubstituteEntitiesDefaultValue; +#endif +XMLPUBFUN int XMLCALL xmlThrDefSubstituteEntitiesDefaultValue(int v); + +XMLPUBFUN xmlRegisterNodeFunc * XMLCALL __xmlRegisterNodeDefaultValue(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlRegisterNodeDefaultValue \ +(*(__xmlRegisterNodeDefaultValue())) +#else +XMLPUBVAR xmlRegisterNodeFunc xmlRegisterNodeDefaultValue; +#endif + +XMLPUBFUN xmlDeregisterNodeFunc * XMLCALL __xmlDeregisterNodeDefaultValue(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlDeregisterNodeDefaultValue \ +(*(__xmlDeregisterNodeDefaultValue())) +#else +XMLPUBVAR xmlDeregisterNodeFunc xmlDeregisterNodeDefaultValue; +#endif + +XMLPUBFUN xmlParserInputBufferCreateFilenameFunc * XMLCALL __xmlParserInputBufferCreateFilenameValue(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlParserInputBufferCreateFilenameValue \ +(*(__xmlParserInputBufferCreateFilenameValue())) +#else +XMLPUBVAR xmlParserInputBufferCreateFilenameFunc xmlParserInputBufferCreateFilenameValue; +#endif + +XMLPUBFUN xmlOutputBufferCreateFilenameFunc * XMLCALL __xmlOutputBufferCreateFilenameValue(void); +#ifdef LIBXML_THREAD_ENABLED +#define xmlOutputBufferCreateFilenameValue \ +(*(__xmlOutputBufferCreateFilenameValue())) +#else +XMLPUBVAR xmlOutputBufferCreateFilenameFunc xmlOutputBufferCreateFilenameValue; +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_GLOBALS_H */ diff --git a/android/native/libxml2/libxml/hash.h b/android/native/libxml2/libxml/hash.h new file mode 100644 index 0000000000..7fe4be754c --- /dev/null +++ b/android/native/libxml2/libxml/hash.h @@ -0,0 +1,233 @@ +/* + * Summary: Chained hash tables + * Description: This module implements the hash table support used in + * various places in the library. + * + * Copy: See Copyright for the status of this software. + * + * Author: Bjorn Reese + */ + +#ifndef __XML_HASH_H__ +#define __XML_HASH_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * The hash table. + */ +typedef struct _xmlHashTable xmlHashTable; +typedef xmlHashTable *xmlHashTablePtr; + +#ifdef __cplusplus +} +#endif + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Recent version of gcc produce a warning when a function pointer is assigned + * to an object pointer, or vice versa. The following macro is a dirty hack + * to allow suppression of the warning. If your architecture has function + * pointers which are a different size than a void pointer, there may be some + * serious trouble within the library. + */ +/** + * XML_CAST_FPTR: + * @fptr: pointer to a function + * + * Macro to do a casting from an object pointer to a + * function pointer without encountering a warning from + * gcc + * + * #define XML_CAST_FPTR(fptr) (*(void **)(&fptr)) + * This macro violated ISO C aliasing rules (gcc4 on s390 broke) + * so it is disabled now + */ + +#define XML_CAST_FPTR(fptr) fptr + + +/* + * function types: + */ +/** + * xmlHashDeallocator: + * @payload: the data in the hash + * @name: the name associated + * + * Callback to free data from a hash. + */ +typedef void (*xmlHashDeallocator)(void *payload, xmlChar *name); +/** + * xmlHashCopier: + * @payload: the data in the hash + * @name: the name associated + * + * Callback to copy data from a hash. + * + * Returns a copy of the data or NULL in case of error. + */ +typedef void *(*xmlHashCopier)(void *payload, xmlChar *name); +/** + * xmlHashScanner: + * @payload: the data in the hash + * @data: extra scannner data + * @name: the name associated + * + * Callback when scanning data in a hash with the simple scanner. + */ +typedef void (*xmlHashScanner)(void *payload, void *data, xmlChar *name); +/** + * xmlHashScannerFull: + * @payload: the data in the hash + * @data: extra scannner data + * @name: the name associated + * @name2: the second name associated + * @name3: the third name associated + * + * Callback when scanning data in a hash with the full scanner. + */ +typedef void (*xmlHashScannerFull)(void *payload, void *data, + const xmlChar *name, const xmlChar *name2, + const xmlChar *name3); + +/* + * Constructor and destructor. + */ +XMLPUBFUN xmlHashTablePtr XMLCALL + xmlHashCreate (int size); +XMLPUBFUN xmlHashTablePtr XMLCALL + xmlHashCreateDict(int size, + xmlDictPtr dict); +XMLPUBFUN void XMLCALL + xmlHashFree (xmlHashTablePtr table, + xmlHashDeallocator f); + +/* + * Add a new entry to the hash table. + */ +XMLPUBFUN int XMLCALL + xmlHashAddEntry (xmlHashTablePtr table, + const xmlChar *name, + void *userdata); +XMLPUBFUN int XMLCALL + xmlHashUpdateEntry(xmlHashTablePtr table, + const xmlChar *name, + void *userdata, + xmlHashDeallocator f); +XMLPUBFUN int XMLCALL + xmlHashAddEntry2(xmlHashTablePtr table, + const xmlChar *name, + const xmlChar *name2, + void *userdata); +XMLPUBFUN int XMLCALL + xmlHashUpdateEntry2(xmlHashTablePtr table, + const xmlChar *name, + const xmlChar *name2, + void *userdata, + xmlHashDeallocator f); +XMLPUBFUN int XMLCALL + xmlHashAddEntry3(xmlHashTablePtr table, + const xmlChar *name, + const xmlChar *name2, + const xmlChar *name3, + void *userdata); +XMLPUBFUN int XMLCALL + xmlHashUpdateEntry3(xmlHashTablePtr table, + const xmlChar *name, + const xmlChar *name2, + const xmlChar *name3, + void *userdata, + xmlHashDeallocator f); + +/* + * Remove an entry from the hash table. + */ +XMLPUBFUN int XMLCALL + xmlHashRemoveEntry(xmlHashTablePtr table, const xmlChar *name, + xmlHashDeallocator f); +XMLPUBFUN int XMLCALL + xmlHashRemoveEntry2(xmlHashTablePtr table, const xmlChar *name, + const xmlChar *name2, xmlHashDeallocator f); +XMLPUBFUN int XMLCALL + xmlHashRemoveEntry3(xmlHashTablePtr table, const xmlChar *name, + const xmlChar *name2, const xmlChar *name3, + xmlHashDeallocator f); + +/* + * Retrieve the userdata. + */ +XMLPUBFUN void * XMLCALL + xmlHashLookup (xmlHashTablePtr table, + const xmlChar *name); +XMLPUBFUN void * XMLCALL + xmlHashLookup2 (xmlHashTablePtr table, + const xmlChar *name, + const xmlChar *name2); +XMLPUBFUN void * XMLCALL + xmlHashLookup3 (xmlHashTablePtr table, + const xmlChar *name, + const xmlChar *name2, + const xmlChar *name3); +XMLPUBFUN void * XMLCALL + xmlHashQLookup (xmlHashTablePtr table, + const xmlChar *name, + const xmlChar *prefix); +XMLPUBFUN void * XMLCALL + xmlHashQLookup2 (xmlHashTablePtr table, + const xmlChar *name, + const xmlChar *prefix, + const xmlChar *name2, + const xmlChar *prefix2); +XMLPUBFUN void * XMLCALL + xmlHashQLookup3 (xmlHashTablePtr table, + const xmlChar *name, + const xmlChar *prefix, + const xmlChar *name2, + const xmlChar *prefix2, + const xmlChar *name3, + const xmlChar *prefix3); + +/* + * Helpers. + */ +XMLPUBFUN xmlHashTablePtr XMLCALL + xmlHashCopy (xmlHashTablePtr table, + xmlHashCopier f); +XMLPUBFUN int XMLCALL + xmlHashSize (xmlHashTablePtr table); +XMLPUBFUN void XMLCALL + xmlHashScan (xmlHashTablePtr table, + xmlHashScanner f, + void *data); +XMLPUBFUN void XMLCALL + xmlHashScan3 (xmlHashTablePtr table, + const xmlChar *name, + const xmlChar *name2, + const xmlChar *name3, + xmlHashScanner f, + void *data); +XMLPUBFUN void XMLCALL + xmlHashScanFull (xmlHashTablePtr table, + xmlHashScannerFull f, + void *data); +XMLPUBFUN void XMLCALL + xmlHashScanFull3(xmlHashTablePtr table, + const xmlChar *name, + const xmlChar *name2, + const xmlChar *name3, + xmlHashScannerFull f, + void *data); +#ifdef __cplusplus +} +#endif +#endif /* ! __XML_HASH_H__ */ diff --git a/android/native/libxml2/libxml/list.h b/android/native/libxml2/libxml/list.h new file mode 100644 index 0000000000..1d83482430 --- /dev/null +++ b/android/native/libxml2/libxml/list.h @@ -0,0 +1,137 @@ +/* + * Summary: lists interfaces + * Description: this module implement the list support used in + * various place in the library. + * + * Copy: See Copyright for the status of this software. + * + * Author: Gary Pennington + */ + +#ifndef __XML_LINK_INCLUDE__ +#define __XML_LINK_INCLUDE__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _xmlLink xmlLink; +typedef xmlLink *xmlLinkPtr; + +typedef struct _xmlList xmlList; +typedef xmlList *xmlListPtr; + +/** + * xmlListDeallocator: + * @lk: the data to deallocate + * + * Callback function used to free data from a list. + */ +typedef void (*xmlListDeallocator) (xmlLinkPtr lk); +/** + * xmlListDataCompare: + * @data0: the first data + * @data1: the second data + * + * Callback function used to compare 2 data. + * + * Returns 0 is equality, -1 or 1 otherwise depending on the ordering. + */ +typedef int (*xmlListDataCompare) (const void *data0, const void *data1); +/** + * xmlListWalker: + * @data: the data found in the list + * @user: extra user provided data to the walker + * + * Callback function used when walking a list with xmlListWalk(). + * + * Returns 0 to stop walking the list, 1 otherwise. + */ +typedef int (*xmlListWalker) (const void *data, const void *user); + +/* Creation/Deletion */ +XMLPUBFUN xmlListPtr XMLCALL + xmlListCreate (xmlListDeallocator deallocator, + xmlListDataCompare compare); +XMLPUBFUN void XMLCALL + xmlListDelete (xmlListPtr l); + +/* Basic Operators */ +XMLPUBFUN void * XMLCALL + xmlListSearch (xmlListPtr l, + void *data); +XMLPUBFUN void * XMLCALL + xmlListReverseSearch (xmlListPtr l, + void *data); +XMLPUBFUN int XMLCALL + xmlListInsert (xmlListPtr l, + void *data) ; +XMLPUBFUN int XMLCALL + xmlListAppend (xmlListPtr l, + void *data) ; +XMLPUBFUN int XMLCALL + xmlListRemoveFirst (xmlListPtr l, + void *data); +XMLPUBFUN int XMLCALL + xmlListRemoveLast (xmlListPtr l, + void *data); +XMLPUBFUN int XMLCALL + xmlListRemoveAll (xmlListPtr l, + void *data); +XMLPUBFUN void XMLCALL + xmlListClear (xmlListPtr l); +XMLPUBFUN int XMLCALL + xmlListEmpty (xmlListPtr l); +XMLPUBFUN xmlLinkPtr XMLCALL + xmlListFront (xmlListPtr l); +XMLPUBFUN xmlLinkPtr XMLCALL + xmlListEnd (xmlListPtr l); +XMLPUBFUN int XMLCALL + xmlListSize (xmlListPtr l); + +XMLPUBFUN void XMLCALL + xmlListPopFront (xmlListPtr l); +XMLPUBFUN void XMLCALL + xmlListPopBack (xmlListPtr l); +XMLPUBFUN int XMLCALL + xmlListPushFront (xmlListPtr l, + void *data); +XMLPUBFUN int XMLCALL + xmlListPushBack (xmlListPtr l, + void *data); + +/* Advanced Operators */ +XMLPUBFUN void XMLCALL + xmlListReverse (xmlListPtr l); +XMLPUBFUN void XMLCALL + xmlListSort (xmlListPtr l); +XMLPUBFUN void XMLCALL + xmlListWalk (xmlListPtr l, + xmlListWalker walker, + const void *user); +XMLPUBFUN void XMLCALL + xmlListReverseWalk (xmlListPtr l, + xmlListWalker walker, + const void *user); +XMLPUBFUN void XMLCALL + xmlListMerge (xmlListPtr l1, + xmlListPtr l2); +XMLPUBFUN xmlListPtr XMLCALL + xmlListDup (const xmlListPtr old); +XMLPUBFUN int XMLCALL + xmlListCopy (xmlListPtr cur, + const xmlListPtr old); +/* Link operators */ +XMLPUBFUN void * XMLCALL + xmlLinkGetData (xmlLinkPtr lk); + +/* xmlListUnique() */ +/* xmlListSwap */ + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_LINK_INCLUDE__ */ diff --git a/android/native/libxml2/libxml/nanohttp.h b/android/native/libxml2/libxml/nanohttp.h new file mode 100644 index 0000000000..5f21368bc3 --- /dev/null +++ b/android/native/libxml2/libxml/nanohttp.h @@ -0,0 +1,16 @@ +/* + * Summary: minimal HTTP implementation + * Description: minimal HTTP implementation allowing to fetch resources + * like external subset. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __NANO_HTTP_H__ +#define __NANO_HTTP_H__ + +#include + +#endif /* __NANO_HTTP_H__ */ diff --git a/android/native/libxml2/libxml/parser.h b/android/native/libxml2/libxml/parser.h new file mode 100644 index 0000000000..54f16608b3 --- /dev/null +++ b/android/native/libxml2/libxml/parser.h @@ -0,0 +1,1237 @@ +/* + * Summary: the core parser module + * Description: Interfaces, constants and types related to the XML parser + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_PARSER_H__ +#define __XML_PARSER_H__ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * XML_DEFAULT_VERSION: + * + * The default version of XML used: 1.0 + */ +#define XML_DEFAULT_VERSION "1.0" + +/** + * xmlParserInput: + * + * An xmlParserInput is an input flow for the XML processor. + * Each entity parsed is associated an xmlParserInput (except the + * few predefined ones). This is the case both for internal entities + * - in which case the flow is already completely in memory - or + * external entities - in which case we use the buf structure for + * progressive reading and I18N conversions to the internal UTF-8 format. + */ + +/** + * xmlParserInputDeallocate: + * @str: the string to deallocate + * + * Callback for freeing some parser input allocations. + */ +typedef void (* xmlParserInputDeallocate)(xmlChar *str); + +struct _xmlParserInput { + /* Input buffer */ + xmlParserInputBufferPtr buf; /* UTF-8 encoded buffer */ + + const char *filename; /* The file analyzed, if any */ + const char *directory; /* the directory/base of the file */ + 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 line; /* Current line */ + int col; /* Current column */ + /* + * NOTE: consumed is only tested for equality in the parser code, + * so even if there is an overflow this should not give troubles + * for parsing very large instances. + */ + unsigned long consumed; /* How many xmlChars already consumed */ + xmlParserInputDeallocate free; /* function to deallocate the base */ + const xmlChar *encoding; /* the encoding string for entity */ + const xmlChar *version; /* the version string for entity */ + int standalone; /* Was that entity marked standalone */ + int id; /* an unique identifier for the entity */ +}; + +/** + * xmlParserNodeInfo: + * + * The parser can be asked to collect Node informations, i.e. at what + * place in the file they were detected. + * NOTE: This is off by default and not very well tested. + */ +typedef struct _xmlParserNodeInfo xmlParserNodeInfo; +typedef xmlParserNodeInfo *xmlParserNodeInfoPtr; + +struct _xmlParserNodeInfo { + const struct _xmlNode* node; + /* Position & line # that text that created the node begins & ends on */ + unsigned long begin_pos; + unsigned long begin_line; + unsigned long end_pos; + unsigned long end_line; +}; + +typedef struct _xmlParserNodeInfoSeq xmlParserNodeInfoSeq; +typedef xmlParserNodeInfoSeq *xmlParserNodeInfoSeqPtr; +struct _xmlParserNodeInfoSeq { + unsigned long maximum; + unsigned long length; + xmlParserNodeInfo* buffer; +}; + +/** + * xmlParserInputState: + * + * The parser is now working also as a state based parser. + * The recursive one use the state info for entities processing. + */ +typedef enum { + XML_PARSER_EOF = -1, /* nothing is to be parsed */ + XML_PARSER_START = 0, /* nothing has been parsed */ + XML_PARSER_MISC, /* Misc* before int subset */ + XML_PARSER_PI, /* Within a processing instruction */ + XML_PARSER_DTD, /* within some DTD content */ + XML_PARSER_PROLOG, /* Misc* after internal subset */ + XML_PARSER_COMMENT, /* within a comment */ + XML_PARSER_START_TAG, /* within a start tag */ + XML_PARSER_CONTENT, /* within the content */ + XML_PARSER_CDATA_SECTION, /* within a CDATA section */ + XML_PARSER_END_TAG, /* within a closing tag */ + XML_PARSER_ENTITY_DECL, /* within an entity declaration */ + XML_PARSER_ENTITY_VALUE, /* within an entity value in a decl */ + XML_PARSER_ATTRIBUTE_VALUE, /* within an attribute value */ + XML_PARSER_SYSTEM_LITERAL, /* within a SYSTEM value */ + XML_PARSER_EPILOG, /* the Misc* after the last end tag */ + XML_PARSER_IGNORE, /* within an IGNORED section */ + XML_PARSER_PUBLIC_LITERAL /* within a PUBLIC value */ +} xmlParserInputState; + +/** + * XML_DETECT_IDS: + * + * Bit in the loadsubset context field to tell to do ID/REFs lookups. + * Use it to initialize xmlLoadExtDtdDefaultValue. + */ +#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 + +/** + * xmlParserMode: + * + * A parser can operate in various modes + */ +typedef enum { + XML_PARSE_UNKNOWN = 0, + XML_PARSE_DOM = 1, + XML_PARSE_SAX = 2, + XML_PARSE_PUSH_DOM = 3, + XML_PARSE_PUSH_SAX = 4, + XML_PARSE_READER = 5 +} xmlParserMode; + +/** + * xmlParserCtxt: + * + * The parser context. + * NOTE This doesn't completely define the parser state, the (current ?) + * design of the parser uses recursive function calls since this allow + * and easy mapping from the production rules of the specification + * to the actual code. The drawback is that the actual function call + * also reflect the parser state. However most of the parsing routines + * takes as the only argument the parser context pointer, so migrating + * to a state based parser for progressive parsing shouldn't be too hard. + */ +struct _xmlParserCtxt { + struct _xmlSAXHandler *sax; /* The SAX handler */ + void *userData; /* For SAX interface only, used by DOM build */ + xmlDocPtr myDoc; /* the document being built */ + int wellFormed; /* is the document well formed */ + int replaceEntities; /* shall we replace entities ? */ + const xmlChar *version; /* the XML version string */ + const xmlChar *encoding; /* the declared encoding, if any */ + int standalone; /* standalone document */ + int html; /* an HTML(1)/Docbook(2) document + * 3 is HTML after + * 10 is HTML after + */ + + /* Input stream stack */ + xmlParserInputPtr input; /* Current input stream */ + int inputNr; /* Number of current input streams */ + int inputMax; /* Max number of input streams */ + xmlParserInputPtr *inputTab; /* stack of inputs */ + + /* Node analysis stack only used for DOM building */ + xmlNodePtr node; /* Current parsed Node */ + int nodeNr; /* Depth of the parsing stack */ + int nodeMax; /* Max depth of the parsing stack */ + xmlNodePtr *nodeTab; /* array of nodes */ + + int record_info; /* Whether node info should be kept */ + xmlParserNodeInfoSeq node_seq; /* info about each node parsed */ + + int errNo; /* error code */ + + int hasExternalSubset; /* reference and external subset */ + int hasPErefs; /* the internal subset has PE refs */ + int external; /* are we parsing an external entity */ + + 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 */ + + char *directory; /* the data directory */ + + /* Node name stack */ + const xmlChar *name; /* Current parsed Node */ + int nameNr; /* Depth of the parsing stack */ + int nameMax; /* Max depth of the parsing stack */ + const xmlChar * *nameTab; /* array of nodes */ + + long nbChars; /* number of xmlChar processed */ + long checkIndex; /* used by progressive parsing lookup */ + int keepBlanks; /* ugly but ... */ + int disableSAX; /* SAX callbacks are disabled */ + int inSubset; /* Parsing is in int 1/ext 2 subset */ + const xmlChar * intSubName; /* name of subset */ + xmlChar * extSubURI; /* URI of external subset */ + xmlChar * extSubSystem; /* SYSTEM ID of external subset */ + + /* xml:space values */ + int * space; /* Should the parser preserve spaces */ + int spaceNr; /* Depth of the parsing stack */ + int spaceMax; /* Max depth of the parsing stack */ + int * spaceTab; /* array of space infos */ + + int depth; /* to prevent entity substitution loops */ + xmlParserInputPtr entity; /* used to check entities boundaries */ + int charset; /* encoding of the in-memory content + actually an xmlCharEncoding */ + int nodelen; /* Those two fields are there to */ + int nodemem; /* Speed up large node parsing */ + int pedantic; /* signal pedantic warnings */ + void *_private; /* For user data, libxml won't touch it */ + + int loadsubset; /* should the external subset be loaded */ + 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 */ + xmlDictPtr dict; /* dictionnary 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 */ + + /* + * pre-interned strings + */ + const xmlChar *str_xml; + const xmlChar *str_xmlns; + const xmlChar *str_xml_ns; + + /* + * Everything below is used only by the new SAX mode + */ + int sax2; /* operating in the new SAX mode */ + int nsNr; /* the number of inherited namespaces */ + int nsMax; /* the size of the arrays */ + const xmlChar * *nsTab; /* the array of prefix/namespace name */ + int *attallocs; /* which attribute were allocated */ + void * *pushTab; /* array of data for push */ + xmlHashTablePtr attsDefault; /* defaulted attributes if any */ + xmlHashTablePtr attsSpecial; /* non-CDATA attributes if any */ + int nsWellFormed; /* is the document XML Nanespace okay */ + int options; /* Extra options */ + + /* + * Those fields are needed only for treaming parsing so far + */ + int dictNames; /* Use dictionary names for the tree */ + int freeElemsNr; /* number of freed element nodes */ + xmlNodePtr freeElems; /* List of freed element nodes */ + int freeAttrsNr; /* number of freed attributes nodes */ + xmlAttrPtr freeAttrs; /* List of freed attributes nodes */ + + /* + * the complete error informations for the last error. + */ + xmlError lastError; + xmlParserMode parseMode; /* the parser mode */ + unsigned long nbentities; /* number of entities references */ + unsigned long sizeentities; /* size of parsed entities */ + + /* for use by HTML non-recursive parser */ + xmlParserNodeInfo *nodeInfo; /* Current NodeInfo */ + int nodeInfoNr; /* Depth of the parsing stack */ + int nodeInfoMax; /* Max depth of the parsing stack */ + xmlParserNodeInfo *nodeInfoTab; /* array of nodeInfos */ +}; + +/** + * xmlSAXLocator: + * + * A SAX Locator. + */ +struct _xmlSAXLocator { + const xmlChar *(*getPublicId)(void *ctx); + const xmlChar *(*getSystemId)(void *ctx); + int (*getLineNumber)(void *ctx); + int (*getColumnNumber)(void *ctx); +}; + +/** + * xmlSAXHandler: + * + * A SAX handler is bunch of callbacks called by the parser when processing + * of the input generate data or structure informations. + */ + +/** + * resolveEntitySAXFunc: + * @ctx: the user data (XML parser context) + * @publicId: The public ID of the entity + * @systemId: The system ID of the entity + * + * Callback: + * The entity loader, to control the loading of external entities, + * the application can either: + * - override this resolveEntity() callback in the SAX block + * - or better use the xmlSetExternalEntityLoader() function to + * set up it's own entity resolution routine + * + * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour. + */ +typedef xmlParserInputPtr (*resolveEntitySAXFunc) (void *ctx, + const xmlChar *publicId, + const xmlChar *systemId); +/** + * internalSubsetSAXFunc: + * @ctx: the user data (XML parser context) + * @name: the root element name + * @ExternalID: the external ID + * @SystemID: the SYSTEM ID (e.g. filename or URL) + * + * Callback on internal subset declaration. + */ +typedef void (*internalSubsetSAXFunc) (void *ctx, + const xmlChar *name, + const xmlChar *ExternalID, + const xmlChar *SystemID); +/** + * externalSubsetSAXFunc: + * @ctx: the user data (XML parser context) + * @name: the root element name + * @ExternalID: the external ID + * @SystemID: the SYSTEM ID (e.g. filename or URL) + * + * Callback on external subset declaration. + */ +typedef void (*externalSubsetSAXFunc) (void *ctx, + const xmlChar *name, + const xmlChar *ExternalID, + const xmlChar *SystemID); +/** + * getEntitySAXFunc: + * @ctx: the user data (XML parser context) + * @name: The entity name + * + * Get an entity by name. + * + * Returns the xmlEntityPtr if found. + */ +typedef xmlEntityPtr (*getEntitySAXFunc) (void *ctx, + const xmlChar *name); +/** + * getParameterEntitySAXFunc: + * @ctx: the user data (XML parser context) + * @name: The entity name + * + * Get a parameter entity by name. + * + * Returns the xmlEntityPtr if found. + */ +typedef xmlEntityPtr (*getParameterEntitySAXFunc) (void *ctx, + const xmlChar *name); +/** + * entityDeclSAXFunc: + * @ctx: the user data (XML parser context) + * @name: the entity name + * @type: the entity type + * @publicId: The public ID of the entity + * @systemId: The system ID of the entity + * @content: the entity value (without processing). + * + * An entity definition has been parsed. + */ +typedef void (*entityDeclSAXFunc) (void *ctx, + const xmlChar *name, + int type, + const xmlChar *publicId, + const xmlChar *systemId, + xmlChar *content); +/** + * notationDeclSAXFunc: + * @ctx: the user data (XML parser context) + * @name: The name of the notation + * @publicId: The public ID of the entity + * @systemId: The system ID of the entity + * + * What to do when a notation declaration has been parsed. + */ +typedef void (*notationDeclSAXFunc)(void *ctx, + const xmlChar *name, + const xmlChar *publicId, + const xmlChar *systemId); +/** + * attributeDeclSAXFunc: + * @ctx: the user data (XML parser context) + * @elem: the name of the element + * @fullname: the attribute name + * @type: the attribute type + * @def: the type of default value + * @defaultValue: the attribute default value + * @tree: the tree of enumerated value set + * + * An attribute definition has been parsed. + */ +typedef void (*attributeDeclSAXFunc)(void *ctx, + const xmlChar *elem, + const xmlChar *fullname, + int type, + int def, + const xmlChar *defaultValue, + xmlEnumerationPtr tree); +/** + * elementDeclSAXFunc: + * @ctx: the user data (XML parser context) + * @name: the element name + * @type: the element type + * @content: the element value tree + * + * An element definition has been parsed. + */ +typedef void (*elementDeclSAXFunc)(void *ctx, + const xmlChar *name, + int type, + xmlElementContentPtr content); +/** + * unparsedEntityDeclSAXFunc: + * @ctx: the user data (XML parser context) + * @name: The name of the entity + * @publicId: The public ID of the entity + * @systemId: The system ID of the entity + * @notationName: the name of the notation + * + * What to do when an unparsed entity declaration is parsed. + */ +typedef void (*unparsedEntityDeclSAXFunc)(void *ctx, + const xmlChar *name, + const xmlChar *publicId, + const xmlChar *systemId, + const xmlChar *notationName); +/** + * setDocumentLocatorSAXFunc: + * @ctx: the user data (XML parser context) + * @loc: A SAX Locator + * + * Receive the document locator at startup, actually xmlDefaultSAXLocator. + * Everything is available on the context, so this is useless in our case. + */ +typedef void (*setDocumentLocatorSAXFunc) (void *ctx, + xmlSAXLocatorPtr loc); +/** + * startDocumentSAXFunc: + * @ctx: the user data (XML parser context) + * + * Called when the document start being processed. + */ +typedef void (*startDocumentSAXFunc) (void *ctx); +/** + * endDocumentSAXFunc: + * @ctx: the user data (XML parser context) + * + * Called when the document end has been detected. + */ +typedef void (*endDocumentSAXFunc) (void *ctx); +/** + * startElementSAXFunc: + * @ctx: the user data (XML parser context) + * @name: The element name, including namespace prefix + * @atts: An array of name/value attributes pairs, NULL terminated + * + * Called when an opening tag has been processed. + */ +typedef void (*startElementSAXFunc) (void *ctx, + const xmlChar *name, + const xmlChar **atts); +/** + * endElementSAXFunc: + * @ctx: the user data (XML parser context) + * @name: The element name + * + * Called when the end of an element has been detected. + */ +typedef void (*endElementSAXFunc) (void *ctx, + const xmlChar *name); +/** + * attributeSAXFunc: + * @ctx: the user data (XML parser context) + * @name: The attribute name, including namespace prefix + * @value: The attribute value + * + * Handle an attribute that has been read by the parser. + * The default handling is to convert the attribute into an + * DOM subtree and past it in a new xmlAttr element added to + * the element. + */ +typedef void (*attributeSAXFunc) (void *ctx, + const xmlChar *name, + const xmlChar *value); +/** + * referenceSAXFunc: + * @ctx: the user data (XML parser context) + * @name: The entity name + * + * Called when an entity reference is detected. + */ +typedef void (*referenceSAXFunc) (void *ctx, + const xmlChar *name); +/** + * charactersSAXFunc: + * @ctx: the user data (XML parser context) + * @ch: a xmlChar string + * @len: the number of xmlChar + * + * Receiving some chars from the parser. + */ +typedef void (*charactersSAXFunc) (void *ctx, + const xmlChar *ch, + int len); +/** + * ignorableWhitespaceSAXFunc: + * @ctx: the user data (XML parser context) + * @ch: a xmlChar string + * @len: the number of xmlChar + * + * Receiving some ignorable whitespaces from the parser. + * UNUSED: by default the DOM building will use characters. + */ +typedef void (*ignorableWhitespaceSAXFunc) (void *ctx, + const xmlChar *ch, + int len); +/** + * processingInstructionSAXFunc: + * @ctx: the user data (XML parser context) + * @target: the target name + * @data: the PI data's + * + * A processing instruction has been parsed. + */ +typedef void (*processingInstructionSAXFunc) (void *ctx, + const xmlChar *target, + const xmlChar *data); +/** + * commentSAXFunc: + * @ctx: the user data (XML parser context) + * @value: the comment content + * + * A comment has been parsed. + */ +typedef void (*commentSAXFunc) (void *ctx, + const xmlChar *value); +/** + * cdataBlockSAXFunc: + * @ctx: the user data (XML parser context) + * @value: The pcdata content + * @len: the block length + * + * Called when a pcdata block has been parsed. + */ +typedef void (*cdataBlockSAXFunc) ( + void *ctx, + const xmlChar *value, + int len); +/** + * warningSAXFunc: + * @ctx: an XML parser context + * @msg: the message to display/transmit + * @...: extra parameters for the message display + * + * Display and format a warning messages, callback. + */ +typedef void (XMLCDECL *warningSAXFunc) (void *ctx, + const char *msg, ...) LIBXML_ATTR_FORMAT(2,3); +/** + * errorSAXFunc: + * @ctx: an XML parser context + * @msg: the message to display/transmit + * @...: extra parameters for the message display + * + * Display and format an error messages, callback. + */ +typedef void (XMLCDECL *errorSAXFunc) (void *ctx, + const char *msg, ...) LIBXML_ATTR_FORMAT(2,3); +/** + * fatalErrorSAXFunc: + * @ctx: an XML parser context + * @msg: the message to display/transmit + * @...: extra parameters for the message display + * + * Display and format fatal error messages, callback. + * Note: so far fatalError() SAX callbacks are not used, error() + * get all the callbacks for errors. + */ +typedef void (XMLCDECL *fatalErrorSAXFunc) (void *ctx, + const char *msg, ...) LIBXML_ATTR_FORMAT(2,3); +/** + * isStandaloneSAXFunc: + * @ctx: the user data (XML parser context) + * + * Is this document tagged standalone? + * + * Returns 1 if true + */ +typedef int (*isStandaloneSAXFunc) (void *ctx); +/** + * hasInternalSubsetSAXFunc: + * @ctx: the user data (XML parser context) + * + * Does this document has an internal subset. + * + * Returns 1 if true + */ +typedef int (*hasInternalSubsetSAXFunc) (void *ctx); + +/** + * hasExternalSubsetSAXFunc: + * @ctx: the user data (XML parser context) + * + * Does this document has an external subset? + * + * Returns 1 if true + */ +typedef int (*hasExternalSubsetSAXFunc) (void *ctx); + +/************************************************************************ + * * + * The SAX version 2 API extensions * + * * + ************************************************************************/ +/** + * XML_SAX2_MAGIC: + * + * Special constant found in SAX2 blocks initialized fields + */ +#define XML_SAX2_MAGIC 0xDEEDBEAF + +/** + * startElementNsSAX2Func: + * @ctx: the user data (XML parser context) + * @localname: the local name of the element + * @prefix: the element namespace prefix if available + * @URI: the element namespace name if available + * @nb_namespaces: number of namespace definitions on that node + * @namespaces: pointer to the array of prefix/URI pairs namespace definitions + * @nb_attributes: the number of attributes on that node + * @nb_defaulted: the number of defaulted attributes. The defaulted + * ones are at the end of the array + * @attributes: pointer to the array of (localname/prefix/URI/value/end) + * attribute values. + * + * SAX2 callback when an element start has been detected by the parser. + * It provides the namespace informations for the element, as well as + * the new namespace declarations on the element. + */ + +typedef void (*startElementNsSAX2Func) (void *ctx, + const xmlChar *localname, + const xmlChar *prefix, + const xmlChar *URI, + int nb_namespaces, + const xmlChar **namespaces, + int nb_attributes, + int nb_defaulted, + const xmlChar **attributes); + +/** + * endElementNsSAX2Func: + * @ctx: the user data (XML parser context) + * @localname: the local name of the element + * @prefix: the element namespace prefix if available + * @URI: the element namespace name if available + * + * SAX2 callback when an element end has been detected by the parser. + * It provides the namespace informations for the element. + */ + +typedef void (*endElementNsSAX2Func) (void *ctx, + const xmlChar *localname, + const xmlChar *prefix, + const xmlChar *URI); + + +struct _xmlSAXHandler { + internalSubsetSAXFunc internalSubset; + isStandaloneSAXFunc isStandalone; + hasInternalSubsetSAXFunc hasInternalSubset; + hasExternalSubsetSAXFunc hasExternalSubset; + resolveEntitySAXFunc resolveEntity; + getEntitySAXFunc getEntity; + entityDeclSAXFunc entityDecl; + notationDeclSAXFunc notationDecl; + attributeDeclSAXFunc attributeDecl; + elementDeclSAXFunc elementDecl; + unparsedEntityDeclSAXFunc unparsedEntityDecl; + setDocumentLocatorSAXFunc setDocumentLocator; + startDocumentSAXFunc startDocument; + endDocumentSAXFunc endDocument; + startElementSAXFunc startElement; + endElementSAXFunc endElement; + referenceSAXFunc reference; + charactersSAXFunc characters; + ignorableWhitespaceSAXFunc ignorableWhitespace; + processingInstructionSAXFunc processingInstruction; + commentSAXFunc comment; + warningSAXFunc warning; + errorSAXFunc error; + fatalErrorSAXFunc fatalError; /* unused error() get all the errors */ + getParameterEntitySAXFunc getParameterEntity; + cdataBlockSAXFunc cdataBlock; + externalSubsetSAXFunc externalSubset; + unsigned int initialized; + /* The following fields are extensions available only on version 2 */ + void *_private; + startElementNsSAX2Func startElementNs; + endElementNsSAX2Func endElementNs; + xmlStructuredErrorFunc serror; +}; + +/* + * SAX Version 1 + */ +typedef struct _xmlSAXHandlerV1 xmlSAXHandlerV1; +typedef xmlSAXHandlerV1 *xmlSAXHandlerV1Ptr; +struct _xmlSAXHandlerV1 { + internalSubsetSAXFunc internalSubset; + isStandaloneSAXFunc isStandalone; + hasInternalSubsetSAXFunc hasInternalSubset; + hasExternalSubsetSAXFunc hasExternalSubset; + resolveEntitySAXFunc resolveEntity; + getEntitySAXFunc getEntity; + entityDeclSAXFunc entityDecl; + notationDeclSAXFunc notationDecl; + attributeDeclSAXFunc attributeDecl; + elementDeclSAXFunc elementDecl; + unparsedEntityDeclSAXFunc unparsedEntityDecl; + setDocumentLocatorSAXFunc setDocumentLocator; + startDocumentSAXFunc startDocument; + endDocumentSAXFunc endDocument; + startElementSAXFunc startElement; + endElementSAXFunc endElement; + referenceSAXFunc reference; + charactersSAXFunc characters; + ignorableWhitespaceSAXFunc ignorableWhitespace; + processingInstructionSAXFunc processingInstruction; + commentSAXFunc comment; + warningSAXFunc warning; + errorSAXFunc error; + fatalErrorSAXFunc fatalError; /* unused error() get all the errors */ + getParameterEntitySAXFunc getParameterEntity; + cdataBlockSAXFunc cdataBlock; + externalSubsetSAXFunc externalSubset; + unsigned int initialized; +}; + + +/** + * xmlExternalEntityLoader: + * @URL: The System ID of the resource requested + * @ID: The Public ID of the resource requested + * @context: the XML parser context + * + * External entity loaders types. + * + * Returns the entity input parser. + */ +typedef xmlParserInputPtr (*xmlExternalEntityLoader) (const char *URL, + const char *ID, + xmlParserCtxtPtr context); + +#ifdef __cplusplus +} +#endif + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/* + * Init/Cleanup + */ +XMLPUBFUN void XMLCALL + xmlInitParser (void); +XMLPUBFUN void XMLCALL + xmlCleanupParser (void); + +/* + * Input functions + */ +XMLPUBFUN int XMLCALL + xmlParserInputRead (xmlParserInputPtr in, + int len); +XMLPUBFUN int XMLCALL + xmlParserInputGrow (xmlParserInputPtr in, + int len); + +/* + * Basic parsing Interfaces + */ +#ifdef LIBXML_SAX1_ENABLED +XMLPUBFUN xmlDocPtr XMLCALL + xmlParseDoc (const xmlChar *cur); +XMLPUBFUN xmlDocPtr XMLCALL + xmlParseFile (const char *filename); +XMLPUBFUN xmlDocPtr XMLCALL + xmlParseMemory (const char *buffer, + int size); +#endif /* LIBXML_SAX1_ENABLED */ +XMLPUBFUN int XMLCALL + xmlSubstituteEntitiesDefault(int val); +XMLPUBFUN int XMLCALL + xmlKeepBlanksDefault (int val); +XMLPUBFUN void XMLCALL + xmlStopParser (xmlParserCtxtPtr ctxt); +XMLPUBFUN int XMLCALL + xmlPedanticParserDefault(int val); +XMLPUBFUN int XMLCALL + xmlLineNumbersDefault (int val); + +#ifdef LIBXML_SAX1_ENABLED +/* + * Recovery mode + */ +XMLPUBFUN xmlDocPtr XMLCALL + xmlRecoverDoc (const xmlChar *cur); +XMLPUBFUN xmlDocPtr XMLCALL + xmlRecoverMemory (const char *buffer, + int size); +XMLPUBFUN xmlDocPtr XMLCALL + xmlRecoverFile (const char *filename); +#endif /* LIBXML_SAX1_ENABLED */ + +/* + * Less common routines and SAX interfaces + */ +XMLPUBFUN int XMLCALL + xmlParseDocument (xmlParserCtxtPtr ctxt); +XMLPUBFUN int XMLCALL + xmlParseExtParsedEnt (xmlParserCtxtPtr ctxt); +#ifdef LIBXML_SAX1_ENABLED +XMLPUBFUN int XMLCALL + xmlSAXUserParseFile (xmlSAXHandlerPtr sax, + void *user_data, + const char *filename); +XMLPUBFUN int XMLCALL + xmlSAXUserParseMemory (xmlSAXHandlerPtr sax, + void *user_data, + const char *buffer, + int size); +XMLPUBFUN xmlDocPtr XMLCALL + xmlSAXParseDoc (xmlSAXHandlerPtr sax, + const xmlChar *cur, + int recovery); +XMLPUBFUN xmlDocPtr XMLCALL + xmlSAXParseMemory (xmlSAXHandlerPtr sax, + const char *buffer, + int size, + int recovery); +XMLPUBFUN xmlDocPtr XMLCALL + xmlSAXParseMemoryWithData (xmlSAXHandlerPtr sax, + const char *buffer, + int size, + int recovery, + void *data); +XMLPUBFUN xmlDocPtr XMLCALL + xmlSAXParseFile (xmlSAXHandlerPtr sax, + const char *filename, + int recovery); +XMLPUBFUN xmlDocPtr XMLCALL + xmlSAXParseFileWithData (xmlSAXHandlerPtr sax, + const char *filename, + int recovery, + void *data); +XMLPUBFUN xmlDocPtr XMLCALL + xmlSAXParseEntity (xmlSAXHandlerPtr sax, + const char *filename); +XMLPUBFUN xmlDocPtr XMLCALL + xmlParseEntity (const char *filename); +#endif /* LIBXML_SAX1_ENABLED */ + +#ifdef LIBXML_VALID_ENABLED +XMLPUBFUN xmlDtdPtr XMLCALL + xmlSAXParseDTD (xmlSAXHandlerPtr sax, + const xmlChar *ExternalID, + const xmlChar *SystemID); +XMLPUBFUN xmlDtdPtr XMLCALL + xmlParseDTD (const xmlChar *ExternalID, + const xmlChar *SystemID); +XMLPUBFUN xmlDtdPtr XMLCALL + xmlIOParseDTD (xmlSAXHandlerPtr sax, + xmlParserInputBufferPtr input, + xmlCharEncoding enc); +#endif /* LIBXML_VALID_ENABLE */ +#ifdef LIBXML_SAX1_ENABLED +XMLPUBFUN int XMLCALL + xmlParseBalancedChunkMemory(xmlDocPtr doc, + xmlSAXHandlerPtr sax, + void *user_data, + int depth, + const xmlChar *string, + xmlNodePtr *lst); +#endif /* LIBXML_SAX1_ENABLED */ +XMLPUBFUN xmlParserErrors XMLCALL + xmlParseInNodeContext (xmlNodePtr node, + const char *data, + int datalen, + int options, + xmlNodePtr *lst); +#ifdef LIBXML_SAX1_ENABLED +XMLPUBFUN int XMLCALL + xmlParseBalancedChunkMemoryRecover(xmlDocPtr doc, + xmlSAXHandlerPtr sax, + void *user_data, + int depth, + const xmlChar *string, + xmlNodePtr *lst, + int recover); +XMLPUBFUN int XMLCALL + xmlParseExternalEntity (xmlDocPtr doc, + xmlSAXHandlerPtr sax, + void *user_data, + int depth, + const xmlChar *URL, + const xmlChar *ID, + xmlNodePtr *lst); +#endif /* LIBXML_SAX1_ENABLED */ +XMLPUBFUN int XMLCALL + xmlParseCtxtExternalEntity(xmlParserCtxtPtr ctx, + const xmlChar *URL, + const xmlChar *ID, + xmlNodePtr *lst); + +/* + * Parser contexts handling. + */ +XMLPUBFUN xmlParserCtxtPtr XMLCALL + xmlNewParserCtxt (void); +XMLPUBFUN int XMLCALL + xmlInitParserCtxt (xmlParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + xmlClearParserCtxt (xmlParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + xmlFreeParserCtxt (xmlParserCtxtPtr ctxt); +#ifdef LIBXML_SAX1_ENABLED +XMLPUBFUN void XMLCALL + xmlSetupParserForBuffer (xmlParserCtxtPtr ctxt, + const xmlChar* buffer, + const char *filename); +#endif /* LIBXML_SAX1_ENABLED */ +XMLPUBFUN xmlParserCtxtPtr XMLCALL + xmlCreateDocParserCtxt (const xmlChar *cur); + +#ifdef LIBXML_LEGACY_ENABLED +/* + * Reading/setting optional parsing features. + */ +XMLPUBFUN int XMLCALL + xmlGetFeaturesList (int *len, + const char **result); +XMLPUBFUN int XMLCALL + xmlGetFeature (xmlParserCtxtPtr ctxt, + const char *name, + void *result); +XMLPUBFUN int XMLCALL + xmlSetFeature (xmlParserCtxtPtr ctxt, + const char *name, + void *value); +#endif /* LIBXML_LEGACY_ENABLED */ + +#ifdef LIBXML_PUSH_ENABLED +/* + * Interfaces for the Push mode. + */ +XMLPUBFUN xmlParserCtxtPtr XMLCALL + xmlCreatePushParserCtxt(xmlSAXHandlerPtr sax, + void *user_data, + const char *chunk, + int size, + const char *filename); +XMLPUBFUN int XMLCALL + xmlParseChunk (xmlParserCtxtPtr ctxt, + const char *chunk, + int size, + int terminate); +#endif /* LIBXML_PUSH_ENABLED */ + +/* + * Special I/O mode. + */ + +XMLPUBFUN xmlParserCtxtPtr XMLCALL + xmlCreateIOParserCtxt (xmlSAXHandlerPtr sax, + void *user_data, + xmlInputReadCallback ioread, + xmlInputCloseCallback ioclose, + void *ioctx, + xmlCharEncoding enc); + +XMLPUBFUN xmlParserInputPtr XMLCALL + xmlNewIOInputStream (xmlParserCtxtPtr ctxt, + xmlParserInputBufferPtr input, + xmlCharEncoding enc); + +/* + * Node infos. + */ +XMLPUBFUN const xmlParserNodeInfo* XMLCALL + xmlParserFindNodeInfo (const xmlParserCtxtPtr ctxt, + const xmlNodePtr node); +XMLPUBFUN void XMLCALL + xmlInitNodeInfoSeq (xmlParserNodeInfoSeqPtr seq); +XMLPUBFUN void XMLCALL + xmlClearNodeInfoSeq (xmlParserNodeInfoSeqPtr seq); +XMLPUBFUN unsigned long XMLCALL + xmlParserFindNodeInfoIndex(const xmlParserNodeInfoSeqPtr seq, + const xmlNodePtr node); +XMLPUBFUN void XMLCALL + xmlParserAddNodeInfo (xmlParserCtxtPtr ctxt, + const xmlParserNodeInfoPtr info); + +/* + * External entities handling actually implemented in xmlIO. + */ + +XMLPUBFUN void XMLCALL + xmlSetExternalEntityLoader(xmlExternalEntityLoader f); +XMLPUBFUN xmlExternalEntityLoader XMLCALL + xmlGetExternalEntityLoader(void); +XMLPUBFUN xmlParserInputPtr XMLCALL + xmlLoadExternalEntity (const char *URL, + const char *ID, + xmlParserCtxtPtr ctxt); + +/* + * Index lookup, actually implemented in the encoding module + */ +XMLPUBFUN long XMLCALL + xmlByteConsumed (xmlParserCtxtPtr ctxt); + +/* + * New set of simpler/more flexible APIs + */ +/** + * xmlParserOption: + * + * This is the set of XML parser options that can be passed down + * to the xmlReadDoc() and similar calls. + */ +typedef enum { + XML_PARSE_RECOVER = 1<<0, /* recover on errors */ + XML_PARSE_NOENT = 1<<1, /* substitute entities */ + XML_PARSE_DTDLOAD = 1<<2, /* load the external subset */ + XML_PARSE_DTDATTR = 1<<3, /* default DTD attributes */ + XML_PARSE_DTDVALID = 1<<4, /* validate with the DTD */ + XML_PARSE_NOERROR = 1<<5, /* suppress error reports */ + XML_PARSE_NOWARNING = 1<<6, /* suppress warning reports */ + XML_PARSE_PEDANTIC = 1<<7, /* pedantic error reporting */ + XML_PARSE_NOBLANKS = 1<<8, /* remove blank nodes */ + XML_PARSE_SAX1 = 1<<9, /* use the SAX1 interface internally */ + XML_PARSE_XINCLUDE = 1<<10,/* Implement XInclude substitition */ + XML_PARSE_NONET = 1<<11,/* Forbid network access */ + XML_PARSE_NODICT = 1<<12,/* Do not reuse the context dictionnary */ + XML_PARSE_NSCLEAN = 1<<13,/* remove redundant namespaces declarations */ + XML_PARSE_NOCDATA = 1<<14,/* merge CDATA as text nodes */ + XML_PARSE_NOXINCNODE= 1<<15,/* do not generate XINCLUDE START/END nodes */ + XML_PARSE_COMPACT = 1<<16,/* compact small text nodes; no modification of + the tree allowed afterwards (will possibly + crash if you try to modify the tree) */ + XML_PARSE_OLD10 = 1<<17,/* parse using XML-1.0 before update 5 */ + XML_PARSE_NOBASEFIX = 1<<18,/* do not fixup XINCLUDE xml:base uris */ + 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 */ +} xmlParserOption; + +XMLPUBFUN void XMLCALL + xmlCtxtReset (xmlParserCtxtPtr ctxt); +XMLPUBFUN int XMLCALL + xmlCtxtResetPush (xmlParserCtxtPtr ctxt, + const char *chunk, + int size, + const char *filename, + const char *encoding); +XMLPUBFUN int XMLCALL + xmlCtxtUseOptions (xmlParserCtxtPtr ctxt, + int options); +XMLPUBFUN xmlDocPtr XMLCALL + xmlReadDoc (const xmlChar *cur, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN xmlDocPtr XMLCALL + xmlReadFile (const char *URL, + const char *encoding, + int options); +XMLPUBFUN xmlDocPtr XMLCALL + xmlReadMemory (const char *buffer, + int size, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN xmlDocPtr XMLCALL + xmlReadFd (int fd, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN xmlDocPtr XMLCALL + xmlReadIO (xmlInputReadCallback ioread, + xmlInputCloseCallback ioclose, + void *ioctx, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN xmlDocPtr XMLCALL + xmlCtxtReadDoc (xmlParserCtxtPtr ctxt, + const xmlChar *cur, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN xmlDocPtr XMLCALL + xmlCtxtReadFile (xmlParserCtxtPtr ctxt, + const char *filename, + const char *encoding, + int options); +XMLPUBFUN xmlDocPtr XMLCALL + xmlCtxtReadMemory (xmlParserCtxtPtr ctxt, + const char *buffer, + int size, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN xmlDocPtr XMLCALL + xmlCtxtReadFd (xmlParserCtxtPtr ctxt, + int fd, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN xmlDocPtr XMLCALL + xmlCtxtReadIO (xmlParserCtxtPtr ctxt, + xmlInputReadCallback ioread, + xmlInputCloseCallback ioclose, + void *ioctx, + const char *URL, + const char *encoding, + int options); + +/* + * Library wide options + */ +/** + * xmlFeature: + * + * Used to examine the existance of features that can be enabled + * or disabled at compile-time. + * They used to be called XML_FEATURE_xxx but this clashed with Expat + */ +typedef enum { + XML_WITH_THREAD = 1, + XML_WITH_TREE = 2, + XML_WITH_OUTPUT = 3, + XML_WITH_PUSH = 4, + XML_WITH_READER = 5, + XML_WITH_PATTERN = 6, + XML_WITH_WRITER = 7, + XML_WITH_SAX1 = 8, + XML_WITH_FTP = 9, + XML_WITH_HTTP = 10, + XML_WITH_VALID = 11, + XML_WITH_HTML = 12, + XML_WITH_LEGACY = 13, + XML_WITH_C14N = 14, + XML_WITH_CATALOG = 15, + XML_WITH_XPATH = 16, + XML_WITH_XPTR = 17, + XML_WITH_XINCLUDE = 18, + XML_WITH_ICONV = 19, + XML_WITH_ISO8859X = 20, + XML_WITH_UNICODE = 21, + XML_WITH_REGEXP = 22, + XML_WITH_AUTOMATA = 23, + XML_WITH_EXPR = 24, + XML_WITH_SCHEMAS = 25, + XML_WITH_SCHEMATRON = 26, + XML_WITH_MODULES = 27, + XML_WITH_DEBUG = 28, + XML_WITH_DEBUG_MEM = 29, + XML_WITH_DEBUG_RUN = 30, + XML_WITH_ZLIB = 31, + XML_WITH_ICU = 32, + XML_WITH_LZMA = 33, + XML_WITH_NONE = 99999 /* just to be sure of allocation size */ +} xmlFeature; + +XMLPUBFUN int XMLCALL + xmlHasFeature (xmlFeature feature); + +#ifdef __cplusplus +} +#endif +#endif /* __XML_PARSER_H__ */ diff --git a/android/native/libxml2/libxml/parserInternals.h b/android/native/libxml2/libxml/parserInternals.h new file mode 100644 index 0000000000..7172548c79 --- /dev/null +++ b/android/native/libxml2/libxml/parserInternals.h @@ -0,0 +1,602 @@ +/* + * Summary: internals routines exported by the parser. + * Description: this module exports a number of internal parsing routines + * they are not really all intended for applications but + * can prove useful doing low level processing. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_PARSER_INTERNALS_H__ +#define __XML_PARSER_INTERNALS_H__ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * xmlParserMaxDepth: + * + * arbitrary depth limit for the XML documents that we allow to + * process. This is not a limitation of the parser but a safety + * boundary feature, use XML_PARSE_HUGE option to override it. + */ +XMLPUBVAR unsigned int xmlParserMaxDepth; + +/** + * XML_MAX_TEXT_LENGTH: + * + * Maximum size allowed for a single text node when building a tree. + * This is not a limitation of the parser but a safety boundary feature, + * use XML_PARSE_HUGE option to override it. + */ +#define XML_MAX_TEXT_LENGTH 10000000 + +/** + * XML_MAX_NAMELEN: + * + * Identifiers can be longer, but this will be more costly + * at runtime. + */ +#define XML_MAX_NAMELEN 100 + +/** + * INPUT_CHUNK: + * + * The parser tries to always have that amount of input ready. + * One of the point is providing context when reporting errors. + */ +#define INPUT_CHUNK 250 + +/************************************************************************ + * * + * UNICODE version of the macros. * + * * + ************************************************************************/ +/** + * IS_BYTE_CHAR: + * @c: an byte value (int) + * + * Macro to check the following production in the XML spec: + * + * [2] Char ::= #x9 | #xA | #xD | [#x20...] + * any byte character in the accepted range + */ +#define IS_BYTE_CHAR(c) xmlIsChar_ch(c) + +/** + * IS_CHAR: + * @c: an UNICODE value (int) + * + * Macro to check the following production in the XML spec: + * + * [2] Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] + * | [#x10000-#x10FFFF] + * any Unicode character, excluding the surrogate blocks, FFFE, and FFFF. + */ +#define IS_CHAR(c) xmlIsCharQ(c) + +/** + * IS_CHAR_CH: + * @c: an xmlChar (usually an unsigned char) + * + * Behaves like IS_CHAR on single-byte value + */ +#define IS_CHAR_CH(c) xmlIsChar_ch(c) + +/** + * IS_BLANK: + * @c: an UNICODE value (int) + * + * Macro to check the following production in the XML spec: + * + * [3] S ::= (#x20 | #x9 | #xD | #xA)+ + */ +#define IS_BLANK(c) xmlIsBlankQ(c) + +/** + * IS_BLANK_CH: + * @c: an xmlChar value (normally unsigned char) + * + * Behaviour same as IS_BLANK + */ +#define IS_BLANK_CH(c) xmlIsBlank_ch(c) + +/** + * IS_BASECHAR: + * @c: an UNICODE value (int) + * + * Macro to check the following production in the XML spec: + * + * [85] BaseChar ::= ... long list see REC ... + */ +#define IS_BASECHAR(c) xmlIsBaseCharQ(c) + +/** + * IS_DIGIT: + * @c: an UNICODE value (int) + * + * Macro to check the following production in the XML spec: + * + * [88] Digit ::= ... long list see REC ... + */ +#define IS_DIGIT(c) xmlIsDigitQ(c) + +/** + * IS_DIGIT_CH: + * @c: an xmlChar value (usually an unsigned char) + * + * Behaves like IS_DIGIT but with a single byte argument + */ +#define IS_DIGIT_CH(c) xmlIsDigit_ch(c) + +/** + * IS_COMBINING: + * @c: an UNICODE value (int) + * + * Macro to check the following production in the XML spec: + * + * [87] CombiningChar ::= ... long list see REC ... + */ +#define IS_COMBINING(c) xmlIsCombiningQ(c) + +/** + * IS_COMBINING_CH: + * @c: an xmlChar (usually an unsigned char) + * + * Always false (all combining chars > 0xff) + */ +#define IS_COMBINING_CH(c) 0 + +/** + * IS_EXTENDER: + * @c: an UNICODE value (int) + * + * Macro to check the following production in the XML spec: + * + * + * [89] Extender ::= #x00B7 | #x02D0 | #x02D1 | #x0387 | #x0640 | + * #x0E46 | #x0EC6 | #x3005 | [#x3031-#x3035] | + * [#x309D-#x309E] | [#x30FC-#x30FE] + */ +#define IS_EXTENDER(c) xmlIsExtenderQ(c) + +/** + * IS_EXTENDER_CH: + * @c: an xmlChar value (usually an unsigned char) + * + * Behaves like IS_EXTENDER but with a single-byte argument + */ +#define IS_EXTENDER_CH(c) xmlIsExtender_ch(c) + +/** + * IS_IDEOGRAPHIC: + * @c: an UNICODE value (int) + * + * Macro to check the following production in the XML spec: + * + * + * [86] Ideographic ::= [#x4E00-#x9FA5] | #x3007 | [#x3021-#x3029] + */ +#define IS_IDEOGRAPHIC(c) xmlIsIdeographicQ(c) + +/** + * IS_LETTER: + * @c: an UNICODE value (int) + * + * Macro to check the following production in the XML spec: + * + * + * [84] Letter ::= BaseChar | Ideographic + */ +#define IS_LETTER(c) (IS_BASECHAR(c) || IS_IDEOGRAPHIC(c)) + +/** + * IS_LETTER_CH: + * @c: an xmlChar value (normally unsigned char) + * + * Macro behaves like IS_LETTER, but only check base chars + * + */ +#define IS_LETTER_CH(c) xmlIsBaseChar_ch(c) + +/** + * IS_ASCII_LETTER: + * @c: an xmlChar value + * + * Macro to check [a-zA-Z] + * + */ +#define IS_ASCII_LETTER(c) (((0x41 <= (c)) && ((c) <= 0x5a)) || \ + ((0x61 <= (c)) && ((c) <= 0x7a))) + +/** + * IS_ASCII_DIGIT: + * @c: an xmlChar value + * + * Macro to check [0-9] + * + */ +#define IS_ASCII_DIGIT(c) ((0x30 <= (c)) && ((c) <= 0x39)) + +/** + * IS_PUBIDCHAR: + * @c: an UNICODE value (int) + * + * Macro to check the following production in the XML spec: + * + * + * [13] PubidChar ::= #x20 | #xD | #xA | [a-zA-Z0-9] | [-'()+,./:=?;!*#@$_%] + */ +#define IS_PUBIDCHAR(c) xmlIsPubidCharQ(c) + +/** + * IS_PUBIDCHAR_CH: + * @c: an xmlChar value (normally unsigned char) + * + * Same as IS_PUBIDCHAR but for single-byte value + */ +#define IS_PUBIDCHAR_CH(c) xmlIsPubidChar_ch(c) + +/** + * SKIP_EOL: + * @p: and UTF8 string pointer + * + * Skips the end of line chars. + */ +#define SKIP_EOL(p) \ + if (*(p) == 0x13) { p++ ; if (*(p) == 0x10) p++; } \ + if (*(p) == 0x10) { p++ ; if (*(p) == 0x13) p++; } + +/** + * MOVETO_ENDTAG: + * @p: and UTF8 string pointer + * + * Skips to the next '>' char. + */ +#define MOVETO_ENDTAG(p) \ + while ((*p) && (*(p) != '>')) (p)++ + +/** + * MOVETO_STARTTAG: + * @p: and UTF8 string pointer + * + * Skips to the next '<' char. + */ +#define MOVETO_STARTTAG(p) \ + while ((*p) && (*(p) != '<')) (p)++ + +/** + * Global variables used for predefined strings. + */ +XMLPUBVAR const xmlChar xmlStringText[]; +XMLPUBVAR const xmlChar xmlStringTextNoenc[]; +XMLPUBVAR const xmlChar xmlStringComment[]; + +/* + * Function to finish the work of the macros where needed. + */ +XMLPUBFUN int XMLCALL xmlIsLetter (int c); + +/** + * Parser context. + */ +XMLPUBFUN xmlParserCtxtPtr XMLCALL + xmlCreateFileParserCtxt (const char *filename); +XMLPUBFUN xmlParserCtxtPtr XMLCALL + xmlCreateURLParserCtxt (const char *filename, + int options); +XMLPUBFUN xmlParserCtxtPtr XMLCALL + xmlCreateMemoryParserCtxt(const char *buffer, + int size); +XMLPUBFUN xmlParserCtxtPtr XMLCALL + xmlCreateEntityParserCtxt(const xmlChar *URL, + const xmlChar *ID, + const xmlChar *base); +XMLPUBFUN int XMLCALL + xmlSwitchEncoding (xmlParserCtxtPtr ctxt, + xmlCharEncoding enc); +XMLPUBFUN int XMLCALL + xmlSwitchToEncoding (xmlParserCtxtPtr ctxt, + xmlCharEncodingHandlerPtr handler); +XMLPUBFUN int XMLCALL + xmlSwitchInputEncoding (xmlParserCtxtPtr ctxt, + xmlParserInputPtr input, + xmlCharEncodingHandlerPtr handler); + +#ifdef IN_LIBXML +/* internal error reporting */ +XMLPUBFUN void XMLCALL + __xmlErrEncoding (xmlParserCtxtPtr ctxt, + xmlParserErrors xmlerr, + const char *msg, + const xmlChar * str1, + const xmlChar * str2); +#endif + +/** + * Input Streams. + */ +XMLPUBFUN xmlParserInputPtr XMLCALL + xmlNewStringInputStream (xmlParserCtxtPtr ctxt, + const xmlChar *buffer); +XMLPUBFUN xmlParserInputPtr XMLCALL + xmlNewEntityInputStream (xmlParserCtxtPtr ctxt, + xmlEntityPtr entity); +XMLPUBFUN int XMLCALL + xmlPushInput (xmlParserCtxtPtr ctxt, + xmlParserInputPtr input); +XMLPUBFUN xmlChar XMLCALL + xmlPopInput (xmlParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + xmlFreeInputStream (xmlParserInputPtr input); +XMLPUBFUN xmlParserInputPtr XMLCALL + xmlNewInputFromFile (xmlParserCtxtPtr ctxt, + const char *filename); +XMLPUBFUN xmlParserInputPtr XMLCALL + xmlNewInputStream (xmlParserCtxtPtr ctxt); + +/** + * Namespaces. + */ +XMLPUBFUN xmlChar * XMLCALL + xmlSplitQName (xmlParserCtxtPtr ctxt, + const xmlChar *name, + xmlChar **prefix); + +/** + * Generic production rules. + */ +XMLPUBFUN const xmlChar * XMLCALL + xmlParseName (xmlParserCtxtPtr ctxt); +XMLPUBFUN xmlChar * XMLCALL + xmlParseNmtoken (xmlParserCtxtPtr ctxt); +XMLPUBFUN xmlChar * XMLCALL + xmlParseEntityValue (xmlParserCtxtPtr ctxt, + xmlChar **orig); +XMLPUBFUN xmlChar * XMLCALL + xmlParseAttValue (xmlParserCtxtPtr ctxt); +XMLPUBFUN xmlChar * XMLCALL + xmlParseSystemLiteral (xmlParserCtxtPtr ctxt); +XMLPUBFUN xmlChar * XMLCALL + xmlParsePubidLiteral (xmlParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + xmlParseCharData (xmlParserCtxtPtr ctxt, + int cdata); +XMLPUBFUN xmlChar * XMLCALL + xmlParseExternalID (xmlParserCtxtPtr ctxt, + xmlChar **publicID, + int strict); +XMLPUBFUN void XMLCALL + xmlParseComment (xmlParserCtxtPtr ctxt); +XMLPUBFUN const xmlChar * XMLCALL + xmlParsePITarget (xmlParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + xmlParsePI (xmlParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + xmlParseNotationDecl (xmlParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + xmlParseEntityDecl (xmlParserCtxtPtr ctxt); +XMLPUBFUN int XMLCALL + xmlParseDefaultDecl (xmlParserCtxtPtr ctxt, + xmlChar **value); +XMLPUBFUN xmlEnumerationPtr XMLCALL + xmlParseNotationType (xmlParserCtxtPtr ctxt); +XMLPUBFUN xmlEnumerationPtr XMLCALL + xmlParseEnumerationType (xmlParserCtxtPtr ctxt); +XMLPUBFUN int XMLCALL + xmlParseEnumeratedType (xmlParserCtxtPtr ctxt, + xmlEnumerationPtr *tree); +XMLPUBFUN int XMLCALL + xmlParseAttributeType (xmlParserCtxtPtr ctxt, + xmlEnumerationPtr *tree); +XMLPUBFUN void XMLCALL + xmlParseAttributeListDecl(xmlParserCtxtPtr ctxt); +XMLPUBFUN xmlElementContentPtr XMLCALL + xmlParseElementMixedContentDecl + (xmlParserCtxtPtr ctxt, + int inputchk); +XMLPUBFUN xmlElementContentPtr XMLCALL + xmlParseElementChildrenContentDecl + (xmlParserCtxtPtr ctxt, + int inputchk); +XMLPUBFUN int XMLCALL + xmlParseElementContentDecl(xmlParserCtxtPtr ctxt, + const xmlChar *name, + xmlElementContentPtr *result); +XMLPUBFUN int XMLCALL + xmlParseElementDecl (xmlParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + xmlParseMarkupDecl (xmlParserCtxtPtr ctxt); +XMLPUBFUN int XMLCALL + xmlParseCharRef (xmlParserCtxtPtr ctxt); +XMLPUBFUN xmlEntityPtr XMLCALL + xmlParseEntityRef (xmlParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + xmlParseReference (xmlParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + xmlParsePEReference (xmlParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + xmlParseDocTypeDecl (xmlParserCtxtPtr ctxt); +#ifdef LIBXML_SAX1_ENABLED +XMLPUBFUN const xmlChar * XMLCALL + xmlParseAttribute (xmlParserCtxtPtr ctxt, + xmlChar **value); +XMLPUBFUN const xmlChar * XMLCALL + xmlParseStartTag (xmlParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + xmlParseEndTag (xmlParserCtxtPtr ctxt); +#endif /* LIBXML_SAX1_ENABLED */ +XMLPUBFUN void XMLCALL + xmlParseCDSect (xmlParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + xmlParseContent (xmlParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + xmlParseElement (xmlParserCtxtPtr ctxt); +XMLPUBFUN xmlChar * XMLCALL + xmlParseVersionNum (xmlParserCtxtPtr ctxt); +XMLPUBFUN xmlChar * XMLCALL + xmlParseVersionInfo (xmlParserCtxtPtr ctxt); +XMLPUBFUN xmlChar * XMLCALL + xmlParseEncName (xmlParserCtxtPtr ctxt); +XMLPUBFUN const xmlChar * XMLCALL + xmlParseEncodingDecl (xmlParserCtxtPtr ctxt); +XMLPUBFUN int XMLCALL + xmlParseSDDecl (xmlParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + xmlParseXMLDecl (xmlParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + xmlParseTextDecl (xmlParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + xmlParseMisc (xmlParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + xmlParseExternalSubset (xmlParserCtxtPtr ctxt, + const xmlChar *ExternalID, + const xmlChar *SystemID); +/** + * XML_SUBSTITUTE_NONE: + * + * If no entities need to be substituted. + */ +#define XML_SUBSTITUTE_NONE 0 +/** + * XML_SUBSTITUTE_REF: + * + * Whether general entities need to be substituted. + */ +#define XML_SUBSTITUTE_REF 1 +/** + * XML_SUBSTITUTE_PEREF: + * + * Whether parameter entities need to be substituted. + */ +#define XML_SUBSTITUTE_PEREF 2 +/** + * XML_SUBSTITUTE_BOTH: + * + * Both general and parameter entities need to be substituted. + */ +#define XML_SUBSTITUTE_BOTH 3 + +XMLPUBFUN xmlChar * XMLCALL + xmlStringDecodeEntities (xmlParserCtxtPtr ctxt, + const xmlChar *str, + int what, + xmlChar end, + xmlChar end2, + xmlChar end3); +XMLPUBFUN xmlChar * XMLCALL + xmlStringLenDecodeEntities (xmlParserCtxtPtr ctxt, + const xmlChar *str, + int len, + int what, + xmlChar end, + xmlChar end2, + xmlChar end3); + +/* + * Generated by MACROS on top of parser.c c.f. PUSH_AND_POP. + */ +XMLPUBFUN int XMLCALL nodePush (xmlParserCtxtPtr ctxt, + xmlNodePtr value); +XMLPUBFUN xmlNodePtr XMLCALL nodePop (xmlParserCtxtPtr ctxt); +XMLPUBFUN int XMLCALL inputPush (xmlParserCtxtPtr ctxt, + xmlParserInputPtr value); +XMLPUBFUN xmlParserInputPtr XMLCALL inputPop (xmlParserCtxtPtr ctxt); +XMLPUBFUN const xmlChar * XMLCALL namePop (xmlParserCtxtPtr ctxt); +XMLPUBFUN int XMLCALL namePush (xmlParserCtxtPtr ctxt, + const xmlChar *value); + +/* + * other commodities shared between parser.c and parserInternals. + */ +XMLPUBFUN int XMLCALL xmlSkipBlankChars (xmlParserCtxtPtr ctxt); +XMLPUBFUN int XMLCALL xmlStringCurrentChar (xmlParserCtxtPtr ctxt, + const xmlChar *cur, + int *len); +XMLPUBFUN void XMLCALL xmlParserHandlePEReference(xmlParserCtxtPtr ctxt); +XMLPUBFUN int XMLCALL xmlCheckLanguageID (const xmlChar *lang); + +/* + * Really core function shared with HTML parser. + */ +XMLPUBFUN int XMLCALL xmlCurrentChar (xmlParserCtxtPtr ctxt, + int *len); +XMLPUBFUN int XMLCALL xmlCopyCharMultiByte (xmlChar *out, + int val); +XMLPUBFUN int XMLCALL xmlCopyChar (int len, + xmlChar *out, + int val); +XMLPUBFUN void XMLCALL xmlNextChar (xmlParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL xmlParserInputShrink (xmlParserInputPtr in); + +/* + * Specific function to keep track of entities references + * and used by the XSLT debugger. + */ +#ifdef LIBXML_LEGACY_ENABLED +/** + * xmlEntityReferenceFunc: + * @ent: the entity + * @firstNode: the fist node in the chunk + * @lastNode: the last nod in the chunk + * + * Callback function used when one needs to be able to track back the + * provenance of a chunk of nodes inherited from an entity replacement. + */ +typedef void (*xmlEntityReferenceFunc) (xmlEntityPtr ent, + xmlNodePtr firstNode, + xmlNodePtr lastNode); + +XMLPUBFUN void XMLCALL xmlSetEntityReferenceFunc (xmlEntityReferenceFunc func); + +XMLPUBFUN xmlChar * XMLCALL + xmlParseQuotedString (xmlParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + xmlParseNamespace (xmlParserCtxtPtr ctxt); +XMLPUBFUN xmlChar * XMLCALL + xmlNamespaceParseNSDef (xmlParserCtxtPtr ctxt); +XMLPUBFUN xmlChar * XMLCALL + xmlScanName (xmlParserCtxtPtr ctxt); +XMLPUBFUN xmlChar * XMLCALL + xmlNamespaceParseNCName (xmlParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL xmlParserHandleReference(xmlParserCtxtPtr ctxt); +XMLPUBFUN xmlChar * XMLCALL + xmlNamespaceParseQName (xmlParserCtxtPtr ctxt, + xmlChar **prefix); +/** + * Entities + */ +XMLPUBFUN xmlChar * XMLCALL + xmlDecodeEntities (xmlParserCtxtPtr ctxt, + int len, + int what, + xmlChar end, + xmlChar end2, + xmlChar end3); +XMLPUBFUN void XMLCALL + xmlHandleEntity (xmlParserCtxtPtr ctxt, + xmlEntityPtr entity); + +#endif /* LIBXML_LEGACY_ENABLED */ + +#ifdef IN_LIBXML +/* + * internal only + */ +XMLPUBFUN void XMLCALL + xmlErrMemory (xmlParserCtxtPtr ctxt, + const char *extra); +#endif + +#ifdef __cplusplus +} +#endif +#endif /* __XML_PARSER_INTERNALS_H__ */ diff --git a/android/native/libxml2/libxml/pattern.h b/android/native/libxml2/libxml/pattern.h new file mode 100644 index 0000000000..97d2cd2bc0 --- /dev/null +++ b/android/native/libxml2/libxml/pattern.h @@ -0,0 +1,100 @@ +/* + * Summary: pattern expression handling + * Description: allows to compile and test pattern expressions for nodes + * either in a tree or based on a parser state. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_PATTERN_H__ +#define __XML_PATTERN_H__ + +#include +#include +#include + +#ifdef LIBXML_PATTERN_ENABLED + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * xmlPattern: + * + * A compiled (XPath based) pattern to select nodes + */ +typedef struct _xmlPattern xmlPattern; +typedef xmlPattern *xmlPatternPtr; + +/** + * xmlPatternFlags: + * + * This is the set of options affecting the behaviour of pattern + * matching with this module + * + */ +typedef enum { + XML_PATTERN_DEFAULT = 0, /* simple pattern match */ + XML_PATTERN_XPATH = 1<<0, /* standard XPath pattern */ + XML_PATTERN_XSSEL = 1<<1, /* XPath subset for schema selector */ + XML_PATTERN_XSFIELD = 1<<2 /* XPath subset for schema field */ +} xmlPatternFlags; + +XMLPUBFUN void XMLCALL + xmlFreePattern (xmlPatternPtr comp); + +XMLPUBFUN void XMLCALL + xmlFreePatternList (xmlPatternPtr comp); + +XMLPUBFUN xmlPatternPtr XMLCALL + xmlPatterncompile (const xmlChar *pattern, + xmlDict *dict, + int flags, + const xmlChar **namespaces); +XMLPUBFUN int XMLCALL + xmlPatternMatch (xmlPatternPtr comp, + xmlNodePtr node); + +/* streaming interfaces */ +typedef struct _xmlStreamCtxt xmlStreamCtxt; +typedef xmlStreamCtxt *xmlStreamCtxtPtr; + +XMLPUBFUN int XMLCALL + xmlPatternStreamable (xmlPatternPtr comp); +XMLPUBFUN int XMLCALL + xmlPatternMaxDepth (xmlPatternPtr comp); +XMLPUBFUN int XMLCALL + xmlPatternMinDepth (xmlPatternPtr comp); +XMLPUBFUN int XMLCALL + xmlPatternFromRoot (xmlPatternPtr comp); +XMLPUBFUN xmlStreamCtxtPtr XMLCALL + xmlPatternGetStreamCtxt (xmlPatternPtr comp); +XMLPUBFUN void XMLCALL + xmlFreeStreamCtxt (xmlStreamCtxtPtr stream); +XMLPUBFUN int XMLCALL + xmlStreamPushNode (xmlStreamCtxtPtr stream, + const xmlChar *name, + const xmlChar *ns, + int nodeType); +XMLPUBFUN int XMLCALL + xmlStreamPush (xmlStreamCtxtPtr stream, + const xmlChar *name, + const xmlChar *ns); +XMLPUBFUN int XMLCALL + xmlStreamPushAttr (xmlStreamCtxtPtr stream, + const xmlChar *name, + const xmlChar *ns); +XMLPUBFUN int XMLCALL + xmlStreamPop (xmlStreamCtxtPtr stream); +XMLPUBFUN int XMLCALL + xmlStreamWantsAnyNode (xmlStreamCtxtPtr stream); +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_PATTERN_ENABLED */ + +#endif /* __XML_PATTERN_H__ */ diff --git a/android/native/libxml2/libxml/relaxng.h b/android/native/libxml2/libxml/relaxng.h new file mode 100644 index 0000000000..bdb0a7d376 --- /dev/null +++ b/android/native/libxml2/libxml/relaxng.h @@ -0,0 +1,213 @@ +/* + * Summary: implementation of the Relax-NG validation + * Description: implementation of the Relax-NG validation + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_RELAX_NG__ +#define __XML_RELAX_NG__ + +#include +#include +#include + +#ifdef LIBXML_SCHEMAS_ENABLED + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _xmlRelaxNG xmlRelaxNG; +typedef xmlRelaxNG *xmlRelaxNGPtr; + + +/** + * xmlRelaxNGValidityErrorFunc: + * @ctx: the validation context + * @msg: the message + * @...: extra arguments + * + * Signature of an error callback from a Relax-NG validation + */ +typedef void (XMLCDECL *xmlRelaxNGValidityErrorFunc) (void *ctx, const char *msg, ...) LIBXML_ATTR_FORMAT(2,3); + +/** + * xmlRelaxNGValidityWarningFunc: + * @ctx: the validation context + * @msg: the message + * @...: extra arguments + * + * Signature of a warning callback from a Relax-NG validation + */ +typedef void (XMLCDECL *xmlRelaxNGValidityWarningFunc) (void *ctx, const char *msg, ...) LIBXML_ATTR_FORMAT(2,3); + +/** + * A schemas validation context + */ +typedef struct _xmlRelaxNGParserCtxt xmlRelaxNGParserCtxt; +typedef xmlRelaxNGParserCtxt *xmlRelaxNGParserCtxtPtr; + +typedef struct _xmlRelaxNGValidCtxt xmlRelaxNGValidCtxt; +typedef xmlRelaxNGValidCtxt *xmlRelaxNGValidCtxtPtr; + +/* + * xmlRelaxNGValidErr: + * + * List of possible Relax NG validation errors + */ +typedef enum { + XML_RELAXNG_OK = 0, + XML_RELAXNG_ERR_MEMORY, + XML_RELAXNG_ERR_TYPE, + XML_RELAXNG_ERR_TYPEVAL, + XML_RELAXNG_ERR_DUPID, + XML_RELAXNG_ERR_TYPECMP, + XML_RELAXNG_ERR_NOSTATE, + XML_RELAXNG_ERR_NODEFINE, + XML_RELAXNG_ERR_LISTEXTRA, + XML_RELAXNG_ERR_LISTEMPTY, + XML_RELAXNG_ERR_INTERNODATA, + XML_RELAXNG_ERR_INTERSEQ, + XML_RELAXNG_ERR_INTEREXTRA, + XML_RELAXNG_ERR_ELEMNAME, + XML_RELAXNG_ERR_ATTRNAME, + XML_RELAXNG_ERR_ELEMNONS, + XML_RELAXNG_ERR_ATTRNONS, + XML_RELAXNG_ERR_ELEMWRONGNS, + XML_RELAXNG_ERR_ATTRWRONGNS, + XML_RELAXNG_ERR_ELEMEXTRANS, + XML_RELAXNG_ERR_ATTREXTRANS, + XML_RELAXNG_ERR_ELEMNOTEMPTY, + XML_RELAXNG_ERR_NOELEM, + XML_RELAXNG_ERR_NOTELEM, + XML_RELAXNG_ERR_ATTRVALID, + XML_RELAXNG_ERR_CONTENTVALID, + XML_RELAXNG_ERR_EXTRACONTENT, + XML_RELAXNG_ERR_INVALIDATTR, + XML_RELAXNG_ERR_DATAELEM, + XML_RELAXNG_ERR_VALELEM, + XML_RELAXNG_ERR_LISTELEM, + XML_RELAXNG_ERR_DATATYPE, + XML_RELAXNG_ERR_VALUE, + XML_RELAXNG_ERR_LIST, + XML_RELAXNG_ERR_NOGRAMMAR, + XML_RELAXNG_ERR_EXTRADATA, + XML_RELAXNG_ERR_LACKDATA, + XML_RELAXNG_ERR_INTERNAL, + XML_RELAXNG_ERR_ELEMWRONG, + XML_RELAXNG_ERR_TEXTWRONG +} xmlRelaxNGValidErr; + +/* + * xmlRelaxNGParserFlags: + * + * List of possible Relax NG Parser flags + */ +typedef enum { + XML_RELAXNGP_NONE = 0, + XML_RELAXNGP_FREE_DOC = 1, + XML_RELAXNGP_CRNG = 2 +} xmlRelaxNGParserFlag; + +XMLPUBFUN int XMLCALL + xmlRelaxNGInitTypes (void); +XMLPUBFUN void XMLCALL + xmlRelaxNGCleanupTypes (void); + +/* + * Interfaces for parsing. + */ +XMLPUBFUN xmlRelaxNGParserCtxtPtr XMLCALL + xmlRelaxNGNewParserCtxt (const char *URL); +XMLPUBFUN xmlRelaxNGParserCtxtPtr XMLCALL + xmlRelaxNGNewMemParserCtxt (const char *buffer, + int size); +XMLPUBFUN xmlRelaxNGParserCtxtPtr XMLCALL + xmlRelaxNGNewDocParserCtxt (xmlDocPtr doc); + +XMLPUBFUN int XMLCALL + xmlRelaxParserSetFlag (xmlRelaxNGParserCtxtPtr ctxt, + int flag); + +XMLPUBFUN void XMLCALL + xmlRelaxNGFreeParserCtxt (xmlRelaxNGParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt, + xmlRelaxNGValidityErrorFunc err, + xmlRelaxNGValidityWarningFunc warn, + void *ctx); +XMLPUBFUN int XMLCALL + xmlRelaxNGGetParserErrors(xmlRelaxNGParserCtxtPtr ctxt, + xmlRelaxNGValidityErrorFunc *err, + xmlRelaxNGValidityWarningFunc *warn, + void **ctx); +XMLPUBFUN void XMLCALL + xmlRelaxNGSetParserStructuredErrors( + xmlRelaxNGParserCtxtPtr ctxt, + xmlStructuredErrorFunc serror, + void *ctx); +XMLPUBFUN xmlRelaxNGPtr XMLCALL + xmlRelaxNGParse (xmlRelaxNGParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + xmlRelaxNGFree (xmlRelaxNGPtr schema); +#ifdef LIBXML_OUTPUT_ENABLED +XMLPUBFUN void XMLCALL + xmlRelaxNGDump (FILE *output, + xmlRelaxNGPtr schema); +XMLPUBFUN void XMLCALL + xmlRelaxNGDumpTree (FILE * output, + xmlRelaxNGPtr schema); +#endif /* LIBXML_OUTPUT_ENABLED */ +/* + * Interfaces for validating + */ +XMLPUBFUN void XMLCALL + xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt, + xmlRelaxNGValidityErrorFunc err, + xmlRelaxNGValidityWarningFunc warn, + void *ctx); +XMLPUBFUN int XMLCALL + xmlRelaxNGGetValidErrors(xmlRelaxNGValidCtxtPtr ctxt, + xmlRelaxNGValidityErrorFunc *err, + xmlRelaxNGValidityWarningFunc *warn, + void **ctx); +XMLPUBFUN void XMLCALL + xmlRelaxNGSetValidStructuredErrors(xmlRelaxNGValidCtxtPtr ctxt, + xmlStructuredErrorFunc serror, void *ctx); +XMLPUBFUN xmlRelaxNGValidCtxtPtr XMLCALL + xmlRelaxNGNewValidCtxt (xmlRelaxNGPtr schema); +XMLPUBFUN void XMLCALL + xmlRelaxNGFreeValidCtxt (xmlRelaxNGValidCtxtPtr ctxt); +XMLPUBFUN int XMLCALL + xmlRelaxNGValidateDoc (xmlRelaxNGValidCtxtPtr ctxt, + xmlDocPtr doc); +/* + * Interfaces for progressive validation when possible + */ +XMLPUBFUN int XMLCALL + xmlRelaxNGValidatePushElement (xmlRelaxNGValidCtxtPtr ctxt, + xmlDocPtr doc, + xmlNodePtr elem); +XMLPUBFUN int XMLCALL + xmlRelaxNGValidatePushCData (xmlRelaxNGValidCtxtPtr ctxt, + const xmlChar *data, + int len); +XMLPUBFUN int XMLCALL + xmlRelaxNGValidatePopElement (xmlRelaxNGValidCtxtPtr ctxt, + xmlDocPtr doc, + xmlNodePtr elem); +XMLPUBFUN int XMLCALL + xmlRelaxNGValidateFullElement (xmlRelaxNGValidCtxtPtr ctxt, + xmlDocPtr doc, + xmlNodePtr elem); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_SCHEMAS_ENABLED */ + +#endif /* __XML_RELAX_NG__ */ diff --git a/android/native/libxml2/libxml/schemasInternals.h b/android/native/libxml2/libxml/schemasInternals.h new file mode 100644 index 0000000000..b68a6e1285 --- /dev/null +++ b/android/native/libxml2/libxml/schemasInternals.h @@ -0,0 +1,958 @@ +/* + * Summary: internal interfaces for XML Schemas + * Description: internal interfaces for the XML Schemas handling + * and schema validity checking + * The Schemas development is a Work In Progress. + * Some of those interfaces are not garanteed to be API or ABI stable ! + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + + +#ifndef __XML_SCHEMA_INTERNALS_H__ +#define __XML_SCHEMA_INTERNALS_H__ + +#include + +#ifdef LIBXML_SCHEMAS_ENABLED + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + XML_SCHEMAS_UNKNOWN = 0, + XML_SCHEMAS_STRING, + XML_SCHEMAS_NORMSTRING, + XML_SCHEMAS_DECIMAL, + XML_SCHEMAS_TIME, + XML_SCHEMAS_GDAY, + XML_SCHEMAS_GMONTH, + XML_SCHEMAS_GMONTHDAY, + XML_SCHEMAS_GYEAR, + XML_SCHEMAS_GYEARMONTH, + XML_SCHEMAS_DATE, + XML_SCHEMAS_DATETIME, + XML_SCHEMAS_DURATION, + XML_SCHEMAS_FLOAT, + XML_SCHEMAS_DOUBLE, + XML_SCHEMAS_BOOLEAN, + XML_SCHEMAS_TOKEN, + XML_SCHEMAS_LANGUAGE, + XML_SCHEMAS_NMTOKEN, + XML_SCHEMAS_NMTOKENS, + XML_SCHEMAS_NAME, + XML_SCHEMAS_QNAME, + XML_SCHEMAS_NCNAME, + XML_SCHEMAS_ID, + XML_SCHEMAS_IDREF, + XML_SCHEMAS_IDREFS, + XML_SCHEMAS_ENTITY, + XML_SCHEMAS_ENTITIES, + XML_SCHEMAS_NOTATION, + XML_SCHEMAS_ANYURI, + XML_SCHEMAS_INTEGER, + XML_SCHEMAS_NPINTEGER, + XML_SCHEMAS_NINTEGER, + XML_SCHEMAS_NNINTEGER, + XML_SCHEMAS_PINTEGER, + XML_SCHEMAS_INT, + XML_SCHEMAS_UINT, + XML_SCHEMAS_LONG, + XML_SCHEMAS_ULONG, + XML_SCHEMAS_SHORT, + XML_SCHEMAS_USHORT, + XML_SCHEMAS_BYTE, + XML_SCHEMAS_UBYTE, + XML_SCHEMAS_HEXBINARY, + XML_SCHEMAS_BASE64BINARY, + XML_SCHEMAS_ANYTYPE, + XML_SCHEMAS_ANYSIMPLETYPE +} xmlSchemaValType; + +/* + * XML Schemas defines multiple type of types. + */ +typedef enum { + XML_SCHEMA_TYPE_BASIC = 1, /* A built-in datatype */ + XML_SCHEMA_TYPE_ANY, + XML_SCHEMA_TYPE_FACET, + XML_SCHEMA_TYPE_SIMPLE, + XML_SCHEMA_TYPE_COMPLEX, + XML_SCHEMA_TYPE_SEQUENCE = 6, + XML_SCHEMA_TYPE_CHOICE, + XML_SCHEMA_TYPE_ALL, + XML_SCHEMA_TYPE_SIMPLE_CONTENT, + XML_SCHEMA_TYPE_COMPLEX_CONTENT, + XML_SCHEMA_TYPE_UR, + XML_SCHEMA_TYPE_RESTRICTION, + XML_SCHEMA_TYPE_EXTENSION, + XML_SCHEMA_TYPE_ELEMENT, + XML_SCHEMA_TYPE_ATTRIBUTE, + XML_SCHEMA_TYPE_ATTRIBUTEGROUP, + XML_SCHEMA_TYPE_GROUP, + XML_SCHEMA_TYPE_NOTATION, + XML_SCHEMA_TYPE_LIST, + XML_SCHEMA_TYPE_UNION, + XML_SCHEMA_TYPE_ANY_ATTRIBUTE, + XML_SCHEMA_TYPE_IDC_UNIQUE, + XML_SCHEMA_TYPE_IDC_KEY, + XML_SCHEMA_TYPE_IDC_KEYREF, + XML_SCHEMA_TYPE_PARTICLE = 25, + XML_SCHEMA_TYPE_ATTRIBUTE_USE, + XML_SCHEMA_FACET_MININCLUSIVE = 1000, + XML_SCHEMA_FACET_MINEXCLUSIVE, + XML_SCHEMA_FACET_MAXINCLUSIVE, + XML_SCHEMA_FACET_MAXEXCLUSIVE, + XML_SCHEMA_FACET_TOTALDIGITS, + XML_SCHEMA_FACET_FRACTIONDIGITS, + XML_SCHEMA_FACET_PATTERN, + XML_SCHEMA_FACET_ENUMERATION, + XML_SCHEMA_FACET_WHITESPACE, + XML_SCHEMA_FACET_LENGTH, + XML_SCHEMA_FACET_MAXLENGTH, + XML_SCHEMA_FACET_MINLENGTH, + XML_SCHEMA_EXTRA_QNAMEREF = 2000, + XML_SCHEMA_EXTRA_ATTR_USE_PROHIB +} xmlSchemaTypeType; + +typedef enum { + XML_SCHEMA_CONTENT_UNKNOWN = 0, + XML_SCHEMA_CONTENT_EMPTY = 1, + XML_SCHEMA_CONTENT_ELEMENTS, + XML_SCHEMA_CONTENT_MIXED, + XML_SCHEMA_CONTENT_SIMPLE, + XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS, /* Obsolete */ + XML_SCHEMA_CONTENT_BASIC, + XML_SCHEMA_CONTENT_ANY +} xmlSchemaContentType; + +typedef struct _xmlSchemaVal xmlSchemaVal; +typedef xmlSchemaVal *xmlSchemaValPtr; + +typedef struct _xmlSchemaType xmlSchemaType; +typedef xmlSchemaType *xmlSchemaTypePtr; + +typedef struct _xmlSchemaFacet xmlSchemaFacet; +typedef xmlSchemaFacet *xmlSchemaFacetPtr; + +/** + * Annotation + */ +typedef struct _xmlSchemaAnnot xmlSchemaAnnot; +typedef xmlSchemaAnnot *xmlSchemaAnnotPtr; +struct _xmlSchemaAnnot { + struct _xmlSchemaAnnot *next; + xmlNodePtr content; /* the annotation */ +}; + +/** + * XML_SCHEMAS_ANYATTR_SKIP: + * + * Skip unknown attribute from validation + * Obsolete, not used anymore. + */ +#define XML_SCHEMAS_ANYATTR_SKIP 1 +/** + * XML_SCHEMAS_ANYATTR_LAX: + * + * Ignore validation non definition on attributes + * Obsolete, not used anymore. + */ +#define XML_SCHEMAS_ANYATTR_LAX 2 +/** + * XML_SCHEMAS_ANYATTR_STRICT: + * + * Apply strict validation rules on attributes + * Obsolete, not used anymore. + */ +#define XML_SCHEMAS_ANYATTR_STRICT 3 +/** + * XML_SCHEMAS_ANY_SKIP: + * + * Skip unknown attribute from validation + */ +#define XML_SCHEMAS_ANY_SKIP 1 +/** + * XML_SCHEMAS_ANY_LAX: + * + * Used by wildcards. + * Validate if type found, don't worry if not found + */ +#define XML_SCHEMAS_ANY_LAX 2 +/** + * XML_SCHEMAS_ANY_STRICT: + * + * Used by wildcards. + * Apply strict validation rules + */ +#define XML_SCHEMAS_ANY_STRICT 3 +/** + * XML_SCHEMAS_ATTR_USE_PROHIBITED: + * + * Used by wildcards. + * The attribute is prohibited. + */ +#define XML_SCHEMAS_ATTR_USE_PROHIBITED 0 +/** + * XML_SCHEMAS_ATTR_USE_REQUIRED: + * + * The attribute is required. + */ +#define XML_SCHEMAS_ATTR_USE_REQUIRED 1 +/** + * XML_SCHEMAS_ATTR_USE_OPTIONAL: + * + * The attribute is optional. + */ +#define XML_SCHEMAS_ATTR_USE_OPTIONAL 2 +/** + * XML_SCHEMAS_ATTR_GLOBAL: + * + * allow elements in no namespace + */ +#define XML_SCHEMAS_ATTR_GLOBAL 1 << 0 +/** + * XML_SCHEMAS_ATTR_NSDEFAULT: + * + * allow elements in no namespace + */ +#define XML_SCHEMAS_ATTR_NSDEFAULT 1 << 7 +/** + * XML_SCHEMAS_ATTR_INTERNAL_RESOLVED: + * + * this is set when the "type" and "ref" references + * have been resolved. + */ +#define XML_SCHEMAS_ATTR_INTERNAL_RESOLVED 1 << 8 +/** + * XML_SCHEMAS_ATTR_FIXED: + * + * the attribute has a fixed value + */ +#define XML_SCHEMAS_ATTR_FIXED 1 << 9 + +/** + * xmlSchemaAttribute: + * An attribute definition. + */ + +typedef struct _xmlSchemaAttribute xmlSchemaAttribute; +typedef xmlSchemaAttribute *xmlSchemaAttributePtr; +struct _xmlSchemaAttribute { + xmlSchemaTypeType type; + struct _xmlSchemaAttribute *next; /* the next attribute (not used?) */ + const xmlChar *name; /* the name of the declaration */ + const xmlChar *id; /* Deprecated; not used */ + const xmlChar *ref; /* Deprecated; not used */ + const xmlChar *refNs; /* Deprecated; not used */ + const xmlChar *typeName; /* the local name of the type definition */ + const xmlChar *typeNs; /* the ns URI of the type definition */ + xmlSchemaAnnotPtr annot; + + xmlSchemaTypePtr base; /* Deprecated; not used */ + int occurs; /* Deprecated; not used */ + const xmlChar *defValue; /* The initial value of the value constraint */ + xmlSchemaTypePtr subtypes; /* the type definition */ + xmlNodePtr node; + const xmlChar *targetNamespace; + int flags; + const xmlChar *refPrefix; /* Deprecated; not used */ + xmlSchemaValPtr defVal; /* The compiled value constraint */ + xmlSchemaAttributePtr refDecl; /* Deprecated; not used */ +}; + +/** + * xmlSchemaAttributeLink: + * Used to build a list of attribute uses on complexType definitions. + * WARNING: Deprecated; not used. + */ +typedef struct _xmlSchemaAttributeLink xmlSchemaAttributeLink; +typedef xmlSchemaAttributeLink *xmlSchemaAttributeLinkPtr; +struct _xmlSchemaAttributeLink { + struct _xmlSchemaAttributeLink *next;/* the next attribute link ... */ + struct _xmlSchemaAttribute *attr;/* the linked attribute */ +}; + +/** + * XML_SCHEMAS_WILDCARD_COMPLETE: + * + * If the wildcard is complete. + */ +#define XML_SCHEMAS_WILDCARD_COMPLETE 1 << 0 + +/** + * xmlSchemaCharValueLink: + * Used to build a list of namespaces on wildcards. + */ +typedef struct _xmlSchemaWildcardNs xmlSchemaWildcardNs; +typedef xmlSchemaWildcardNs *xmlSchemaWildcardNsPtr; +struct _xmlSchemaWildcardNs { + struct _xmlSchemaWildcardNs *next;/* the next constraint link ... */ + const xmlChar *value;/* the value */ +}; + +/** + * xmlSchemaWildcard. + * A wildcard. + */ +typedef struct _xmlSchemaWildcard xmlSchemaWildcard; +typedef xmlSchemaWildcard *xmlSchemaWildcardPtr; +struct _xmlSchemaWildcard { + xmlSchemaTypeType type; /* The kind of type */ + const xmlChar *id; /* Deprecated; not used */ + xmlSchemaAnnotPtr annot; + xmlNodePtr node; + int minOccurs; /* Deprecated; not used */ + int maxOccurs; /* Deprecated; not used */ + int processContents; + int any; /* Indicates if the ns constraint is of ##any */ + xmlSchemaWildcardNsPtr nsSet; /* The list of allowed namespaces */ + xmlSchemaWildcardNsPtr negNsSet; /* The negated namespace */ + int flags; +}; + +/** + * XML_SCHEMAS_ATTRGROUP_WILDCARD_BUILDED: + * + * The attribute wildcard has been already builded. + */ +#define XML_SCHEMAS_ATTRGROUP_WILDCARD_BUILDED 1 << 0 +/** + * XML_SCHEMAS_ATTRGROUP_GLOBAL: + * + * The attribute wildcard has been already builded. + */ +#define XML_SCHEMAS_ATTRGROUP_GLOBAL 1 << 1 +/** + * XML_SCHEMAS_ATTRGROUP_MARKED: + * + * Marks the attr group as marked; used for circular checks. + */ +#define XML_SCHEMAS_ATTRGROUP_MARKED 1 << 2 + +/** + * XML_SCHEMAS_ATTRGROUP_REDEFINED: + * + * The attr group was redefined. + */ +#define XML_SCHEMAS_ATTRGROUP_REDEFINED 1 << 3 +/** + * XML_SCHEMAS_ATTRGROUP_HAS_REFS: + * + * Whether this attr. group contains attr. group references. + */ +#define XML_SCHEMAS_ATTRGROUP_HAS_REFS 1 << 4 + +/** + * An attribute group definition. + * + * xmlSchemaAttribute and xmlSchemaAttributeGroup start of structures + * must be kept similar + */ +typedef struct _xmlSchemaAttributeGroup xmlSchemaAttributeGroup; +typedef xmlSchemaAttributeGroup *xmlSchemaAttributeGroupPtr; +struct _xmlSchemaAttributeGroup { + xmlSchemaTypeType type; /* The kind of type */ + struct _xmlSchemaAttribute *next;/* the next attribute if in a group ... */ + const xmlChar *name; + const xmlChar *id; + const xmlChar *ref; /* Deprecated; not used */ + const xmlChar *refNs; /* Deprecated; not used */ + xmlSchemaAnnotPtr annot; + + xmlSchemaAttributePtr attributes; /* Deprecated; not used */ + xmlNodePtr node; + int flags; + xmlSchemaWildcardPtr attributeWildcard; + const xmlChar *refPrefix; /* Deprecated; not used */ + xmlSchemaAttributeGroupPtr refItem; /* Deprecated; not used */ + const xmlChar *targetNamespace; + void *attrUses; +}; + +/** + * xmlSchemaTypeLink: + * Used to build a list of types (e.g. member types of + * simpleType with variety "union"). + */ +typedef struct _xmlSchemaTypeLink xmlSchemaTypeLink; +typedef xmlSchemaTypeLink *xmlSchemaTypeLinkPtr; +struct _xmlSchemaTypeLink { + struct _xmlSchemaTypeLink *next;/* the next type link ... */ + xmlSchemaTypePtr type;/* the linked type */ +}; + +/** + * xmlSchemaFacetLink: + * Used to build a list of facets. + */ +typedef struct _xmlSchemaFacetLink xmlSchemaFacetLink; +typedef xmlSchemaFacetLink *xmlSchemaFacetLinkPtr; +struct _xmlSchemaFacetLink { + struct _xmlSchemaFacetLink *next;/* the next facet link ... */ + xmlSchemaFacetPtr facet;/* the linked facet */ +}; + +/** + * XML_SCHEMAS_TYPE_MIXED: + * + * the element content type is mixed + */ +#define XML_SCHEMAS_TYPE_MIXED 1 << 0 +/** + * XML_SCHEMAS_TYPE_DERIVATION_METHOD_EXTENSION: + * + * the simple or complex type has a derivation method of "extension". + */ +#define XML_SCHEMAS_TYPE_DERIVATION_METHOD_EXTENSION 1 << 1 +/** + * XML_SCHEMAS_TYPE_DERIVATION_METHOD_RESTRICTION: + * + * the simple or complex type has a derivation method of "restriction". + */ +#define XML_SCHEMAS_TYPE_DERIVATION_METHOD_RESTRICTION 1 << 2 +/** + * XML_SCHEMAS_TYPE_GLOBAL: + * + * the type is global + */ +#define XML_SCHEMAS_TYPE_GLOBAL 1 << 3 +/** + * XML_SCHEMAS_TYPE_OWNED_ATTR_WILDCARD: + * + * the complexType owns an attribute wildcard, i.e. + * it can be freed by the complexType + */ +#define XML_SCHEMAS_TYPE_OWNED_ATTR_WILDCARD 1 << 4 /* Obsolete. */ +/** + * XML_SCHEMAS_TYPE_VARIETY_ABSENT: + * + * the simpleType has a variety of "absent". + * TODO: Actually not necessary :-/, since if + * none of the variety flags occur then it's + * automatically absent. + */ +#define XML_SCHEMAS_TYPE_VARIETY_ABSENT 1 << 5 +/** + * XML_SCHEMAS_TYPE_VARIETY_LIST: + * + * the simpleType has a variety of "list". + */ +#define XML_SCHEMAS_TYPE_VARIETY_LIST 1 << 6 +/** + * XML_SCHEMAS_TYPE_VARIETY_UNION: + * + * the simpleType has a variety of "union". + */ +#define XML_SCHEMAS_TYPE_VARIETY_UNION 1 << 7 +/** + * XML_SCHEMAS_TYPE_VARIETY_ATOMIC: + * + * the simpleType has a variety of "union". + */ +#define XML_SCHEMAS_TYPE_VARIETY_ATOMIC 1 << 8 +/** + * XML_SCHEMAS_TYPE_FINAL_EXTENSION: + * + * the complexType has a final of "extension". + */ +#define XML_SCHEMAS_TYPE_FINAL_EXTENSION 1 << 9 +/** + * XML_SCHEMAS_TYPE_FINAL_RESTRICTION: + * + * the simpleType/complexType has a final of "restriction". + */ +#define XML_SCHEMAS_TYPE_FINAL_RESTRICTION 1 << 10 +/** + * XML_SCHEMAS_TYPE_FINAL_LIST: + * + * the simpleType has a final of "list". + */ +#define XML_SCHEMAS_TYPE_FINAL_LIST 1 << 11 +/** + * XML_SCHEMAS_TYPE_FINAL_UNION: + * + * the simpleType has a final of "union". + */ +#define XML_SCHEMAS_TYPE_FINAL_UNION 1 << 12 +/** + * XML_SCHEMAS_TYPE_FINAL_DEFAULT: + * + * the simpleType has a final of "default". + */ +#define XML_SCHEMAS_TYPE_FINAL_DEFAULT 1 << 13 +/** + * XML_SCHEMAS_TYPE_BUILTIN_PRIMITIVE: + * + * Marks the item as a builtin primitive. + */ +#define XML_SCHEMAS_TYPE_BUILTIN_PRIMITIVE 1 << 14 +/** + * XML_SCHEMAS_TYPE_MARKED: + * + * Marks the item as marked; used for circular checks. + */ +#define XML_SCHEMAS_TYPE_MARKED 1 << 16 +/** + * XML_SCHEMAS_TYPE_BLOCK_DEFAULT: + * + * the complexType did not specify 'block' so use the default of the + * item. + */ +#define XML_SCHEMAS_TYPE_BLOCK_DEFAULT 1 << 17 +/** + * XML_SCHEMAS_TYPE_BLOCK_EXTENSION: + * + * the complexType has a 'block' of "extension". + */ +#define XML_SCHEMAS_TYPE_BLOCK_EXTENSION 1 << 18 +/** + * XML_SCHEMAS_TYPE_BLOCK_RESTRICTION: + * + * the complexType has a 'block' of "restriction". + */ +#define XML_SCHEMAS_TYPE_BLOCK_RESTRICTION 1 << 19 +/** + * XML_SCHEMAS_TYPE_ABSTRACT: + * + * the simple/complexType is abstract. + */ +#define XML_SCHEMAS_TYPE_ABSTRACT 1 << 20 +/** + * XML_SCHEMAS_TYPE_FACETSNEEDVALUE: + * + * indicates if the facets need a computed value + */ +#define XML_SCHEMAS_TYPE_FACETSNEEDVALUE 1 << 21 +/** + * XML_SCHEMAS_TYPE_INTERNAL_RESOLVED: + * + * indicates that the type was typefixed + */ +#define XML_SCHEMAS_TYPE_INTERNAL_RESOLVED 1 << 22 +/** + * XML_SCHEMAS_TYPE_INTERNAL_INVALID: + * + * indicates that the type is invalid + */ +#define XML_SCHEMAS_TYPE_INTERNAL_INVALID 1 << 23 +/** + * XML_SCHEMAS_TYPE_WHITESPACE_PRESERVE: + * + * a whitespace-facet value of "preserve" + */ +#define XML_SCHEMAS_TYPE_WHITESPACE_PRESERVE 1 << 24 +/** + * XML_SCHEMAS_TYPE_WHITESPACE_REPLACE: + * + * a whitespace-facet value of "replace" + */ +#define XML_SCHEMAS_TYPE_WHITESPACE_REPLACE 1 << 25 +/** + * XML_SCHEMAS_TYPE_WHITESPACE_COLLAPSE: + * + * a whitespace-facet value of "collapse" + */ +#define XML_SCHEMAS_TYPE_WHITESPACE_COLLAPSE 1 << 26 +/** + * XML_SCHEMAS_TYPE_HAS_FACETS: + * + * has facets + */ +#define XML_SCHEMAS_TYPE_HAS_FACETS 1 << 27 +/** + * XML_SCHEMAS_TYPE_NORMVALUENEEDED: + * + * indicates if the facets (pattern) need a normalized value + */ +#define XML_SCHEMAS_TYPE_NORMVALUENEEDED 1 << 28 + +/** + * XML_SCHEMAS_TYPE_FIXUP_1: + * + * First stage of fixup was done. + */ +#define XML_SCHEMAS_TYPE_FIXUP_1 1 << 29 + +/** + * XML_SCHEMAS_TYPE_REDEFINED: + * + * The type was redefined. + */ +#define XML_SCHEMAS_TYPE_REDEFINED 1 << 30 +/** + * XML_SCHEMAS_TYPE_REDEFINING: + * + * The type redefines an other type. + */ +/* #define XML_SCHEMAS_TYPE_REDEFINING 1 << 31 */ + +/** + * _xmlSchemaType: + * + * Schemas type definition. + */ +struct _xmlSchemaType { + xmlSchemaTypeType type; /* The kind of type */ + struct _xmlSchemaType *next; /* the next type if in a sequence ... */ + const xmlChar *name; + const xmlChar *id ; /* Deprecated; not used */ + const xmlChar *ref; /* Deprecated; not used */ + const xmlChar *refNs; /* Deprecated; not used */ + xmlSchemaAnnotPtr annot; + xmlSchemaTypePtr subtypes; + xmlSchemaAttributePtr attributes; /* Deprecated; not used */ + xmlNodePtr node; + int minOccurs; /* Deprecated; not used */ + int maxOccurs; /* Deprecated; not used */ + + int flags; + xmlSchemaContentType contentType; + const xmlChar *base; /* Base type's local name */ + const xmlChar *baseNs; /* Base type's target namespace */ + xmlSchemaTypePtr baseType; /* The base type component */ + xmlSchemaFacetPtr facets; /* Local facets */ + struct _xmlSchemaType *redef; /* Deprecated; not used */ + int recurse; /* Obsolete */ + xmlSchemaAttributeLinkPtr *attributeUses; /* Deprecated; not used */ + xmlSchemaWildcardPtr attributeWildcard; + int builtInType; /* Type of built-in types. */ + xmlSchemaTypeLinkPtr memberTypes; /* member-types if a union type. */ + xmlSchemaFacetLinkPtr facetSet; /* All facets (incl. inherited) */ + const xmlChar *refPrefix; /* Deprecated; not used */ + xmlSchemaTypePtr contentTypeDef; /* Used for the simple content of complex types. + Could we use @subtypes for this? */ + xmlRegexpPtr contModel; /* Holds the automaton of the content model */ + const xmlChar *targetNamespace; + void *attrUses; +}; + +/* + * xmlSchemaElement: + * An element definition. + * + * xmlSchemaType, xmlSchemaFacet and xmlSchemaElement start of + * structures must be kept similar + */ +/** + * XML_SCHEMAS_ELEM_NILLABLE: + * + * the element is nillable + */ +#define XML_SCHEMAS_ELEM_NILLABLE 1 << 0 +/** + * XML_SCHEMAS_ELEM_GLOBAL: + * + * the element is global + */ +#define XML_SCHEMAS_ELEM_GLOBAL 1 << 1 +/** + * XML_SCHEMAS_ELEM_DEFAULT: + * + * the element has a default value + */ +#define XML_SCHEMAS_ELEM_DEFAULT 1 << 2 +/** + * XML_SCHEMAS_ELEM_FIXED: + * + * the element has a fixed value + */ +#define XML_SCHEMAS_ELEM_FIXED 1 << 3 +/** + * XML_SCHEMAS_ELEM_ABSTRACT: + * + * the element is abstract + */ +#define XML_SCHEMAS_ELEM_ABSTRACT 1 << 4 +/** + * XML_SCHEMAS_ELEM_TOPLEVEL: + * + * the element is top level + * obsolete: use XML_SCHEMAS_ELEM_GLOBAL instead + */ +#define XML_SCHEMAS_ELEM_TOPLEVEL 1 << 5 +/** + * XML_SCHEMAS_ELEM_REF: + * + * the element is a reference to a type + */ +#define XML_SCHEMAS_ELEM_REF 1 << 6 +/** + * XML_SCHEMAS_ELEM_NSDEFAULT: + * + * allow elements in no namespace + * Obsolete, not used anymore. + */ +#define XML_SCHEMAS_ELEM_NSDEFAULT 1 << 7 +/** + * XML_SCHEMAS_ELEM_INTERNAL_RESOLVED: + * + * this is set when "type", "ref", "substitutionGroup" + * references have been resolved. + */ +#define XML_SCHEMAS_ELEM_INTERNAL_RESOLVED 1 << 8 + /** + * XML_SCHEMAS_ELEM_CIRCULAR: + * + * a helper flag for the search of circular references. + */ +#define XML_SCHEMAS_ELEM_CIRCULAR 1 << 9 +/** + * XML_SCHEMAS_ELEM_BLOCK_ABSENT: + * + * the "block" attribute is absent + */ +#define XML_SCHEMAS_ELEM_BLOCK_ABSENT 1 << 10 +/** + * XML_SCHEMAS_ELEM_BLOCK_EXTENSION: + * + * disallowed substitutions are absent + */ +#define XML_SCHEMAS_ELEM_BLOCK_EXTENSION 1 << 11 +/** + * XML_SCHEMAS_ELEM_BLOCK_RESTRICTION: + * + * disallowed substitutions: "restriction" + */ +#define XML_SCHEMAS_ELEM_BLOCK_RESTRICTION 1 << 12 +/** + * XML_SCHEMAS_ELEM_BLOCK_SUBSTITUTION: + * + * disallowed substitutions: "substituion" + */ +#define XML_SCHEMAS_ELEM_BLOCK_SUBSTITUTION 1 << 13 +/** + * XML_SCHEMAS_ELEM_FINAL_ABSENT: + * + * substitution group exclusions are absent + */ +#define XML_SCHEMAS_ELEM_FINAL_ABSENT 1 << 14 +/** + * XML_SCHEMAS_ELEM_FINAL_EXTENSION: + * + * substitution group exclusions: "extension" + */ +#define XML_SCHEMAS_ELEM_FINAL_EXTENSION 1 << 15 +/** + * XML_SCHEMAS_ELEM_FINAL_RESTRICTION: + * + * substitution group exclusions: "restriction" + */ +#define XML_SCHEMAS_ELEM_FINAL_RESTRICTION 1 << 16 +/** + * XML_SCHEMAS_ELEM_SUBST_GROUP_HEAD: + * + * the declaration is a substitution group head + */ +#define XML_SCHEMAS_ELEM_SUBST_GROUP_HEAD 1 << 17 +/** + * XML_SCHEMAS_ELEM_INTERNAL_CHECKED: + * + * this is set when the elem decl has been checked against + * all constraints + */ +#define XML_SCHEMAS_ELEM_INTERNAL_CHECKED 1 << 18 + +typedef struct _xmlSchemaElement xmlSchemaElement; +typedef xmlSchemaElement *xmlSchemaElementPtr; +struct _xmlSchemaElement { + xmlSchemaTypeType type; /* The kind of type */ + struct _xmlSchemaType *next; /* Not used? */ + const xmlChar *name; + const xmlChar *id; /* Deprecated; not used */ + const xmlChar *ref; /* Deprecated; not used */ + const xmlChar *refNs; /* Deprecated; not used */ + xmlSchemaAnnotPtr annot; + xmlSchemaTypePtr subtypes; /* the type definition */ + xmlSchemaAttributePtr attributes; + xmlNodePtr node; + int minOccurs; /* Deprecated; not used */ + int maxOccurs; /* Deprecated; not used */ + + int flags; + const xmlChar *targetNamespace; + const xmlChar *namedType; + const xmlChar *namedTypeNs; + const xmlChar *substGroup; + const xmlChar *substGroupNs; + const xmlChar *scope; + const xmlChar *value; /* The original value of the value constraint. */ + struct _xmlSchemaElement *refDecl; /* This will now be used for the + substitution group affiliation */ + xmlRegexpPtr contModel; /* Obsolete for WXS, maybe used for RelaxNG */ + xmlSchemaContentType contentType; + const xmlChar *refPrefix; /* Deprecated; not used */ + xmlSchemaValPtr defVal; /* The compiled value contraint. */ + void *idcs; /* The identity-constraint defs */ +}; + +/* + * XML_SCHEMAS_FACET_UNKNOWN: + * + * unknown facet handling + */ +#define XML_SCHEMAS_FACET_UNKNOWN 0 +/* + * XML_SCHEMAS_FACET_PRESERVE: + * + * preserve the type of the facet + */ +#define XML_SCHEMAS_FACET_PRESERVE 1 +/* + * XML_SCHEMAS_FACET_REPLACE: + * + * replace the type of the facet + */ +#define XML_SCHEMAS_FACET_REPLACE 2 +/* + * XML_SCHEMAS_FACET_COLLAPSE: + * + * collapse the types of the facet + */ +#define XML_SCHEMAS_FACET_COLLAPSE 3 +/** + * A facet definition. + */ +struct _xmlSchemaFacet { + xmlSchemaTypeType type; /* The kind of type */ + struct _xmlSchemaFacet *next;/* the next type if in a sequence ... */ + const xmlChar *value; /* The original value */ + const xmlChar *id; /* Obsolete */ + xmlSchemaAnnotPtr annot; + xmlNodePtr node; + int fixed; /* XML_SCHEMAS_FACET_PRESERVE, etc. */ + int whitespace; + xmlSchemaValPtr val; /* The compiled value */ + xmlRegexpPtr regexp; /* The regex for patterns */ +}; + +/** + * A notation definition. + */ +typedef struct _xmlSchemaNotation xmlSchemaNotation; +typedef xmlSchemaNotation *xmlSchemaNotationPtr; +struct _xmlSchemaNotation { + xmlSchemaTypeType type; /* The kind of type */ + const xmlChar *name; + xmlSchemaAnnotPtr annot; + const xmlChar *identifier; + const xmlChar *targetNamespace; +}; + +/* +* TODO: Actually all those flags used for the schema should sit +* on the schema parser context, since they are used only +* during parsing an XML schema document, and not available +* on the component level as per spec. +*/ +/** + * XML_SCHEMAS_QUALIF_ELEM: + * + * Reflects elementFormDefault == qualified in + * an XML schema document. + */ +#define XML_SCHEMAS_QUALIF_ELEM 1 << 0 +/** + * XML_SCHEMAS_QUALIF_ATTR: + * + * Reflects attributeFormDefault == qualified in + * an XML schema document. + */ +#define XML_SCHEMAS_QUALIF_ATTR 1 << 1 +/** + * XML_SCHEMAS_FINAL_DEFAULT_EXTENSION: + * + * the schema has "extension" in the set of finalDefault. + */ +#define XML_SCHEMAS_FINAL_DEFAULT_EXTENSION 1 << 2 +/** + * XML_SCHEMAS_FINAL_DEFAULT_RESTRICTION: + * + * the schema has "restriction" in the set of finalDefault. + */ +#define XML_SCHEMAS_FINAL_DEFAULT_RESTRICTION 1 << 3 +/** + * XML_SCHEMAS_FINAL_DEFAULT_LIST: + * + * the cshema has "list" in the set of finalDefault. + */ +#define XML_SCHEMAS_FINAL_DEFAULT_LIST 1 << 4 +/** + * XML_SCHEMAS_FINAL_DEFAULT_UNION: + * + * the schema has "union" in the set of finalDefault. + */ +#define XML_SCHEMAS_FINAL_DEFAULT_UNION 1 << 5 +/** + * XML_SCHEMAS_BLOCK_DEFAULT_EXTENSION: + * + * the schema has "extension" in the set of blockDefault. + */ +#define XML_SCHEMAS_BLOCK_DEFAULT_EXTENSION 1 << 6 +/** + * XML_SCHEMAS_BLOCK_DEFAULT_RESTRICTION: + * + * the schema has "restriction" in the set of blockDefault. + */ +#define XML_SCHEMAS_BLOCK_DEFAULT_RESTRICTION 1 << 7 +/** + * XML_SCHEMAS_BLOCK_DEFAULT_SUBSTITUTION: + * + * the schema has "substitution" in the set of blockDefault. + */ +#define XML_SCHEMAS_BLOCK_DEFAULT_SUBSTITUTION 1 << 8 +/** + * XML_SCHEMAS_INCLUDING_CONVERT_NS: + * + * the schema is currently including an other schema with + * no target namespace. + */ +#define XML_SCHEMAS_INCLUDING_CONVERT_NS 1 << 9 +/** + * _xmlSchema: + * + * A Schemas definition + */ +struct _xmlSchema { + const xmlChar *name; /* schema name */ + const xmlChar *targetNamespace; /* the target namespace */ + const xmlChar *version; + const xmlChar *id; /* Obsolete */ + xmlDocPtr doc; + xmlSchemaAnnotPtr annot; + int flags; + + xmlHashTablePtr typeDecl; + xmlHashTablePtr attrDecl; + xmlHashTablePtr attrgrpDecl; + xmlHashTablePtr elemDecl; + xmlHashTablePtr notaDecl; + + xmlHashTablePtr schemasImports; + + void *_private; /* unused by the library for users or bindings */ + xmlHashTablePtr groupDecl; + xmlDictPtr dict; + void *includes; /* the includes, this is opaque for now */ + int preserve; /* whether to free the document */ + int counter; /* used to give ononymous components unique names */ + xmlHashTablePtr idcDef; /* All identity-constraint defs. */ + void *volatiles; /* Obsolete */ +}; + +XMLPUBFUN void XMLCALL xmlSchemaFreeType (xmlSchemaTypePtr type); +XMLPUBFUN void XMLCALL xmlSchemaFreeWildcard(xmlSchemaWildcardPtr wildcard); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_SCHEMAS_ENABLED */ +#endif /* __XML_SCHEMA_INTERNALS_H__ */ diff --git a/android/native/libxml2/libxml/schematron.h b/android/native/libxml2/libxml/schematron.h new file mode 100644 index 0000000000..f442826ccd --- /dev/null +++ b/android/native/libxml2/libxml/schematron.h @@ -0,0 +1,142 @@ +/* + * Summary: XML Schemastron implementation + * Description: interface to the XML Schematron validity checking. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + + +#ifndef __XML_SCHEMATRON_H__ +#define __XML_SCHEMATRON_H__ + +#include + +#ifdef LIBXML_SCHEMATRON_ENABLED + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + XML_SCHEMATRON_OUT_QUIET = 1 << 0, /* quiet no report */ + XML_SCHEMATRON_OUT_TEXT = 1 << 1, /* build a textual report */ + XML_SCHEMATRON_OUT_XML = 1 << 2, /* output SVRL */ + XML_SCHEMATRON_OUT_ERROR = 1 << 3, /* output via xmlStructuredErrorFunc */ + XML_SCHEMATRON_OUT_FILE = 1 << 8, /* output to a file descriptor */ + XML_SCHEMATRON_OUT_BUFFER = 1 << 9, /* output to a buffer */ + XML_SCHEMATRON_OUT_IO = 1 << 10 /* output to I/O mechanism */ +} xmlSchematronValidOptions; + +/** + * The schemas related types are kept internal + */ +typedef struct _xmlSchematron xmlSchematron; +typedef xmlSchematron *xmlSchematronPtr; + +/** + * xmlSchematronValidityErrorFunc: + * @ctx: the validation context + * @msg: the message + * @...: extra arguments + * + * Signature of an error callback from a Schematron validation + */ +typedef void (*xmlSchematronValidityErrorFunc) (void *ctx, const char *msg, ...); + +/** + * xmlSchematronValidityWarningFunc: + * @ctx: the validation context + * @msg: the message + * @...: extra arguments + * + * Signature of a warning callback from a Schematron validation + */ +typedef void (*xmlSchematronValidityWarningFunc) (void *ctx, const char *msg, ...); + +/** + * A schemas validation context + */ +typedef struct _xmlSchematronParserCtxt xmlSchematronParserCtxt; +typedef xmlSchematronParserCtxt *xmlSchematronParserCtxtPtr; + +typedef struct _xmlSchematronValidCtxt xmlSchematronValidCtxt; +typedef xmlSchematronValidCtxt *xmlSchematronValidCtxtPtr; + +/* + * Interfaces for parsing. + */ +XMLPUBFUN xmlSchematronParserCtxtPtr XMLCALL + xmlSchematronNewParserCtxt (const char *URL); +XMLPUBFUN xmlSchematronParserCtxtPtr XMLCALL + xmlSchematronNewMemParserCtxt(const char *buffer, + int size); +XMLPUBFUN xmlSchematronParserCtxtPtr XMLCALL + xmlSchematronNewDocParserCtxt(xmlDocPtr doc); +XMLPUBFUN void XMLCALL + xmlSchematronFreeParserCtxt (xmlSchematronParserCtxtPtr ctxt); +/***** +XMLPUBFUN void XMLCALL + xmlSchematronSetParserErrors(xmlSchematronParserCtxtPtr ctxt, + xmlSchematronValidityErrorFunc err, + xmlSchematronValidityWarningFunc warn, + void *ctx); +XMLPUBFUN int XMLCALL + xmlSchematronGetParserErrors(xmlSchematronParserCtxtPtr ctxt, + xmlSchematronValidityErrorFunc * err, + xmlSchematronValidityWarningFunc * warn, + void **ctx); +XMLPUBFUN int XMLCALL + xmlSchematronIsValid (xmlSchematronValidCtxtPtr ctxt); + *****/ +XMLPUBFUN xmlSchematronPtr XMLCALL + xmlSchematronParse (xmlSchematronParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + xmlSchematronFree (xmlSchematronPtr schema); +/* + * Interfaces for validating + */ +XMLPUBFUN void XMLCALL + xmlSchematronSetValidStructuredErrors( + xmlSchematronValidCtxtPtr ctxt, + xmlStructuredErrorFunc serror, + void *ctx); +/****** +XMLPUBFUN void XMLCALL + xmlSchematronSetValidErrors (xmlSchematronValidCtxtPtr ctxt, + xmlSchematronValidityErrorFunc err, + xmlSchematronValidityWarningFunc warn, + void *ctx); +XMLPUBFUN int XMLCALL + xmlSchematronGetValidErrors (xmlSchematronValidCtxtPtr ctxt, + xmlSchematronValidityErrorFunc *err, + xmlSchematronValidityWarningFunc *warn, + void **ctx); +XMLPUBFUN int XMLCALL + xmlSchematronSetValidOptions(xmlSchematronValidCtxtPtr ctxt, + int options); +XMLPUBFUN int XMLCALL + xmlSchematronValidCtxtGetOptions(xmlSchematronValidCtxtPtr ctxt); +XMLPUBFUN int XMLCALL + xmlSchematronValidateOneElement (xmlSchematronValidCtxtPtr ctxt, + xmlNodePtr elem); + *******/ + +XMLPUBFUN xmlSchematronValidCtxtPtr XMLCALL + xmlSchematronNewValidCtxt (xmlSchematronPtr schema, + int options); +XMLPUBFUN void XMLCALL + xmlSchematronFreeValidCtxt (xmlSchematronValidCtxtPtr ctxt); +XMLPUBFUN int XMLCALL + xmlSchematronValidateDoc (xmlSchematronValidCtxtPtr ctxt, + xmlDocPtr instance); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_SCHEMATRON_ENABLED */ +#endif /* __XML_SCHEMATRON_H__ */ diff --git a/android/native/libxml2/libxml/threads.h b/android/native/libxml2/libxml/threads.h new file mode 100644 index 0000000000..d31f16acbd --- /dev/null +++ b/android/native/libxml2/libxml/threads.h @@ -0,0 +1,84 @@ +/** + * Summary: interfaces for thread handling + * Description: set of generic threading related routines + * should work with pthreads, Windows native or TLS threads + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_THREADS_H__ +#define __XML_THREADS_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * xmlMutex are a simple mutual exception locks. + */ +typedef struct _xmlMutex xmlMutex; +typedef xmlMutex *xmlMutexPtr; + +/* + * xmlRMutex are reentrant mutual exception locks. + */ +typedef struct _xmlRMutex xmlRMutex; +typedef xmlRMutex *xmlRMutexPtr; + +#ifdef __cplusplus +} +#endif +#include +#ifdef __cplusplus +extern "C" { +#endif +XMLPUBFUN xmlMutexPtr XMLCALL + xmlNewMutex (void); +XMLPUBFUN void XMLCALL + xmlMutexLock (xmlMutexPtr tok); +XMLPUBFUN void XMLCALL + xmlMutexUnlock (xmlMutexPtr tok); +XMLPUBFUN void XMLCALL + xmlFreeMutex (xmlMutexPtr tok); + +XMLPUBFUN xmlRMutexPtr XMLCALL + xmlNewRMutex (void); +XMLPUBFUN void XMLCALL + xmlRMutexLock (xmlRMutexPtr tok); +XMLPUBFUN void XMLCALL + xmlRMutexUnlock (xmlRMutexPtr tok); +XMLPUBFUN void XMLCALL + xmlFreeRMutex (xmlRMutexPtr tok); + +/* + * Library wide APIs. + */ +XMLPUBFUN void XMLCALL + xmlInitThreads (void); +XMLPUBFUN void XMLCALL + xmlLockLibrary (void); +XMLPUBFUN void XMLCALL + xmlUnlockLibrary(void); +XMLPUBFUN int XMLCALL + xmlGetThreadId (void); +XMLPUBFUN int XMLCALL + xmlIsMainThread (void); +XMLPUBFUN void XMLCALL + xmlCleanupThreads(void); +XMLPUBFUN xmlGlobalStatePtr XMLCALL + xmlGetGlobalState(void); + +#if defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && defined(LIBXML_STATIC_FOR_DLL) +int XMLCALL xmlDllMain(void *hinstDLL, unsigned long fdwReason, void *lpvReserved); +#endif + +#ifdef __cplusplus +} +#endif + + +#endif /* __XML_THREADS_H__ */ diff --git a/android/native/libxml2/libxml/tree.h b/android/native/libxml2/libxml/tree.h new file mode 100644 index 0000000000..b151b399cd --- /dev/null +++ b/android/native/libxml2/libxml/tree.h @@ -0,0 +1,1252 @@ +/* + * Summary: interfaces for tree manipulation + * Description: this module describes the structures found in an tree resulting + * from an XML or HTML parsing, as well as the API provided for + * various processing on that tree + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_TREE_H__ +#define __XML_TREE_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Some of the basic types pointer to structures: + */ +/* xmlIO.h */ +typedef struct _xmlParserInputBuffer xmlParserInputBuffer; +typedef xmlParserInputBuffer *xmlParserInputBufferPtr; + +typedef struct _xmlOutputBuffer xmlOutputBuffer; +typedef xmlOutputBuffer *xmlOutputBufferPtr; + +/* parser.h */ +typedef struct _xmlParserInput xmlParserInput; +typedef xmlParserInput *xmlParserInputPtr; + +typedef struct _xmlParserCtxt xmlParserCtxt; +typedef xmlParserCtxt *xmlParserCtxtPtr; + +typedef struct _xmlSAXLocator xmlSAXLocator; +typedef xmlSAXLocator *xmlSAXLocatorPtr; + +typedef struct _xmlSAXHandler xmlSAXHandler; +typedef xmlSAXHandler *xmlSAXHandlerPtr; + +/* entities.h */ +typedef struct _xmlEntity xmlEntity; +typedef xmlEntity *xmlEntityPtr; + +/** + * BASE_BUFFER_SIZE: + * + * default buffer size 4000. + */ +#define BASE_BUFFER_SIZE 4096 + +/** + * LIBXML_NAMESPACE_DICT: + * + * Defines experimental behaviour: + * 1) xmlNs gets an additional field @context (a xmlDoc) + * 2) when creating a tree, xmlNs->href is stored in the dict of xmlDoc. + */ +/* #define LIBXML_NAMESPACE_DICT */ + +/** + * xmlBufferAllocationScheme: + * + * A buffer allocation scheme can be defined to either match exactly the + * need or double it's allocated size each time it is found too small. + */ + +typedef enum { + XML_BUFFER_ALLOC_DOUBLEIT, /* double each time one need to grow */ + XML_BUFFER_ALLOC_EXACT, /* grow only to the minimal size */ + XML_BUFFER_ALLOC_IMMUTABLE, /* immutable buffer */ + XML_BUFFER_ALLOC_IO /* special allocation scheme used for I/O */ +} xmlBufferAllocationScheme; + +/** + * xmlBuffer: + * + * A buffer structure. + */ +typedef struct _xmlBuffer xmlBuffer; +typedef xmlBuffer *xmlBufferPtr; +struct _xmlBuffer { + xmlChar *content; /* The buffer content UTF8 */ + unsigned int use; /* The buffer size used */ + unsigned int size; /* The buffer size */ + xmlBufferAllocationScheme alloc; /* The realloc method */ + xmlChar *contentIO; /* in IO mode we may have a different base */ +}; + +/** + * XML_XML_NAMESPACE: + * + * This is the namespace for the special xml: prefix predefined in the + * XML Namespace specification. + */ +#define XML_XML_NAMESPACE \ + (const xmlChar *) "http://www.w3.org/XML/1998/namespace" + +/** + * XML_XML_ID: + * + * This is the name for the special xml:id attribute + */ +#define XML_XML_ID (const xmlChar *) "xml:id" + +/* + * The different element types carried by an XML tree. + * + * NOTE: This is synchronized with DOM Level1 values + * See http://www.w3.org/TR/REC-DOM-Level-1/ + * + * Actually this had diverged a bit, and now XML_DOCUMENT_TYPE_NODE should + * be deprecated to use an XML_DTD_NODE. + */ +typedef enum { + XML_ELEMENT_NODE= 1, + XML_ATTRIBUTE_NODE= 2, + XML_TEXT_NODE= 3, + XML_CDATA_SECTION_NODE= 4, + XML_ENTITY_REF_NODE= 5, + XML_ENTITY_NODE= 6, + XML_PI_NODE= 7, + XML_COMMENT_NODE= 8, + XML_DOCUMENT_NODE= 9, + XML_DOCUMENT_TYPE_NODE= 10, + XML_DOCUMENT_FRAG_NODE= 11, + XML_NOTATION_NODE= 12, + XML_HTML_DOCUMENT_NODE= 13, + XML_DTD_NODE= 14, + XML_ELEMENT_DECL= 15, + XML_ATTRIBUTE_DECL= 16, + XML_ENTITY_DECL= 17, + XML_NAMESPACE_DECL= 18, + XML_XINCLUDE_START= 19, + XML_XINCLUDE_END= 20 +#ifdef LIBXML_DOCB_ENABLED + ,XML_DOCB_DOCUMENT_NODE= 21 +#endif +} xmlElementType; + + +/** + * xmlNotation: + * + * A DTD Notation definition. + */ + +typedef struct _xmlNotation xmlNotation; +typedef xmlNotation *xmlNotationPtr; +struct _xmlNotation { + const xmlChar *name; /* Notation name */ + const xmlChar *PublicID; /* Public identifier, if any */ + const xmlChar *SystemID; /* System identifier, if any */ +}; + +/** + * xmlAttributeType: + * + * A DTD Attribute type definition. + */ + +typedef enum { + XML_ATTRIBUTE_CDATA = 1, + XML_ATTRIBUTE_ID, + XML_ATTRIBUTE_IDREF , + XML_ATTRIBUTE_IDREFS, + XML_ATTRIBUTE_ENTITY, + XML_ATTRIBUTE_ENTITIES, + XML_ATTRIBUTE_NMTOKEN, + XML_ATTRIBUTE_NMTOKENS, + XML_ATTRIBUTE_ENUMERATION, + XML_ATTRIBUTE_NOTATION +} xmlAttributeType; + +/** + * xmlAttributeDefault: + * + * A DTD Attribute default definition. + */ + +typedef enum { + XML_ATTRIBUTE_NONE = 1, + XML_ATTRIBUTE_REQUIRED, + XML_ATTRIBUTE_IMPLIED, + XML_ATTRIBUTE_FIXED +} xmlAttributeDefault; + +/** + * xmlEnumeration: + * + * List structure used when there is an enumeration in DTDs. + */ + +typedef struct _xmlEnumeration xmlEnumeration; +typedef xmlEnumeration *xmlEnumerationPtr; +struct _xmlEnumeration { + struct _xmlEnumeration *next; /* next one */ + const xmlChar *name; /* Enumeration name */ +}; + +/** + * xmlAttribute: + * + * An Attribute declaration in a DTD. + */ + +typedef struct _xmlAttribute xmlAttribute; +typedef xmlAttribute *xmlAttributePtr; +struct _xmlAttribute { + void *_private; /* application data */ + xmlElementType type; /* XML_ATTRIBUTE_DECL, must be second ! */ + const xmlChar *name; /* Attribute name */ + struct _xmlNode *children; /* NULL */ + struct _xmlNode *last; /* NULL */ + struct _xmlDtd *parent; /* -> DTD */ + struct _xmlNode *next; /* next sibling link */ + struct _xmlNode *prev; /* previous sibling link */ + struct _xmlDoc *doc; /* the containing document */ + + struct _xmlAttribute *nexth; /* next in hash table */ + xmlAttributeType atype; /* The attribute type */ + xmlAttributeDefault def; /* the default */ + const xmlChar *defaultValue; /* or the default value */ + xmlEnumerationPtr tree; /* or the enumeration tree if any */ + const xmlChar *prefix; /* the namespace prefix if any */ + const xmlChar *elem; /* Element holding the attribute */ +}; + +/** + * xmlElementContentType: + * + * Possible definitions of element content types. + */ +typedef enum { + XML_ELEMENT_CONTENT_PCDATA = 1, + XML_ELEMENT_CONTENT_ELEMENT, + XML_ELEMENT_CONTENT_SEQ, + XML_ELEMENT_CONTENT_OR +} xmlElementContentType; + +/** + * xmlElementContentOccur: + * + * Possible definitions of element content occurrences. + */ +typedef enum { + XML_ELEMENT_CONTENT_ONCE = 1, + XML_ELEMENT_CONTENT_OPT, + XML_ELEMENT_CONTENT_MULT, + XML_ELEMENT_CONTENT_PLUS +} xmlElementContentOccur; + +/** + * xmlElementContent: + * + * An XML Element content as stored after parsing an element definition + * in a DTD. + */ + +typedef struct _xmlElementContent xmlElementContent; +typedef xmlElementContent *xmlElementContentPtr; +struct _xmlElementContent { + xmlElementContentType type; /* PCDATA, ELEMENT, SEQ or OR */ + xmlElementContentOccur ocur; /* ONCE, OPT, MULT or PLUS */ + const xmlChar *name; /* Element name */ + struct _xmlElementContent *c1; /* first child */ + struct _xmlElementContent *c2; /* second child */ + struct _xmlElementContent *parent; /* parent */ + const xmlChar *prefix; /* Namespace prefix */ +}; + +/** + * xmlElementTypeVal: + * + * The different possibilities for an element content type. + */ + +typedef enum { + XML_ELEMENT_TYPE_UNDEFINED = 0, + XML_ELEMENT_TYPE_EMPTY = 1, + XML_ELEMENT_TYPE_ANY, + XML_ELEMENT_TYPE_MIXED, + XML_ELEMENT_TYPE_ELEMENT +} xmlElementTypeVal; + +#ifdef __cplusplus +} +#endif +#include +#ifdef __cplusplus +extern "C" { +#endif + +/** + * xmlElement: + * + * An XML Element declaration from a DTD. + */ + +typedef struct _xmlElement xmlElement; +typedef xmlElement *xmlElementPtr; +struct _xmlElement { + void *_private; /* application data */ + xmlElementType type; /* XML_ELEMENT_DECL, must be second ! */ + const xmlChar *name; /* Element name */ + struct _xmlNode *children; /* NULL */ + struct _xmlNode *last; /* NULL */ + struct _xmlDtd *parent; /* -> DTD */ + struct _xmlNode *next; /* next sibling link */ + struct _xmlNode *prev; /* previous sibling link */ + struct _xmlDoc *doc; /* the containing document */ + + xmlElementTypeVal etype; /* The type */ + xmlElementContentPtr content; /* the allowed element content */ + xmlAttributePtr attributes; /* List of the declared attributes */ + const xmlChar *prefix; /* the namespace prefix if any */ +#ifdef LIBXML_REGEXP_ENABLED + xmlRegexpPtr contModel; /* the validating regexp */ +#else + void *contModel; +#endif +}; + + +/** + * XML_LOCAL_NAMESPACE: + * + * A namespace declaration node. + */ +#define XML_LOCAL_NAMESPACE XML_NAMESPACE_DECL +typedef xmlElementType xmlNsType; + +/** + * xmlNs: + * + * An XML namespace. + * Note that prefix == NULL is valid, it defines the default namespace + * within the subtree (until overridden). + * + * xmlNsType is unified with xmlElementType. + */ + +typedef struct _xmlNs xmlNs; +typedef xmlNs *xmlNsPtr; +struct _xmlNs { + struct _xmlNs *next; /* next Ns link for this node */ + xmlNsType type; /* global or local */ + const xmlChar *href; /* URL for the namespace */ + const xmlChar *prefix; /* prefix for the namespace */ + void *_private; /* application data */ + struct _xmlDoc *context; /* normally an xmlDoc */ +}; + +/** + * xmlDtd: + * + * An XML DTD, as defined by parent link */ + struct _xmlNode *next; /* next sibling link */ + struct _xmlNode *prev; /* previous sibling link */ + struct _xmlDoc *doc; /* the containing document */ + + /* End of common part */ + void *notations; /* Hash table for notations if any */ + void *elements; /* Hash table for elements if any */ + void *attributes; /* Hash table for attributes if any */ + void *entities; /* Hash table for entities if any */ + const xmlChar *ExternalID; /* External identifier for PUBLIC DTD */ + const xmlChar *SystemID; /* URI for a SYSTEM or PUBLIC DTD */ + void *pentities; /* Hash table for param entities if any */ +}; + +/** + * xmlAttr: + * + * An attribute on an XML node. + */ +typedef struct _xmlAttr xmlAttr; +typedef xmlAttr *xmlAttrPtr; +struct _xmlAttr { + void *_private; /* application data */ + xmlElementType type; /* XML_ATTRIBUTE_NODE, must be second ! */ + const xmlChar *name; /* the name of the property */ + struct _xmlNode *children; /* the value of the property */ + struct _xmlNode *last; /* NULL */ + struct _xmlNode *parent; /* child->parent link */ + struct _xmlAttr *next; /* next sibling link */ + struct _xmlAttr *prev; /* previous sibling link */ + struct _xmlDoc *doc; /* the containing document */ + xmlNs *ns; /* pointer to the associated namespace */ + xmlAttributeType atype; /* the attribute type if validating */ + void *psvi; /* for type/PSVI informations */ +}; + +/** + * xmlID: + * + * An XML ID instance. + */ + +typedef struct _xmlID xmlID; +typedef xmlID *xmlIDPtr; +struct _xmlID { + struct _xmlID *next; /* next ID */ + const xmlChar *value; /* The ID name */ + xmlAttrPtr attr; /* The attribute holding it */ + const xmlChar *name; /* The attribute if attr is not available */ + int lineno; /* The line number if attr is not available */ + struct _xmlDoc *doc; /* The document holding the ID */ +}; + +/** + * xmlRef: + * + * An XML IDREF instance. + */ + +typedef struct _xmlRef xmlRef; +typedef xmlRef *xmlRefPtr; +struct _xmlRef { + struct _xmlRef *next; /* next Ref */ + const xmlChar *value; /* The Ref name */ + xmlAttrPtr attr; /* The attribute holding it */ + const xmlChar *name; /* The attribute if attr is not available */ + int lineno; /* The line number if attr is not available */ +}; + +/** + * xmlNode: + * + * A node in an XML tree. + */ +typedef struct _xmlNode xmlNode; +typedef xmlNode *xmlNodePtr; +struct _xmlNode { + void *_private; /* application data */ + xmlElementType type; /* type number, must be second ! */ + const xmlChar *name; /* the name of the node, or the entity */ + struct _xmlNode *children; /* parent->childs link */ + struct _xmlNode *last; /* last child link */ + struct _xmlNode *parent; /* child->parent link */ + struct _xmlNode *next; /* next sibling link */ + struct _xmlNode *prev; /* previous sibling link */ + struct _xmlDoc *doc; /* the containing document */ + + /* End of common part */ + xmlNs *ns; /* pointer to the associated namespace */ + xmlChar *content; /* the content */ + struct _xmlAttr *properties;/* properties list */ + xmlNs *nsDef; /* namespace definitions on this node */ + void *psvi; /* for type/PSVI informations */ + unsigned short line; /* line number */ + unsigned short extra; /* extra data for XPath/XSLT */ +}; + +/** + * XML_GET_CONTENT: + * + * Macro to extract the content pointer of a node. + */ +#define XML_GET_CONTENT(n) \ + ((n)->type == XML_ELEMENT_NODE ? NULL : (n)->content) + +/** + * XML_GET_LINE: + * + * Macro to extract the line number of an element node. + */ +#define XML_GET_LINE(n) \ + (xmlGetLineNo(n)) + +/** + * xmlDocProperty + * + * Set of properties of the document as found by the parser + * Some of them are linked to similary named xmlParserOption + */ +typedef enum { + XML_DOC_WELLFORMED = 1<<0, /* document is XML well formed */ + XML_DOC_NSVALID = 1<<1, /* document is Namespace valid */ + XML_DOC_OLD10 = 1<<2, /* parsed with old XML-1.0 parser */ + XML_DOC_DTDVALID = 1<<3, /* DTD validation was successful */ + XML_DOC_XINCLUDE = 1<<4, /* XInclude substitution was done */ + XML_DOC_USERBUILT = 1<<5, /* Document was built using the API + and not by parsing an instance */ + XML_DOC_INTERNAL = 1<<6, /* built for internal processing */ + XML_DOC_HTML = 1<<7 /* parsed or built HTML document */ +} xmlDocProperties; + +/** + * xmlDoc: + * + * An XML document. + */ +typedef struct _xmlDoc xmlDoc; +typedef xmlDoc *xmlDocPtr; +struct _xmlDoc { + void *_private; /* application data */ + xmlElementType type; /* XML_DOCUMENT_NODE, must be second ! */ + char *name; /* name/filename/URI of the document */ + struct _xmlNode *children; /* the document tree */ + struct _xmlNode *last; /* last child link */ + struct _xmlNode *parent; /* child->parent link */ + struct _xmlNode *next; /* next sibling link */ + struct _xmlNode *prev; /* previous sibling link */ + struct _xmlDoc *doc; /* autoreference to itself */ + + /* End of common part */ + int compression;/* level of zlib compression */ + int standalone; /* standalone document (no external refs) + 1 if standalone="yes" + 0 if standalone="no" + -1 if there is no XML declaration + -2 if there is an XML declaration, but no + standalone attribute was specified */ + struct _xmlDtd *intSubset; /* the document internal subset */ + struct _xmlDtd *extSubset; /* the document external subset */ + struct _xmlNs *oldNs; /* Global namespace, the old way */ + const xmlChar *version; /* the XML version string */ + const xmlChar *encoding; /* external initial encoding, if any */ + void *ids; /* Hash table for ID attributes if any */ + void *refs; /* Hash table for IDREFs attributes if any */ + const xmlChar *URL; /* The URI for that document */ + int charset; /* encoding of the in-memory content + actually an xmlCharEncoding */ + struct _xmlDict *dict; /* dict used to allocate names or NULL */ + void *psvi; /* for type/PSVI informations */ + int parseFlags; /* set of xmlParserOption used to parse the + document */ + int properties; /* set of xmlDocProperties for this document + set at the end of parsing */ +}; + + +typedef struct _xmlDOMWrapCtxt xmlDOMWrapCtxt; +typedef xmlDOMWrapCtxt *xmlDOMWrapCtxtPtr; + +/** + * xmlDOMWrapAcquireNsFunction: + * @ctxt: a DOM wrapper context + * @node: the context node (element or attribute) + * @nsName: the requested namespace name + * @nsPrefix: the requested namespace prefix + * + * A function called to acquire namespaces (xmlNs) from the wrapper. + * + * Returns an xmlNsPtr or NULL in case of an error. + */ +typedef xmlNsPtr (*xmlDOMWrapAcquireNsFunction) (xmlDOMWrapCtxtPtr ctxt, + xmlNodePtr node, + const xmlChar *nsName, + const xmlChar *nsPrefix); + +/** + * xmlDOMWrapCtxt: + * + * Context for DOM wrapper-operations. + */ +struct _xmlDOMWrapCtxt { + void * _private; + /* + * The type of this context, just in case we need specialized + * contexts in the future. + */ + int type; + /* + * Internal namespace map used for various operations. + */ + void * namespaceMap; + /* + * Use this one to acquire an xmlNsPtr intended for node->ns. + * (Note that this is not intended for elem->nsDef). + */ + xmlDOMWrapAcquireNsFunction getNsForNodeFunc; +}; + +/** + * xmlChildrenNode: + * + * Macro for compatibility naming layer with libxml1. Maps + * to "children." + */ +#ifndef xmlChildrenNode +#define xmlChildrenNode children +#endif + +/** + * xmlRootNode: + * + * Macro for compatibility naming layer with libxml1. Maps + * to "children". + */ +#ifndef xmlRootNode +#define xmlRootNode children +#endif + +/* + * Variables. + */ + +/* + * Some helper functions + */ +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_DEBUG_ENABLED) || defined(LIBXML_SAX1_ENABLED) || defined(LIBXML_WRITER_ENABLED) || defined(LIBXML_DOCB_ENABLED) +XMLPUBFUN int XMLCALL + xmlValidateNCName (const xmlChar *value, + int space); +#endif + +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) +XMLPUBFUN int XMLCALL + xmlValidateQName (const xmlChar *value, + int space); +XMLPUBFUN int XMLCALL + xmlValidateName (const xmlChar *value, + int space); +XMLPUBFUN int XMLCALL + xmlValidateNMToken (const xmlChar *value, + int space); +#endif + +XMLPUBFUN xmlChar * XMLCALL + xmlBuildQName (const xmlChar *ncname, + const xmlChar *prefix, + xmlChar *memory, + int len); +XMLPUBFUN xmlChar * XMLCALL + xmlSplitQName2 (const xmlChar *name, + xmlChar **prefix); +XMLPUBFUN const xmlChar * XMLCALL + xmlSplitQName3 (const xmlChar *name, + int *len); + +/* + * Handling Buffers. + */ + +XMLPUBFUN void XMLCALL + xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme); +XMLPUBFUN xmlBufferAllocationScheme XMLCALL + xmlGetBufferAllocationScheme(void); + +XMLPUBFUN xmlBufferPtr XMLCALL + xmlBufferCreate (void); +XMLPUBFUN xmlBufferPtr XMLCALL + xmlBufferCreateSize (size_t size); +XMLPUBFUN xmlBufferPtr XMLCALL + xmlBufferCreateStatic (void *mem, + size_t size); +XMLPUBFUN int XMLCALL + xmlBufferResize (xmlBufferPtr buf, + unsigned int size); +XMLPUBFUN void XMLCALL + xmlBufferFree (xmlBufferPtr buf); +XMLPUBFUN int XMLCALL + xmlBufferDump (FILE *file, + xmlBufferPtr buf); +XMLPUBFUN int XMLCALL + xmlBufferAdd (xmlBufferPtr buf, + const xmlChar *str, + int len); +XMLPUBFUN int XMLCALL + xmlBufferAddHead (xmlBufferPtr buf, + const xmlChar *str, + int len); +XMLPUBFUN int XMLCALL + xmlBufferCat (xmlBufferPtr buf, + const xmlChar *str); +XMLPUBFUN int XMLCALL + xmlBufferCCat (xmlBufferPtr buf, + const char *str); +XMLPUBFUN int XMLCALL + xmlBufferShrink (xmlBufferPtr buf, + unsigned int len); +XMLPUBFUN int XMLCALL + xmlBufferGrow (xmlBufferPtr buf, + unsigned int len); +XMLPUBFUN void XMLCALL + xmlBufferEmpty (xmlBufferPtr buf); +XMLPUBFUN const xmlChar* XMLCALL + xmlBufferContent (const xmlBufferPtr buf); +XMLPUBFUN void XMLCALL + xmlBufferSetAllocationScheme(xmlBufferPtr buf, + xmlBufferAllocationScheme scheme); +XMLPUBFUN int XMLCALL + xmlBufferLength (const xmlBufferPtr buf); + +/* + * Creating/freeing new structures. + */ +XMLPUBFUN xmlDtdPtr XMLCALL + xmlCreateIntSubset (xmlDocPtr doc, + const xmlChar *name, + const xmlChar *ExternalID, + const xmlChar *SystemID); +XMLPUBFUN xmlDtdPtr XMLCALL + xmlNewDtd (xmlDocPtr doc, + const xmlChar *name, + const xmlChar *ExternalID, + const xmlChar *SystemID); +XMLPUBFUN xmlDtdPtr XMLCALL + xmlGetIntSubset (xmlDocPtr doc); +XMLPUBFUN void XMLCALL + xmlFreeDtd (xmlDtdPtr cur); +#ifdef LIBXML_LEGACY_ENABLED +XMLPUBFUN xmlNsPtr XMLCALL + xmlNewGlobalNs (xmlDocPtr doc, + const xmlChar *href, + const xmlChar *prefix); +#endif /* LIBXML_LEGACY_ENABLED */ +XMLPUBFUN xmlNsPtr XMLCALL + xmlNewNs (xmlNodePtr node, + const xmlChar *href, + const xmlChar *prefix); +XMLPUBFUN void XMLCALL + xmlFreeNs (xmlNsPtr cur); +XMLPUBFUN void XMLCALL + xmlFreeNsList (xmlNsPtr cur); +XMLPUBFUN xmlDocPtr XMLCALL + xmlNewDoc (const xmlChar *version); +XMLPUBFUN void XMLCALL + xmlFreeDoc (xmlDocPtr cur); +XMLPUBFUN xmlAttrPtr XMLCALL + xmlNewDocProp (xmlDocPtr doc, + const xmlChar *name, + const xmlChar *value); +#if defined(LIBXML_TREE_ENABLED) || \ + defined(LIBXML_SCHEMAS_ENABLED) +XMLPUBFUN xmlAttrPtr XMLCALL + xmlNewProp (xmlNodePtr node, + const xmlChar *name, + const xmlChar *value); +#endif +XMLPUBFUN xmlAttrPtr XMLCALL + xmlNewNsProp (xmlNodePtr node, + xmlNsPtr ns, + const xmlChar *name, + const xmlChar *value); +XMLPUBFUN xmlAttrPtr XMLCALL + xmlNewNsPropEatName (xmlNodePtr node, + xmlNsPtr ns, + xmlChar *name, + const xmlChar *value); +XMLPUBFUN void XMLCALL + xmlFreePropList (xmlAttrPtr cur); +XMLPUBFUN void XMLCALL + xmlFreeProp (xmlAttrPtr cur); +XMLPUBFUN xmlAttrPtr XMLCALL + xmlCopyProp (xmlNodePtr target, + xmlAttrPtr cur); +XMLPUBFUN xmlAttrPtr XMLCALL + xmlCopyPropList (xmlNodePtr target, + xmlAttrPtr cur); +#ifdef LIBXML_TREE_ENABLED +XMLPUBFUN xmlDtdPtr XMLCALL + xmlCopyDtd (xmlDtdPtr dtd); +#endif /* LIBXML_TREE_ENABLED */ +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) +XMLPUBFUN xmlDocPtr XMLCALL + xmlCopyDoc (xmlDocPtr doc, + int recursive); +#endif /* defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) */ +/* + * Creating new nodes. + */ +XMLPUBFUN xmlNodePtr XMLCALL + xmlNewDocNode (xmlDocPtr doc, + xmlNsPtr ns, + const xmlChar *name, + const xmlChar *content); +XMLPUBFUN xmlNodePtr XMLCALL + xmlNewDocNodeEatName (xmlDocPtr doc, + xmlNsPtr ns, + xmlChar *name, + const xmlChar *content); +XMLPUBFUN xmlNodePtr XMLCALL + xmlNewNode (xmlNsPtr ns, + const xmlChar *name); +XMLPUBFUN xmlNodePtr XMLCALL + xmlNewNodeEatName (xmlNsPtr ns, + xmlChar *name); +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) +XMLPUBFUN xmlNodePtr XMLCALL + xmlNewChild (xmlNodePtr parent, + xmlNsPtr ns, + const xmlChar *name, + const xmlChar *content); +#endif +XMLPUBFUN xmlNodePtr XMLCALL + xmlNewDocText (xmlDocPtr doc, + const xmlChar *content); +XMLPUBFUN xmlNodePtr XMLCALL + xmlNewText (const xmlChar *content); +XMLPUBFUN xmlNodePtr XMLCALL + xmlNewDocPI (xmlDocPtr doc, + const xmlChar *name, + const xmlChar *content); +XMLPUBFUN xmlNodePtr XMLCALL + xmlNewPI (const xmlChar *name, + const xmlChar *content); +XMLPUBFUN xmlNodePtr XMLCALL + xmlNewDocTextLen (xmlDocPtr doc, + const xmlChar *content, + int len); +XMLPUBFUN xmlNodePtr XMLCALL + xmlNewTextLen (const xmlChar *content, + int len); +XMLPUBFUN xmlNodePtr XMLCALL + xmlNewDocComment (xmlDocPtr doc, + const xmlChar *content); +XMLPUBFUN xmlNodePtr XMLCALL + xmlNewComment (const xmlChar *content); +XMLPUBFUN xmlNodePtr XMLCALL + xmlNewCDataBlock (xmlDocPtr doc, + const xmlChar *content, + int len); +XMLPUBFUN xmlNodePtr XMLCALL + xmlNewCharRef (xmlDocPtr doc, + const xmlChar *name); +XMLPUBFUN xmlNodePtr XMLCALL + xmlNewReference (xmlDocPtr doc, + const xmlChar *name); +XMLPUBFUN xmlNodePtr XMLCALL + xmlCopyNode (const xmlNodePtr node, + int recursive); +XMLPUBFUN xmlNodePtr XMLCALL + xmlDocCopyNode (const xmlNodePtr node, + xmlDocPtr doc, + int recursive); +XMLPUBFUN xmlNodePtr XMLCALL + xmlDocCopyNodeList (xmlDocPtr doc, + const xmlNodePtr node); +XMLPUBFUN xmlNodePtr XMLCALL + xmlCopyNodeList (const xmlNodePtr node); +#ifdef LIBXML_TREE_ENABLED +XMLPUBFUN xmlNodePtr XMLCALL + xmlNewTextChild (xmlNodePtr parent, + xmlNsPtr ns, + const xmlChar *name, + const xmlChar *content); +XMLPUBFUN xmlNodePtr XMLCALL + xmlNewDocRawNode (xmlDocPtr doc, + xmlNsPtr ns, + const xmlChar *name, + const xmlChar *content); +XMLPUBFUN xmlNodePtr XMLCALL + xmlNewDocFragment (xmlDocPtr doc); +#endif /* LIBXML_TREE_ENABLED */ + +/* + * Navigating. + */ +XMLPUBFUN long XMLCALL + xmlGetLineNo (xmlNodePtr node); +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED) +XMLPUBFUN xmlChar * XMLCALL + xmlGetNodePath (xmlNodePtr node); +#endif /* defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED) */ +XMLPUBFUN xmlNodePtr XMLCALL + xmlDocGetRootElement (xmlDocPtr doc); +XMLPUBFUN xmlNodePtr XMLCALL + xmlGetLastChild (xmlNodePtr parent); +XMLPUBFUN int XMLCALL + xmlNodeIsText (xmlNodePtr node); +XMLPUBFUN int XMLCALL + xmlIsBlankNode (xmlNodePtr node); + +/* + * Changing the structure. + */ +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED) +XMLPUBFUN xmlNodePtr XMLCALL + xmlDocSetRootElement (xmlDocPtr doc, + xmlNodePtr root); +#endif /* defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED) */ +#ifdef LIBXML_TREE_ENABLED +XMLPUBFUN void XMLCALL + xmlNodeSetName (xmlNodePtr cur, + const xmlChar *name); +#endif /* LIBXML_TREE_ENABLED */ +XMLPUBFUN xmlNodePtr XMLCALL + xmlAddChild (xmlNodePtr parent, + xmlNodePtr cur); +XMLPUBFUN xmlNodePtr XMLCALL + xmlAddChildList (xmlNodePtr parent, + xmlNodePtr cur); +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED) +XMLPUBFUN xmlNodePtr XMLCALL + xmlReplaceNode (xmlNodePtr old, + xmlNodePtr cur); +#endif /* defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED) */ +#if defined(LIBXML_TREE_ENABLED) || \ + defined(LIBXML_SCHEMAS_ENABLED) +XMLPUBFUN xmlNodePtr XMLCALL + xmlAddPrevSibling (xmlNodePtr cur, + xmlNodePtr elem); +#endif /* LIBXML_TREE_ENABLED || LIBXML_SCHEMAS_ENABLED */ +XMLPUBFUN xmlNodePtr XMLCALL + xmlAddSibling (xmlNodePtr cur, + xmlNodePtr elem); +XMLPUBFUN xmlNodePtr XMLCALL + xmlAddNextSibling (xmlNodePtr cur, + xmlNodePtr elem); +XMLPUBFUN void XMLCALL + xmlUnlinkNode (xmlNodePtr cur); +XMLPUBFUN xmlNodePtr XMLCALL + xmlTextMerge (xmlNodePtr first, + xmlNodePtr second); +XMLPUBFUN int XMLCALL + xmlTextConcat (xmlNodePtr node, + const xmlChar *content, + int len); +XMLPUBFUN void XMLCALL + xmlFreeNodeList (xmlNodePtr cur); +XMLPUBFUN void XMLCALL + xmlFreeNode (xmlNodePtr cur); +XMLPUBFUN void XMLCALL + xmlSetTreeDoc (xmlNodePtr tree, + xmlDocPtr doc); +XMLPUBFUN void XMLCALL + xmlSetListDoc (xmlNodePtr list, + xmlDocPtr doc); +/* + * Namespaces. + */ +XMLPUBFUN xmlNsPtr XMLCALL + xmlSearchNs (xmlDocPtr doc, + xmlNodePtr node, + const xmlChar *nameSpace); +XMLPUBFUN xmlNsPtr XMLCALL + xmlSearchNsByHref (xmlDocPtr doc, + xmlNodePtr node, + const xmlChar *href); +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) +XMLPUBFUN xmlNsPtr * XMLCALL + xmlGetNsList (xmlDocPtr doc, + xmlNodePtr node); +#endif /* defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) */ + +XMLPUBFUN void XMLCALL + xmlSetNs (xmlNodePtr node, + xmlNsPtr ns); +XMLPUBFUN xmlNsPtr XMLCALL + xmlCopyNamespace (xmlNsPtr cur); +XMLPUBFUN xmlNsPtr XMLCALL + xmlCopyNamespaceList (xmlNsPtr cur); + +/* + * Changing the content. + */ +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) +XMLPUBFUN xmlAttrPtr XMLCALL + xmlSetProp (xmlNodePtr node, + const xmlChar *name, + const xmlChar *value); +XMLPUBFUN xmlAttrPtr XMLCALL + xmlSetNsProp (xmlNodePtr node, + xmlNsPtr ns, + const xmlChar *name, + const xmlChar *value); +#endif /* defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) */ +XMLPUBFUN xmlChar * XMLCALL + xmlGetNoNsProp (xmlNodePtr node, + const xmlChar *name); +XMLPUBFUN xmlChar * XMLCALL + xmlGetProp (xmlNodePtr node, + const xmlChar *name); +XMLPUBFUN xmlAttrPtr XMLCALL + xmlHasProp (xmlNodePtr node, + const xmlChar *name); +XMLPUBFUN xmlAttrPtr XMLCALL + xmlHasNsProp (xmlNodePtr node, + const xmlChar *name, + const xmlChar *nameSpace); +XMLPUBFUN xmlChar * XMLCALL + xmlGetNsProp (xmlNodePtr node, + const xmlChar *name, + const xmlChar *nameSpace); +XMLPUBFUN xmlNodePtr XMLCALL + xmlStringGetNodeList (xmlDocPtr doc, + const xmlChar *value); +XMLPUBFUN xmlNodePtr XMLCALL + xmlStringLenGetNodeList (xmlDocPtr doc, + const xmlChar *value, + int len); +XMLPUBFUN xmlChar * XMLCALL + xmlNodeListGetString (xmlDocPtr doc, + xmlNodePtr list, + int inLine); +#ifdef LIBXML_TREE_ENABLED +XMLPUBFUN xmlChar * XMLCALL + xmlNodeListGetRawString (xmlDocPtr doc, + xmlNodePtr list, + int inLine); +#endif /* LIBXML_TREE_ENABLED */ +XMLPUBFUN void XMLCALL + xmlNodeSetContent (xmlNodePtr cur, + const xmlChar *content); +#ifdef LIBXML_TREE_ENABLED +XMLPUBFUN void XMLCALL + xmlNodeSetContentLen (xmlNodePtr cur, + const xmlChar *content, + int len); +#endif /* LIBXML_TREE_ENABLED */ +XMLPUBFUN void XMLCALL + xmlNodeAddContent (xmlNodePtr cur, + const xmlChar *content); +XMLPUBFUN void XMLCALL + xmlNodeAddContentLen (xmlNodePtr cur, + const xmlChar *content, + int len); +XMLPUBFUN xmlChar * XMLCALL + xmlNodeGetContent (xmlNodePtr cur); +XMLPUBFUN int XMLCALL + xmlNodeBufGetContent (xmlBufferPtr buffer, + xmlNodePtr cur); +XMLPUBFUN xmlChar * XMLCALL + xmlNodeGetLang (xmlNodePtr cur); +XMLPUBFUN int XMLCALL + xmlNodeGetSpacePreserve (xmlNodePtr cur); +#ifdef LIBXML_TREE_ENABLED +XMLPUBFUN void XMLCALL + xmlNodeSetLang (xmlNodePtr cur, + const xmlChar *lang); +XMLPUBFUN void XMLCALL + xmlNodeSetSpacePreserve (xmlNodePtr cur, + int val); +#endif /* LIBXML_TREE_ENABLED */ +XMLPUBFUN xmlChar * XMLCALL + xmlNodeGetBase (xmlDocPtr doc, + xmlNodePtr cur); +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) +XMLPUBFUN void XMLCALL + xmlNodeSetBase (xmlNodePtr cur, + const xmlChar *uri); +#endif + +/* + * Removing content. + */ +XMLPUBFUN int XMLCALL + xmlRemoveProp (xmlAttrPtr cur); +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) +XMLPUBFUN int XMLCALL + xmlUnsetNsProp (xmlNodePtr node, + xmlNsPtr ns, + const xmlChar *name); +XMLPUBFUN int XMLCALL + xmlUnsetProp (xmlNodePtr node, + const xmlChar *name); +#endif /* defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) */ + +/* + * Internal, don't use. + */ +XMLPUBFUN void XMLCALL + xmlBufferWriteCHAR (xmlBufferPtr buf, + const xmlChar *string); +XMLPUBFUN void XMLCALL + xmlBufferWriteChar (xmlBufferPtr buf, + const char *string); +XMLPUBFUN void XMLCALL + xmlBufferWriteQuotedString(xmlBufferPtr buf, + const xmlChar *string); + +#ifdef LIBXML_OUTPUT_ENABLED +XMLPUBFUN void xmlAttrSerializeTxtContent(xmlBufferPtr buf, + xmlDocPtr doc, + xmlAttrPtr attr, + const xmlChar *string); +#endif /* LIBXML_OUTPUT_ENABLED */ + +#ifdef LIBXML_TREE_ENABLED +/* + * Namespace handling. + */ +XMLPUBFUN int XMLCALL + xmlReconciliateNs (xmlDocPtr doc, + xmlNodePtr tree); +#endif + +#ifdef LIBXML_OUTPUT_ENABLED +/* + * Saving. + */ +XMLPUBFUN void XMLCALL + xmlDocDumpFormatMemory (xmlDocPtr cur, + xmlChar **mem, + int *size, + int format); +XMLPUBFUN void XMLCALL + xmlDocDumpMemory (xmlDocPtr cur, + xmlChar **mem, + int *size); +XMLPUBFUN void XMLCALL + xmlDocDumpMemoryEnc (xmlDocPtr out_doc, + xmlChar **doc_txt_ptr, + int * doc_txt_len, + const char *txt_encoding); +XMLPUBFUN void XMLCALL + xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, + xmlChar **doc_txt_ptr, + int * doc_txt_len, + const char *txt_encoding, + int format); +XMLPUBFUN int XMLCALL + xmlDocFormatDump (FILE *f, + xmlDocPtr cur, + int format); +XMLPUBFUN int XMLCALL + xmlDocDump (FILE *f, + xmlDocPtr cur); +XMLPUBFUN void XMLCALL + xmlElemDump (FILE *f, + xmlDocPtr doc, + xmlNodePtr cur); +XMLPUBFUN int XMLCALL + xmlSaveFile (const char *filename, + xmlDocPtr cur); +XMLPUBFUN int XMLCALL + xmlSaveFormatFile (const char *filename, + xmlDocPtr cur, + int format); +XMLPUBFUN int XMLCALL + xmlNodeDump (xmlBufferPtr buf, + xmlDocPtr doc, + xmlNodePtr cur, + int level, + int format); + +XMLPUBFUN int XMLCALL + xmlSaveFileTo (xmlOutputBufferPtr buf, + xmlDocPtr cur, + const char *encoding); +XMLPUBFUN int XMLCALL + xmlSaveFormatFileTo (xmlOutputBufferPtr buf, + xmlDocPtr cur, + const char *encoding, + int format); +XMLPUBFUN void XMLCALL + xmlNodeDumpOutput (xmlOutputBufferPtr buf, + xmlDocPtr doc, + xmlNodePtr cur, + int level, + int format, + const char *encoding); + +XMLPUBFUN int XMLCALL + xmlSaveFormatFileEnc (const char *filename, + xmlDocPtr cur, + const char *encoding, + int format); + +XMLPUBFUN int XMLCALL + xmlSaveFileEnc (const char *filename, + xmlDocPtr cur, + const char *encoding); + +#endif /* LIBXML_OUTPUT_ENABLED */ +/* + * XHTML + */ +XMLPUBFUN int XMLCALL + xmlIsXHTML (const xmlChar *systemID, + const xmlChar *publicID); + +/* + * Compression. + */ +XMLPUBFUN int XMLCALL + xmlGetDocCompressMode (xmlDocPtr doc); +XMLPUBFUN void XMLCALL + xmlSetDocCompressMode (xmlDocPtr doc, + int mode); +XMLPUBFUN int XMLCALL + xmlGetCompressMode (void); +XMLPUBFUN void XMLCALL + xmlSetCompressMode (int mode); + +/* +* DOM-wrapper helper functions. +*/ +XMLPUBFUN xmlDOMWrapCtxtPtr XMLCALL + xmlDOMWrapNewCtxt (void); +XMLPUBFUN void XMLCALL + xmlDOMWrapFreeCtxt (xmlDOMWrapCtxtPtr ctxt); +XMLPUBFUN int XMLCALL + xmlDOMWrapReconcileNamespaces(xmlDOMWrapCtxtPtr ctxt, + xmlNodePtr elem, + int options); +XMLPUBFUN int XMLCALL + xmlDOMWrapAdoptNode (xmlDOMWrapCtxtPtr ctxt, + xmlDocPtr sourceDoc, + xmlNodePtr node, + xmlDocPtr destDoc, + xmlNodePtr destParent, + int options); +XMLPUBFUN int XMLCALL + xmlDOMWrapRemoveNode (xmlDOMWrapCtxtPtr ctxt, + xmlDocPtr doc, + xmlNodePtr node, + int options); +XMLPUBFUN int XMLCALL + xmlDOMWrapCloneNode (xmlDOMWrapCtxtPtr ctxt, + xmlDocPtr sourceDoc, + xmlNodePtr node, + xmlNodePtr *clonedNode, + xmlDocPtr destDoc, + xmlNodePtr destParent, + int deep, + int options); + +#ifdef LIBXML_TREE_ENABLED +/* + * 5 interfaces from DOM ElementTraversal, but different in entities + * traversal. + */ +XMLPUBFUN unsigned long XMLCALL + xmlChildElementCount (xmlNodePtr parent); +XMLPUBFUN xmlNodePtr XMLCALL + xmlNextElementSibling (xmlNodePtr node); +XMLPUBFUN xmlNodePtr XMLCALL + xmlFirstElementChild (xmlNodePtr parent); +XMLPUBFUN xmlNodePtr XMLCALL + xmlLastElementChild (xmlNodePtr parent); +XMLPUBFUN xmlNodePtr XMLCALL + xmlPreviousElementSibling (xmlNodePtr node); +#endif +#ifdef __cplusplus +} +#endif +#ifndef __XML_PARSER_H__ +#include +#endif + +#endif /* __XML_TREE_H__ */ + diff --git a/android/native/libxml2/libxml/uri.h b/android/native/libxml2/libxml/uri.h new file mode 100644 index 0000000000..db48262b13 --- /dev/null +++ b/android/native/libxml2/libxml/uri.h @@ -0,0 +1,94 @@ +/** + * Summary: library of generic URI related routines + * Description: library of generic URI related routines + * Implements RFC 2396 + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_URI_H__ +#define __XML_URI_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * xmlURI: + * + * A parsed URI reference. This is a struct containing the various fields + * as described in RFC 2396 but separated for further processing. + * + * Note: query is a deprecated field which is incorrectly unescaped. + * query_raw takes precedence over query if the former is set. + * See: http://mail.gnome.org/archives/xml/2007-April/thread.html#00127 + */ +typedef struct _xmlURI xmlURI; +typedef xmlURI *xmlURIPtr; +struct _xmlURI { + char *scheme; /* the URI scheme */ + char *opaque; /* opaque part */ + char *authority; /* the authority part */ + char *server; /* the server part */ + char *user; /* the user part */ + int port; /* the port number */ + char *path; /* the path string */ + char *query; /* the query string (deprecated - use with caution) */ + char *fragment; /* the fragment identifier */ + int cleanup; /* parsing potentially unclean URI */ + char *query_raw; /* the query string (as it appears in the URI) */ +}; + +/* + * This function is in tree.h: + * xmlChar * xmlNodeGetBase (xmlDocPtr doc, + * xmlNodePtr cur); + */ +XMLPUBFUN xmlURIPtr XMLCALL + xmlCreateURI (void); +XMLPUBFUN xmlChar * XMLCALL + xmlBuildURI (const xmlChar *URI, + const xmlChar *base); +XMLPUBFUN xmlChar * XMLCALL + xmlBuildRelativeURI (const xmlChar *URI, + const xmlChar *base); +XMLPUBFUN xmlURIPtr XMLCALL + xmlParseURI (const char *str); +XMLPUBFUN xmlURIPtr XMLCALL + xmlParseURIRaw (const char *str, + int raw); +XMLPUBFUN int XMLCALL + xmlParseURIReference (xmlURIPtr uri, + const char *str); +XMLPUBFUN xmlChar * XMLCALL + xmlSaveUri (xmlURIPtr uri); +XMLPUBFUN void XMLCALL + xmlPrintURI (FILE *stream, + xmlURIPtr uri); +XMLPUBFUN xmlChar * XMLCALL + xmlURIEscapeStr (const xmlChar *str, + const xmlChar *list); +XMLPUBFUN char * XMLCALL + xmlURIUnescapeString (const char *str, + int len, + char *target); +XMLPUBFUN int XMLCALL + xmlNormalizeURIPath (char *path); +XMLPUBFUN xmlChar * XMLCALL + xmlURIEscape (const xmlChar *str); +XMLPUBFUN void XMLCALL + xmlFreeURI (xmlURIPtr uri); +XMLPUBFUN xmlChar* XMLCALL + xmlCanonicPath (const xmlChar *path); +XMLPUBFUN xmlChar* XMLCALL + xmlPathToURI (const xmlChar *path); + +#ifdef __cplusplus +} +#endif +#endif /* __XML_URI_H__ */ diff --git a/android/native/libxml2/libxml/valid.h b/android/native/libxml2/libxml/valid.h new file mode 100644 index 0000000000..a2307f1212 --- /dev/null +++ b/android/native/libxml2/libxml/valid.h @@ -0,0 +1,458 @@ +/* + * Summary: The DTD validation + * Description: API for the DTD handling and the validity checking + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + + +#ifndef __XML_VALID_H__ +#define __XML_VALID_H__ + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Validation state added for non-determinist content model. + */ +typedef struct _xmlValidState xmlValidState; +typedef xmlValidState *xmlValidStatePtr; + +/** + * xmlValidityErrorFunc: + * @ctx: usually an xmlValidCtxtPtr to a validity error context, + * but comes from ctxt->userData (which normally contains such + * a pointer); ctxt->userData can be changed by the user. + * @msg: the string to format *printf like vararg + * @...: remaining arguments to the format + * + * Callback called when a validity error is found. This is a message + * oriented function similar to an *printf function. + */ +typedef void (XMLCDECL *xmlValidityErrorFunc) (void *ctx, + const char *msg, + ...) LIBXML_ATTR_FORMAT(2,3); + +/** + * xmlValidityWarningFunc: + * @ctx: usually an xmlValidCtxtPtr to a validity error context, + * but comes from ctxt->userData (which normally contains such + * a pointer); ctxt->userData can be changed by the user. + * @msg: the string to format *printf like vararg + * @...: remaining arguments to the format + * + * Callback called when a validity warning is found. This is a message + * oriented function similar to an *printf function. + */ +typedef void (XMLCDECL *xmlValidityWarningFunc) (void *ctx, + const char *msg, + ...) LIBXML_ATTR_FORMAT(2,3); + +#ifdef IN_LIBXML +/** + * XML_CTXT_FINISH_DTD_0: + * + * Special value for finishDtd field when embedded in an xmlParserCtxt + */ +#define XML_CTXT_FINISH_DTD_0 0xabcd1234 +/** + * XML_CTXT_FINISH_DTD_1: + * + * Special value for finishDtd field when embedded in an xmlParserCtxt + */ +#define XML_CTXT_FINISH_DTD_1 0xabcd1235 +#endif + +/* + * xmlValidCtxt: + * An xmlValidCtxt is used for error reporting when validating. + */ +typedef struct _xmlValidCtxt xmlValidCtxt; +typedef xmlValidCtxt *xmlValidCtxtPtr; +struct _xmlValidCtxt { + void *userData; /* user specific data block */ + xmlValidityErrorFunc error; /* the callback in case of errors */ + xmlValidityWarningFunc warning; /* the callback in case of warning */ + + /* Node analysis stack used when validating within entities */ + xmlNodePtr node; /* Current parsed Node */ + int nodeNr; /* Depth of the parsing stack */ + int nodeMax; /* Max depth of the parsing stack */ + xmlNodePtr *nodeTab; /* array of nodes */ + + unsigned int finishDtd; /* finished validating the Dtd ? */ + xmlDocPtr doc; /* the document */ + int valid; /* temporary validity check result */ + + /* state state used for non-determinist content validation */ + xmlValidState *vstate; /* current state */ + int vstateNr; /* Depth of the validation stack */ + int vstateMax; /* Max depth of the validation stack */ + xmlValidState *vstateTab; /* array of validation states */ + +#ifdef LIBXML_REGEXP_ENABLED + xmlAutomataPtr am; /* the automata */ + xmlAutomataStatePtr state; /* used to build the automata */ +#else + void *am; + void *state; +#endif +}; + +/* + * ALL notation declarations are stored in a table. + * There is one table per DTD. + */ + +typedef struct _xmlHashTable xmlNotationTable; +typedef xmlNotationTable *xmlNotationTablePtr; + +/* + * ALL element declarations are stored in a table. + * There is one table per DTD. + */ + +typedef struct _xmlHashTable xmlElementTable; +typedef xmlElementTable *xmlElementTablePtr; + +/* + * ALL attribute declarations are stored in a table. + * There is one table per DTD. + */ + +typedef struct _xmlHashTable xmlAttributeTable; +typedef xmlAttributeTable *xmlAttributeTablePtr; + +/* + * ALL IDs attributes are stored in a table. + * There is one table per document. + */ + +typedef struct _xmlHashTable xmlIDTable; +typedef xmlIDTable *xmlIDTablePtr; + +/* + * ALL Refs attributes are stored in a table. + * There is one table per document. + */ + +typedef struct _xmlHashTable xmlRefTable; +typedef xmlRefTable *xmlRefTablePtr; + +/* Notation */ +XMLPUBFUN xmlNotationPtr XMLCALL + xmlAddNotationDecl (xmlValidCtxtPtr ctxt, + xmlDtdPtr dtd, + const xmlChar *name, + const xmlChar *PublicID, + const xmlChar *SystemID); +#ifdef LIBXML_TREE_ENABLED +XMLPUBFUN xmlNotationTablePtr XMLCALL + xmlCopyNotationTable (xmlNotationTablePtr table); +#endif /* LIBXML_TREE_ENABLED */ +XMLPUBFUN void XMLCALL + xmlFreeNotationTable (xmlNotationTablePtr table); +#ifdef LIBXML_OUTPUT_ENABLED +XMLPUBFUN void XMLCALL + xmlDumpNotationDecl (xmlBufferPtr buf, + xmlNotationPtr nota); +XMLPUBFUN void XMLCALL + xmlDumpNotationTable (xmlBufferPtr buf, + xmlNotationTablePtr table); +#endif /* LIBXML_OUTPUT_ENABLED */ + +/* Element Content */ +/* the non Doc version are being deprecated */ +XMLPUBFUN xmlElementContentPtr XMLCALL + xmlNewElementContent (const xmlChar *name, + xmlElementContentType type); +XMLPUBFUN xmlElementContentPtr XMLCALL + xmlCopyElementContent (xmlElementContentPtr content); +XMLPUBFUN void XMLCALL + xmlFreeElementContent (xmlElementContentPtr cur); +/* the new versions with doc argument */ +XMLPUBFUN xmlElementContentPtr XMLCALL + xmlNewDocElementContent (xmlDocPtr doc, + const xmlChar *name, + xmlElementContentType type); +XMLPUBFUN xmlElementContentPtr XMLCALL + xmlCopyDocElementContent(xmlDocPtr doc, + xmlElementContentPtr content); +XMLPUBFUN void XMLCALL + xmlFreeDocElementContent(xmlDocPtr doc, + xmlElementContentPtr cur); +XMLPUBFUN void XMLCALL + xmlSnprintfElementContent(char *buf, + int size, + xmlElementContentPtr content, + int englob); +#ifdef LIBXML_OUTPUT_ENABLED +/* DEPRECATED */ +XMLPUBFUN void XMLCALL + xmlSprintfElementContent(char *buf, + xmlElementContentPtr content, + int englob); +#endif /* LIBXML_OUTPUT_ENABLED */ +/* DEPRECATED */ + +/* Element */ +XMLPUBFUN xmlElementPtr XMLCALL + xmlAddElementDecl (xmlValidCtxtPtr ctxt, + xmlDtdPtr dtd, + const xmlChar *name, + xmlElementTypeVal type, + xmlElementContentPtr content); +#ifdef LIBXML_TREE_ENABLED +XMLPUBFUN xmlElementTablePtr XMLCALL + xmlCopyElementTable (xmlElementTablePtr table); +#endif /* LIBXML_TREE_ENABLED */ +XMLPUBFUN void XMLCALL + xmlFreeElementTable (xmlElementTablePtr table); +#ifdef LIBXML_OUTPUT_ENABLED +XMLPUBFUN void XMLCALL + xmlDumpElementTable (xmlBufferPtr buf, + xmlElementTablePtr table); +XMLPUBFUN void XMLCALL + xmlDumpElementDecl (xmlBufferPtr buf, + xmlElementPtr elem); +#endif /* LIBXML_OUTPUT_ENABLED */ + +/* Enumeration */ +XMLPUBFUN xmlEnumerationPtr XMLCALL + xmlCreateEnumeration (const xmlChar *name); +XMLPUBFUN void XMLCALL + xmlFreeEnumeration (xmlEnumerationPtr cur); +#ifdef LIBXML_TREE_ENABLED +XMLPUBFUN xmlEnumerationPtr XMLCALL + xmlCopyEnumeration (xmlEnumerationPtr cur); +#endif /* LIBXML_TREE_ENABLED */ + +/* Attribute */ +XMLPUBFUN xmlAttributePtr XMLCALL + xmlAddAttributeDecl (xmlValidCtxtPtr ctxt, + xmlDtdPtr dtd, + const xmlChar *elem, + const xmlChar *name, + const xmlChar *ns, + xmlAttributeType type, + xmlAttributeDefault def, + const xmlChar *defaultValue, + xmlEnumerationPtr tree); +#ifdef LIBXML_TREE_ENABLED +XMLPUBFUN xmlAttributeTablePtr XMLCALL + xmlCopyAttributeTable (xmlAttributeTablePtr table); +#endif /* LIBXML_TREE_ENABLED */ +XMLPUBFUN void XMLCALL + xmlFreeAttributeTable (xmlAttributeTablePtr table); +#ifdef LIBXML_OUTPUT_ENABLED +XMLPUBFUN void XMLCALL + xmlDumpAttributeTable (xmlBufferPtr buf, + xmlAttributeTablePtr table); +XMLPUBFUN void XMLCALL + xmlDumpAttributeDecl (xmlBufferPtr buf, + xmlAttributePtr attr); +#endif /* LIBXML_OUTPUT_ENABLED */ + +/* IDs */ +XMLPUBFUN xmlIDPtr XMLCALL + xmlAddID (xmlValidCtxtPtr ctxt, + xmlDocPtr doc, + const xmlChar *value, + xmlAttrPtr attr); +XMLPUBFUN void XMLCALL + xmlFreeIDTable (xmlIDTablePtr table); +XMLPUBFUN xmlAttrPtr XMLCALL + xmlGetID (xmlDocPtr doc, + const xmlChar *ID); +XMLPUBFUN int XMLCALL + xmlIsID (xmlDocPtr doc, + xmlNodePtr elem, + xmlAttrPtr attr); +XMLPUBFUN int XMLCALL + xmlRemoveID (xmlDocPtr doc, + xmlAttrPtr attr); + +/* IDREFs */ +XMLPUBFUN xmlRefPtr XMLCALL + xmlAddRef (xmlValidCtxtPtr ctxt, + xmlDocPtr doc, + const xmlChar *value, + xmlAttrPtr attr); +XMLPUBFUN void XMLCALL + xmlFreeRefTable (xmlRefTablePtr table); +XMLPUBFUN int XMLCALL + xmlIsRef (xmlDocPtr doc, + xmlNodePtr elem, + xmlAttrPtr attr); +XMLPUBFUN int XMLCALL + xmlRemoveRef (xmlDocPtr doc, + xmlAttrPtr attr); +XMLPUBFUN xmlListPtr XMLCALL + xmlGetRefs (xmlDocPtr doc, + const xmlChar *ID); + +/** + * The public function calls related to validity checking. + */ +#ifdef LIBXML_VALID_ENABLED +/* Allocate/Release Validation Contexts */ +XMLPUBFUN xmlValidCtxtPtr XMLCALL + xmlNewValidCtxt(void); +XMLPUBFUN void XMLCALL + xmlFreeValidCtxt(xmlValidCtxtPtr); + +XMLPUBFUN int XMLCALL + xmlValidateRoot (xmlValidCtxtPtr ctxt, + xmlDocPtr doc); +XMLPUBFUN int XMLCALL + xmlValidateElementDecl (xmlValidCtxtPtr ctxt, + xmlDocPtr doc, + xmlElementPtr elem); +XMLPUBFUN xmlChar * XMLCALL + xmlValidNormalizeAttributeValue(xmlDocPtr doc, + xmlNodePtr elem, + const xmlChar *name, + const xmlChar *value); +XMLPUBFUN xmlChar * XMLCALL + xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, + xmlDocPtr doc, + xmlNodePtr elem, + const xmlChar *name, + const xmlChar *value); +XMLPUBFUN int XMLCALL + xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, + xmlDocPtr doc, + xmlAttributePtr attr); +XMLPUBFUN int XMLCALL + xmlValidateAttributeValue(xmlAttributeType type, + const xmlChar *value); +XMLPUBFUN int XMLCALL + xmlValidateNotationDecl (xmlValidCtxtPtr ctxt, + xmlDocPtr doc, + xmlNotationPtr nota); +XMLPUBFUN int XMLCALL + xmlValidateDtd (xmlValidCtxtPtr ctxt, + xmlDocPtr doc, + xmlDtdPtr dtd); +XMLPUBFUN int XMLCALL + xmlValidateDtdFinal (xmlValidCtxtPtr ctxt, + xmlDocPtr doc); +XMLPUBFUN int XMLCALL + xmlValidateDocument (xmlValidCtxtPtr ctxt, + xmlDocPtr doc); +XMLPUBFUN int XMLCALL + xmlValidateElement (xmlValidCtxtPtr ctxt, + xmlDocPtr doc, + xmlNodePtr elem); +XMLPUBFUN int XMLCALL + xmlValidateOneElement (xmlValidCtxtPtr ctxt, + xmlDocPtr doc, + xmlNodePtr elem); +XMLPUBFUN int XMLCALL + xmlValidateOneAttribute (xmlValidCtxtPtr ctxt, + xmlDocPtr doc, + xmlNodePtr elem, + xmlAttrPtr attr, + const xmlChar *value); +XMLPUBFUN int XMLCALL + xmlValidateOneNamespace (xmlValidCtxtPtr ctxt, + xmlDocPtr doc, + xmlNodePtr elem, + const xmlChar *prefix, + xmlNsPtr ns, + const xmlChar *value); +XMLPUBFUN int XMLCALL + xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, + xmlDocPtr doc); +#endif /* LIBXML_VALID_ENABLED */ + +#if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) +XMLPUBFUN int XMLCALL + xmlValidateNotationUse (xmlValidCtxtPtr ctxt, + xmlDocPtr doc, + const xmlChar *notationName); +#endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */ + +XMLPUBFUN int XMLCALL + xmlIsMixedElement (xmlDocPtr doc, + const xmlChar *name); +XMLPUBFUN xmlAttributePtr XMLCALL + xmlGetDtdAttrDesc (xmlDtdPtr dtd, + const xmlChar *elem, + const xmlChar *name); +XMLPUBFUN xmlAttributePtr XMLCALL + xmlGetDtdQAttrDesc (xmlDtdPtr dtd, + const xmlChar *elem, + const xmlChar *name, + const xmlChar *prefix); +XMLPUBFUN xmlNotationPtr XMLCALL + xmlGetDtdNotationDesc (xmlDtdPtr dtd, + const xmlChar *name); +XMLPUBFUN xmlElementPtr XMLCALL + xmlGetDtdQElementDesc (xmlDtdPtr dtd, + const xmlChar *name, + const xmlChar *prefix); +XMLPUBFUN xmlElementPtr XMLCALL + xmlGetDtdElementDesc (xmlDtdPtr dtd, + const xmlChar *name); + +#ifdef LIBXML_VALID_ENABLED + +XMLPUBFUN int XMLCALL + xmlValidGetPotentialChildren(xmlElementContent *ctree, + const xmlChar **names, + int *len, + int max); + +XMLPUBFUN int XMLCALL + xmlValidGetValidElements(xmlNode *prev, + xmlNode *next, + const xmlChar **names, + int max); +XMLPUBFUN int XMLCALL + xmlValidateNameValue (const xmlChar *value); +XMLPUBFUN int XMLCALL + xmlValidateNamesValue (const xmlChar *value); +XMLPUBFUN int XMLCALL + xmlValidateNmtokenValue (const xmlChar *value); +XMLPUBFUN int XMLCALL + xmlValidateNmtokensValue(const xmlChar *value); + +#ifdef LIBXML_REGEXP_ENABLED +/* + * Validation based on the regexp support + */ +XMLPUBFUN int XMLCALL + xmlValidBuildContentModel(xmlValidCtxtPtr ctxt, + xmlElementPtr elem); + +XMLPUBFUN int XMLCALL + xmlValidatePushElement (xmlValidCtxtPtr ctxt, + xmlDocPtr doc, + xmlNodePtr elem, + const xmlChar *qname); +XMLPUBFUN int XMLCALL + xmlValidatePushCData (xmlValidCtxtPtr ctxt, + const xmlChar *data, + int len); +XMLPUBFUN int XMLCALL + xmlValidatePopElement (xmlValidCtxtPtr ctxt, + xmlDocPtr doc, + xmlNodePtr elem, + const xmlChar *qname); +#endif /* LIBXML_REGEXP_ENABLED */ +#endif /* LIBXML_VALID_ENABLED */ +#ifdef __cplusplus +} +#endif +#endif /* __XML_VALID_H__ */ diff --git a/android/native/libxml2/libxml/xinclude.h b/android/native/libxml2/libxml/xinclude.h new file mode 100644 index 0000000000..863ab25ad9 --- /dev/null +++ b/android/native/libxml2/libxml/xinclude.h @@ -0,0 +1,129 @@ +/* + * Summary: implementation of XInclude + * Description: API to handle XInclude processing, + * implements the + * World Wide Web Consortium Last Call Working Draft 10 November 2003 + * http://www.w3.org/TR/2003/WD-xinclude-20031110 + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XINCLUDE_H__ +#define __XML_XINCLUDE_H__ + +#include +#include + +#ifdef LIBXML_XINCLUDE_ENABLED + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * XINCLUDE_NS: + * + * Macro defining the Xinclude namespace: http://www.w3.org/2003/XInclude + */ +#define XINCLUDE_NS (const xmlChar *) "http://www.w3.org/2003/XInclude" +/** + * XINCLUDE_OLD_NS: + * + * Macro defining the draft Xinclude namespace: http://www.w3.org/2001/XInclude + */ +#define XINCLUDE_OLD_NS (const xmlChar *) "http://www.w3.org/2001/XInclude" +/** + * XINCLUDE_NODE: + * + * Macro defining "include" + */ +#define XINCLUDE_NODE (const xmlChar *) "include" +/** + * XINCLUDE_FALLBACK: + * + * Macro defining "fallback" + */ +#define XINCLUDE_FALLBACK (const xmlChar *) "fallback" +/** + * XINCLUDE_HREF: + * + * Macro defining "href" + */ +#define XINCLUDE_HREF (const xmlChar *) "href" +/** + * XINCLUDE_PARSE: + * + * Macro defining "parse" + */ +#define XINCLUDE_PARSE (const xmlChar *) "parse" +/** + * XINCLUDE_PARSE_XML: + * + * Macro defining "xml" + */ +#define XINCLUDE_PARSE_XML (const xmlChar *) "xml" +/** + * XINCLUDE_PARSE_TEXT: + * + * Macro defining "text" + */ +#define XINCLUDE_PARSE_TEXT (const xmlChar *) "text" +/** + * XINCLUDE_PARSE_ENCODING: + * + * Macro defining "encoding" + */ +#define XINCLUDE_PARSE_ENCODING (const xmlChar *) "encoding" +/** + * XINCLUDE_PARSE_XPOINTER: + * + * Macro defining "xpointer" + */ +#define XINCLUDE_PARSE_XPOINTER (const xmlChar *) "xpointer" + +typedef struct _xmlXIncludeCtxt xmlXIncludeCtxt; +typedef xmlXIncludeCtxt *xmlXIncludeCtxtPtr; + +/* + * standalone processing + */ +XMLPUBFUN int XMLCALL + xmlXIncludeProcess (xmlDocPtr doc); +XMLPUBFUN int XMLCALL + xmlXIncludeProcessFlags (xmlDocPtr doc, + int flags); +XMLPUBFUN int XMLCALL + xmlXIncludeProcessFlagsData(xmlDocPtr doc, + int flags, + void *data); +XMLPUBFUN int XMLCALL + xmlXIncludeProcessTreeFlagsData(xmlNodePtr tree, + int flags, + void *data); +XMLPUBFUN int XMLCALL + xmlXIncludeProcessTree (xmlNodePtr tree); +XMLPUBFUN int XMLCALL + xmlXIncludeProcessTreeFlags(xmlNodePtr tree, + int flags); +/* + * contextual processing + */ +XMLPUBFUN xmlXIncludeCtxtPtr XMLCALL + xmlXIncludeNewContext (xmlDocPtr doc); +XMLPUBFUN int XMLCALL + xmlXIncludeSetFlags (xmlXIncludeCtxtPtr ctxt, + int flags); +XMLPUBFUN void XMLCALL + xmlXIncludeFreeContext (xmlXIncludeCtxtPtr ctxt); +XMLPUBFUN int XMLCALL + xmlXIncludeProcessNode (xmlXIncludeCtxtPtr ctxt, + xmlNodePtr tree); +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_XINCLUDE_ENABLED */ + +#endif /* __XML_XINCLUDE_H__ */ diff --git a/android/native/libxml2/libxml/xlink.h b/android/native/libxml2/libxml/xlink.h new file mode 100644 index 0000000000..083c7eda40 --- /dev/null +++ b/android/native/libxml2/libxml/xlink.h @@ -0,0 +1,189 @@ +/* + * Summary: unfinished XLink detection module + * Description: unfinished XLink detection module + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XLINK_H__ +#define __XML_XLINK_H__ + +#include +#include + +#ifdef LIBXML_XPTR_ENABLED + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Various defines for the various Link properties. + * + * NOTE: the link detection layer will try to resolve QName expansion + * of namespaces. If "foo" is the prefix for "http://foo.com/" + * then the link detection layer will expand role="foo:myrole" + * to "http://foo.com/:myrole". + * NOTE: the link detection layer will expand URI-Refences found on + * href attributes by using the base mechanism if found. + */ +typedef xmlChar *xlinkHRef; +typedef xmlChar *xlinkRole; +typedef xmlChar *xlinkTitle; + +typedef enum { + XLINK_TYPE_NONE = 0, + XLINK_TYPE_SIMPLE, + XLINK_TYPE_EXTENDED, + XLINK_TYPE_EXTENDED_SET +} xlinkType; + +typedef enum { + XLINK_SHOW_NONE = 0, + XLINK_SHOW_NEW, + XLINK_SHOW_EMBED, + XLINK_SHOW_REPLACE +} xlinkShow; + +typedef enum { + XLINK_ACTUATE_NONE = 0, + XLINK_ACTUATE_AUTO, + XLINK_ACTUATE_ONREQUEST +} xlinkActuate; + +/** + * xlinkNodeDetectFunc: + * @ctx: user data pointer + * @node: the node to check + * + * This is the prototype for the link detection routine. + * It calls the default link detection callbacks upon link detection. + */ +typedef void (*xlinkNodeDetectFunc) (void *ctx, xmlNodePtr node); + +/* + * The link detection module interact with the upper layers using + * a set of callback registered at parsing time. + */ + +/** + * xlinkSimpleLinkFunk: + * @ctx: user data pointer + * @node: the node carrying the link + * @href: the target of the link + * @role: the role string + * @title: the link title + * + * This is the prototype for a simple link detection callback. + */ +typedef void +(*xlinkSimpleLinkFunk) (void *ctx, + xmlNodePtr node, + const xlinkHRef href, + const xlinkRole role, + const xlinkTitle title); + +/** + * xlinkExtendedLinkFunk: + * @ctx: user data pointer + * @node: the node carrying the link + * @nbLocators: the number of locators detected on the link + * @hrefs: pointer to the array of locator hrefs + * @roles: pointer to the array of locator roles + * @nbArcs: the number of arcs detected on the link + * @from: pointer to the array of source roles found on the arcs + * @to: pointer to the array of target roles found on the arcs + * @show: array of values for the show attributes found on the arcs + * @actuate: array of values for the actuate attributes found on the arcs + * @nbTitles: the number of titles detected on the link + * @title: array of titles detected on the link + * @langs: array of xml:lang values for the titles + * + * This is the prototype for a extended link detection callback. + */ +typedef void +(*xlinkExtendedLinkFunk)(void *ctx, + xmlNodePtr node, + int nbLocators, + const xlinkHRef *hrefs, + const xlinkRole *roles, + int nbArcs, + const xlinkRole *from, + const xlinkRole *to, + xlinkShow *show, + xlinkActuate *actuate, + int nbTitles, + const xlinkTitle *titles, + const xmlChar **langs); + +/** + * xlinkExtendedLinkSetFunk: + * @ctx: user data pointer + * @node: the node carrying the link + * @nbLocators: the number of locators detected on the link + * @hrefs: pointer to the array of locator hrefs + * @roles: pointer to the array of locator roles + * @nbTitles: the number of titles detected on the link + * @title: array of titles detected on the link + * @langs: array of xml:lang values for the titles + * + * This is the prototype for a extended link set detection callback. + */ +typedef void +(*xlinkExtendedLinkSetFunk) (void *ctx, + xmlNodePtr node, + int nbLocators, + const xlinkHRef *hrefs, + const xlinkRole *roles, + int nbTitles, + const xlinkTitle *titles, + const xmlChar **langs); + +/** + * This is the structure containing a set of Links detection callbacks. + * + * There is no default xlink callbacks, if one want to get link + * recognition activated, those call backs must be provided before parsing. + */ +typedef struct _xlinkHandler xlinkHandler; +typedef xlinkHandler *xlinkHandlerPtr; +struct _xlinkHandler { + xlinkSimpleLinkFunk simple; + xlinkExtendedLinkFunk extended; + xlinkExtendedLinkSetFunk set; +}; + +/* + * The default detection routine, can be overridden, they call the default + * detection callbacks. + */ + +XMLPUBFUN xlinkNodeDetectFunc XMLCALL + xlinkGetDefaultDetect (void); +XMLPUBFUN void XMLCALL + xlinkSetDefaultDetect (xlinkNodeDetectFunc func); + +/* + * Routines to set/get the default handlers. + */ +XMLPUBFUN xlinkHandlerPtr XMLCALL + xlinkGetDefaultHandler (void); +XMLPUBFUN void XMLCALL + xlinkSetDefaultHandler (xlinkHandlerPtr handler); + +/* + * Link detection module itself. + */ +XMLPUBFUN xlinkType XMLCALL + xlinkIsLink (xmlDocPtr doc, + xmlNodePtr node); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_XPTR_ENABLED */ + +#endif /* __XML_XLINK_H__ */ diff --git a/android/native/libxml2/libxml/xmlIO.h b/android/native/libxml2/libxml/xmlIO.h new file mode 100644 index 0000000000..fa6dcf2ca9 --- /dev/null +++ b/android/native/libxml2/libxml/xmlIO.h @@ -0,0 +1,317 @@ +/* + * Summary: interface for the I/O interfaces used by the parser + * Description: interface for the I/O interfaces used by the parser + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_IO_H__ +#define __XML_IO_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Those are the functions and datatypes for the parser input + * I/O structures. + */ + +/** + * xmlInputMatchCallback: + * @filename: the filename or URI + * + * Callback used in the I/O Input API to detect if the current handler + * can provide input fonctionnalities for this resource. + * + * Returns 1 if yes and 0 if another Input module should be used + */ +typedef int (XMLCALL *xmlInputMatchCallback) (char const *filename); +/** + * xmlInputOpenCallback: + * @filename: the filename or URI + * + * Callback used in the I/O Input API to open the resource + * + * Returns an Input context or NULL in case or error + */ +typedef void * (XMLCALL *xmlInputOpenCallback) (char const *filename); +/** + * xmlInputReadCallback: + * @context: an Input context + * @buffer: the buffer to store data read + * @len: the length of the buffer in bytes + * + * Callback used in the I/O Input API to read the resource + * + * Returns the number of bytes read or -1 in case of error + */ +typedef int (XMLCALL *xmlInputReadCallback) (void * context, char * buffer, int len); +/** + * xmlInputCloseCallback: + * @context: an Input context + * + * Callback used in the I/O Input API to close the resource + * + * Returns 0 or -1 in case of error + */ +typedef int (XMLCALL *xmlInputCloseCallback) (void * context); + +#ifdef LIBXML_OUTPUT_ENABLED +/* + * Those are the functions and datatypes for the library output + * I/O structures. + */ + +/** + * xmlOutputMatchCallback: + * @filename: the filename or URI + * + * Callback used in the I/O Output API to detect if the current handler + * can provide output fonctionnalities for this resource. + * + * Returns 1 if yes and 0 if another Output module should be used + */ +typedef int (XMLCALL *xmlOutputMatchCallback) (char const *filename); +/** + * xmlOutputOpenCallback: + * @filename: the filename or URI + * + * Callback used in the I/O Output API to open the resource + * + * Returns an Output context or NULL in case or error + */ +typedef void * (XMLCALL *xmlOutputOpenCallback) (char const *filename); +/** + * xmlOutputWriteCallback: + * @context: an Output context + * @buffer: the buffer of data to write + * @len: the length of the buffer in bytes + * + * Callback used in the I/O Output API to write to the resource + * + * Returns the number of bytes written or -1 in case of error + */ +typedef int (XMLCALL *xmlOutputWriteCallback) (void * context, const char * buffer, + int len); +/** + * xmlOutputCloseCallback: + * @context: an Output context + * + * Callback used in the I/O Output API to close the resource + * + * Returns 0 or -1 in case of error + */ +typedef int (XMLCALL *xmlOutputCloseCallback) (void * context); +#endif /* LIBXML_OUTPUT_ENABLED */ + +#ifdef __cplusplus +} +#endif + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif +struct _xmlParserInputBuffer { + void* context; + xmlInputReadCallback readcallback; + xmlInputCloseCallback closecallback; + + xmlCharEncodingHandlerPtr encoder; /* I18N conversions to UTF-8 */ + + xmlBufferPtr buffer; /* Local buffer encoded in UTF-8 */ + xmlBufferPtr raw; /* if encoder != NULL buffer for raw input */ + int compressed; /* -1=unknown, 0=not compressed, 1=compressed */ + int error; + unsigned long rawconsumed;/* amount consumed from raw */ +}; + + +#ifdef LIBXML_OUTPUT_ENABLED +struct _xmlOutputBuffer { + void* context; + xmlOutputWriteCallback writecallback; + xmlOutputCloseCallback closecallback; + + xmlCharEncodingHandlerPtr encoder; /* I18N conversions to UTF-8 */ + + xmlBufferPtr buffer; /* Local buffer encoded in UTF-8 or ISOLatin */ + xmlBufferPtr conv; /* if encoder != NULL buffer for output */ + int written; /* total number of byte written */ + int error; +}; +#endif /* LIBXML_OUTPUT_ENABLED */ + +/* + * Interfaces for input + */ +XMLPUBFUN void XMLCALL + xmlCleanupInputCallbacks (void); + +XMLPUBFUN int XMLCALL + xmlPopInputCallbacks (void); + +XMLPUBFUN void XMLCALL + xmlRegisterDefaultInputCallbacks (void); +XMLPUBFUN xmlParserInputBufferPtr XMLCALL + xmlAllocParserInputBuffer (xmlCharEncoding enc); + +XMLPUBFUN xmlParserInputBufferPtr XMLCALL + xmlParserInputBufferCreateFilename (const char *URI, + xmlCharEncoding enc); +XMLPUBFUN xmlParserInputBufferPtr XMLCALL + xmlParserInputBufferCreateFile (FILE *file, + xmlCharEncoding enc); +XMLPUBFUN xmlParserInputBufferPtr XMLCALL + xmlParserInputBufferCreateFd (int fd, + xmlCharEncoding enc); +XMLPUBFUN xmlParserInputBufferPtr XMLCALL + xmlParserInputBufferCreateMem (const char *mem, int size, + xmlCharEncoding enc); +XMLPUBFUN xmlParserInputBufferPtr XMLCALL + xmlParserInputBufferCreateStatic (const char *mem, int size, + xmlCharEncoding enc); +XMLPUBFUN xmlParserInputBufferPtr XMLCALL + xmlParserInputBufferCreateIO (xmlInputReadCallback ioread, + xmlInputCloseCallback ioclose, + void *ioctx, + xmlCharEncoding enc); +XMLPUBFUN int XMLCALL + xmlParserInputBufferRead (xmlParserInputBufferPtr in, + int len); +XMLPUBFUN int XMLCALL + xmlParserInputBufferGrow (xmlParserInputBufferPtr in, + int len); +XMLPUBFUN int XMLCALL + xmlParserInputBufferPush (xmlParserInputBufferPtr in, + int len, + const char *buf); +XMLPUBFUN void XMLCALL + xmlFreeParserInputBuffer (xmlParserInputBufferPtr in); +XMLPUBFUN char * XMLCALL + xmlParserGetDirectory (const char *filename); + +XMLPUBFUN int XMLCALL + xmlRegisterInputCallbacks (xmlInputMatchCallback matchFunc, + xmlInputOpenCallback openFunc, + xmlInputReadCallback readFunc, + xmlInputCloseCallback closeFunc); + +xmlParserInputBufferPtr + __xmlParserInputBufferCreateFilename(const char *URI, + xmlCharEncoding enc); + +#ifdef LIBXML_OUTPUT_ENABLED +/* + * Interfaces for output + */ +XMLPUBFUN void XMLCALL + xmlCleanupOutputCallbacks (void); +XMLPUBFUN void XMLCALL + xmlRegisterDefaultOutputCallbacks(void); +XMLPUBFUN xmlOutputBufferPtr XMLCALL + xmlAllocOutputBuffer (xmlCharEncodingHandlerPtr encoder); + +XMLPUBFUN xmlOutputBufferPtr XMLCALL + xmlOutputBufferCreateFilename (const char *URI, + xmlCharEncodingHandlerPtr encoder, + int compression); + +XMLPUBFUN xmlOutputBufferPtr XMLCALL + xmlOutputBufferCreateFile (FILE *file, + xmlCharEncodingHandlerPtr encoder); + +XMLPUBFUN xmlOutputBufferPtr XMLCALL + xmlOutputBufferCreateBuffer (xmlBufferPtr buffer, + xmlCharEncodingHandlerPtr encoder); + +XMLPUBFUN xmlOutputBufferPtr XMLCALL + xmlOutputBufferCreateFd (int fd, + xmlCharEncodingHandlerPtr encoder); + +XMLPUBFUN xmlOutputBufferPtr XMLCALL + xmlOutputBufferCreateIO (xmlOutputWriteCallback iowrite, + xmlOutputCloseCallback ioclose, + void *ioctx, + xmlCharEncodingHandlerPtr encoder); + +XMLPUBFUN int XMLCALL + xmlOutputBufferWrite (xmlOutputBufferPtr out, + int len, + const char *buf); +XMLPUBFUN int XMLCALL + xmlOutputBufferWriteString (xmlOutputBufferPtr out, + const char *str); +XMLPUBFUN int XMLCALL + xmlOutputBufferWriteEscape (xmlOutputBufferPtr out, + const xmlChar *str, + xmlCharEncodingOutputFunc escaping); + +XMLPUBFUN int XMLCALL + xmlOutputBufferFlush (xmlOutputBufferPtr out); +XMLPUBFUN int XMLCALL + xmlOutputBufferClose (xmlOutputBufferPtr out); + +XMLPUBFUN int XMLCALL + xmlRegisterOutputCallbacks (xmlOutputMatchCallback matchFunc, + xmlOutputOpenCallback openFunc, + xmlOutputWriteCallback writeFunc, + xmlOutputCloseCallback closeFunc); + +xmlOutputBufferPtr + __xmlOutputBufferCreateFilename(const char *URI, + xmlCharEncodingHandlerPtr encoder, + int compression); + +#endif /* LIBXML_OUTPUT_ENABLED */ + +XMLPUBFUN xmlParserInputPtr XMLCALL + xmlCheckHTTPInput (xmlParserCtxtPtr ctxt, + xmlParserInputPtr ret); + +/* + * A predefined entity loader disabling network accesses + */ +XMLPUBFUN xmlParserInputPtr XMLCALL + xmlNoNetExternalEntityLoader (const char *URL, + const char *ID, + xmlParserCtxtPtr ctxt); + +/* + * xmlNormalizeWindowsPath is obsolete, don't use it. + * Check xmlCanonicPath in uri.h for a better alternative. + */ +XMLPUBFUN xmlChar * XMLCALL + xmlNormalizeWindowsPath (const xmlChar *path); + +XMLPUBFUN int XMLCALL + xmlCheckFilename (const char *path); +/** + * Default 'file://' protocol callbacks + */ +XMLPUBFUN int XMLCALL + xmlFileMatch (const char *filename); +XMLPUBFUN void * XMLCALL + xmlFileOpen (const char *filename); +XMLPUBFUN int XMLCALL + xmlFileRead (void * context, + char * buffer, + int len); +XMLPUBFUN int XMLCALL + xmlFileClose (void * context); + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_IO_H__ */ diff --git a/android/native/libxml2/libxml/xmlautomata.h b/android/native/libxml2/libxml/xmlautomata.h new file mode 100644 index 0000000000..f98b55e2b8 --- /dev/null +++ b/android/native/libxml2/libxml/xmlautomata.h @@ -0,0 +1,146 @@ +/* + * Summary: API to build regexp automata + * Description: the API to build regexp automata + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_AUTOMATA_H__ +#define __XML_AUTOMATA_H__ + +#include +#include + +#ifdef LIBXML_REGEXP_ENABLED +#ifdef LIBXML_AUTOMATA_ENABLED +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * xmlAutomataPtr: + * + * A libxml automata description, It can be compiled into a regexp + */ +typedef struct _xmlAutomata xmlAutomata; +typedef xmlAutomata *xmlAutomataPtr; + +/** + * xmlAutomataStatePtr: + * + * A state int the automata description, + */ +typedef struct _xmlAutomataState xmlAutomataState; +typedef xmlAutomataState *xmlAutomataStatePtr; + +/* + * Building API + */ +XMLPUBFUN xmlAutomataPtr XMLCALL + xmlNewAutomata (void); +XMLPUBFUN void XMLCALL + xmlFreeAutomata (xmlAutomataPtr am); + +XMLPUBFUN xmlAutomataStatePtr XMLCALL + xmlAutomataGetInitState (xmlAutomataPtr am); +XMLPUBFUN int XMLCALL + xmlAutomataSetFinalState (xmlAutomataPtr am, + xmlAutomataStatePtr state); +XMLPUBFUN xmlAutomataStatePtr XMLCALL + xmlAutomataNewState (xmlAutomataPtr am); +XMLPUBFUN xmlAutomataStatePtr XMLCALL + xmlAutomataNewTransition (xmlAutomataPtr am, + xmlAutomataStatePtr from, + xmlAutomataStatePtr to, + const xmlChar *token, + void *data); +XMLPUBFUN xmlAutomataStatePtr XMLCALL + xmlAutomataNewTransition2 (xmlAutomataPtr am, + xmlAutomataStatePtr from, + xmlAutomataStatePtr to, + const xmlChar *token, + const xmlChar *token2, + void *data); +XMLPUBFUN xmlAutomataStatePtr XMLCALL + xmlAutomataNewNegTrans (xmlAutomataPtr am, + xmlAutomataStatePtr from, + xmlAutomataStatePtr to, + const xmlChar *token, + const xmlChar *token2, + void *data); + +XMLPUBFUN xmlAutomataStatePtr XMLCALL + xmlAutomataNewCountTrans (xmlAutomataPtr am, + xmlAutomataStatePtr from, + xmlAutomataStatePtr to, + const xmlChar *token, + int min, + int max, + void *data); +XMLPUBFUN xmlAutomataStatePtr XMLCALL + xmlAutomataNewCountTrans2 (xmlAutomataPtr am, + xmlAutomataStatePtr from, + xmlAutomataStatePtr to, + const xmlChar *token, + const xmlChar *token2, + int min, + int max, + void *data); +XMLPUBFUN xmlAutomataStatePtr XMLCALL + xmlAutomataNewOnceTrans (xmlAutomataPtr am, + xmlAutomataStatePtr from, + xmlAutomataStatePtr to, + const xmlChar *token, + int min, + int max, + void *data); +XMLPUBFUN xmlAutomataStatePtr XMLCALL + xmlAutomataNewOnceTrans2 (xmlAutomataPtr am, + xmlAutomataStatePtr from, + xmlAutomataStatePtr to, + const xmlChar *token, + const xmlChar *token2, + int min, + int max, + void *data); +XMLPUBFUN xmlAutomataStatePtr XMLCALL + xmlAutomataNewAllTrans (xmlAutomataPtr am, + xmlAutomataStatePtr from, + xmlAutomataStatePtr to, + int lax); +XMLPUBFUN xmlAutomataStatePtr XMLCALL + xmlAutomataNewEpsilon (xmlAutomataPtr am, + xmlAutomataStatePtr from, + xmlAutomataStatePtr to); +XMLPUBFUN xmlAutomataStatePtr XMLCALL + xmlAutomataNewCountedTrans (xmlAutomataPtr am, + xmlAutomataStatePtr from, + xmlAutomataStatePtr to, + int counter); +XMLPUBFUN xmlAutomataStatePtr XMLCALL + xmlAutomataNewCounterTrans (xmlAutomataPtr am, + xmlAutomataStatePtr from, + xmlAutomataStatePtr to, + int counter); +XMLPUBFUN int XMLCALL + xmlAutomataNewCounter (xmlAutomataPtr am, + int min, + int max); + +XMLPUBFUN xmlRegexpPtr XMLCALL + xmlAutomataCompile (xmlAutomataPtr am); +XMLPUBFUN int XMLCALL + xmlAutomataIsDeterminist (xmlAutomataPtr am); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_AUTOMATA_ENABLED */ +#endif /* LIBXML_REGEXP_ENABLED */ + +#endif /* __XML_AUTOMATA_H__ */ diff --git a/android/native/libxml2/libxml/xmlerror.h b/android/native/libxml2/libxml/xmlerror.h new file mode 100644 index 0000000000..e924211235 --- /dev/null +++ b/android/native/libxml2/libxml/xmlerror.h @@ -0,0 +1,944 @@ +/* + * Summary: error handling + * Description: the API used to report errors + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#include + +#ifndef __XML_ERROR_H__ +#define __XML_ERROR_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * xmlErrorLevel: + * + * Indicates the level of an error + */ +typedef enum { + XML_ERR_NONE = 0, + XML_ERR_WARNING = 1, /* A simple warning */ + XML_ERR_ERROR = 2, /* A recoverable error */ + XML_ERR_FATAL = 3 /* A fatal error */ +} xmlErrorLevel; + +/** + * xmlErrorDomain: + * + * Indicates where an error may have come from + */ +typedef enum { + XML_FROM_NONE = 0, + XML_FROM_PARSER, /* The XML parser */ + XML_FROM_TREE, /* The tree module */ + XML_FROM_NAMESPACE, /* The XML Namespace module */ + XML_FROM_DTD, /* The XML DTD validation with parser context*/ + XML_FROM_HTML, /* The HTML parser */ + XML_FROM_MEMORY, /* The memory allocator */ + XML_FROM_OUTPUT, /* The serialization code */ + XML_FROM_IO, /* The Input/Output stack */ + XML_FROM_FTP, /* The FTP module */ + XML_FROM_HTTP, /* The HTTP module */ + XML_FROM_XINCLUDE, /* The XInclude processing */ + XML_FROM_XPATH, /* The XPath module */ + XML_FROM_XPOINTER, /* The XPointer module */ + XML_FROM_REGEXP, /* The regular expressions module */ + XML_FROM_DATATYPE, /* The W3C XML Schemas Datatype module */ + XML_FROM_SCHEMASP, /* The W3C XML Schemas parser module */ + XML_FROM_SCHEMASV, /* The W3C XML Schemas validation module */ + XML_FROM_RELAXNGP, /* The Relax-NG parser module */ + XML_FROM_RELAXNGV, /* The Relax-NG validator module */ + XML_FROM_CATALOG, /* The Catalog module */ + XML_FROM_C14N, /* The Canonicalization module */ + XML_FROM_XSLT, /* The XSLT engine from libxslt */ + XML_FROM_VALID, /* The XML DTD validation with valid context */ + XML_FROM_CHECK, /* The error checking module */ + XML_FROM_WRITER, /* The xmlwriter module */ + XML_FROM_MODULE, /* The dynamically loaded module module*/ + XML_FROM_I18N, /* The module handling character conversion */ + XML_FROM_SCHEMATRONV /* The Schematron validator module */ +} xmlErrorDomain; + +/** + * xmlError: + * + * An XML Error instance. + */ + +typedef struct _xmlError xmlError; +typedef xmlError *xmlErrorPtr; +struct _xmlError { + int domain; /* What part of the library raised this error */ + int code; /* The error code, e.g. an xmlParserError */ + char *message;/* human-readable informative error message */ + xmlErrorLevel level;/* how consequent is the error */ + char *file; /* the filename */ + int line; /* the line number if available */ + char *str1; /* extra string information */ + char *str2; /* extra string information */ + char *str3; /* extra string information */ + int int1; /* extra number information */ + int int2; /* column number of the error or 0 if N/A (todo: rename this field when we would break ABI) */ + void *ctxt; /* the parser context if available */ + void *node; /* the node in the tree */ +}; + +/** + * xmlParserError: + * + * This is an error that the XML (or HTML) parser can generate + */ +typedef enum { + XML_ERR_OK = 0, + XML_ERR_INTERNAL_ERROR, /* 1 */ + XML_ERR_NO_MEMORY, /* 2 */ + XML_ERR_DOCUMENT_START, /* 3 */ + XML_ERR_DOCUMENT_EMPTY, /* 4 */ + XML_ERR_DOCUMENT_END, /* 5 */ + XML_ERR_INVALID_HEX_CHARREF, /* 6 */ + XML_ERR_INVALID_DEC_CHARREF, /* 7 */ + XML_ERR_INVALID_CHARREF, /* 8 */ + XML_ERR_INVALID_CHAR, /* 9 */ + XML_ERR_CHARREF_AT_EOF, /* 10 */ + XML_ERR_CHARREF_IN_PROLOG, /* 11 */ + XML_ERR_CHARREF_IN_EPILOG, /* 12 */ + XML_ERR_CHARREF_IN_DTD, /* 13 */ + XML_ERR_ENTITYREF_AT_EOF, /* 14 */ + XML_ERR_ENTITYREF_IN_PROLOG, /* 15 */ + XML_ERR_ENTITYREF_IN_EPILOG, /* 16 */ + XML_ERR_ENTITYREF_IN_DTD, /* 17 */ + XML_ERR_PEREF_AT_EOF, /* 18 */ + XML_ERR_PEREF_IN_PROLOG, /* 19 */ + XML_ERR_PEREF_IN_EPILOG, /* 20 */ + XML_ERR_PEREF_IN_INT_SUBSET, /* 21 */ + XML_ERR_ENTITYREF_NO_NAME, /* 22 */ + XML_ERR_ENTITYREF_SEMICOL_MISSING, /* 23 */ + XML_ERR_PEREF_NO_NAME, /* 24 */ + XML_ERR_PEREF_SEMICOL_MISSING, /* 25 */ + XML_ERR_UNDECLARED_ENTITY, /* 26 */ + XML_WAR_UNDECLARED_ENTITY, /* 27 */ + XML_ERR_UNPARSED_ENTITY, /* 28 */ + XML_ERR_ENTITY_IS_EXTERNAL, /* 29 */ + XML_ERR_ENTITY_IS_PARAMETER, /* 30 */ + XML_ERR_UNKNOWN_ENCODING, /* 31 */ + XML_ERR_UNSUPPORTED_ENCODING, /* 32 */ + XML_ERR_STRING_NOT_STARTED, /* 33 */ + XML_ERR_STRING_NOT_CLOSED, /* 34 */ + XML_ERR_NS_DECL_ERROR, /* 35 */ + XML_ERR_ENTITY_NOT_STARTED, /* 36 */ + XML_ERR_ENTITY_NOT_FINISHED, /* 37 */ + XML_ERR_LT_IN_ATTRIBUTE, /* 38 */ + XML_ERR_ATTRIBUTE_NOT_STARTED, /* 39 */ + XML_ERR_ATTRIBUTE_NOT_FINISHED, /* 40 */ + XML_ERR_ATTRIBUTE_WITHOUT_VALUE, /* 41 */ + XML_ERR_ATTRIBUTE_REDEFINED, /* 42 */ + XML_ERR_LITERAL_NOT_STARTED, /* 43 */ + XML_ERR_LITERAL_NOT_FINISHED, /* 44 */ + XML_ERR_COMMENT_NOT_FINISHED, /* 45 */ + XML_ERR_PI_NOT_STARTED, /* 46 */ + XML_ERR_PI_NOT_FINISHED, /* 47 */ + XML_ERR_NOTATION_NOT_STARTED, /* 48 */ + XML_ERR_NOTATION_NOT_FINISHED, /* 49 */ + XML_ERR_ATTLIST_NOT_STARTED, /* 50 */ + XML_ERR_ATTLIST_NOT_FINISHED, /* 51 */ + XML_ERR_MIXED_NOT_STARTED, /* 52 */ + XML_ERR_MIXED_NOT_FINISHED, /* 53 */ + XML_ERR_ELEMCONTENT_NOT_STARTED, /* 54 */ + XML_ERR_ELEMCONTENT_NOT_FINISHED, /* 55 */ + XML_ERR_XMLDECL_NOT_STARTED, /* 56 */ + XML_ERR_XMLDECL_NOT_FINISHED, /* 57 */ + XML_ERR_CONDSEC_NOT_STARTED, /* 58 */ + XML_ERR_CONDSEC_NOT_FINISHED, /* 59 */ + XML_ERR_EXT_SUBSET_NOT_FINISHED, /* 60 */ + XML_ERR_DOCTYPE_NOT_FINISHED, /* 61 */ + XML_ERR_MISPLACED_CDATA_END, /* 62 */ + XML_ERR_CDATA_NOT_FINISHED, /* 63 */ + XML_ERR_RESERVED_XML_NAME, /* 64 */ + XML_ERR_SPACE_REQUIRED, /* 65 */ + XML_ERR_SEPARATOR_REQUIRED, /* 66 */ + XML_ERR_NMTOKEN_REQUIRED, /* 67 */ + XML_ERR_NAME_REQUIRED, /* 68 */ + XML_ERR_PCDATA_REQUIRED, /* 69 */ + XML_ERR_URI_REQUIRED, /* 70 */ + XML_ERR_PUBID_REQUIRED, /* 71 */ + XML_ERR_LT_REQUIRED, /* 72 */ + XML_ERR_GT_REQUIRED, /* 73 */ + XML_ERR_LTSLASH_REQUIRED, /* 74 */ + XML_ERR_EQUAL_REQUIRED, /* 75 */ + XML_ERR_TAG_NAME_MISMATCH, /* 76 */ + XML_ERR_TAG_NOT_FINISHED, /* 77 */ + XML_ERR_STANDALONE_VALUE, /* 78 */ + XML_ERR_ENCODING_NAME, /* 79 */ + XML_ERR_HYPHEN_IN_COMMENT, /* 80 */ + XML_ERR_INVALID_ENCODING, /* 81 */ + XML_ERR_EXT_ENTITY_STANDALONE, /* 82 */ + XML_ERR_CONDSEC_INVALID, /* 83 */ + XML_ERR_VALUE_REQUIRED, /* 84 */ + XML_ERR_NOT_WELL_BALANCED, /* 85 */ + XML_ERR_EXTRA_CONTENT, /* 86 */ + XML_ERR_ENTITY_CHAR_ERROR, /* 87 */ + XML_ERR_ENTITY_PE_INTERNAL, /* 88 */ + XML_ERR_ENTITY_LOOP, /* 89 */ + XML_ERR_ENTITY_BOUNDARY, /* 90 */ + XML_ERR_INVALID_URI, /* 91 */ + XML_ERR_URI_FRAGMENT, /* 92 */ + XML_WAR_CATALOG_PI, /* 93 */ + XML_ERR_NO_DTD, /* 94 */ + XML_ERR_CONDSEC_INVALID_KEYWORD, /* 95 */ + XML_ERR_VERSION_MISSING, /* 96 */ + XML_WAR_UNKNOWN_VERSION, /* 97 */ + XML_WAR_LANG_VALUE, /* 98 */ + XML_WAR_NS_URI, /* 99 */ + XML_WAR_NS_URI_RELATIVE, /* 100 */ + XML_ERR_MISSING_ENCODING, /* 101 */ + XML_WAR_SPACE_VALUE, /* 102 */ + XML_ERR_NOT_STANDALONE, /* 103 */ + XML_ERR_ENTITY_PROCESSING, /* 104 */ + XML_ERR_NOTATION_PROCESSING, /* 105 */ + XML_WAR_NS_COLUMN, /* 106 */ + XML_WAR_ENTITY_REDEFINED, /* 107 */ + XML_ERR_UNKNOWN_VERSION, /* 108 */ + XML_ERR_VERSION_MISMATCH, /* 109 */ + XML_NS_ERR_XML_NAMESPACE = 200, + XML_NS_ERR_UNDEFINED_NAMESPACE, /* 201 */ + XML_NS_ERR_QNAME, /* 202 */ + XML_NS_ERR_ATTRIBUTE_REDEFINED, /* 203 */ + XML_NS_ERR_EMPTY, /* 204 */ + XML_NS_ERR_COLON, /* 205 */ + XML_DTD_ATTRIBUTE_DEFAULT = 500, + XML_DTD_ATTRIBUTE_REDEFINED, /* 501 */ + XML_DTD_ATTRIBUTE_VALUE, /* 502 */ + XML_DTD_CONTENT_ERROR, /* 503 */ + XML_DTD_CONTENT_MODEL, /* 504 */ + XML_DTD_CONTENT_NOT_DETERMINIST, /* 505 */ + XML_DTD_DIFFERENT_PREFIX, /* 506 */ + XML_DTD_ELEM_DEFAULT_NAMESPACE, /* 507 */ + XML_DTD_ELEM_NAMESPACE, /* 508 */ + XML_DTD_ELEM_REDEFINED, /* 509 */ + XML_DTD_EMPTY_NOTATION, /* 510 */ + XML_DTD_ENTITY_TYPE, /* 511 */ + XML_DTD_ID_FIXED, /* 512 */ + XML_DTD_ID_REDEFINED, /* 513 */ + XML_DTD_ID_SUBSET, /* 514 */ + XML_DTD_INVALID_CHILD, /* 515 */ + XML_DTD_INVALID_DEFAULT, /* 516 */ + XML_DTD_LOAD_ERROR, /* 517 */ + XML_DTD_MISSING_ATTRIBUTE, /* 518 */ + XML_DTD_MIXED_CORRUPT, /* 519 */ + XML_DTD_MULTIPLE_ID, /* 520 */ + XML_DTD_NO_DOC, /* 521 */ + XML_DTD_NO_DTD, /* 522 */ + XML_DTD_NO_ELEM_NAME, /* 523 */ + XML_DTD_NO_PREFIX, /* 524 */ + XML_DTD_NO_ROOT, /* 525 */ + XML_DTD_NOTATION_REDEFINED, /* 526 */ + XML_DTD_NOTATION_VALUE, /* 527 */ + XML_DTD_NOT_EMPTY, /* 528 */ + XML_DTD_NOT_PCDATA, /* 529 */ + XML_DTD_NOT_STANDALONE, /* 530 */ + XML_DTD_ROOT_NAME, /* 531 */ + XML_DTD_STANDALONE_WHITE_SPACE, /* 532 */ + XML_DTD_UNKNOWN_ATTRIBUTE, /* 533 */ + XML_DTD_UNKNOWN_ELEM, /* 534 */ + XML_DTD_UNKNOWN_ENTITY, /* 535 */ + XML_DTD_UNKNOWN_ID, /* 536 */ + XML_DTD_UNKNOWN_NOTATION, /* 537 */ + XML_DTD_STANDALONE_DEFAULTED, /* 538 */ + XML_DTD_XMLID_VALUE, /* 539 */ + XML_DTD_XMLID_TYPE, /* 540 */ + XML_DTD_DUP_TOKEN, /* 541 */ + XML_HTML_STRUCURE_ERROR = 800, + XML_HTML_UNKNOWN_TAG, /* 801 */ + XML_RNGP_ANYNAME_ATTR_ANCESTOR = 1000, + XML_RNGP_ATTR_CONFLICT, /* 1001 */ + XML_RNGP_ATTRIBUTE_CHILDREN, /* 1002 */ + XML_RNGP_ATTRIBUTE_CONTENT, /* 1003 */ + XML_RNGP_ATTRIBUTE_EMPTY, /* 1004 */ + XML_RNGP_ATTRIBUTE_NOOP, /* 1005 */ + XML_RNGP_CHOICE_CONTENT, /* 1006 */ + XML_RNGP_CHOICE_EMPTY, /* 1007 */ + XML_RNGP_CREATE_FAILURE, /* 1008 */ + XML_RNGP_DATA_CONTENT, /* 1009 */ + XML_RNGP_DEF_CHOICE_AND_INTERLEAVE, /* 1010 */ + XML_RNGP_DEFINE_CREATE_FAILED, /* 1011 */ + XML_RNGP_DEFINE_EMPTY, /* 1012 */ + XML_RNGP_DEFINE_MISSING, /* 1013 */ + XML_RNGP_DEFINE_NAME_MISSING, /* 1014 */ + XML_RNGP_ELEM_CONTENT_EMPTY, /* 1015 */ + XML_RNGP_ELEM_CONTENT_ERROR, /* 1016 */ + XML_RNGP_ELEMENT_EMPTY, /* 1017 */ + XML_RNGP_ELEMENT_CONTENT, /* 1018 */ + XML_RNGP_ELEMENT_NAME, /* 1019 */ + XML_RNGP_ELEMENT_NO_CONTENT, /* 1020 */ + XML_RNGP_ELEM_TEXT_CONFLICT, /* 1021 */ + XML_RNGP_EMPTY, /* 1022 */ + XML_RNGP_EMPTY_CONSTRUCT, /* 1023 */ + XML_RNGP_EMPTY_CONTENT, /* 1024 */ + XML_RNGP_EMPTY_NOT_EMPTY, /* 1025 */ + XML_RNGP_ERROR_TYPE_LIB, /* 1026 */ + XML_RNGP_EXCEPT_EMPTY, /* 1027 */ + XML_RNGP_EXCEPT_MISSING, /* 1028 */ + XML_RNGP_EXCEPT_MULTIPLE, /* 1029 */ + XML_RNGP_EXCEPT_NO_CONTENT, /* 1030 */ + XML_RNGP_EXTERNALREF_EMTPY, /* 1031 */ + XML_RNGP_EXTERNAL_REF_FAILURE, /* 1032 */ + XML_RNGP_EXTERNALREF_RECURSE, /* 1033 */ + XML_RNGP_FORBIDDEN_ATTRIBUTE, /* 1034 */ + XML_RNGP_FOREIGN_ELEMENT, /* 1035 */ + XML_RNGP_GRAMMAR_CONTENT, /* 1036 */ + XML_RNGP_GRAMMAR_EMPTY, /* 1037 */ + XML_RNGP_GRAMMAR_MISSING, /* 1038 */ + XML_RNGP_GRAMMAR_NO_START, /* 1039 */ + XML_RNGP_GROUP_ATTR_CONFLICT, /* 1040 */ + XML_RNGP_HREF_ERROR, /* 1041 */ + XML_RNGP_INCLUDE_EMPTY, /* 1042 */ + XML_RNGP_INCLUDE_FAILURE, /* 1043 */ + XML_RNGP_INCLUDE_RECURSE, /* 1044 */ + XML_RNGP_INTERLEAVE_ADD, /* 1045 */ + XML_RNGP_INTERLEAVE_CREATE_FAILED, /* 1046 */ + XML_RNGP_INTERLEAVE_EMPTY, /* 1047 */ + XML_RNGP_INTERLEAVE_NO_CONTENT, /* 1048 */ + XML_RNGP_INVALID_DEFINE_NAME, /* 1049 */ + XML_RNGP_INVALID_URI, /* 1050 */ + XML_RNGP_INVALID_VALUE, /* 1051 */ + XML_RNGP_MISSING_HREF, /* 1052 */ + XML_RNGP_NAME_MISSING, /* 1053 */ + XML_RNGP_NEED_COMBINE, /* 1054 */ + XML_RNGP_NOTALLOWED_NOT_EMPTY, /* 1055 */ + XML_RNGP_NSNAME_ATTR_ANCESTOR, /* 1056 */ + XML_RNGP_NSNAME_NO_NS, /* 1057 */ + XML_RNGP_PARAM_FORBIDDEN, /* 1058 */ + XML_RNGP_PARAM_NAME_MISSING, /* 1059 */ + XML_RNGP_PARENTREF_CREATE_FAILED, /* 1060 */ + XML_RNGP_PARENTREF_NAME_INVALID, /* 1061 */ + XML_RNGP_PARENTREF_NO_NAME, /* 1062 */ + XML_RNGP_PARENTREF_NO_PARENT, /* 1063 */ + XML_RNGP_PARENTREF_NOT_EMPTY, /* 1064 */ + XML_RNGP_PARSE_ERROR, /* 1065 */ + XML_RNGP_PAT_ANYNAME_EXCEPT_ANYNAME, /* 1066 */ + XML_RNGP_PAT_ATTR_ATTR, /* 1067 */ + XML_RNGP_PAT_ATTR_ELEM, /* 1068 */ + XML_RNGP_PAT_DATA_EXCEPT_ATTR, /* 1069 */ + XML_RNGP_PAT_DATA_EXCEPT_ELEM, /* 1070 */ + XML_RNGP_PAT_DATA_EXCEPT_EMPTY, /* 1071 */ + XML_RNGP_PAT_DATA_EXCEPT_GROUP, /* 1072 */ + XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE, /* 1073 */ + XML_RNGP_PAT_DATA_EXCEPT_LIST, /* 1074 */ + XML_RNGP_PAT_DATA_EXCEPT_ONEMORE, /* 1075 */ + XML_RNGP_PAT_DATA_EXCEPT_REF, /* 1076 */ + XML_RNGP_PAT_DATA_EXCEPT_TEXT, /* 1077 */ + XML_RNGP_PAT_LIST_ATTR, /* 1078 */ + XML_RNGP_PAT_LIST_ELEM, /* 1079 */ + XML_RNGP_PAT_LIST_INTERLEAVE, /* 1080 */ + XML_RNGP_PAT_LIST_LIST, /* 1081 */ + XML_RNGP_PAT_LIST_REF, /* 1082 */ + XML_RNGP_PAT_LIST_TEXT, /* 1083 */ + XML_RNGP_PAT_NSNAME_EXCEPT_ANYNAME, /* 1084 */ + XML_RNGP_PAT_NSNAME_EXCEPT_NSNAME, /* 1085 */ + XML_RNGP_PAT_ONEMORE_GROUP_ATTR, /* 1086 */ + XML_RNGP_PAT_ONEMORE_INTERLEAVE_ATTR, /* 1087 */ + XML_RNGP_PAT_START_ATTR, /* 1088 */ + XML_RNGP_PAT_START_DATA, /* 1089 */ + XML_RNGP_PAT_START_EMPTY, /* 1090 */ + XML_RNGP_PAT_START_GROUP, /* 1091 */ + XML_RNGP_PAT_START_INTERLEAVE, /* 1092 */ + XML_RNGP_PAT_START_LIST, /* 1093 */ + XML_RNGP_PAT_START_ONEMORE, /* 1094 */ + XML_RNGP_PAT_START_TEXT, /* 1095 */ + XML_RNGP_PAT_START_VALUE, /* 1096 */ + XML_RNGP_PREFIX_UNDEFINED, /* 1097 */ + XML_RNGP_REF_CREATE_FAILED, /* 1098 */ + XML_RNGP_REF_CYCLE, /* 1099 */ + XML_RNGP_REF_NAME_INVALID, /* 1100 */ + XML_RNGP_REF_NO_DEF, /* 1101 */ + XML_RNGP_REF_NO_NAME, /* 1102 */ + XML_RNGP_REF_NOT_EMPTY, /* 1103 */ + XML_RNGP_START_CHOICE_AND_INTERLEAVE, /* 1104 */ + XML_RNGP_START_CONTENT, /* 1105 */ + XML_RNGP_START_EMPTY, /* 1106 */ + XML_RNGP_START_MISSING, /* 1107 */ + XML_RNGP_TEXT_EXPECTED, /* 1108 */ + XML_RNGP_TEXT_HAS_CHILD, /* 1109 */ + XML_RNGP_TYPE_MISSING, /* 1110 */ + XML_RNGP_TYPE_NOT_FOUND, /* 1111 */ + XML_RNGP_TYPE_VALUE, /* 1112 */ + XML_RNGP_UNKNOWN_ATTRIBUTE, /* 1113 */ + XML_RNGP_UNKNOWN_COMBINE, /* 1114 */ + XML_RNGP_UNKNOWN_CONSTRUCT, /* 1115 */ + XML_RNGP_UNKNOWN_TYPE_LIB, /* 1116 */ + XML_RNGP_URI_FRAGMENT, /* 1117 */ + XML_RNGP_URI_NOT_ABSOLUTE, /* 1118 */ + XML_RNGP_VALUE_EMPTY, /* 1119 */ + XML_RNGP_VALUE_NO_CONTENT, /* 1120 */ + XML_RNGP_XMLNS_NAME, /* 1121 */ + XML_RNGP_XML_NS, /* 1122 */ + XML_XPATH_EXPRESSION_OK = 1200, + XML_XPATH_NUMBER_ERROR, /* 1201 */ + XML_XPATH_UNFINISHED_LITERAL_ERROR, /* 1202 */ + XML_XPATH_START_LITERAL_ERROR, /* 1203 */ + XML_XPATH_VARIABLE_REF_ERROR, /* 1204 */ + XML_XPATH_UNDEF_VARIABLE_ERROR, /* 1205 */ + XML_XPATH_INVALID_PREDICATE_ERROR, /* 1206 */ + XML_XPATH_EXPR_ERROR, /* 1207 */ + XML_XPATH_UNCLOSED_ERROR, /* 1208 */ + XML_XPATH_UNKNOWN_FUNC_ERROR, /* 1209 */ + XML_XPATH_INVALID_OPERAND, /* 1210 */ + XML_XPATH_INVALID_TYPE, /* 1211 */ + XML_XPATH_INVALID_ARITY, /* 1212 */ + XML_XPATH_INVALID_CTXT_SIZE, /* 1213 */ + XML_XPATH_INVALID_CTXT_POSITION, /* 1214 */ + XML_XPATH_MEMORY_ERROR, /* 1215 */ + XML_XPTR_SYNTAX_ERROR, /* 1216 */ + XML_XPTR_RESOURCE_ERROR, /* 1217 */ + XML_XPTR_SUB_RESOURCE_ERROR, /* 1218 */ + XML_XPATH_UNDEF_PREFIX_ERROR, /* 1219 */ + XML_XPATH_ENCODING_ERROR, /* 1220 */ + XML_XPATH_INVALID_CHAR_ERROR, /* 1221 */ + XML_TREE_INVALID_HEX = 1300, + XML_TREE_INVALID_DEC, /* 1301 */ + XML_TREE_UNTERMINATED_ENTITY, /* 1302 */ + XML_TREE_NOT_UTF8, /* 1303 */ + XML_SAVE_NOT_UTF8 = 1400, + XML_SAVE_CHAR_INVALID, /* 1401 */ + XML_SAVE_NO_DOCTYPE, /* 1402 */ + XML_SAVE_UNKNOWN_ENCODING, /* 1403 */ + XML_REGEXP_COMPILE_ERROR = 1450, + XML_IO_UNKNOWN = 1500, + XML_IO_EACCES, /* 1501 */ + XML_IO_EAGAIN, /* 1502 */ + XML_IO_EBADF, /* 1503 */ + XML_IO_EBADMSG, /* 1504 */ + XML_IO_EBUSY, /* 1505 */ + XML_IO_ECANCELED, /* 1506 */ + XML_IO_ECHILD, /* 1507 */ + XML_IO_EDEADLK, /* 1508 */ + XML_IO_EDOM, /* 1509 */ + XML_IO_EEXIST, /* 1510 */ + XML_IO_EFAULT, /* 1511 */ + XML_IO_EFBIG, /* 1512 */ + XML_IO_EINPROGRESS, /* 1513 */ + XML_IO_EINTR, /* 1514 */ + XML_IO_EINVAL, /* 1515 */ + XML_IO_EIO, /* 1516 */ + XML_IO_EISDIR, /* 1517 */ + XML_IO_EMFILE, /* 1518 */ + XML_IO_EMLINK, /* 1519 */ + XML_IO_EMSGSIZE, /* 1520 */ + XML_IO_ENAMETOOLONG, /* 1521 */ + XML_IO_ENFILE, /* 1522 */ + XML_IO_ENODEV, /* 1523 */ + XML_IO_ENOENT, /* 1524 */ + XML_IO_ENOEXEC, /* 1525 */ + XML_IO_ENOLCK, /* 1526 */ + XML_IO_ENOMEM, /* 1527 */ + XML_IO_ENOSPC, /* 1528 */ + XML_IO_ENOSYS, /* 1529 */ + XML_IO_ENOTDIR, /* 1530 */ + XML_IO_ENOTEMPTY, /* 1531 */ + XML_IO_ENOTSUP, /* 1532 */ + XML_IO_ENOTTY, /* 1533 */ + XML_IO_ENXIO, /* 1534 */ + XML_IO_EPERM, /* 1535 */ + XML_IO_EPIPE, /* 1536 */ + XML_IO_ERANGE, /* 1537 */ + XML_IO_EROFS, /* 1538 */ + XML_IO_ESPIPE, /* 1539 */ + XML_IO_ESRCH, /* 1540 */ + XML_IO_ETIMEDOUT, /* 1541 */ + XML_IO_EXDEV, /* 1542 */ + XML_IO_NETWORK_ATTEMPT, /* 1543 */ + XML_IO_ENCODER, /* 1544 */ + XML_IO_FLUSH, /* 1545 */ + XML_IO_WRITE, /* 1546 */ + XML_IO_NO_INPUT, /* 1547 */ + XML_IO_BUFFER_FULL, /* 1548 */ + XML_IO_LOAD_ERROR, /* 1549 */ + XML_IO_ENOTSOCK, /* 1550 */ + XML_IO_EISCONN, /* 1551 */ + XML_IO_ECONNREFUSED, /* 1552 */ + XML_IO_ENETUNREACH, /* 1553 */ + XML_IO_EADDRINUSE, /* 1554 */ + XML_IO_EALREADY, /* 1555 */ + XML_IO_EAFNOSUPPORT, /* 1556 */ + XML_XINCLUDE_RECURSION=1600, + XML_XINCLUDE_PARSE_VALUE, /* 1601 */ + XML_XINCLUDE_ENTITY_DEF_MISMATCH, /* 1602 */ + XML_XINCLUDE_NO_HREF, /* 1603 */ + XML_XINCLUDE_NO_FALLBACK, /* 1604 */ + XML_XINCLUDE_HREF_URI, /* 1605 */ + XML_XINCLUDE_TEXT_FRAGMENT, /* 1606 */ + XML_XINCLUDE_TEXT_DOCUMENT, /* 1607 */ + XML_XINCLUDE_INVALID_CHAR, /* 1608 */ + XML_XINCLUDE_BUILD_FAILED, /* 1609 */ + XML_XINCLUDE_UNKNOWN_ENCODING, /* 1610 */ + XML_XINCLUDE_MULTIPLE_ROOT, /* 1611 */ + XML_XINCLUDE_XPTR_FAILED, /* 1612 */ + XML_XINCLUDE_XPTR_RESULT, /* 1613 */ + XML_XINCLUDE_INCLUDE_IN_INCLUDE, /* 1614 */ + XML_XINCLUDE_FALLBACKS_IN_INCLUDE, /* 1615 */ + XML_XINCLUDE_FALLBACK_NOT_IN_INCLUDE, /* 1616 */ + XML_XINCLUDE_DEPRECATED_NS, /* 1617 */ + XML_XINCLUDE_FRAGMENT_ID, /* 1618 */ + XML_CATALOG_MISSING_ATTR = 1650, + XML_CATALOG_ENTRY_BROKEN, /* 1651 */ + XML_CATALOG_PREFER_VALUE, /* 1652 */ + XML_CATALOG_NOT_CATALOG, /* 1653 */ + XML_CATALOG_RECURSION, /* 1654 */ + XML_SCHEMAP_PREFIX_UNDEFINED = 1700, + XML_SCHEMAP_ATTRFORMDEFAULT_VALUE, /* 1701 */ + XML_SCHEMAP_ATTRGRP_NONAME_NOREF, /* 1702 */ + XML_SCHEMAP_ATTR_NONAME_NOREF, /* 1703 */ + XML_SCHEMAP_COMPLEXTYPE_NONAME_NOREF, /* 1704 */ + XML_SCHEMAP_ELEMFORMDEFAULT_VALUE, /* 1705 */ + XML_SCHEMAP_ELEM_NONAME_NOREF, /* 1706 */ + XML_SCHEMAP_EXTENSION_NO_BASE, /* 1707 */ + XML_SCHEMAP_FACET_NO_VALUE, /* 1708 */ + XML_SCHEMAP_FAILED_BUILD_IMPORT, /* 1709 */ + XML_SCHEMAP_GROUP_NONAME_NOREF, /* 1710 */ + XML_SCHEMAP_IMPORT_NAMESPACE_NOT_URI, /* 1711 */ + XML_SCHEMAP_IMPORT_REDEFINE_NSNAME, /* 1712 */ + XML_SCHEMAP_IMPORT_SCHEMA_NOT_URI, /* 1713 */ + XML_SCHEMAP_INVALID_BOOLEAN, /* 1714 */ + XML_SCHEMAP_INVALID_ENUM, /* 1715 */ + XML_SCHEMAP_INVALID_FACET, /* 1716 */ + XML_SCHEMAP_INVALID_FACET_VALUE, /* 1717 */ + XML_SCHEMAP_INVALID_MAXOCCURS, /* 1718 */ + XML_SCHEMAP_INVALID_MINOCCURS, /* 1719 */ + XML_SCHEMAP_INVALID_REF_AND_SUBTYPE, /* 1720 */ + XML_SCHEMAP_INVALID_WHITE_SPACE, /* 1721 */ + XML_SCHEMAP_NOATTR_NOREF, /* 1722 */ + XML_SCHEMAP_NOTATION_NO_NAME, /* 1723 */ + XML_SCHEMAP_NOTYPE_NOREF, /* 1724 */ + XML_SCHEMAP_REF_AND_SUBTYPE, /* 1725 */ + XML_SCHEMAP_RESTRICTION_NONAME_NOREF, /* 1726 */ + XML_SCHEMAP_SIMPLETYPE_NONAME, /* 1727 */ + XML_SCHEMAP_TYPE_AND_SUBTYPE, /* 1728 */ + XML_SCHEMAP_UNKNOWN_ALL_CHILD, /* 1729 */ + XML_SCHEMAP_UNKNOWN_ANYATTRIBUTE_CHILD, /* 1730 */ + XML_SCHEMAP_UNKNOWN_ATTR_CHILD, /* 1731 */ + XML_SCHEMAP_UNKNOWN_ATTRGRP_CHILD, /* 1732 */ + XML_SCHEMAP_UNKNOWN_ATTRIBUTE_GROUP, /* 1733 */ + XML_SCHEMAP_UNKNOWN_BASE_TYPE, /* 1734 */ + XML_SCHEMAP_UNKNOWN_CHOICE_CHILD, /* 1735 */ + XML_SCHEMAP_UNKNOWN_COMPLEXCONTENT_CHILD, /* 1736 */ + XML_SCHEMAP_UNKNOWN_COMPLEXTYPE_CHILD, /* 1737 */ + XML_SCHEMAP_UNKNOWN_ELEM_CHILD, /* 1738 */ + XML_SCHEMAP_UNKNOWN_EXTENSION_CHILD, /* 1739 */ + XML_SCHEMAP_UNKNOWN_FACET_CHILD, /* 1740 */ + XML_SCHEMAP_UNKNOWN_FACET_TYPE, /* 1741 */ + XML_SCHEMAP_UNKNOWN_GROUP_CHILD, /* 1742 */ + XML_SCHEMAP_UNKNOWN_IMPORT_CHILD, /* 1743 */ + XML_SCHEMAP_UNKNOWN_LIST_CHILD, /* 1744 */ + XML_SCHEMAP_UNKNOWN_NOTATION_CHILD, /* 1745 */ + XML_SCHEMAP_UNKNOWN_PROCESSCONTENT_CHILD, /* 1746 */ + XML_SCHEMAP_UNKNOWN_REF, /* 1747 */ + XML_SCHEMAP_UNKNOWN_RESTRICTION_CHILD, /* 1748 */ + XML_SCHEMAP_UNKNOWN_SCHEMAS_CHILD, /* 1749 */ + XML_SCHEMAP_UNKNOWN_SEQUENCE_CHILD, /* 1750 */ + XML_SCHEMAP_UNKNOWN_SIMPLECONTENT_CHILD, /* 1751 */ + XML_SCHEMAP_UNKNOWN_SIMPLETYPE_CHILD, /* 1752 */ + XML_SCHEMAP_UNKNOWN_TYPE, /* 1753 */ + XML_SCHEMAP_UNKNOWN_UNION_CHILD, /* 1754 */ + XML_SCHEMAP_ELEM_DEFAULT_FIXED, /* 1755 */ + XML_SCHEMAP_REGEXP_INVALID, /* 1756 */ + XML_SCHEMAP_FAILED_LOAD, /* 1757 */ + XML_SCHEMAP_NOTHING_TO_PARSE, /* 1758 */ + XML_SCHEMAP_NOROOT, /* 1759 */ + XML_SCHEMAP_REDEFINED_GROUP, /* 1760 */ + XML_SCHEMAP_REDEFINED_TYPE, /* 1761 */ + XML_SCHEMAP_REDEFINED_ELEMENT, /* 1762 */ + XML_SCHEMAP_REDEFINED_ATTRGROUP, /* 1763 */ + XML_SCHEMAP_REDEFINED_ATTR, /* 1764 */ + XML_SCHEMAP_REDEFINED_NOTATION, /* 1765 */ + XML_SCHEMAP_FAILED_PARSE, /* 1766 */ + XML_SCHEMAP_UNKNOWN_PREFIX, /* 1767 */ + XML_SCHEMAP_DEF_AND_PREFIX, /* 1768 */ + XML_SCHEMAP_UNKNOWN_INCLUDE_CHILD, /* 1769 */ + XML_SCHEMAP_INCLUDE_SCHEMA_NOT_URI, /* 1770 */ + XML_SCHEMAP_INCLUDE_SCHEMA_NO_URI, /* 1771 */ + XML_SCHEMAP_NOT_SCHEMA, /* 1772 */ + XML_SCHEMAP_UNKNOWN_MEMBER_TYPE, /* 1773 */ + XML_SCHEMAP_INVALID_ATTR_USE, /* 1774 */ + XML_SCHEMAP_RECURSIVE, /* 1775 */ + XML_SCHEMAP_SUPERNUMEROUS_LIST_ITEM_TYPE, /* 1776 */ + XML_SCHEMAP_INVALID_ATTR_COMBINATION, /* 1777 */ + XML_SCHEMAP_INVALID_ATTR_INLINE_COMBINATION, /* 1778 */ + XML_SCHEMAP_MISSING_SIMPLETYPE_CHILD, /* 1779 */ + XML_SCHEMAP_INVALID_ATTR_NAME, /* 1780 */ + XML_SCHEMAP_REF_AND_CONTENT, /* 1781 */ + XML_SCHEMAP_CT_PROPS_CORRECT_1, /* 1782 */ + XML_SCHEMAP_CT_PROPS_CORRECT_2, /* 1783 */ + XML_SCHEMAP_CT_PROPS_CORRECT_3, /* 1784 */ + XML_SCHEMAP_CT_PROPS_CORRECT_4, /* 1785 */ + XML_SCHEMAP_CT_PROPS_CORRECT_5, /* 1786 */ + XML_SCHEMAP_DERIVATION_OK_RESTRICTION_1, /* 1787 */ + XML_SCHEMAP_DERIVATION_OK_RESTRICTION_2_1_1, /* 1788 */ + XML_SCHEMAP_DERIVATION_OK_RESTRICTION_2_1_2, /* 1789 */ + XML_SCHEMAP_DERIVATION_OK_RESTRICTION_2_2, /* 1790 */ + XML_SCHEMAP_DERIVATION_OK_RESTRICTION_3, /* 1791 */ + XML_SCHEMAP_WILDCARD_INVALID_NS_MEMBER, /* 1792 */ + XML_SCHEMAP_INTERSECTION_NOT_EXPRESSIBLE, /* 1793 */ + XML_SCHEMAP_UNION_NOT_EXPRESSIBLE, /* 1794 */ + XML_SCHEMAP_SRC_IMPORT_3_1, /* 1795 */ + XML_SCHEMAP_SRC_IMPORT_3_2, /* 1796 */ + XML_SCHEMAP_DERIVATION_OK_RESTRICTION_4_1, /* 1797 */ + XML_SCHEMAP_DERIVATION_OK_RESTRICTION_4_2, /* 1798 */ + XML_SCHEMAP_DERIVATION_OK_RESTRICTION_4_3, /* 1799 */ + XML_SCHEMAP_COS_CT_EXTENDS_1_3, /* 1800 */ + XML_SCHEMAV_NOROOT = 1801, + XML_SCHEMAV_UNDECLAREDELEM, /* 1802 */ + XML_SCHEMAV_NOTTOPLEVEL, /* 1803 */ + XML_SCHEMAV_MISSING, /* 1804 */ + XML_SCHEMAV_WRONGELEM, /* 1805 */ + XML_SCHEMAV_NOTYPE, /* 1806 */ + XML_SCHEMAV_NOROLLBACK, /* 1807 */ + XML_SCHEMAV_ISABSTRACT, /* 1808 */ + XML_SCHEMAV_NOTEMPTY, /* 1809 */ + XML_SCHEMAV_ELEMCONT, /* 1810 */ + XML_SCHEMAV_HAVEDEFAULT, /* 1811 */ + XML_SCHEMAV_NOTNILLABLE, /* 1812 */ + XML_SCHEMAV_EXTRACONTENT, /* 1813 */ + XML_SCHEMAV_INVALIDATTR, /* 1814 */ + XML_SCHEMAV_INVALIDELEM, /* 1815 */ + XML_SCHEMAV_NOTDETERMINIST, /* 1816 */ + XML_SCHEMAV_CONSTRUCT, /* 1817 */ + XML_SCHEMAV_INTERNAL, /* 1818 */ + XML_SCHEMAV_NOTSIMPLE, /* 1819 */ + XML_SCHEMAV_ATTRUNKNOWN, /* 1820 */ + XML_SCHEMAV_ATTRINVALID, /* 1821 */ + XML_SCHEMAV_VALUE, /* 1822 */ + XML_SCHEMAV_FACET, /* 1823 */ + XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_1, /* 1824 */ + XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_2, /* 1825 */ + XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_3, /* 1826 */ + XML_SCHEMAV_CVC_TYPE_3_1_1, /* 1827 */ + XML_SCHEMAV_CVC_TYPE_3_1_2, /* 1828 */ + XML_SCHEMAV_CVC_FACET_VALID, /* 1829 */ + XML_SCHEMAV_CVC_LENGTH_VALID, /* 1830 */ + XML_SCHEMAV_CVC_MINLENGTH_VALID, /* 1831 */ + XML_SCHEMAV_CVC_MAXLENGTH_VALID, /* 1832 */ + XML_SCHEMAV_CVC_MININCLUSIVE_VALID, /* 1833 */ + XML_SCHEMAV_CVC_MAXINCLUSIVE_VALID, /* 1834 */ + XML_SCHEMAV_CVC_MINEXCLUSIVE_VALID, /* 1835 */ + XML_SCHEMAV_CVC_MAXEXCLUSIVE_VALID, /* 1836 */ + XML_SCHEMAV_CVC_TOTALDIGITS_VALID, /* 1837 */ + XML_SCHEMAV_CVC_FRACTIONDIGITS_VALID, /* 1838 */ + XML_SCHEMAV_CVC_PATTERN_VALID, /* 1839 */ + XML_SCHEMAV_CVC_ENUMERATION_VALID, /* 1840 */ + XML_SCHEMAV_CVC_COMPLEX_TYPE_2_1, /* 1841 */ + XML_SCHEMAV_CVC_COMPLEX_TYPE_2_2, /* 1842 */ + XML_SCHEMAV_CVC_COMPLEX_TYPE_2_3, /* 1843 */ + XML_SCHEMAV_CVC_COMPLEX_TYPE_2_4, /* 1844 */ + XML_SCHEMAV_CVC_ELT_1, /* 1845 */ + XML_SCHEMAV_CVC_ELT_2, /* 1846 */ + XML_SCHEMAV_CVC_ELT_3_1, /* 1847 */ + XML_SCHEMAV_CVC_ELT_3_2_1, /* 1848 */ + XML_SCHEMAV_CVC_ELT_3_2_2, /* 1849 */ + XML_SCHEMAV_CVC_ELT_4_1, /* 1850 */ + XML_SCHEMAV_CVC_ELT_4_2, /* 1851 */ + XML_SCHEMAV_CVC_ELT_4_3, /* 1852 */ + XML_SCHEMAV_CVC_ELT_5_1_1, /* 1853 */ + XML_SCHEMAV_CVC_ELT_5_1_2, /* 1854 */ + XML_SCHEMAV_CVC_ELT_5_2_1, /* 1855 */ + XML_SCHEMAV_CVC_ELT_5_2_2_1, /* 1856 */ + XML_SCHEMAV_CVC_ELT_5_2_2_2_1, /* 1857 */ + XML_SCHEMAV_CVC_ELT_5_2_2_2_2, /* 1858 */ + XML_SCHEMAV_CVC_ELT_6, /* 1859 */ + XML_SCHEMAV_CVC_ELT_7, /* 1860 */ + XML_SCHEMAV_CVC_ATTRIBUTE_1, /* 1861 */ + XML_SCHEMAV_CVC_ATTRIBUTE_2, /* 1862 */ + XML_SCHEMAV_CVC_ATTRIBUTE_3, /* 1863 */ + XML_SCHEMAV_CVC_ATTRIBUTE_4, /* 1864 */ + XML_SCHEMAV_CVC_COMPLEX_TYPE_3_1, /* 1865 */ + XML_SCHEMAV_CVC_COMPLEX_TYPE_3_2_1, /* 1866 */ + XML_SCHEMAV_CVC_COMPLEX_TYPE_3_2_2, /* 1867 */ + XML_SCHEMAV_CVC_COMPLEX_TYPE_4, /* 1868 */ + XML_SCHEMAV_CVC_COMPLEX_TYPE_5_1, /* 1869 */ + XML_SCHEMAV_CVC_COMPLEX_TYPE_5_2, /* 1870 */ + XML_SCHEMAV_ELEMENT_CONTENT, /* 1871 */ + XML_SCHEMAV_DOCUMENT_ELEMENT_MISSING, /* 1872 */ + XML_SCHEMAV_CVC_COMPLEX_TYPE_1, /* 1873 */ + XML_SCHEMAV_CVC_AU, /* 1874 */ + XML_SCHEMAV_CVC_TYPE_1, /* 1875 */ + XML_SCHEMAV_CVC_TYPE_2, /* 1876 */ + XML_SCHEMAV_CVC_IDC, /* 1877 */ + XML_SCHEMAV_CVC_WILDCARD, /* 1878 */ + XML_SCHEMAV_MISC, /* 1879 */ + XML_XPTR_UNKNOWN_SCHEME = 1900, + XML_XPTR_CHILDSEQ_START, /* 1901 */ + XML_XPTR_EVAL_FAILED, /* 1902 */ + XML_XPTR_EXTRA_OBJECTS, /* 1903 */ + XML_C14N_CREATE_CTXT = 1950, + XML_C14N_REQUIRES_UTF8, /* 1951 */ + XML_C14N_CREATE_STACK, /* 1952 */ + XML_C14N_INVALID_NODE, /* 1953 */ + XML_C14N_UNKNOW_NODE, /* 1954 */ + XML_C14N_RELATIVE_NAMESPACE, /* 1955 */ + XML_FTP_PASV_ANSWER = 2000, + XML_FTP_EPSV_ANSWER, /* 2001 */ + XML_FTP_ACCNT, /* 2002 */ + XML_FTP_URL_SYNTAX, /* 2003 */ + XML_HTTP_URL_SYNTAX = 2020, + XML_HTTP_USE_IP, /* 2021 */ + XML_HTTP_UNKNOWN_HOST, /* 2022 */ + XML_SCHEMAP_SRC_SIMPLE_TYPE_1 = 3000, + XML_SCHEMAP_SRC_SIMPLE_TYPE_2, /* 3001 */ + XML_SCHEMAP_SRC_SIMPLE_TYPE_3, /* 3002 */ + XML_SCHEMAP_SRC_SIMPLE_TYPE_4, /* 3003 */ + XML_SCHEMAP_SRC_RESOLVE, /* 3004 */ + XML_SCHEMAP_SRC_RESTRICTION_BASE_OR_SIMPLETYPE, /* 3005 */ + XML_SCHEMAP_SRC_LIST_ITEMTYPE_OR_SIMPLETYPE, /* 3006 */ + XML_SCHEMAP_SRC_UNION_MEMBERTYPES_OR_SIMPLETYPES, /* 3007 */ + XML_SCHEMAP_ST_PROPS_CORRECT_1, /* 3008 */ + XML_SCHEMAP_ST_PROPS_CORRECT_2, /* 3009 */ + XML_SCHEMAP_ST_PROPS_CORRECT_3, /* 3010 */ + XML_SCHEMAP_COS_ST_RESTRICTS_1_1, /* 3011 */ + XML_SCHEMAP_COS_ST_RESTRICTS_1_2, /* 3012 */ + XML_SCHEMAP_COS_ST_RESTRICTS_1_3_1, /* 3013 */ + XML_SCHEMAP_COS_ST_RESTRICTS_1_3_2, /* 3014 */ + XML_SCHEMAP_COS_ST_RESTRICTS_2_1, /* 3015 */ + XML_SCHEMAP_COS_ST_RESTRICTS_2_3_1_1, /* 3016 */ + XML_SCHEMAP_COS_ST_RESTRICTS_2_3_1_2, /* 3017 */ + XML_SCHEMAP_COS_ST_RESTRICTS_2_3_2_1, /* 3018 */ + XML_SCHEMAP_COS_ST_RESTRICTS_2_3_2_2, /* 3019 */ + XML_SCHEMAP_COS_ST_RESTRICTS_2_3_2_3, /* 3020 */ + XML_SCHEMAP_COS_ST_RESTRICTS_2_3_2_4, /* 3021 */ + XML_SCHEMAP_COS_ST_RESTRICTS_2_3_2_5, /* 3022 */ + XML_SCHEMAP_COS_ST_RESTRICTS_3_1, /* 3023 */ + XML_SCHEMAP_COS_ST_RESTRICTS_3_3_1, /* 3024 */ + XML_SCHEMAP_COS_ST_RESTRICTS_3_3_1_2, /* 3025 */ + XML_SCHEMAP_COS_ST_RESTRICTS_3_3_2_2, /* 3026 */ + XML_SCHEMAP_COS_ST_RESTRICTS_3_3_2_1, /* 3027 */ + XML_SCHEMAP_COS_ST_RESTRICTS_3_3_2_3, /* 3028 */ + XML_SCHEMAP_COS_ST_RESTRICTS_3_3_2_4, /* 3029 */ + XML_SCHEMAP_COS_ST_RESTRICTS_3_3_2_5, /* 3030 */ + XML_SCHEMAP_COS_ST_DERIVED_OK_2_1, /* 3031 */ + XML_SCHEMAP_COS_ST_DERIVED_OK_2_2, /* 3032 */ + XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED, /* 3033 */ + XML_SCHEMAP_S4S_ELEM_MISSING, /* 3034 */ + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, /* 3035 */ + XML_SCHEMAP_S4S_ATTR_MISSING, /* 3036 */ + XML_SCHEMAP_S4S_ATTR_INVALID_VALUE, /* 3037 */ + XML_SCHEMAP_SRC_ELEMENT_1, /* 3038 */ + XML_SCHEMAP_SRC_ELEMENT_2_1, /* 3039 */ + XML_SCHEMAP_SRC_ELEMENT_2_2, /* 3040 */ + XML_SCHEMAP_SRC_ELEMENT_3, /* 3041 */ + XML_SCHEMAP_P_PROPS_CORRECT_1, /* 3042 */ + XML_SCHEMAP_P_PROPS_CORRECT_2_1, /* 3043 */ + XML_SCHEMAP_P_PROPS_CORRECT_2_2, /* 3044 */ + XML_SCHEMAP_E_PROPS_CORRECT_2, /* 3045 */ + XML_SCHEMAP_E_PROPS_CORRECT_3, /* 3046 */ + XML_SCHEMAP_E_PROPS_CORRECT_4, /* 3047 */ + XML_SCHEMAP_E_PROPS_CORRECT_5, /* 3048 */ + XML_SCHEMAP_E_PROPS_CORRECT_6, /* 3049 */ + XML_SCHEMAP_SRC_INCLUDE, /* 3050 */ + XML_SCHEMAP_SRC_ATTRIBUTE_1, /* 3051 */ + XML_SCHEMAP_SRC_ATTRIBUTE_2, /* 3052 */ + XML_SCHEMAP_SRC_ATTRIBUTE_3_1, /* 3053 */ + XML_SCHEMAP_SRC_ATTRIBUTE_3_2, /* 3054 */ + XML_SCHEMAP_SRC_ATTRIBUTE_4, /* 3055 */ + XML_SCHEMAP_NO_XMLNS, /* 3056 */ + XML_SCHEMAP_NO_XSI, /* 3057 */ + XML_SCHEMAP_COS_VALID_DEFAULT_1, /* 3058 */ + XML_SCHEMAP_COS_VALID_DEFAULT_2_1, /* 3059 */ + XML_SCHEMAP_COS_VALID_DEFAULT_2_2_1, /* 3060 */ + XML_SCHEMAP_COS_VALID_DEFAULT_2_2_2, /* 3061 */ + XML_SCHEMAP_CVC_SIMPLE_TYPE, /* 3062 */ + XML_SCHEMAP_COS_CT_EXTENDS_1_1, /* 3063 */ + XML_SCHEMAP_SRC_IMPORT_1_1, /* 3064 */ + XML_SCHEMAP_SRC_IMPORT_1_2, /* 3065 */ + XML_SCHEMAP_SRC_IMPORT_2, /* 3066 */ + XML_SCHEMAP_SRC_IMPORT_2_1, /* 3067 */ + XML_SCHEMAP_SRC_IMPORT_2_2, /* 3068 */ + XML_SCHEMAP_INTERNAL, /* 3069 non-W3C */ + XML_SCHEMAP_NOT_DETERMINISTIC, /* 3070 non-W3C */ + XML_SCHEMAP_SRC_ATTRIBUTE_GROUP_1, /* 3071 */ + XML_SCHEMAP_SRC_ATTRIBUTE_GROUP_2, /* 3072 */ + XML_SCHEMAP_SRC_ATTRIBUTE_GROUP_3, /* 3073 */ + XML_SCHEMAP_MG_PROPS_CORRECT_1, /* 3074 */ + XML_SCHEMAP_MG_PROPS_CORRECT_2, /* 3075 */ + XML_SCHEMAP_SRC_CT_1, /* 3076 */ + XML_SCHEMAP_DERIVATION_OK_RESTRICTION_2_1_3, /* 3077 */ + XML_SCHEMAP_AU_PROPS_CORRECT_2, /* 3078 */ + XML_SCHEMAP_A_PROPS_CORRECT_2, /* 3079 */ + XML_SCHEMAP_C_PROPS_CORRECT, /* 3080 */ + XML_SCHEMAP_SRC_REDEFINE, /* 3081 */ + XML_SCHEMAP_SRC_IMPORT, /* 3082 */ + XML_SCHEMAP_WARN_SKIP_SCHEMA, /* 3083 */ + XML_SCHEMAP_WARN_UNLOCATED_SCHEMA, /* 3084 */ + XML_SCHEMAP_WARN_ATTR_REDECL_PROH, /* 3085 */ + XML_SCHEMAP_WARN_ATTR_POINTLESS_PROH, /* 3085 */ + XML_SCHEMAP_AG_PROPS_CORRECT, /* 3086 */ + XML_SCHEMAP_COS_CT_EXTENDS_1_2, /* 3087 */ + XML_SCHEMAP_AU_PROPS_CORRECT, /* 3088 */ + XML_SCHEMAP_A_PROPS_CORRECT_3, /* 3089 */ + XML_SCHEMAP_COS_ALL_LIMITED, /* 3090 */ + XML_SCHEMATRONV_ASSERT = 4000, /* 4000 */ + XML_SCHEMATRONV_REPORT, + XML_MODULE_OPEN = 4900, /* 4900 */ + XML_MODULE_CLOSE, /* 4901 */ + XML_CHECK_FOUND_ELEMENT = 5000, + XML_CHECK_FOUND_ATTRIBUTE, /* 5001 */ + XML_CHECK_FOUND_TEXT, /* 5002 */ + XML_CHECK_FOUND_CDATA, /* 5003 */ + XML_CHECK_FOUND_ENTITYREF, /* 5004 */ + XML_CHECK_FOUND_ENTITY, /* 5005 */ + XML_CHECK_FOUND_PI, /* 5006 */ + XML_CHECK_FOUND_COMMENT, /* 5007 */ + XML_CHECK_FOUND_DOCTYPE, /* 5008 */ + XML_CHECK_FOUND_FRAGMENT, /* 5009 */ + XML_CHECK_FOUND_NOTATION, /* 5010 */ + XML_CHECK_UNKNOWN_NODE, /* 5011 */ + XML_CHECK_ENTITY_TYPE, /* 5012 */ + XML_CHECK_NO_PARENT, /* 5013 */ + XML_CHECK_NO_DOC, /* 5014 */ + XML_CHECK_NO_NAME, /* 5015 */ + XML_CHECK_NO_ELEM, /* 5016 */ + XML_CHECK_WRONG_DOC, /* 5017 */ + XML_CHECK_NO_PREV, /* 5018 */ + XML_CHECK_WRONG_PREV, /* 5019 */ + XML_CHECK_NO_NEXT, /* 5020 */ + XML_CHECK_WRONG_NEXT, /* 5021 */ + XML_CHECK_NOT_DTD, /* 5022 */ + XML_CHECK_NOT_ATTR, /* 5023 */ + XML_CHECK_NOT_ATTR_DECL, /* 5024 */ + XML_CHECK_NOT_ELEM_DECL, /* 5025 */ + XML_CHECK_NOT_ENTITY_DECL, /* 5026 */ + XML_CHECK_NOT_NS_DECL, /* 5027 */ + XML_CHECK_NO_HREF, /* 5028 */ + XML_CHECK_WRONG_PARENT,/* 5029 */ + XML_CHECK_NS_SCOPE, /* 5030 */ + XML_CHECK_NS_ANCESTOR, /* 5031 */ + XML_CHECK_NOT_UTF8, /* 5032 */ + XML_CHECK_NO_DICT, /* 5033 */ + XML_CHECK_NOT_NCNAME, /* 5034 */ + XML_CHECK_OUTSIDE_DICT, /* 5035 */ + XML_CHECK_WRONG_NAME, /* 5036 */ + XML_CHECK_NAME_NOT_NULL, /* 5037 */ + XML_I18N_NO_NAME = 6000, + XML_I18N_NO_HANDLER, /* 6001 */ + XML_I18N_EXCESS_HANDLER, /* 6002 */ + XML_I18N_CONV_FAILED, /* 6003 */ + XML_I18N_NO_OUTPUT /* 6004 */ +#if 0 + XML_CHECK_, /* 5033 */ + XML_CHECK_X /* 503 */ +#endif +} xmlParserErrors; + +/** + * xmlGenericErrorFunc: + * @ctx: a parsing context + * @msg: the message + * @...: the extra arguments of the varags to format the message + * + * Signature of the function to use when there is an error and + * no parsing or validity context available . + */ +typedef void (XMLCDECL *xmlGenericErrorFunc) (void *ctx, + const char *msg, + ...) LIBXML_ATTR_FORMAT(2,3); +/** + * xmlStructuredErrorFunc: + * @userData: user provided data for the error callback + * @error: the error being raised. + * + * Signature of the function to use when there is an error and + * the module handles the new error reporting mechanism. + */ +typedef void (XMLCALL *xmlStructuredErrorFunc) (void *userData, xmlErrorPtr error); + +/* + * Use the following function to reset the two global variables + * xmlGenericError and xmlGenericErrorContext. + */ +XMLPUBFUN void XMLCALL + xmlSetGenericErrorFunc (void *ctx, + xmlGenericErrorFunc handler); +XMLPUBFUN void XMLCALL + initGenericErrorDefaultFunc (xmlGenericErrorFunc *handler); + +XMLPUBFUN void XMLCALL + xmlSetStructuredErrorFunc (void *ctx, + xmlStructuredErrorFunc handler); +/* + * Default message routines used by SAX and Valid context for error + * and warning reporting. + */ +XMLPUBFUN void XMLCDECL + xmlParserError (void *ctx, + const char *msg, + ...) LIBXML_ATTR_FORMAT(2,3); +XMLPUBFUN void XMLCDECL + xmlParserWarning (void *ctx, + const char *msg, + ...) LIBXML_ATTR_FORMAT(2,3); +XMLPUBFUN void XMLCDECL + xmlParserValidityError (void *ctx, + const char *msg, + ...) LIBXML_ATTR_FORMAT(2,3); +XMLPUBFUN void XMLCDECL + xmlParserValidityWarning (void *ctx, + const char *msg, + ...) LIBXML_ATTR_FORMAT(2,3); +XMLPUBFUN void XMLCALL + xmlParserPrintFileInfo (xmlParserInputPtr input); +XMLPUBFUN void XMLCALL + xmlParserPrintFileContext (xmlParserInputPtr input); + +/* + * Extended error information routines + */ +XMLPUBFUN xmlErrorPtr XMLCALL + xmlGetLastError (void); +XMLPUBFUN void XMLCALL + xmlResetLastError (void); +XMLPUBFUN xmlErrorPtr XMLCALL + xmlCtxtGetLastError (void *ctx); +XMLPUBFUN void XMLCALL + xmlCtxtResetLastError (void *ctx); +XMLPUBFUN void XMLCALL + xmlResetError (xmlErrorPtr err); +XMLPUBFUN int XMLCALL + xmlCopyError (xmlErrorPtr from, + xmlErrorPtr to); + +#ifdef IN_LIBXML +/* + * Internal callback reporting routine + */ +XMLPUBFUN void XMLCALL + __xmlRaiseError (xmlStructuredErrorFunc schannel, + xmlGenericErrorFunc channel, + void *data, + void *ctx, + void *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); +XMLPUBFUN void XMLCALL + __xmlSimpleError (int domain, + int code, + xmlNodePtr node, + const char *msg, + const char *extra); +#endif +#ifdef __cplusplus +} +#endif +#endif /* __XML_ERROR_H__ */ diff --git a/android/native/libxml2/libxml/xmlexports.h b/android/native/libxml2/libxml/xmlexports.h new file mode 100644 index 0000000000..9c6790c80f --- /dev/null +++ b/android/native/libxml2/libxml/xmlexports.h @@ -0,0 +1,162 @@ +/* + * Summary: macros for marking symbols as exportable/importable. + * Description: macros for marking symbols as exportable/importable. + * + * Copy: See Copyright for the status of this software. + * + * Author: Igor Zlatovic + */ + +#ifndef __XML_EXPORTS_H__ +#define __XML_EXPORTS_H__ + +/** + * XMLPUBFUN, XMLPUBVAR, XMLCALL + * + * Macros which declare an exportable function, an exportable variable and + * the calling convention used for functions. + * + * Please use an extra block for every platform/compiler combination when + * modifying this, rather than overlong #ifdef lines. This helps + * readability as well as the fact that different compilers on the same + * platform might need different definitions. + */ + +/** + * XMLPUBFUN: + * + * Macros which declare an exportable function + */ +#define XMLPUBFUN +/** + * XMLPUBVAR: + * + * Macros which declare an exportable variable + */ +#define XMLPUBVAR extern +/** + * XMLCALL: + * + * Macros which declare the called convention for exported functions + */ +#define XMLCALL +/** + * XMLCDECL: + * + * Macro which declares the calling convention for exported functions that + * use '...'. + */ +#define XMLCDECL + +/** DOC_DISABLE */ + +/* Windows platform with MS compiler */ +#if defined(_WIN32) && defined(_MSC_VER) + #undef XMLPUBFUN + #undef XMLPUBVAR + #undef XMLCALL + #undef XMLCDECL + #if defined(IN_LIBXML) && !defined(LIBXML_STATIC) + #define XMLPUBFUN __declspec(dllexport) + #define XMLPUBVAR __declspec(dllexport) + #else + #define XMLPUBFUN + #if !defined(LIBXML_STATIC) + #define XMLPUBVAR __declspec(dllimport) extern + #else + #define XMLPUBVAR extern + #endif + #endif + #if defined(LIBXML_FASTCALL) + #define XMLCALL __fastcall + #else + #define XMLCALL __cdecl + #endif + #define XMLCDECL __cdecl + #if !defined _REENTRANT + #define _REENTRANT + #endif +#endif + +/* Windows platform with Borland compiler */ +#if defined(_WIN32) && defined(__BORLANDC__) + #undef XMLPUBFUN + #undef XMLPUBVAR + #undef XMLCALL + #undef XMLCDECL + #if defined(IN_LIBXML) && !defined(LIBXML_STATIC) + #define XMLPUBFUN __declspec(dllexport) + #define XMLPUBVAR __declspec(dllexport) extern + #else + #define XMLPUBFUN + #if !defined(LIBXML_STATIC) + #define XMLPUBVAR __declspec(dllimport) extern + #else + #define XMLPUBVAR extern + #endif + #endif + #define XMLCALL __cdecl + #define XMLCDECL __cdecl + #if !defined _REENTRANT + #define _REENTRANT + #endif +#endif + +/* Windows platform with GNU compiler (Mingw) */ +#if defined(_WIN32) && defined(__MINGW32__) + #undef XMLPUBFUN + #undef XMLPUBVAR + #undef XMLCALL + #undef XMLCDECL + /* + * if defined(IN_LIBXML) this raises problems on mingw with msys + * _imp__xmlFree listed as missing. Try to workaround the problem + * by also making that declaration when compiling client code. + */ + #if defined(IN_LIBXML) && !defined(LIBXML_STATIC) + #define XMLPUBFUN __declspec(dllexport) + #define XMLPUBVAR __declspec(dllexport) + #else + #define XMLPUBFUN + #if !defined(LIBXML_STATIC) + #define XMLPUBVAR __declspec(dllimport) extern + #else + #define XMLPUBVAR extern + #endif + #endif + #define XMLCALL __cdecl + #define XMLCDECL __cdecl + #if !defined _REENTRANT + #define _REENTRANT + #endif +#endif + +/* Cygwin platform, GNU compiler */ +#if defined(_WIN32) && defined(__CYGWIN__) + #undef XMLPUBFUN + #undef XMLPUBVAR + #undef XMLCALL + #undef XMLCDECL + #if defined(IN_LIBXML) && !defined(LIBXML_STATIC) + #define XMLPUBFUN __declspec(dllexport) + #define XMLPUBVAR __declspec(dllexport) + #else + #define XMLPUBFUN + #if !defined(LIBXML_STATIC) + #define XMLPUBVAR __declspec(dllimport) extern + #else + #define XMLPUBVAR + #endif + #endif + #define XMLCALL __cdecl + #define XMLCDECL __cdecl +#endif + +/* Compatibility */ +#if !defined(LIBXML_DLL_IMPORT) +#define LIBXML_DLL_IMPORT XMLPUBVAR +#endif + +#endif /* __XML_EXPORTS_H__ */ + + diff --git a/android/native/libxml2/libxml/xmlmemory.h b/android/native/libxml2/libxml/xmlmemory.h new file mode 100644 index 0000000000..17e375a3c9 --- /dev/null +++ b/android/native/libxml2/libxml/xmlmemory.h @@ -0,0 +1,224 @@ +/* + * Summary: interface for the memory allocator + * Description: provides interfaces for the memory allocator, + * including debugging capabilities. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + + +#ifndef __DEBUG_MEMORY_ALLOC__ +#define __DEBUG_MEMORY_ALLOC__ + +#include +#include + +/** + * DEBUG_MEMORY: + * + * DEBUG_MEMORY replaces the allocator with a collect and debug + * shell to the libc allocator. + * DEBUG_MEMORY should only be activated when debugging + * libxml i.e. if libxml has been configured with --with-debug-mem too. + */ +/* #define DEBUG_MEMORY_FREED */ +/* #define DEBUG_MEMORY_LOCATION */ + +#ifdef DEBUG +#ifndef DEBUG_MEMORY +#define DEBUG_MEMORY +#endif +#endif + +/** + * DEBUG_MEMORY_LOCATION: + * + * DEBUG_MEMORY_LOCATION should be activated only when debugging + * libxml i.e. if libxml has been configured with --with-debug-mem too. + */ +#ifdef DEBUG_MEMORY_LOCATION +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * The XML memory wrapper support 4 basic overloadable functions. + */ +/** + * xmlFreeFunc: + * @mem: an already allocated block of memory + * + * Signature for a free() implementation. + */ +typedef void (XMLCALL *xmlFreeFunc)(void *mem); +/** + * xmlMallocFunc: + * @size: the size requested in bytes + * + * Signature for a malloc() implementation. + * + * Returns a pointer to the newly allocated block or NULL in case of error. + */ +typedef void *(LIBXML_ATTR_ALLOC_SIZE(1) XMLCALL *xmlMallocFunc)(size_t size); + +/** + * xmlReallocFunc: + * @mem: an already allocated block of memory + * @size: the new size requested in bytes + * + * Signature for a realloc() implementation. + * + * Returns a pointer to the newly reallocated block or NULL in case of error. + */ +typedef void *(XMLCALL *xmlReallocFunc)(void *mem, size_t size); + +/** + * xmlStrdupFunc: + * @str: a zero terminated string + * + * Signature for an strdup() implementation. + * + * Returns the copy of the string or NULL in case of error. + */ +typedef char *(XMLCALL *xmlStrdupFunc)(const char *str); + +/* + * The 4 interfaces used for all memory handling within libxml. +LIBXML_DLL_IMPORT xmlFreeFunc xmlFree; +LIBXML_DLL_IMPORT xmlMallocFunc xmlMalloc; +LIBXML_DLL_IMPORT xmlMallocFunc xmlMallocAtomic; +LIBXML_DLL_IMPORT xmlReallocFunc xmlRealloc; +LIBXML_DLL_IMPORT xmlStrdupFunc xmlMemStrdup; + */ + +/* + * The way to overload the existing functions. + * The xmlGc function have an extra entry for atomic block + * allocations useful for garbage collected memory allocators + */ +XMLPUBFUN int XMLCALL + xmlMemSetup (xmlFreeFunc freeFunc, + xmlMallocFunc mallocFunc, + xmlReallocFunc reallocFunc, + xmlStrdupFunc strdupFunc); +XMLPUBFUN int XMLCALL + xmlMemGet (xmlFreeFunc *freeFunc, + xmlMallocFunc *mallocFunc, + xmlReallocFunc *reallocFunc, + xmlStrdupFunc *strdupFunc); +XMLPUBFUN int XMLCALL + xmlGcMemSetup (xmlFreeFunc freeFunc, + xmlMallocFunc mallocFunc, + xmlMallocFunc mallocAtomicFunc, + xmlReallocFunc reallocFunc, + xmlStrdupFunc strdupFunc); +XMLPUBFUN int XMLCALL + xmlGcMemGet (xmlFreeFunc *freeFunc, + xmlMallocFunc *mallocFunc, + xmlMallocFunc *mallocAtomicFunc, + xmlReallocFunc *reallocFunc, + xmlStrdupFunc *strdupFunc); + +/* + * Initialization of the memory layer. + */ +XMLPUBFUN int XMLCALL + xmlInitMemory (void); + +/* + * Cleanup of the memory layer. + */ +XMLPUBFUN void XMLCALL + xmlCleanupMemory (void); +/* + * These are specific to the XML debug memory wrapper. + */ +XMLPUBFUN int XMLCALL + xmlMemUsed (void); +XMLPUBFUN int XMLCALL + xmlMemBlocks (void); +XMLPUBFUN void XMLCALL + xmlMemDisplay (FILE *fp); +XMLPUBFUN void XMLCALL + xmlMemDisplayLast(FILE *fp, long nbBytes); +XMLPUBFUN void XMLCALL + xmlMemShow (FILE *fp, int nr); +XMLPUBFUN void XMLCALL + xmlMemoryDump (void); +XMLPUBFUN void * XMLCALL + xmlMemMalloc (size_t size) LIBXML_ATTR_ALLOC_SIZE(1); +XMLPUBFUN void * XMLCALL + xmlMemRealloc (void *ptr,size_t size); +XMLPUBFUN void XMLCALL + xmlMemFree (void *ptr); +XMLPUBFUN char * XMLCALL + xmlMemoryStrdup (const char *str); +XMLPUBFUN void * XMLCALL + xmlMallocLoc (size_t size, const char *file, int line) LIBXML_ATTR_ALLOC_SIZE(1); +XMLPUBFUN void * XMLCALL + xmlReallocLoc (void *ptr, size_t size, const char *file, int line); +XMLPUBFUN void * XMLCALL + xmlMallocAtomicLoc (size_t size, const char *file, int line) LIBXML_ATTR_ALLOC_SIZE(1); +XMLPUBFUN char * XMLCALL + xmlMemStrdupLoc (const char *str, const char *file, int line); + + +#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 */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#ifndef __XML_GLOBALS_H +#ifndef __XML_THREADS_H__ +#include +#include +#endif +#endif + +#endif /* __DEBUG_MEMORY_ALLOC__ */ + diff --git a/android/native/libxml2/libxml/xmlmodule.h b/android/native/libxml2/libxml/xmlmodule.h new file mode 100644 index 0000000000..8f4a56035b --- /dev/null +++ b/android/native/libxml2/libxml/xmlmodule.h @@ -0,0 +1,57 @@ +/* + * Summary: dynamic module loading + * Description: basic API for dynamic module loading, used by + * libexslt added in 2.6.17 + * + * Copy: See Copyright for the status of this software. + * + * Author: Joel W. Reed + */ + +#ifndef __XML_MODULE_H__ +#define __XML_MODULE_H__ + +#include + +#ifdef LIBXML_MODULES_ENABLED + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * xmlModulePtr: + * + * A handle to a dynamically loaded module + */ +typedef struct _xmlModule xmlModule; +typedef xmlModule *xmlModulePtr; + +/** + * xmlModuleOption: + * + * enumeration of options that can be passed down to xmlModuleOpen() + */ +typedef enum { + XML_MODULE_LAZY = 1, /* lazy binding */ + XML_MODULE_LOCAL= 2 /* local binding */ +} xmlModuleOption; + +XMLPUBFUN xmlModulePtr XMLCALL xmlModuleOpen (const char *filename, + int options); + +XMLPUBFUN int XMLCALL xmlModuleSymbol (xmlModulePtr module, + const char* name, + void **result); + +XMLPUBFUN int XMLCALL xmlModuleClose (xmlModulePtr module); + +XMLPUBFUN int XMLCALL xmlModuleFree (xmlModulePtr module); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_MODULES_ENABLED */ + +#endif /*__XML_MODULE_H__ */ diff --git a/android/native/libxml2/libxml/xmlreader.h b/android/native/libxml2/libxml/xmlreader.h new file mode 100644 index 0000000000..696448258b --- /dev/null +++ b/android/native/libxml2/libxml/xmlreader.h @@ -0,0 +1,424 @@ +/* + * Summary: the XMLReader implementation + * Description: API of the XML streaming API based on C# interfaces. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XMLREADER_H__ +#define __XML_XMLREADER_H__ + +#include +#include +#include +#ifdef LIBXML_SCHEMAS_ENABLED +#include +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * xmlParserSeverities: + * + * How severe an error callback is when the per-reader error callback API + * is used. + */ +typedef enum { + XML_PARSER_SEVERITY_VALIDITY_WARNING = 1, + XML_PARSER_SEVERITY_VALIDITY_ERROR = 2, + XML_PARSER_SEVERITY_WARNING = 3, + XML_PARSER_SEVERITY_ERROR = 4 +} xmlParserSeverities; + +#ifdef LIBXML_READER_ENABLED + +/** + * xmlTextReaderMode: + * + * Internal state values for the reader. + */ +typedef enum { + XML_TEXTREADER_MODE_INITIAL = 0, + XML_TEXTREADER_MODE_INTERACTIVE = 1, + XML_TEXTREADER_MODE_ERROR = 2, + XML_TEXTREADER_MODE_EOF =3, + XML_TEXTREADER_MODE_CLOSED = 4, + XML_TEXTREADER_MODE_READING = 5 +} xmlTextReaderMode; + +/** + * xmlParserProperties: + * + * Some common options to use with xmlTextReaderSetParserProp, but it + * is better to use xmlParserOption and the xmlReaderNewxxx and + * xmlReaderForxxx APIs now. + */ +typedef enum { + XML_PARSER_LOADDTD = 1, + XML_PARSER_DEFAULTATTRS = 2, + XML_PARSER_VALIDATE = 3, + XML_PARSER_SUBST_ENTITIES = 4 +} xmlParserProperties; + +/** + * xmlReaderTypes: + * + * Predefined constants for the different types of nodes. + */ +typedef enum { + XML_READER_TYPE_NONE = 0, + XML_READER_TYPE_ELEMENT = 1, + XML_READER_TYPE_ATTRIBUTE = 2, + XML_READER_TYPE_TEXT = 3, + XML_READER_TYPE_CDATA = 4, + XML_READER_TYPE_ENTITY_REFERENCE = 5, + XML_READER_TYPE_ENTITY = 6, + XML_READER_TYPE_PROCESSING_INSTRUCTION = 7, + XML_READER_TYPE_COMMENT = 8, + XML_READER_TYPE_DOCUMENT = 9, + XML_READER_TYPE_DOCUMENT_TYPE = 10, + XML_READER_TYPE_DOCUMENT_FRAGMENT = 11, + XML_READER_TYPE_NOTATION = 12, + XML_READER_TYPE_WHITESPACE = 13, + XML_READER_TYPE_SIGNIFICANT_WHITESPACE = 14, + XML_READER_TYPE_END_ELEMENT = 15, + XML_READER_TYPE_END_ENTITY = 16, + XML_READER_TYPE_XML_DECLARATION = 17 +} xmlReaderTypes; + +/** + * xmlTextReader: + * + * Structure for an xmlReader context. + */ +typedef struct _xmlTextReader xmlTextReader; + +/** + * xmlTextReaderPtr: + * + * Pointer to an xmlReader context. + */ +typedef xmlTextReader *xmlTextReaderPtr; + +/* + * Constructors & Destructor + */ +XMLPUBFUN xmlTextReaderPtr XMLCALL + xmlNewTextReader (xmlParserInputBufferPtr input, + const char *URI); +XMLPUBFUN xmlTextReaderPtr XMLCALL + xmlNewTextReaderFilename(const char *URI); + +XMLPUBFUN void XMLCALL + xmlFreeTextReader (xmlTextReaderPtr reader); + +XMLPUBFUN int XMLCALL + xmlTextReaderSetup(xmlTextReaderPtr reader, + xmlParserInputBufferPtr input, const char *URL, + const char *encoding, int options); + +/* + * Iterators + */ +XMLPUBFUN int XMLCALL + xmlTextReaderRead (xmlTextReaderPtr reader); + +#ifdef LIBXML_WRITER_ENABLED +XMLPUBFUN xmlChar * XMLCALL + xmlTextReaderReadInnerXml (xmlTextReaderPtr reader); + +XMLPUBFUN xmlChar * XMLCALL + xmlTextReaderReadOuterXml (xmlTextReaderPtr reader); +#endif + +XMLPUBFUN xmlChar * XMLCALL + xmlTextReaderReadString (xmlTextReaderPtr reader); +XMLPUBFUN int XMLCALL + xmlTextReaderReadAttributeValue (xmlTextReaderPtr reader); + +/* + * Attributes of the node + */ +XMLPUBFUN int XMLCALL + xmlTextReaderAttributeCount(xmlTextReaderPtr reader); +XMLPUBFUN int XMLCALL + xmlTextReaderDepth (xmlTextReaderPtr reader); +XMLPUBFUN int XMLCALL + xmlTextReaderHasAttributes(xmlTextReaderPtr reader); +XMLPUBFUN int XMLCALL + xmlTextReaderHasValue(xmlTextReaderPtr reader); +XMLPUBFUN int XMLCALL + xmlTextReaderIsDefault (xmlTextReaderPtr reader); +XMLPUBFUN int XMLCALL + xmlTextReaderIsEmptyElement(xmlTextReaderPtr reader); +XMLPUBFUN int XMLCALL + xmlTextReaderNodeType (xmlTextReaderPtr reader); +XMLPUBFUN int XMLCALL + xmlTextReaderQuoteChar (xmlTextReaderPtr reader); +XMLPUBFUN int XMLCALL + xmlTextReaderReadState (xmlTextReaderPtr reader); +XMLPUBFUN int XMLCALL + xmlTextReaderIsNamespaceDecl(xmlTextReaderPtr reader); + +XMLPUBFUN const xmlChar * XMLCALL + xmlTextReaderConstBaseUri (xmlTextReaderPtr reader); +XMLPUBFUN const xmlChar * XMLCALL + xmlTextReaderConstLocalName (xmlTextReaderPtr reader); +XMLPUBFUN const xmlChar * XMLCALL + xmlTextReaderConstName (xmlTextReaderPtr reader); +XMLPUBFUN const xmlChar * XMLCALL + xmlTextReaderConstNamespaceUri(xmlTextReaderPtr reader); +XMLPUBFUN const xmlChar * XMLCALL + xmlTextReaderConstPrefix (xmlTextReaderPtr reader); +XMLPUBFUN const xmlChar * XMLCALL + xmlTextReaderConstXmlLang (xmlTextReaderPtr reader); +XMLPUBFUN const xmlChar * XMLCALL + xmlTextReaderConstString (xmlTextReaderPtr reader, + const xmlChar *str); +XMLPUBFUN const xmlChar * XMLCALL + xmlTextReaderConstValue (xmlTextReaderPtr reader); + +/* + * use the Const version of the routine for + * better performance and simpler code + */ +XMLPUBFUN xmlChar * XMLCALL + xmlTextReaderBaseUri (xmlTextReaderPtr reader); +XMLPUBFUN xmlChar * XMLCALL + xmlTextReaderLocalName (xmlTextReaderPtr reader); +XMLPUBFUN xmlChar * XMLCALL + xmlTextReaderName (xmlTextReaderPtr reader); +XMLPUBFUN xmlChar * XMLCALL + xmlTextReaderNamespaceUri(xmlTextReaderPtr reader); +XMLPUBFUN xmlChar * XMLCALL + xmlTextReaderPrefix (xmlTextReaderPtr reader); +XMLPUBFUN xmlChar * XMLCALL + xmlTextReaderXmlLang (xmlTextReaderPtr reader); +XMLPUBFUN xmlChar * XMLCALL + xmlTextReaderValue (xmlTextReaderPtr reader); + +/* + * Methods of the XmlTextReader + */ +XMLPUBFUN int XMLCALL + xmlTextReaderClose (xmlTextReaderPtr reader); +XMLPUBFUN xmlChar * XMLCALL + xmlTextReaderGetAttributeNo (xmlTextReaderPtr reader, + int no); +XMLPUBFUN xmlChar * XMLCALL + xmlTextReaderGetAttribute (xmlTextReaderPtr reader, + const xmlChar *name); +XMLPUBFUN xmlChar * XMLCALL + xmlTextReaderGetAttributeNs (xmlTextReaderPtr reader, + const xmlChar *localName, + const xmlChar *namespaceURI); +XMLPUBFUN xmlParserInputBufferPtr XMLCALL + xmlTextReaderGetRemainder (xmlTextReaderPtr reader); +XMLPUBFUN xmlChar * XMLCALL + xmlTextReaderLookupNamespace(xmlTextReaderPtr reader, + const xmlChar *prefix); +XMLPUBFUN int XMLCALL + xmlTextReaderMoveToAttributeNo(xmlTextReaderPtr reader, + int no); +XMLPUBFUN int XMLCALL + xmlTextReaderMoveToAttribute(xmlTextReaderPtr reader, + const xmlChar *name); +XMLPUBFUN int XMLCALL + xmlTextReaderMoveToAttributeNs(xmlTextReaderPtr reader, + const xmlChar *localName, + const xmlChar *namespaceURI); +XMLPUBFUN int XMLCALL + xmlTextReaderMoveToFirstAttribute(xmlTextReaderPtr reader); +XMLPUBFUN int XMLCALL + xmlTextReaderMoveToNextAttribute(xmlTextReaderPtr reader); +XMLPUBFUN int XMLCALL + xmlTextReaderMoveToElement (xmlTextReaderPtr reader); +XMLPUBFUN int XMLCALL + xmlTextReaderNormalization (xmlTextReaderPtr reader); +XMLPUBFUN const xmlChar * XMLCALL + xmlTextReaderConstEncoding (xmlTextReaderPtr reader); + +/* + * Extensions + */ +XMLPUBFUN int XMLCALL + xmlTextReaderSetParserProp (xmlTextReaderPtr reader, + int prop, + int value); +XMLPUBFUN int XMLCALL + xmlTextReaderGetParserProp (xmlTextReaderPtr reader, + int prop); +XMLPUBFUN xmlNodePtr XMLCALL + xmlTextReaderCurrentNode (xmlTextReaderPtr reader); + +XMLPUBFUN int XMLCALL + xmlTextReaderGetParserLineNumber(xmlTextReaderPtr reader); + +XMLPUBFUN int XMLCALL + xmlTextReaderGetParserColumnNumber(xmlTextReaderPtr reader); + +XMLPUBFUN xmlNodePtr XMLCALL + xmlTextReaderPreserve (xmlTextReaderPtr reader); +#ifdef LIBXML_PATTERN_ENABLED +XMLPUBFUN int XMLCALL + xmlTextReaderPreservePattern(xmlTextReaderPtr reader, + const xmlChar *pattern, + const xmlChar **namespaces); +#endif /* LIBXML_PATTERN_ENABLED */ +XMLPUBFUN xmlDocPtr XMLCALL + xmlTextReaderCurrentDoc (xmlTextReaderPtr reader); +XMLPUBFUN xmlNodePtr XMLCALL + xmlTextReaderExpand (xmlTextReaderPtr reader); +XMLPUBFUN int XMLCALL + xmlTextReaderNext (xmlTextReaderPtr reader); +XMLPUBFUN int XMLCALL + xmlTextReaderNextSibling (xmlTextReaderPtr reader); +XMLPUBFUN int XMLCALL + xmlTextReaderIsValid (xmlTextReaderPtr reader); +#ifdef LIBXML_SCHEMAS_ENABLED +XMLPUBFUN int XMLCALL + xmlTextReaderRelaxNGValidate(xmlTextReaderPtr reader, + const char *rng); +XMLPUBFUN int XMLCALL + xmlTextReaderRelaxNGSetSchema(xmlTextReaderPtr reader, + xmlRelaxNGPtr schema); +XMLPUBFUN int XMLCALL + xmlTextReaderSchemaValidate (xmlTextReaderPtr reader, + const char *xsd); +XMLPUBFUN int XMLCALL + xmlTextReaderSchemaValidateCtxt(xmlTextReaderPtr reader, + xmlSchemaValidCtxtPtr ctxt, + int options); +XMLPUBFUN int XMLCALL + xmlTextReaderSetSchema (xmlTextReaderPtr reader, + xmlSchemaPtr schema); +#endif +XMLPUBFUN const xmlChar * XMLCALL + xmlTextReaderConstXmlVersion(xmlTextReaderPtr reader); +XMLPUBFUN int XMLCALL + xmlTextReaderStandalone (xmlTextReaderPtr reader); + + +/* + * Index lookup + */ +XMLPUBFUN long XMLCALL + xmlTextReaderByteConsumed (xmlTextReaderPtr reader); + +/* + * New more complete APIs for simpler creation and reuse of readers + */ +XMLPUBFUN xmlTextReaderPtr XMLCALL + xmlReaderWalker (xmlDocPtr doc); +XMLPUBFUN xmlTextReaderPtr XMLCALL + xmlReaderForDoc (const xmlChar * cur, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN xmlTextReaderPtr XMLCALL + xmlReaderForFile (const char *filename, + const char *encoding, + int options); +XMLPUBFUN xmlTextReaderPtr XMLCALL + xmlReaderForMemory (const char *buffer, + int size, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN xmlTextReaderPtr XMLCALL + xmlReaderForFd (int fd, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN xmlTextReaderPtr XMLCALL + xmlReaderForIO (xmlInputReadCallback ioread, + xmlInputCloseCallback ioclose, + void *ioctx, + const char *URL, + const char *encoding, + int options); + +XMLPUBFUN int XMLCALL + xmlReaderNewWalker (xmlTextReaderPtr reader, + xmlDocPtr doc); +XMLPUBFUN int XMLCALL + xmlReaderNewDoc (xmlTextReaderPtr reader, + const xmlChar * cur, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN int XMLCALL + xmlReaderNewFile (xmlTextReaderPtr reader, + const char *filename, + const char *encoding, + int options); +XMLPUBFUN int XMLCALL + xmlReaderNewMemory (xmlTextReaderPtr reader, + const char *buffer, + int size, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN int XMLCALL + xmlReaderNewFd (xmlTextReaderPtr reader, + int fd, + const char *URL, + const char *encoding, + int options); +XMLPUBFUN int XMLCALL + xmlReaderNewIO (xmlTextReaderPtr reader, + xmlInputReadCallback ioread, + xmlInputCloseCallback ioclose, + void *ioctx, + const char *URL, + const char *encoding, + int options); +/* + * Error handling extensions + */ +typedef void * xmlTextReaderLocatorPtr; + +/** + * xmlTextReaderErrorFunc: + * @arg: the user argument + * @msg: the message + * @severity: the severity of the error + * @locator: a locator indicating where the error occured + * + * Signature of an error callback from a reader parser + */ +typedef void (XMLCALL *xmlTextReaderErrorFunc)(void *arg, + const char *msg, + xmlParserSeverities severity, + xmlTextReaderLocatorPtr locator); +XMLPUBFUN int XMLCALL + xmlTextReaderLocatorLineNumber(xmlTextReaderLocatorPtr locator); +/*int xmlTextReaderLocatorLinePosition(xmlTextReaderLocatorPtr locator);*/ +XMLPUBFUN xmlChar * XMLCALL + xmlTextReaderLocatorBaseURI (xmlTextReaderLocatorPtr locator); +XMLPUBFUN void XMLCALL + xmlTextReaderSetErrorHandler(xmlTextReaderPtr reader, + xmlTextReaderErrorFunc f, + void *arg); +XMLPUBFUN void XMLCALL + xmlTextReaderSetStructuredErrorHandler(xmlTextReaderPtr reader, + xmlStructuredErrorFunc f, + void *arg); +XMLPUBFUN void XMLCALL + xmlTextReaderGetErrorHandler(xmlTextReaderPtr reader, + xmlTextReaderErrorFunc *f, + void **arg); + +#endif /* LIBXML_READER_ENABLED */ + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_XMLREADER_H__ */ + diff --git a/android/native/libxml2/libxml/xmlregexp.h b/android/native/libxml2/libxml/xmlregexp.h new file mode 100644 index 0000000000..7009645a92 --- /dev/null +++ b/android/native/libxml2/libxml/xmlregexp.h @@ -0,0 +1,222 @@ +/* + * Summary: regular expressions handling + * Description: basic API for libxml regular expressions handling used + * for XML Schemas and validation. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_REGEXP_H__ +#define __XML_REGEXP_H__ + +#include + +#ifdef LIBXML_REGEXP_ENABLED + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * xmlRegexpPtr: + * + * A libxml regular expression, they can actually be far more complex + * thank the POSIX regex expressions. + */ +typedef struct _xmlRegexp xmlRegexp; +typedef xmlRegexp *xmlRegexpPtr; + +/** + * xmlRegExecCtxtPtr: + * + * A libxml progressive regular expression evaluation context + */ +typedef struct _xmlRegExecCtxt xmlRegExecCtxt; +typedef xmlRegExecCtxt *xmlRegExecCtxtPtr; + +#ifdef __cplusplus +} +#endif +#include +#include +#ifdef __cplusplus +extern "C" { +#endif + +/* + * The POSIX like API + */ +XMLPUBFUN xmlRegexpPtr XMLCALL + xmlRegexpCompile (const xmlChar *regexp); +XMLPUBFUN void XMLCALL xmlRegFreeRegexp(xmlRegexpPtr regexp); +XMLPUBFUN int XMLCALL + xmlRegexpExec (xmlRegexpPtr comp, + const xmlChar *value); +XMLPUBFUN void XMLCALL + xmlRegexpPrint (FILE *output, + xmlRegexpPtr regexp); +XMLPUBFUN int XMLCALL + xmlRegexpIsDeterminist(xmlRegexpPtr comp); + +/** + * xmlRegExecCallbacks: + * @exec: the regular expression context + * @token: the current token string + * @transdata: transition data + * @inputdata: input data + * + * Callback function when doing a transition in the automata + */ +typedef void (*xmlRegExecCallbacks) (xmlRegExecCtxtPtr exec, + const xmlChar *token, + void *transdata, + void *inputdata); + +/* + * The progressive API + */ +XMLPUBFUN xmlRegExecCtxtPtr XMLCALL + xmlRegNewExecCtxt (xmlRegexpPtr comp, + xmlRegExecCallbacks callback, + void *data); +XMLPUBFUN void XMLCALL + xmlRegFreeExecCtxt (xmlRegExecCtxtPtr exec); +XMLPUBFUN int XMLCALL + xmlRegExecPushString(xmlRegExecCtxtPtr exec, + const xmlChar *value, + void *data); +XMLPUBFUN int XMLCALL + xmlRegExecPushString2(xmlRegExecCtxtPtr exec, + const xmlChar *value, + const xmlChar *value2, + void *data); + +XMLPUBFUN int XMLCALL + xmlRegExecNextValues(xmlRegExecCtxtPtr exec, + int *nbval, + int *nbneg, + xmlChar **values, + int *terminal); +XMLPUBFUN int XMLCALL + xmlRegExecErrInfo (xmlRegExecCtxtPtr exec, + const xmlChar **string, + int *nbval, + int *nbneg, + xmlChar **values, + int *terminal); +#ifdef LIBXML_EXPR_ENABLED +/* + * Formal regular expression handling + * Its goal is to do some formal work on content models + */ + +/* expressions are used within a context */ +typedef struct _xmlExpCtxt xmlExpCtxt; +typedef xmlExpCtxt *xmlExpCtxtPtr; + +XMLPUBFUN void XMLCALL + xmlExpFreeCtxt (xmlExpCtxtPtr ctxt); +XMLPUBFUN xmlExpCtxtPtr XMLCALL + xmlExpNewCtxt (int maxNodes, + xmlDictPtr dict); + +XMLPUBFUN int XMLCALL + xmlExpCtxtNbNodes(xmlExpCtxtPtr ctxt); +XMLPUBFUN int XMLCALL + xmlExpCtxtNbCons(xmlExpCtxtPtr ctxt); + +/* Expressions are trees but the tree is opaque */ +typedef struct _xmlExpNode xmlExpNode; +typedef xmlExpNode *xmlExpNodePtr; + +typedef enum { + XML_EXP_EMPTY = 0, + XML_EXP_FORBID = 1, + XML_EXP_ATOM = 2, + XML_EXP_SEQ = 3, + XML_EXP_OR = 4, + XML_EXP_COUNT = 5 +} xmlExpNodeType; + +/* + * 2 core expressions shared by all for the empty language set + * and for the set with just the empty token + */ +XMLPUBVAR xmlExpNodePtr forbiddenExp; +XMLPUBVAR xmlExpNodePtr emptyExp; + +/* + * Expressions are reference counted internally + */ +XMLPUBFUN void XMLCALL + xmlExpFree (xmlExpCtxtPtr ctxt, + xmlExpNodePtr expr); +XMLPUBFUN void XMLCALL + xmlExpRef (xmlExpNodePtr expr); + +/* + * constructors can be either manual or from a string + */ +XMLPUBFUN xmlExpNodePtr XMLCALL + xmlExpParse (xmlExpCtxtPtr ctxt, + const char *expr); +XMLPUBFUN xmlExpNodePtr XMLCALL + xmlExpNewAtom (xmlExpCtxtPtr ctxt, + const xmlChar *name, + int len); +XMLPUBFUN xmlExpNodePtr XMLCALL + xmlExpNewOr (xmlExpCtxtPtr ctxt, + xmlExpNodePtr left, + xmlExpNodePtr right); +XMLPUBFUN xmlExpNodePtr XMLCALL + xmlExpNewSeq (xmlExpCtxtPtr ctxt, + xmlExpNodePtr left, + xmlExpNodePtr right); +XMLPUBFUN xmlExpNodePtr XMLCALL + xmlExpNewRange (xmlExpCtxtPtr ctxt, + xmlExpNodePtr subset, + int min, + int max); +/* + * The really interesting APIs + */ +XMLPUBFUN int XMLCALL + xmlExpIsNillable(xmlExpNodePtr expr); +XMLPUBFUN int XMLCALL + xmlExpMaxToken (xmlExpNodePtr expr); +XMLPUBFUN int XMLCALL + xmlExpGetLanguage(xmlExpCtxtPtr ctxt, + xmlExpNodePtr expr, + const xmlChar**langList, + int len); +XMLPUBFUN int XMLCALL + xmlExpGetStart (xmlExpCtxtPtr ctxt, + xmlExpNodePtr expr, + const xmlChar**tokList, + int len); +XMLPUBFUN xmlExpNodePtr XMLCALL + xmlExpStringDerive(xmlExpCtxtPtr ctxt, + xmlExpNodePtr expr, + const xmlChar *str, + int len); +XMLPUBFUN xmlExpNodePtr XMLCALL + xmlExpExpDerive (xmlExpCtxtPtr ctxt, + xmlExpNodePtr expr, + xmlExpNodePtr sub); +XMLPUBFUN int XMLCALL + xmlExpSubsume (xmlExpCtxtPtr ctxt, + xmlExpNodePtr expr, + xmlExpNodePtr sub); +XMLPUBFUN void XMLCALL + xmlExpDump (xmlBufferPtr buf, + xmlExpNodePtr expr); +#endif /* LIBXML_EXPR_ENABLED */ +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_REGEXP_ENABLED */ + +#endif /*__XML_REGEXP_H__ */ diff --git a/android/native/libxml2/libxml/xmlsave.h b/android/native/libxml2/libxml/xmlsave.h new file mode 100644 index 0000000000..fb329b22db --- /dev/null +++ b/android/native/libxml2/libxml/xmlsave.h @@ -0,0 +1,88 @@ +/* + * Summary: the XML document serializer + * Description: API to save document or subtree of document + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XMLSAVE_H__ +#define __XML_XMLSAVE_H__ + +#include +#include +#include +#include + +#ifdef LIBXML_OUTPUT_ENABLED +#ifdef __cplusplus +extern "C" { +#endif + +/** + * xmlSaveOption: + * + * This is the set of XML save options that can be passed down + * to the xmlSaveToFd() and similar calls. + */ +typedef enum { + XML_SAVE_FORMAT = 1<<0, /* format save output */ + XML_SAVE_NO_DECL = 1<<1, /* drop the xml declaration */ + XML_SAVE_NO_EMPTY = 1<<2, /* no empty tags */ + XML_SAVE_NO_XHTML = 1<<3, /* disable XHTML1 specific rules */ + XML_SAVE_XHTML = 1<<4, /* force XHTML1 specific rules */ + XML_SAVE_AS_XML = 1<<5, /* force XML serialization on HTML doc */ + XML_SAVE_AS_HTML = 1<<6, /* force HTML serialization on XML doc */ + XML_SAVE_WSNONSIG = 1<<7 /* format with non-significant whitespace */ +} xmlSaveOption; + + +typedef struct _xmlSaveCtxt xmlSaveCtxt; +typedef xmlSaveCtxt *xmlSaveCtxtPtr; + +XMLPUBFUN xmlSaveCtxtPtr XMLCALL + xmlSaveToFd (int fd, + const char *encoding, + int options); +XMLPUBFUN xmlSaveCtxtPtr XMLCALL + xmlSaveToFilename (const char *filename, + const char *encoding, + int options); + +XMLPUBFUN xmlSaveCtxtPtr XMLCALL + xmlSaveToBuffer (xmlBufferPtr buffer, + const char *encoding, + int options); + +XMLPUBFUN xmlSaveCtxtPtr XMLCALL + xmlSaveToIO (xmlOutputWriteCallback iowrite, + xmlOutputCloseCallback ioclose, + void *ioctx, + const char *encoding, + int options); + +XMLPUBFUN long XMLCALL + xmlSaveDoc (xmlSaveCtxtPtr ctxt, + xmlDocPtr doc); +XMLPUBFUN long XMLCALL + xmlSaveTree (xmlSaveCtxtPtr ctxt, + xmlNodePtr node); + +XMLPUBFUN int XMLCALL + xmlSaveFlush (xmlSaveCtxtPtr ctxt); +XMLPUBFUN int XMLCALL + xmlSaveClose (xmlSaveCtxtPtr ctxt); +XMLPUBFUN int XMLCALL + xmlSaveSetEscape (xmlSaveCtxtPtr ctxt, + xmlCharEncodingOutputFunc escape); +XMLPUBFUN int XMLCALL + xmlSaveSetAttrEscape (xmlSaveCtxtPtr ctxt, + xmlCharEncodingOutputFunc escape); +#ifdef __cplusplus +} +#endif +#endif /* LIBXML_OUTPUT_ENABLED */ +#endif /* __XML_XMLSAVE_H__ */ + + diff --git a/android/native/libxml2/libxml/xmlschemas.h b/android/native/libxml2/libxml/xmlschemas.h new file mode 100644 index 0000000000..752bc3ad79 --- /dev/null +++ b/android/native/libxml2/libxml/xmlschemas.h @@ -0,0 +1,218 @@ +/* + * Summary: incomplete XML Schemas structure implementation + * Description: interface to the XML Schemas handling and schema validity + * checking, it is incomplete right now. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + + +#ifndef __XML_SCHEMA_H__ +#define __XML_SCHEMA_H__ + +#include + +#ifdef LIBXML_SCHEMAS_ENABLED + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * This error codes are obsolete; not used any more. + */ +typedef enum { + XML_SCHEMAS_ERR_OK = 0, + XML_SCHEMAS_ERR_NOROOT = 1, + XML_SCHEMAS_ERR_UNDECLAREDELEM, + XML_SCHEMAS_ERR_NOTTOPLEVEL, + XML_SCHEMAS_ERR_MISSING, + XML_SCHEMAS_ERR_WRONGELEM, + XML_SCHEMAS_ERR_NOTYPE, + XML_SCHEMAS_ERR_NOROLLBACK, + XML_SCHEMAS_ERR_ISABSTRACT, + XML_SCHEMAS_ERR_NOTEMPTY, + XML_SCHEMAS_ERR_ELEMCONT, + XML_SCHEMAS_ERR_HAVEDEFAULT, + XML_SCHEMAS_ERR_NOTNILLABLE, + XML_SCHEMAS_ERR_EXTRACONTENT, + XML_SCHEMAS_ERR_INVALIDATTR, + XML_SCHEMAS_ERR_INVALIDELEM, + XML_SCHEMAS_ERR_NOTDETERMINIST, + XML_SCHEMAS_ERR_CONSTRUCT, + XML_SCHEMAS_ERR_INTERNAL, + XML_SCHEMAS_ERR_NOTSIMPLE, + XML_SCHEMAS_ERR_ATTRUNKNOWN, + XML_SCHEMAS_ERR_ATTRINVALID, + XML_SCHEMAS_ERR_VALUE, + XML_SCHEMAS_ERR_FACET, + XML_SCHEMAS_ERR_, + XML_SCHEMAS_ERR_XXX +} xmlSchemaValidError; + +/* +* ATTENTION: Change xmlSchemaSetValidOptions's check +* for invalid values, if adding to the validation +* options below. +*/ +/** + * xmlSchemaValidOption: + * + * This is the set of XML Schema validation options. + */ +typedef enum { + XML_SCHEMA_VAL_VC_I_CREATE = 1<<0 + /* Default/fixed: create an attribute node + * or an element's text node on the instance. + */ +} xmlSchemaValidOption; + +/* + XML_SCHEMA_VAL_XSI_ASSEMBLE = 1<<1, + * assemble schemata using + * xsi:schemaLocation and + * xsi:noNamespaceSchemaLocation +*/ + +/** + * The schemas related types are kept internal + */ +typedef struct _xmlSchema xmlSchema; +typedef xmlSchema *xmlSchemaPtr; + +/** + * xmlSchemaValidityErrorFunc: + * @ctx: the validation context + * @msg: the message + * @...: extra arguments + * + * Signature of an error callback from an XSD validation + */ +typedef void (XMLCDECL *xmlSchemaValidityErrorFunc) (void *ctx, const char *msg, ...) LIBXML_ATTR_FORMAT(2,3); + +/** + * xmlSchemaValidityWarningFunc: + * @ctx: the validation context + * @msg: the message + * @...: extra arguments + * + * Signature of a warning callback from an XSD validation + */ +typedef void (XMLCDECL *xmlSchemaValidityWarningFunc) (void *ctx, const char *msg, ...) LIBXML_ATTR_FORMAT(2,3); + +/** + * A schemas validation context + */ +typedef struct _xmlSchemaParserCtxt xmlSchemaParserCtxt; +typedef xmlSchemaParserCtxt *xmlSchemaParserCtxtPtr; + +typedef struct _xmlSchemaValidCtxt xmlSchemaValidCtxt; +typedef xmlSchemaValidCtxt *xmlSchemaValidCtxtPtr; + +/* + * Interfaces for parsing. + */ +XMLPUBFUN xmlSchemaParserCtxtPtr XMLCALL + xmlSchemaNewParserCtxt (const char *URL); +XMLPUBFUN xmlSchemaParserCtxtPtr XMLCALL + xmlSchemaNewMemParserCtxt (const char *buffer, + int size); +XMLPUBFUN xmlSchemaParserCtxtPtr XMLCALL + xmlSchemaNewDocParserCtxt (xmlDocPtr doc); +XMLPUBFUN void XMLCALL + xmlSchemaFreeParserCtxt (xmlSchemaParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + xmlSchemaSetParserErrors (xmlSchemaParserCtxtPtr ctxt, + xmlSchemaValidityErrorFunc err, + xmlSchemaValidityWarningFunc warn, + void *ctx); +XMLPUBFUN void XMLCALL + xmlSchemaSetParserStructuredErrors(xmlSchemaParserCtxtPtr ctxt, + xmlStructuredErrorFunc serror, + void *ctx); +XMLPUBFUN int XMLCALL + xmlSchemaGetParserErrors(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaValidityErrorFunc * err, + xmlSchemaValidityWarningFunc * warn, + void **ctx); +XMLPUBFUN int XMLCALL + xmlSchemaIsValid (xmlSchemaValidCtxtPtr ctxt); + +XMLPUBFUN xmlSchemaPtr XMLCALL + xmlSchemaParse (xmlSchemaParserCtxtPtr ctxt); +XMLPUBFUN void XMLCALL + xmlSchemaFree (xmlSchemaPtr schema); +#ifdef LIBXML_OUTPUT_ENABLED +XMLPUBFUN void XMLCALL + xmlSchemaDump (FILE *output, + xmlSchemaPtr schema); +#endif /* LIBXML_OUTPUT_ENABLED */ +/* + * Interfaces for validating + */ +XMLPUBFUN void XMLCALL + xmlSchemaSetValidErrors (xmlSchemaValidCtxtPtr ctxt, + xmlSchemaValidityErrorFunc err, + xmlSchemaValidityWarningFunc warn, + void *ctx); +XMLPUBFUN void XMLCALL + xmlSchemaSetValidStructuredErrors(xmlSchemaValidCtxtPtr ctxt, + xmlStructuredErrorFunc serror, + void *ctx); +XMLPUBFUN int XMLCALL + xmlSchemaGetValidErrors (xmlSchemaValidCtxtPtr ctxt, + xmlSchemaValidityErrorFunc *err, + xmlSchemaValidityWarningFunc *warn, + void **ctx); +XMLPUBFUN int XMLCALL + xmlSchemaSetValidOptions (xmlSchemaValidCtxtPtr ctxt, + int options); +XMLPUBFUN int XMLCALL + xmlSchemaValidCtxtGetOptions(xmlSchemaValidCtxtPtr ctxt); + +XMLPUBFUN xmlSchemaValidCtxtPtr XMLCALL + xmlSchemaNewValidCtxt (xmlSchemaPtr schema); +XMLPUBFUN void XMLCALL + xmlSchemaFreeValidCtxt (xmlSchemaValidCtxtPtr ctxt); +XMLPUBFUN int XMLCALL + xmlSchemaValidateDoc (xmlSchemaValidCtxtPtr ctxt, + xmlDocPtr instance); +XMLPUBFUN int XMLCALL + xmlSchemaValidateOneElement (xmlSchemaValidCtxtPtr ctxt, + xmlNodePtr elem); +XMLPUBFUN int XMLCALL + xmlSchemaValidateStream (xmlSchemaValidCtxtPtr ctxt, + xmlParserInputBufferPtr input, + xmlCharEncoding enc, + xmlSAXHandlerPtr sax, + void *user_data); +XMLPUBFUN int XMLCALL + xmlSchemaValidateFile (xmlSchemaValidCtxtPtr ctxt, + const char * filename, + int options); + +XMLPUBFUN xmlParserCtxtPtr XMLCALL + xmlSchemaValidCtxtGetParserCtxt(xmlSchemaValidCtxtPtr ctxt); + +/* + * Interface to insert Schemas SAX validation in a SAX stream + */ +typedef struct _xmlSchemaSAXPlug xmlSchemaSAXPlugStruct; +typedef xmlSchemaSAXPlugStruct *xmlSchemaSAXPlugPtr; + +XMLPUBFUN xmlSchemaSAXPlugPtr XMLCALL + xmlSchemaSAXPlug (xmlSchemaValidCtxtPtr ctxt, + xmlSAXHandlerPtr *sax, + void **user_data); +XMLPUBFUN int XMLCALL + xmlSchemaSAXUnplug (xmlSchemaSAXPlugPtr plug); +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_SCHEMAS_ENABLED */ +#endif /* __XML_SCHEMA_H__ */ diff --git a/android/native/libxml2/libxml/xmlschemastypes.h b/android/native/libxml2/libxml/xmlschemastypes.h new file mode 100644 index 0000000000..9a3a7a175e --- /dev/null +++ b/android/native/libxml2/libxml/xmlschemastypes.h @@ -0,0 +1,151 @@ +/* + * Summary: implementation of XML Schema Datatypes + * Description: module providing the XML Schema Datatypes implementation + * both definition and validity checking + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + + +#ifndef __XML_SCHEMA_TYPES_H__ +#define __XML_SCHEMA_TYPES_H__ + +#include + +#ifdef LIBXML_SCHEMAS_ENABLED + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + XML_SCHEMA_WHITESPACE_UNKNOWN = 0, + XML_SCHEMA_WHITESPACE_PRESERVE = 1, + XML_SCHEMA_WHITESPACE_REPLACE = 2, + XML_SCHEMA_WHITESPACE_COLLAPSE = 3 +} xmlSchemaWhitespaceValueType; + +XMLPUBFUN void XMLCALL + xmlSchemaInitTypes (void); +XMLPUBFUN void XMLCALL + xmlSchemaCleanupTypes (void); +XMLPUBFUN xmlSchemaTypePtr XMLCALL + xmlSchemaGetPredefinedType (const xmlChar *name, + const xmlChar *ns); +XMLPUBFUN int XMLCALL + xmlSchemaValidatePredefinedType (xmlSchemaTypePtr type, + const xmlChar *value, + xmlSchemaValPtr *val); +XMLPUBFUN int XMLCALL + xmlSchemaValPredefTypeNode (xmlSchemaTypePtr type, + const xmlChar *value, + xmlSchemaValPtr *val, + xmlNodePtr node); +XMLPUBFUN int XMLCALL + xmlSchemaValidateFacet (xmlSchemaTypePtr base, + xmlSchemaFacetPtr facet, + const xmlChar *value, + xmlSchemaValPtr val); +XMLPUBFUN int XMLCALL + xmlSchemaValidateFacetWhtsp (xmlSchemaFacetPtr facet, + xmlSchemaWhitespaceValueType fws, + xmlSchemaValType valType, + const xmlChar *value, + xmlSchemaValPtr val, + xmlSchemaWhitespaceValueType ws); +XMLPUBFUN void XMLCALL + xmlSchemaFreeValue (xmlSchemaValPtr val); +XMLPUBFUN xmlSchemaFacetPtr XMLCALL + xmlSchemaNewFacet (void); +XMLPUBFUN int XMLCALL + xmlSchemaCheckFacet (xmlSchemaFacetPtr facet, + xmlSchemaTypePtr typeDecl, + xmlSchemaParserCtxtPtr ctxt, + const xmlChar *name); +XMLPUBFUN void XMLCALL + xmlSchemaFreeFacet (xmlSchemaFacetPtr facet); +XMLPUBFUN int XMLCALL + xmlSchemaCompareValues (xmlSchemaValPtr x, + xmlSchemaValPtr y); +XMLPUBFUN xmlSchemaTypePtr XMLCALL + xmlSchemaGetBuiltInListSimpleTypeItemType (xmlSchemaTypePtr type); +XMLPUBFUN int XMLCALL + xmlSchemaValidateListSimpleTypeFacet (xmlSchemaFacetPtr facet, + const xmlChar *value, + unsigned long actualLen, + unsigned long *expectedLen); +XMLPUBFUN xmlSchemaTypePtr XMLCALL + xmlSchemaGetBuiltInType (xmlSchemaValType type); +XMLPUBFUN int XMLCALL + xmlSchemaIsBuiltInTypeFacet (xmlSchemaTypePtr type, + int facetType); +XMLPUBFUN xmlChar * XMLCALL + xmlSchemaCollapseString (const xmlChar *value); +XMLPUBFUN xmlChar * XMLCALL + xmlSchemaWhiteSpaceReplace (const xmlChar *value); +XMLPUBFUN unsigned long XMLCALL + xmlSchemaGetFacetValueAsULong (xmlSchemaFacetPtr facet); +XMLPUBFUN int XMLCALL + xmlSchemaValidateLengthFacet (xmlSchemaTypePtr type, + xmlSchemaFacetPtr facet, + const xmlChar *value, + xmlSchemaValPtr val, + unsigned long *length); +XMLPUBFUN int XMLCALL + xmlSchemaValidateLengthFacetWhtsp(xmlSchemaFacetPtr facet, + xmlSchemaValType valType, + const xmlChar *value, + xmlSchemaValPtr val, + unsigned long *length, + xmlSchemaWhitespaceValueType ws); +XMLPUBFUN int XMLCALL + xmlSchemaValPredefTypeNodeNoNorm(xmlSchemaTypePtr type, + const xmlChar *value, + xmlSchemaValPtr *val, + xmlNodePtr node); +XMLPUBFUN int XMLCALL + xmlSchemaGetCanonValue (xmlSchemaValPtr val, + const xmlChar **retValue); +XMLPUBFUN int XMLCALL + xmlSchemaGetCanonValueWhtsp (xmlSchemaValPtr val, + const xmlChar **retValue, + xmlSchemaWhitespaceValueType ws); +XMLPUBFUN int XMLCALL + xmlSchemaValueAppend (xmlSchemaValPtr prev, + xmlSchemaValPtr cur); +XMLPUBFUN xmlSchemaValPtr XMLCALL + xmlSchemaValueGetNext (xmlSchemaValPtr cur); +XMLPUBFUN const xmlChar * XMLCALL + xmlSchemaValueGetAsString (xmlSchemaValPtr val); +XMLPUBFUN int XMLCALL + xmlSchemaValueGetAsBoolean (xmlSchemaValPtr val); +XMLPUBFUN xmlSchemaValPtr XMLCALL + xmlSchemaNewStringValue (xmlSchemaValType type, + const xmlChar *value); +XMLPUBFUN xmlSchemaValPtr XMLCALL + xmlSchemaNewNOTATIONValue (const xmlChar *name, + const xmlChar *ns); +XMLPUBFUN xmlSchemaValPtr XMLCALL + xmlSchemaNewQNameValue (const xmlChar *namespaceName, + const xmlChar *localName); +XMLPUBFUN int XMLCALL + xmlSchemaCompareValuesWhtsp (xmlSchemaValPtr x, + xmlSchemaWhitespaceValueType xws, + xmlSchemaValPtr y, + xmlSchemaWhitespaceValueType yws); +XMLPUBFUN xmlSchemaValPtr XMLCALL + xmlSchemaCopyValue (xmlSchemaValPtr val); +XMLPUBFUN xmlSchemaValType XMLCALL + xmlSchemaGetValType (xmlSchemaValPtr val); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_SCHEMAS_ENABLED */ +#endif /* __XML_SCHEMA_TYPES_H__ */ diff --git a/android/native/libxml2/libxml/xmlstring.h b/android/native/libxml2/libxml/xmlstring.h new file mode 100644 index 0000000000..0bc6888865 --- /dev/null +++ b/android/native/libxml2/libxml/xmlstring.h @@ -0,0 +1,140 @@ +/* + * Summary: set of routines to process strings + * Description: type and interfaces needed for the internal string handling + * of the library, especially UTF8 processing. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_STRING_H__ +#define __XML_STRING_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * xmlChar: + * + * This is a basic byte in an UTF-8 encoded string. + * It's unsigned allowing to pinpoint case where char * are assigned + * to xmlChar * (possibly making serialization back impossible). + */ +typedef unsigned char xmlChar; + +/** + * BAD_CAST: + * + * Macro to cast a string to an xmlChar * when one know its safe. + */ +#define BAD_CAST (xmlChar *) + +/* + * xmlChar handling + */ +XMLPUBFUN xmlChar * XMLCALL + xmlStrdup (const xmlChar *cur); +XMLPUBFUN xmlChar * XMLCALL + xmlStrndup (const xmlChar *cur, + int len); +XMLPUBFUN xmlChar * XMLCALL + xmlCharStrndup (const char *cur, + int len); +XMLPUBFUN xmlChar * XMLCALL + xmlCharStrdup (const char *cur); +XMLPUBFUN xmlChar * XMLCALL + xmlStrsub (const xmlChar *str, + int start, + int len); +XMLPUBFUN const xmlChar * XMLCALL + xmlStrchr (const xmlChar *str, + xmlChar val); +XMLPUBFUN const xmlChar * XMLCALL + xmlStrstr (const xmlChar *str, + const xmlChar *val); +XMLPUBFUN const xmlChar * XMLCALL + xmlStrcasestr (const xmlChar *str, + const xmlChar *val); +XMLPUBFUN int XMLCALL + xmlStrcmp (const xmlChar *str1, + const xmlChar *str2); +XMLPUBFUN int XMLCALL + xmlStrncmp (const xmlChar *str1, + const xmlChar *str2, + int len); +XMLPUBFUN int XMLCALL + xmlStrcasecmp (const xmlChar *str1, + const xmlChar *str2); +XMLPUBFUN int XMLCALL + xmlStrncasecmp (const xmlChar *str1, + const xmlChar *str2, + int len); +XMLPUBFUN int XMLCALL + xmlStrEqual (const xmlChar *str1, + const xmlChar *str2); +XMLPUBFUN int XMLCALL + xmlStrQEqual (const xmlChar *pref, + const xmlChar *name, + const xmlChar *str); +XMLPUBFUN int XMLCALL + xmlStrlen (const xmlChar *str); +XMLPUBFUN xmlChar * XMLCALL + xmlStrcat (xmlChar *cur, + const xmlChar *add); +XMLPUBFUN xmlChar * XMLCALL + xmlStrncat (xmlChar *cur, + const xmlChar *add, + int len); +XMLPUBFUN xmlChar * XMLCALL + xmlStrncatNew (const xmlChar *str1, + const xmlChar *str2, + int len); +XMLPUBFUN int XMLCALL + xmlStrPrintf (xmlChar *buf, + int len, + const xmlChar *msg, + ...); +XMLPUBFUN int XMLCALL + xmlStrVPrintf (xmlChar *buf, + int len, + const xmlChar *msg, + va_list ap); + +XMLPUBFUN int XMLCALL + xmlGetUTF8Char (const unsigned char *utf, + int *len); +XMLPUBFUN int XMLCALL + xmlCheckUTF8 (const unsigned char *utf); +XMLPUBFUN int XMLCALL + xmlUTF8Strsize (const xmlChar *utf, + int len); +XMLPUBFUN xmlChar * XMLCALL + xmlUTF8Strndup (const xmlChar *utf, + int len); +XMLPUBFUN const xmlChar * XMLCALL + xmlUTF8Strpos (const xmlChar *utf, + int pos); +XMLPUBFUN int XMLCALL + xmlUTF8Strloc (const xmlChar *utf, + const xmlChar *utfchar); +XMLPUBFUN xmlChar * XMLCALL + xmlUTF8Strsub (const xmlChar *utf, + int start, + int len); +XMLPUBFUN int XMLCALL + xmlUTF8Strlen (const xmlChar *utf); +XMLPUBFUN int XMLCALL + xmlUTF8Size (const xmlChar *utf); +XMLPUBFUN int XMLCALL + xmlUTF8Charcmp (const xmlChar *utf1, + const xmlChar *utf2); + +#ifdef __cplusplus +} +#endif +#endif /* __XML_STRING_H__ */ diff --git a/android/native/libxml2/libxml/xmlunicode.h b/android/native/libxml2/libxml/xmlunicode.h new file mode 100644 index 0000000000..01ac8b61f5 --- /dev/null +++ b/android/native/libxml2/libxml/xmlunicode.h @@ -0,0 +1,202 @@ +/* + * Summary: Unicode character APIs + * Description: API for the Unicode character APIs + * + * This file is automatically generated from the + * UCS description files of the Unicode Character Database + * 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 + * Sources: Blocks-4.0.1.txt UnicodeData-4.0.1.txt + * Author: Daniel Veillard + */ + +#ifndef __XML_UNICODE_H__ +#define __XML_UNICODE_H__ + +#include + +#ifdef LIBXML_UNICODE_ENABLED + +#ifdef __cplusplus +extern "C" { +#endif + +XMLPUBFUN int XMLCALL xmlUCSIsAegeanNumbers (int code); +XMLPUBFUN int XMLCALL xmlUCSIsAlphabeticPresentationForms (int code); +XMLPUBFUN int XMLCALL xmlUCSIsArabic (int code); +XMLPUBFUN int XMLCALL xmlUCSIsArabicPresentationFormsA (int code); +XMLPUBFUN int XMLCALL xmlUCSIsArabicPresentationFormsB (int code); +XMLPUBFUN int XMLCALL xmlUCSIsArmenian (int code); +XMLPUBFUN int XMLCALL xmlUCSIsArrows (int code); +XMLPUBFUN int XMLCALL xmlUCSIsBasicLatin (int code); +XMLPUBFUN int XMLCALL xmlUCSIsBengali (int code); +XMLPUBFUN int XMLCALL xmlUCSIsBlockElements (int code); +XMLPUBFUN int XMLCALL xmlUCSIsBopomofo (int code); +XMLPUBFUN int XMLCALL xmlUCSIsBopomofoExtended (int code); +XMLPUBFUN int XMLCALL xmlUCSIsBoxDrawing (int code); +XMLPUBFUN int XMLCALL xmlUCSIsBraillePatterns (int code); +XMLPUBFUN int XMLCALL xmlUCSIsBuhid (int code); +XMLPUBFUN int XMLCALL xmlUCSIsByzantineMusicalSymbols (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCJKCompatibility (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCJKCompatibilityForms (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCJKCompatibilityIdeographs (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCJKCompatibilityIdeographsSupplement (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCJKRadicalsSupplement (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCJKSymbolsandPunctuation (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCJKUnifiedIdeographs (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCJKUnifiedIdeographsExtensionA (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCJKUnifiedIdeographsExtensionB (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCherokee (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCombiningDiacriticalMarks (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCombiningDiacriticalMarksforSymbols (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCombiningHalfMarks (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCombiningMarksforSymbols (int code); +XMLPUBFUN int XMLCALL xmlUCSIsControlPictures (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCurrencySymbols (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCypriotSyllabary (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCyrillic (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCyrillicSupplement (int code); +XMLPUBFUN int XMLCALL xmlUCSIsDeseret (int code); +XMLPUBFUN int XMLCALL xmlUCSIsDevanagari (int code); +XMLPUBFUN int XMLCALL xmlUCSIsDingbats (int code); +XMLPUBFUN int XMLCALL xmlUCSIsEnclosedAlphanumerics (int code); +XMLPUBFUN int XMLCALL xmlUCSIsEnclosedCJKLettersandMonths (int code); +XMLPUBFUN int XMLCALL xmlUCSIsEthiopic (int code); +XMLPUBFUN int XMLCALL xmlUCSIsGeneralPunctuation (int code); +XMLPUBFUN int XMLCALL xmlUCSIsGeometricShapes (int code); +XMLPUBFUN int XMLCALL xmlUCSIsGeorgian (int code); +XMLPUBFUN int XMLCALL xmlUCSIsGothic (int code); +XMLPUBFUN int XMLCALL xmlUCSIsGreek (int code); +XMLPUBFUN int XMLCALL xmlUCSIsGreekExtended (int code); +XMLPUBFUN int XMLCALL xmlUCSIsGreekandCoptic (int code); +XMLPUBFUN int XMLCALL xmlUCSIsGujarati (int code); +XMLPUBFUN int XMLCALL xmlUCSIsGurmukhi (int code); +XMLPUBFUN int XMLCALL xmlUCSIsHalfwidthandFullwidthForms (int code); +XMLPUBFUN int XMLCALL xmlUCSIsHangulCompatibilityJamo (int code); +XMLPUBFUN int XMLCALL xmlUCSIsHangulJamo (int code); +XMLPUBFUN int XMLCALL xmlUCSIsHangulSyllables (int code); +XMLPUBFUN int XMLCALL xmlUCSIsHanunoo (int code); +XMLPUBFUN int XMLCALL xmlUCSIsHebrew (int code); +XMLPUBFUN int XMLCALL xmlUCSIsHighPrivateUseSurrogates (int code); +XMLPUBFUN int XMLCALL xmlUCSIsHighSurrogates (int code); +XMLPUBFUN int XMLCALL xmlUCSIsHiragana (int code); +XMLPUBFUN int XMLCALL xmlUCSIsIPAExtensions (int code); +XMLPUBFUN int XMLCALL xmlUCSIsIdeographicDescriptionCharacters (int code); +XMLPUBFUN int XMLCALL xmlUCSIsKanbun (int code); +XMLPUBFUN int XMLCALL xmlUCSIsKangxiRadicals (int code); +XMLPUBFUN int XMLCALL xmlUCSIsKannada (int code); +XMLPUBFUN int XMLCALL xmlUCSIsKatakana (int code); +XMLPUBFUN int XMLCALL xmlUCSIsKatakanaPhoneticExtensions (int code); +XMLPUBFUN int XMLCALL xmlUCSIsKhmer (int code); +XMLPUBFUN int XMLCALL xmlUCSIsKhmerSymbols (int code); +XMLPUBFUN int XMLCALL xmlUCSIsLao (int code); +XMLPUBFUN int XMLCALL xmlUCSIsLatin1Supplement (int code); +XMLPUBFUN int XMLCALL xmlUCSIsLatinExtendedA (int code); +XMLPUBFUN int XMLCALL xmlUCSIsLatinExtendedB (int code); +XMLPUBFUN int XMLCALL xmlUCSIsLatinExtendedAdditional (int code); +XMLPUBFUN int XMLCALL xmlUCSIsLetterlikeSymbols (int code); +XMLPUBFUN int XMLCALL xmlUCSIsLimbu (int code); +XMLPUBFUN int XMLCALL xmlUCSIsLinearBIdeograms (int code); +XMLPUBFUN int XMLCALL xmlUCSIsLinearBSyllabary (int code); +XMLPUBFUN int XMLCALL xmlUCSIsLowSurrogates (int code); +XMLPUBFUN int XMLCALL xmlUCSIsMalayalam (int code); +XMLPUBFUN int XMLCALL xmlUCSIsMathematicalAlphanumericSymbols (int code); +XMLPUBFUN int XMLCALL xmlUCSIsMathematicalOperators (int code); +XMLPUBFUN int XMLCALL xmlUCSIsMiscellaneousMathematicalSymbolsA (int code); +XMLPUBFUN int XMLCALL xmlUCSIsMiscellaneousMathematicalSymbolsB (int code); +XMLPUBFUN int XMLCALL xmlUCSIsMiscellaneousSymbols (int code); +XMLPUBFUN int XMLCALL xmlUCSIsMiscellaneousSymbolsandArrows (int code); +XMLPUBFUN int XMLCALL xmlUCSIsMiscellaneousTechnical (int code); +XMLPUBFUN int XMLCALL xmlUCSIsMongolian (int code); +XMLPUBFUN int XMLCALL xmlUCSIsMusicalSymbols (int code); +XMLPUBFUN int XMLCALL xmlUCSIsMyanmar (int code); +XMLPUBFUN int XMLCALL xmlUCSIsNumberForms (int code); +XMLPUBFUN int XMLCALL xmlUCSIsOgham (int code); +XMLPUBFUN int XMLCALL xmlUCSIsOldItalic (int code); +XMLPUBFUN int XMLCALL xmlUCSIsOpticalCharacterRecognition (int code); +XMLPUBFUN int XMLCALL xmlUCSIsOriya (int code); +XMLPUBFUN int XMLCALL xmlUCSIsOsmanya (int code); +XMLPUBFUN int XMLCALL xmlUCSIsPhoneticExtensions (int code); +XMLPUBFUN int XMLCALL xmlUCSIsPrivateUse (int code); +XMLPUBFUN int XMLCALL xmlUCSIsPrivateUseArea (int code); +XMLPUBFUN int XMLCALL xmlUCSIsRunic (int code); +XMLPUBFUN int XMLCALL xmlUCSIsShavian (int code); +XMLPUBFUN int XMLCALL xmlUCSIsSinhala (int code); +XMLPUBFUN int XMLCALL xmlUCSIsSmallFormVariants (int code); +XMLPUBFUN int XMLCALL xmlUCSIsSpacingModifierLetters (int code); +XMLPUBFUN int XMLCALL xmlUCSIsSpecials (int code); +XMLPUBFUN int XMLCALL xmlUCSIsSuperscriptsandSubscripts (int code); +XMLPUBFUN int XMLCALL xmlUCSIsSupplementalArrowsA (int code); +XMLPUBFUN int XMLCALL xmlUCSIsSupplementalArrowsB (int code); +XMLPUBFUN int XMLCALL xmlUCSIsSupplementalMathematicalOperators (int code); +XMLPUBFUN int XMLCALL xmlUCSIsSupplementaryPrivateUseAreaA (int code); +XMLPUBFUN int XMLCALL xmlUCSIsSupplementaryPrivateUseAreaB (int code); +XMLPUBFUN int XMLCALL xmlUCSIsSyriac (int code); +XMLPUBFUN int XMLCALL xmlUCSIsTagalog (int code); +XMLPUBFUN int XMLCALL xmlUCSIsTagbanwa (int code); +XMLPUBFUN int XMLCALL xmlUCSIsTags (int code); +XMLPUBFUN int XMLCALL xmlUCSIsTaiLe (int code); +XMLPUBFUN int XMLCALL xmlUCSIsTaiXuanJingSymbols (int code); +XMLPUBFUN int XMLCALL xmlUCSIsTamil (int code); +XMLPUBFUN int XMLCALL xmlUCSIsTelugu (int code); +XMLPUBFUN int XMLCALL xmlUCSIsThaana (int code); +XMLPUBFUN int XMLCALL xmlUCSIsThai (int code); +XMLPUBFUN int XMLCALL xmlUCSIsTibetan (int code); +XMLPUBFUN int XMLCALL xmlUCSIsUgaritic (int code); +XMLPUBFUN int XMLCALL xmlUCSIsUnifiedCanadianAboriginalSyllabics (int code); +XMLPUBFUN int XMLCALL xmlUCSIsVariationSelectors (int code); +XMLPUBFUN int XMLCALL xmlUCSIsVariationSelectorsSupplement (int code); +XMLPUBFUN int XMLCALL xmlUCSIsYiRadicals (int code); +XMLPUBFUN int XMLCALL xmlUCSIsYiSyllables (int code); +XMLPUBFUN int XMLCALL xmlUCSIsYijingHexagramSymbols (int code); + +XMLPUBFUN int XMLCALL xmlUCSIsBlock (int code, const char *block); + +XMLPUBFUN int XMLCALL xmlUCSIsCatC (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatCc (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatCf (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatCo (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatCs (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatL (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatLl (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatLm (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatLo (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatLt (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatLu (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatM (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatMc (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatMe (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatMn (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatN (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatNd (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatNl (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatNo (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatP (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatPc (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatPd (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatPe (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatPf (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatPi (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatPo (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatPs (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatS (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatSc (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatSk (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatSm (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatSo (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatZ (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatZl (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatZp (int code); +XMLPUBFUN int XMLCALL xmlUCSIsCatZs (int code); + +XMLPUBFUN int XMLCALL xmlUCSIsCat (int code, const char *cat); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_UNICODE_ENABLED */ + +#endif /* __XML_UNICODE_H__ */ diff --git a/android/native/libxml2/libxml/xmlversion.h b/android/native/libxml2/libxml/xmlversion.h new file mode 100644 index 0000000000..fc9320617c --- /dev/null +++ b/android/native/libxml2/libxml/xmlversion.h @@ -0,0 +1,449 @@ +/* + * Summary: compile-time version informations + * Description: compile-time version informations for the XML library + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_VERSION_H__ +#define __XML_VERSION_H__ + +#include "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 XMLCALL xmlCheckVersion(int version); +#endif /* LIBXML2_COMPILING_MSCCDEF */ + +/** + * LIBXML_DOTTED_VERSION: + * + * the version string like "1.2.3" + */ +#define LIBXML_DOTTED_VERSION "2.7.8" + +/** + * LIBXML_VERSION: + * + * the version number: 1.2.3 value is 10203 + */ +#define LIBXML_VERSION 20708 + +/** + * LIBXML_VERSION_STRING: + * + * the version number string, 1.2.3 value is "10203" + */ +#define LIBXML_VERSION_STRING "20708" + +/** + * LIBXML_VERSION_EXTRA: + * + * extra version information, used to show a CVS compilation + */ +#define LIBXML_VERSION_EXTRA "-GITv2.7.8-56-g8973d58" + +/** + * LIBXML_TEST_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(20708); + +#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 */ + +/** + * LIBXML_THREAD_ENABLED: + * + * Whether the thread support is configured in + */ +#if 0 +#if defined(_REENTRANT) || defined(__MT__) || \ + (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE - 0 >= 199506L)) +#define LIBXML_THREAD_ENABLED +#endif +#endif + +/** + * LIBXML_TREE_ENABLED: + * + * Whether the DOM like tree manipulation API support is configured in + */ +#if 1 +#define LIBXML_TREE_ENABLED +#endif + +/** + * LIBXML_OUTPUT_ENABLED: + * + * Whether the serialization/saving support is configured in + */ +#if 1 +#define LIBXML_OUTPUT_ENABLED +#endif + +/** + * LIBXML_PUSH_ENABLED: + * + * Whether the push parsing interfaces are configured in + */ +#if 1 +#define LIBXML_PUSH_ENABLED +#endif + +/** + * LIBXML_READER_ENABLED: + * + * Whether the xmlReader parsing interface is configured in + */ +#if 1 +#define LIBXML_READER_ENABLED +#endif + +/** + * LIBXML_PATTERN_ENABLED: + * + * Whether the xmlPattern node selection interface is configured in + */ +#if 0 +#define LIBXML_PATTERN_ENABLED +#endif + +/** + * LIBXML_WRITER_ENABLED: + * + * Whether the xmlWriter saving interface is configured in + */ +#if 1 +#define LIBXML_WRITER_ENABLED +#endif + +/** + * LIBXML_SAX1_ENABLED: + * + * Whether the older SAX1 interface is configured in + */ +#if 1 +#define LIBXML_SAX1_ENABLED +#endif + +/** + * LIBXML_VALID_ENABLED: + * + * Whether the DTD validation support is configured in + */ +#if 0 +#define LIBXML_VALID_ENABLED +#endif + +/** + * LIBXML_LEGACY_ENABLED: + * + * Whether the deprecated APIs are compiled in for compatibility + */ +#if 0 +#define LIBXML_LEGACY_ENABLED +#endif + +/** + * LIBXML_C14N_ENABLED: + * + * Whether the Canonicalization support is configured in + */ +#if 0 +#define LIBXML_C14N_ENABLED +#endif + +/** + * LIBXML_CATALOG_ENABLED: + * + * Whether the Catalog support is configured in + */ +#if 0 +#define LIBXML_CATALOG_ENABLED +#endif + +/** + * LIBXML_DOCB_ENABLED: + * + * Whether the SGML Docbook support is configured in + */ +#if 0 +#define LIBXML_DOCB_ENABLED +#endif + +/** + * LIBXML_XPATH_ENABLED: + * + * Whether XPath is configured in + */ +#if 1 +#define LIBXML_XPATH_ENABLED +#endif + +/** + * LIBXML_XPTR_ENABLED: + * + * Whether XPointer is configured in + */ +#if 1 +#define LIBXML_XPTR_ENABLED +#endif + +/** + * LIBXML_XINCLUDE_ENABLED: + * + * Whether XInclude is configured in + */ +#if 0 +#define LIBXML_XINCLUDE_ENABLED +#endif + +/** + * LIBXML_ICONV_ENABLED: + * + * Whether iconv support is available + */ +#if 0 +#define LIBXML_ICONV_ENABLED +#endif + +/** + * LIBXML_ICU_ENABLED: + * + * Whether icu support is available + */ +#if 1 +#define LIBXML_ICU_ENABLED +#endif + +/** + * LIBXML_ISO8859X_ENABLED: + * + * Whether ISO-8859-* support is made available in case iconv is not + */ +#if 1 +#define LIBXML_ISO8859X_ENABLED +#endif + +/** + * LIBXML_DEBUG_ENABLED: + * + * Whether Debugging module is configured in + */ +#if 0 +#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: + * + * Whether the runtime debugging is configured in + */ +#if 0 +#define LIBXML_DEBUG_RUNTIME +#endif + +/** + * LIBXML_UNICODE_ENABLED: + * + * Whether the Unicode related interfaces are compiled in + */ +#if 0 +#define LIBXML_UNICODE_ENABLED +#endif + +/** + * LIBXML_REGEXP_ENABLED: + * + * Whether the regular expressions interfaces are compiled in + */ +#if 0 +#define LIBXML_REGEXP_ENABLED +#endif + +/** + * LIBXML_AUTOMATA_ENABLED: + * + * Whether the automata interfaces are compiled in + */ +#if 1 +#define LIBXML_AUTOMATA_ENABLED +#endif + +/** + * LIBXML_EXPR_ENABLED: + * + * Whether the formal expressions interfaces are compiled in + */ +#if 0 +#define LIBXML_EXPR_ENABLED +#endif + +/** + * LIBXML_SCHEMAS_ENABLED: + * + * Whether the Schemas validation interfaces are compiled in + */ +#if 0 +#define LIBXML_SCHEMAS_ENABLED +#endif + +/** + * LIBXML_SCHEMATRON_ENABLED: + * + * Whether the Schematron validation interfaces are compiled in + */ +#if 0 +#define LIBXML_SCHEMATRON_ENABLED +#endif + +/** + * LIBXML_MODULES_ENABLED: + * + * Whether the module interfaces are compiled in + */ +#if 1 +#define LIBXML_MODULES_ENABLED +/** + * LIBXML_MODULE_EXTENSION: + * + * the string suffix used by dynamic modules (usually shared libraries) + */ +#define LIBXML_MODULE_EXTENSION "" +#endif + +/** + * LIBXML_ZLIB_ENABLED: + * + * Whether the Zlib support is compiled in + */ +#if 0 +#define LIBXML_ZLIB_ENABLED +#endif + +/** + * LIBXML_LZMA_ENABLED: + * + * Whether the Lzma support is compiled in + */ +#if 0 +#define LIBXML_LZMA_ENABLED +#endif + +#ifdef __GNUC__ +#ifdef HAVE_ANSIDECL_H +#include +#endif + +/** + * ATTRIBUTE_UNUSED: + * + * Macro used to signal to GCC unused function parameters + */ + +#ifndef ATTRIBUTE_UNUSED +#define ATTRIBUTE_UNUSED __attribute__((unused)) +#endif + +/** + * LIBXML_ATTR_ALLOC_SIZE: + * + * Macro used to indicate to GCC this is an allocator function + */ + +#ifndef LIBXML_ATTR_ALLOC_SIZE +# if ((__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 + +/** + * LIBXML_ATTR_FORMAT: + * + * Macro used to indicate to GCC the parameter are printf like + */ + +#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 + +#else /* ! __GNUC__ */ +/** + * ATTRIBUTE_UNUSED: + * + * Macro used to signal to GCC unused function parameters + */ +#define ATTRIBUTE_UNUSED +/** + * LIBXML_ATTR_ALLOC_SIZE: + * + * Macro used to indicate to GCC this is an allocator function + */ +#define LIBXML_ATTR_ALLOC_SIZE(x) +/** + * LIBXML_ATTR_FORMAT: + * + * Macro used to indicate to GCC the parameter are printf like + */ +#define LIBXML_ATTR_FORMAT(fmt,args) +#endif /* __GNUC__ */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif + + diff --git a/android/native/libxml2/libxml/xmlwriter.h b/android/native/libxml2/libxml/xmlwriter.h new file mode 100644 index 0000000000..91e683c88c --- /dev/null +++ b/android/native/libxml2/libxml/xmlwriter.h @@ -0,0 +1,485 @@ + +/* + * Summary: text writing API for XML + * Description: text writing API for XML + * + * Copy: See Copyright for the status of this software. + * + * Author: Alfred Mickautsch + */ + +#ifndef __XML_XMLWRITER_H__ +#define __XML_XMLWRITER_H__ + +#include + +#ifdef LIBXML_WRITER_ENABLED + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + typedef struct _xmlTextWriter xmlTextWriter; + typedef xmlTextWriter *xmlTextWriterPtr; + +/* + * Constructors & Destructor + */ + XMLPUBFUN xmlTextWriterPtr XMLCALL + xmlNewTextWriter(xmlOutputBufferPtr out); + XMLPUBFUN xmlTextWriterPtr XMLCALL + xmlNewTextWriterFilename(const char *uri, int compression); + XMLPUBFUN xmlTextWriterPtr XMLCALL + xmlNewTextWriterMemory(xmlBufferPtr buf, int compression); + XMLPUBFUN xmlTextWriterPtr XMLCALL + xmlNewTextWriterPushParser(xmlParserCtxtPtr ctxt, int compression); + XMLPUBFUN xmlTextWriterPtr XMLCALL + xmlNewTextWriterDoc(xmlDocPtr * doc, int compression); + XMLPUBFUN xmlTextWriterPtr XMLCALL + xmlNewTextWriterTree(xmlDocPtr doc, xmlNodePtr node, + int compression); + XMLPUBFUN void XMLCALL xmlFreeTextWriter(xmlTextWriterPtr writer); + +/* + * Functions + */ + + +/* + * Document + */ + XMLPUBFUN int XMLCALL + xmlTextWriterStartDocument(xmlTextWriterPtr writer, + const char *version, + const char *encoding, + const char *standalone); + XMLPUBFUN int XMLCALL xmlTextWriterEndDocument(xmlTextWriterPtr + writer); + +/* + * Comments + */ + XMLPUBFUN int XMLCALL xmlTextWriterStartComment(xmlTextWriterPtr + writer); + XMLPUBFUN int XMLCALL xmlTextWriterEndComment(xmlTextWriterPtr writer); + XMLPUBFUN int XMLCALL + xmlTextWriterWriteFormatComment(xmlTextWriterPtr writer, + const char *format, ...) + LIBXML_ATTR_FORMAT(2,3); + XMLPUBFUN int XMLCALL + xmlTextWriterWriteVFormatComment(xmlTextWriterPtr writer, + const char *format, + va_list argptr) + LIBXML_ATTR_FORMAT(2,0); + XMLPUBFUN int XMLCALL xmlTextWriterWriteComment(xmlTextWriterPtr + writer, + const xmlChar * + content); + +/* + * Elements + */ + XMLPUBFUN int XMLCALL + xmlTextWriterStartElement(xmlTextWriterPtr writer, + const xmlChar * name); + XMLPUBFUN int XMLCALL xmlTextWriterStartElementNS(xmlTextWriterPtr + writer, + const xmlChar * + prefix, + const xmlChar * name, + const xmlChar * + namespaceURI); + XMLPUBFUN int XMLCALL xmlTextWriterEndElement(xmlTextWriterPtr writer); + XMLPUBFUN int XMLCALL xmlTextWriterFullEndElement(xmlTextWriterPtr + writer); + +/* + * Elements conveniency functions + */ + XMLPUBFUN int XMLCALL + xmlTextWriterWriteFormatElement(xmlTextWriterPtr writer, + const xmlChar * name, + const char *format, ...) + LIBXML_ATTR_FORMAT(3,4); + XMLPUBFUN int XMLCALL + xmlTextWriterWriteVFormatElement(xmlTextWriterPtr writer, + const xmlChar * name, + const char *format, + va_list argptr) + LIBXML_ATTR_FORMAT(3,0); + XMLPUBFUN int XMLCALL xmlTextWriterWriteElement(xmlTextWriterPtr + writer, + const xmlChar * name, + const xmlChar * + content); + XMLPUBFUN int XMLCALL + xmlTextWriterWriteFormatElementNS(xmlTextWriterPtr writer, + const xmlChar * prefix, + const xmlChar * name, + const xmlChar * namespaceURI, + const char *format, ...) + LIBXML_ATTR_FORMAT(5,6); + XMLPUBFUN int XMLCALL + xmlTextWriterWriteVFormatElementNS(xmlTextWriterPtr writer, + const xmlChar * prefix, + const xmlChar * name, + const xmlChar * namespaceURI, + const char *format, + va_list argptr) + LIBXML_ATTR_FORMAT(5,0); + XMLPUBFUN int XMLCALL xmlTextWriterWriteElementNS(xmlTextWriterPtr + writer, + const xmlChar * + prefix, + const xmlChar * name, + const xmlChar * + namespaceURI, + const xmlChar * + content); + +/* + * Text + */ + XMLPUBFUN int XMLCALL + xmlTextWriterWriteFormatRaw(xmlTextWriterPtr writer, + const char *format, ...) + LIBXML_ATTR_FORMAT(2,3); + XMLPUBFUN int XMLCALL + xmlTextWriterWriteVFormatRaw(xmlTextWriterPtr writer, + const char *format, va_list argptr) + LIBXML_ATTR_FORMAT(2,0); + XMLPUBFUN int XMLCALL + xmlTextWriterWriteRawLen(xmlTextWriterPtr writer, + const xmlChar * content, int len); + XMLPUBFUN int XMLCALL + xmlTextWriterWriteRaw(xmlTextWriterPtr writer, + const xmlChar * content); + XMLPUBFUN int XMLCALL xmlTextWriterWriteFormatString(xmlTextWriterPtr + writer, + const char + *format, ...) + LIBXML_ATTR_FORMAT(2,3); + XMLPUBFUN int XMLCALL xmlTextWriterWriteVFormatString(xmlTextWriterPtr + writer, + const char + *format, + va_list argptr) + LIBXML_ATTR_FORMAT(2,0); + XMLPUBFUN int XMLCALL xmlTextWriterWriteString(xmlTextWriterPtr writer, + const xmlChar * + content); + XMLPUBFUN int XMLCALL xmlTextWriterWriteBase64(xmlTextWriterPtr writer, + const char *data, + int start, int len); + XMLPUBFUN int XMLCALL xmlTextWriterWriteBinHex(xmlTextWriterPtr writer, + const char *data, + int start, int len); + +/* + * Attributes + */ + XMLPUBFUN int XMLCALL + xmlTextWriterStartAttribute(xmlTextWriterPtr writer, + const xmlChar * name); + XMLPUBFUN int XMLCALL xmlTextWriterStartAttributeNS(xmlTextWriterPtr + writer, + const xmlChar * + prefix, + const xmlChar * + name, + const xmlChar * + namespaceURI); + XMLPUBFUN int XMLCALL xmlTextWriterEndAttribute(xmlTextWriterPtr + writer); + +/* + * Attributes conveniency functions + */ + XMLPUBFUN int XMLCALL + xmlTextWriterWriteFormatAttribute(xmlTextWriterPtr writer, + const xmlChar * name, + const char *format, ...) + LIBXML_ATTR_FORMAT(3,4); + XMLPUBFUN int XMLCALL + xmlTextWriterWriteVFormatAttribute(xmlTextWriterPtr writer, + const xmlChar * name, + const char *format, + va_list argptr) + LIBXML_ATTR_FORMAT(3,0); + XMLPUBFUN int XMLCALL xmlTextWriterWriteAttribute(xmlTextWriterPtr + writer, + const xmlChar * name, + const xmlChar * + content); + XMLPUBFUN int XMLCALL + xmlTextWriterWriteFormatAttributeNS(xmlTextWriterPtr writer, + const xmlChar * prefix, + const xmlChar * name, + const xmlChar * namespaceURI, + const char *format, ...) + LIBXML_ATTR_FORMAT(5,6); + XMLPUBFUN int XMLCALL + xmlTextWriterWriteVFormatAttributeNS(xmlTextWriterPtr writer, + const xmlChar * prefix, + const xmlChar * name, + const xmlChar * namespaceURI, + const char *format, + va_list argptr) + LIBXML_ATTR_FORMAT(5,0); + XMLPUBFUN int XMLCALL xmlTextWriterWriteAttributeNS(xmlTextWriterPtr + writer, + const xmlChar * + prefix, + const xmlChar * + name, + const xmlChar * + namespaceURI, + const xmlChar * + content); + +/* + * PI's + */ + XMLPUBFUN int XMLCALL + xmlTextWriterStartPI(xmlTextWriterPtr writer, + const xmlChar * target); + XMLPUBFUN int XMLCALL xmlTextWriterEndPI(xmlTextWriterPtr writer); + +/* + * PI conveniency functions + */ + XMLPUBFUN int XMLCALL + xmlTextWriterWriteFormatPI(xmlTextWriterPtr writer, + const xmlChar * target, + const char *format, ...) + LIBXML_ATTR_FORMAT(3,4); + XMLPUBFUN int XMLCALL + xmlTextWriterWriteVFormatPI(xmlTextWriterPtr writer, + const xmlChar * target, + const char *format, va_list argptr) + LIBXML_ATTR_FORMAT(3,0); + XMLPUBFUN int XMLCALL + xmlTextWriterWritePI(xmlTextWriterPtr writer, + const xmlChar * target, + const xmlChar * content); + +/** + * xmlTextWriterWriteProcessingInstruction: + * + * This macro maps to xmlTextWriterWritePI + */ +#define xmlTextWriterWriteProcessingInstruction xmlTextWriterWritePI + +/* + * CDATA + */ + XMLPUBFUN int XMLCALL xmlTextWriterStartCDATA(xmlTextWriterPtr writer); + XMLPUBFUN int XMLCALL xmlTextWriterEndCDATA(xmlTextWriterPtr writer); + +/* + * CDATA conveniency functions + */ + XMLPUBFUN int XMLCALL + xmlTextWriterWriteFormatCDATA(xmlTextWriterPtr writer, + const char *format, ...) + LIBXML_ATTR_FORMAT(2,3); + XMLPUBFUN int XMLCALL + xmlTextWriterWriteVFormatCDATA(xmlTextWriterPtr writer, + const char *format, va_list argptr) + LIBXML_ATTR_FORMAT(2,0); + XMLPUBFUN int XMLCALL + xmlTextWriterWriteCDATA(xmlTextWriterPtr writer, + const xmlChar * content); + +/* + * DTD + */ + XMLPUBFUN int XMLCALL + xmlTextWriterStartDTD(xmlTextWriterPtr writer, + const xmlChar * name, + const xmlChar * pubid, + const xmlChar * sysid); + XMLPUBFUN int XMLCALL xmlTextWriterEndDTD(xmlTextWriterPtr writer); + +/* + * DTD conveniency functions + */ + XMLPUBFUN int XMLCALL + xmlTextWriterWriteFormatDTD(xmlTextWriterPtr writer, + const xmlChar * name, + const xmlChar * pubid, + const xmlChar * sysid, + const char *format, ...) + LIBXML_ATTR_FORMAT(5,6); + XMLPUBFUN int XMLCALL + xmlTextWriterWriteVFormatDTD(xmlTextWriterPtr writer, + const xmlChar * name, + const xmlChar * pubid, + const xmlChar * sysid, + const char *format, va_list argptr) + LIBXML_ATTR_FORMAT(5,0); + XMLPUBFUN int XMLCALL + xmlTextWriterWriteDTD(xmlTextWriterPtr writer, + const xmlChar * name, + const xmlChar * pubid, + const xmlChar * sysid, + const xmlChar * subset); + +/** + * xmlTextWriterWriteDocType: + * + * this macro maps to xmlTextWriterWriteDTD + */ +#define xmlTextWriterWriteDocType xmlTextWriterWriteDTD + +/* + * DTD element definition + */ + XMLPUBFUN int XMLCALL + xmlTextWriterStartDTDElement(xmlTextWriterPtr writer, + const xmlChar * name); + XMLPUBFUN int XMLCALL xmlTextWriterEndDTDElement(xmlTextWriterPtr + writer); + +/* + * DTD element definition conveniency functions + */ + XMLPUBFUN int XMLCALL + xmlTextWriterWriteFormatDTDElement(xmlTextWriterPtr writer, + const xmlChar * name, + const char *format, ...) + LIBXML_ATTR_FORMAT(3,4); + XMLPUBFUN int XMLCALL + xmlTextWriterWriteVFormatDTDElement(xmlTextWriterPtr writer, + const xmlChar * name, + const char *format, + va_list argptr) + LIBXML_ATTR_FORMAT(3,0); + XMLPUBFUN int XMLCALL xmlTextWriterWriteDTDElement(xmlTextWriterPtr + writer, + const xmlChar * + name, + const xmlChar * + content); + +/* + * DTD attribute list definition + */ + XMLPUBFUN int XMLCALL + xmlTextWriterStartDTDAttlist(xmlTextWriterPtr writer, + const xmlChar * name); + XMLPUBFUN int XMLCALL xmlTextWriterEndDTDAttlist(xmlTextWriterPtr + writer); + +/* + * DTD attribute list definition conveniency functions + */ + XMLPUBFUN int XMLCALL + xmlTextWriterWriteFormatDTDAttlist(xmlTextWriterPtr writer, + const xmlChar * name, + const char *format, ...) + LIBXML_ATTR_FORMAT(3,4); + XMLPUBFUN int XMLCALL + xmlTextWriterWriteVFormatDTDAttlist(xmlTextWriterPtr writer, + const xmlChar * name, + const char *format, + va_list argptr) + LIBXML_ATTR_FORMAT(3,0); + XMLPUBFUN int XMLCALL xmlTextWriterWriteDTDAttlist(xmlTextWriterPtr + writer, + const xmlChar * + name, + const xmlChar * + content); + +/* + * DTD entity definition + */ + XMLPUBFUN int XMLCALL + xmlTextWriterStartDTDEntity(xmlTextWriterPtr writer, + int pe, const xmlChar * name); + XMLPUBFUN int XMLCALL xmlTextWriterEndDTDEntity(xmlTextWriterPtr + writer); + +/* + * DTD entity definition conveniency functions + */ + XMLPUBFUN int XMLCALL + xmlTextWriterWriteFormatDTDInternalEntity(xmlTextWriterPtr writer, + int pe, + const xmlChar * name, + const char *format, ...) + LIBXML_ATTR_FORMAT(4,5); + XMLPUBFUN int XMLCALL + xmlTextWriterWriteVFormatDTDInternalEntity(xmlTextWriterPtr writer, + int pe, + const xmlChar * name, + const char *format, + va_list argptr) + LIBXML_ATTR_FORMAT(4,0); + XMLPUBFUN int XMLCALL + xmlTextWriterWriteDTDInternalEntity(xmlTextWriterPtr writer, + int pe, + const xmlChar * name, + const xmlChar * content); + XMLPUBFUN int XMLCALL + xmlTextWriterWriteDTDExternalEntity(xmlTextWriterPtr writer, + int pe, + const xmlChar * name, + const xmlChar * pubid, + const xmlChar * sysid, + const xmlChar * ndataid); + XMLPUBFUN int XMLCALL + xmlTextWriterWriteDTDExternalEntityContents(xmlTextWriterPtr + writer, + const xmlChar * pubid, + const xmlChar * sysid, + const xmlChar * + ndataid); + XMLPUBFUN int XMLCALL xmlTextWriterWriteDTDEntity(xmlTextWriterPtr + writer, int pe, + const xmlChar * name, + const xmlChar * + pubid, + const xmlChar * + sysid, + const xmlChar * + ndataid, + const xmlChar * + content); + +/* + * DTD notation definition + */ + XMLPUBFUN int XMLCALL + xmlTextWriterWriteDTDNotation(xmlTextWriterPtr writer, + const xmlChar * name, + const xmlChar * pubid, + const xmlChar * sysid); + +/* + * Indentation + */ + XMLPUBFUN int XMLCALL + xmlTextWriterSetIndent(xmlTextWriterPtr writer, int indent); + XMLPUBFUN int XMLCALL + xmlTextWriterSetIndentString(xmlTextWriterPtr writer, + const xmlChar * str); + +/* + * misc + */ + XMLPUBFUN int XMLCALL xmlTextWriterFlush(xmlTextWriterPtr writer); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_WRITER_ENABLED */ + +#endif /* __XML_XMLWRITER_H__ */ diff --git a/android/native/libxml2/libxml/xpath.h b/android/native/libxml2/libxml/xpath.h new file mode 100644 index 0000000000..ddd9dd82b5 --- /dev/null +++ b/android/native/libxml2/libxml/xpath.h @@ -0,0 +1,549 @@ +/* + * Summary: XML Path Language implementation + * Description: API for the XML Path Language implementation + * + * XML Path Language implementation + * XPath is a language for addressing parts of an XML document, + * designed to be used by both XSLT and XPointer + * http://www.w3.org/TR/xpath + * + * Implements + * W3C Recommendation 16 November 1999 + * http://www.w3.org/TR/1999/REC-xpath-19991116 + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XPATH_H__ +#define __XML_XPATH_H__ + +#include + +#ifdef LIBXML_XPATH_ENABLED + +#include +#include +#include +#endif /* LIBXML_XPATH_ENABLED */ + +#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) +#ifdef __cplusplus +extern "C" { +#endif +#endif /* LIBXML_XPATH_ENABLED or LIBXML_SCHEMAS_ENABLED */ + +#ifdef LIBXML_XPATH_ENABLED + +typedef struct _xmlXPathContext xmlXPathContext; +typedef xmlXPathContext *xmlXPathContextPtr; +typedef struct _xmlXPathParserContext xmlXPathParserContext; +typedef xmlXPathParserContext *xmlXPathParserContextPtr; + +/** + * The set of XPath error codes. + */ + +typedef enum { + XPATH_EXPRESSION_OK = 0, + XPATH_NUMBER_ERROR, + XPATH_UNFINISHED_LITERAL_ERROR, + XPATH_START_LITERAL_ERROR, + XPATH_VARIABLE_REF_ERROR, + XPATH_UNDEF_VARIABLE_ERROR, + XPATH_INVALID_PREDICATE_ERROR, + XPATH_EXPR_ERROR, + XPATH_UNCLOSED_ERROR, + XPATH_UNKNOWN_FUNC_ERROR, + XPATH_INVALID_OPERAND, + XPATH_INVALID_TYPE, + XPATH_INVALID_ARITY, + XPATH_INVALID_CTXT_SIZE, + XPATH_INVALID_CTXT_POSITION, + XPATH_MEMORY_ERROR, + XPTR_SYNTAX_ERROR, + XPTR_RESOURCE_ERROR, + XPTR_SUB_RESOURCE_ERROR, + XPATH_UNDEF_PREFIX_ERROR, + XPATH_ENCODING_ERROR, + XPATH_INVALID_CHAR_ERROR, + XPATH_INVALID_CTXT, + XPATH_STACK_ERROR +} xmlXPathError; + +/* + * A node-set (an unordered collection of nodes without duplicates). + */ +typedef struct _xmlNodeSet xmlNodeSet; +typedef xmlNodeSet *xmlNodeSetPtr; +struct _xmlNodeSet { + int nodeNr; /* number of nodes in the set */ + int nodeMax; /* size of the array as allocated */ + xmlNodePtr *nodeTab; /* array of nodes in no particular order */ + /* @@ with_ns to check wether namespace nodes should be looked at @@ */ +}; + +/* + * An expression is evaluated to yield an object, which + * has one of the following four basic types: + * - node-set + * - boolean + * - number + * - string + * + * @@ XPointer will add more types ! + */ + +typedef enum { + XPATH_UNDEFINED = 0, + XPATH_NODESET = 1, + XPATH_BOOLEAN = 2, + XPATH_NUMBER = 3, + XPATH_STRING = 4, + XPATH_POINT = 5, + XPATH_RANGE = 6, + XPATH_LOCATIONSET = 7, + XPATH_USERS = 8, + XPATH_XSLT_TREE = 9 /* An XSLT value tree, non modifiable */ +} xmlXPathObjectType; + +typedef struct _xmlXPathObject xmlXPathObject; +typedef xmlXPathObject *xmlXPathObjectPtr; +struct _xmlXPathObject { + xmlXPathObjectType type; + xmlNodeSetPtr nodesetval; + int boolval; + double floatval; + xmlChar *stringval; + void *user; + int index; + void *user2; + int index2; +}; + +/** + * xmlXPathConvertFunc: + * @obj: an XPath object + * @type: the number of the target type + * + * A conversion function is associated to a type and used to cast + * the new type to primitive values. + * + * Returns -1 in case of error, 0 otherwise + */ +typedef int (*xmlXPathConvertFunc) (xmlXPathObjectPtr obj, int type); + +/* + * Extra type: a name and a conversion function. + */ + +typedef struct _xmlXPathType xmlXPathType; +typedef xmlXPathType *xmlXPathTypePtr; +struct _xmlXPathType { + const xmlChar *name; /* the type name */ + xmlXPathConvertFunc func; /* the conversion function */ +}; + +/* + * Extra variable: a name and a value. + */ + +typedef struct _xmlXPathVariable xmlXPathVariable; +typedef xmlXPathVariable *xmlXPathVariablePtr; +struct _xmlXPathVariable { + const xmlChar *name; /* the variable name */ + xmlXPathObjectPtr value; /* the value */ +}; + +/** + * xmlXPathEvalFunc: + * @ctxt: an XPath parser context + * @nargs: the number of arguments passed to the function + * + * An XPath evaluation function, the parameters are on the XPath context stack. + */ + +typedef void (*xmlXPathEvalFunc)(xmlXPathParserContextPtr ctxt, + int nargs); + +/* + * Extra function: a name and a evaluation function. + */ + +typedef struct _xmlXPathFunct xmlXPathFunct; +typedef xmlXPathFunct *xmlXPathFuncPtr; +struct _xmlXPathFunct { + const xmlChar *name; /* the function name */ + xmlXPathEvalFunc func; /* the evaluation function */ +}; + +/** + * xmlXPathAxisFunc: + * @ctxt: the XPath interpreter context + * @cur: the previous node being explored on that axis + * + * An axis traversal function. To traverse an axis, the engine calls + * the first time with cur == NULL and repeat until the function returns + * NULL indicating the end of the axis traversal. + * + * Returns the next node in that axis or NULL if at the end of the axis. + */ + +typedef xmlXPathObjectPtr (*xmlXPathAxisFunc) (xmlXPathParserContextPtr ctxt, + xmlXPathObjectPtr cur); + +/* + * Extra axis: a name and an axis function. + */ + +typedef struct _xmlXPathAxis xmlXPathAxis; +typedef xmlXPathAxis *xmlXPathAxisPtr; +struct _xmlXPathAxis { + const xmlChar *name; /* the axis name */ + xmlXPathAxisFunc func; /* the search function */ +}; + +/** + * xmlXPathFunction: + * @ctxt: the XPath interprestation context + * @nargs: the number of arguments + * + * An XPath function. + * The arguments (if any) are popped out from the context stack + * and the result is pushed on the stack. + */ + +typedef void (*xmlXPathFunction) (xmlXPathParserContextPtr ctxt, int nargs); + +/* + * Function and Variable Lookup. + */ + +/** + * xmlXPathVariableLookupFunc: + * @ctxt: an XPath context + * @name: name of the variable + * @ns_uri: the namespace name hosting this variable + * + * Prototype for callbacks used to plug variable lookup in the XPath + * engine. + * + * Returns the XPath object value or NULL if not found. + */ +typedef xmlXPathObjectPtr (*xmlXPathVariableLookupFunc) (void *ctxt, + const xmlChar *name, + const xmlChar *ns_uri); + +/** + * xmlXPathFuncLookupFunc: + * @ctxt: an XPath context + * @name: name of the function + * @ns_uri: the namespace name hosting this function + * + * Prototype for callbacks used to plug function lookup in the XPath + * engine. + * + * Returns the XPath function or NULL if not found. + */ +typedef xmlXPathFunction (*xmlXPathFuncLookupFunc) (void *ctxt, + const xmlChar *name, + const xmlChar *ns_uri); + +/** + * xmlXPathFlags: + * Flags for XPath engine compilation and runtime + */ +/** + * XML_XPATH_CHECKNS: + * + * check namespaces at compilation + */ +#define XML_XPATH_CHECKNS (1<<0) +/** + * XML_XPATH_NOVAR: + * + * forbid variables in expression + */ +#define XML_XPATH_NOVAR (1<<1) + +/** + * xmlXPathContext: + * + * Expression evaluation occurs with respect to a context. + * he context consists of: + * - a node (the context node) + * - a node list (the context node list) + * - a set of variable bindings + * - a function library + * - the set of namespace declarations in scope for the expression + * Following the switch to hash tables, this need to be trimmed up at + * the next binary incompatible release. + * The node may be modified when the context is passed to libxml2 + * for an XPath evaluation so you may need to initialize it again + * before the next call. + */ + +struct _xmlXPathContext { + xmlDocPtr doc; /* The current document */ + xmlNodePtr node; /* The current node */ + + int nb_variables_unused; /* unused (hash table) */ + int max_variables_unused; /* unused (hash table) */ + xmlHashTablePtr varHash; /* Hash table of defined variables */ + + int nb_types; /* number of defined types */ + int max_types; /* max number of types */ + xmlXPathTypePtr types; /* Array of defined types */ + + int nb_funcs_unused; /* unused (hash table) */ + int max_funcs_unused; /* unused (hash table) */ + xmlHashTablePtr funcHash; /* Hash table of defined funcs */ + + int nb_axis; /* number of defined axis */ + int max_axis; /* max number of axis */ + xmlXPathAxisPtr axis; /* Array of defined axis */ + + /* the namespace nodes of the context node */ + xmlNsPtr *namespaces; /* Array of namespaces */ + int nsNr; /* number of namespace in scope */ + void *user; /* function to free */ + + /* extra variables */ + int contextSize; /* the context size */ + int proximityPosition; /* the proximity position */ + + /* extra stuff for XPointer */ + int xptr; /* is this an XPointer context? */ + xmlNodePtr here; /* for here() */ + xmlNodePtr origin; /* for origin() */ + + /* the set of namespace declarations in scope for the expression */ + xmlHashTablePtr nsHash; /* The namespaces hash table */ + xmlXPathVariableLookupFunc varLookupFunc;/* variable lookup func */ + void *varLookupData; /* variable lookup data */ + + /* Possibility to link in an extra item */ + void *extra; /* needed for XSLT */ + + /* The function name and URI when calling a function */ + const xmlChar *function; + const xmlChar *functionURI; + + /* function lookup function and data */ + xmlXPathFuncLookupFunc funcLookupFunc;/* function lookup func */ + void *funcLookupData; /* function lookup data */ + + /* temporary namespace lists kept for walking the namespace axis */ + xmlNsPtr *tmpNsList; /* Array of namespaces */ + int tmpNsNr; /* number of namespaces in scope */ + + /* error reporting mechanism */ + void *userData; /* user specific data block */ + xmlStructuredErrorFunc error; /* the callback in case of errors */ + xmlError lastError; /* the last error */ + xmlNodePtr debugNode; /* the source node XSLT */ + + /* dictionary */ + xmlDictPtr dict; /* dictionary if any */ + + int flags; /* flags to control compilation */ + + /* Cache for reusal of XPath objects */ + void *cache; +}; + +/* + * The structure of a compiled expression form is not public. + */ + +typedef struct _xmlXPathCompExpr xmlXPathCompExpr; +typedef xmlXPathCompExpr *xmlXPathCompExprPtr; + +/** + * xmlXPathParserContext: + * + * An XPath parser context. It contains pure parsing informations, + * an xmlXPathContext, and the stack of objects. + */ +struct _xmlXPathParserContext { + const xmlChar *cur; /* the current char being parsed */ + const xmlChar *base; /* the full expression */ + + int error; /* error code */ + + xmlXPathContextPtr context; /* the evaluation context */ + xmlXPathObjectPtr value; /* the current value */ + int valueNr; /* number of values stacked */ + int valueMax; /* max number of values stacked */ + xmlXPathObjectPtr *valueTab; /* stack of values */ + + xmlXPathCompExprPtr comp; /* the precompiled expression */ + int xptr; /* it this an XPointer expression */ + xmlNodePtr ancestor; /* used for walking preceding axis */ + + int valueFrame; /* used to limit Pop on the stack */ +}; + +/************************************************************************ + * * + * Public API * + * * + ************************************************************************/ + +/** + * Objects and Nodesets handling + */ + +XMLPUBVAR double xmlXPathNAN; +XMLPUBVAR double xmlXPathPINF; +XMLPUBVAR double xmlXPathNINF; + +/* These macros may later turn into functions */ +/** + * xmlXPathNodeSetGetLength: + * @ns: a node-set + * + * Implement a functionality similar to the DOM NodeList.length. + * + * Returns the number of nodes in the node-set. + */ +#define xmlXPathNodeSetGetLength(ns) ((ns) ? (ns)->nodeNr : 0) +/** + * xmlXPathNodeSetItem: + * @ns: a node-set + * @index: index of a node in the set + * + * Implements a functionality similar to the DOM NodeList.item(). + * + * Returns the xmlNodePtr at the given @index in @ns or NULL if + * @index is out of range (0 to length-1) + */ +#define xmlXPathNodeSetItem(ns, index) \ + ((((ns) != NULL) && \ + ((index) >= 0) && ((index) < (ns)->nodeNr)) ? \ + (ns)->nodeTab[(index)] \ + : NULL) +/** + * xmlXPathNodeSetIsEmpty: + * @ns: a node-set + * + * Checks whether @ns is empty or not. + * + * Returns %TRUE if @ns is an empty node-set. + */ +#define xmlXPathNodeSetIsEmpty(ns) \ + (((ns) == NULL) || ((ns)->nodeNr == 0) || ((ns)->nodeTab == NULL)) + + +XMLPUBFUN void XMLCALL + xmlXPathFreeObject (xmlXPathObjectPtr obj); +XMLPUBFUN xmlNodeSetPtr XMLCALL + xmlXPathNodeSetCreate (xmlNodePtr val); +XMLPUBFUN void XMLCALL + xmlXPathFreeNodeSetList (xmlXPathObjectPtr obj); +XMLPUBFUN void XMLCALL + xmlXPathFreeNodeSet (xmlNodeSetPtr obj); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPathObjectCopy (xmlXPathObjectPtr val); +XMLPUBFUN int XMLCALL + xmlXPathCmpNodes (xmlNodePtr node1, + xmlNodePtr node2); +/** + * Conversion functions to basic types. + */ +XMLPUBFUN int XMLCALL + xmlXPathCastNumberToBoolean (double val); +XMLPUBFUN int XMLCALL + xmlXPathCastStringToBoolean (const xmlChar * val); +XMLPUBFUN int XMLCALL + xmlXPathCastNodeSetToBoolean(xmlNodeSetPtr ns); +XMLPUBFUN int XMLCALL + xmlXPathCastToBoolean (xmlXPathObjectPtr val); + +XMLPUBFUN double XMLCALL + xmlXPathCastBooleanToNumber (int val); +XMLPUBFUN double XMLCALL + xmlXPathCastStringToNumber (const xmlChar * val); +XMLPUBFUN double XMLCALL + xmlXPathCastNodeToNumber (xmlNodePtr node); +XMLPUBFUN double XMLCALL + xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns); +XMLPUBFUN double XMLCALL + xmlXPathCastToNumber (xmlXPathObjectPtr val); + +XMLPUBFUN xmlChar * XMLCALL + xmlXPathCastBooleanToString (int val); +XMLPUBFUN xmlChar * XMLCALL + xmlXPathCastNumberToString (double val); +XMLPUBFUN xmlChar * XMLCALL + xmlXPathCastNodeToString (xmlNodePtr node); +XMLPUBFUN xmlChar * XMLCALL + xmlXPathCastNodeSetToString (xmlNodeSetPtr ns); +XMLPUBFUN xmlChar * XMLCALL + xmlXPathCastToString (xmlXPathObjectPtr val); + +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPathConvertBoolean (xmlXPathObjectPtr val); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPathConvertNumber (xmlXPathObjectPtr val); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPathConvertString (xmlXPathObjectPtr val); + +/** + * Context handling. + */ +XMLPUBFUN xmlXPathContextPtr XMLCALL + xmlXPathNewContext (xmlDocPtr doc); +XMLPUBFUN void XMLCALL + xmlXPathFreeContext (xmlXPathContextPtr ctxt); +XMLPUBFUN int XMLCALL + xmlXPathContextSetCache(xmlXPathContextPtr ctxt, + int active, + int value, + int options); +/** + * Evaluation functions. + */ +XMLPUBFUN long XMLCALL + xmlXPathOrderDocElems (xmlDocPtr doc); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPathEval (const xmlChar *str, + xmlXPathContextPtr ctx); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPathEvalExpression (const xmlChar *str, + xmlXPathContextPtr ctxt); +XMLPUBFUN int XMLCALL + xmlXPathEvalPredicate (xmlXPathContextPtr ctxt, + xmlXPathObjectPtr res); +/** + * Separate compilation/evaluation entry points. + */ +XMLPUBFUN xmlXPathCompExprPtr XMLCALL + xmlXPathCompile (const xmlChar *str); +XMLPUBFUN xmlXPathCompExprPtr XMLCALL + xmlXPathCtxtCompile (xmlXPathContextPtr ctxt, + const xmlChar *str); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPathCompiledEval (xmlXPathCompExprPtr comp, + xmlXPathContextPtr ctx); +XMLPUBFUN int XMLCALL + xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp, + xmlXPathContextPtr ctxt); +XMLPUBFUN void XMLCALL + xmlXPathFreeCompExpr (xmlXPathCompExprPtr comp); +#endif /* LIBXML_XPATH_ENABLED */ +#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) +XMLPUBFUN void XMLCALL + xmlXPathInit (void); +XMLPUBFUN int XMLCALL + xmlXPathIsNaN (double val); +XMLPUBFUN int XMLCALL + xmlXPathIsInf (double val); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_XPATH_ENABLED or LIBXML_SCHEMAS_ENABLED*/ +#endif /* ! __XML_XPATH_H__ */ diff --git a/android/native/libxml2/libxml/xpathInternals.h b/android/native/libxml2/libxml/xpathInternals.h new file mode 100644 index 0000000000..dcd524343e --- /dev/null +++ b/android/native/libxml2/libxml/xpathInternals.h @@ -0,0 +1,630 @@ +/* + * Summary: internal interfaces for XML Path Language implementation + * Description: internal interfaces for XML Path Language implementation + * used to build new modules on top of XPath like XPointer and + * XSLT + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XPATH_INTERNALS_H__ +#define __XML_XPATH_INTERNALS_H__ + +#include +#include + +#ifdef LIBXML_XPATH_ENABLED + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************ + * * + * Helpers * + * * + ************************************************************************/ + +/* + * Many of these macros may later turn into functions. They + * shouldn't be used in #ifdef's preprocessor instructions. + */ +/** + * xmlXPathSetError: + * @ctxt: an XPath parser context + * @err: an xmlXPathError code + * + * Raises an error. + */ +#define xmlXPathSetError(ctxt, err) \ + { xmlXPatherror((ctxt), __FILE__, __LINE__, (err)); \ + if ((ctxt) != NULL) (ctxt)->error = (err); } + +/** + * xmlXPathSetArityError: + * @ctxt: an XPath parser context + * + * Raises an XPATH_INVALID_ARITY error. + */ +#define xmlXPathSetArityError(ctxt) \ + xmlXPathSetError((ctxt), XPATH_INVALID_ARITY) + +/** + * xmlXPathSetTypeError: + * @ctxt: an XPath parser context + * + * Raises an XPATH_INVALID_TYPE error. + */ +#define xmlXPathSetTypeError(ctxt) \ + xmlXPathSetError((ctxt), XPATH_INVALID_TYPE) + +/** + * xmlXPathGetError: + * @ctxt: an XPath parser context + * + * Get the error code of an XPath context. + * + * Returns the context error. + */ +#define xmlXPathGetError(ctxt) ((ctxt)->error) + +/** + * xmlXPathCheckError: + * @ctxt: an XPath parser context + * + * Check if an XPath error was raised. + * + * Returns true if an error has been raised, false otherwise. + */ +#define xmlXPathCheckError(ctxt) ((ctxt)->error != XPATH_EXPRESSION_OK) + +/** + * xmlXPathGetDocument: + * @ctxt: an XPath parser context + * + * Get the document of an XPath context. + * + * Returns the context document. + */ +#define xmlXPathGetDocument(ctxt) ((ctxt)->context->doc) + +/** + * xmlXPathGetContextNode: + * @ctxt: an XPath parser context + * + * Get the context node of an XPath context. + * + * Returns the context node. + */ +#define xmlXPathGetContextNode(ctxt) ((ctxt)->context->node) + +XMLPUBFUN int XMLCALL + xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt); +XMLPUBFUN double XMLCALL + xmlXPathPopNumber (xmlXPathParserContextPtr ctxt); +XMLPUBFUN xmlChar * XMLCALL + xmlXPathPopString (xmlXPathParserContextPtr ctxt); +XMLPUBFUN xmlNodeSetPtr XMLCALL + xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt); +XMLPUBFUN void * XMLCALL + xmlXPathPopExternal (xmlXPathParserContextPtr ctxt); + +/** + * xmlXPathReturnBoolean: + * @ctxt: an XPath parser context + * @val: a boolean + * + * Pushes the boolean @val on the context stack. + */ +#define xmlXPathReturnBoolean(ctxt, val) \ + valuePush((ctxt), xmlXPathNewBoolean(val)) + +/** + * xmlXPathReturnTrue: + * @ctxt: an XPath parser context + * + * Pushes true on the context stack. + */ +#define xmlXPathReturnTrue(ctxt) xmlXPathReturnBoolean((ctxt), 1) + +/** + * xmlXPathReturnFalse: + * @ctxt: an XPath parser context + * + * Pushes false on the context stack. + */ +#define xmlXPathReturnFalse(ctxt) xmlXPathReturnBoolean((ctxt), 0) + +/** + * xmlXPathReturnNumber: + * @ctxt: an XPath parser context + * @val: a double + * + * Pushes the double @val on the context stack. + */ +#define xmlXPathReturnNumber(ctxt, val) \ + valuePush((ctxt), xmlXPathNewFloat(val)) + +/** + * xmlXPathReturnString: + * @ctxt: an XPath parser context + * @str: a string + * + * Pushes the string @str on the context stack. + */ +#define xmlXPathReturnString(ctxt, str) \ + valuePush((ctxt), xmlXPathWrapString(str)) + +/** + * xmlXPathReturnEmptyString: + * @ctxt: an XPath parser context + * + * Pushes an empty string on the stack. + */ +#define xmlXPathReturnEmptyString(ctxt) \ + valuePush((ctxt), xmlXPathNewCString("")) + +/** + * xmlXPathReturnNodeSet: + * @ctxt: an XPath parser context + * @ns: a node-set + * + * Pushes the node-set @ns on the context stack. + */ +#define xmlXPathReturnNodeSet(ctxt, ns) \ + valuePush((ctxt), xmlXPathWrapNodeSet(ns)) + +/** + * xmlXPathReturnEmptyNodeSet: + * @ctxt: an XPath parser context + * + * Pushes an empty node-set on the context stack. + */ +#define xmlXPathReturnEmptyNodeSet(ctxt) \ + valuePush((ctxt), xmlXPathNewNodeSet(NULL)) + +/** + * xmlXPathReturnExternal: + * @ctxt: an XPath parser context + * @val: user data + * + * Pushes user data on the context stack. + */ +#define xmlXPathReturnExternal(ctxt, val) \ + valuePush((ctxt), xmlXPathWrapExternal(val)) + +/** + * xmlXPathStackIsNodeSet: + * @ctxt: an XPath parser context + * + * Check if the current value on the XPath stack is a node set or + * an XSLT value tree. + * + * Returns true if the current object on the stack is a node-set. + */ +#define xmlXPathStackIsNodeSet(ctxt) \ + (((ctxt)->value != NULL) \ + && (((ctxt)->value->type == XPATH_NODESET) \ + || ((ctxt)->value->type == XPATH_XSLT_TREE))) + +/** + * xmlXPathStackIsExternal: + * @ctxt: an XPath parser context + * + * Checks if the current value on the XPath stack is an external + * object. + * + * Returns true if the current object on the stack is an external + * object. + */ +#define xmlXPathStackIsExternal(ctxt) \ + ((ctxt->value != NULL) && (ctxt->value->type == XPATH_USERS)) + +/** + * xmlXPathEmptyNodeSet: + * @ns: a node-set + * + * Empties a node-set. + */ +#define xmlXPathEmptyNodeSet(ns) \ + { while ((ns)->nodeNr > 0) (ns)->nodeTab[(ns)->nodeNr--] = NULL; } + +/** + * CHECK_ERROR: + * + * Macro to return from the function if an XPath error was detected. + */ +#define CHECK_ERROR \ + if (ctxt->error != XPATH_EXPRESSION_OK) return + +/** + * CHECK_ERROR0: + * + * Macro to return 0 from the function if an XPath error was detected. + */ +#define CHECK_ERROR0 \ + if (ctxt->error != XPATH_EXPRESSION_OK) return(0) + +/** + * XP_ERROR: + * @X: the error code + * + * Macro to raise an XPath error and return. + */ +#define XP_ERROR(X) \ + { xmlXPathErr(ctxt, X); return; } + +/** + * XP_ERROR0: + * @X: the error code + * + * Macro to raise an XPath error and return 0. + */ +#define XP_ERROR0(X) \ + { xmlXPathErr(ctxt, X); return(0); } + +/** + * CHECK_TYPE: + * @typeval: the XPath type + * + * Macro to check that the value on top of the XPath stack is of a given + * type. + */ +#define CHECK_TYPE(typeval) \ + if ((ctxt->value == NULL) || (ctxt->value->type != typeval)) \ + XP_ERROR(XPATH_INVALID_TYPE) + +/** + * CHECK_TYPE0: + * @typeval: the XPath type + * + * Macro to check that the value on top of the XPath stack is of a given + * type. Return(0) in case of failure + */ +#define CHECK_TYPE0(typeval) \ + if ((ctxt->value == NULL) || (ctxt->value->type != typeval)) \ + XP_ERROR0(XPATH_INVALID_TYPE) + +/** + * CHECK_ARITY: + * @x: the number of expected args + * + * Macro to check that the number of args passed to an XPath function matches. + */ +#define CHECK_ARITY(x) \ + if (ctxt == NULL) return; \ + if (nargs != (x)) \ + XP_ERROR(XPATH_INVALID_ARITY); + +/** + * CAST_TO_STRING: + * + * Macro to try to cast the value on the top of the XPath stack to a string. + */ +#define CAST_TO_STRING \ + if ((ctxt->value != NULL) && (ctxt->value->type != XPATH_STRING)) \ + xmlXPathStringFunction(ctxt, 1); + +/** + * CAST_TO_NUMBER: + * + * Macro to try to cast the value on the top of the XPath stack to a number. + */ +#define CAST_TO_NUMBER \ + if ((ctxt->value != NULL) && (ctxt->value->type != XPATH_NUMBER)) \ + xmlXPathNumberFunction(ctxt, 1); + +/** + * CAST_TO_BOOLEAN: + * + * Macro to try to cast the value on the top of the XPath stack to a boolean. + */ +#define CAST_TO_BOOLEAN \ + if ((ctxt->value != NULL) && (ctxt->value->type != XPATH_BOOLEAN)) \ + xmlXPathBooleanFunction(ctxt, 1); + +/* + * Variable Lookup forwarding. + */ + +XMLPUBFUN void XMLCALL + xmlXPathRegisterVariableLookup (xmlXPathContextPtr ctxt, + xmlXPathVariableLookupFunc f, + void *data); + +/* + * Function Lookup forwarding. + */ + +XMLPUBFUN void XMLCALL + xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt, + xmlXPathFuncLookupFunc f, + void *funcCtxt); + +/* + * Error reporting. + */ +XMLPUBFUN void XMLCALL + xmlXPatherror (xmlXPathParserContextPtr ctxt, + const char *file, + int line, + int no); + +XMLPUBFUN void XMLCALL + xmlXPathErr (xmlXPathParserContextPtr ctxt, + int error); + +#ifdef LIBXML_DEBUG_ENABLED +XMLPUBFUN void XMLCALL + xmlXPathDebugDumpObject (FILE *output, + xmlXPathObjectPtr cur, + int depth); +XMLPUBFUN void XMLCALL + xmlXPathDebugDumpCompExpr(FILE *output, + xmlXPathCompExprPtr comp, + int depth); +#endif +/** + * NodeSet handling. + */ +XMLPUBFUN int XMLCALL + xmlXPathNodeSetContains (xmlNodeSetPtr cur, + xmlNodePtr val); +XMLPUBFUN xmlNodeSetPtr XMLCALL + xmlXPathDifference (xmlNodeSetPtr nodes1, + xmlNodeSetPtr nodes2); +XMLPUBFUN xmlNodeSetPtr XMLCALL + xmlXPathIntersection (xmlNodeSetPtr nodes1, + xmlNodeSetPtr nodes2); + +XMLPUBFUN xmlNodeSetPtr XMLCALL + xmlXPathDistinctSorted (xmlNodeSetPtr nodes); +XMLPUBFUN xmlNodeSetPtr XMLCALL + xmlXPathDistinct (xmlNodeSetPtr nodes); + +XMLPUBFUN int XMLCALL + xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, + xmlNodeSetPtr nodes2); + +XMLPUBFUN xmlNodeSetPtr XMLCALL + xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, + xmlNodePtr node); +XMLPUBFUN xmlNodeSetPtr XMLCALL + xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, + xmlNodeSetPtr nodes2); +XMLPUBFUN xmlNodeSetPtr XMLCALL + xmlXPathNodeLeading (xmlNodeSetPtr nodes, + xmlNodePtr node); +XMLPUBFUN xmlNodeSetPtr XMLCALL + xmlXPathLeading (xmlNodeSetPtr nodes1, + xmlNodeSetPtr nodes2); + +XMLPUBFUN xmlNodeSetPtr XMLCALL + xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, + xmlNodePtr node); +XMLPUBFUN xmlNodeSetPtr XMLCALL + xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, + xmlNodeSetPtr nodes2); +XMLPUBFUN xmlNodeSetPtr XMLCALL + xmlXPathNodeTrailing (xmlNodeSetPtr nodes, + xmlNodePtr node); +XMLPUBFUN xmlNodeSetPtr XMLCALL + xmlXPathTrailing (xmlNodeSetPtr nodes1, + xmlNodeSetPtr nodes2); + + +/** + * Extending a context. + */ + +XMLPUBFUN int XMLCALL + xmlXPathRegisterNs (xmlXPathContextPtr ctxt, + const xmlChar *prefix, + const xmlChar *ns_uri); +XMLPUBFUN const xmlChar * XMLCALL + xmlXPathNsLookup (xmlXPathContextPtr ctxt, + const xmlChar *prefix); +XMLPUBFUN void XMLCALL + xmlXPathRegisteredNsCleanup (xmlXPathContextPtr ctxt); + +XMLPUBFUN int XMLCALL + xmlXPathRegisterFunc (xmlXPathContextPtr ctxt, + const xmlChar *name, + xmlXPathFunction f); +XMLPUBFUN int XMLCALL + xmlXPathRegisterFuncNS (xmlXPathContextPtr ctxt, + const xmlChar *name, + const xmlChar *ns_uri, + xmlXPathFunction f); +XMLPUBFUN int XMLCALL + xmlXPathRegisterVariable (xmlXPathContextPtr ctxt, + const xmlChar *name, + xmlXPathObjectPtr value); +XMLPUBFUN int XMLCALL + xmlXPathRegisterVariableNS (xmlXPathContextPtr ctxt, + const xmlChar *name, + const xmlChar *ns_uri, + xmlXPathObjectPtr value); +XMLPUBFUN xmlXPathFunction XMLCALL + xmlXPathFunctionLookup (xmlXPathContextPtr ctxt, + const xmlChar *name); +XMLPUBFUN xmlXPathFunction XMLCALL + xmlXPathFunctionLookupNS (xmlXPathContextPtr ctxt, + const xmlChar *name, + const xmlChar *ns_uri); +XMLPUBFUN void XMLCALL + xmlXPathRegisteredFuncsCleanup (xmlXPathContextPtr ctxt); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPathVariableLookup (xmlXPathContextPtr ctxt, + const xmlChar *name); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPathVariableLookupNS (xmlXPathContextPtr ctxt, + const xmlChar *name, + const xmlChar *ns_uri); +XMLPUBFUN void XMLCALL + xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt); + +/** + * Utilities to extend XPath. + */ +XMLPUBFUN xmlXPathParserContextPtr XMLCALL + xmlXPathNewParserContext (const xmlChar *str, + xmlXPathContextPtr ctxt); +XMLPUBFUN void XMLCALL + xmlXPathFreeParserContext (xmlXPathParserContextPtr ctxt); + +/* TODO: remap to xmlXPathValuePop and Push. */ +XMLPUBFUN xmlXPathObjectPtr XMLCALL + valuePop (xmlXPathParserContextPtr ctxt); +XMLPUBFUN int XMLCALL + valuePush (xmlXPathParserContextPtr ctxt, + xmlXPathObjectPtr value); + +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPathNewString (const xmlChar *val); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPathNewCString (const char *val); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPathWrapString (xmlChar *val); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPathWrapCString (char * val); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPathNewFloat (double val); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPathNewBoolean (int val); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPathNewNodeSet (xmlNodePtr val); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPathNewValueTree (xmlNodePtr val); +XMLPUBFUN void XMLCALL + xmlXPathNodeSetAdd (xmlNodeSetPtr cur, + xmlNodePtr val); +XMLPUBFUN void XMLCALL + xmlXPathNodeSetAddUnique (xmlNodeSetPtr cur, + xmlNodePtr val); +XMLPUBFUN void XMLCALL + xmlXPathNodeSetAddNs (xmlNodeSetPtr cur, + xmlNodePtr node, + xmlNsPtr ns); +XMLPUBFUN void XMLCALL + xmlXPathNodeSetSort (xmlNodeSetPtr set); + +XMLPUBFUN void XMLCALL + xmlXPathRoot (xmlXPathParserContextPtr ctxt); +XMLPUBFUN void XMLCALL + xmlXPathEvalExpr (xmlXPathParserContextPtr ctxt); +XMLPUBFUN xmlChar * XMLCALL + xmlXPathParseName (xmlXPathParserContextPtr ctxt); +XMLPUBFUN xmlChar * XMLCALL + xmlXPathParseNCName (xmlXPathParserContextPtr ctxt); + +/* + * Existing functions. + */ +XMLPUBFUN double XMLCALL + xmlXPathStringEvalNumber (const xmlChar *str); +XMLPUBFUN int XMLCALL + xmlXPathEvaluatePredicateResult (xmlXPathParserContextPtr ctxt, + xmlXPathObjectPtr res); +XMLPUBFUN void XMLCALL + xmlXPathRegisterAllFunctions (xmlXPathContextPtr ctxt); +XMLPUBFUN xmlNodeSetPtr XMLCALL + xmlXPathNodeSetMerge (xmlNodeSetPtr val1, + xmlNodeSetPtr val2); +XMLPUBFUN void XMLCALL + xmlXPathNodeSetDel (xmlNodeSetPtr cur, + xmlNodePtr val); +XMLPUBFUN void XMLCALL + xmlXPathNodeSetRemove (xmlNodeSetPtr cur, + int val); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPathNewNodeSetList (xmlNodeSetPtr val); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPathWrapNodeSet (xmlNodeSetPtr val); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPathWrapExternal (void *val); + +XMLPUBFUN int XMLCALL xmlXPathEqualValues(xmlXPathParserContextPtr ctxt); +XMLPUBFUN int XMLCALL xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt); +XMLPUBFUN int XMLCALL xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict); +XMLPUBFUN void XMLCALL xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt); +XMLPUBFUN void XMLCALL xmlXPathAddValues(xmlXPathParserContextPtr ctxt); +XMLPUBFUN void XMLCALL xmlXPathSubValues(xmlXPathParserContextPtr ctxt); +XMLPUBFUN void XMLCALL xmlXPathMultValues(xmlXPathParserContextPtr ctxt); +XMLPUBFUN void XMLCALL xmlXPathDivValues(xmlXPathParserContextPtr ctxt); +XMLPUBFUN void XMLCALL xmlXPathModValues(xmlXPathParserContextPtr ctxt); + +XMLPUBFUN int XMLCALL xmlXPathIsNodeType(const xmlChar *name); + +/* + * Some of the axis navigation routines. + */ +XMLPUBFUN xmlNodePtr XMLCALL xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, + xmlNodePtr cur); +XMLPUBFUN xmlNodePtr XMLCALL xmlXPathNextChild(xmlXPathParserContextPtr ctxt, + xmlNodePtr cur); +XMLPUBFUN xmlNodePtr XMLCALL xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, + xmlNodePtr cur); +XMLPUBFUN xmlNodePtr XMLCALL xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, + xmlNodePtr cur); +XMLPUBFUN xmlNodePtr XMLCALL xmlXPathNextParent(xmlXPathParserContextPtr ctxt, + xmlNodePtr cur); +XMLPUBFUN xmlNodePtr XMLCALL xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, + xmlNodePtr cur); +XMLPUBFUN xmlNodePtr XMLCALL xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, + xmlNodePtr cur); +XMLPUBFUN xmlNodePtr XMLCALL xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, + xmlNodePtr cur); +XMLPUBFUN xmlNodePtr XMLCALL xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, + xmlNodePtr cur); +XMLPUBFUN xmlNodePtr XMLCALL xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, + xmlNodePtr cur); +XMLPUBFUN xmlNodePtr XMLCALL xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, + xmlNodePtr cur); +XMLPUBFUN xmlNodePtr XMLCALL xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, + xmlNodePtr cur); +XMLPUBFUN xmlNodePtr XMLCALL xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, + xmlNodePtr cur); +/* + * The official core of XPath functions. + */ +XMLPUBFUN void XMLCALL xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs); +XMLPUBFUN void XMLCALL xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs); + +/** + * Really internal functions + */ +XMLPUBFUN void XMLCALL xmlXPathNodeSetFreeNs(xmlNsPtr ns); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_XPATH_ENABLED */ +#endif /* ! __XML_XPATH_INTERNALS_H__ */ diff --git a/android/native/libxml2/libxml/xpointer.h b/android/native/libxml2/libxml/xpointer.h new file mode 100644 index 0000000000..dde1dfb3d1 --- /dev/null +++ b/android/native/libxml2/libxml/xpointer.h @@ -0,0 +1,114 @@ +/* + * Summary: API to handle XML Pointers + * Description: API to handle XML Pointers + * Base implementation was made accordingly to + * W3C Candidate Recommendation 7 June 2000 + * http://www.w3.org/TR/2000/CR-xptr-20000607 + * + * Added support for the element() scheme described in: + * W3C Proposed Recommendation 13 November 2002 + * http://www.w3.org/TR/2002/PR-xptr-element-20021113/ + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XPTR_H__ +#define __XML_XPTR_H__ + +#include + +#ifdef LIBXML_XPTR_ENABLED + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * A Location Set + */ +typedef struct _xmlLocationSet xmlLocationSet; +typedef xmlLocationSet *xmlLocationSetPtr; +struct _xmlLocationSet { + int locNr; /* number of locations in the set */ + int locMax; /* size of the array as allocated */ + xmlXPathObjectPtr *locTab;/* array of locations */ +}; + +/* + * Handling of location sets. + */ + +XMLPUBFUN xmlLocationSetPtr XMLCALL + xmlXPtrLocationSetCreate (xmlXPathObjectPtr val); +XMLPUBFUN void XMLCALL + xmlXPtrFreeLocationSet (xmlLocationSetPtr obj); +XMLPUBFUN xmlLocationSetPtr XMLCALL + xmlXPtrLocationSetMerge (xmlLocationSetPtr val1, + xmlLocationSetPtr val2); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPtrNewRange (xmlNodePtr start, + int startindex, + xmlNodePtr end, + int endindex); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPtrNewRangePoints (xmlXPathObjectPtr start, + xmlXPathObjectPtr end); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPtrNewRangeNodePoint (xmlNodePtr start, + xmlXPathObjectPtr end); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPtrNewRangePointNode (xmlXPathObjectPtr start, + xmlNodePtr end); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPtrNewRangeNodes (xmlNodePtr start, + xmlNodePtr end); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPtrNewLocationSetNodes (xmlNodePtr start, + xmlNodePtr end); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPtrNewLocationSetNodeSet(xmlNodeSetPtr set); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPtrNewRangeNodeObject (xmlNodePtr start, + xmlXPathObjectPtr end); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPtrNewCollapsedRange (xmlNodePtr start); +XMLPUBFUN void XMLCALL + xmlXPtrLocationSetAdd (xmlLocationSetPtr cur, + xmlXPathObjectPtr val); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPtrWrapLocationSet (xmlLocationSetPtr val); +XMLPUBFUN void XMLCALL + xmlXPtrLocationSetDel (xmlLocationSetPtr cur, + xmlXPathObjectPtr val); +XMLPUBFUN void XMLCALL + xmlXPtrLocationSetRemove (xmlLocationSetPtr cur, + int val); + +/* + * Functions. + */ +XMLPUBFUN xmlXPathContextPtr XMLCALL + xmlXPtrNewContext (xmlDocPtr doc, + xmlNodePtr here, + xmlNodePtr origin); +XMLPUBFUN xmlXPathObjectPtr XMLCALL + xmlXPtrEval (const xmlChar *str, + xmlXPathContextPtr ctx); +XMLPUBFUN void XMLCALL + xmlXPtrRangeToFunction (xmlXPathParserContextPtr ctxt, + int nargs); +XMLPUBFUN xmlNodePtr XMLCALL + xmlXPtrBuildNodeList (xmlXPathObjectPtr obj); +XMLPUBFUN void XMLCALL + xmlXPtrEvalRangePredicate (xmlXPathParserContextPtr ctxt); +#ifdef __cplusplus +} +#endif + +#endif /* LIBXML_XPTR_ENABLED */ +#endif /* __XML_XPTR_H__ */ diff --git a/android/native/libxml2/list.c b/android/native/libxml2/list.c new file mode 100644 index 0000000000..5c01c83586 --- /dev/null +++ b/android/native/libxml2/list.c @@ -0,0 +1,779 @@ +/* + * list.c: lists handling implementation + * + * Copyright (C) 2000 Gary Pennington and Daniel Veillard. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND + * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER. + * + * Author: Gary.Pennington@uk.sun.com + */ + +#define IN_LIBXML +#include "libxml.h" + +#include +#include +#include +#include +#include + +/* + * Type definition are kept internal + */ + +struct _xmlLink +{ + struct _xmlLink *next; + struct _xmlLink *prev; + void *data; +}; + +struct _xmlList +{ + xmlLinkPtr sentinel; + void (*linkDeallocator)(xmlLinkPtr ); + int (*linkCompare)(const void *, const void*); +}; + +/************************************************************************ + * * + * Interfaces * + * * + ************************************************************************/ + +/** + * xmlLinkDeallocator: + * @l: a list + * @lk: a link + * + * Unlink and deallocate @lk from list @l + */ +static void +xmlLinkDeallocator(xmlListPtr l, xmlLinkPtr lk) +{ + (lk->prev)->next = lk->next; + (lk->next)->prev = lk->prev; + if(l->linkDeallocator) + l->linkDeallocator(lk); + xmlFree(lk); +} + +/** + * xmlLinkCompare: + * @data0: first data + * @data1: second data + * + * Compares two arbitrary data + * + * Returns -1, 0 or 1 depending on whether data1 is greater equal or smaller + * than data0 + */ +static int +xmlLinkCompare(const void *data0, const void *data1) +{ + if (data0 < data1) + return (-1); + else if (data0 == data1) + return (0); + return (1); +} + +/** + * xmlListLowerSearch: + * @l: a list + * @data: a data + * + * Search data in the ordered list walking from the beginning + * + * Returns the link containing the data or NULL + */ +static xmlLinkPtr +xmlListLowerSearch(xmlListPtr l, void *data) +{ + xmlLinkPtr lk; + + if (l == NULL) + return(NULL); + for(lk = l->sentinel->next;lk != l->sentinel && l->linkCompare(lk->data, data) <0 ;lk = lk->next); + return lk; +} + +/** + * xmlListHigherSearch: + * @l: a list + * @data: a data + * + * Search data in the ordered list walking backward from the end + * + * Returns the link containing the data or NULL + */ +static xmlLinkPtr +xmlListHigherSearch(xmlListPtr l, void *data) +{ + xmlLinkPtr lk; + + if (l == NULL) + return(NULL); + for(lk = l->sentinel->prev;lk != l->sentinel && l->linkCompare(lk->data, data) >0 ;lk = lk->prev); + return lk; +} + +/** + * xmlListSearch: + * @l: a list + * @data: a data + * + * Search data in the list + * + * Returns the link containing the data or NULL + */ +static xmlLinkPtr +xmlListLinkSearch(xmlListPtr l, void *data) +{ + xmlLinkPtr lk; + if (l == NULL) + return(NULL); + lk = xmlListLowerSearch(l, data); + if (lk == l->sentinel) + return NULL; + else { + if (l->linkCompare(lk->data, data) ==0) + return lk; + return NULL; + } +} + +/** + * xmlListLinkReverseSearch: + * @l: a list + * @data: a data + * + * Search data in the list processing backward + * + * Returns the link containing the data or NULL + */ +static xmlLinkPtr +xmlListLinkReverseSearch(xmlListPtr l, void *data) +{ + xmlLinkPtr lk; + if (l == NULL) + return(NULL); + lk = xmlListHigherSearch(l, data); + if (lk == l->sentinel) + return NULL; + else { + if (l->linkCompare(lk->data, data) ==0) + return lk; + return NULL; + } +} + +/** + * xmlListCreate: + * @deallocator: an optional deallocator function + * @compare: an optional comparison function + * + * Create a new list + * + * Returns the new list or NULL in case of error + */ +xmlListPtr +xmlListCreate(xmlListDeallocator deallocator, xmlListDataCompare compare) +{ + xmlListPtr l; + if (NULL == (l = (xmlListPtr )xmlMalloc( sizeof(xmlList)))) { + xmlGenericError(xmlGenericErrorContext, + "Cannot initialize memory for list"); + 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); + } + l->sentinel->next = l->sentinel; + l->sentinel->prev = l->sentinel; + l->sentinel->data = NULL; + + /* If there is a link deallocator, use it */ + if (deallocator != NULL) + l->linkDeallocator = deallocator; + /* If there is a link comparator, use it */ + if (compare != NULL) + l->linkCompare = compare; + else /* Use our own */ + l->linkCompare = xmlLinkCompare; + return l; +} + +/** + * xmlListSearch: + * @l: a list + * @data: a search value + * + * Search the list for an existing value of @data + * + * Returns the value associated to @data or NULL in case of error + */ +void * +xmlListSearch(xmlListPtr l, void *data) +{ + xmlLinkPtr lk; + if (l == NULL) + return(NULL); + lk = xmlListLinkSearch(l, data); + if (lk) + return (lk->data); + return NULL; +} + +/** + * xmlListReverseSearch: + * @l: a list + * @data: a search value + * + * Search the list in reverse order for an existing value of @data + * + * Returns the value associated to @data or NULL in case of error + */ +void * +xmlListReverseSearch(xmlListPtr l, void *data) +{ + xmlLinkPtr lk; + if (l == NULL) + return(NULL); + lk = xmlListLinkReverseSearch(l, data); + if (lk) + return (lk->data); + return NULL; +} + +/** + * xmlListInsert: + * @l: a list + * @data: the data + * + * Insert data in the ordered list at the beginning for this value + * + * Returns 0 in case of success, 1 in case of failure + */ +int +xmlListInsert(xmlListPtr l, void *data) +{ + xmlLinkPtr lkPlace, lkNew; + + if (l == NULL) + return(1); + lkPlace = xmlListLowerSearch(l, data); + /* Add the new link */ + lkNew = (xmlLinkPtr) xmlMalloc(sizeof(xmlLink)); + if (lkNew == NULL) { + xmlGenericError(xmlGenericErrorContext, + "Cannot initialize memory for new link"); + return (1); + } + lkNew->data = data; + lkPlace = lkPlace->prev; + lkNew->next = lkPlace->next; + (lkPlace->next)->prev = lkNew; + lkPlace->next = lkNew; + lkNew->prev = lkPlace; + return 0; +} + +/** + * xmlListAppend: + * @l: a list + * @data: the data + * + * Insert data in the ordered list at the end for this value + * + * Returns 0 in case of success, 1 in case of failure + */ +int xmlListAppend(xmlListPtr l, void *data) +{ + xmlLinkPtr lkPlace, lkNew; + + if (l == NULL) + return(1); + lkPlace = xmlListHigherSearch(l, data); + /* Add the new link */ + lkNew = (xmlLinkPtr) xmlMalloc(sizeof(xmlLink)); + if (lkNew == NULL) { + xmlGenericError(xmlGenericErrorContext, + "Cannot initialize memory for new link"); + return (1); + } + lkNew->data = data; + lkNew->next = lkPlace->next; + (lkPlace->next)->prev = lkNew; + lkPlace->next = lkNew; + lkNew->prev = lkPlace; + return 0; +} + +/** + * xmlListDelete: + * @l: a list + * + * Deletes the list and its associated data + */ +void xmlListDelete(xmlListPtr l) +{ + if (l == NULL) + return; + + xmlListClear(l); + xmlFree(l->sentinel); + xmlFree(l); +} + +/** + * xmlListRemoveFirst: + * @l: a list + * @data: list data + * + * Remove the first instance associated to data in the list + * + * Returns 1 if a deallocation occured, or 0 if not found + */ +int +xmlListRemoveFirst(xmlListPtr l, void *data) +{ + xmlLinkPtr lk; + + if (l == NULL) + return(0); + /*Find the first instance of this data */ + lk = xmlListLinkSearch(l, data); + if (lk != NULL) { + xmlLinkDeallocator(l, lk); + return 1; + } + return 0; +} + +/** + * xmlListRemoveLast: + * @l: a list + * @data: list data + * + * Remove the last instance associated to data in the list + * + * Returns 1 if a deallocation occured, or 0 if not found + */ +int +xmlListRemoveLast(xmlListPtr l, void *data) +{ + xmlLinkPtr lk; + + if (l == NULL) + return(0); + /*Find the last instance of this data */ + lk = xmlListLinkReverseSearch(l, data); + if (lk != NULL) { + xmlLinkDeallocator(l, lk); + return 1; + } + return 0; +} + +/** + * xmlListRemoveAll: + * @l: a list + * @data: list data + * + * Remove the all instance associated to data in the list + * + * Returns the number of deallocation, or 0 if not found + */ +int +xmlListRemoveAll(xmlListPtr l, void *data) +{ + int count=0; + + if (l == NULL) + return(0); + + while(xmlListRemoveFirst(l, data)) + count++; + return count; +} + +/** + * xmlListClear: + * @l: a list + * + * Remove the all data in the list + */ +void +xmlListClear(xmlListPtr l) +{ + xmlLinkPtr lk; + + if (l == NULL) + return; + lk = l->sentinel->next; + while(lk != l->sentinel) { + xmlLinkPtr next = lk->next; + + xmlLinkDeallocator(l, lk); + lk = next; + } +} + +/** + * xmlListEmpty: + * @l: a list + * + * Is the list empty ? + * + * Returns 1 if the list is empty, 0 if not empty and -1 in case of error + */ +int +xmlListEmpty(xmlListPtr l) +{ + if (l == NULL) + return(-1); + return (l->sentinel->next == l->sentinel); +} + +/** + * xmlListFront: + * @l: a list + * + * Get the first element in the list + * + * Returns the first element in the list, or NULL + */ +xmlLinkPtr +xmlListFront(xmlListPtr l) +{ + if (l == NULL) + return(NULL); + return (l->sentinel->next); +} + +/** + * xmlListEnd: + * @l: a list + * + * Get the last element in the list + * + * Returns the last element in the list, or NULL + */ +xmlLinkPtr +xmlListEnd(xmlListPtr l) +{ + if (l == NULL) + return(NULL); + return (l->sentinel->prev); +} + +/** + * xmlListSize: + * @l: a list + * + * Get the number of elements in the list + * + * Returns the number of elements in the list or -1 in case of error + */ +int +xmlListSize(xmlListPtr l) +{ + xmlLinkPtr lk; + int count=0; + + if (l == NULL) + return(-1); + /* TODO: keep a counter in xmlList instead */ + for(lk = l->sentinel->next; lk != l->sentinel; lk = lk->next, count++); + return count; +} + +/** + * xmlListPopFront: + * @l: a list + * + * Removes the first element in the list + */ +void +xmlListPopFront(xmlListPtr l) +{ + if(!xmlListEmpty(l)) + xmlLinkDeallocator(l, l->sentinel->next); +} + +/** + * xmlListPopBack: + * @l: a list + * + * Removes the last element in the list + */ +void +xmlListPopBack(xmlListPtr l) +{ + if(!xmlListEmpty(l)) + xmlLinkDeallocator(l, l->sentinel->prev); +} + +/** + * xmlListPushFront: + * @l: a list + * @data: new data + * + * add the new data at the beginning of the list + * + * Returns 1 if successful, 0 otherwise + */ +int +xmlListPushFront(xmlListPtr l, void *data) +{ + xmlLinkPtr lkPlace, lkNew; + + if (l == NULL) + return(0); + lkPlace = l->sentinel; + /* Add the new link */ + lkNew = (xmlLinkPtr) xmlMalloc(sizeof(xmlLink)); + if (lkNew == NULL) { + xmlGenericError(xmlGenericErrorContext, + "Cannot initialize memory for new link"); + return (0); + } + lkNew->data = data; + lkNew->next = lkPlace->next; + (lkPlace->next)->prev = lkNew; + lkPlace->next = lkNew; + lkNew->prev = lkPlace; + return 1; +} + +/** + * xmlListPushBack: + * @l: a list + * @data: new data + * + * add the new data at the end of the list + * + * Returns 1 if successful, 0 otherwise + */ +int +xmlListPushBack(xmlListPtr l, void *data) +{ + xmlLinkPtr lkPlace, lkNew; + + if (l == NULL) + 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"); + return (0); + } + lkNew->data = data; + lkNew->next = lkPlace->next; + (lkPlace->next)->prev = lkNew; + lkPlace->next = lkNew; + lkNew->prev = lkPlace; + return 1; +} + +/** + * xmlLinkGetData: + * @lk: a link + * + * See Returns. + * + * Returns a pointer to the data referenced from this link + */ +void * +xmlLinkGetData(xmlLinkPtr lk) +{ + if (lk == NULL) + return(NULL); + return lk->data; +} + +/** + * xmlListReverse: + * @l: a list + * + * Reverse the order of the elements in the list + */ +void +xmlListReverse(xmlListPtr l) +{ + xmlLinkPtr lk; + xmlLinkPtr lkPrev; + + if (l == NULL) + return; + lkPrev = l->sentinel; + for (lk = l->sentinel->next; lk != l->sentinel; lk = lk->next) { + lkPrev->next = lkPrev->prev; + lkPrev->prev = lk; + lkPrev = lk; + } + /* Fix up the last node */ + lkPrev->next = lkPrev->prev; + lkPrev->prev = lk; +} + +/** + * xmlListSort: + * @l: a list + * + * Sort all the elements in the list + */ +void +xmlListSort(xmlListPtr l) +{ + xmlListPtr lTemp; + + if (l == NULL) + return; + if(xmlListEmpty(l)) + return; + + /* I think that the real answer is to implement quicksort, the + * alternative is to implement some list copying procedure which + * would be based on a list copy followed by a clear followed by + * an insert. This is slow... + */ + + if (NULL ==(lTemp = xmlListDup(l))) + return; + xmlListClear(l); + xmlListMerge(l, lTemp); + xmlListDelete(lTemp); + return; +} + +/** + * xmlListWalk: + * @l: a list + * @walker: a processing function + * @user: a user parameter passed to the walker function + * + * Walk all the element of the first from first to last and + * apply the walker function to it + */ +void +xmlListWalk(xmlListPtr l, xmlListWalker walker, const void *user) { + xmlLinkPtr lk; + + if ((l == NULL) || (walker == NULL)) + return; + for(lk = l->sentinel->next; lk != l->sentinel; lk = lk->next) { + if((walker(lk->data, user)) == 0) + break; + } +} + +/** + * xmlListReverseWalk: + * @l: a list + * @walker: a processing function + * @user: a user parameter passed to the walker function + * + * Walk all the element of the list in reverse order and + * apply the walker function to it + */ +void +xmlListReverseWalk(xmlListPtr l, xmlListWalker walker, const void *user) { + xmlLinkPtr lk; + + if ((l == NULL) || (walker == NULL)) + return; + for(lk = l->sentinel->prev; lk != l->sentinel; lk = lk->prev) { + if((walker(lk->data, user)) == 0) + break; + } +} + +/** + * xmlListMerge: + * @l1: the original list + * @l2: the new list + * + * include all the elements of the second list in the first one and + * clear the second list + */ +void +xmlListMerge(xmlListPtr l1, xmlListPtr l2) +{ + xmlListCopy(l1, l2); + xmlListClear(l2); +} + +/** + * xmlListDup: + * @old: the list + * + * Duplicate the list + * + * Returns a new copy of the list or NULL in case of error + */ +xmlListPtr +xmlListDup(const xmlListPtr old) +{ + xmlListPtr cur; + + if (old == NULL) + return(NULL); + /* Hmmm, how to best deal with allocation issues when copying + * lists. If there is a de-allocator, should responsibility lie with + * the new list or the old list. Surely not both. I'll arbitrarily + * set it to be the old list for the time being whilst I work out + * the answer + */ + if (NULL ==(cur = xmlListCreate(NULL, old->linkCompare))) + return (NULL); + if (0 != xmlListCopy(cur, old)) + return NULL; + return cur; +} + +/** + * xmlListCopy: + * @cur: the new list + * @old: the old list + * + * Move all the element from the old list in the new list + * + * Returns 0 in case of success 1 in case of error + */ +int +xmlListCopy(xmlListPtr cur, const xmlListPtr old) +{ + /* Walk the old tree and insert the data into the new one */ + xmlLinkPtr lk; + + if ((old == NULL) || (cur == NULL)) + return(1); + for(lk = old->sentinel->next; lk != old->sentinel; lk = lk->next) { + if (0 !=xmlListInsert(cur, lk->data)) { + xmlListDelete(cur); + return (1); + } + } + return (0); +} +/* xmlListUnique() */ +/* xmlListSwap */ +#define bottom_list +#include "elfgcchack.h" diff --git a/android/native/libxml2/parser.c b/android/native/libxml2/parser.c new file mode 100644 index 0000000000..5092eadd4e --- /dev/null +++ b/android/native/libxml2/parser.c @@ -0,0 +1,14979 @@ +/* + * parser.c : an XML 1.0 parser, namespaces and validity support are mostly + * implemented on top of the SAX interfaces + * + * References: + * The XML specification: + * http://www.w3.org/TR/REC-xml + * Original 1.0 version: + * http://www.w3.org/TR/1998/REC-xml-19980210 + * XML second edition working draft + * http://www.w3.org/TR/2000/WD-xml-2e-20000814 + * + * Okay this is a big file, the parser core is around 7000 lines, then it + * is followed by the progressive parser top routines, then the various + * high level APIs to call the parser and a few miscellaneous functions. + * A number of helper functions and deprecated ones have been moved to + * parserInternals.c to reduce this file size. + * As much as possible the functions are associated with their relative + * production in the XML specification. A few productions defining the + * different ranges of character are actually implanted either in + * parserInternals.h or parserInternals.c + * The DOM tree build is realized from the default SAX callbacks in + * the module SAX.c. + * The routines doing the validation checks are in valid.c and called either + * from the SAX callbacks or as standalone functions using a preparsed + * document. + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + */ + +#define IN_LIBXML +#include "libxml.h" + +#if defined(WIN32) && !defined (__CYGWIN__) +#define XML_DIR_SEP '\\' +#else +#define XML_DIR_SEP '/' +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef LIBXML_CATALOG_ENABLED +#include +#endif +#ifdef LIBXML_SCHEMAS_ENABLED +#include +#include +#endif +#ifdef HAVE_CTYPE_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_ZLIB_H +#include +#endif +#ifdef HAVE_LZMA_H +#include +#endif + +static void +xmlFatalErr(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *info); + +static xmlParserCtxtPtr +xmlCreateEntityParserCtxtInternal(const xmlChar *URL, const xmlChar *ID, + const xmlChar *base, xmlParserCtxtPtr pctx); + +/************************************************************************ + * * + * Arbitrary limits set in the parser. See XML_PARSE_HUGE * + * * + ************************************************************************/ + +#define XML_PARSER_BIG_ENTITY 1000 +#define XML_PARSER_LOT_ENTITY 5000 + +/* + * XML_PARSER_NON_LINEAR is the threshold where the ratio of parsed entity + * replacement over the size in byte of the input indicates that you have + * and eponential behaviour. A value of 10 correspond to at least 3 entity + * replacement per byte of input. + */ +#define XML_PARSER_NON_LINEAR 10 + +/* + * xmlParserEntityCheck + * + * Function to check non-linear entity expansion behaviour + * This is here to detect and stop exponential linear entity expansion + * This is not a limitation of the parser but a safety + * boundary feature. It can be disabled with the XML_PARSE_HUGE + * parser option. + */ +static int +xmlParserEntityCheck(xmlParserCtxtPtr ctxt, unsigned long size, + xmlEntityPtr ent) +{ + unsigned long consumed = 0; + + if ((ctxt == NULL) || (ctxt->options & XML_PARSE_HUGE)) + return (0); + if (ctxt->lastError.code == XML_ERR_ENTITY_LOOP) + return (1); + if (size != 0) { + /* + * Do the check based on the replacement size of the entity + */ + if (size < XML_PARSER_BIG_ENTITY) + return(0); + + /* + * A limit on the amount of text data reasonably used + */ + if (ctxt->input != NULL) { + consumed = ctxt->input->consumed + + (ctxt->input->cur - ctxt->input->base); + } + consumed += ctxt->sizeentities; + + if ((size < XML_PARSER_NON_LINEAR * consumed) && + (ctxt->nbentities * 3 < XML_PARSER_NON_LINEAR * consumed)) + return (0); + } else if (ent != NULL) { + /* + * use the number of parsed entities in the replacement + */ + size = ent->checked; + + /* + * The amount of data parsed counting entities size only once + */ + if (ctxt->input != NULL) { + consumed = ctxt->input->consumed + + (ctxt->input->cur - ctxt->input->base); + } + consumed += ctxt->sizeentities; + + /* + * Check the density of entities for the amount of data + * knowing an entity reference will take at least 3 bytes + */ + if (size * 3 < consumed * XML_PARSER_NON_LINEAR) + return (0); + } else { + /* + * strange we got no data for checking just return + */ + return (0); + } + + xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL); + return (1); +} + +/** + * xmlParserMaxDepth: + * + * arbitrary depth limit for the XML documents that we allow to + * process. This is not a limitation of the parser but a safety + * boundary feature. It can be disabled with the XML_PARSE_HUGE + * parser option. + */ +unsigned int xmlParserMaxDepth = 256; + + + +#define SAX2 1 +#define XML_PARSER_BIG_BUFFER_SIZE 300 +#define XML_PARSER_BUFFER_SIZE 100 +#define SAX_COMPAT_MODE BAD_CAST "SAX compatibility mode document" + +/* + * List of XML prefixed PI allowed by W3C specs + */ + +static const char *xmlW3CPIs[] = { + "xml-stylesheet", + "xml-model", + NULL +}; + + +/* DEPR void xmlParserHandleReference(xmlParserCtxtPtr ctxt); */ +static xmlEntityPtr xmlParseStringPEReference(xmlParserCtxtPtr ctxt, + const xmlChar **str); + +static 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, + const char *encoding); +#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); + +static int +xmlLoadEntityContent(xmlParserCtxtPtr ctxt, xmlEntityPtr entity); + +/************************************************************************ + * * + * Some factorized error routines * + * * + ************************************************************************/ + +/** + * xmlErrAttributeDup: + * @ctxt: an XML parser context + * @prefix: the attribute prefix + * @localname: the attribute localname + * + * Handle a redefinition of attribute error + */ +static 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); + else + __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER, + XML_ERR_ATTRIBUTE_REDEFINED, XML_ERR_FATAL, NULL, 0, + (const char *) prefix, (const char *) localname, + NULL, 0, 0, "Attribute %s:%s redefined\n", prefix, + localname); + if (ctxt != NULL) { + ctxt->wellFormed = 0; + if (ctxt->recovery == 0) + ctxt->disableSAX = 1; + } +} + +/** + * xmlFatalErr: + * @ctxt: an XML parser context + * @error: the error number + * @extra: extra information string + * + * Handle a fatal parser error, i.e. violating Well-Formedness constraints + */ +static void +xmlFatalErr(xmlParserCtxtPtr ctxt, xmlParserErrors error, 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\n"; + break; + case XML_ERR_INVALID_DEC_CHARREF: + errmsg = "CharRef: invalid decimal value\n"; + break; + case XML_ERR_INVALID_CHARREF: + errmsg = "CharRef: invalid value\n"; + break; + case XML_ERR_INTERNAL_ERROR: + errmsg = "internal error"; + break; + case XML_ERR_PEREF_AT_EOF: + errmsg = "PEReference at end of document\n"; + break; + case XML_ERR_PEREF_IN_PROLOG: + errmsg = "PEReference in prolog\n"; + break; + case XML_ERR_PEREF_IN_EPILOG: + errmsg = "PEReference in epilog\n"; + break; + case XML_ERR_PEREF_NO_NAME: + errmsg = "PEReference: no name\n"; + break; + case XML_ERR_PEREF_SEMICOL_MISSING: + errmsg = "PEReference: expecting ';'\n"; + break; + case XML_ERR_ENTITY_LOOP: + errmsg = "Detected an entity reference loop\n"; + break; + case XML_ERR_ENTITY_NOT_STARTED: + errmsg = "EntityValue: \" or ' expected\n"; + break; + case XML_ERR_ENTITY_PE_INTERNAL: + errmsg = "PEReferences forbidden in internal subset\n"; + break; + case XML_ERR_ENTITY_NOT_FINISHED: + errmsg = "EntityValue: \" or ' expected\n"; + break; + case XML_ERR_ATTRIBUTE_NOT_STARTED: + errmsg = "AttValue: \" or ' expected\n"; + break; + case XML_ERR_LT_IN_ATTRIBUTE: + errmsg = "Unescaped '<' not allowed in attributes values\n"; + break; + case XML_ERR_LITERAL_NOT_STARTED: + errmsg = "SystemLiteral \" or ' expected\n"; + break; + case XML_ERR_LITERAL_NOT_FINISHED: + errmsg = "Unfinished System or Public ID \" or ' expected\n"; + break; + case XML_ERR_MISPLACED_CDATA_END: + errmsg = "Sequence ']]>' not allowed in content\n"; + break; + case XML_ERR_URI_REQUIRED: + errmsg = "SYSTEM or PUBLIC, the URI is missing\n"; + break; + case XML_ERR_PUBID_REQUIRED: + errmsg = "PUBLIC, the Public Identifier is missing\n"; + break; + case XML_ERR_HYPHEN_IN_COMMENT: + errmsg = "Comment must not contain '--' (double-hyphen)\n"; + break; + case XML_ERR_PI_NOT_STARTED: + errmsg = "xmlParsePI : no target name\n"; + break; + case XML_ERR_RESERVED_XML_NAME: + errmsg = "Invalid PI name\n"; + break; + case XML_ERR_NOTATION_NOT_STARTED: + errmsg = "NOTATION: Name expected here\n"; + break; + case XML_ERR_NOTATION_NOT_FINISHED: + errmsg = "'>' required to close NOTATION declaration\n"; + break; + case XML_ERR_VALUE_REQUIRED: + errmsg = "Entity value required\n"; + break; + case XML_ERR_URI_FRAGMENT: + errmsg = "Fragment not allowed"; + break; + case XML_ERR_ATTLIST_NOT_STARTED: + errmsg = "'(' required to start ATTLIST enumeration\n"; + break; + case XML_ERR_NMTOKEN_REQUIRED: + errmsg = "NmToken expected in ATTLIST enumeration\n"; + break; + case XML_ERR_ATTLIST_NOT_FINISHED: + errmsg = "')' required to finish ATTLIST enumeration\n"; + break; + case XML_ERR_MIXED_NOT_STARTED: + errmsg = "MixedContentDecl : '|' or ')*' expected\n"; + break; + case XML_ERR_PCDATA_REQUIRED: + errmsg = "MixedContentDecl : '#PCDATA' expected\n"; + break; + case XML_ERR_ELEMCONTENT_NOT_STARTED: + errmsg = "ContentDecl : Name or '(' expected\n"; + break; + case XML_ERR_ELEMCONTENT_NOT_FINISHED: + errmsg = "ContentDecl : ',' '|' or ')' expected\n"; + break; + case XML_ERR_PEREF_IN_INT_SUBSET: + errmsg = + "PEReference: forbidden within markup decl in internal subset\n"; + break; + case XML_ERR_GT_REQUIRED: + errmsg = "expected '>'\n"; + break; + case XML_ERR_CONDSEC_INVALID: + errmsg = "XML conditional section '[' expected\n"; + break; + case XML_ERR_EXT_SUBSET_NOT_FINISHED: + errmsg = "Content error in the external subset\n"; + break; + case XML_ERR_CONDSEC_INVALID_KEYWORD: + errmsg = + "conditional section INCLUDE or IGNORE keyword expected\n"; + break; + case XML_ERR_CONDSEC_NOT_FINISHED: + errmsg = "XML conditional section not closed\n"; + break; + case XML_ERR_XMLDECL_NOT_STARTED: + errmsg = "Text declaration '' expected\n"; + break; + case XML_ERR_EXT_ENTITY_STANDALONE: + errmsg = "external parsed entities cannot be standalone\n"; + break; + case XML_ERR_ENTITYREF_SEMICOL_MISSING: + errmsg = "EntityRef: expecting ';'\n"; + break; + case XML_ERR_DOCTYPE_NOT_FINISHED: + errmsg = "DOCTYPE improperly terminated\n"; + break; + case XML_ERR_LTSLASH_REQUIRED: + errmsg = "EndTag: 'errNo = error; + __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER, error, + XML_ERR_FATAL, NULL, 0, info, NULL, NULL, 0, 0, errmsg, + info); + if (ctxt != NULL) { + ctxt->wellFormed = 0; + if (ctxt->recovery == 0) + ctxt->disableSAX = 1; + } +} + +/** + * xmlFatalErrMsg: + * @ctxt: an XML parser context + * @error: the error number + * @msg: the error message + * + * Handle a fatal parser error, i.e. violating Well-Formedness constraints + */ +static void +xmlFatalErrMsg(xmlParserCtxtPtr ctxt, xmlParserErrors error, + const char *msg) +{ + if ((ctxt != NULL) && (ctxt->disableSAX != 0) && + (ctxt->instate == XML_PARSER_EOF)) + return; + 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; + } +} + +/** + * xmlWarningMsg: + * @ctxt: an XML parser context + * @error: the error number + * @msg: the error message + * @str1: extra data + * @str2: extra data + * + * Handle a warning. + */ +static void +xmlWarningMsg(xmlParserCtxtPtr ctxt, xmlParserErrors error, + const char *msg, const xmlChar *str1, const xmlChar *str2) +{ + xmlStructuredErrorFunc schannel = NULL; + + if ((ctxt != NULL) && (ctxt->disableSAX != 0) && + (ctxt->instate == XML_PARSER_EOF)) + return; + 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); + } +} + +/** + * xmlValidityError: + * @ctxt: an XML parser context + * @error: the error number + * @msg: the error message + * @str1: extra data + * + * Handle a validity error. + */ +static void +xmlValidityError(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->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); + } +} + +/** + * xmlFatalErrMsgInt: + * @ctxt: an XML parser context + * @error: the error number + * @msg: the error message + * @val: an integer value + * + * Handle a fatal parser error, i.e. violating Well-Formedness constraints + */ +static void +xmlFatalErrMsgInt(xmlParserCtxtPtr ctxt, xmlParserErrors error, + const char *msg, int val) +{ + if ((ctxt != NULL) && (ctxt->disableSAX != 0) && + (ctxt->instate == XML_PARSER_EOF)) + return; + 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; + } +} + +/** + * xmlFatalErrMsgStrIntStr: + * @ctxt: an XML parser context + * @error: the error number + * @msg: the error message + * @str1: an string info + * @val: an integer value + * @str2: an string info + * + * Handle a fatal parser error, i.e. violating Well-Formedness constraints + */ +static void +xmlFatalErrMsgStrIntStr(xmlParserCtxtPtr ctxt, xmlParserErrors error, + const char *msg, const xmlChar *str1, int val, + const xmlChar *str2) +{ + if ((ctxt != NULL) && (ctxt->disableSAX != 0) && + (ctxt->instate == XML_PARSER_EOF)) + return; + 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; + } +} + +/** + * xmlFatalErrMsgStr: + * @ctxt: an XML parser context + * @error: the error number + * @msg: the error message + * @val: a string value + * + * Handle a fatal parser error, i.e. violating Well-Formedness constraints + */ +static void +xmlFatalErrMsgStr(xmlParserCtxtPtr ctxt, xmlParserErrors error, + const char *msg, const xmlChar * val) +{ + if ((ctxt != NULL) && (ctxt->disableSAX != 0) && + (ctxt->instate == XML_PARSER_EOF)) + return; + 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; + } +} + +/** + * xmlErrMsgStr: + * @ctxt: an XML parser context + * @error: the error number + * @msg: the error message + * @val: a string value + * + * Handle a non fatal parser error + */ +static void +xmlErrMsgStr(xmlParserCtxtPtr ctxt, xmlParserErrors error, + const char *msg, const xmlChar * val) +{ + if ((ctxt != NULL) && (ctxt->disableSAX != 0) && + (ctxt->instate == XML_PARSER_EOF)) + return; + 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); +} + +/** + * xmlNsErr: + * @ctxt: an XML parser context + * @error: the error number + * @msg: the message + * @info1: extra information string + * @info2: extra information string + * + * Handle a fatal parser error, i.e. violating Well-Formedness constraints + */ +static void +xmlNsErr(xmlParserCtxtPtr ctxt, xmlParserErrors error, + const char *msg, + const xmlChar * info1, const xmlChar * info2, + const xmlChar * info3) +{ + if ((ctxt != NULL) && (ctxt->disableSAX != 0) && + (ctxt->instate == XML_PARSER_EOF)) + return; + 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; +} + +/** + * xmlNsWarn + * @ctxt: an XML parser context + * @error: the error number + * @msg: the message + * @info1: extra information string + * @info2: extra information string + * + * Handle a fatal parser error, i.e. violating Well-Formedness constraints + */ +static void +xmlNsWarn(xmlParserCtxtPtr ctxt, xmlParserErrors error, + const char *msg, + const xmlChar * info1, const xmlChar * info2, + const xmlChar * info3) +{ + if ((ctxt != NULL) && (ctxt->disableSAX != 0) && + (ctxt->instate == XML_PARSER_EOF)) + return; + __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); +} + +/************************************************************************ + * * + * Library wide options * + * * + ************************************************************************/ + +/** + * xmlHasFeature: + * @feature: the feature to be examined + * + * Examines if the library has been compiled with a given feature. + * + * Returns a non-zero value if the feature exist, otherwise zero. + * Returns zero (0) if the feature does not exist or an unknown + * unknown feature is requested, non-zero otherwise. + */ +int +xmlHasFeature(xmlFeature feature) +{ + switch (feature) { + case XML_WITH_THREAD: +#ifdef LIBXML_THREAD_ENABLED + return(1); +#else + return(0); +#endif + case XML_WITH_TREE: +#ifdef LIBXML_TREE_ENABLED + return(1); +#else + return(0); +#endif + case XML_WITH_OUTPUT: +#ifdef LIBXML_OUTPUT_ENABLED + return(1); +#else + return(0); +#endif + case XML_WITH_PUSH: +#ifdef LIBXML_PUSH_ENABLED + return(1); +#else + return(0); +#endif + case XML_WITH_READER: +#ifdef LIBXML_READER_ENABLED + return(1); +#else + return(0); +#endif + case XML_WITH_PATTERN: +#ifdef LIBXML_PATTERN_ENABLED + return(1); +#else + return(0); +#endif + case XML_WITH_WRITER: +#ifdef LIBXML_WRITER_ENABLED + return(1); +#else + return(0); +#endif + case XML_WITH_SAX1: +#ifdef LIBXML_SAX1_ENABLED + return(1); +#else + return(0); +#endif + case XML_WITH_FTP: + return(0); + case XML_WITH_HTTP: + return(0); + case XML_WITH_VALID: +#ifdef LIBXML_VALID_ENABLED + return(1); +#else + return(0); +#endif + case XML_WITH_HTML: + return(0); + case XML_WITH_LEGACY: +#ifdef LIBXML_LEGACY_ENABLED + return(1); +#else + return(0); +#endif + case XML_WITH_C14N: +#ifdef LIBXML_C14N_ENABLED + return(1); +#else + return(0); +#endif + case XML_WITH_CATALOG: +#ifdef LIBXML_CATALOG_ENABLED + return(1); +#else + return(0); +#endif + case XML_WITH_XPATH: +#ifdef LIBXML_XPATH_ENABLED + return(1); +#else + return(0); +#endif + case XML_WITH_XPTR: +#ifdef LIBXML_XPTR_ENABLED + return(1); +#else + return(0); +#endif + case XML_WITH_XINCLUDE: +#ifdef LIBXML_XINCLUDE_ENABLED + return(1); +#else + return(0); +#endif + case XML_WITH_ICONV: +#ifdef LIBXML_ICONV_ENABLED + return(1); +#else + return(0); +#endif + case XML_WITH_ISO8859X: +#ifdef LIBXML_ISO8859X_ENABLED + return(1); +#else + return(0); +#endif + case XML_WITH_UNICODE: +#ifdef LIBXML_UNICODE_ENABLED + return(1); +#else + return(0); +#endif + case XML_WITH_REGEXP: +#ifdef LIBXML_REGEXP_ENABLED + return(1); +#else + return(0); +#endif + case XML_WITH_AUTOMATA: +#ifdef LIBXML_AUTOMATA_ENABLED + return(1); +#else + return(0); +#endif + case XML_WITH_EXPR: +#ifdef LIBXML_EXPR_ENABLED + return(1); +#else + return(0); +#endif + case XML_WITH_SCHEMAS: +#ifdef LIBXML_SCHEMAS_ENABLED + return(1); +#else + return(0); +#endif + case XML_WITH_SCHEMATRON: +#ifdef LIBXML_SCHEMATRON_ENABLED + return(1); +#else + return(0); +#endif + case XML_WITH_MODULES: +#ifdef LIBXML_MODULES_ENABLED + return(1); +#else + return(0); +#endif + case XML_WITH_DEBUG: +#ifdef LIBXML_DEBUG_ENABLED + return(1); +#else + return(0); +#endif + case XML_WITH_DEBUG_MEM: +#ifdef DEBUG_MEMORY_LOCATION + return(1); +#else + return(0); +#endif + case XML_WITH_DEBUG_RUN: +#ifdef LIBXML_DEBUG_RUNTIME + return(1); +#else + return(0); +#endif + case XML_WITH_ZLIB: +#ifdef LIBXML_ZLIB_ENABLED + return(1); +#else + return(0); +#endif + case XML_WITH_LZMA: +#ifdef LIBXML_LZMA_ENABLED + return(1); +#else + return(0); +#endif + case XML_WITH_ICU: +#ifdef LIBXML_ICU_ENABLED + return(1); +#else + return(0); +#endif + default: + break; + } + return(0); +} + +/************************************************************************ + * * + * SAX2 defaulted attributes handling * + * * + ************************************************************************/ + +/** + * xmlDetectSAX2: + * @ctxt: an XML parser context + * + * Do the SAX2 detection and specific intialization + */ +static void +xmlDetectSAX2(xmlParserCtxtPtr ctxt) { + if (ctxt == NULL) return; +#ifdef LIBXML_SAX1_ENABLED + if ((ctxt->sax) && (ctxt->sax->initialized == XML_SAX2_MAGIC) && + ((ctxt->sax->startElementNs != NULL) || + (ctxt->sax->endElementNs != NULL))) ctxt->sax2 = 1; +#else + ctxt->sax2 = 1; +#endif /* LIBXML_SAX1_ENABLED */ + + 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); + } +} + +typedef struct _xmlDefAttrs xmlDefAttrs; +typedef xmlDefAttrs *xmlDefAttrsPtr; +struct _xmlDefAttrs { + int nbAttrs; /* number of defaulted attributes on that element */ + int maxAttrs; /* the size of the array */ + const xmlChar *values[5]; /* array of localname/prefix/values/external */ +}; + +/** + * xmlAttrNormalizeSpace: + * @src: the source string + * @dst: the target string + * + * Normalize the space in non CDATA attribute values: + * If the attribute type 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. + * Note that the size of dst need to be at least src, and if one doesn't need + * to preserve dst (and it doesn't come from a dictionary or read-only) then + * passing src as dst is just fine. + * + * Returns a pointer to the normalized value (dst) or NULL if no conversion + * is needed. + */ +static xmlChar * +xmlAttrNormalizeSpace(const xmlChar *src, xmlChar *dst) +{ + if ((src == NULL) || (dst == NULL)) + return(NULL); + + while (*src == 0x20) src++; + while (*src != 0) { + if (*src == 0x20) { + while (*src == 0x20) src++; + if (*src != 0) + *dst++ = 0x20; + } else { + *dst++ = *src++; + } + } + *dst = 0; + if (dst == src) + return(NULL); + 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 = (int) 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 + * @fullname: the element fullname + * @fullattr: the attribute fullname + * @value: the attribute value + * + * Add a defaulted attribute for an element + */ +static void +xmlAddDefAttrs(xmlParserCtxtPtr ctxt, + const xmlChar *fullname, + const xmlChar *fullattr, + const xmlChar *value) { + xmlDefAttrsPtr defaults; + int len; + const xmlChar *name; + const xmlChar *prefix; + + /* + * Allows to detect attribute redefinitions + */ + if (ctxt->attsSpecial != NULL) { + if (xmlHashLookup2(ctxt->attsSpecial, fullname, fullattr) != NULL) + return; + } + + if (ctxt->attsDefault == NULL) { + ctxt->attsDefault = xmlHashCreateDict(10, ctxt->dict); + if (ctxt->attsDefault == NULL) + goto mem_error; + } + + /* + * split the element name into prefix:localname , the string found + * are within the DTD and then not associated to namespace names. + */ + name = xmlSplitQName3(fullname, &len); + if (name == NULL) { + name = xmlDictLookup(ctxt->dict, fullname, -1); + prefix = NULL; + } else { + name = xmlDictLookup(ctxt->dict, name, -1); + prefix = xmlDictLookup(ctxt->dict, fullname, len); + } + + /* + * make sure there is some storage + */ + defaults = xmlHashLookup2(ctxt->attsDefault, name, prefix); + if (defaults == NULL) { + defaults = (xmlDefAttrsPtr) xmlMalloc(sizeof(xmlDefAttrs) + + (4 * 5) * sizeof(const xmlChar *)); + if (defaults == NULL) + goto mem_error; + defaults->nbAttrs = 0; + defaults->maxAttrs = 4; + if (xmlHashUpdateEntry2(ctxt->attsDefault, name, prefix, + defaults, NULL) < 0) { + xmlFree(defaults); + goto mem_error; + } + } else if (defaults->nbAttrs >= defaults->maxAttrs) { + xmlDefAttrsPtr temp; + + temp = (xmlDefAttrsPtr) xmlRealloc(defaults, sizeof(xmlDefAttrs) + + (2 * defaults->maxAttrs * 5) * sizeof(const xmlChar *)); + if (temp == NULL) + goto mem_error; + defaults = temp; + defaults->maxAttrs *= 2; + if (xmlHashUpdateEntry2(ctxt->attsDefault, name, prefix, + defaults, NULL) < 0) { + xmlFree(defaults); + goto mem_error; + } + } + + /* + * Split the element name into prefix:localname , the string found + * are within the DTD and hen not associated to namespace names. + */ + name = xmlSplitQName3(fullattr, &len); + if (name == NULL) { + name = xmlDictLookup(ctxt->dict, fullattr, -1); + prefix = NULL; + } else { + name = xmlDictLookup(ctxt->dict, name, -1); + prefix = xmlDictLookup(ctxt->dict, fullattr, len); + } + + defaults->values[5 * defaults->nbAttrs] = name; + defaults->values[5 * defaults->nbAttrs + 1] = prefix; + /* intern the string and precompute the end */ + len = xmlStrlen(value); + value = xmlDictLookup(ctxt->dict, value, len); + defaults->values[5 * defaults->nbAttrs + 2] = value; + defaults->values[5 * defaults->nbAttrs + 3] = value + len; + if (ctxt->external) + defaults->values[5 * defaults->nbAttrs + 4] = BAD_CAST "external"; + else + defaults->values[5 * defaults->nbAttrs + 4] = NULL; + defaults->nbAttrs++; + + return; + +mem_error: + xmlErrMemory(ctxt, NULL); + return; +} + +/** + * xmlAddSpecialAttr: + * @ctxt: an XML parser context + * @fullname: the element fullname + * @fullattr: the attribute fullname + * @type: the attribute type + * + * Register this attribute type + */ +static void +xmlAddSpecialAttr(xmlParserCtxtPtr ctxt, + const xmlChar *fullname, + const xmlChar *fullattr, + int type) +{ + if (ctxt->attsSpecial == NULL) { + ctxt->attsSpecial = xmlHashCreateDict(10, ctxt->dict); + if (ctxt->attsSpecial == NULL) + goto mem_error; + } + + if (xmlHashLookup2(ctxt->attsSpecial, fullname, fullattr) != NULL) + return; + + xmlHashAddEntry2(ctxt->attsSpecial, fullname, fullattr, + (void *) (long) type); + return; + +mem_error: + xmlErrMemory(ctxt, NULL); + return; +} + +/** + * xmlCleanSpecialAttrCallback: + * + * Removes CDATA attributes from the special attribute table + */ +static void +xmlCleanSpecialAttrCallback(void *payload, void *data, + const xmlChar *fullname, const xmlChar *fullattr, + const xmlChar *unused ATTRIBUTE_UNUSED) { + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) data; + + if (((long) payload) == XML_ATTRIBUTE_CDATA) { + xmlHashRemoveEntry2(ctxt->attsSpecial, fullname, fullattr, NULL); + } +} + +/** + * xmlCleanSpecialAttr: + * @ctxt: an XML parser context + * + * Trim the list of attributes defined to remove all those of type + * CDATA as they are not special. This call should be done when finishing + * to parse the DTD and before starting to parse the document root. + */ +static void +xmlCleanSpecialAttr(xmlParserCtxtPtr ctxt) +{ + if (ctxt->attsSpecial == NULL) + return; + + xmlHashScanFull(ctxt->attsSpecial, xmlCleanSpecialAttrCallback, ctxt); + + if (xmlHashSize(ctxt->attsSpecial) == 0) { + xmlHashFree(ctxt->attsSpecial, NULL); + ctxt->attsSpecial = NULL; + } + return; +} + +/** + * xmlCheckLanguageID: + * @lang: pointer to the string value + * + * Checks that the value conforms to the LanguageID production: + * + * NOTE: this is somewhat deprecated, those productions were removed from + * the XML Second edition. + * + * [33] LanguageID ::= Langcode ('-' Subcode)* + * [34] Langcode ::= ISO639Code | IanaCode | UserCode + * [35] ISO639Code ::= ([a-z] | [A-Z]) ([a-z] | [A-Z]) + * [36] IanaCode ::= ('i' | 'I') '-' ([a-z] | [A-Z])+ + * [37] UserCode ::= ('x' | 'X') '-' ([a-z] | [A-Z])+ + * [38] Subcode ::= ([a-z] | [A-Z])+ + * + * The current REC reference the sucessors of RFC 1766, currently 5646 + * + * http://www.rfc-editor.org/rfc/rfc5646.txt + * langtag = language + * ["-" script] + * ["-" region] + * *("-" variant) + * *("-" extension) + * ["-" privateuse] + * language = 2*3ALPHA ; shortest ISO 639 code + * ["-" extlang] ; sometimes followed by + * ; extended language subtags + * / 4ALPHA ; or reserved for future use + * / 5*8ALPHA ; or registered language subtag + * + * extlang = 3ALPHA ; selected ISO 639 codes + * *2("-" 3ALPHA) ; permanently reserved + * + * script = 4ALPHA ; ISO 15924 code + * + * region = 2ALPHA ; ISO 3166-1 code + * / 3DIGIT ; UN M.49 code + * + * variant = 5*8alphanum ; registered variants + * / (DIGIT 3alphanum) + * + * extension = singleton 1*("-" (2*8alphanum)) + * + * ; Single alphanumerics + * ; "x" reserved for private use + * singleton = DIGIT ; 0 - 9 + * / %x41-57 ; A - W + * / %x59-5A ; Y - Z + * / %x61-77 ; a - w + * / %x79-7A ; y - z + * + * it sounds right to still allow Irregular i-xxx IANA and user codes too + * The parser below doesn't try to cope with extension or privateuse + * that could be added but that's not interoperable anyway + * + * Returns 1 if correct 0 otherwise + **/ +int +xmlCheckLanguageID(const xmlChar * lang) +{ + const xmlChar *cur = lang, *nxt; + + if (cur == NULL) + return (0); + if (((cur[0] == 'i') && (cur[1] == '-')) || + ((cur[0] == 'I') && (cur[1] == '-')) || + ((cur[0] == 'x') && (cur[1] == '-')) || + ((cur[0] == 'X') && (cur[1] == '-'))) { + /* + * Still allow IANA code and user code which were coming + * from the previous version of the XML-1.0 specification + * it's deprecated but we should not fail + */ + cur += 2; + while (((cur[0] >= 'A') && (cur[0] <= 'Z')) || + ((cur[0] >= 'a') && (cur[0] <= 'z'))) + cur++; + return(cur[0] == 0); + } + nxt = cur; + while (((nxt[0] >= 'A') && (nxt[0] <= 'Z')) || + ((nxt[0] >= 'a') && (nxt[0] <= 'z'))) + nxt++; + if (nxt - cur >= 4) { + /* + * Reserved + */ + if ((nxt - cur > 8) || (nxt[0] != 0)) + return(0); + return(1); + } + if (nxt - cur < 2) + return(0); + /* we got an ISO 639 code */ + if (nxt[0] == 0) + return(1); + if (nxt[0] != '-') + return(0); + + nxt++; + cur = nxt; + /* now we can have extlang or script or region or variant */ + if ((nxt[0] >= '0') && (nxt[0] <= '9')) + goto region_m49; + + while (((nxt[0] >= 'A') && (nxt[0] <= 'Z')) || + ((nxt[0] >= 'a') && (nxt[0] <= 'z'))) + nxt++; + if (nxt - cur == 4) + goto script; + if (nxt - cur == 2) + goto region; + if ((nxt - cur >= 5) && (nxt - cur <= 8)) + goto variant; + if (nxt - cur != 3) + return(0); + /* we parsed an extlang */ + if (nxt[0] == 0) + return(1); + if (nxt[0] != '-') + return(0); + + nxt++; + cur = nxt; + /* now we can have script or region or variant */ + if ((nxt[0] >= '0') && (nxt[0] <= '9')) + goto region_m49; + + while (((nxt[0] >= 'A') && (nxt[0] <= 'Z')) || + ((nxt[0] >= 'a') && (nxt[0] <= 'z'))) + nxt++; + if (nxt - cur == 2) + goto region; + if ((nxt - cur >= 5) && (nxt - cur <= 8)) + goto variant; + if (nxt - cur != 4) + return(0); + /* we parsed a script */ +script: + if (nxt[0] == 0) + return(1); + if (nxt[0] != '-') + return(0); + + nxt++; + cur = nxt; + /* now we can have region or variant */ + if ((nxt[0] >= '0') && (nxt[0] <= '9')) + goto region_m49; + + while (((nxt[0] >= 'A') && (nxt[0] <= 'Z')) || + ((nxt[0] >= 'a') && (nxt[0] <= 'z'))) + nxt++; + + if ((nxt - cur >= 5) && (nxt - cur <= 8)) + goto variant; + if (nxt - cur != 2) + return(0); + /* we parsed a region */ +region: + if (nxt[0] == 0) + return(1); + if (nxt[0] != '-') + return(0); + + nxt++; + cur = nxt; + /* now we can just have a variant */ + while (((nxt[0] >= 'A') && (nxt[0] <= 'Z')) || + ((nxt[0] >= 'a') && (nxt[0] <= 'z'))) + nxt++; + + if ((nxt - cur < 5) || (nxt - cur > 8)) + return(0); + + /* we parsed a variant */ +variant: + if (nxt[0] == 0) + return(1); + if (nxt[0] != '-') + return(0); + /* extensions and private use subtags not checked */ + return (1); + +region_m49: + if (((nxt[1] >= '0') && (nxt[1] <= '9')) && + ((nxt[2] >= '0') && (nxt[2] <= '9'))) { + nxt += 3; + goto region; + } + return(0); +} + +/************************************************************************ + * * + * Parser stacks related functions and macros * + * * + ************************************************************************/ + +static xmlEntityPtr xmlParseStringEntityRef(xmlParserCtxtPtr ctxt, + const xmlChar ** str); + +#ifdef SAX2 +/** + * nsPush: + * @ctxt: an XML parser context + * @prefix: the namespace prefix or NULL + * @URL: the namespace name + * + * Pushes a new parser namespace on top of the ns stack + * + * Returns -1 in case of error, -2 if the namespace should be discarded + * and the index in the stack otherwise. + */ +static int +nsPush(xmlParserCtxtPtr ctxt, const xmlChar *prefix, const xmlChar *URL) +{ + if (ctxt->options & XML_PARSE_NSCLEAN) { + int i; + for (i = 0;i < ctxt->nsNr;i += 2) { + if (ctxt->nsTab[i] == prefix) { + /* in scope */ + if (ctxt->nsTab[i + 1] == URL) + return(-2); + /* out of scope keep it */ + break; + } + } + } + if ((ctxt->nsMax == 0) || (ctxt->nsTab == NULL)) { + ctxt->nsMax = 10; + ctxt->nsNr = 0; + ctxt->nsTab = (const xmlChar **) + xmlMalloc(ctxt->nsMax * sizeof(xmlChar *)); + if (ctxt->nsTab == NULL) { + xmlErrMemory(ctxt, NULL); + ctxt->nsMax = 0; + return (-1); + } + } else if (ctxt->nsNr >= ctxt->nsMax) { + const xmlChar ** tmp; + ctxt->nsMax *= 2; + tmp = (const xmlChar **) xmlRealloc((char *) ctxt->nsTab, + ctxt->nsMax * sizeof(ctxt->nsTab[0])); + if (tmp == NULL) { + xmlErrMemory(ctxt, NULL); + ctxt->nsMax /= 2; + return (-1); + } + ctxt->nsTab = tmp; + } + ctxt->nsTab[ctxt->nsNr++] = prefix; + ctxt->nsTab[ctxt->nsNr++] = URL; + return (ctxt->nsNr); +} +/** + * nsPop: + * @ctxt: an XML parser context + * @nr: the number to pop + * + * Pops the top @nr parser prefix/namespace from the ns stack + * + * Returns the number of namespaces removed + */ +static int +nsPop(xmlParserCtxtPtr ctxt, int nr) +{ + int i; + + if (ctxt->nsTab == NULL) return(0); + if (ctxt->nsNr < nr) { + xmlGenericError(xmlGenericErrorContext, "Pbm popping %d NS\n", nr); + nr = ctxt->nsNr; + } + if (ctxt->nsNr <= 0) + return (0); + + for (i = 0;i < nr;i++) { + ctxt->nsNr--; + ctxt->nsTab[ctxt->nsNr] = NULL; + } + return(nr); +} +#endif + +static int +xmlCtxtGrowAttrs(xmlParserCtxtPtr ctxt, int nr) { + const xmlChar **atts; + int *attallocs; + int maxatts; + + if (ctxt->atts == NULL) { + maxatts = 55; /* allow for 10 attrs by default */ + atts = (const xmlChar **) + xmlMalloc(maxatts * sizeof(xmlChar *)); + if (atts == NULL) goto mem_error; + ctxt->atts = atts; + attallocs = (int *) xmlMalloc((maxatts / 5) * sizeof(int)); + if (attallocs == NULL) goto mem_error; + ctxt->attallocs = attallocs; + ctxt->maxatts = maxatts; + } else if (nr + 5 > ctxt->maxatts) { + maxatts = (nr + 5) * 2; + atts = (const xmlChar **) xmlRealloc((void *) ctxt->atts, + maxatts * sizeof(const xmlChar *)); + if (atts == NULL) goto mem_error; + ctxt->atts = atts; + attallocs = (int *) xmlRealloc((void *) ctxt->attallocs, + (maxatts / 5) * sizeof(int)); + if (attallocs == NULL) goto mem_error; + ctxt->attallocs = attallocs; + ctxt->maxatts = maxatts; + } + return(ctxt->maxatts); +mem_error: + xmlErrMemory(ctxt, NULL); + return(-1); +} + +/** + * inputPush: + * @ctxt: an XML parser context + * @value: the parser input + * + * Pushes a new parser input on top of the input stack + * + * Returns -1 in case of error, the index in the stack otherwise + */ +int +inputPush(xmlParserCtxtPtr ctxt, xmlParserInputPtr value) +{ + if ((ctxt == NULL) || (value == NULL)) + return(-1); + if (ctxt->inputNr >= ctxt->inputMax) { + ctxt->inputMax *= 2; + ctxt->inputTab = + (xmlParserInputPtr *) xmlRealloc(ctxt->inputTab, + ctxt->inputMax * + sizeof(ctxt->inputTab[0])); + if (ctxt->inputTab == NULL) { + xmlErrMemory(ctxt, NULL); + xmlFreeInputStream(value); + ctxt->inputMax /= 2; + value = NULL; + return (-1); + } + } + ctxt->inputTab[ctxt->inputNr] = value; + ctxt->input = value; + return (ctxt->inputNr++); +} +/** + * inputPop: + * @ctxt: an XML parser context + * + * Pops the top parser input from the input stack + * + * Returns the input just removed + */ +xmlParserInputPtr +inputPop(xmlParserCtxtPtr ctxt) +{ + xmlParserInputPtr ret; + + if (ctxt == NULL) + return(NULL); + if (ctxt->inputNr <= 0) + return (NULL); + ctxt->inputNr--; + if (ctxt->inputNr > 0) + ctxt->input = ctxt->inputTab[ctxt->inputNr - 1]; + else + ctxt->input = NULL; + ret = ctxt->inputTab[ctxt->inputNr]; + ctxt->inputTab[ctxt->inputNr] = NULL; + return (ret); +} +/** + * nodePush: + * @ctxt: an XML parser context + * @value: the element node + * + * Pushes a new element node on top of the node stack + * + * Returns -1 in case of error, the index in the stack otherwise + */ +int +nodePush(xmlParserCtxtPtr ctxt, xmlNodePtr value) +{ + if (ctxt == NULL) return(0); + if (ctxt->nodeNr >= ctxt->nodeMax) { + xmlNodePtr *tmp; + + tmp = (xmlNodePtr *) xmlRealloc(ctxt->nodeTab, + ctxt->nodeMax * 2 * + sizeof(ctxt->nodeTab[0])); + if (tmp == NULL) { + xmlErrMemory(ctxt, NULL); + 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); + ctxt->instate = XML_PARSER_EOF; + return(-1); + } + ctxt->nodeTab[ctxt->nodeNr] = value; + ctxt->node = value; + return (ctxt->nodeNr++); +} + +/** + * nodePop: + * @ctxt: an XML parser context + * + * Pops the top element node from the node stack + * + * Returns the node just removed + */ +xmlNodePtr +nodePop(xmlParserCtxtPtr ctxt) +{ + xmlNodePtr ret; + + if (ctxt == NULL) return(NULL); + if (ctxt->nodeNr <= 0) + return (NULL); + ctxt->nodeNr--; + if (ctxt->nodeNr > 0) + ctxt->node = ctxt->nodeTab[ctxt->nodeNr - 1]; + else + ctxt->node = NULL; + ret = ctxt->nodeTab[ctxt->nodeNr]; + ctxt->nodeTab[ctxt->nodeNr] = NULL; + return (ret); +} + +#ifdef LIBXML_PUSH_ENABLED +/** + * nameNsPush: + * @ctxt: an XML parser context + * @value: the element name + * @prefix: the element prefix + * @URI: the element namespace name + * + * Pushes a new element name/prefix/URL on top of the name stack + * + * Returns -1 in case of error, the index in the stack otherwise + */ +static int +nameNsPush(xmlParserCtxtPtr ctxt, const xmlChar * value, + const xmlChar *prefix, const xmlChar *URI, int nsNr) +{ + if (ctxt->nameNr >= ctxt->nameMax) { + const xmlChar * *tmp; + void **tmp2; + ctxt->nameMax *= 2; + tmp = (const xmlChar * *) xmlRealloc((xmlChar * *)ctxt->nameTab, + ctxt->nameMax * + sizeof(ctxt->nameTab[0])); + if (tmp == NULL) { + ctxt->nameMax /= 2; + goto mem_error; + } + ctxt->nameTab = tmp; + tmp2 = (void **) xmlRealloc((void * *)ctxt->pushTab, + ctxt->nameMax * 3 * + sizeof(ctxt->pushTab[0])); + if (tmp2 == NULL) { + ctxt->nameMax /= 2; + goto mem_error; + } + ctxt->pushTab = tmp2; + } + ctxt->nameTab[ctxt->nameNr] = value; + ctxt->name = value; + ctxt->pushTab[ctxt->nameNr * 3] = (void *) prefix; + ctxt->pushTab[ctxt->nameNr * 3 + 1] = (void *) URI; + ctxt->pushTab[ctxt->nameNr * 3 + 2] = (void *) (long) nsNr; + return (ctxt->nameNr++); +mem_error: + xmlErrMemory(ctxt, NULL); + return (-1); +} +/** + * nameNsPop: + * @ctxt: an XML parser context + * + * Pops the top element/prefix/URI name from the name stack + * + * Returns the name just removed + */ +static const xmlChar * +nameNsPop(xmlParserCtxtPtr ctxt) +{ + const xmlChar *ret; + + if (ctxt->nameNr <= 0) + return (NULL); + ctxt->nameNr--; + if (ctxt->nameNr > 0) + ctxt->name = ctxt->nameTab[ctxt->nameNr - 1]; + else + ctxt->name = NULL; + ret = ctxt->nameTab[ctxt->nameNr]; + ctxt->nameTab[ctxt->nameNr] = NULL; + return (ret); +} +#endif /* LIBXML_PUSH_ENABLED */ + +/** + * namePush: + * @ctxt: an XML parser context + * @value: the element name + * + * Pushes a new element name on top of the name stack + * + * Returns -1 in case of error, the index in the stack otherwise + */ +int +namePush(xmlParserCtxtPtr ctxt, const xmlChar * value) +{ + if (ctxt == NULL) return (-1); + + if (ctxt->nameNr >= ctxt->nameMax) { + const xmlChar * *tmp; + tmp = (const xmlChar * *) xmlRealloc((xmlChar * *)ctxt->nameTab, + ctxt->nameMax * 2 * + sizeof(ctxt->nameTab[0])); + if (tmp == NULL) { + goto mem_error; + } + ctxt->nameTab = tmp; + ctxt->nameMax *= 2; + } + ctxt->nameTab[ctxt->nameNr] = value; + ctxt->name = value; + return (ctxt->nameNr++); +mem_error: + xmlErrMemory(ctxt, NULL); + return (-1); +} +/** + * namePop: + * @ctxt: an XML parser context + * + * Pops the top element name from the name stack + * + * Returns the name just removed + */ +const xmlChar * +namePop(xmlParserCtxtPtr ctxt) +{ + const xmlChar *ret; + + if ((ctxt == NULL) || (ctxt->nameNr <= 0)) + return (NULL); + ctxt->nameNr--; + if (ctxt->nameNr > 0) + ctxt->name = ctxt->nameTab[ctxt->nameNr - 1]; + else + ctxt->name = NULL; + ret = ctxt->nameTab[ctxt->nameNr]; + ctxt->nameTab[ctxt->nameNr] = NULL; + return (ret); +} + +static int spacePush(xmlParserCtxtPtr ctxt, int val) { + if (ctxt->spaceNr >= ctxt->spaceMax) { + int *tmp; + + ctxt->spaceMax *= 2; + tmp = (int *) xmlRealloc(ctxt->spaceTab, + ctxt->spaceMax * sizeof(ctxt->spaceTab[0])); + if (tmp == NULL) { + xmlErrMemory(ctxt, NULL); + ctxt->spaceMax /=2; + return(-1); + } + ctxt->spaceTab = tmp; + } + ctxt->spaceTab[ctxt->spaceNr] = val; + ctxt->space = &ctxt->spaceTab[ctxt->spaceNr]; + return(ctxt->spaceNr++); +} + +static int spacePop(xmlParserCtxtPtr ctxt) { + int ret; + if (ctxt->spaceNr <= 0) return(0); + ctxt->spaceNr--; + if (ctxt->spaceNr > 0) + ctxt->space = &ctxt->spaceTab[ctxt->spaceNr - 1]; + else + ctxt->space = &ctxt->spaceTab[0]; + ret = ctxt->spaceTab[ctxt->spaceNr]; + ctxt->spaceTab[ctxt->spaceNr] = -1; + return(ret); +} + +/* + * Macros for accessing the content. Those should be used only by the parser, + * and not exported. + * + * Dirty macros, i.e. one often need to make assumption on the context to + * use them + * + * CUR_PTR return the current pointer to the xmlChar to be parsed. + * To be used with extreme caution since operations consuming + * characters may move the input buffer to a different location ! + * CUR returns the current xmlChar value, i.e. a 8 bit value if compiled + * This should be used internally by the parser + * only to compare to ASCII values otherwise it would break when + * running with UTF-8 encoding. + * RAW same as CUR but in the input buffer, bypass any token + * extraction that may have been done + * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only + * to compare on ASCII based substring. + * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined + * strings without newlines within the parser. + * NEXT1(l) Skip 1 xmlChar, and must also be used only to skip 1 non-newline ASCII + * defined char within the parser. + * Clean macros, not dependent of an ASCII context, expect UTF-8 encoding + * + * NEXT Skip to the next character, this does the proper decoding + * in UTF-8 mode. It also pop-up unfinished entities on the fly. + * NEXTL(l) Skip the current unicode character of l xmlChars long. + * CUR_CHAR(l) returns the current unicode character (int), set l + * to the number of xmlChars used for the encoding [0-5]. + * CUR_SCHAR same but operate on a string instead of the context + * COPY_BUF copy the current unicode char to the target buffer, increment + * the index + * GROW, SHRINK handling of input buffers + */ + +#define RAW (*ctxt->input->cur) +#define CUR (*ctxt->input->cur) +#define NXT(val) ctxt->input->cur[(val)] +#define CUR_PTR ctxt->input->cur + +#define CMP4( s, c1, c2, c3, c4 ) \ + ( ((unsigned char *) s)[ 0 ] == c1 && ((unsigned char *) s)[ 1 ] == c2 && \ + ((unsigned char *) s)[ 2 ] == c3 && ((unsigned char *) s)[ 3 ] == c4 ) +#define CMP5( s, c1, c2, c3, c4, c5 ) \ + ( CMP4( s, c1, c2, c3, c4 ) && ((unsigned char *) s)[ 4 ] == c5 ) +#define CMP6( s, c1, c2, c3, c4, c5, c6 ) \ + ( CMP5( s, c1, c2, c3, c4, c5 ) && ((unsigned char *) s)[ 5 ] == c6 ) +#define CMP7( s, c1, c2, c3, c4, c5, c6, c7 ) \ + ( CMP6( s, c1, c2, c3, c4, c5, c6 ) && ((unsigned char *) s)[ 6 ] == c7 ) +#define CMP8( s, c1, c2, c3, c4, c5, c6, c7, c8 ) \ + ( CMP7( s, c1, c2, c3, c4, c5, c6, c7 ) && ((unsigned char *) s)[ 7 ] == c8 ) +#define CMP9( s, c1, c2, c3, c4, c5, c6, c7, c8, c9 ) \ + ( CMP8( s, c1, c2, c3, c4, c5, c6, c7, c8 ) && \ + ((unsigned char *) s)[ 8 ] == c9 ) +#define CMP10( s, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10 ) \ + ( CMP9( s, c1, c2, c3, c4, c5, c6, c7, c8, c9 ) && \ + ((unsigned char *) s)[ 9 ] == c10 ) + +#define SKIP(val) do { \ + ctxt->nbChars += (val),ctxt->input->cur += (val),ctxt->input->col+=(val); \ + if (*ctxt->input->cur == '%') xmlParserHandlePEReference(ctxt); \ + if ((*ctxt->input->cur == 0) && \ + (xmlParserInputGrow(ctxt->input, INPUT_CHUNK) <= 0)) \ + xmlPopInput(ctxt); \ + } while (0) + +#define SKIPL(val) do { \ + int skipl; \ + for(skipl=0; skiplinput->cur) == '\n') { \ + ctxt->input->line++; ctxt->input->col = 1; \ + } else ctxt->input->col++; \ + ctxt->nbChars++; \ + ctxt->input->cur++; \ + } \ + if (*ctxt->input->cur == '%') xmlParserHandlePEReference(ctxt); \ + if ((*ctxt->input->cur == 0) && \ + (xmlParserInputGrow(ctxt->input, INPUT_CHUNK) <= 0)) \ + xmlPopInput(ctxt); \ + } while (0) + +#define SHRINK if ((ctxt->progressive == 0) && \ + (ctxt->input->cur - ctxt->input->base > 2 * INPUT_CHUNK) && \ + (ctxt->input->end - ctxt->input->cur < 2 * INPUT_CHUNK)) \ + xmlSHRINK (ctxt); + +static void xmlSHRINK (xmlParserCtxtPtr ctxt) { + xmlParserInputShrink(ctxt->input); + if ((*ctxt->input->cur == 0) && + (xmlParserInputGrow(ctxt->input, INPUT_CHUNK) <= 0)) + xmlPopInput(ctxt); + } + +#define GROW if ((ctxt->progressive == 0) && \ + (ctxt->input->end - ctxt->input->cur < INPUT_CHUNK)) \ + xmlGROW (ctxt); + +static void xmlGROW (xmlParserCtxtPtr ctxt) { + xmlParserInputGrow(ctxt->input, INPUT_CHUNK); + if ((ctxt->input->cur != NULL) && (*ctxt->input->cur == 0) && + (xmlParserInputGrow(ctxt->input, INPUT_CHUNK) <= 0)) + xmlPopInput(ctxt); +} + +#define SKIP_BLANKS xmlSkipBlankChars(ctxt) + +#define NEXT xmlNextChar(ctxt) + +#define NEXT1 { \ + ctxt->input->col++; \ + ctxt->input->cur++; \ + ctxt->nbChars++; \ + if (*ctxt->input->cur == 0) \ + xmlParserInputGrow(ctxt->input, INPUT_CHUNK); \ + } + +#define NEXTL(l) do { \ + if (*(ctxt->input->cur) == '\n') { \ + ctxt->input->line++; ctxt->input->col = 1; \ + } else ctxt->input->col++; \ + ctxt->input->cur += l; \ + if (*ctxt->input->cur == '%') xmlParserHandlePEReference(ctxt); \ + } while (0) + +#define CUR_CHAR(l) xmlCurrentChar(ctxt, &l) +#define CUR_SCHAR(s, l) xmlStringCurrentChar(ctxt, s, &l) + +#define COPY_BUF(l,b,i,v) \ + if (l == 1) b[i++] = (xmlChar) v; \ + else i += xmlCopyCharMultiByte(&b[i],v) + +/** + * xmlSkipBlankChars: + * @ctxt: the XML parser context + * + * skip all blanks character found at that point in the input streams. + * It pops up finished entities in the process if allowable at that point. + * + * Returns the number of space chars skipped + */ + +int +xmlSkipBlankChars(xmlParserCtxtPtr ctxt) { + int res = 0; + + /* + * It's Okay to use CUR/NEXT here since all the blanks are on + * the ASCII range. + */ + if ((ctxt->inputNr == 1) && (ctxt->instate != XML_PARSER_DTD)) { + const xmlChar *cur; + /* + * if we are in the document content, go really fast + */ + cur = ctxt->input->cur; + while (IS_BLANK_CH(*cur)) { + if (*cur == '\n') { + ctxt->input->line++; ctxt->input->col = 1; + } + cur++; + res++; + if (*cur == 0) { + ctxt->input->cur = cur; + xmlParserInputGrow(ctxt->input, INPUT_CHUNK); + cur = ctxt->input->cur; + } + } + ctxt->input->cur = cur; + } else { + int cur; + do { + cur = CUR; + while (IS_BLANK_CH(cur)) { /* CHECKED tstblanks.xml */ + NEXT; + cur = CUR; + res++; + } + while ((cur == 0) && (ctxt->inputNr > 1) && + (ctxt->instate != XML_PARSER_COMMENT)) { + xmlPopInput(ctxt); + cur = CUR; + } + /* + * Need to handle support of entities branching here + */ + if (*ctxt->input->cur == '%') xmlParserHandlePEReference(ctxt); + } while (IS_BLANK(cur)); /* CHECKED tstblanks.xml */ + } + return(res); +} + +/************************************************************************ + * * + * Commodity functions to handle entities * + * * + ************************************************************************/ + +/** + * xmlPopInput: + * @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 + */ +xmlChar +xmlPopInput(xmlParserCtxtPtr ctxt) { + if ((ctxt == NULL) || (ctxt->inputNr <= 1)) return(0); + if (xmlParserDebugEntities) + xmlGenericError(xmlGenericErrorContext, + "Popping input %d\n", ctxt->inputNr); + xmlFreeInputStream(inputPop(ctxt)); + if ((*ctxt->input->cur == 0) && + (xmlParserInputGrow(ctxt->input, INPUT_CHUNK) <= 0)) + return(xmlPopInput(ctxt)); + return(CUR); +} + +/** + * xmlPushInput: + * @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). + * Returns -1 in case of error or the index in the input stack + */ +int +xmlPushInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr input) { + 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); + } + ret = inputPush(ctxt, input); + GROW; + return(ret); +} + +/** + * xmlParseCharRef: + * @ctxt: an XML parser context + * + * parse Reference declarations + * + * [66] CharRef ::= '&#' [0-9]+ ';' | + * '&#x' [0-9a-fA-F]+ ';' + * + * [ WFC: Legal Character ] + * Characters referred to using character references must match the + * production for Char. + * + * Returns the value parsed (as an int), 0 in case of error + */ +int +xmlParseCharRef(xmlParserCtxtPtr ctxt) { + unsigned int val = 0; + int count = 0; + unsigned int outofrange = 0; + + /* + * Using RAW/CUR/NEXT is okay since we are working on ASCII range here + */ + if ((RAW == '&') && (NXT(1) == '#') && + (NXT(2) == 'x')) { + SKIP(3); + GROW; + while (RAW != ';') { /* loop blocked by count */ + if (count++ > 20) { + count = 0; + GROW; + } + if ((RAW >= '0') && (RAW <= '9')) + val = val * 16 + (CUR - '0'); + else if ((RAW >= 'a') && (RAW <= 'f') && (count < 20)) + val = val * 16 + (CUR - 'a') + 10; + else if ((RAW >= 'A') && (RAW <= 'F') && (count < 20)) + val = val * 16 + (CUR - 'A') + 10; + else { + xmlFatalErr(ctxt, XML_ERR_INVALID_HEX_CHARREF, NULL); + val = 0; + break; + } + if (val > 0x10FFFF) + outofrange = val; + + NEXT; + count++; + } + if (RAW == ';') { + /* on purpose to avoid reentrancy problems with NEXT and SKIP */ + ctxt->input->col++; + ctxt->nbChars ++; + ctxt->input->cur++; + } + } else if ((RAW == '&') && (NXT(1) == '#')) { + SKIP(2); + GROW; + while (RAW != ';') { /* loop blocked by count */ + if (count++ > 20) { + count = 0; + GROW; + } + if ((RAW >= '0') && (RAW <= '9')) + val = val * 10 + (CUR - '0'); + else { + xmlFatalErr(ctxt, XML_ERR_INVALID_DEC_CHARREF, NULL); + val = 0; + break; + } + if (val > 0x10FFFF) + outofrange = val; + + NEXT; + count++; + } + if (RAW == ';') { + /* on purpose to avoid reentrancy problems with NEXT and SKIP */ + ctxt->input->col++; + ctxt->nbChars ++; + ctxt->input->cur++; + } + } else { + xmlFatalErr(ctxt, XML_ERR_INVALID_CHARREF, NULL); + } + + /* + * [ WFC: Legal Character ] + * Characters referred to using character references must match the + * production for Char. + */ + if ((IS_CHAR(val) && (outofrange == 0))) { + return(val); + } else { + xmlFatalErrMsgInt(ctxt, XML_ERR_INVALID_CHAR, + "xmlParseCharRef: invalid xmlChar value %d\n", + val); + } + return(0); +} + +/** + * xmlParseStringCharRef: + * @ctxt: an XML parser context + * @str: a pointer to an index in the string + * + * parse Reference declarations, variant parsing from a string rather + * than an an input flow. + * + * [66] CharRef ::= '&#' [0-9]+ ';' | + * '&#x' [0-9a-fA-F]+ ';' + * + * [ WFC: Legal Character ] + * Characters referred to using character references must match the + * production for Char. + * + * Returns the value parsed (as an int), 0 in case of error, str will be + * updated to the current value of the index + */ +static int +xmlParseStringCharRef(xmlParserCtxtPtr ctxt, const xmlChar **str) { + const xmlChar *ptr; + xmlChar cur; + unsigned int val = 0; + unsigned int outofrange = 0; + + if ((str == NULL) || (*str == NULL)) return(0); + ptr = *str; + cur = *ptr; + if ((cur == '&') && (ptr[1] == '#') && (ptr[2] == 'x')) { + ptr += 3; + cur = *ptr; + while (cur != ';') { /* Non input consuming loop */ + if ((cur >= '0') && (cur <= '9')) + val = val * 16 + (cur - '0'); + else if ((cur >= 'a') && (cur <= 'f')) + val = val * 16 + (cur - 'a') + 10; + else if ((cur >= 'A') && (cur <= 'F')) + val = val * 16 + (cur - 'A') + 10; + else { + xmlFatalErr(ctxt, XML_ERR_INVALID_HEX_CHARREF, NULL); + val = 0; + break; + } + if (val > 0x10FFFF) + outofrange = val; + + ptr++; + cur = *ptr; + } + if (cur == ';') + ptr++; + } else if ((cur == '&') && (ptr[1] == '#')){ + ptr += 2; + cur = *ptr; + while (cur != ';') { /* Non input consuming loops */ + if ((cur >= '0') && (cur <= '9')) + val = val * 10 + (cur - '0'); + else { + xmlFatalErr(ctxt, XML_ERR_INVALID_DEC_CHARREF, NULL); + val = 0; + break; + } + if (val > 0x10FFFF) + outofrange = val; + + ptr++; + cur = *ptr; + } + if (cur == ';') + ptr++; + } else { + xmlFatalErr(ctxt, XML_ERR_INVALID_CHARREF, NULL); + return(0); + } + *str = ptr; + + /* + * [ WFC: Legal Character ] + * Characters referred to using character references must match the + * production for Char. + */ + if ((IS_CHAR(val) && (outofrange == 0))) { + return(val); + } else { + xmlFatalErrMsgInt(ctxt, XML_ERR_INVALID_CHAR, + "xmlParseStringCharRef: invalid xmlChar value %d\n", + val); + } + return(0); +} + +/** + * xmlNewBlanksWrapperInputStream: + * @ctxt: an XML parser context + * @entity: an Entity pointer + * + * Create a new input stream for wrapping + * blanks around a PEReference + * + * Returns the new input stream or NULL + */ + +static void deallocblankswrapper (xmlChar *str) {xmlFree(str);} + +static xmlParserInputPtr +xmlNewBlanksWrapperInputStream(xmlParserCtxtPtr ctxt, xmlEntityPtr entity) { + xmlParserInputPtr input; + xmlChar *buffer; + size_t length; + if (entity == NULL) { + xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR, + "xmlNewBlanksWrapperInputStream entity\n"); + return(NULL); + } + if (xmlParserDebugEntities) + xmlGenericError(xmlGenericErrorContext, + "new blanks wrapper for entity: %s\n", entity->name); + input = xmlNewInputStream(ctxt); + if (input == NULL) { + return(NULL); + } + length = xmlStrlen(entity->name) + 5; + buffer = xmlMallocAtomic(length); + if (buffer == NULL) { + xmlErrMemory(ctxt, NULL); + xmlFree(input); + return(NULL); + } + buffer [0] = ' '; + buffer [1] = '%'; + buffer [length-3] = ';'; + buffer [length-2] = ' '; + buffer [length-1] = 0; + memcpy(buffer + 2, entity->name, length - 5); + input->free = deallocblankswrapper; + input->base = buffer; + input->cur = buffer; + input->length = length; + input->end = &buffer[length]; + return(input); +} + +/** + * xmlParserHandlePEReference: + * @ctxt: the parser context + * + * [69] PEReference ::= '%' Name ';' + * + * [ WFC: No Recursion ] + * A parsed entity must not contain a recursive + * reference to itself, either directly or indirectly. + * + * [ WFC: Entity Declared ] + * In a document without any DTD, a document with only an internal DTD + * subset which contains no parameter entity references, or a document + * with "standalone='yes'", ... ... The declaration of a parameter + * entity must precede any reference to it... + * + * [ VC: Entity Declared ] + * In a document with an external subset or external parameter entities + * with "standalone='no'", ... ... The declaration of a parameter entity + * must precede any reference to it... + * + * [ WFC: In DTD ] + * Parameter-entity references may only appear in the DTD. + * NOTE: misleading but this is handled. + * + * A PEReference may have been detected in the current input stream + * the handling is done accordingly to + * http://www.w3.org/TR/REC-xml#entproc + * i.e. + * - Included in literal in entity values + * - Included as Parameter Entity reference within DTDs + */ +void +xmlParserHandlePEReference(xmlParserCtxtPtr ctxt) { + const xmlChar *name; + xmlEntityPtr entity = NULL; + xmlParserInputPtr input; + + if (RAW != '%') return; + switch(ctxt->instate) { + case XML_PARSER_CDATA_SECTION: + return; + case XML_PARSER_COMMENT: + return; + case XML_PARSER_START_TAG: + return; + case XML_PARSER_END_TAG: + return; + case XML_PARSER_EOF: + xmlFatalErr(ctxt, XML_ERR_PEREF_AT_EOF, NULL); + return; + case XML_PARSER_PROLOG: + case XML_PARSER_START: + case XML_PARSER_MISC: + xmlFatalErr(ctxt, XML_ERR_PEREF_IN_PROLOG, NULL); + return; + case XML_PARSER_ENTITY_DECL: + case XML_PARSER_CONTENT: + case XML_PARSER_ATTRIBUTE_VALUE: + case XML_PARSER_PI: + case XML_PARSER_SYSTEM_LITERAL: + case XML_PARSER_PUBLIC_LITERAL: + /* we just ignore it there */ + return; + case XML_PARSER_EPILOG: + xmlFatalErr(ctxt, XML_ERR_PEREF_IN_EPILOG, NULL); + return; + case XML_PARSER_ENTITY_VALUE: + /* + * NOTE: in the case of entity values, we don't do the + * substitution here since we need the literal + * entity value to be able to save the internal + * subset of the document. + * This will be handled by xmlStringDecodeEntities + */ + return; + case XML_PARSER_DTD: + /* + * [WFC: Well-Formedness Constraint: PEs in Internal Subset] + * In the internal DTD subset, parameter-entity references + * can occur only where markup declarations can occur, not + * within markup declarations. + * In that case this is handled in xmlParseMarkupDecl + */ + if ((ctxt->external == 0) && (ctxt->inputNr == 1)) + return; + if (IS_BLANK_CH(NXT(1)) || NXT(1) == 0) + return; + break; + case XML_PARSER_IGNORE: + return; + } + + NEXT; + name = xmlParseName(ctxt); + if (xmlParserDebugEntities) + xmlGenericError(xmlGenericErrorContext, + "PEReference: %s\n", name); + if (name == NULL) { + xmlFatalErr(ctxt, XML_ERR_PEREF_NO_NAME, NULL); + } else { + if (RAW == ';') { + NEXT; + if ((ctxt->sax != NULL) && (ctxt->sax->getParameterEntity != NULL)) + entity = ctxt->sax->getParameterEntity(ctxt->userData, name); + if (entity == NULL) { + + /* + * [ WFC: Entity Declared ] + * In a document without any DTD, a document with only an + * internal DTD subset which contains no parameter entity + * references, or a document with "standalone='yes'", ... + * ... The declaration of a parameter entity must precede + * any reference to it... + */ + if ((ctxt->standalone == 1) || + ((ctxt->hasExternalSubset == 0) && + (ctxt->hasPErefs == 0))) { + xmlFatalErrMsgStr(ctxt, XML_ERR_UNDECLARED_ENTITY, + "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; + } + } else if (ctxt->input->free != deallocblankswrapper) { + input = xmlNewBlanksWrapperInputStream(ctxt, entity); + if (xmlPushInput(ctxt, input) < 0) + return; + } else { + if ((entity->etype == XML_INTERNAL_PARAMETER_ENTITY) || + (entity->etype == XML_EXTERNAL_PARAMETER_ENTITY)) { + xmlChar start[4]; + xmlCharEncoding enc; + + /* + * handle the extra spaces added before and after + * c.f. http://www.w3.org/TR/REC-xml#as-PE + * this is done independently. + */ + input = xmlNewEntityInputStream(ctxt, entity); + if (xmlPushInput(ctxt, input) < 0) + return; + + /* + * Get the 4 first bytes and decode the charset + * if enc != XML_CHAR_ENCODING_NONE + * plug some encoding conversion routines. + * Note that, since we may have some non-UTF8 + * encoding (like UTF16, bug 135229), the 'length' + * is not known, but we can calculate based upon + * the amount of data in the buffer. + */ + GROW + if ((ctxt->input->end - ctxt->input->cur)>=4) { + start[0] = RAW; + start[1] = NXT(1); + start[2] = NXT(2); + start[3] = NXT(3); + enc = xmlDetectCharEncoding(start, 4); + if (enc != XML_CHAR_ENCODING_NONE) { + xmlSwitchEncoding(ctxt, enc); + } + } + + if ((entity->etype == XML_EXTERNAL_PARAMETER_ENTITY) && + (CMP5(CUR_PTR, '<', '?', 'x', 'm', 'l' )) && + (IS_BLANK_CH(NXT(5)))) { + xmlParseTextDecl(ctxt); + } + } else { + xmlFatalErrMsgStr(ctxt, XML_ERR_ENTITY_IS_PARAMETER, + "PEReference: %s is not a parameter entity\n", + name); + } + } + } else { + xmlFatalErr(ctxt, XML_ERR_PEREF_SEMICOL_MISSING, NULL); + } + } +} + +/* + * Macro used to grow the current buffer. + */ +#define growBuffer(buffer, n) { \ + xmlChar *tmp; \ + buffer##_size *= 2; \ + buffer##_size += n; \ + tmp = (xmlChar *) \ + xmlRealloc(buffer, buffer##_size * sizeof(xmlChar)); \ + if (tmp == NULL) goto mem_error; \ + buffer = tmp; \ +} + +/** + * xmlStringLenDecodeEntities: + * @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 + * + * 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) { + xmlChar *buffer = NULL; + int buffer_size = 0; + + xmlChar *current = NULL; + xmlChar *rep = NULL; + const xmlChar *last; + xmlEntityPtr ent; + int c,l; + int nbchars = 0; + + if ((ctxt == NULL) || (str == NULL) || (len < 0)) + return(NULL); + last = str + len; + + if (((ctxt->depth > 40) && + ((ctxt->options & XML_PARSE_HUGE) == 0)) || + (ctxt->depth > 1024)) { + xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL); + return(NULL); + } + + /* + * allocate a translation buffer. + */ + buffer_size = XML_PARSER_BIG_BUFFER_SIZE; + buffer = (xmlChar *) xmlMallocAtomic(buffer_size * sizeof(xmlChar)); + if (buffer == NULL) goto mem_error; + + /* + * OK loop until we reach one of the ending char or a size limit. + * we are operating on already parsed values. + */ + if (str < last) + c = CUR_SCHAR(str, l); + else + c = 0; + while ((c != 0) && (c != end) && /* non input consuming loop */ + (c != end2) && (c != end3)) { + + if (c == 0) break; + if ((c == '&') && (str[1] == '#')) { + int val = xmlParseStringCharRef(ctxt, &str); + if (val != 0) { + COPY_BUF(0,buffer,nbchars,val); + } + if (nbchars > buffer_size - XML_PARSER_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 ((ctxt->lastError.code == XML_ERR_ENTITY_LOOP) || + (ctxt->lastError.code == XML_ERR_INTERNAL_ERROR)) + goto int_error; + if (ent != NULL) + ctxt->nbentities += ent->checked; + if ((ent != NULL) && + (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) { + if (ent->content != NULL) { + COPY_BUF(0,buffer,nbchars,ent->content[0]); + if (nbchars > buffer_size - XML_PARSER_BUFFER_SIZE) { + growBuffer(buffer, XML_PARSER_BUFFER_SIZE); + } + } else { + xmlFatalErrMsg(ctxt, XML_ERR_INTERNAL_ERROR, + "predefined entity has no content\n"); + } + } else if ((ent != NULL) && (ent->content != NULL)) { + ctxt->depth++; + rep = xmlStringDecodeEntities(ctxt, ent->content, what, + 0, 0, 0); + ctxt->depth--; + + if (rep != NULL) { + current = rep; + while (*current != 0) { /* non input consuming loop */ + buffer[nbchars++] = *current++; + if (nbchars > + buffer_size - XML_PARSER_BUFFER_SIZE) { + if (xmlParserEntityCheck(ctxt, nbchars, ent)) + goto int_error; + 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 > buffer_size - i - XML_PARSER_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 (ctxt->lastError.code == XML_ERR_ENTITY_LOOP) + goto int_error; + if (ent != NULL) + ctxt->nbentities += ent->checked; + if (ent != NULL) { + if (ent->content == NULL) { + xmlLoadEntityContent(ctxt, ent); + } + ctxt->depth++; + rep = xmlStringDecodeEntities(ctxt, ent->content, what, + 0, 0, 0); + ctxt->depth--; + if (rep != NULL) { + current = rep; + while (*current != 0) { /* non input consuming loop */ + buffer[nbchars++] = *current++; + if (nbchars > + buffer_size - XML_PARSER_BUFFER_SIZE) { + if (xmlParserEntityCheck(ctxt, nbchars, ent)) + goto int_error; + growBuffer(buffer, XML_PARSER_BUFFER_SIZE); + } + } + xmlFree(rep); + rep = NULL; + } + } + } else { + COPY_BUF(l,buffer,nbchars,c); + str += l; + if (nbchars > buffer_size - XML_PARSER_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); +} + +/** + * xmlStringDecodeEntities: + * @ctxt: the parser context + * @str: the input string + * @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 + * + * 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, + xmlChar end, xmlChar end2, xmlChar end3) { + if ((ctxt == NULL) || (str == NULL)) return(NULL); + return(xmlStringLenDecodeEntities(ctxt, str, xmlStrlen(str), what, + end, end2, end3)); +} + +/************************************************************************ + * * + * Commodity functions, cleanup needed ? * + * * + ************************************************************************/ + +/** + * areBlanks: + * @ctxt: an XML parser context + * @str: a xmlChar * + * @len: the size of @str + * @blank_chars: we know the chars are blanks + * + * Is this a sequence of blank chars that one can ignore ? + * + * Returns 1 if ignorable 0 otherwise. + */ + +static int areBlanks(xmlParserCtxtPtr ctxt, const xmlChar *str, int len, + int blank_chars) { + int i, ret; + xmlNodePtr lastChild; + + /* + * Don't spend time trying to differentiate them, the same callback is + * used ! + */ + if (ctxt->sax->ignorableWhitespace == ctxt->sax->characters) + return(0); + + /* + * Check for xml:space value. + */ + if ((ctxt->space == NULL) || (*(ctxt->space) == 1) || + (*(ctxt->space) == -2)) + return(0); + + /* + * Check that the string is made of blanks + */ + if (blank_chars == 0) { + for (i = 0;i < len;i++) + if (!(IS_BLANK_CH(str[i]))) return(0); + } + + /* + * Look if the element is mixed content in the DTD if available + */ + if (ctxt->node == NULL) return(0); + if (ctxt->myDoc != NULL) { + ret = xmlIsMixedElement(ctxt->myDoc, ctxt->node->name); + if (ret == 0) return(1); + if (ret == 1) return(0); + } + + /* + * Otherwise, heuristic :-\ + */ + if ((RAW != '<') && (RAW != 0xD)) return(0); + if ((ctxt->node->children == NULL) && + (RAW == '<') && (NXT(1) == '/')) return(0); + + lastChild = xmlGetLastChild(ctxt->node); + if (lastChild == NULL) { + if ((ctxt->node->type != XML_ELEMENT_NODE) && + (ctxt->node->content != NULL)) return(0); + } else if (xmlNodeIsText(lastChild)) + return(0); + else if ((ctxt->node->children != NULL) && + (xmlNodeIsText(ctxt->node->children))) + return(0); + return(1); +} + +/************************************************************************ + * * + * Extra stuff for namespace support * + * Relates to http://www.w3.org/TR/WD-xml-names * + * * + ************************************************************************/ + +/** + * xmlSplitQName: + * @ctxt: an XML parser context + * @name: an XML parser context + * @prefix: a xmlChar ** + * + * parse an UTF8 encoded XML qualified name string + * + * [NS 5] QName ::= (Prefix ':')? LocalPart + * + * [NS 6] Prefix ::= NCName + * + * [NS 7] LocalPart ::= NCName + * + * Returns the local part, and prefix is updated + * to get the Prefix if any. + */ + +xmlChar * +xmlSplitQName(xmlParserCtxtPtr ctxt, const xmlChar *name, xmlChar **prefix) { + xmlChar buf[XML_MAX_NAMELEN + 5]; + xmlChar *buffer = NULL; + int len = 0; + int max = XML_MAX_NAMELEN; + xmlChar *ret = NULL; + const xmlChar *cur = name; + int c; + + if (prefix == NULL) return(NULL); + *prefix = NULL; + + if (cur == NULL) return(NULL); + +#ifndef XML_XML_NAMESPACE + /* xml: prefix is not really a namespace */ + if ((cur[0] == 'x') && (cur[1] == 'm') && + (cur[2] == 'l') && (cur[3] == ':')) + return(xmlStrdup(name)); +#endif + + /* nasty but well=formed */ + if (cur[0] == ':') + return(xmlStrdup(name)); + + c = *cur++; + while ((c != 0) && (c != ':') && (len < max)) { /* tested bigname.xml */ + buf[len++] = c; + c = *cur++; + } + if (len >= max) { + /* + * Okay someone managed to make a huge name, so he's ready to pay + * for the processing speed. + */ + max = len * 2; + + buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar)); + if (buffer == NULL) { + xmlErrMemory(ctxt, NULL); + return(NULL); + } + memcpy(buffer, buf, len); + while ((c != 0) && (c != ':')) { /* tested bigname.xml */ + if (len + 10 > max) { + xmlChar *tmp; + + max *= 2; + tmp = (xmlChar *) xmlRealloc(buffer, + max * sizeof(xmlChar)); + if (tmp == NULL) { + xmlFree(buffer); + xmlErrMemory(ctxt, NULL); + return(NULL); + } + buffer = tmp; + } + buffer[len++] = c; + c = *cur++; + } + buffer[len] = 0; + } + + if ((c == ':') && (*cur == 0)) { + if (buffer != NULL) + xmlFree(buffer); + *prefix = NULL; + return(xmlStrdup(name)); + } + + if (buffer == NULL) + ret = xmlStrndup(buf, len); + else { + ret = buffer; + buffer = NULL; + max = XML_MAX_NAMELEN; + } + + + if (c == ':') { + c = *cur; + *prefix = ret; + if (c == 0) { + return(xmlStrndup(BAD_CAST "", 0)); + } + len = 0; + + /* + * Check that the first character is proper to start + * a new name + */ + if (!(((c >= 0x61) && (c <= 0x7A)) || + ((c >= 0x41) && (c <= 0x5A)) || + (c == '_') || (c == ':'))) { + int l; + int first = CUR_SCHAR(cur, l); + + if (!IS_LETTER(first) && (first != '_')) { + xmlFatalErrMsgStr(ctxt, XML_NS_ERR_QNAME, + "Name %s is not XML Namespace compliant\n", + name); + } + } + cur++; + + while ((c != 0) && (len < max)) { /* tested bigname2.xml */ + buf[len++] = c; + c = *cur++; + } + if (len >= max) { + /* + * Okay someone managed to make a huge name, so he's ready to pay + * for the processing speed. + */ + max = len * 2; + + buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar)); + if (buffer == NULL) { + xmlErrMemory(ctxt, NULL); + return(NULL); + } + memcpy(buffer, buf, len); + while (c != 0) { /* tested bigname2.xml */ + if (len + 10 > max) { + xmlChar *tmp; + + max *= 2; + tmp = (xmlChar *) xmlRealloc(buffer, + max * sizeof(xmlChar)); + if (tmp == NULL) { + xmlErrMemory(ctxt, NULL); + xmlFree(buffer); + return(NULL); + } + buffer = tmp; + } + buffer[len++] = c; + c = *cur++; + } + buffer[len] = 0; + } + + if (buffer == NULL) + ret = xmlStrndup(buf, len); + else { + ret = buffer; + } + } + + return(ret); +} + +/************************************************************************ + * * + * The parser itself * + * Relates to http://www.w3.org/TR/REC-xml * + * * + ************************************************************************/ + +/************************************************************************ + * * + * Routines to parse Name, NCName and NmToken * + * * + ************************************************************************/ +#ifdef DEBUG +static unsigned long nbParseName = 0; +static unsigned long nbParseNmToken = 0; +static unsigned long nbParseNCName = 0; +static unsigned long nbParseNCNameComplex = 0; +static unsigned long nbParseNameComplex = 0; +static unsigned long nbParseStringName = 0; +#endif + +/* + * The two following functions are related to the change of accepted + * characters for Name and NmToken in the Revision 5 of XML-1.0 + * They correspond to the modified production [4] and the new production [4a] + * changes in that revision. Also note that the macros used for the + * productions Letter, Digit, CombiningChar and Extender are not needed + * anymore. + * We still keep compatibility to pre-revision5 parsing semantic if the + * new XML_PARSE_OLD10 option is given to the parser. + */ +static int +xmlIsNameStartChar(xmlParserCtxtPtr ctxt, int c) { + if ((ctxt->options & XML_PARSE_OLD10) == 0) { + /* + * Use the new checks of production [4] [4a] amd [5] of the + * Update 5 of XML-1.0 + */ + if ((c != ' ') && (c != '>') && (c != '/') && /* accelerators */ + (((c >= 'a') && (c <= 'z')) || + ((c >= 'A') && (c <= 'Z')) || + (c == '_') || (c == ':') || + ((c >= 0xC0) && (c <= 0xD6)) || + ((c >= 0xD8) && (c <= 0xF6)) || + ((c >= 0xF8) && (c <= 0x2FF)) || + ((c >= 0x370) && (c <= 0x37D)) || + ((c >= 0x37F) && (c <= 0x1FFF)) || + ((c >= 0x200C) && (c <= 0x200D)) || + ((c >= 0x2070) && (c <= 0x218F)) || + ((c >= 0x2C00) && (c <= 0x2FEF)) || + ((c >= 0x3001) && (c <= 0xD7FF)) || + ((c >= 0xF900) && (c <= 0xFDCF)) || + ((c >= 0xFDF0) && (c <= 0xFFFD)) || + ((c >= 0x10000) && (c <= 0xEFFFF)))) + return(1); + } else { + if (IS_LETTER(c) || (c == '_') || (c == ':')) + return(1); + } + return(0); +} + +static int +xmlIsNameChar(xmlParserCtxtPtr ctxt, int c) { + if ((ctxt->options & XML_PARSE_OLD10) == 0) { + /* + * Use the new checks of production [4] [4a] amd [5] of the + * Update 5 of XML-1.0 + */ + if ((c != ' ') && (c != '>') && (c != '/') && /* accelerators */ + (((c >= 'a') && (c <= 'z')) || + ((c >= 'A') && (c <= 'Z')) || + ((c >= '0') && (c <= '9')) || /* !start */ + (c == '_') || (c == ':') || + (c == '-') || (c == '.') || (c == 0xB7) || /* !start */ + ((c >= 0xC0) && (c <= 0xD6)) || + ((c >= 0xD8) && (c <= 0xF6)) || + ((c >= 0xF8) && (c <= 0x2FF)) || + ((c >= 0x300) && (c <= 0x36F)) || /* !start */ + ((c >= 0x370) && (c <= 0x37D)) || + ((c >= 0x37F) && (c <= 0x1FFF)) || + ((c >= 0x200C) && (c <= 0x200D)) || + ((c >= 0x203F) && (c <= 0x2040)) || /* !start */ + ((c >= 0x2070) && (c <= 0x218F)) || + ((c >= 0x2C00) && (c <= 0x2FEF)) || + ((c >= 0x3001) && (c <= 0xD7FF)) || + ((c >= 0xF900) && (c <= 0xFDCF)) || + ((c >= 0xFDF0) && (c <= 0xFFFD)) || + ((c >= 0x10000) && (c <= 0xEFFFF)))) + return(1); + } else { + if ((IS_LETTER(c)) || (IS_DIGIT(c)) || + (c == '.') || (c == '-') || + (c == '_') || (c == ':') || + (IS_COMBINING(c)) || + (IS_EXTENDER(c))) + return(1); + } + return(0); +} + +static xmlChar * xmlParseAttValueInternal(xmlParserCtxtPtr ctxt, + int *len, int *alloc, int normalize); + +static const xmlChar * +xmlParseNameComplex(xmlParserCtxtPtr ctxt) { + int len = 0, l; + int c; + int count = 0; + +#ifdef DEBUG + nbParseNameComplex++; +#endif + + /* + * Handler for more complex cases + */ + GROW; + c = CUR_CHAR(l); + if ((ctxt->options & XML_PARSE_OLD10) == 0) { + /* + * Use the new checks of production [4] [4a] amd [5] of the + * Update 5 of XML-1.0 + */ + if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */ + (!(((c >= 'a') && (c <= 'z')) || + ((c >= 'A') && (c <= 'Z')) || + (c == '_') || (c == ':') || + ((c >= 0xC0) && (c <= 0xD6)) || + ((c >= 0xD8) && (c <= 0xF6)) || + ((c >= 0xF8) && (c <= 0x2FF)) || + ((c >= 0x370) && (c <= 0x37D)) || + ((c >= 0x37F) && (c <= 0x1FFF)) || + ((c >= 0x200C) && (c <= 0x200D)) || + ((c >= 0x2070) && (c <= 0x218F)) || + ((c >= 0x2C00) && (c <= 0x2FEF)) || + ((c >= 0x3001) && (c <= 0xD7FF)) || + ((c >= 0xF900) && (c <= 0xFDCF)) || + ((c >= 0xFDF0) && (c <= 0xFFFD)) || + ((c >= 0x10000) && (c <= 0xEFFFF))))) { + return(NULL); + } + len += l; + NEXTL(l); + c = CUR_CHAR(l); + while ((c != ' ') && (c != '>') && (c != '/') && /* accelerators */ + (((c >= 'a') && (c <= 'z')) || + ((c >= 'A') && (c <= 'Z')) || + ((c >= '0') && (c <= '9')) || /* !start */ + (c == '_') || (c == ':') || + (c == '-') || (c == '.') || (c == 0xB7) || /* !start */ + ((c >= 0xC0) && (c <= 0xD6)) || + ((c >= 0xD8) && (c <= 0xF6)) || + ((c >= 0xF8) && (c <= 0x2FF)) || + ((c >= 0x300) && (c <= 0x36F)) || /* !start */ + ((c >= 0x370) && (c <= 0x37D)) || + ((c >= 0x37F) && (c <= 0x1FFF)) || + ((c >= 0x200C) && (c <= 0x200D)) || + ((c >= 0x203F) && (c <= 0x2040)) || /* !start */ + ((c >= 0x2070) && (c <= 0x218F)) || + ((c >= 0x2C00) && (c <= 0x2FEF)) || + ((c >= 0x3001) && (c <= 0xD7FF)) || + ((c >= 0xF900) && (c <= 0xFDCF)) || + ((c >= 0xFDF0) && (c <= 0xFFFD)) || + ((c >= 0x10000) && (c <= 0xEFFFF)) + )) { + if (count++ > 100) { + count = 0; + GROW; + } + len += l; + NEXTL(l); + c = CUR_CHAR(l); + } + } else { + if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */ + (!IS_LETTER(c) && (c != '_') && + (c != ':'))) { + return(NULL); + } + len += l; + NEXTL(l); + c = CUR_CHAR(l); + + while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */ + ((IS_LETTER(c)) || (IS_DIGIT(c)) || + (c == '.') || (c == '-') || + (c == '_') || (c == ':') || + (IS_COMBINING(c)) || + (IS_EXTENDER(c)))) { + if (count++ > 100) { + count = 0; + GROW; + } + len += l; + NEXTL(l); + c = CUR_CHAR(l); + } + } + 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)); +} + +/** + * xmlParseName: + * @ctxt: an XML parser context + * + * parse an XML name. + * + * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | + * CombiningChar | Extender + * + * [5] Name ::= (Letter | '_' | ':') (NameChar)* + * + * [6] Names ::= Name (#x20 Name)* + * + * Returns the Name parsed or NULL + */ + +const xmlChar * +xmlParseName(xmlParserCtxtPtr ctxt) { + const xmlChar *in; + const xmlChar *ret; + int count = 0; + + GROW; + +#ifdef DEBUG + nbParseName++; +#endif + + /* + * Accelerator for simple ASCII names + */ + in = ctxt->input->cur; + if (((*in >= 0x61) && (*in <= 0x7A)) || + ((*in >= 0x41) && (*in <= 0x5A)) || + (*in == '_') || (*in == ':')) { + in++; + while (((*in >= 0x61) && (*in <= 0x7A)) || + ((*in >= 0x41) && (*in <= 0x5A)) || + ((*in >= 0x30) && (*in <= 0x39)) || + (*in == '_') || (*in == '-') || + (*in == ':') || (*in == '.')) + in++; + if ((*in > 0) && (*in < 0x80)) { + count = in - ctxt->input->cur; + ret = xmlDictLookup(ctxt->dict, ctxt->input->cur, count); + ctxt->input->cur = in; + ctxt->nbChars += count; + ctxt->input->col += count; + if (ret == NULL) + xmlErrMemory(ctxt, NULL); + return(ret); + } + } + /* accelerator for special cases */ + return(xmlParseNameComplex(ctxt)); +} + +static const xmlChar * +xmlParseNCNameComplex(xmlParserCtxtPtr ctxt) { + int len = 0, l; + int c; + int count = 0; + +#ifdef DEBUG + nbParseNCNameComplex++; +#endif + + /* + * Handler for more complex cases + */ + GROW; + c = CUR_CHAR(l); + if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */ + (!xmlIsNameStartChar(ctxt, c) || (c == ':'))) { + return(NULL); + } + + while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */ + (xmlIsNameChar(ctxt, c) && (c != ':'))) { + if (count++ > 100) { + count = 0; + GROW; + } + len += l; + NEXTL(l); + c = CUR_CHAR(l); + } + return(xmlDictLookup(ctxt->dict, ctxt->input->cur - len, len)); +} + +/** + * xmlParseNCName: + * @ctxt: an XML parser context + * @len: lenght of the string parsed + * + * parse an XML name. + * + * [4NS] NCNameChar ::= Letter | Digit | '.' | '-' | '_' | + * CombiningChar | Extender + * + * [5NS] NCName ::= (Letter | '_') (NCNameChar)* + * + * Returns the Name parsed or NULL + */ + +static const xmlChar * +xmlParseNCName(xmlParserCtxtPtr ctxt) { + const xmlChar *in; + const xmlChar *ret; + int count = 0; + +#ifdef DEBUG + nbParseNCName++; +#endif + + /* + * Accelerator for simple ASCII names + */ + in = ctxt->input->cur; + if (((*in >= 0x61) && (*in <= 0x7A)) || + ((*in >= 0x41) && (*in <= 0x5A)) || + (*in == '_')) { + in++; + while (((*in >= 0x61) && (*in <= 0x7A)) || + ((*in >= 0x41) && (*in <= 0x5A)) || + ((*in >= 0x30) && (*in <= 0x39)) || + (*in == '_') || (*in == '-') || + (*in == '.')) + in++; + if ((*in > 0) && (*in < 0x80)) { + count = in - ctxt->input->cur; + ret = xmlDictLookup(ctxt->dict, ctxt->input->cur, count); + ctxt->input->cur = in; + ctxt->nbChars += count; + ctxt->input->col += count; + if (ret == NULL) { + xmlErrMemory(ctxt, NULL); + } + return(ret); + } + } + return(xmlParseNCNameComplex(ctxt)); +} + +/** + * xmlParseNameAndCompare: + * @ctxt: an XML parser context + * + * parse an XML name and compares for match + * (specialized for endtag parsing) + * + * Returns NULL for an illegal name, (xmlChar*) 1 for success + * and the name for mismatch + */ + +static const xmlChar * +xmlParseNameAndCompare(xmlParserCtxtPtr ctxt, xmlChar const *other) { + register const xmlChar *cmp = other; + register const xmlChar *in; + const xmlChar *ret; + + GROW; + + in = ctxt->input->cur; + while (*in != 0 && *in == *cmp) { + ++in; + ++cmp; + ctxt->input->col++; + } + if (*cmp == 0 && (*in == '>' || IS_BLANK_CH (*in))) { + /* success */ + ctxt->input->cur = in; + return (const xmlChar*) 1; + } + /* failure (or end of input buffer), check with full function */ + ret = xmlParseName (ctxt); + /* strings coming from the dictionnary direct compare possible */ + if (ret == other) { + return (const xmlChar*) 1; + } + return ret; +} + +/** + * xmlParseStringName: + * @ctxt: an XML parser context + * @str: a pointer to the string pointer (IN/OUT) + * + * parse an XML name. + * + * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | + * CombiningChar | Extender + * + * [5] Name ::= (Letter | '_' | ':') (NameChar)* + * + * [6] Names ::= Name (#x20 Name)* + * + * Returns the Name parsed or NULL. The @str pointer + * is updated to the current location in the string. + */ + +static xmlChar * +xmlParseStringName(xmlParserCtxtPtr ctxt, const xmlChar** str) { + xmlChar buf[XML_MAX_NAMELEN + 5]; + const xmlChar *cur = *str; + int len = 0, l; + int c; + +#ifdef DEBUG + nbParseStringName++; +#endif + + c = CUR_SCHAR(cur, l); + if (!xmlIsNameStartChar(ctxt, c)) { + return(NULL); + } + + COPY_BUF(l,buf,len,c); + cur += l; + c = CUR_SCHAR(cur, l); + while (xmlIsNameChar(ctxt, c)) { + COPY_BUF(l,buf,len,c); + cur += l; + c = CUR_SCHAR(cur, l); + if (len >= XML_MAX_NAMELEN) { /* test bigentname.xml */ + /* + * Okay someone managed to make a huge name, so he's ready to pay + * for the processing speed. + */ + xmlChar *buffer; + int max = len * 2; + + buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar)); + if (buffer == NULL) { + xmlErrMemory(ctxt, NULL); + return(NULL); + } + memcpy(buffer, buf, len); + while (xmlIsNameChar(ctxt, c)) { + if (len + 10 > max) { + xmlChar *tmp; + max *= 2; + tmp = (xmlChar *) xmlRealloc(buffer, + max * sizeof(xmlChar)); + if (tmp == NULL) { + xmlErrMemory(ctxt, NULL); + xmlFree(buffer); + return(NULL); + } + buffer = tmp; + } + COPY_BUF(l,buffer,len,c); + cur += l; + c = CUR_SCHAR(cur, l); + } + buffer[len] = 0; + *str = cur; + return(buffer); + } + } + *str = cur; + return(xmlStrndup(buf, len)); +} + +/** + * xmlParseNmtoken: + * @ctxt: an XML parser context + * + * parse an XML Nmtoken. + * + * [7] Nmtoken ::= (NameChar)+ + * + * [8] Nmtokens ::= Nmtoken (#x20 Nmtoken)* + * + * Returns the Nmtoken parsed or NULL + */ + +xmlChar * +xmlParseNmtoken(xmlParserCtxtPtr ctxt) { + xmlChar buf[XML_MAX_NAMELEN + 5]; + int len = 0, l; + int c; + int count = 0; + +#ifdef DEBUG + nbParseNmToken++; +#endif + + GROW; + c = CUR_CHAR(l); + + while (xmlIsNameChar(ctxt, c)) { + if (count++ > 100) { + count = 0; + GROW; + } + COPY_BUF(l,buf,len,c); + NEXTL(l); + c = CUR_CHAR(l); + if (len >= XML_MAX_NAMELEN) { + /* + * Okay someone managed to make a huge token, so he's ready to pay + * for the processing speed. + */ + xmlChar *buffer; + int max = len * 2; + + buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar)); + if (buffer == NULL) { + xmlErrMemory(ctxt, NULL); + return(NULL); + } + memcpy(buffer, buf, len); + while (xmlIsNameChar(ctxt, c)) { + if (count++ > 100) { + count = 0; + GROW; + } + if (len + 10 > max) { + xmlChar *tmp; + + max *= 2; + tmp = (xmlChar *) xmlRealloc(buffer, + max * sizeof(xmlChar)); + if (tmp == NULL) { + xmlErrMemory(ctxt, NULL); + xmlFree(buffer); + return(NULL); + } + buffer = tmp; + } + COPY_BUF(l,buffer,len,c); + NEXTL(l); + c = CUR_CHAR(l); + } + buffer[len] = 0; + return(buffer); + } + } + if (len == 0) + return(NULL); + return(xmlStrndup(buf, len)); +} + +/** + * xmlParseEntityValue: + * @ctxt: an XML parser context + * @orig: if non-NULL store a copy of the original entity value + * + * parse a value for ENTITY declarations + * + * [9] EntityValue ::= '"' ([^%&"] | PEReference | Reference)* '"' | + * "'" ([^%&'] | PEReference | Reference)* "'" + * + * Returns the EntityValue parsed with reference substituted or NULL + */ + +xmlChar * +xmlParseEntityValue(xmlParserCtxtPtr ctxt, xmlChar **orig) { + xmlChar *buf = NULL; + int len = 0; + int size = XML_PARSER_BUFFER_SIZE; + int c, l; + xmlChar stop; + xmlChar *ret = NULL; + const xmlChar *cur = NULL; + xmlParserInputPtr input; + + if (RAW == '"') stop = '"'; + else if (RAW == '\'') stop = '\''; + else { + xmlFatalErr(ctxt, XML_ERR_ENTITY_NOT_STARTED, NULL); + return(NULL); + } + buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar)); + if (buf == NULL) { + xmlErrMemory(ctxt, NULL); + return(NULL); + } + + /* + * The content of the entity definition is copied in a buffer. + */ + + ctxt->instate = XML_PARSER_ENTITY_VALUE; + input = ctxt->input; + GROW; + NEXT; + c = CUR_CHAR(l); + /* + * NOTE: 4.4.5 Included in Literal + * When a parameter entity reference appears in a literal entity + * value, ... a single or double quote character in the replacement + * text is always treated as a normal data character and will not + * terminate the literal. + * In practice it means we stop the loop only when back at parsing + * the initial entity and the quote is found + */ + while ((IS_CHAR(c)) && ((c != stop) || /* checked */ + (ctxt->input != input))) { + if (len + 5 >= size) { + xmlChar *tmp; + + size *= 2; + tmp = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar)); + if (tmp == NULL) { + xmlErrMemory(ctxt, NULL); + xmlFree(buf); + return(NULL); + } + buf = tmp; + } + COPY_BUF(l,buf,len,c); + NEXTL(l); + /* + * Pop-up of finished entities. + */ + while ((RAW == 0) && (ctxt->inputNr > 1)) /* non input consuming */ + xmlPopInput(ctxt); + + GROW; + c = CUR_CHAR(l); + if (c == 0) { + GROW; + c = CUR_CHAR(l); + } + } + buf[len] = 0; + + /* + * Raise problem w.r.t. '&' and '%' being used in non-entities + * reference constructs. Note Charref will be handled in + * xmlStringDecodeEntities() + */ + cur = buf; + while (*cur != 0) { /* non input consuming */ + if ((*cur == '%') || ((*cur == '&') && (cur[1] != '#'))) { + xmlChar *name; + xmlChar tmp = *cur; + + cur++; + name = xmlParseStringName(ctxt, &cur); + if ((name == NULL) || (*cur != ';')) { + xmlFatalErrMsgInt(ctxt, XML_ERR_ENTITY_CHAR_ERROR, + "EntityValue: '%c' forbidden except for entities references\n", + tmp); + } + if ((tmp == '%') && (ctxt->inSubset == 1) && + (ctxt->inputNr == 1)) { + xmlFatalErr(ctxt, XML_ERR_ENTITY_PE_INTERNAL, NULL); + } + if (name != NULL) + xmlFree(name); + if (*cur == 0) + break; + } + cur++; + } + + /* + * Then PEReference entities are substituted. + */ + if (c != stop) { + xmlFatalErr(ctxt, XML_ERR_ENTITY_NOT_FINISHED, NULL); + xmlFree(buf); + } else { + NEXT; + /* + * NOTE: 4.4.7 Bypassed + * When a general entity reference appears in the EntityValue in + * an entity declaration, it is bypassed and left as is. + * so XML_SUBSTITUTE_REF is not set here. + */ + ret = xmlStringDecodeEntities(ctxt, buf, XML_SUBSTITUTE_PEREF, + 0, 0, 0); + if (orig != NULL) + *orig = buf; + else + xmlFree(buf); + } + + return(ret); +} + +/** + * xmlParseAttValueComplex: + * @ctxt: an XML parser context + * @len: the resulting attribute len + * @normalize: wether to apply the inner normalization + * + * parse a value for an attribute, this is the fallback function + * of xmlParseAttValue() when the attribute parsing requires handling + * of non-ASCII characters, or normalization compaction. + * + * Returns the AttValue parsed or NULL. The value has to be freed by the caller. + */ +static xmlChar * +xmlParseAttValueComplex(xmlParserCtxtPtr ctxt, int *attlen, int normalize) { + xmlChar limit = 0; + xmlChar *buf = NULL; + xmlChar *rep = NULL; + int len = 0; + int buf_size = 0; + int c, l, in_space = 0; + xmlChar *current = NULL; + xmlEntityPtr ent; + + if (NXT(0) == '"') { + ctxt->instate = XML_PARSER_ATTRIBUTE_VALUE; + limit = '"'; + NEXT; + } else if (NXT(0) == '\'') { + limit = '\''; + ctxt->instate = XML_PARSER_ATTRIBUTE_VALUE; + NEXT; + } else { + xmlFatalErr(ctxt, XML_ERR_ATTRIBUTE_NOT_STARTED, NULL); + return(NULL); + } + + /* + * allocate a translation buffer. + */ + buf_size = XML_PARSER_BUFFER_SIZE; + buf = (xmlChar *) xmlMallocAtomic(buf_size * sizeof(xmlChar)); + if (buf == NULL) goto mem_error; + + /* + * OK loop until we reach one of the ending char or a size limit. + */ + c = CUR_CHAR(l); + while ((NXT(0) != limit) && /* checked */ + (IS_CHAR(c)) && (c != '<')) { + if (c == 0) break; + if (c == '&') { + in_space = 0; + if (NXT(1) == '#') { + int val = xmlParseCharRef(ctxt); + + if (val == '&') { + if (ctxt->replaceEntities) { + if (len > buf_size - 10) { + growBuffer(buf, 10); + } + buf[len++] = '&'; + } else { + /* + * The reparsing will be done in xmlStringGetNodeList() + * called by the attribute() function in SAX.c + */ + if (len > buf_size - 10) { + growBuffer(buf, 10); + } + buf[len++] = '&'; + buf[len++] = '#'; + buf[len++] = '3'; + buf[len++] = '8'; + buf[len++] = ';'; + } + } else if (val != 0) { + if (len > buf_size - 10) { + growBuffer(buf, 10); + } + len += xmlCopyChar(0, &buf[len], val); + } + } else { + ent = xmlParseEntityRef(ctxt); + ctxt->nbentities++; + if (ent != NULL) + ctxt->nbentities += ent->owner; + if ((ent != NULL) && + (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) { + if (len > buf_size - 10) { + 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) { + rep = xmlStringDecodeEntities(ctxt, ent->content, + XML_SUBSTITUTE_REF, + 0, 0, 0); + 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 > buf_size - 10) { + growBuffer(buf, 10); + } + } + xmlFree(rep); + rep = NULL; + } + } else { + if (len > buf_size - 10) { + 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; + + /* + * This may look absurd but is needed to detect + * entities problems + */ + if ((ent->etype != XML_INTERNAL_PREDEFINED_ENTITY) && + (ent->content != NULL)) { + rep = xmlStringDecodeEntities(ctxt, ent->content, + XML_SUBSTITUTE_REF, 0, 0, 0); + if (rep != NULL) { + xmlFree(rep); + rep = NULL; + } + } + + /* + * Just output the reference + */ + buf[len++] = '&'; + while (len > buf_size - i - 10) { + growBuffer(buf, i + 10); + } + for (;i > 0;i--) + buf[len++] = *cur++; + buf[len++] = ';'; + } + } + } else { + if ((c == 0x20) || (c == 0xD) || (c == 0xA) || (c == 0x9)) { + if ((len != 0) || (!normalize)) { + if ((!normalize) || (!in_space)) { + COPY_BUF(l,buf,len,0x20); + while (len > buf_size - 10) { + growBuffer(buf, 10); + } + } + in_space = 1; + } + } else { + in_space = 0; + COPY_BUF(l,buf,len,c); + if (len > buf_size - 10) { + growBuffer(buf, 10); + } + } + NEXTL(l); + } + GROW; + c = CUR_CHAR(l); + } + if ((in_space) && (normalize)) { + while (buf[len - 1] == 0x20) len--; + } + buf[len] = 0; + if (RAW == '<') { + xmlFatalErr(ctxt, XML_ERR_LT_IN_ATTRIBUTE, NULL); + } else if (RAW != limit) { + 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"); + } + } else + NEXT; + if (attlen != NULL) *attlen = len; + return(buf); + +mem_error: + xmlErrMemory(ctxt, NULL); + if (buf != NULL) + xmlFree(buf); + if (rep != NULL) + xmlFree(rep); + return(NULL); +} + +/** + * xmlParseAttValue: + * @ctxt: an XML parser context + * + * parse a value for an attribute + * Note: the parser won't do substitution of entities here, this + * will be handled later in xmlStringGetNodeList + * + * [10] AttValue ::= '"' ([^<&"] | Reference)* '"' | + * "'" ([^<&'] | Reference)* "'" + * + * 3.3.3 Attribute-Value Normalization: + * Before the value of an attribute is passed to the application or + * checked for validity, the XML processor must normalize it as follows: + * - a character reference is processed by appending the referenced + * character to the attribute value + * - an entity reference is processed by recursively processing the + * replacement text of the entity + * - a whitespace character (#x20, #xD, #xA, #x9) is processed by + * appending #x20 to the normalized value, except that only a single + * #x20 is appended for a "#xD#xA" sequence that is part of an external + * parsed entity or the literal entity value of an internal parsed entity + * - other characters are processed by appending them to the normalized value + * If the declared value is not CDATA, then the XML processor must further + * process the normalized attribute value by discarding any leading and + * trailing space (#x20) characters, and by replacing sequences of space + * (#x20) characters by a single space (#x20) character. + * All attributes for which no declaration has been read should be treated + * by a non-validating parser as if declared CDATA. + * + * Returns the AttValue parsed or NULL. The value has to be freed by the caller. + */ + + +xmlChar * +xmlParseAttValue(xmlParserCtxtPtr ctxt) { + if ((ctxt == NULL) || (ctxt->input == NULL)) return(NULL); + return(xmlParseAttValueInternal(ctxt, NULL, NULL, 0)); +} + +/** + * xmlParseSystemLiteral: + * @ctxt: an XML parser context + * + * parse an XML Literal + * + * [11] SystemLiteral ::= ('"' [^"]* '"') | ("'" [^']* "'") + * + * Returns the SystemLiteral parsed or NULL + */ + +xmlChar * +xmlParseSystemLiteral(xmlParserCtxtPtr ctxt) { + xmlChar *buf = NULL; + int len = 0; + int size = XML_PARSER_BUFFER_SIZE; + int cur, l; + xmlChar stop; + int state = ctxt->instate; + int count = 0; + + SHRINK; + if (RAW == '"') { + NEXT; + stop = '"'; + } else if (RAW == '\'') { + NEXT; + stop = '\''; + } else { + xmlFatalErr(ctxt, XML_ERR_LITERAL_NOT_STARTED, NULL); + return(NULL); + } + + buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar)); + if (buf == NULL) { + xmlErrMemory(ctxt, NULL); + return(NULL); + } + ctxt->instate = XML_PARSER_SYSTEM_LITERAL; + cur = CUR_CHAR(l); + while ((IS_CHAR(cur)) && (cur != stop)) { /* checked */ + if (len + 5 >= size) { + xmlChar *tmp; + + size *= 2; + tmp = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar)); + if (tmp == NULL) { + xmlFree(buf); + xmlErrMemory(ctxt, NULL); + ctxt->instate = (xmlParserInputState) state; + return(NULL); + } + buf = tmp; + } + count++; + if (count > 50) { + GROW; + count = 0; + } + COPY_BUF(l,buf,len,cur); + NEXTL(l); + cur = CUR_CHAR(l); + if (cur == 0) { + GROW; + SHRINK; + cur = CUR_CHAR(l); + } + } + buf[len] = 0; + ctxt->instate = (xmlParserInputState) state; + if (!IS_CHAR(cur)) { + xmlFatalErr(ctxt, XML_ERR_LITERAL_NOT_FINISHED, NULL); + } else { + NEXT; + } + return(buf); +} + +/** + * xmlParsePubidLiteral: + * @ctxt: an XML parser context + * + * parse an XML public literal + * + * [12] PubidLiteral ::= '"' PubidChar* '"' | "'" (PubidChar - "'")* "'" + * + * Returns the PubidLiteral parsed or NULL. + */ + +xmlChar * +xmlParsePubidLiteral(xmlParserCtxtPtr ctxt) { + xmlChar *buf = NULL; + int len = 0; + int size = XML_PARSER_BUFFER_SIZE; + xmlChar cur; + xmlChar stop; + int count = 0; + xmlParserInputState oldstate = ctxt->instate; + + SHRINK; + if (RAW == '"') { + NEXT; + stop = '"'; + } else if (RAW == '\'') { + NEXT; + stop = '\''; + } else { + xmlFatalErr(ctxt, XML_ERR_LITERAL_NOT_STARTED, NULL); + return(NULL); + } + buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar)); + if (buf == NULL) { + xmlErrMemory(ctxt, NULL); + return(NULL); + } + ctxt->instate = XML_PARSER_PUBLIC_LITERAL; + cur = CUR; + while ((IS_PUBIDCHAR_CH(cur)) && (cur != stop)) { /* checked */ + if (len + 1 >= size) { + xmlChar *tmp; + + size *= 2; + tmp = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar)); + if (tmp == NULL) { + xmlErrMemory(ctxt, NULL); + xmlFree(buf); + return(NULL); + } + buf = tmp; + } + buf[len++] = cur; + count++; + if (count > 50) { + GROW; + count = 0; + } + NEXT; + cur = CUR; + if (cur == 0) { + GROW; + SHRINK; + cur = CUR; + } + } + buf[len] = 0; + if (cur != stop) { + xmlFatalErr(ctxt, XML_ERR_LITERAL_NOT_FINISHED, NULL); + } else { + NEXT; + } + ctxt->instate = oldstate; + return(buf); +} + +static void xmlParseCharDataComplex(xmlParserCtxtPtr ctxt, int cdata); + +/* + * used for the test in the inner loop of the char data testing + */ +static const unsigned char test_char_data[256] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9, CR/LF separated */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x00, 0x27, /* & */ + 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3A, 0x3B, 0x00, 0x3D, 0x3E, 0x3F, /* < */ + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x00, 0x5E, 0x5F, /* ] */ + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* non-ascii */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +/** + * xmlParseCharData: + * @ctxt: an XML parser context + * @cdata: int indicating whether we are within a CDATA section + * + * parse a CharData section. + * if we are within a CDATA section ']]>' marks an end of section. + * + * The right angle bracket (>) may be represented using the string ">", + * and must, for compatibility, be escaped using ">" or a character + * reference when it appears in the string "]]>" in content, when that + * string is not marking the end of a CDATA section. + * + * [14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*) + */ + +void +xmlParseCharData(xmlParserCtxtPtr ctxt, int cdata) { + const xmlChar *in; + int nbchar = 0; + int line = ctxt->input->line; + int col = ctxt->input->col; + int ccol; + + SHRINK; + GROW; + /* + * Accelerated common case where input don't need to be + * modified before passing it to the handler. + */ + if (!cdata) { + in = ctxt->input->cur; + do { +get_more_space: + while (*in == 0x20) { in++; ctxt->input->col++; } + if (*in == 0xA) { + do { + ctxt->input->line++; ctxt->input->col = 1; + in++; + } while (*in == 0xA); + goto get_more_space; + } + if (*in == '<') { + nbchar = in - ctxt->input->cur; + if (nbchar > 0) { + const xmlChar *tmp = ctxt->input->cur; + ctxt->input->cur = in; + + if ((ctxt->sax != NULL) && + (ctxt->sax->ignorableWhitespace != + ctxt->sax->characters)) { + if (areBlanks(ctxt, tmp, nbchar, 1)) { + if (ctxt->sax->ignorableWhitespace != NULL) + ctxt->sax->ignorableWhitespace(ctxt->userData, + tmp, nbchar); + } else { + if (ctxt->sax->characters != NULL) + ctxt->sax->characters(ctxt->userData, + tmp, nbchar); + if (*ctxt->space == -1) + *ctxt->space = -2; + } + } else if ((ctxt->sax != NULL) && + (ctxt->sax->characters != NULL)) { + ctxt->sax->characters(ctxt->userData, + tmp, nbchar); + } + } + return; + } + +get_more: + ccol = ctxt->input->col; + while (test_char_data[*in]) { + in++; + ccol++; + } + ctxt->input->col = ccol; + if (*in == 0xA) { + do { + ctxt->input->line++; ctxt->input->col = 1; + in++; + } while (*in == 0xA); + goto get_more; + } + if (*in == ']') { + if ((in[1] == ']') && (in[2] == '>')) { + xmlFatalErr(ctxt, XML_ERR_MISPLACED_CDATA_END, NULL); + ctxt->input->cur = in; + return; + } + in++; + ctxt->input->col++; + goto get_more; + } + nbchar = in - ctxt->input->cur; + if (nbchar > 0) { + if ((ctxt->sax != NULL) && + (ctxt->sax->ignorableWhitespace != + ctxt->sax->characters) && + (IS_BLANK_CH(*ctxt->input->cur))) { + const xmlChar *tmp = ctxt->input->cur; + ctxt->input->cur = in; + + if (areBlanks(ctxt, tmp, nbchar, 0)) { + if (ctxt->sax->ignorableWhitespace != NULL) + ctxt->sax->ignorableWhitespace(ctxt->userData, + tmp, nbchar); + } else { + if (ctxt->sax->characters != NULL) + ctxt->sax->characters(ctxt->userData, + tmp, nbchar); + if (*ctxt->space == -1) + *ctxt->space = -2; + } + line = ctxt->input->line; + col = ctxt->input->col; + } else if (ctxt->sax != NULL) { + if (ctxt->sax->characters != NULL) + ctxt->sax->characters(ctxt->userData, + ctxt->input->cur, nbchar); + line = ctxt->input->line; + col = ctxt->input->col; + } + /* something really bad happened in the SAX callback */ + if (ctxt->instate != XML_PARSER_CONTENT) + return; + } + ctxt->input->cur = in; + if (*in == 0xD) { + in++; + if (*in == 0xA) { + ctxt->input->cur = in; + in++; + ctxt->input->line++; ctxt->input->col = 1; + continue; /* while */ + } + in--; + } + if (*in == '<') { + return; + } + if (*in == '&') { + return; + } + SHRINK; + GROW; + in = ctxt->input->cur; + } while (((*in >= 0x20) && (*in <= 0x7F)) || (*in == 0x09)); + nbchar = 0; + } + ctxt->input->line = line; + ctxt->input->col = col; + xmlParseCharDataComplex(ctxt, cdata); +} + +/** + * xmlParseCharDataComplex: + * @ctxt: an XML parser context + * @cdata: int indicating whether we are within a CDATA section + * + * parse a CharData section.this is the fallback function + * of xmlParseCharData() when the parsing requires handling + * of non-ASCII characters. + */ +static void +xmlParseCharDataComplex(xmlParserCtxtPtr ctxt, int cdata) { + xmlChar buf[XML_PARSER_BIG_BUFFER_SIZE + 5]; + int nbchar = 0; + int cur, l; + int count = 0; + + SHRINK; + GROW; + cur = CUR_CHAR(l); + while ((cur != '<') && /* checked */ + (cur != '&') && + (IS_CHAR(cur))) /* test also done in xmlCurrentChar() */ { + if ((cur == ']') && (NXT(1) == ']') && + (NXT(2) == '>')) { + if (cdata) break; + else { + xmlFatalErr(ctxt, XML_ERR_MISPLACED_CDATA_END, NULL); + } + } + COPY_BUF(l,buf,nbchar,cur); + if (nbchar >= XML_PARSER_BIG_BUFFER_SIZE) { + buf[nbchar] = 0; + + /* + * OK the segment is to be consumed as chars. + */ + if ((ctxt->sax != NULL) && (!ctxt->disableSAX)) { + if (areBlanks(ctxt, buf, nbchar, 0)) { + if (ctxt->sax->ignorableWhitespace != NULL) + ctxt->sax->ignorableWhitespace(ctxt->userData, + buf, nbchar); + } else { + if (ctxt->sax->characters != NULL) + ctxt->sax->characters(ctxt->userData, buf, nbchar); + if ((ctxt->sax->characters != + ctxt->sax->ignorableWhitespace) && + (*ctxt->space == -1)) + *ctxt->space = -2; + } + } + nbchar = 0; + /* something really bad happened in the SAX callback */ + if (ctxt->instate != XML_PARSER_CONTENT) + return; + } + count++; + if (count > 50) { + GROW; + count = 0; + } + NEXTL(l); + cur = CUR_CHAR(l); + } + if (nbchar != 0) { + buf[nbchar] = 0; + /* + * OK the segment is to be consumed as chars. + */ + if ((ctxt->sax != NULL) && (!ctxt->disableSAX)) { + if (areBlanks(ctxt, buf, nbchar, 0)) { + if (ctxt->sax->ignorableWhitespace != NULL) + ctxt->sax->ignorableWhitespace(ctxt->userData, buf, nbchar); + } else { + if (ctxt->sax->characters != NULL) + ctxt->sax->characters(ctxt->userData, buf, nbchar); + if ((ctxt->sax->characters != ctxt->sax->ignorableWhitespace) && + (*ctxt->space == -1)) + *ctxt->space = -2; + } + } + } + if ((cur != 0) && (!IS_CHAR(cur))) { + /* Generate the error and skip the offending character */ + xmlFatalErrMsgInt(ctxt, XML_ERR_INVALID_CHAR, + "PCDATA invalid Char value %d\n", + cur); + NEXTL(l); + } +} + +/** + * xmlParseExternalID: + * @ctxt: an XML parser context + * @publicID: a xmlChar** receiving PubidLiteral + * @strict: indicate whether we should restrict parsing to only + * production [75], see NOTE below + * + * Parse an External ID or a Public ID + * + * NOTE: Productions [75] and [83] interact badly since [75] can generate + * 'PUBLIC' S PubidLiteral S SystemLiteral + * + * [75] ExternalID ::= 'SYSTEM' S SystemLiteral + * | 'PUBLIC' S PubidLiteral S SystemLiteral + * + * [83] PublicID ::= 'PUBLIC' S PubidLiteral + * + * Returns the function returns SystemLiteral and in the second + * case publicID receives PubidLiteral, is strict is off + * it is possible to return NULL and have publicID set. + */ + +xmlChar * +xmlParseExternalID(xmlParserCtxtPtr ctxt, xmlChar **publicID, int strict) { + xmlChar *URI = NULL; + + SHRINK; + + *publicID = NULL; + if (CMP6(CUR_PTR, 'S', 'Y', 'S', 'T', 'E', 'M')) { + SKIP(6); + if (!IS_BLANK_CH(CUR)) { + xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, + "Space required after 'SYSTEM'\n"); + } + SKIP_BLANKS; + URI = xmlParseSystemLiteral(ctxt); + if (URI == NULL) { + xmlFatalErr(ctxt, XML_ERR_URI_REQUIRED, NULL); + } + } else if (CMP6(CUR_PTR, 'P', 'U', 'B', 'L', 'I', 'C')) { + SKIP(6); + if (!IS_BLANK_CH(CUR)) { + xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, + "Space required after 'PUBLIC'\n"); + } + SKIP_BLANKS; + *publicID = xmlParsePubidLiteral(ctxt); + if (*publicID == NULL) { + xmlFatalErr(ctxt, XML_ERR_PUBID_REQUIRED, NULL); + } + if (strict) { + /* + * We don't handle [83] so "S SystemLiteral" is required. + */ + if (!IS_BLANK_CH(CUR)) { + xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, + "Space required after the Public Identifier\n"); + } + } else { + /* + * We handle [83] so we return immediately, if + * "S SystemLiteral" is not detected. From a purely parsing + * point of view that's a nice mess. + */ + const xmlChar *ptr; + GROW; + + ptr = CUR_PTR; + if (!IS_BLANK_CH(*ptr)) return(NULL); + + while (IS_BLANK_CH(*ptr)) ptr++; /* TODO: dangerous, fix ! */ + if ((*ptr != '\'') && (*ptr != '"')) return(NULL); + } + SKIP_BLANKS; + URI = xmlParseSystemLiteral(ctxt); + if (URI == NULL) { + xmlFatalErr(ctxt, XML_ERR_URI_REQUIRED, NULL); + } + } + return(URI); +} + +/** + * xmlParseCommentComplex: + * @ctxt: an XML parser context + * @buf: the already parsed part of the buffer + * @len: number of bytes filles in the buffer + * @size: allocated size of the buffer + * + * Skip an XML (SGML) comment + * The spec says that "For compatibility, the string "--" (double-hyphen) + * must not occur within comments. " + * This is the slow routine in case the accelerator for ascii didn't work + * + * [15] Comment ::= '' + */ +static void +xmlParseCommentComplex(xmlParserCtxtPtr ctxt, xmlChar *buf, int len, int size) { + int q, ql; + int r, rl; + int cur, l; + int count = 0; + int inputid; + + inputid = ctxt->input->id; + + if (buf == NULL) { + len = 0; + size = XML_PARSER_BUFFER_SIZE; + buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar)); + if (buf == NULL) { + xmlErrMemory(ctxt, NULL); + return; + } + } + GROW; /* Assure there's enough input data */ + q = CUR_CHAR(ql); + if (q == 0) + goto not_terminated; + if (!IS_CHAR(q)) { + xmlFatalErrMsgInt(ctxt, XML_ERR_INVALID_CHAR, + "xmlParseComment: invalid xmlChar value %d\n", + q); + xmlFree (buf); + return; + } + NEXTL(ql); + r = CUR_CHAR(rl); + if (r == 0) + goto not_terminated; + if (!IS_CHAR(r)) { + xmlFatalErrMsgInt(ctxt, XML_ERR_INVALID_CHAR, + "xmlParseComment: invalid xmlChar value %d\n", + q); + xmlFree (buf); + return; + } + NEXTL(rl); + cur = CUR_CHAR(l); + if (cur == 0) + goto not_terminated; + while (IS_CHAR(cur) && /* checked */ + ((cur != '>') || + (r != '-') || (q != '-'))) { + if ((r == '-') && (q == '-')) { + xmlFatalErr(ctxt, XML_ERR_HYPHEN_IN_COMMENT, NULL); + } + if (len + 5 >= size) { + xmlChar *new_buf; + size *= 2; + new_buf = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar)); + if (new_buf == NULL) { + xmlFree (buf); + xmlErrMemory(ctxt, NULL); + return; + } + buf = new_buf; + } + COPY_BUF(ql,buf,len,q); + q = r; + ql = rl; + r = cur; + rl = l; + + count++; + if (count > 50) { + GROW; + count = 0; + } + NEXTL(l); + cur = CUR_CHAR(l); + if (cur == 0) { + SHRINK; + GROW; + cur = CUR_CHAR(l); + } + } + buf[len] = 0; + if (cur == 0) { + xmlFatalErrMsgStr(ctxt, XML_ERR_COMMENT_NOT_FINISHED, + "Comment not terminated \n + * The spec says that "For compatibility, the string "--" (double-hyphen) + * must not occur within comments. " + * + * [15] Comment ::= '' + */ +void +xmlParseComment(xmlParserCtxtPtr ctxt) { + xmlChar *buf = NULL; + int size = XML_PARSER_BUFFER_SIZE; + int len = 0; + xmlParserInputState state; + const xmlChar *in; + int nbchar = 0, ccol; + int inputid; + + /* + * Check that there is a comment right here. + */ + if ((RAW != '<') || (NXT(1) != '!') || + (NXT(2) != '-') || (NXT(3) != '-')) return; + state = ctxt->instate; + ctxt->instate = XML_PARSER_COMMENT; + inputid = ctxt->input->id; + SKIP(4); + SHRINK; + GROW; + + /* + * Accelerated common case where input don't need to be + * modified before passing it to the handler. + */ + in = ctxt->input->cur; + do { + if (*in == 0xA) { + do { + ctxt->input->line++; ctxt->input->col = 1; + in++; + } while (*in == 0xA); + } +get_more: + ccol = ctxt->input->col; + while (((*in > '-') && (*in <= 0x7F)) || + ((*in >= 0x20) && (*in < '-')) || + (*in == 0x09)) { + in++; + ccol++; + } + ctxt->input->col = ccol; + if (*in == 0xA) { + do { + ctxt->input->line++; ctxt->input->col = 1; + in++; + } while (*in == 0xA); + goto get_more; + } + nbchar = in - ctxt->input->cur; + /* + * save current set of data + */ + if (nbchar > 0) { + if ((ctxt->sax != NULL) && + (ctxt->sax->comment != NULL)) { + if (buf == NULL) { + if ((*in == '-') && (in[1] == '-')) + size = nbchar + 1; + else + size = XML_PARSER_BUFFER_SIZE + nbchar; + buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar)); + if (buf == NULL) { + xmlErrMemory(ctxt, NULL); + ctxt->instate = state; + return; + } + len = 0; + } else if (len + nbchar + 1 >= size) { + xmlChar *new_buf; + size += len + nbchar + XML_PARSER_BUFFER_SIZE; + new_buf = (xmlChar *) xmlRealloc(buf, + size * sizeof(xmlChar)); + if (new_buf == NULL) { + xmlFree (buf); + xmlErrMemory(ctxt, NULL); + ctxt->instate = state; + return; + } + buf = new_buf; + } + memcpy(&buf[len], ctxt->input->cur, nbchar); + len += nbchar; + buf[len] = 0; + } + } + ctxt->input->cur = in; + if (*in == 0xA) { + in++; + ctxt->input->line++; ctxt->input->col = 1; + } + if (*in == 0xD) { + in++; + if (*in == 0xA) { + ctxt->input->cur = in; + in++; + ctxt->input->line++; ctxt->input->col = 1; + continue; /* while */ + } + in--; + } + SHRINK; + GROW; + 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)) { + if (buf != NULL) + ctxt->sax->comment(ctxt->userData, buf); + else + ctxt->sax->comment(ctxt->userData, BAD_CAST ""); + } + if (buf != NULL) + xmlFree(buf); + ctxt->instate = state; + return; + } + if (buf != NULL) + xmlFatalErrMsgStr(ctxt, XML_ERR_COMMENT_NOT_FINISHED, + "Comment not terminated \n"); + } + fprintf(output, ">\n"); + if (grammar->start == NULL) { + fprintf(output, " "); + } else { + fprintf(output, "\n"); + xmlRelaxNGDumpDefine(output, grammar->start); + fprintf(output, "\n"); + } + /* TODO ? Dump the defines ? */ + fprintf(output, "\n"); +} + +/** + * xmlRelaxNGDump: + * @output: the file output + * @schema: a schema structure + * + * Dump a RelaxNG structure back + */ +void +xmlRelaxNGDump(FILE * output, xmlRelaxNGPtr schema) +{ + if (output == NULL) + return; + if (schema == NULL) { + fprintf(output, "RelaxNG empty or failed to compile\n"); + return; + } + fprintf(output, "RelaxNG: "); + if (schema->doc == NULL) { + fprintf(output, "no document\n"); + } else if (schema->doc->URL != NULL) { + fprintf(output, "%s\n", schema->doc->URL); + } else { + fprintf(output, "\n"); + } + if (schema->topgrammar == NULL) { + fprintf(output, "RelaxNG has no top grammar\n"); + return; + } + xmlRelaxNGDumpGrammar(output, schema->topgrammar, 1); +} + +/** + * xmlRelaxNGDumpTree: + * @output: the file output + * @schema: a schema structure + * + * Dump the transformed RelaxNG tree. + */ +void +xmlRelaxNGDumpTree(FILE * output, xmlRelaxNGPtr schema) +{ + if (output == NULL) + return; + if (schema == NULL) { + fprintf(output, "RelaxNG empty or failed to compile\n"); + return; + } + if (schema->doc == NULL) { + fprintf(output, "no document\n"); + } else { + xmlDocDump(output, schema->doc); + } +} +#endif /* LIBXML_OUTPUT_ENABLED */ + +/************************************************************************ + * * + * Validation of compiled content * + * * + ************************************************************************/ +static int xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt, + xmlRelaxNGDefinePtr define); + +/** + * xmlRelaxNGValidateCompiledCallback: + * @exec: the regular expression instance + * @token: the token which matched + * @transdata: callback data, the define for the subelement if available + @ @inputdata: callback data, the Relax NG validation context + * + * Handle the callback and if needed validate the element children. + */ +static void +xmlRelaxNGValidateCompiledCallback(xmlRegExecCtxtPtr exec ATTRIBUTE_UNUSED, + const xmlChar * token, + void *transdata, void *inputdata) +{ + xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata; + xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata; + int ret; + +#ifdef DEBUG_COMPILE + xmlGenericError(xmlGenericErrorContext, + "Compiled callback for: '%s'\n", token); +#endif + if (ctxt == NULL) { + fprintf(stderr, "callback on %s missing context\n", token); + return; + } + if (define == NULL) { + if (token[0] == '#') + return; + fprintf(stderr, "callback on %s missing define\n", token); + if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK)) + ctxt->errNo = XML_RELAXNG_ERR_INTERNAL; + 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; + return; + } else 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; + return; + } + ret = xmlRelaxNGValidateDefinition(ctxt, define); + if (ret != 0) + ctxt->perr = ret; +} + +/** + * xmlRelaxNGValidateCompiledContent: + * @ctxt: the RelaxNG validation context + * @regexp: the regular expression as compiled + * @content: list of children to test against the regexp + * + * Validate the content model of an element or start using the regexp + * + * Returns 0 in case of success, -1 in case of error. + */ +static int +xmlRelaxNGValidateCompiledContent(xmlRelaxNGValidCtxtPtr ctxt, + xmlRegexpPtr regexp, xmlNodePtr content) +{ + xmlRegExecCtxtPtr exec; + xmlNodePtr cur; + int ret = 0; + int oldperr; + + if ((ctxt == NULL) || (regexp == NULL)) + return (-1); + oldperr = ctxt->perr; + exec = xmlRegNewExecCtxt(regexp, + xmlRelaxNGValidateCompiledCallback, ctxt); + ctxt->perr = 0; + cur = content; + while (cur != NULL) { + ctxt->state->seq = cur; + switch (cur->type) { + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: + if (xmlIsBlankNode(cur)) + break; + ret = xmlRegExecPushString(exec, BAD_CAST "#text", ctxt); + if (ret < 0) { + VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG, + cur->parent->name); + } + break; + case XML_ELEMENT_NODE: + if (cur->ns != NULL) { + ret = xmlRegExecPushString2(exec, cur->name, + cur->ns->href, ctxt); + } else { + ret = xmlRegExecPushString(exec, cur->name, ctxt); + } + if (ret < 0) { + VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, cur->name); + } + break; + default: + break; + } + if (ret < 0) + break; + /* + * Switch to next element + */ + cur = cur->next; + } + ret = xmlRegExecPushString(exec, NULL, NULL); + if (ret == 1) { + ret = 0; + ctxt->state->seq = NULL; + } else if (ret == 0) { + /* + * TODO: get some of the names needed to exit the current state of exec + */ + VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST ""); + ret = -1; + if ((ctxt->flags & FLAGS_IGNORABLE) == 0) + xmlRelaxNGDumpValidError(ctxt); + } else { + ret = -1; + } + xmlRegFreeExecCtxt(exec); + /* + * There might be content model errors outside of the pure + * regexp validation, e.g. for attribute values. + */ + if ((ret == 0) && (ctxt->perr != 0)) { + ret = ctxt->perr; + } + ctxt->perr = oldperr; + return (ret); +} + +/************************************************************************ + * * + * Progressive validation of when possible * + * * + ************************************************************************/ +static int xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt, + xmlRelaxNGDefinePtr defines); +static int xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt, + int dolog); +static void xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt); + +/** + * xmlRelaxNGElemPush: + * @ctxt: the validation context + * @exec: the regexp runtime for the new content model + * + * Push a new regexp for the current node content model on the stack + * + * Returns 0 in case of success and -1 in case of error. + */ +static int +xmlRelaxNGElemPush(xmlRelaxNGValidCtxtPtr ctxt, xmlRegExecCtxtPtr exec) +{ + if (ctxt->elemTab == NULL) { + ctxt->elemMax = 10; + ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlMalloc(ctxt->elemMax * + sizeof + (xmlRegExecCtxtPtr)); + if (ctxt->elemTab == NULL) { + xmlRngVErrMemory(ctxt, "validating\n"); + return (-1); + } + } + if (ctxt->elemNr >= ctxt->elemMax) { + ctxt->elemMax *= 2; + ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlRealloc(ctxt->elemTab, + ctxt->elemMax * + sizeof + (xmlRegExecCtxtPtr)); + if (ctxt->elemTab == NULL) { + xmlRngVErrMemory(ctxt, "validating\n"); + return (-1); + } + } + ctxt->elemTab[ctxt->elemNr++] = exec; + ctxt->elem = exec; + return (0); +} + +/** + * xmlRelaxNGElemPop: + * @ctxt: the validation context + * + * Pop the regexp of the current node content model from the stack + * + * Returns the exec or NULL if empty + */ +static xmlRegExecCtxtPtr +xmlRelaxNGElemPop(xmlRelaxNGValidCtxtPtr ctxt) +{ + xmlRegExecCtxtPtr ret; + + if (ctxt->elemNr <= 0) + return (NULL); + ctxt->elemNr--; + ret = ctxt->elemTab[ctxt->elemNr]; + ctxt->elemTab[ctxt->elemNr] = NULL; + if (ctxt->elemNr > 0) + ctxt->elem = ctxt->elemTab[ctxt->elemNr - 1]; + else + ctxt->elem = NULL; + return (ret); +} + +/** + * xmlRelaxNGValidateProgressiveCallback: + * @exec: the regular expression instance + * @token: the token which matched + * @transdata: callback data, the define for the subelement if available + @ @inputdata: callback data, the Relax NG validation context + * + * Handle the callback and if needed validate the element children. + * some of the in/out informations are passed via the context in @inputdata. + */ +static void +xmlRelaxNGValidateProgressiveCallback(xmlRegExecCtxtPtr exec + ATTRIBUTE_UNUSED, + const xmlChar * token, + void *transdata, void *inputdata) +{ + xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata; + xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata; + xmlRelaxNGValidStatePtr state, oldstate; + xmlNodePtr node; + int ret = 0, oldflags; + +#ifdef DEBUG_PROGRESSIVE + xmlGenericError(xmlGenericErrorContext, + "Progressive callback for: '%s'\n", token); +#endif + if (ctxt == NULL) { + fprintf(stderr, "callback on %s missing context\n", token); + return; + } + node = ctxt->pnode; + ctxt->pstate = 1; + if (define == NULL) { + if (token[0] == '#') + return; + fprintf(stderr, "callback on %s missing define\n", token); + if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK)) + ctxt->errNo = XML_RELAXNG_ERR_INTERNAL; + 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) { + fprintf(stderr, "callback on %s define is not element\n", token); + if (ctxt->errNo == XML_RELAXNG_OK) + ctxt->errNo = XML_RELAXNG_ERR_INTERNAL; + ctxt->pstate = -1; + return; + } + if (node->type != XML_ELEMENT_NODE) { + VALID_ERR(XML_RELAXNG_ERR_NOTELEM); + if ((ctxt->flags & FLAGS_IGNORABLE) == 0) + xmlRelaxNGDumpValidError(ctxt); + ctxt->pstate = -1; + return; + } + if (define->contModel == NULL) { + /* + * this node cannot be validated in a streamable fashion + */ +#ifdef DEBUG_PROGRESSIVE + xmlGenericError(xmlGenericErrorContext, + "Element '%s' validation is not streamable\n", + token); +#endif + ctxt->pstate = 0; + ctxt->pdef = define; + return; + } + exec = xmlRegNewExecCtxt(define->contModel, + xmlRelaxNGValidateProgressiveCallback, ctxt); + if (exec == NULL) { + ctxt->pstate = -1; + return; + } + xmlRelaxNGElemPush(ctxt, exec); + + /* + * Validate the attributes part of the content. + */ + state = xmlRelaxNGNewValidState(ctxt, node); + if (state == NULL) { + ctxt->pstate = -1; + return; + } + oldstate = ctxt->state; + ctxt->state = state; + if (define->attrs != NULL) { + ret = xmlRelaxNGValidateAttributeList(ctxt, define->attrs); + if (ret != 0) { + ctxt->pstate = -1; + VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name); + } + } + if (ctxt->state != NULL) { + ctxt->state->seq = NULL; + ret = xmlRelaxNGValidateElementEnd(ctxt, 1); + if (ret != 0) { + ctxt->pstate = -1; + } + xmlRelaxNGFreeValidState(ctxt, ctxt->state); + } else if (ctxt->states != NULL) { + int tmp = -1, i; + + oldflags = ctxt->flags; + + for (i = 0; i < ctxt->states->nbState; i++) { + state = ctxt->states->tabState[i]; + ctxt->state = state; + ctxt->state->seq = NULL; + + if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) { + tmp = 0; + break; + } + } + if (tmp != 0) { + /* + * validation error, log the message for the "best" one + */ + ctxt->flags |= FLAGS_IGNORABLE; + xmlRelaxNGLogBestError(ctxt); + } + for (i = 0; i < ctxt->states->nbState; i++) { + xmlRelaxNGFreeValidState(ctxt, ctxt->states->tabState[i]); + } + xmlRelaxNGFreeStates(ctxt, ctxt->states); + ctxt->states = NULL; + if ((ret == 0) && (tmp == -1)) + ctxt->pstate = -1; + ctxt->flags = oldflags; + } + if (ctxt->pstate == -1) { + if ((ctxt->flags & FLAGS_IGNORABLE) == 0) { + xmlRelaxNGDumpValidError(ctxt); + } + } + ctxt->state = oldstate; +} + +/** + * xmlRelaxNGValidatePushElement: + * @ctxt: the validation context + * @doc: a document instance + * @elem: an element instance + * + * Push a new element start on the RelaxNG validation stack. + * + * returns 1 if no validation problem was found or 0 if validating the + * element requires a full node, and -1 in case of error. + */ +int +xmlRelaxNGValidatePushElement(xmlRelaxNGValidCtxtPtr ctxt, + xmlDocPtr doc ATTRIBUTE_UNUSED, + xmlNodePtr elem) +{ + int ret = 1; + + if ((ctxt == NULL) || (elem == NULL)) + return (-1); + +#ifdef DEBUG_PROGRESSIVE + xmlGenericError(xmlGenericErrorContext, "PushElem %s\n", elem->name); +#endif + if (ctxt->elem == 0) { + xmlRelaxNGPtr schema; + xmlRelaxNGGrammarPtr grammar; + xmlRegExecCtxtPtr exec; + xmlRelaxNGDefinePtr define; + + schema = ctxt->schema; + if (schema == NULL) { + VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR); + return (-1); + } + grammar = schema->topgrammar; + if ((grammar == NULL) || (grammar->start == NULL)) { + VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR); + return (-1); + } + define = grammar->start; + if (define->contModel == NULL) { + ctxt->pdef = define; + return (0); + } + exec = xmlRegNewExecCtxt(define->contModel, + xmlRelaxNGValidateProgressiveCallback, + ctxt); + if (exec == NULL) { + return (-1); + } + xmlRelaxNGElemPush(ctxt, exec); + } + ctxt->pnode = elem; + ctxt->pstate = 0; + if (elem->ns != NULL) { + ret = + xmlRegExecPushString2(ctxt->elem, elem->name, elem->ns->href, + ctxt); + } else { + ret = xmlRegExecPushString(ctxt->elem, elem->name, ctxt); + } + if (ret < 0) { + VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, elem->name); + } else { + if (ctxt->pstate == 0) + ret = 0; + else if (ctxt->pstate < 0) + ret = -1; + else + ret = 1; + } +#ifdef DEBUG_PROGRESSIVE + if (ret < 0) + xmlGenericError(xmlGenericErrorContext, "PushElem %s failed\n", + elem->name); +#endif + return (ret); +} + +/** + * xmlRelaxNGValidatePushCData: + * @ctxt: the RelaxNG validation context + * @data: some character data read + * @len: the lenght of the data + * + * check the CData parsed for validation in the current stack + * + * returns 1 if no validation problem was found or -1 otherwise + */ +int +xmlRelaxNGValidatePushCData(xmlRelaxNGValidCtxtPtr ctxt, + const xmlChar * data, int len ATTRIBUTE_UNUSED) +{ + int ret = 1; + + if ((ctxt == NULL) || (ctxt->elem == NULL) || (data == NULL)) + return (-1); + +#ifdef DEBUG_PROGRESSIVE + xmlGenericError(xmlGenericErrorContext, "CDATA %s %d\n", data, len); +#endif + + while (*data != 0) { + if (!IS_BLANK_CH(*data)) + break; + data++; + } + if (*data == 0) + return (1); + + ret = xmlRegExecPushString(ctxt->elem, BAD_CAST "#text", ctxt); + if (ret < 0) { + VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG, BAD_CAST " TODO "); +#ifdef DEBUG_PROGRESSIVE + xmlGenericError(xmlGenericErrorContext, "CDATA failed\n"); +#endif + + return (-1); + } + return (1); +} + +/** + * xmlRelaxNGValidatePopElement: + * @ctxt: the RelaxNG validation context + * @doc: a document instance + * @elem: an element instance + * + * Pop the element end from the RelaxNG validation stack. + * + * returns 1 if no validation problem was found or 0 otherwise + */ +int +xmlRelaxNGValidatePopElement(xmlRelaxNGValidCtxtPtr ctxt, + xmlDocPtr doc ATTRIBUTE_UNUSED, + xmlNodePtr elem) +{ + int ret; + xmlRegExecCtxtPtr exec; + + if ((ctxt == NULL) || (ctxt->elem == NULL) || (elem == NULL)) + return (-1); +#ifdef DEBUG_PROGRESSIVE + xmlGenericError(xmlGenericErrorContext, "PopElem %s\n", elem->name); +#endif + /* + * verify that we reached a terminal state of the content model. + */ + exec = xmlRelaxNGElemPop(ctxt); + ret = xmlRegExecPushString(exec, NULL, NULL); + if (ret == 0) { + /* + * TODO: get some of the names needed to exit the current state of exec + */ + VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST ""); + ret = -1; + } else if (ret < 0) { + ret = -1; + } else { + ret = 1; + } + xmlRegFreeExecCtxt(exec); +#ifdef DEBUG_PROGRESSIVE + if (ret < 0) + xmlGenericError(xmlGenericErrorContext, "PopElem %s failed\n", + elem->name); +#endif + return (ret); +} + +/** + * xmlRelaxNGValidateFullElement: + * @ctxt: the validation context + * @doc: a document instance + * @elem: an element instance + * + * Validate a full subtree when xmlRelaxNGValidatePushElement() returned + * 0 and the content of the node has been expanded. + * + * returns 1 if no validation problem was found or -1 in case of error. + */ +int +xmlRelaxNGValidateFullElement(xmlRelaxNGValidCtxtPtr ctxt, + xmlDocPtr doc ATTRIBUTE_UNUSED, + xmlNodePtr elem) +{ + int ret; + xmlRelaxNGValidStatePtr state; + + if ((ctxt == NULL) || (ctxt->pdef == NULL) || (elem == NULL)) + return (-1); +#ifdef DEBUG_PROGRESSIVE + xmlGenericError(xmlGenericErrorContext, "FullElem %s\n", elem->name); +#endif + state = xmlRelaxNGNewValidState(ctxt, elem->parent); + if (state == NULL) { + return (-1); + } + state->seq = elem; + ctxt->state = state; + ctxt->errNo = XML_RELAXNG_OK; + ret = xmlRelaxNGValidateDefinition(ctxt, ctxt->pdef); + if ((ret != 0) || (ctxt->errNo != XML_RELAXNG_OK)) + ret = -1; + else + ret = 1; + xmlRelaxNGFreeValidState(ctxt, ctxt->state); + ctxt->state = NULL; +#ifdef DEBUG_PROGRESSIVE + if (ret < 0) + xmlGenericError(xmlGenericErrorContext, "FullElem %s failed\n", + elem->name); +#endif + return (ret); +} + +/************************************************************************ + * * + * Generic interpreted validation implementation * + * * + ************************************************************************/ +static int xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt, + xmlRelaxNGDefinePtr define); + +/** + * xmlRelaxNGSkipIgnored: + * @ctxt: a schema validation context + * @node: the top node. + * + * Skip ignorable nodes in that context + * + * Returns the new sibling or NULL in case of error. + */ +static xmlNodePtr +xmlRelaxNGSkipIgnored(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED, + xmlNodePtr node) +{ + /* + * TODO complete and handle entities + */ + while ((node != NULL) && + ((node->type == XML_COMMENT_NODE) || + (node->type == XML_PI_NODE) || + (node->type == XML_XINCLUDE_START) || + (node->type == XML_XINCLUDE_END) || + (((node->type == XML_TEXT_NODE) || + (node->type == XML_CDATA_SECTION_NODE)) && + ((ctxt->flags & FLAGS_MIXED_CONTENT) || + (IS_BLANK_NODE(node)))))) { + node = node->next; + } + return (node); +} + +/** + * xmlRelaxNGNormalize: + * @ctxt: a schema validation context + * @str: the string to normalize + * + * Implements the normalizeWhiteSpace( s ) function from + * section 6.2.9 of the spec + * + * Returns the new string or NULL in case of error. + */ +static xmlChar * +xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar * str) +{ + xmlChar *ret, *p; + const xmlChar *tmp; + int len; + + if (str == NULL) + return (NULL); + tmp = str; + while (*tmp != 0) + tmp++; + len = tmp - str; + + ret = (xmlChar *) xmlMallocAtomic((len + 1) * sizeof(xmlChar)); + if (ret == NULL) { + xmlRngVErrMemory(ctxt, "validating\n"); + return (NULL); + } + p = ret; + while (IS_BLANK_CH(*str)) + str++; + while (*str != 0) { + if (IS_BLANK_CH(*str)) { + while (IS_BLANK_CH(*str)) + str++; + if (*str == 0) + break; + *p++ = ' '; + } else + *p++ = *str++; + } + *p = 0; + return (ret); +} + +/** + * xmlRelaxNGValidateDatatype: + * @ctxt: a Relax-NG validation context + * @value: the string value + * @type: the datatype definition + * @node: the node + * + * Validate the given value against the dataype + * + * Returns 0 if the validation succeeded or an error code. + */ +static int +xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt, + const xmlChar * value, + xmlRelaxNGDefinePtr define, xmlNodePtr node) +{ + int ret, tmp; + xmlRelaxNGTypeLibraryPtr lib; + void *result = NULL; + xmlRelaxNGDefinePtr cur; + + if ((define == NULL) || (define->data == NULL)) { + return (-1); + } + lib = (xmlRelaxNGTypeLibraryPtr) define->data; + if (lib->check != NULL) { + if ((define->attrs != NULL) && + (define->attrs->type == XML_RELAXNG_PARAM)) { + ret = + lib->check(lib->data, define->name, value, &result, node); + } else { + ret = lib->check(lib->data, define->name, value, NULL, node); + } + } else + ret = -1; + if (ret < 0) { + VALID_ERR2(XML_RELAXNG_ERR_TYPE, define->name); + if ((result != NULL) && (lib != NULL) && (lib->freef != NULL)) + lib->freef(lib->data, result); + return (-1); + } else if (ret == 1) { + ret = 0; + } else if (ret == 2) { + VALID_ERR2P(XML_RELAXNG_ERR_DUPID, value); + } else { + VALID_ERR3P(XML_RELAXNG_ERR_TYPEVAL, define->name, value); + ret = -1; + } + cur = define->attrs; + while ((ret == 0) && (cur != NULL) && (cur->type == XML_RELAXNG_PARAM)) { + if (lib->facet != NULL) { + tmp = lib->facet(lib->data, define->name, cur->name, + cur->value, value, result); + if (tmp != 0) + ret = -1; + } + cur = cur->next; + } + if ((ret == 0) && (define->content != NULL)) { + const xmlChar *oldvalue, *oldendvalue; + + oldvalue = ctxt->state->value; + oldendvalue = ctxt->state->endvalue; + ctxt->state->value = (xmlChar *) value; + ctxt->state->endvalue = NULL; + ret = xmlRelaxNGValidateValue(ctxt, define->content); + ctxt->state->value = (xmlChar *) oldvalue; + ctxt->state->endvalue = (xmlChar *) oldendvalue; + } + if ((result != NULL) && (lib != NULL) && (lib->freef != NULL)) + lib->freef(lib->data, result); + return (ret); +} + +/** + * xmlRelaxNGNextValue: + * @ctxt: a Relax-NG validation context + * + * Skip to the next value when validating within a list + * + * Returns 0 if the operation succeeded or an error code. + */ +static int +xmlRelaxNGNextValue(xmlRelaxNGValidCtxtPtr ctxt) +{ + xmlChar *cur; + + cur = ctxt->state->value; + if ((cur == NULL) || (ctxt->state->endvalue == NULL)) { + ctxt->state->value = NULL; + ctxt->state->endvalue = NULL; + return (0); + } + while (*cur != 0) + cur++; + while ((cur != ctxt->state->endvalue) && (*cur == 0)) + cur++; + if (cur == ctxt->state->endvalue) + ctxt->state->value = NULL; + else + ctxt->state->value = cur; + return (0); +} + +/** + * xmlRelaxNGValidateValueList: + * @ctxt: a Relax-NG validation context + * @defines: the list of definitions to verify + * + * Validate the given set of definitions for the current value + * + * Returns 0 if the validation succeeded or an error code. + */ +static int +xmlRelaxNGValidateValueList(xmlRelaxNGValidCtxtPtr ctxt, + xmlRelaxNGDefinePtr defines) +{ + int ret = 0; + + while (defines != NULL) { + ret = xmlRelaxNGValidateValue(ctxt, defines); + if (ret != 0) + break; + defines = defines->next; + } + return (ret); +} + +/** + * xmlRelaxNGValidateValue: + * @ctxt: a Relax-NG validation context + * @define: the definition to verify + * + * Validate the given definition for the current value + * + * Returns 0 if the validation succeeded or an error code. + */ +static int +xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt, + xmlRelaxNGDefinePtr define) +{ + int ret = 0, oldflags; + xmlChar *value; + + value = ctxt->state->value; + switch (define->type) { + case XML_RELAXNG_EMPTY:{ + if ((value != NULL) && (value[0] != 0)) { + int idx = 0; + + while (IS_BLANK_CH(value[idx])) + idx++; + if (value[idx] != 0) + ret = -1; + } + break; + } + case XML_RELAXNG_TEXT: + break; + case XML_RELAXNG_VALUE:{ + if (!xmlStrEqual(value, define->value)) { + if (define->name != NULL) { + xmlRelaxNGTypeLibraryPtr lib; + + lib = (xmlRelaxNGTypeLibraryPtr) define->data; + if ((lib != NULL) && (lib->comp != NULL)) { + ret = lib->comp(lib->data, define->name, + define->value, define->node, + (void *) define->attrs, + value, ctxt->state->node); + } else + ret = -1; + if (ret < 0) { + VALID_ERR2(XML_RELAXNG_ERR_TYPECMP, + define->name); + return (-1); + } else if (ret == 1) { + ret = 0; + } else { + ret = -1; + } + } else { + xmlChar *nval, *nvalue; + + /* + * TODO: trivial optimizations are possible by + * computing at compile-time + */ + nval = xmlRelaxNGNormalize(ctxt, define->value); + nvalue = xmlRelaxNGNormalize(ctxt, value); + + if ((nval == NULL) || (nvalue == NULL) || + (!xmlStrEqual(nval, nvalue))) + ret = -1; + if (nval != NULL) + xmlFree(nval); + if (nvalue != NULL) + xmlFree(nvalue); + } + } + if (ret == 0) + xmlRelaxNGNextValue(ctxt); + break; + } + case XML_RELAXNG_DATATYPE:{ + ret = xmlRelaxNGValidateDatatype(ctxt, value, define, + ctxt->state->seq); + if (ret == 0) + xmlRelaxNGNextValue(ctxt); + + break; + } + case XML_RELAXNG_CHOICE:{ + xmlRelaxNGDefinePtr list = define->content; + xmlChar *oldvalue; + + oldflags = ctxt->flags; + ctxt->flags |= FLAGS_IGNORABLE; + + oldvalue = ctxt->state->value; + while (list != NULL) { + ret = xmlRelaxNGValidateValue(ctxt, list); + if (ret == 0) { + break; + } + ctxt->state->value = oldvalue; + list = list->next; + } + ctxt->flags = oldflags; + if (ret != 0) { + if ((ctxt->flags & FLAGS_IGNORABLE) == 0) + xmlRelaxNGDumpValidError(ctxt); + } else { + if (ctxt->errNr > 0) + xmlRelaxNGPopErrors(ctxt, 0); + } + break; + } + case XML_RELAXNG_LIST:{ + xmlRelaxNGDefinePtr list = define->content; + xmlChar *oldvalue, *oldend, *val, *cur; + +#ifdef DEBUG_LIST + int nb_values = 0; +#endif + + oldvalue = ctxt->state->value; + oldend = ctxt->state->endvalue; + + val = xmlStrdup(oldvalue); + if (val == NULL) { + val = xmlStrdup(BAD_CAST ""); + } + if (val == NULL) { + VALID_ERR(XML_RELAXNG_ERR_NOSTATE); + return (-1); + } + cur = val; + while (*cur != 0) { + if (IS_BLANK_CH(*cur)) { + *cur = 0; + cur++; +#ifdef DEBUG_LIST + nb_values++; +#endif + while (IS_BLANK_CH(*cur)) + *cur++ = 0; + } else + cur++; + } +#ifdef DEBUG_LIST + xmlGenericError(xmlGenericErrorContext, + "list value: '%s' found %d items\n", + oldvalue, nb_values); + nb_values = 0; +#endif + ctxt->state->endvalue = cur; + cur = val; + while ((*cur == 0) && (cur != ctxt->state->endvalue)) + cur++; + + ctxt->state->value = cur; + + while (list != NULL) { + if (ctxt->state->value == ctxt->state->endvalue) + ctxt->state->value = NULL; + ret = xmlRelaxNGValidateValue(ctxt, list); + if (ret != 0) { +#ifdef DEBUG_LIST + xmlGenericError(xmlGenericErrorContext, + "Failed to validate value: '%s' with %d rule\n", + ctxt->state->value, nb_values); +#endif + break; + } +#ifdef DEBUG_LIST + nb_values++; +#endif + list = list->next; + } + + if ((ret == 0) && (ctxt->state->value != NULL) && + (ctxt->state->value != ctxt->state->endvalue)) { + VALID_ERR2(XML_RELAXNG_ERR_LISTEXTRA, + ctxt->state->value); + ret = -1; + } + xmlFree(val); + ctxt->state->value = oldvalue; + ctxt->state->endvalue = oldend; + break; + } + case XML_RELAXNG_ONEORMORE: + ret = xmlRelaxNGValidateValueList(ctxt, define->content); + if (ret != 0) { + break; + } + /* no break on purpose */ + case XML_RELAXNG_ZEROORMORE:{ + xmlChar *cur, *temp; + + if ((ctxt->state->value == NULL) || + (*ctxt->state->value == 0)) { + ret = 0; + break; + } + oldflags = ctxt->flags; + ctxt->flags |= FLAGS_IGNORABLE; + cur = ctxt->state->value; + temp = NULL; + while ((cur != NULL) && (cur != ctxt->state->endvalue) && + (temp != cur)) { + temp = cur; + ret = + xmlRelaxNGValidateValueList(ctxt, define->content); + if (ret != 0) { + ctxt->state->value = temp; + ret = 0; + break; + } + cur = ctxt->state->value; + } + ctxt->flags = oldflags; + if (ctxt->errNr > 0) + xmlRelaxNGPopErrors(ctxt, 0); + break; + } + case XML_RELAXNG_OPTIONAL:{ + xmlChar *temp; + + if ((ctxt->state->value == NULL) || + (*ctxt->state->value == 0)) { + ret = 0; + break; + } + oldflags = ctxt->flags; + ctxt->flags |= FLAGS_IGNORABLE; + temp = ctxt->state->value; + ret = xmlRelaxNGValidateValue(ctxt, define->content); + ctxt->flags = oldflags; + if (ret != 0) { + ctxt->state->value = temp; + if (ctxt->errNr > 0) + xmlRelaxNGPopErrors(ctxt, 0); + ret = 0; + break; + } + if (ctxt->errNr > 0) + xmlRelaxNGPopErrors(ctxt, 0); + break; + } + case XML_RELAXNG_EXCEPT:{ + xmlRelaxNGDefinePtr list; + + list = define->content; + while (list != NULL) { + ret = xmlRelaxNGValidateValue(ctxt, list); + if (ret == 0) { + ret = -1; + break; + } else + ret = 0; + list = list->next; + } + break; + } + case XML_RELAXNG_DEF: + case XML_RELAXNG_GROUP:{ + xmlRelaxNGDefinePtr list; + + list = define->content; + while (list != NULL) { + ret = xmlRelaxNGValidateValue(ctxt, list); + if (ret != 0) { + ret = -1; + break; + } else + ret = 0; + list = list->next; + } + break; + } + case XML_RELAXNG_REF: + case XML_RELAXNG_PARENTREF: + if (define->content == NULL) { + VALID_ERR(XML_RELAXNG_ERR_NODEFINE); + ret = -1; + } else { + ret = xmlRelaxNGValidateValue(ctxt, define->content); + } + break; + default: + TODO ret = -1; + } + return (ret); +} + +/** + * xmlRelaxNGValidateValueContent: + * @ctxt: a Relax-NG validation context + * @defines: the list of definitions to verify + * + * Validate the given definitions for the current value + * + * Returns 0 if the validation succeeded or an error code. + */ +static int +xmlRelaxNGValidateValueContent(xmlRelaxNGValidCtxtPtr ctxt, + xmlRelaxNGDefinePtr defines) +{ + int ret = 0; + + while (defines != NULL) { + ret = xmlRelaxNGValidateValue(ctxt, defines); + if (ret != 0) + break; + defines = defines->next; + } + return (ret); +} + +/** + * xmlRelaxNGAttributeMatch: + * @ctxt: a Relax-NG validation context + * @define: the definition to check + * @prop: the attribute + * + * Check if the attribute matches the definition nameClass + * + * Returns 1 if the attribute matches, 0 if no, or -1 in case of error + */ +static int +xmlRelaxNGAttributeMatch(xmlRelaxNGValidCtxtPtr ctxt, + xmlRelaxNGDefinePtr define, xmlAttrPtr prop) +{ + int ret; + + if (define->name != NULL) { + if (!xmlStrEqual(define->name, prop->name)) + return (0); + } + if (define->ns != NULL) { + if (define->ns[0] == 0) { + if (prop->ns != NULL) + return (0); + } else { + if ((prop->ns == NULL) || + (!xmlStrEqual(define->ns, prop->ns->href))) + return (0); + } + } + if (define->nameClass == NULL) + return (1); + define = define->nameClass; + if (define->type == XML_RELAXNG_EXCEPT) { + xmlRelaxNGDefinePtr list; + + list = define->content; + while (list != NULL) { + ret = xmlRelaxNGAttributeMatch(ctxt, list, prop); + if (ret == 1) + return (0); + if (ret < 0) + return (ret); + list = list->next; + } + } else { + TODO} + return (1); +} + +/** + * xmlRelaxNGValidateAttribute: + * @ctxt: a Relax-NG validation context + * @define: the definition to verify + * + * Validate the given attribute definition for that node + * + * Returns 0 if the validation succeeded or an error code. + */ +static int +xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt, + xmlRelaxNGDefinePtr define) +{ + int ret = 0, i; + xmlChar *value, *oldvalue; + xmlAttrPtr prop = NULL, tmp; + xmlNodePtr oldseq; + + if (ctxt->state->nbAttrLeft <= 0) + return (-1); + if (define->name != NULL) { + for (i = 0; i < ctxt->state->nbAttrs; i++) { + tmp = ctxt->state->attrs[i]; + if ((tmp != NULL) && (xmlStrEqual(define->name, tmp->name))) { + if ((((define->ns == NULL) || (define->ns[0] == 0)) && + (tmp->ns == NULL)) || + ((tmp->ns != NULL) && + (xmlStrEqual(define->ns, tmp->ns->href)))) { + prop = tmp; + break; + } + } + } + if (prop != NULL) { + value = xmlNodeListGetString(prop->doc, prop->children, 1); + oldvalue = ctxt->state->value; + oldseq = ctxt->state->seq; + ctxt->state->seq = (xmlNodePtr) prop; + ctxt->state->value = value; + ctxt->state->endvalue = NULL; + ret = xmlRelaxNGValidateValueContent(ctxt, define->content); + if (ctxt->state->value != NULL) + value = ctxt->state->value; + if (value != NULL) + xmlFree(value); + ctxt->state->value = oldvalue; + ctxt->state->seq = oldseq; + if (ret == 0) { + /* + * flag the attribute as processed + */ + ctxt->state->attrs[i] = NULL; + ctxt->state->nbAttrLeft--; + } + } else { + ret = -1; + } +#ifdef DEBUG + xmlGenericError(xmlGenericErrorContext, + "xmlRelaxNGValidateAttribute(%s): %d\n", + define->name, ret); +#endif + } else { + for (i = 0; i < ctxt->state->nbAttrs; i++) { + tmp = ctxt->state->attrs[i]; + if ((tmp != NULL) && + (xmlRelaxNGAttributeMatch(ctxt, define, tmp) == 1)) { + prop = tmp; + break; + } + } + if (prop != NULL) { + value = xmlNodeListGetString(prop->doc, prop->children, 1); + oldvalue = ctxt->state->value; + oldseq = ctxt->state->seq; + ctxt->state->seq = (xmlNodePtr) prop; + ctxt->state->value = value; + ret = xmlRelaxNGValidateValueContent(ctxt, define->content); + if (ctxt->state->value != NULL) + value = ctxt->state->value; + if (value != NULL) + xmlFree(value); + ctxt->state->value = oldvalue; + ctxt->state->seq = oldseq; + if (ret == 0) { + /* + * flag the attribute as processed + */ + ctxt->state->attrs[i] = NULL; + ctxt->state->nbAttrLeft--; + } + } else { + ret = -1; + } +#ifdef DEBUG + if (define->ns != NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlRelaxNGValidateAttribute(nsName ns = %s): %d\n", + define->ns, ret); + } else { + xmlGenericError(xmlGenericErrorContext, + "xmlRelaxNGValidateAttribute(anyName): %d\n", + ret); + } +#endif + } + + return (ret); +} + +/** + * xmlRelaxNGValidateAttributeList: + * @ctxt: a Relax-NG validation context + * @define: the list of definition to verify + * + * Validate the given node against the list of attribute definitions + * + * Returns 0 if the validation succeeded or an error code. + */ +static int +xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt, + xmlRelaxNGDefinePtr defines) +{ + int ret = 0, res; + int needmore = 0; + xmlRelaxNGDefinePtr cur; + + cur = defines; + while (cur != NULL) { + if (cur->type == XML_RELAXNG_ATTRIBUTE) { + if (xmlRelaxNGValidateAttribute(ctxt, cur) != 0) + ret = -1; + } else + needmore = 1; + cur = cur->next; + } + if (!needmore) + return (ret); + cur = defines; + while (cur != NULL) { + if (cur->type != XML_RELAXNG_ATTRIBUTE) { + if ((ctxt->state != NULL) || (ctxt->states != NULL)) { + res = xmlRelaxNGValidateDefinition(ctxt, cur); + if (res < 0) + ret = -1; + } else { + VALID_ERR(XML_RELAXNG_ERR_NOSTATE); + return (-1); + } + if (res == -1) /* continues on -2 */ + break; + } + cur = cur->next; + } + + return (ret); +} + +/** + * xmlRelaxNGNodeMatchesList: + * @node: the node + * @list: a NULL terminated array of definitions + * + * Check if a node can be matched by one of the definitions + * + * Returns 1 if matches 0 otherwise + */ +static int +xmlRelaxNGNodeMatchesList(xmlNodePtr node, xmlRelaxNGDefinePtr * list) +{ + xmlRelaxNGDefinePtr cur; + int i = 0, tmp; + + if ((node == NULL) || (list == NULL)) + return (0); + + cur = list[i++]; + while (cur != NULL) { + if ((node->type == XML_ELEMENT_NODE) && + (cur->type == XML_RELAXNG_ELEMENT)) { + tmp = xmlRelaxNGElementMatch(NULL, cur, node); + if (tmp == 1) + return (1); + } else if (((node->type == XML_TEXT_NODE) || + (node->type == XML_CDATA_SECTION_NODE)) && + (cur->type == XML_RELAXNG_TEXT)) { + return (1); + } + cur = list[i++]; + } + return (0); +} + +/** + * xmlRelaxNGValidateInterleave: + * @ctxt: a Relax-NG validation context + * @define: the definition to verify + * + * Validate an interleave definition for a node. + * + * Returns 0 if the validation succeeded or an error code. + */ +static int +xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt, + xmlRelaxNGDefinePtr define) +{ + int ret = 0, i, nbgroups; + int errNr = ctxt->errNr; + int oldflags; + + xmlRelaxNGValidStatePtr oldstate; + xmlRelaxNGPartitionPtr partitions; + xmlRelaxNGInterleaveGroupPtr group = NULL; + xmlNodePtr cur, start, last = NULL, lastchg = NULL, lastelem; + xmlNodePtr *list = NULL, *lasts = NULL; + + if (define->data != NULL) { + partitions = (xmlRelaxNGPartitionPtr) define->data; + nbgroups = partitions->nbgroups; + } else { + VALID_ERR(XML_RELAXNG_ERR_INTERNODATA); + return (-1); + } + /* + * Optimizations for MIXED + */ + oldflags = ctxt->flags; + if (define->dflags & IS_MIXED) { + ctxt->flags |= FLAGS_MIXED_CONTENT; + if (nbgroups == 2) { + /* + * this is a pure case + */ + if (ctxt->state != NULL) + ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt, + ctxt->state->seq); + if (partitions->groups[0]->rule->type == XML_RELAXNG_TEXT) + ret = xmlRelaxNGValidateDefinition(ctxt, + partitions->groups[1]-> + rule); + else + ret = xmlRelaxNGValidateDefinition(ctxt, + partitions->groups[0]-> + rule); + if (ret == 0) { + if (ctxt->state != NULL) + ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt, + ctxt->state-> + seq); + } + ctxt->flags = oldflags; + return (ret); + } + } + + /* + * Build arrays to store the first and last node of the chain + * pertaining to each group + */ + list = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr)); + if (list == NULL) { + xmlRngVErrMemory(ctxt, "validating\n"); + return (-1); + } + memset(list, 0, nbgroups * sizeof(xmlNodePtr)); + lasts = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr)); + if (lasts == NULL) { + xmlRngVErrMemory(ctxt, "validating\n"); + return (-1); + } + memset(lasts, 0, nbgroups * sizeof(xmlNodePtr)); + + /* + * Walk the sequence of children finding the right group and + * sorting them in sequences. + */ + cur = ctxt->state->seq; + cur = xmlRelaxNGSkipIgnored(ctxt, cur); + start = cur; + while (cur != NULL) { + ctxt->state->seq = cur; + if ((partitions->triage != NULL) && + (partitions->flags & IS_DETERMINIST)) { + void *tmp = NULL; + + if ((cur->type == XML_TEXT_NODE) || + (cur->type == XML_CDATA_SECTION_NODE)) { + tmp = xmlHashLookup2(partitions->triage, BAD_CAST "#text", + NULL); + } else if (cur->type == XML_ELEMENT_NODE) { + if (cur->ns != NULL) { + tmp = xmlHashLookup2(partitions->triage, cur->name, + cur->ns->href); + if (tmp == NULL) + tmp = xmlHashLookup2(partitions->triage, + BAD_CAST "#any", + cur->ns->href); + } else + tmp = + xmlHashLookup2(partitions->triage, cur->name, + NULL); + if (tmp == NULL) + tmp = + xmlHashLookup2(partitions->triage, BAD_CAST "#any", + NULL); + } + + if (tmp == NULL) { + i = nbgroups; + } else { + i = ((long) tmp) - 1; + if (partitions->flags & IS_NEEDCHECK) { + group = partitions->groups[i]; + if (!xmlRelaxNGNodeMatchesList(cur, group->defs)) + i = nbgroups; + } + } + } else { + for (i = 0; i < nbgroups; i++) { + group = partitions->groups[i]; + if (group == NULL) + continue; + if (xmlRelaxNGNodeMatchesList(cur, group->defs)) + break; + } + } + /* + * We break as soon as an element not matched is found + */ + if (i >= nbgroups) { + break; + } + if (lasts[i] != NULL) { + lasts[i]->next = cur; + lasts[i] = cur; + } else { + list[i] = cur; + lasts[i] = cur; + } + if (cur->next != NULL) + lastchg = cur->next; + else + lastchg = cur; + cur = xmlRelaxNGSkipIgnored(ctxt, cur->next); + } + if (ret != 0) { + VALID_ERR(XML_RELAXNG_ERR_INTERSEQ); + ret = -1; + goto done; + } + lastelem = cur; + oldstate = ctxt->state; + for (i = 0; i < nbgroups; i++) { + ctxt->state = xmlRelaxNGCopyValidState(ctxt, oldstate); + group = partitions->groups[i]; + if (lasts[i] != NULL) { + last = lasts[i]->next; + lasts[i]->next = NULL; + } + ctxt->state->seq = list[i]; + ret = xmlRelaxNGValidateDefinition(ctxt, group->rule); + if (ret != 0) + break; + if (ctxt->state != NULL) { + cur = ctxt->state->seq; + cur = xmlRelaxNGSkipIgnored(ctxt, cur); + xmlRelaxNGFreeValidState(ctxt, oldstate); + oldstate = ctxt->state; + ctxt->state = NULL; + if (cur != NULL) { + VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name); + ret = -1; + ctxt->state = oldstate; + goto done; + } + } else if (ctxt->states != NULL) { + int j; + int found = 0; + int best = -1; + int lowattr = -1; + + /* + * PBM: what happen if there is attributes checks in the interleaves + */ + + for (j = 0; j < ctxt->states->nbState; j++) { + cur = ctxt->states->tabState[j]->seq; + cur = xmlRelaxNGSkipIgnored(ctxt, cur); + if (cur == NULL) { + if (found == 0) { + lowattr = ctxt->states->tabState[j]->nbAttrLeft; + best = j; + } + found = 1; + if (ctxt->states->tabState[j]->nbAttrLeft <= lowattr) { + /* try to keep the latest one to mach old heuristic */ + lowattr = ctxt->states->tabState[j]->nbAttrLeft; + best = j; + } + if (lowattr == 0) + break; + } else if (found == 0) { + if (lowattr == -1) { + lowattr = ctxt->states->tabState[j]->nbAttrLeft; + best = j; + } else + if (ctxt->states->tabState[j]->nbAttrLeft <= lowattr) { + /* try to keep the latest one to mach old heuristic */ + lowattr = ctxt->states->tabState[j]->nbAttrLeft; + best = j; + } + } + } + /* + * BIG PBM: here we pick only one restarting point :-( + */ + if (ctxt->states->nbState > 0) { + xmlRelaxNGFreeValidState(ctxt, oldstate); + if (best != -1) { + oldstate = ctxt->states->tabState[best]; + ctxt->states->tabState[best] = NULL; + } else { + oldstate = + ctxt->states->tabState[ctxt->states->nbState - 1]; + ctxt->states->tabState[ctxt->states->nbState - 1] = NULL; + ctxt->states->nbState--; + } + } + for (j = 0; j < ctxt->states->nbState ; j++) { + xmlRelaxNGFreeValidState(ctxt, ctxt->states->tabState[j]); + } + xmlRelaxNGFreeStates(ctxt, ctxt->states); + ctxt->states = NULL; + if (found == 0) { + if (cur == NULL) { + VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, + (const xmlChar *) "noname"); + } else { + VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name); + } + ret = -1; + ctxt->state = oldstate; + goto done; + } + } else { + ret = -1; + break; + } + if (lasts[i] != NULL) { + lasts[i]->next = last; + } + } + if (ctxt->state != NULL) + xmlRelaxNGFreeValidState(ctxt, ctxt->state); + ctxt->state = oldstate; + ctxt->state->seq = lastelem; + if (ret != 0) { + VALID_ERR(XML_RELAXNG_ERR_INTERSEQ); + ret = -1; + goto done; + } + + done: + ctxt->flags = oldflags; + /* + * builds the next links chain from the prev one + */ + cur = lastchg; + while (cur != NULL) { + if ((cur == start) || (cur->prev == NULL)) + break; + cur->prev->next = cur; + cur = cur->prev; + } + if (ret == 0) { + if (ctxt->errNr > errNr) + xmlRelaxNGPopErrors(ctxt, errNr); + } + + xmlFree(list); + xmlFree(lasts); + return (ret); +} + +/** + * xmlRelaxNGValidateDefinitionList: + * @ctxt: a Relax-NG validation context + * @define: the list of definition to verify + * + * Validate the given node content against the (list) of definitions + * + * Returns 0 if the validation succeeded or an error code. + */ +static int +xmlRelaxNGValidateDefinitionList(xmlRelaxNGValidCtxtPtr ctxt, + xmlRelaxNGDefinePtr defines) +{ + int ret = 0, res; + + + if (defines == NULL) { + VALID_ERR2(XML_RELAXNG_ERR_INTERNAL, + BAD_CAST "NULL definition list"); + return (-1); + } + while (defines != NULL) { + if ((ctxt->state != NULL) || (ctxt->states != NULL)) { + res = xmlRelaxNGValidateDefinition(ctxt, defines); + if (res < 0) + ret = -1; + } else { + VALID_ERR(XML_RELAXNG_ERR_NOSTATE); + return (-1); + } + if (res == -1) /* continues on -2 */ + break; + defines = defines->next; + } + + return (ret); +} + +/** + * xmlRelaxNGElementMatch: + * @ctxt: a Relax-NG validation context + * @define: the definition to check + * @elem: the element + * + * Check if the element matches the definition nameClass + * + * Returns 1 if the element matches, 0 if no, or -1 in case of error + */ +static int +xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt, + xmlRelaxNGDefinePtr define, xmlNodePtr elem) +{ + int ret = 0, oldflags = 0; + + if (define->name != NULL) { + if (!xmlStrEqual(elem->name, define->name)) { + VALID_ERR3(XML_RELAXNG_ERR_ELEMNAME, define->name, elem->name); + return (0); + } + } + if ((define->ns != NULL) && (define->ns[0] != 0)) { + if (elem->ns == NULL) { + VALID_ERR2(XML_RELAXNG_ERR_ELEMNONS, elem->name); + return (0); + } else if (!xmlStrEqual(elem->ns->href, define->ns)) { + VALID_ERR3(XML_RELAXNG_ERR_ELEMWRONGNS, + elem->name, define->ns); + return (0); + } + } else if ((elem->ns != NULL) && (define->ns != NULL) && + (define->name == NULL)) { + VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS, elem->name); + return (0); + } else if ((elem->ns != NULL) && (define->name != NULL)) { + VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS, define->name); + return (0); + } + + if (define->nameClass == NULL) + return (1); + + define = define->nameClass; + if (define->type == XML_RELAXNG_EXCEPT) { + xmlRelaxNGDefinePtr list; + + if (ctxt != NULL) { + oldflags = ctxt->flags; + ctxt->flags |= FLAGS_IGNORABLE; + } + + list = define->content; + while (list != NULL) { + ret = xmlRelaxNGElementMatch(ctxt, list, elem); + if (ret == 1) { + if (ctxt != NULL) + ctxt->flags = oldflags; + return (0); + } + if (ret < 0) { + if (ctxt != NULL) + ctxt->flags = oldflags; + return (ret); + } + list = list->next; + } + ret = 1; + if (ctxt != NULL) { + ctxt->flags = oldflags; + } + } else if (define->type == XML_RELAXNG_CHOICE) { + xmlRelaxNGDefinePtr list; + + if (ctxt != NULL) { + oldflags = ctxt->flags; + ctxt->flags |= FLAGS_IGNORABLE; + } + + list = define->nameClass; + while (list != NULL) { + ret = xmlRelaxNGElementMatch(ctxt, list, elem); + if (ret == 1) { + if (ctxt != NULL) + ctxt->flags = oldflags; + return (1); + } + if (ret < 0) { + if (ctxt != NULL) + ctxt->flags = oldflags; + return (ret); + } + list = list->next; + } + if (ctxt != NULL) { + if (ret != 0) { + if ((ctxt->flags & FLAGS_IGNORABLE) == 0) + xmlRelaxNGDumpValidError(ctxt); + } else { + if (ctxt->errNr > 0) + xmlRelaxNGPopErrors(ctxt, 0); + } + } + ret = 0; + if (ctxt != NULL) { + ctxt->flags = oldflags; + } + } else { + TODO ret = -1; + } + return (ret); +} + +/** + * xmlRelaxNGBestState: + * @ctxt: a Relax-NG validation context + * + * Find the "best" state in the ctxt->states list of states to report + * errors about. I.e. a state with no element left in the child list + * or the one with the less attributes left. + * This is called only if a falidation error was detected + * + * Returns the index of the "best" state or -1 in case of error + */ +static int +xmlRelaxNGBestState(xmlRelaxNGValidCtxtPtr ctxt) +{ + xmlRelaxNGValidStatePtr state; + int i, tmp; + int best = -1; + int value = 1000000; + + if ((ctxt == NULL) || (ctxt->states == NULL) || + (ctxt->states->nbState <= 0)) + return (-1); + + for (i = 0; i < ctxt->states->nbState; i++) { + state = ctxt->states->tabState[i]; + if (state == NULL) + continue; + if (state->seq != NULL) { + if ((best == -1) || (value > 100000)) { + value = 100000; + best = i; + } + } else { + tmp = state->nbAttrLeft; + if ((best == -1) || (value > tmp)) { + value = tmp; + best = i; + } + } + } + return (best); +} + +/** + * xmlRelaxNGLogBestError: + * @ctxt: a Relax-NG validation context + * + * Find the "best" state in the ctxt->states list of states to report + * errors about and log it. + */ +static void +xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt) +{ + int best; + + if ((ctxt == NULL) || (ctxt->states == NULL) || + (ctxt->states->nbState <= 0)) + return; + + best = xmlRelaxNGBestState(ctxt); + if ((best >= 0) && (best < ctxt->states->nbState)) { + ctxt->state = ctxt->states->tabState[best]; + + xmlRelaxNGValidateElementEnd(ctxt, 1); + } +} + +/** + * xmlRelaxNGValidateElementEnd: + * @ctxt: a Relax-NG validation context + * @dolog: indicate that error logging should be done + * + * Validate the end of the element, implements check that + * there is nothing left not consumed in the element content + * or in the attribute list. + * + * Returns 0 if the validation succeeded or an error code. + */ +static int +xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt, int dolog) +{ + int i; + xmlRelaxNGValidStatePtr state; + + state = ctxt->state; + if (state->seq != NULL) { + state->seq = xmlRelaxNGSkipIgnored(ctxt, state->seq); + if (state->seq != NULL) { + if (dolog) { + VALID_ERR3(XML_RELAXNG_ERR_EXTRACONTENT, + state->node->name, state->seq->name); + } + return (-1); + } + } + for (i = 0; i < state->nbAttrs; i++) { + if (state->attrs[i] != NULL) { + if (dolog) { + VALID_ERR3(XML_RELAXNG_ERR_INVALIDATTR, + state->attrs[i]->name, state->node->name); + } + return (-1 - i); + } + } + return (0); +} + +/** + * xmlRelaxNGValidateState: + * @ctxt: a Relax-NG validation context + * @define: the definition to verify + * + * Validate the current state against the definition + * + * Returns 0 if the validation succeeded or an error code. + */ +static int +xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt, + xmlRelaxNGDefinePtr define) +{ + xmlNodePtr node; + int ret = 0, i, tmp, oldflags, errNr; + xmlRelaxNGValidStatePtr oldstate = NULL, state; + + if (define == NULL) { + VALID_ERR(XML_RELAXNG_ERR_NODEFINE); + return (-1); + } + + if (ctxt->state != NULL) { + node = ctxt->state->seq; + } else { + node = NULL; + } +#ifdef DEBUG + for (i = 0; i < ctxt->depth; i++) + xmlGenericError(xmlGenericErrorContext, " "); + xmlGenericError(xmlGenericErrorContext, + "Start validating %s ", xmlRelaxNGDefName(define)); + if (define->name != NULL) + xmlGenericError(xmlGenericErrorContext, "%s ", define->name); + if ((node != NULL) && (node->name != NULL)) + xmlGenericError(xmlGenericErrorContext, "on %s\n", node->name); + else + xmlGenericError(xmlGenericErrorContext, "\n"); +#endif + ctxt->depth++; + switch (define->type) { + case XML_RELAXNG_EMPTY: + node = xmlRelaxNGSkipIgnored(ctxt, node); + ret = 0; + break; + case XML_RELAXNG_NOT_ALLOWED: + ret = -1; + break; + case XML_RELAXNG_TEXT: + while ((node != NULL) && + ((node->type == XML_TEXT_NODE) || + (node->type == XML_COMMENT_NODE) || + (node->type == XML_PI_NODE) || + (node->type == XML_CDATA_SECTION_NODE))) + node = node->next; + ctxt->state->seq = node; + break; + case XML_RELAXNG_ELEMENT: + errNr = ctxt->errNr; + node = xmlRelaxNGSkipIgnored(ctxt, node); + if (node == NULL) { + VALID_ERR2(XML_RELAXNG_ERR_NOELEM, define->name); + ret = -1; + if ((ctxt->flags & FLAGS_IGNORABLE) == 0) + xmlRelaxNGDumpValidError(ctxt); + break; + } + if (node->type != XML_ELEMENT_NODE) { + VALID_ERR(XML_RELAXNG_ERR_NOTELEM); + ret = -1; + if ((ctxt->flags & FLAGS_IGNORABLE) == 0) + xmlRelaxNGDumpValidError(ctxt); + break; + } + /* + * This node was already validated successfully against + * this definition. + */ + if (node->psvi == define) { + ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt, node->next); + if (ctxt->errNr > errNr) + xmlRelaxNGPopErrors(ctxt, errNr); + if (ctxt->errNr != 0) { + while ((ctxt->err != NULL) && + (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME) + && (xmlStrEqual(ctxt->err->arg2, node->name))) + || + ((ctxt->err->err == + XML_RELAXNG_ERR_ELEMEXTRANS) + && (xmlStrEqual(ctxt->err->arg1, node->name))) + || (ctxt->err->err == XML_RELAXNG_ERR_NOELEM) + || (ctxt->err->err == + XML_RELAXNG_ERR_NOTELEM))) + xmlRelaxNGValidErrorPop(ctxt); + } + break; + } + + ret = xmlRelaxNGElementMatch(ctxt, define, node); + if (ret <= 0) { + ret = -1; + if ((ctxt->flags & FLAGS_IGNORABLE) == 0) + xmlRelaxNGDumpValidError(ctxt); + break; + } + ret = 0; + if (ctxt->errNr != 0) { + if (ctxt->errNr > errNr) + xmlRelaxNGPopErrors(ctxt, errNr); + while ((ctxt->err != NULL) && + (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME) && + (xmlStrEqual(ctxt->err->arg2, node->name))) || + ((ctxt->err->err == XML_RELAXNG_ERR_ELEMEXTRANS) && + (xmlStrEqual(ctxt->err->arg1, node->name))) || + (ctxt->err->err == XML_RELAXNG_ERR_NOELEM) || + (ctxt->err->err == XML_RELAXNG_ERR_NOTELEM))) + xmlRelaxNGValidErrorPop(ctxt); + } + errNr = ctxt->errNr; + + oldflags = ctxt->flags; + if (ctxt->flags & FLAGS_MIXED_CONTENT) { + ctxt->flags -= FLAGS_MIXED_CONTENT; + } + state = xmlRelaxNGNewValidState(ctxt, node); + if (state == NULL) { + ret = -1; + if ((ctxt->flags & FLAGS_IGNORABLE) == 0) + xmlRelaxNGDumpValidError(ctxt); + break; + } + + oldstate = ctxt->state; + ctxt->state = state; + if (define->attrs != NULL) { + tmp = xmlRelaxNGValidateAttributeList(ctxt, define->attrs); + if (tmp != 0) { + ret = -1; + VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name); + } + } + if (define->contModel != NULL) { + xmlRelaxNGValidStatePtr nstate, tmpstate = ctxt->state; + xmlRelaxNGStatesPtr tmpstates = ctxt->states; + xmlNodePtr nseq; + + nstate = xmlRelaxNGNewValidState(ctxt, node); + ctxt->state = nstate; + ctxt->states = NULL; + + tmp = xmlRelaxNGValidateCompiledContent(ctxt, + define->contModel, + ctxt->state->seq); + nseq = ctxt->state->seq; + ctxt->state = tmpstate; + ctxt->states = tmpstates; + xmlRelaxNGFreeValidState(ctxt, nstate); + +#ifdef DEBUG_COMPILE + xmlGenericError(xmlGenericErrorContext, + "Validating content of '%s' : %d\n", + define->name, tmp); +#endif + if (tmp != 0) + ret = -1; + + if (ctxt->states != NULL) { + tmp = -1; + + for (i = 0; i < ctxt->states->nbState; i++) { + state = ctxt->states->tabState[i]; + ctxt->state = state; + ctxt->state->seq = nseq; + + if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) { + tmp = 0; + break; + } + } + if (tmp != 0) { + /* + * validation error, log the message for the "best" one + */ + ctxt->flags |= FLAGS_IGNORABLE; + xmlRelaxNGLogBestError(ctxt); + } + for (i = 0; i < ctxt->states->nbState; i++) { + xmlRelaxNGFreeValidState(ctxt, + ctxt->states-> + tabState[i]); + } + xmlRelaxNGFreeStates(ctxt, ctxt->states); + ctxt->flags = oldflags; + ctxt->states = NULL; + if ((ret == 0) && (tmp == -1)) + ret = -1; + } else { + state = ctxt->state; + if (ctxt->state != NULL) + ctxt->state->seq = nseq; + if (ret == 0) + ret = xmlRelaxNGValidateElementEnd(ctxt, 1); + xmlRelaxNGFreeValidState(ctxt, state); + } + } else { + if (define->content != NULL) { + tmp = xmlRelaxNGValidateDefinitionList(ctxt, + define-> + content); + if (tmp != 0) { + ret = -1; + if (ctxt->state == NULL) { + ctxt->state = oldstate; + VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID, + node->name); + ctxt->state = NULL; + } else { + VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID, + node->name); + } + + } + } + if (ctxt->states != NULL) { + tmp = -1; + + for (i = 0; i < ctxt->states->nbState; i++) { + state = ctxt->states->tabState[i]; + ctxt->state = state; + + if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) { + tmp = 0; + break; + } + } + if (tmp != 0) { + /* + * validation error, log the message for the "best" one + */ + ctxt->flags |= FLAGS_IGNORABLE; + xmlRelaxNGLogBestError(ctxt); + } + for (i = 0; i < ctxt->states->nbState; i++) { + xmlRelaxNGFreeValidState(ctxt, + ctxt->states->tabState[i]); + ctxt->states->tabState[i] = NULL; + } + xmlRelaxNGFreeStates(ctxt, ctxt->states); + ctxt->flags = oldflags; + ctxt->states = NULL; + if ((ret == 0) && (tmp == -1)) + ret = -1; + } else { + state = ctxt->state; + if (ret == 0) + ret = xmlRelaxNGValidateElementEnd(ctxt, 1); + xmlRelaxNGFreeValidState(ctxt, state); + } + } + if (ret == 0) { + node->psvi = define; + } + ctxt->flags = oldflags; + ctxt->state = oldstate; + if (oldstate != NULL) + oldstate->seq = xmlRelaxNGSkipIgnored(ctxt, node->next); + if (ret != 0) { + if ((ctxt->flags & FLAGS_IGNORABLE) == 0) { + xmlRelaxNGDumpValidError(ctxt); + ret = 0; +#if 0 + } else { + ret = -2; +#endif + } + } else { + if (ctxt->errNr > errNr) + xmlRelaxNGPopErrors(ctxt, errNr); + } + +#ifdef DEBUG + xmlGenericError(xmlGenericErrorContext, + "xmlRelaxNGValidateDefinition(): validated %s : %d", + node->name, ret); + if (oldstate == NULL) + xmlGenericError(xmlGenericErrorContext, ": no state\n"); + else if (oldstate->seq == NULL) + xmlGenericError(xmlGenericErrorContext, ": done\n"); + else if (oldstate->seq->type == XML_ELEMENT_NODE) + xmlGenericError(xmlGenericErrorContext, ": next elem %s\n", + oldstate->seq->name); + else + xmlGenericError(xmlGenericErrorContext, ": next %s %d\n", + oldstate->seq->name, oldstate->seq->type); +#endif + break; + case XML_RELAXNG_OPTIONAL:{ + errNr = ctxt->errNr; + oldflags = ctxt->flags; + ctxt->flags |= FLAGS_IGNORABLE; + oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state); + ret = + xmlRelaxNGValidateDefinitionList(ctxt, + define->content); + if (ret != 0) { + if (ctxt->state != NULL) + xmlRelaxNGFreeValidState(ctxt, ctxt->state); + ctxt->state = oldstate; + ctxt->flags = oldflags; + ret = 0; + if (ctxt->errNr > errNr) + xmlRelaxNGPopErrors(ctxt, errNr); + break; + } + if (ctxt->states != NULL) { + xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate); + } else { + ctxt->states = xmlRelaxNGNewStates(ctxt, 1); + if (ctxt->states == NULL) { + xmlRelaxNGFreeValidState(ctxt, oldstate); + ctxt->flags = oldflags; + ret = -1; + if (ctxt->errNr > errNr) + xmlRelaxNGPopErrors(ctxt, errNr); + break; + } + xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate); + xmlRelaxNGAddStates(ctxt, ctxt->states, ctxt->state); + ctxt->state = NULL; + } + ctxt->flags = oldflags; + ret = 0; + if (ctxt->errNr > errNr) + xmlRelaxNGPopErrors(ctxt, errNr); + break; + } + case XML_RELAXNG_ONEORMORE: + errNr = ctxt->errNr; + ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content); + if (ret != 0) { + break; + } + if (ctxt->errNr > errNr) + xmlRelaxNGPopErrors(ctxt, errNr); + /* no break on purpose */ + case XML_RELAXNG_ZEROORMORE:{ + int progress; + xmlRelaxNGStatesPtr states = NULL, res = NULL; + int base, j; + + errNr = ctxt->errNr; + res = xmlRelaxNGNewStates(ctxt, 1); + if (res == NULL) { + ret = -1; + break; + } + /* + * All the input states are also exit states + */ + if (ctxt->state != NULL) { + xmlRelaxNGAddStates(ctxt, res, + xmlRelaxNGCopyValidState(ctxt, + ctxt-> + state)); + } else { + for (j = 0; j < ctxt->states->nbState; j++) { + xmlRelaxNGAddStates(ctxt, res, + xmlRelaxNGCopyValidState(ctxt, + ctxt->states->tabState[j])); + } + } + oldflags = ctxt->flags; + ctxt->flags |= FLAGS_IGNORABLE; + do { + progress = 0; + base = res->nbState; + + if (ctxt->states != NULL) { + states = ctxt->states; + for (i = 0; i < states->nbState; i++) { + ctxt->state = states->tabState[i]; + ctxt->states = NULL; + ret = xmlRelaxNGValidateDefinitionList(ctxt, + define-> + content); + if (ret == 0) { + if (ctxt->state != NULL) { + tmp = xmlRelaxNGAddStates(ctxt, res, + ctxt->state); + ctxt->state = NULL; + if (tmp == 1) + progress = 1; + } else if (ctxt->states != NULL) { + for (j = 0; j < ctxt->states->nbState; + j++) { + tmp = + xmlRelaxNGAddStates(ctxt, res, + ctxt->states->tabState[j]); + if (tmp == 1) + progress = 1; + } + xmlRelaxNGFreeStates(ctxt, + ctxt->states); + ctxt->states = NULL; + } + } else { + if (ctxt->state != NULL) { + xmlRelaxNGFreeValidState(ctxt, + ctxt->state); + ctxt->state = NULL; + } + } + } + } else { + ret = xmlRelaxNGValidateDefinitionList(ctxt, + define-> + content); + if (ret != 0) { + xmlRelaxNGFreeValidState(ctxt, ctxt->state); + ctxt->state = NULL; + } else { + base = res->nbState; + if (ctxt->state != NULL) { + tmp = xmlRelaxNGAddStates(ctxt, res, + ctxt->state); + ctxt->state = NULL; + if (tmp == 1) + progress = 1; + } else if (ctxt->states != NULL) { + for (j = 0; j < ctxt->states->nbState; j++) { + tmp = xmlRelaxNGAddStates(ctxt, res, + ctxt->states->tabState[j]); + if (tmp == 1) + progress = 1; + } + if (states == NULL) { + states = ctxt->states; + } else { + xmlRelaxNGFreeStates(ctxt, + ctxt->states); + } + ctxt->states = NULL; + } + } + } + if (progress) { + /* + * Collect all the new nodes added at that step + * and make them the new node set + */ + if (res->nbState - base == 1) { + ctxt->state = xmlRelaxNGCopyValidState(ctxt, + res-> + tabState + [base]); + } else { + if (states == NULL) { + xmlRelaxNGNewStates(ctxt, + res->nbState - base); + states = ctxt->states; + if (states == NULL) { + progress = 0; + break; + } + } + states->nbState = 0; + for (i = base; i < res->nbState; i++) + xmlRelaxNGAddStates(ctxt, states, + xmlRelaxNGCopyValidState + (ctxt, res->tabState[i])); + ctxt->states = states; + } + } + } while (progress == 1); + if (states != NULL) { + xmlRelaxNGFreeStates(ctxt, states); + } + ctxt->states = res; + ctxt->flags = oldflags; +#if 0 + /* + * errors may have to be propagated back... + */ + if (ctxt->errNr > errNr) + xmlRelaxNGPopErrors(ctxt, errNr); +#endif + ret = 0; + break; + } + case XML_RELAXNG_CHOICE:{ + xmlRelaxNGDefinePtr list = NULL; + xmlRelaxNGStatesPtr states = NULL; + + node = xmlRelaxNGSkipIgnored(ctxt, node); + + errNr = ctxt->errNr; + if ((define->dflags & IS_TRIABLE) && (define->data != NULL) && + (node != NULL)) { + /* + * node == NULL can't be optimized since IS_TRIABLE + * doesn't account for choice which may lead to + * only attributes. + */ + xmlHashTablePtr triage = + (xmlHashTablePtr) define->data; + + /* + * Something we can optimize cleanly there is only one + * possble branch out ! + */ + if ((node->type == XML_TEXT_NODE) || + (node->type == XML_CDATA_SECTION_NODE)) { + list = + xmlHashLookup2(triage, BAD_CAST "#text", NULL); + } else if (node->type == XML_ELEMENT_NODE) { + if (node->ns != NULL) { + list = xmlHashLookup2(triage, node->name, + node->ns->href); + if (list == NULL) + list = + xmlHashLookup2(triage, BAD_CAST "#any", + node->ns->href); + } else + list = + xmlHashLookup2(triage, node->name, NULL); + if (list == NULL) + list = + xmlHashLookup2(triage, BAD_CAST "#any", + NULL); + } + if (list == NULL) { + ret = -1; + VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, node->name); + break; + } + ret = xmlRelaxNGValidateDefinition(ctxt, list); + if (ret == 0) { + } + break; + } + + list = define->content; + oldflags = ctxt->flags; + ctxt->flags |= FLAGS_IGNORABLE; + + while (list != NULL) { + oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state); + ret = xmlRelaxNGValidateDefinition(ctxt, list); + if (ret == 0) { + if (states == NULL) { + states = xmlRelaxNGNewStates(ctxt, 1); + } + if (ctxt->state != NULL) { + xmlRelaxNGAddStates(ctxt, states, ctxt->state); + } else if (ctxt->states != NULL) { + for (i = 0; i < ctxt->states->nbState; i++) { + xmlRelaxNGAddStates(ctxt, states, + ctxt->states-> + tabState[i]); + } + xmlRelaxNGFreeStates(ctxt, ctxt->states); + ctxt->states = NULL; + } + } else { + xmlRelaxNGFreeValidState(ctxt, ctxt->state); + } + ctxt->state = oldstate; + list = list->next; + } + if (states != NULL) { + xmlRelaxNGFreeValidState(ctxt, oldstate); + ctxt->states = states; + ctxt->state = NULL; + ret = 0; + } else { + ctxt->states = NULL; + } + ctxt->flags = oldflags; + if (ret != 0) { + if ((ctxt->flags & FLAGS_IGNORABLE) == 0) { + xmlRelaxNGDumpValidError(ctxt); + } + } else { + if (ctxt->errNr > errNr) + xmlRelaxNGPopErrors(ctxt, errNr); + } + break; + } + case XML_RELAXNG_DEF: + case XML_RELAXNG_GROUP: + ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content); + break; + case XML_RELAXNG_INTERLEAVE: + ret = xmlRelaxNGValidateInterleave(ctxt, define); + break; + case XML_RELAXNG_ATTRIBUTE: + ret = xmlRelaxNGValidateAttribute(ctxt, define); + break; + case XML_RELAXNG_START: + case XML_RELAXNG_NOOP: + case XML_RELAXNG_REF: + case XML_RELAXNG_EXTERNALREF: + case XML_RELAXNG_PARENTREF: + ret = xmlRelaxNGValidateDefinition(ctxt, define->content); + break; + case XML_RELAXNG_DATATYPE:{ + xmlNodePtr child; + xmlChar *content = NULL; + + child = node; + while (child != NULL) { + if (child->type == XML_ELEMENT_NODE) { + VALID_ERR2(XML_RELAXNG_ERR_DATAELEM, + node->parent->name); + ret = -1; + break; + } else if ((child->type == XML_TEXT_NODE) || + (child->type == XML_CDATA_SECTION_NODE)) { + content = xmlStrcat(content, child->content); + } + /* TODO: handle entities ... */ + child = child->next; + } + if (ret == -1) { + if (content != NULL) + xmlFree(content); + break; + } + if (content == NULL) { + content = xmlStrdup(BAD_CAST ""); + if (content == NULL) { + xmlRngVErrMemory(ctxt, "validating\n"); + ret = -1; + break; + } + } + ret = xmlRelaxNGValidateDatatype(ctxt, content, define, + ctxt->state->seq); + if (ret == -1) { + VALID_ERR2(XML_RELAXNG_ERR_DATATYPE, define->name); + } else if (ret == 0) { + ctxt->state->seq = NULL; + } + if (content != NULL) + xmlFree(content); + break; + } + case XML_RELAXNG_VALUE:{ + xmlChar *content = NULL; + xmlChar *oldvalue; + xmlNodePtr child; + + child = node; + while (child != NULL) { + if (child->type == XML_ELEMENT_NODE) { + VALID_ERR2(XML_RELAXNG_ERR_VALELEM, + node->parent->name); + ret = -1; + break; + } else if ((child->type == XML_TEXT_NODE) || + (child->type == XML_CDATA_SECTION_NODE)) { + content = xmlStrcat(content, child->content); + } + /* TODO: handle entities ... */ + child = child->next; + } + if (ret == -1) { + if (content != NULL) + xmlFree(content); + break; + } + if (content == NULL) { + content = xmlStrdup(BAD_CAST ""); + if (content == NULL) { + xmlRngVErrMemory(ctxt, "validating\n"); + ret = -1; + break; + } + } + oldvalue = ctxt->state->value; + ctxt->state->value = content; + ret = xmlRelaxNGValidateValue(ctxt, define); + ctxt->state->value = oldvalue; + if (ret == -1) { + VALID_ERR2(XML_RELAXNG_ERR_VALUE, define->name); + } else if (ret == 0) { + ctxt->state->seq = NULL; + } + if (content != NULL) + xmlFree(content); + break; + } + case XML_RELAXNG_LIST:{ + xmlChar *content; + xmlNodePtr child; + xmlChar *oldvalue, *oldendvalue; + int len; + + /* + * Make sure it's only text nodes + */ + + content = NULL; + child = node; + while (child != NULL) { + if (child->type == XML_ELEMENT_NODE) { + VALID_ERR2(XML_RELAXNG_ERR_LISTELEM, + node->parent->name); + ret = -1; + break; + } else if ((child->type == XML_TEXT_NODE) || + (child->type == XML_CDATA_SECTION_NODE)) { + content = xmlStrcat(content, child->content); + } + /* TODO: handle entities ... */ + child = child->next; + } + if (ret == -1) { + if (content != NULL) + xmlFree(content); + break; + } + if (content == NULL) { + content = xmlStrdup(BAD_CAST ""); + if (content == NULL) { + xmlRngVErrMemory(ctxt, "validating\n"); + ret = -1; + break; + } + } + len = xmlStrlen(content); + oldvalue = ctxt->state->value; + oldendvalue = ctxt->state->endvalue; + ctxt->state->value = content; + ctxt->state->endvalue = content + len; + ret = xmlRelaxNGValidateValue(ctxt, define); + ctxt->state->value = oldvalue; + ctxt->state->endvalue = oldendvalue; + if (ret == -1) { + VALID_ERR(XML_RELAXNG_ERR_LIST); + } else if ((ret == 0) && (node != NULL)) { + ctxt->state->seq = node->next; + } + if (content != NULL) + xmlFree(content); + break; + } + case XML_RELAXNG_EXCEPT: + case XML_RELAXNG_PARAM: + TODO ret = -1; + break; + } + ctxt->depth--; +#ifdef DEBUG + for (i = 0; i < ctxt->depth; i++) + xmlGenericError(xmlGenericErrorContext, " "); + xmlGenericError(xmlGenericErrorContext, + "Validating %s ", xmlRelaxNGDefName(define)); + if (define->name != NULL) + xmlGenericError(xmlGenericErrorContext, "%s ", define->name); + if (ret == 0) + xmlGenericError(xmlGenericErrorContext, "suceeded\n"); + else + xmlGenericError(xmlGenericErrorContext, "failed\n"); +#endif + return (ret); +} + +/** + * xmlRelaxNGValidateDefinition: + * @ctxt: a Relax-NG validation context + * @define: the definition to verify + * + * Validate the current node lists against the definition + * + * Returns 0 if the validation succeeded or an error code. + */ +static int +xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt, + xmlRelaxNGDefinePtr define) +{ + xmlRelaxNGStatesPtr states, res; + int i, j, k, ret, oldflags; + + /* + * We should NOT have both ctxt->state and ctxt->states + */ + if ((ctxt->state != NULL) && (ctxt->states != NULL)) { + TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state); + ctxt->state = NULL; + } + + if ((ctxt->states == NULL) || (ctxt->states->nbState == 1)) { + if (ctxt->states != NULL) { + ctxt->state = ctxt->states->tabState[0]; + xmlRelaxNGFreeStates(ctxt, ctxt->states); + ctxt->states = NULL; + } + ret = xmlRelaxNGValidateState(ctxt, define); + if ((ctxt->state != NULL) && (ctxt->states != NULL)) { + TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state); + ctxt->state = NULL; + } + if ((ctxt->states != NULL) && (ctxt->states->nbState == 1)) { + ctxt->state = ctxt->states->tabState[0]; + xmlRelaxNGFreeStates(ctxt, ctxt->states); + ctxt->states = NULL; + } + return (ret); + } + + states = ctxt->states; + ctxt->states = NULL; + res = NULL; + j = 0; + oldflags = ctxt->flags; + ctxt->flags |= FLAGS_IGNORABLE; + for (i = 0; i < states->nbState; i++) { + ctxt->state = states->tabState[i]; + ctxt->states = NULL; + ret = xmlRelaxNGValidateState(ctxt, define); + /* + * We should NOT have both ctxt->state and ctxt->states + */ + if ((ctxt->state != NULL) && (ctxt->states != NULL)) { + TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state); + ctxt->state = NULL; + } + if (ret == 0) { + if (ctxt->states == NULL) { + if (res != NULL) { + /* add the state to the container */ + xmlRelaxNGAddStates(ctxt, res, ctxt->state); + ctxt->state = NULL; + } else { + /* add the state directly in states */ + states->tabState[j++] = ctxt->state; + ctxt->state = NULL; + } + } else { + if (res == NULL) { + /* make it the new container and copy other results */ + res = ctxt->states; + ctxt->states = NULL; + for (k = 0; k < j; k++) + xmlRelaxNGAddStates(ctxt, res, + states->tabState[k]); + } else { + /* add all the new results to res and reff the container */ + for (k = 0; k < ctxt->states->nbState; k++) + xmlRelaxNGAddStates(ctxt, res, + ctxt->states->tabState[k]); + xmlRelaxNGFreeStates(ctxt, ctxt->states); + ctxt->states = NULL; + } + } + } else { + if (ctxt->state != NULL) { + xmlRelaxNGFreeValidState(ctxt, ctxt->state); + ctxt->state = NULL; + } else if (ctxt->states != NULL) { + for (k = 0; k < ctxt->states->nbState; k++) + xmlRelaxNGFreeValidState(ctxt, + ctxt->states->tabState[k]); + xmlRelaxNGFreeStates(ctxt, ctxt->states); + ctxt->states = NULL; + } + } + } + ctxt->flags = oldflags; + if (res != NULL) { + xmlRelaxNGFreeStates(ctxt, states); + ctxt->states = res; + ret = 0; + } else if (j > 1) { + states->nbState = j; + ctxt->states = states; + ret = 0; + } else if (j == 1) { + ctxt->state = states->tabState[0]; + xmlRelaxNGFreeStates(ctxt, states); + ret = 0; + } else { + ret = -1; + xmlRelaxNGFreeStates(ctxt, states); + if (ctxt->states != NULL) { + xmlRelaxNGFreeStates(ctxt, ctxt->states); + ctxt->states = NULL; + } + } + if ((ctxt->state != NULL) && (ctxt->states != NULL)) { + TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state); + ctxt->state = NULL; + } + return (ret); +} + +/** + * xmlRelaxNGValidateDocument: + * @ctxt: a Relax-NG validation context + * @doc: the document + * + * Validate the given document + * + * Returns 0 if the validation succeeded or an error code. + */ +static int +xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) +{ + int ret; + xmlRelaxNGPtr schema; + xmlRelaxNGGrammarPtr grammar; + xmlRelaxNGValidStatePtr state; + xmlNodePtr node; + + if ((ctxt == NULL) || (ctxt->schema == NULL) || (doc == NULL)) + return (-1); + + ctxt->errNo = XML_RELAXNG_OK; + schema = ctxt->schema; + grammar = schema->topgrammar; + if (grammar == NULL) { + VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR); + return (-1); + } + state = xmlRelaxNGNewValidState(ctxt, NULL); + ctxt->state = state; + ret = xmlRelaxNGValidateDefinition(ctxt, grammar->start); + if ((ctxt->state != NULL) && (state->seq != NULL)) { + state = ctxt->state; + node = state->seq; + node = xmlRelaxNGSkipIgnored(ctxt, node); + if (node != NULL) { + if (ret != -1) { + VALID_ERR(XML_RELAXNG_ERR_EXTRADATA); + ret = -1; + } + } + } else if (ctxt->states != NULL) { + int i; + int tmp = -1; + + for (i = 0; i < ctxt->states->nbState; i++) { + state = ctxt->states->tabState[i]; + node = state->seq; + node = xmlRelaxNGSkipIgnored(ctxt, node); + if (node == NULL) + tmp = 0; + xmlRelaxNGFreeValidState(ctxt, state); + } + if (tmp == -1) { + if (ret != -1) { + VALID_ERR(XML_RELAXNG_ERR_EXTRADATA); + ret = -1; + } + } + } + if (ctxt->state != NULL) { + xmlRelaxNGFreeValidState(ctxt, ctxt->state); + ctxt->state = NULL; + } + if (ret != 0) + xmlRelaxNGDumpValidError(ctxt); +#ifdef DEBUG + else if (ctxt->errNr != 0) { + ctxt->error(ctxt->userData, + "%d Extra error messages left on stack !\n", + ctxt->errNr); + xmlRelaxNGDumpValidError(ctxt); + } +#endif +#ifdef LIBXML_VALID_ENABLED + if (ctxt->idref == 1) { + xmlValidCtxt vctxt; + + memset(&vctxt, 0, sizeof(xmlValidCtxt)); + vctxt.valid = 1; + vctxt.error = ctxt->error; + vctxt.warning = ctxt->warning; + vctxt.userData = ctxt->userData; + + if (xmlValidateDocumentFinal(&vctxt, doc) != 1) + ret = -1; + } +#endif /* LIBXML_VALID_ENABLED */ + if ((ret == 0) && (ctxt->errNo != XML_RELAXNG_OK)) + ret = -1; + + return (ret); +} + +/** + * xmlRelaxNGCleanPSVI: + * @node: an input element or document + * + * Call this routine to speed up XPath computation on static documents. + * This stamps all the element nodes with the document order + * Like for line information, the order is kept in the element->content + * field, the value stored is actually - the node number (starting at -1) + * to be able to differentiate from line numbers. + * + * Returns the number of elements found in the document or -1 in case + * of error. + */ +static void +xmlRelaxNGCleanPSVI(xmlNodePtr node) { + xmlNodePtr cur; + + if ((node == NULL) || + ((node->type != XML_ELEMENT_NODE) && + (node->type != XML_DOCUMENT_NODE) && + (node->type != XML_HTML_DOCUMENT_NODE))) + return; + if (node->type == XML_ELEMENT_NODE) + node->psvi = NULL; + + cur = node->children; + while (cur != NULL) { + if (cur->type == XML_ELEMENT_NODE) { + cur->psvi = NULL; + if (cur->children != NULL) { + cur = cur->children; + continue; + } + } + if (cur->next != NULL) { + cur = cur->next; + continue; + } + do { + cur = cur->parent; + if (cur == NULL) + break; + if (cur == node) { + cur = NULL; + break; + } + if (cur->next != NULL) { + cur = cur->next; + break; + } + } while (cur != NULL); + } + return; +} +/************************************************************************ + * * + * Validation interfaces * + * * + ************************************************************************/ + +/** + * xmlRelaxNGNewValidCtxt: + * @schema: a precompiled XML RelaxNGs + * + * Create an XML RelaxNGs validation context based on the given schema + * + * Returns the validation context or NULL in case of error + */ +xmlRelaxNGValidCtxtPtr +xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema) +{ + xmlRelaxNGValidCtxtPtr ret; + + ret = (xmlRelaxNGValidCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGValidCtxt)); + if (ret == NULL) { + xmlRngVErrMemory(NULL, "building context\n"); + 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; + ret->errTab = NULL; + if (schema != NULL) + ret->idref = schema->idref; + ret->states = NULL; + ret->freeState = NULL; + ret->freeStates = NULL; + ret->errNo = XML_RELAXNG_OK; + return (ret); +} + +/** + * xmlRelaxNGFreeValidCtxt: + * @ctxt: the schema validation context + * + * Free the resources associated to the schema validation context + */ +void +xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt) +{ + int k; + + if (ctxt == NULL) + return; + if (ctxt->states != NULL) + xmlRelaxNGFreeStates(NULL, ctxt->states); + if (ctxt->freeState != NULL) { + for (k = 0; k < ctxt->freeState->nbState; k++) { + xmlRelaxNGFreeValidState(NULL, ctxt->freeState->tabState[k]); + } + xmlRelaxNGFreeStates(NULL, ctxt->freeState); + } + if (ctxt->freeStates != NULL) { + for (k = 0; k < ctxt->freeStatesNr; k++) { + xmlRelaxNGFreeStates(NULL, ctxt->freeStates[k]); + } + xmlFree(ctxt->freeStates); + } + if (ctxt->errTab != NULL) + xmlFree(ctxt->errTab); + if (ctxt->elemTab != NULL) { + xmlRegExecCtxtPtr exec; + + exec = xmlRelaxNGElemPop(ctxt); + while (exec != NULL) { + xmlRegFreeExecCtxt(exec); + exec = xmlRelaxNGElemPop(ctxt); + } + xmlFree(ctxt->elemTab); + } + xmlFree(ctxt); +} + +/** + * xmlRelaxNGSetValidErrors: + * @ctxt: a Relax-NG validation context + * @err: the error function + * @warn: the warning function + * @ctx: the functions context + * + * Set the error and warning callback informations + */ +void +xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt, + xmlRelaxNGValidityErrorFunc err, + xmlRelaxNGValidityWarningFunc warn, void *ctx) +{ + if (ctxt == NULL) + return; + ctxt->error = err; + ctxt->warning = warn; + ctxt->userData = ctx; + ctxt->serror = NULL; +} + +/** + * xmlRelaxNGSetValidStructuredErrors: + * @ctxt: a Relax-NG validation context + * @serror: the structured error function + * @ctx: the functions context + * + * Set the structured error callback + */ +void +xmlRelaxNGSetValidStructuredErrors(xmlRelaxNGValidCtxtPtr ctxt, + xmlStructuredErrorFunc serror, void *ctx) +{ + if (ctxt == NULL) + return; + ctxt->serror = serror; + ctxt->error = NULL; + ctxt->warning = NULL; + ctxt->userData = ctx; +} + +/** + * xmlRelaxNGGetValidErrors: + * @ctxt: a Relax-NG validation context + * @err: the error function result + * @warn: the warning function result + * @ctx: the functions context result + * + * Get the error and warning callback informations + * + * Returns -1 in case of error and 0 otherwise + */ +int +xmlRelaxNGGetValidErrors(xmlRelaxNGValidCtxtPtr ctxt, + xmlRelaxNGValidityErrorFunc * err, + xmlRelaxNGValidityWarningFunc * warn, void **ctx) +{ + if (ctxt == NULL) + return (-1); + if (err != NULL) + *err = ctxt->error; + if (warn != NULL) + *warn = ctxt->warning; + if (ctx != NULL) + *ctx = ctxt->userData; + return (0); +} + +/** + * xmlRelaxNGValidateDoc: + * @ctxt: a Relax-NG validation context + * @doc: a parsed document tree + * + * Validate a document tree in memory. + * + * Returns 0 if the document is valid, a positive error code + * number otherwise and -1 in case of internal or API error. + */ +int +xmlRelaxNGValidateDoc(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) +{ + int ret; + + if ((ctxt == NULL) || (doc == NULL)) + return (-1); + + ctxt->doc = doc; + + ret = xmlRelaxNGValidateDocument(ctxt, doc); + /* + * Remove all left PSVI + */ + xmlRelaxNGCleanPSVI((xmlNodePtr) doc); + + /* + * TODO: build error codes + */ + if (ret == -1) + return (1); + return (ret); +} + +#define bottom_relaxng +#include "elfgcchack.h" +#endif /* LIBXML_SCHEMAS_ENABLED */ diff --git a/android/native/libxml2/schematron.c b/android/native/libxml2/schematron.c new file mode 100644 index 0000000000..07709e2440 --- /dev/null +++ b/android/native/libxml2/schematron.c @@ -0,0 +1,1785 @@ +/* + * schematron.c : implementation of the Schematron schema validity checking + * + * See Copyright for the status of this software. + * + * Daniel Veillard + */ + +/* + * TODO: + * + double check the semantic, especially + * - multiple rules applying in a single pattern/node + * - the semantic of libxml2 patterns vs. XSLT production referenced + * by the spec. + * + export of results in SVRL + * + full parsing and coverage of the spec, conformance of the input to the + * spec + * + divergences between the draft and the ISO proposed standard :-( + * + hook and test include + * + try and compare with the XSLT version + */ + +#define IN_LIBXML +#include "libxml.h" + +#ifdef LIBXML_SCHEMATRON_ENABLED + +#include +#include +#include +#include +#include +#include +#include +#include + +#define SCHEMATRON_PARSE_OPTIONS XML_PARSE_NOENT + +#define SCT_OLD_NS BAD_CAST "http://www.ascc.net/xml/schematron" + +#define XML_SCHEMATRON_NS BAD_CAST "http://purl.oclc.org/dsdl/schematron" + + +static const xmlChar *xmlSchematronNs = XML_SCHEMATRON_NS; +static const xmlChar *xmlOldSchematronNs = SCT_OLD_NS; + +#define IS_SCHEMATRON(node, elem) \ + ((node != NULL) && (node->type == XML_ELEMENT_NODE ) && \ + (node->ns != NULL) && \ + (xmlStrEqual(node->name, (const xmlChar *) elem)) && \ + ((xmlStrEqual(node->ns->href, xmlSchematronNs)) || \ + (xmlStrEqual(node->ns->href, xmlOldSchematronNs)))) + +#define NEXT_SCHEMATRON(node) \ + while (node != NULL) { \ + if ((node->type == XML_ELEMENT_NODE ) && (node->ns != NULL) && \ + ((xmlStrEqual(node->ns->href, xmlSchematronNs)) || \ + (xmlStrEqual(node->ns->href, xmlOldSchematronNs)))) \ + break; \ + node = node->next; \ + } + +/** + * TODO: + * + * macro to flag unimplemented blocks + */ +#define TODO \ + xmlGenericError(xmlGenericErrorContext, \ + "Unimplemented block at %s:%d\n", \ + __FILE__, __LINE__); + +typedef enum { + XML_SCHEMATRON_ASSERT=1, + XML_SCHEMATRON_REPORT=2 +} xmlSchematronTestType; + +/** + * _xmlSchematronTest: + * + * A Schematrons test, either an assert or a report + */ +typedef struct _xmlSchematronTest xmlSchematronTest; +typedef xmlSchematronTest *xmlSchematronTestPtr; +struct _xmlSchematronTest { + xmlSchematronTestPtr next; /* the next test in the list */ + xmlSchematronTestType type; /* the test type */ + xmlNodePtr node; /* the node in the tree */ + xmlChar *test; /* the expression to test */ + xmlXPathCompExprPtr comp; /* the compiled expression */ + xmlChar *report; /* the message to report */ +}; + +/** + * _xmlSchematronRule: + * + * A Schematrons rule + */ +typedef struct _xmlSchematronRule xmlSchematronRule; +typedef xmlSchematronRule *xmlSchematronRulePtr; +struct _xmlSchematronRule { + xmlSchematronRulePtr next; /* the next rule in the list */ + xmlSchematronRulePtr patnext;/* the next rule in the pattern list */ + xmlNodePtr node; /* the node in the tree */ + xmlChar *context; /* the context evaluation rule */ + xmlSchematronTestPtr tests; /* the list of tests */ + xmlPatternPtr pattern; /* the compiled pattern associated */ + xmlChar *report; /* the message to report */ +}; + +/** + * _xmlSchematronPattern: + * + * A Schematrons pattern + */ +typedef struct _xmlSchematronPattern xmlSchematronPattern; +typedef xmlSchematronPattern *xmlSchematronPatternPtr; +struct _xmlSchematronPattern { + xmlSchematronPatternPtr next;/* the next pattern in the list */ + xmlSchematronRulePtr rules; /* the list of rules */ + xmlChar *name; /* the name of the pattern */ +}; + +/** + * _xmlSchematron: + * + * A Schematrons definition + */ +struct _xmlSchematron { + const xmlChar *name; /* schema name */ + int preserve; /* was the document passed by the user */ + xmlDocPtr doc; /* pointer to the parsed document */ + int flags; /* specific to this schematron */ + + void *_private; /* unused by the library */ + xmlDictPtr dict; /* the dictionnary used internally */ + + const xmlChar *title; /* the title if any */ + + int nbNs; /* the number of namespaces */ + + int nbPattern; /* the number of patterns */ + xmlSchematronPatternPtr patterns;/* the patterns found */ + xmlSchematronRulePtr rules; /* the rules gathered */ + int nbNamespaces; /* number of namespaces in the array */ + int maxNamespaces; /* size of the array */ + const xmlChar **namespaces; /* the array of namespaces */ +}; + +/** + * xmlSchematronValidCtxt: + * + * A Schematrons validation context + */ +struct _xmlSchematronValidCtxt { + int type; + int flags; /* an or of xmlSchematronValidOptions */ + + xmlDictPtr dict; + int nberrors; + int err; + + xmlSchematronPtr schema; + xmlXPathContextPtr xctxt; + + FILE *outputFile; /* if using XML_SCHEMATRON_OUT_FILE */ + xmlBufferPtr outputBuffer; /* if using XML_SCHEMATRON_OUT_BUFFER */ + xmlOutputWriteCallback iowrite; /* if using XML_SCHEMATRON_OUT_IO */ + xmlOutputCloseCallback ioclose; + void *ioctx; + + /* error reporting data */ + void *userData; /* user specific data block */ + xmlSchematronValidityErrorFunc error;/* the callback in case of errors */ + xmlSchematronValidityWarningFunc warning;/* callback in case of warning */ + xmlStructuredErrorFunc serror; /* the structured function */ +}; + +struct _xmlSchematronParserCtxt { + int type; + const xmlChar *URL; + xmlDocPtr doc; + int preserve; /* Whether the doc should be freed */ + const char *buffer; + int size; + + xmlDictPtr dict; /* dictionnary for interned string names */ + + int nberrors; + int err; + xmlXPathContextPtr xctxt; /* the XPath context used for compilation */ + xmlSchematronPtr schema; + + int nbNamespaces; /* number of namespaces in the array */ + int maxNamespaces; /* size of the array */ + const xmlChar **namespaces; /* the array of namespaces */ + + int nbIncludes; /* number of includes in the array */ + int maxIncludes; /* size of the array */ + xmlNodePtr *includes; /* the array of includes */ + + /* error reporting data */ + void *userData; /* user specific data block */ + xmlSchematronValidityErrorFunc error;/* the callback in case of errors */ + xmlSchematronValidityWarningFunc warning;/* callback in case of warning */ + xmlStructuredErrorFunc serror; /* the structured function */ +}; + +#define XML_STRON_CTXT_PARSER 1 +#define XML_STRON_CTXT_VALIDATOR 2 + +/************************************************************************ + * * + * Error reporting * + * * + ************************************************************************/ + +/** + * xmlSchematronPErrMemory: + * @node: a context node + * @extra: extra informations + * + * Handle an out of memory condition + */ +static void +xmlSchematronPErrMemory(xmlSchematronParserCtxtPtr ctxt, + const char *extra, xmlNodePtr node) +{ + if (ctxt != NULL) + ctxt->nberrors++; + __xmlSimpleError(XML_FROM_SCHEMASP, XML_ERR_NO_MEMORY, node, NULL, + extra); +} + +/** + * xmlSchematronPErr: + * @ctxt: the parsing context + * @node: the context node + * @error: the error code + * @msg: the error message + * @str1: extra data + * @str2: extra data + * + * Handle a parser error + */ +static void +xmlSchematronPErr(xmlSchematronParserCtxtPtr ctxt, xmlNodePtr node, int error, + const char *msg, const xmlChar * str1, const xmlChar * str2) +{ + xmlGenericErrorFunc channel = NULL; + xmlStructuredErrorFunc schannel = NULL; + void *data = NULL; + + if (ctxt != NULL) { + ctxt->nberrors++; + channel = ctxt->error; + data = ctxt->userData; + 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); +} + +/** + * xmlSchematronVTypeErrMemory: + * @node: a context node + * @extra: extra informations + * + * Handle an out of memory condition + */ +static void +xmlSchematronVErrMemory(xmlSchematronValidCtxtPtr ctxt, + const char *extra, xmlNodePtr node) +{ + if (ctxt != NULL) { + ctxt->nberrors++; + ctxt->err = XML_SCHEMAV_INTERNAL; + } + __xmlSimpleError(XML_FROM_SCHEMASV, XML_ERR_NO_MEMORY, node, NULL, + extra); +} + +/************************************************************************ + * * + * Parsing and compilation of the Schematrontrons * + * * + ************************************************************************/ + +/** + * xmlSchematronAddTest: + * @ctxt: the schema parsing context + * @type: the type of test + * @rule: the parent rule + * @node: the node hosting the test + * @test: the associated test + * @report: the associated report string + * + * Add a test to a schematron + * + * Returns the new pointer or NULL in case of error + */ +static xmlSchematronTestPtr +xmlSchematronAddTest(xmlSchematronParserCtxtPtr ctxt, + xmlSchematronTestType type, + xmlSchematronRulePtr rule, + xmlNodePtr node, xmlChar *test, xmlChar *report) +{ + xmlSchematronTestPtr ret; + xmlXPathCompExprPtr comp; + + if ((ctxt == NULL) || (rule == NULL) || (node == NULL) || + (test == NULL)) + return(NULL); + + /* + * try first to compile the test expression + */ + comp = xmlXPathCtxtCompile(ctxt->xctxt, test); + if (comp == NULL) { + xmlSchematronPErr(ctxt, node, + XML_SCHEMAP_NOROOT, + "Failed to compile test expression %s", + test, NULL); + return(NULL); + } + + ret = (xmlSchematronTestPtr) xmlMalloc(sizeof(xmlSchematronTest)); + if (ret == NULL) { + xmlSchematronPErrMemory(ctxt, "allocating schema test", node); + return (NULL); + } + memset(ret, 0, sizeof(xmlSchematronTest)); + ret->type = type; + ret->node = node; + ret->test = test; + ret->comp = comp; + ret->report = report; + ret->next = NULL; + if (rule->tests == NULL) { + rule->tests = ret; + } else { + xmlSchematronTestPtr prev = rule->tests; + + while (prev->next != NULL) + prev = prev->next; + prev->next = ret; + } + return (ret); +} + +/** + * xmlSchematronFreeTests: + * @tests: a list of tests + * + * Free a list of tests. + */ +static void +xmlSchematronFreeTests(xmlSchematronTestPtr tests) { + xmlSchematronTestPtr next; + + while (tests != NULL) { + next = tests->next; + if (tests->test != NULL) + xmlFree(tests->test); + if (tests->comp != NULL) + xmlXPathFreeCompExpr(tests->comp); + if (tests->report != NULL) + xmlFree(tests->report); + xmlFree(tests); + tests = next; + } +} + +/** + * xmlSchematronAddRule: + * @ctxt: the schema parsing context + * @schema: a schema structure + * @node: the node hosting the rule + * @context: the associated context string + * @report: the associated report string + * + * Add a rule to a schematron + * + * Returns the new pointer or NULL in case of error + */ +static xmlSchematronRulePtr +xmlSchematronAddRule(xmlSchematronParserCtxtPtr ctxt, xmlSchematronPtr schema, + xmlSchematronPatternPtr pat, xmlNodePtr node, + xmlChar *context, xmlChar *report) +{ + xmlSchematronRulePtr ret; + xmlPatternPtr pattern; + + if ((ctxt == NULL) || (schema == NULL) || (node == NULL) || + (context == NULL)) + return(NULL); + + /* + * Try first to compile the pattern + */ + pattern = xmlPatterncompile(context, ctxt->dict, XML_PATTERN_XPATH, + ctxt->namespaces); + if (pattern == NULL) { + xmlSchematronPErr(ctxt, node, + XML_SCHEMAP_NOROOT, + "Failed to compile context expression %s", + context, NULL); + } + + ret = (xmlSchematronRulePtr) xmlMalloc(sizeof(xmlSchematronRule)); + if (ret == NULL) { + xmlSchematronPErrMemory(ctxt, "allocating schema rule", node); + return (NULL); + } + memset(ret, 0, sizeof(xmlSchematronRule)); + ret->node = node; + ret->context = context; + ret->pattern = pattern; + ret->report = report; + ret->next = NULL; + if (schema->rules == NULL) { + schema->rules = ret; + } else { + xmlSchematronRulePtr prev = schema->rules; + + while (prev->next != NULL) + prev = prev->next; + prev->next = ret; + } + ret->patnext = NULL; + if (pat->rules == NULL) { + pat->rules = ret; + } else { + xmlSchematronRulePtr prev = pat->rules; + + while (prev->patnext != NULL) + prev = prev->patnext; + prev->patnext = ret; + } + return (ret); +} + +/** + * xmlSchematronFreeRules: + * @rules: a list of rules + * + * Free a list of rules. + */ +static void +xmlSchematronFreeRules(xmlSchematronRulePtr rules) { + xmlSchematronRulePtr next; + + while (rules != NULL) { + next = rules->next; + if (rules->tests) + xmlSchematronFreeTests(rules->tests); + if (rules->context != NULL) + xmlFree(rules->context); + if (rules->pattern) + xmlFreePattern(rules->pattern); + if (rules->report != NULL) + xmlFree(rules->report); + xmlFree(rules); + rules = next; + } +} + +/** + * xmlSchematronAddPattern: + * @ctxt: the schema parsing context + * @schema: a schema structure + * @node: the node hosting the pattern + * @id: the id or name of the pattern + * + * Add a pattern to a schematron + * + * Returns the new pointer or NULL in case of error + */ +static xmlSchematronPatternPtr +xmlSchematronAddPattern(xmlSchematronParserCtxtPtr ctxt, + xmlSchematronPtr schema, xmlNodePtr node, xmlChar *name) +{ + xmlSchematronPatternPtr ret; + + if ((ctxt == NULL) || (schema == NULL) || (node == NULL) || (name == NULL)) + return(NULL); + + ret = (xmlSchematronPatternPtr) xmlMalloc(sizeof(xmlSchematronPattern)); + if (ret == NULL) { + xmlSchematronPErrMemory(ctxt, "allocating schema pattern", node); + return (NULL); + } + memset(ret, 0, sizeof(xmlSchematronPattern)); + ret->name = name; + ret->next = NULL; + if (schema->patterns == NULL) { + schema->patterns = ret; + } else { + xmlSchematronPatternPtr prev = schema->patterns; + + while (prev->next != NULL) + prev = prev->next; + prev->next = ret; + } + return (ret); +} + +/** + * xmlSchematronFreePatterns: + * @patterns: a list of patterns + * + * Free a list of patterns. + */ +static void +xmlSchematronFreePatterns(xmlSchematronPatternPtr patterns) { + xmlSchematronPatternPtr next; + + while (patterns != NULL) { + next = patterns->next; + if (patterns->name != NULL) + xmlFree(patterns->name); + xmlFree(patterns); + patterns = next; + } +} + +/** + * xmlSchematronNewSchematron: + * @ctxt: a schema validation context + * + * Allocate a new Schematron structure. + * + * Returns the newly allocated structure or NULL in case or error + */ +static xmlSchematronPtr +xmlSchematronNewSchematron(xmlSchematronParserCtxtPtr ctxt) +{ + xmlSchematronPtr ret; + + ret = (xmlSchematronPtr) xmlMalloc(sizeof(xmlSchematron)); + if (ret == NULL) { + xmlSchematronPErrMemory(ctxt, "allocating schema", NULL); + return (NULL); + } + memset(ret, 0, sizeof(xmlSchematron)); + ret->dict = ctxt->dict; + xmlDictReference(ret->dict); + + return (ret); +} + +/** + * xmlSchematronFree: + * @schema: a schema structure + * + * Deallocate a Schematron structure. + */ +void +xmlSchematronFree(xmlSchematronPtr schema) +{ + if (schema == NULL) + return; + + if ((schema->doc != NULL) && (!(schema->preserve))) + xmlFreeDoc(schema->doc); + + if (schema->namespaces != NULL) + xmlFree((char **) schema->namespaces); + + xmlSchematronFreeRules(schema->rules); + xmlSchematronFreePatterns(schema->patterns); + xmlDictFree(schema->dict); + xmlFree(schema); +} + +/** + * xmlSchematronNewParserCtxt: + * @URL: the location of the schema + * + * Create an XML Schematrons parse context for that file/resource expected + * to contain an XML Schematrons file. + * + * Returns the parser context or NULL in case of error + */ +xmlSchematronParserCtxtPtr +xmlSchematronNewParserCtxt(const char *URL) +{ + xmlSchematronParserCtxtPtr ret; + + if (URL == NULL) + return (NULL); + + ret = + (xmlSchematronParserCtxtPtr) + xmlMalloc(sizeof(xmlSchematronParserCtxt)); + if (ret == NULL) { + xmlSchematronPErrMemory(NULL, "allocating schema parser context", + NULL); + return (NULL); + } + memset(ret, 0, sizeof(xmlSchematronParserCtxt)); + ret->type = XML_STRON_CTXT_PARSER; + ret->dict = xmlDictCreate(); + ret->URL = xmlDictLookup(ret->dict, (const xmlChar *) URL, -1); + ret->includes = NULL; + ret->xctxt = xmlXPathNewContext(NULL); + if (ret->xctxt == NULL) { + xmlSchematronPErrMemory(NULL, "allocating schema parser XPath context", + NULL); + xmlSchematronFreeParserCtxt(ret); + return (NULL); + } + ret->xctxt->flags = XML_XPATH_CHECKNS; + return (ret); +} + +/** + * xmlSchematronNewMemParserCtxt: + * @buffer: a pointer to a char array containing the schemas + * @size: the size of the array + * + * Create an XML Schematrons parse context for that memory buffer expected + * to contain an XML Schematrons file. + * + * Returns the parser context or NULL in case of error + */ +xmlSchematronParserCtxtPtr +xmlSchematronNewMemParserCtxt(const char *buffer, int size) +{ + xmlSchematronParserCtxtPtr ret; + + if ((buffer == NULL) || (size <= 0)) + return (NULL); + + ret = + (xmlSchematronParserCtxtPtr) + xmlMalloc(sizeof(xmlSchematronParserCtxt)); + if (ret == NULL) { + xmlSchematronPErrMemory(NULL, "allocating schema parser context", + NULL); + return (NULL); + } + memset(ret, 0, sizeof(xmlSchematronParserCtxt)); + ret->buffer = buffer; + ret->size = size; + ret->dict = xmlDictCreate(); + ret->xctxt = xmlXPathNewContext(NULL); + if (ret->xctxt == NULL) { + xmlSchematronPErrMemory(NULL, "allocating schema parser XPath context", + NULL); + xmlSchematronFreeParserCtxt(ret); + return (NULL); + } + return (ret); +} + +/** + * xmlSchematronNewDocParserCtxt: + * @doc: a preparsed document tree + * + * Create an XML Schematrons parse context for that document. + * NB. The document may be modified during the parsing process. + * + * Returns the parser context or NULL in case of error + */ +xmlSchematronParserCtxtPtr +xmlSchematronNewDocParserCtxt(xmlDocPtr doc) +{ + xmlSchematronParserCtxtPtr ret; + + if (doc == NULL) + return (NULL); + + ret = + (xmlSchematronParserCtxtPtr) + xmlMalloc(sizeof(xmlSchematronParserCtxt)); + if (ret == NULL) { + xmlSchematronPErrMemory(NULL, "allocating schema parser context", + NULL); + return (NULL); + } + memset(ret, 0, sizeof(xmlSchematronParserCtxt)); + ret->doc = doc; + ret->dict = xmlDictCreate(); + /* The application has responsibility for the document */ + ret->preserve = 1; + ret->xctxt = xmlXPathNewContext(doc); + if (ret->xctxt == NULL) { + xmlSchematronPErrMemory(NULL, "allocating schema parser XPath context", + NULL); + xmlSchematronFreeParserCtxt(ret); + return (NULL); + } + + return (ret); +} + +/** + * xmlSchematronFreeParserCtxt: + * @ctxt: the schema parser context + * + * Free the resources associated to the schema parser context + */ +void +xmlSchematronFreeParserCtxt(xmlSchematronParserCtxtPtr ctxt) +{ + if (ctxt == NULL) + return; + if (ctxt->doc != NULL && !ctxt->preserve) + xmlFreeDoc(ctxt->doc); + if (ctxt->xctxt != NULL) { + xmlXPathFreeContext(ctxt->xctxt); + } + if (ctxt->namespaces != NULL) + xmlFree((char **) ctxt->namespaces); + xmlDictFree(ctxt->dict); + xmlFree(ctxt); +} + +#if 0 +/** + * xmlSchematronPushInclude: + * @ctxt: the schema parser context + * @doc: the included document + * @cur: the current include node + * + * Add an included document + */ +static void +xmlSchematronPushInclude(xmlSchematronParserCtxtPtr ctxt, + xmlDocPtr doc, xmlNodePtr cur) +{ + if (ctxt->includes == NULL) { + ctxt->maxIncludes = 10; + ctxt->includes = (xmlNodePtr *) + xmlMalloc(ctxt->maxIncludes * 2 * sizeof(xmlNodePtr)); + if (ctxt->includes == NULL) { + xmlSchematronPErrMemory(NULL, "allocating parser includes", + NULL); + return; + } + ctxt->nbIncludes = 0; + } else if (ctxt->nbIncludes + 2 >= ctxt->maxIncludes) { + xmlNodePtr *tmp; + + tmp = (xmlNodePtr *) + xmlRealloc(ctxt->includes, ctxt->maxIncludes * 4 * + sizeof(xmlNodePtr)); + if (tmp == NULL) { + xmlSchematronPErrMemory(NULL, "allocating parser includes", + NULL); + return; + } + ctxt->includes = tmp; + ctxt->maxIncludes *= 2; + } + ctxt->includes[2 * ctxt->nbIncludes] = cur; + ctxt->includes[2 * ctxt->nbIncludes + 1] = (xmlNodePtr) doc; + ctxt->nbIncludes++; +} + +/** + * xmlSchematronPopInclude: + * @ctxt: the schema parser context + * + * Pop an include level. The included document is being freed + * + * Returns the node immediately following the include or NULL if the + * include list was empty. + */ +static xmlNodePtr +xmlSchematronPopInclude(xmlSchematronParserCtxtPtr ctxt) +{ + xmlDocPtr doc; + xmlNodePtr ret; + + if (ctxt->nbIncludes <= 0) + return(NULL); + ctxt->nbIncludes--; + doc = (xmlDocPtr) ctxt->includes[2 * ctxt->nbIncludes + 1]; + ret = ctxt->includes[2 * ctxt->nbIncludes]; + xmlFreeDoc(doc); + if (ret != NULL) + ret = ret->next; + if (ret == NULL) + return(xmlSchematronPopInclude(ctxt)); + return(ret); +} +#endif + +/** + * xmlSchematronAddNamespace: + * @ctxt: the schema parser context + * @prefix: the namespace prefix + * @ns: the namespace name + * + * Add a namespace definition in the context + */ +static void +xmlSchematronAddNamespace(xmlSchematronParserCtxtPtr ctxt, + const xmlChar *prefix, const xmlChar *ns) +{ + if (ctxt->namespaces == NULL) { + ctxt->maxNamespaces = 10; + ctxt->namespaces = (const xmlChar **) + xmlMalloc(ctxt->maxNamespaces * 2 * sizeof(const xmlChar *)); + if (ctxt->namespaces == NULL) { + xmlSchematronPErrMemory(NULL, "allocating parser namespaces", + NULL); + return; + } + ctxt->nbNamespaces = 0; + } else if (ctxt->nbNamespaces + 2 >= ctxt->maxNamespaces) { + const xmlChar **tmp; + + tmp = (const xmlChar **) + xmlRealloc((xmlChar **) ctxt->namespaces, ctxt->maxNamespaces * 4 * + sizeof(const xmlChar *)); + if (tmp == NULL) { + xmlSchematronPErrMemory(NULL, "allocating parser namespaces", + NULL); + return; + } + ctxt->namespaces = tmp; + ctxt->maxNamespaces *= 2; + } + ctxt->namespaces[2 * ctxt->nbNamespaces] = + xmlDictLookup(ctxt->dict, ns, -1); + ctxt->namespaces[2 * ctxt->nbNamespaces + 1] = + xmlDictLookup(ctxt->dict, prefix, -1); + ctxt->nbNamespaces++; + ctxt->namespaces[2 * ctxt->nbNamespaces] = NULL; + ctxt->namespaces[2 * ctxt->nbNamespaces + 1] = NULL; + +} + +/** + * xmlSchematronParseRule: + * @ctxt: a schema validation context + * @rule: the rule node + * + * parse a rule element + */ +static void +xmlSchematronParseRule(xmlSchematronParserCtxtPtr ctxt, + xmlSchematronPatternPtr pattern, + xmlNodePtr rule) +{ + xmlNodePtr cur; + int nbChecks = 0; + xmlChar *test; + xmlChar *context; + xmlChar *report; + xmlSchematronRulePtr ruleptr; + xmlSchematronTestPtr testptr; + + if ((ctxt == NULL) || (rule == NULL)) return; + + context = xmlGetNoNsProp(rule, BAD_CAST "context"); + if (context == NULL) { + xmlSchematronPErr(ctxt, rule, + XML_SCHEMAP_NOROOT, + "rule has no context attribute", + NULL, NULL); + return; + } else if (context[0] == 0) { + xmlSchematronPErr(ctxt, rule, + XML_SCHEMAP_NOROOT, + "rule has an empty context attribute", + NULL, NULL); + xmlFree(context); + return; + } else { + ruleptr = xmlSchematronAddRule(ctxt, ctxt->schema, pattern, + rule, context, NULL); + if (ruleptr == NULL) { + xmlFree(context); + return; + } + } + + cur = rule->children; + NEXT_SCHEMATRON(cur); + while (cur != NULL) { + if (IS_SCHEMATRON(cur, "assert")) { + nbChecks++; + test = xmlGetNoNsProp(cur, BAD_CAST "test"); + if (test == NULL) { + xmlSchematronPErr(ctxt, cur, + XML_SCHEMAP_NOROOT, + "assert has no test attribute", + NULL, NULL); + } else if (test[0] == 0) { + xmlSchematronPErr(ctxt, cur, + XML_SCHEMAP_NOROOT, + "assert has an empty test attribute", + NULL, NULL); + xmlFree(test); + } else { + /* TODO will need dynamic processing instead */ + report = xmlNodeGetContent(cur); + + testptr = xmlSchematronAddTest(ctxt, XML_SCHEMATRON_ASSERT, + ruleptr, cur, test, report); + if (testptr == NULL) + xmlFree(test); + } + } else if (IS_SCHEMATRON(cur, "report")) { + nbChecks++; + test = xmlGetNoNsProp(cur, BAD_CAST "test"); + if (test == NULL) { + xmlSchematronPErr(ctxt, cur, + XML_SCHEMAP_NOROOT, + "assert has no test attribute", + NULL, NULL); + } else if (test[0] == 0) { + xmlSchematronPErr(ctxt, cur, + XML_SCHEMAP_NOROOT, + "assert has an empty test attribute", + NULL, NULL); + xmlFree(test); + } else { + /* TODO will need dynamic processing instead */ + report = xmlNodeGetContent(cur); + + testptr = xmlSchematronAddTest(ctxt, XML_SCHEMATRON_REPORT, + ruleptr, cur, test, report); + if (testptr == NULL) + xmlFree(test); + } + } else { + xmlSchematronPErr(ctxt, cur, + XML_SCHEMAP_NOROOT, + "Expecting an assert or a report element instead of %s", + cur->name, NULL); + } + cur = cur->next; + NEXT_SCHEMATRON(cur); + } + if (nbChecks == 0) { + xmlSchematronPErr(ctxt, rule, + XML_SCHEMAP_NOROOT, + "rule has no assert nor report element", NULL, NULL); + } +} + +/** + * xmlSchematronParsePattern: + * @ctxt: a schema validation context + * @pat: the pattern node + * + * parse a pattern element + */ +static void +xmlSchematronParsePattern(xmlSchematronParserCtxtPtr ctxt, xmlNodePtr pat) +{ + xmlNodePtr cur; + xmlSchematronPatternPtr pattern; + int nbRules = 0; + xmlChar *id; + + if ((ctxt == NULL) || (pat == NULL)) return; + + id = xmlGetNoNsProp(pat, BAD_CAST "id"); + if (id == NULL) { + id = xmlGetNoNsProp(pat, BAD_CAST "name"); + } + pattern = xmlSchematronAddPattern(ctxt, ctxt->schema, pat, id); + if (pattern == NULL) { + if (id != NULL) + xmlFree(id); + return; + } + cur = pat->children; + NEXT_SCHEMATRON(cur); + while (cur != NULL) { + if (IS_SCHEMATRON(cur, "rule")) { + xmlSchematronParseRule(ctxt, pattern, cur); + nbRules++; + } else { + xmlSchematronPErr(ctxt, cur, + XML_SCHEMAP_NOROOT, + "Expecting a rule element instead of %s", cur->name, NULL); + } + cur = cur->next; + NEXT_SCHEMATRON(cur); + } + if (nbRules == 0) { + xmlSchematronPErr(ctxt, pat, + XML_SCHEMAP_NOROOT, + "Pattern has no rule element", NULL, NULL); + } +} + +#if 0 +/** + * xmlSchematronLoadInclude: + * @ctxt: a schema validation context + * @cur: the include element + * + * Load the include document, Push the current pointer + * + * Returns the updated node pointer + */ +static xmlNodePtr +xmlSchematronLoadInclude(xmlSchematronParserCtxtPtr ctxt, xmlNodePtr cur) +{ + xmlNodePtr ret = NULL; + xmlDocPtr doc = NULL; + xmlChar *href = NULL; + xmlChar *base = NULL; + xmlChar *URI = NULL; + + if ((ctxt == NULL) || (cur == NULL)) + return(NULL); + + href = xmlGetNoNsProp(cur, BAD_CAST "href"); + if (href == NULL) { + xmlSchematronPErr(ctxt, cur, + XML_SCHEMAP_NOROOT, + "Include has no href attribute", NULL, NULL); + return(cur->next); + } + + /* do the URI base composition, load and find the root */ + base = xmlNodeGetBase(cur->doc, cur); + URI = xmlBuildURI(href, base); + doc = xmlReadFile((const char *) URI, NULL, SCHEMATRON_PARSE_OPTIONS); + if (doc == NULL) { + xmlSchematronPErr(ctxt, cur, + XML_SCHEMAP_FAILED_LOAD, + "could not load include '%s'.\n", + URI, NULL); + goto done; + } + ret = xmlDocGetRootElement(doc); + if (ret == NULL) { + xmlSchematronPErr(ctxt, cur, + XML_SCHEMAP_FAILED_LOAD, + "could not find root from include '%s'.\n", + URI, NULL); + goto done; + } + + /* Success, push the include for rollback on exit */ + xmlSchematronPushInclude(ctxt, doc, cur); + +done: + if (ret == NULL) { + if (doc != NULL) + xmlFreeDoc(doc); + } + xmlFree(href); + if (base != NULL) + xmlFree(base); + if (URI != NULL) + xmlFree(URI); + return(ret); +} +#endif + +/** + * xmlSchematronParse: + * @ctxt: a schema validation context + * + * parse a schema definition resource and build an internal + * XML Shema struture which can be used to validate instances. + * + * Returns the internal XML Schematron structure built from the resource or + * NULL in case of error + */ +xmlSchematronPtr +xmlSchematronParse(xmlSchematronParserCtxtPtr ctxt) +{ + xmlSchematronPtr ret = NULL; + xmlDocPtr doc; + xmlNodePtr root, cur; + int preserve = 0; + + if (ctxt == NULL) + return (NULL); + + ctxt->nberrors = 0; + + /* + * First step is to parse the input document into an DOM/Infoset + */ + if (ctxt->URL != NULL) { + doc = xmlReadFile((const char *) ctxt->URL, NULL, + SCHEMATRON_PARSE_OPTIONS); + if (doc == NULL) { + xmlSchematronPErr(ctxt, NULL, + XML_SCHEMAP_FAILED_LOAD, + "xmlSchematronParse: could not load '%s'.\n", + ctxt->URL, NULL); + return (NULL); + } + ctxt->preserve = 0; + } else if (ctxt->buffer != NULL) { + doc = xmlReadMemory(ctxt->buffer, ctxt->size, NULL, NULL, + SCHEMATRON_PARSE_OPTIONS); + if (doc == NULL) { + xmlSchematronPErr(ctxt, NULL, + XML_SCHEMAP_FAILED_PARSE, + "xmlSchematronParse: could not parse.\n", + NULL, NULL); + return (NULL); + } + doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer"); + ctxt->URL = xmlDictLookup(ctxt->dict, BAD_CAST "in_memory_buffer", -1); + ctxt->preserve = 0; + } else if (ctxt->doc != NULL) { + doc = ctxt->doc; + preserve = 1; + ctxt->preserve = 1; + } else { + xmlSchematronPErr(ctxt, NULL, + XML_SCHEMAP_NOTHING_TO_PARSE, + "xmlSchematronParse: could not parse.\n", + NULL, NULL); + return (NULL); + } + + /* + * Then extract the root and Schematron parse it + */ + root = xmlDocGetRootElement(doc); + if (root == NULL) { + xmlSchematronPErr(ctxt, (xmlNodePtr) doc, + XML_SCHEMAP_NOROOT, + "The schema has no document element.\n", NULL, NULL); + if (!preserve) { + xmlFreeDoc(doc); + } + return (NULL); + } + + if (!IS_SCHEMATRON(root, "schema")) { + xmlSchematronPErr(ctxt, root, + XML_SCHEMAP_NOROOT, + "The XML document '%s' is not a XML schematron document", + ctxt->URL, NULL); + goto exit; + } + ret = xmlSchematronNewSchematron(ctxt); + if (ret == NULL) + goto exit; + ctxt->schema = ret; + + /* + * scan the schema elements + */ + cur = root->children; + NEXT_SCHEMATRON(cur); + if (IS_SCHEMATRON(cur, "title")) { + xmlChar *title = xmlNodeGetContent(cur); + if (title != NULL) { + ret->title = xmlDictLookup(ret->dict, title, -1); + xmlFree(title); + } + cur = cur->next; + NEXT_SCHEMATRON(cur); + } + while (IS_SCHEMATRON(cur, "ns")) { + xmlChar *prefix = xmlGetNoNsProp(cur, BAD_CAST "prefix"); + xmlChar *uri = xmlGetNoNsProp(cur, BAD_CAST "uri"); + if ((uri == NULL) || (uri[0] == 0)) { + xmlSchematronPErr(ctxt, cur, + XML_SCHEMAP_NOROOT, + "ns element has no uri", NULL, NULL); + } + if ((prefix == NULL) || (prefix[0] == 0)) { + xmlSchematronPErr(ctxt, cur, + XML_SCHEMAP_NOROOT, + "ns element has no prefix", NULL, NULL); + } + if ((prefix) && (uri)) { + xmlXPathRegisterNs(ctxt->xctxt, prefix, uri); + xmlSchematronAddNamespace(ctxt, prefix, uri); + ret->nbNs++; + } + if (uri) + xmlFree(uri); + if (prefix) + xmlFree(prefix); + cur = cur->next; + NEXT_SCHEMATRON(cur); + } + while (cur != NULL) { + if (IS_SCHEMATRON(cur, "pattern")) { + xmlSchematronParsePattern(ctxt, cur); + ret->nbPattern++; + } else { + xmlSchematronPErr(ctxt, cur, + XML_SCHEMAP_NOROOT, + "Expecting a pattern element instead of %s", cur->name, NULL); + } + cur = cur->next; + NEXT_SCHEMATRON(cur); + } + if (ret->nbPattern == 0) { + xmlSchematronPErr(ctxt, root, + XML_SCHEMAP_NOROOT, + "The schematron document '%s' has no pattern", + ctxt->URL, NULL); + goto exit; + } + /* the original document must be kept for reporting */ + ret->doc = doc; + if (preserve) { + ret->preserve = 1; + } + preserve = 1; + +exit: + if (!preserve) { + xmlFreeDoc(doc); + } + if (ret != NULL) { + if (ctxt->nberrors != 0) { + xmlSchematronFree(ret); + ret = NULL; + } else { + ret->namespaces = ctxt->namespaces; + ret->nbNamespaces = ctxt->nbNamespaces; + ctxt->namespaces = NULL; + } + } + return (ret); +} + +/************************************************************************ + * * + * Schematrontron Reports handler * + * * + ************************************************************************/ + +static xmlNodePtr +xmlSchematronGetNode(xmlSchematronValidCtxtPtr ctxt, + xmlNodePtr cur, const xmlChar *xpath) { + xmlNodePtr node = NULL; + xmlXPathObjectPtr ret; + + if ((ctxt == NULL) || (cur == NULL) || (xpath == NULL)) + return(NULL); + + ctxt->xctxt->doc = cur->doc; + ctxt->xctxt->node = cur; + ret = xmlXPathEval(xpath, ctxt->xctxt); + if (ret == NULL) + return(NULL); + + if ((ret->type == XPATH_NODESET) && + (ret->nodesetval != NULL) && (ret->nodesetval->nodeNr > 0)) + node = ret->nodesetval->nodeTab[0]; + + xmlXPathFreeObject(ret); + return(node); +} + +/** + * xmlSchematronReportOutput: + * @ctxt: the validation context + * @cur: the current node tested + * @msg: the message output + * + * Output part of the report to whatever channel the user selected + */ +static void +xmlSchematronReportOutput(xmlSchematronValidCtxtPtr ctxt ATTRIBUTE_UNUSED, + xmlNodePtr cur ATTRIBUTE_UNUSED, + const char *msg) { + /* TODO */ + fprintf(stderr, "%s", msg); +} + +/** + * xmlSchematronFormatReport: + * @ctxt: the validation context + * @test: the test node + * @cur: the current node tested + * + * Build the string being reported to the user. + * + * Returns a report string or NULL in case of error. The string needs + * to be deallocated by teh caller + */ +static xmlChar * +xmlSchematronFormatReport(xmlSchematronValidCtxtPtr ctxt, + xmlNodePtr test, xmlNodePtr cur) { + xmlChar *ret = NULL; + xmlNodePtr child, node; + + if ((test == NULL) || (cur == NULL)) + return(ret); + + child = test->children; + while (child != NULL) { + if ((child->type == XML_TEXT_NODE) || + (child->type == XML_CDATA_SECTION_NODE)) + ret = xmlStrcat(ret, child->content); + else if (IS_SCHEMATRON(child, "name")) { + xmlChar *path; + + path = xmlGetNoNsProp(child, BAD_CAST "path"); + + node = cur; + if (path != NULL) { + node = xmlSchematronGetNode(ctxt, cur, path); + if (node == NULL) + node = cur; + xmlFree(path); + } + + if ((node->ns == NULL) || (node->ns->prefix == NULL)) + ret = xmlStrcat(ret, node->name); + else { + ret = xmlStrcat(ret, node->ns->prefix); + ret = xmlStrcat(ret, BAD_CAST ":"); + ret = xmlStrcat(ret, node->name); + } + } else { + child = child->next; + continue; + } + + /* + * remove superfluous \n + */ + if (ret != NULL) { + int len = xmlStrlen(ret); + xmlChar c; + + if (len > 0) { + c = ret[len - 1]; + if ((c == ' ') || (c == '\n') || (c == '\r') || (c == '\t')) { + while ((c == ' ') || (c == '\n') || + (c == '\r') || (c == '\t')) { + len--; + if (len == 0) + break; + c = ret[len - 1]; + } + ret[len] = ' '; + ret[len + 1] = 0; + } + } + } + + child = child->next; + } + return(ret); +} + +/** + * xmlSchematronReportSuccess: + * @ctxt: the validation context + * @test: the compiled test + * @cur: the current node tested + * @success: boolean value for the result + * + * called from the validation engine when an assert or report test have + * been done. + */ +static void +xmlSchematronReportSuccess(xmlSchematronValidCtxtPtr ctxt, + xmlSchematronTestPtr test, xmlNodePtr cur, xmlSchematronPatternPtr pattern, int success) { + if ((ctxt == NULL) || (cur == NULL) || (test == NULL)) + return; + /* if quiet and not SVRL report only failures */ + if ((ctxt->flags & XML_SCHEMATRON_OUT_QUIET) && + ((ctxt->flags & XML_SCHEMATRON_OUT_XML) == 0) && + (test->type == XML_SCHEMATRON_REPORT)) + return; + if (ctxt->flags & XML_SCHEMATRON_OUT_XML) { + TODO + } else { + xmlChar *path; + char msg[1000]; + long line; + const xmlChar *report = NULL; + + if (((test->type == XML_SCHEMATRON_REPORT) & (!success)) || + ((test->type == XML_SCHEMATRON_ASSERT) & (success))) + return; + line = xmlGetLineNo(cur); + path = xmlGetNodePath(cur); + if (path == NULL) + path = (xmlChar *) cur->name; +#if 0 + if ((test->report != NULL) && (test->report[0] != 0)) + report = test->report; +#endif + if (test->node != NULL) + report = xmlSchematronFormatReport(ctxt, test->node, cur); + if (report == NULL) { + if (test->type == XML_SCHEMATRON_ASSERT) { + report = xmlStrdup((const xmlChar *) "node failed assert"); + } else { + report = xmlStrdup((const xmlChar *) "node failed report"); + } + } + snprintf(msg, 999, "%s line %ld: %s\n", (const char *) path, + line, (const char *) report); + + if (ctxt->flags & XML_SCHEMATRON_OUT_ERROR) { + xmlStructuredErrorFunc schannel = NULL; + xmlGenericErrorFunc channel = NULL; + void *data = NULL; + + if (ctxt != NULL) { + if (ctxt->serror != NULL) + schannel = ctxt->serror; + else + channel = ctxt->error; + data = ctxt->userData; + } + + __xmlRaiseError(schannel, channel, data, + NULL, cur, XML_FROM_SCHEMATRONV, + (test->type == XML_SCHEMATRON_ASSERT)?XML_SCHEMATRONV_ASSERT:XML_SCHEMATRONV_REPORT, + XML_ERR_ERROR, NULL, line, + (pattern == NULL)?NULL:((const char *) pattern->name), + (const char *) path, + (const char *) report, 0, 0, + "%s", msg); + } else { + xmlSchematronReportOutput(ctxt, cur, &msg[0]); + } + + xmlFree((char *) report); + + if ((path != NULL) && (path != (xmlChar *) cur->name)) + xmlFree(path); + } +} + +/** + * xmlSchematronReportPattern: + * @ctxt: the validation context + * @pattern: the current pattern + * + * called from the validation engine when starting to check a pattern + */ +static void +xmlSchematronReportPattern(xmlSchematronValidCtxtPtr ctxt, + xmlSchematronPatternPtr pattern) { + if ((ctxt == NULL) || (pattern == NULL)) + return; + if ((ctxt->flags & XML_SCHEMATRON_OUT_QUIET) || (ctxt->flags & XML_SCHEMATRON_OUT_ERROR)) /* Error gives pattern name as part of error */ + return; + if (ctxt->flags & XML_SCHEMATRON_OUT_XML) { + TODO + } else { + char msg[1000]; + + if (pattern->name == NULL) + return; + snprintf(msg, 999, "Pattern: %s\n", (const char *) pattern->name); + xmlSchematronReportOutput(ctxt, NULL, &msg[0]); + } +} + + +/************************************************************************ + * * + * Validation against a Schematrontron * + * * + ************************************************************************/ + +/** + * xmlSchematronSetValidStructuredErrors: + * @ctxt: a Schematron validation context + * @serror: the structured error function + * @ctx: the functions context + * + * Set the structured error callback + */ +void +xmlSchematronSetValidStructuredErrors(xmlSchematronValidCtxtPtr ctxt, + xmlStructuredErrorFunc serror, void *ctx) +{ + if (ctxt == NULL) + return; + ctxt->serror = serror; + ctxt->error = NULL; + ctxt->warning = NULL; + ctxt->userData = ctx; +} + +/** + * xmlSchematronNewValidCtxt: + * @schema: a precompiled XML Schematrons + * @options: a set of xmlSchematronValidOptions + * + * Create an XML Schematrons validation context based on the given schema. + * + * Returns the validation context or NULL in case of error + */ +xmlSchematronValidCtxtPtr +xmlSchematronNewValidCtxt(xmlSchematronPtr schema, int options) +{ + int i; + xmlSchematronValidCtxtPtr ret; + + ret = (xmlSchematronValidCtxtPtr) xmlMalloc(sizeof(xmlSchematronValidCtxt)); + if (ret == NULL) { + xmlSchematronVErrMemory(NULL, "allocating validation context", + NULL); + return (NULL); + } + memset(ret, 0, sizeof(xmlSchematronValidCtxt)); + ret->type = XML_STRON_CTXT_VALIDATOR; + ret->schema = schema; + ret->xctxt = xmlXPathNewContext(NULL); + ret->flags = options; + if (ret->xctxt == NULL) { + xmlSchematronPErrMemory(NULL, "allocating schema parser XPath context", + NULL); + xmlSchematronFreeValidCtxt(ret); + return (NULL); + } + for (i = 0;i < schema->nbNamespaces;i++) { + if ((schema->namespaces[2 * i] == NULL) || + (schema->namespaces[2 * i + 1] == NULL)) + break; + xmlXPathRegisterNs(ret->xctxt, schema->namespaces[2 * i + 1], + schema->namespaces[2 * i]); + } + return (ret); +} + +/** + * xmlSchematronFreeValidCtxt: + * @ctxt: the schema validation context + * + * Free the resources associated to the schema validation context + */ +void +xmlSchematronFreeValidCtxt(xmlSchematronValidCtxtPtr ctxt) +{ + if (ctxt == NULL) + return; + if (ctxt->xctxt != NULL) + xmlXPathFreeContext(ctxt->xctxt); + if (ctxt->dict != NULL) + xmlDictFree(ctxt->dict); + xmlFree(ctxt); +} + +static xmlNodePtr +xmlSchematronNextNode(xmlNodePtr cur) { + if (cur->children != NULL) { + /* + * Do not descend on entities declarations + */ + if (cur->children->type != XML_ENTITY_DECL) { + cur = cur->children; + /* + * Skip DTDs + */ + if (cur->type != XML_DTD_NODE) + return(cur); + } + } + + while (cur->next != NULL) { + cur = cur->next; + if ((cur->type != XML_ENTITY_DECL) && + (cur->type != XML_DTD_NODE)) + return(cur); + } + + do { + cur = cur->parent; + if (cur == NULL) break; + if (cur->type == XML_DOCUMENT_NODE) return(NULL); + if (cur->next != NULL) { + cur = cur->next; + return(cur); + } + } while (cur != NULL); + return(cur); +} + +/** + * xmlSchematronRunTest: + * @ctxt: the schema validation context + * @test: the current test + * @instance: the document instace tree + * @cur: the current node in the instance + * + * Validate a rule against a tree instance at a given position + * + * Returns 1 in case of success, 0 if error and -1 in case of internal error + */ +static int +xmlSchematronRunTest(xmlSchematronValidCtxtPtr ctxt, + xmlSchematronTestPtr test, xmlDocPtr instance, xmlNodePtr cur, xmlSchematronPatternPtr pattern) +{ + xmlXPathObjectPtr ret; + int failed; + + failed = 0; + ctxt->xctxt->doc = instance; + ctxt->xctxt->node = cur; + ret = xmlXPathCompiledEval(test->comp, ctxt->xctxt); + if (ret == NULL) { + failed = 1; + } else { + switch (ret->type) { + case XPATH_XSLT_TREE: + case XPATH_NODESET: + if ((ret->nodesetval == NULL) || + (ret->nodesetval->nodeNr == 0)) + failed = 1; + break; + case XPATH_BOOLEAN: + failed = !ret->boolval; + break; + case XPATH_NUMBER: + if ((xmlXPathIsNaN(ret->floatval)) || + (ret->floatval == 0.0)) + failed = 1; + break; + case XPATH_STRING: + if ((ret->stringval == NULL) || + (ret->stringval[0] == 0)) + failed = 1; + break; + case XPATH_UNDEFINED: + case XPATH_POINT: + case XPATH_RANGE: + case XPATH_LOCATIONSET: + case XPATH_USERS: + failed = 1; + break; + } + xmlXPathFreeObject(ret); + } + if ((failed) && (test->type == XML_SCHEMATRON_ASSERT)) + ctxt->nberrors++; + else if ((!failed) && (test->type == XML_SCHEMATRON_REPORT)) + ctxt->nberrors++; + + xmlSchematronReportSuccess(ctxt, test, cur, pattern, !failed); + + return(!failed); +} + +/** + * xmlSchematronValidateDoc: + * @ctxt: the schema validation context + * @instance: the document instace tree + * + * Validate a tree instance against the schematron + * + * Returns 0 in case of success, -1 in case of internal error + * and an error count otherwise. + */ +int +xmlSchematronValidateDoc(xmlSchematronValidCtxtPtr ctxt, xmlDocPtr instance) +{ + xmlNodePtr cur, root; + xmlSchematronPatternPtr pattern; + xmlSchematronRulePtr rule; + xmlSchematronTestPtr test; + + if ((ctxt == NULL) || (ctxt->schema == NULL) || + (ctxt->schema->rules == NULL) || (instance == NULL)) + return(-1); + ctxt->nberrors = 0; + root = xmlDocGetRootElement(instance); + if (root == NULL) { + TODO + ctxt->nberrors++; + return(1); + } + if ((ctxt->flags & XML_SCHEMATRON_OUT_QUIET) || + (ctxt->flags == 0)) { + /* + * we are just trying to assert the validity of the document, + * speed primes over the output, run in a single pass + */ + cur = root; + while (cur != NULL) { + rule = ctxt->schema->rules; + while (rule != NULL) { + if (xmlPatternMatch(rule->pattern, cur) == 1) { + test = rule->tests; + while (test != NULL) { + xmlSchematronRunTest(ctxt, test, instance, cur, (xmlSchematronPatternPtr)rule->pattern); + test = test->next; + } + } + rule = rule->next; + } + + cur = xmlSchematronNextNode(cur); + } + } else { + /* + * Process all contexts one at a time + */ + pattern = ctxt->schema->patterns; + + while (pattern != NULL) { + xmlSchematronReportPattern(ctxt, pattern); + + /* + * TODO convert the pattern rule to a direct XPath and + * compute directly instead of using the pattern matching + * over the full document... + * Check the exact semantic + */ + cur = root; + while (cur != NULL) { + rule = pattern->rules; + while (rule != NULL) { + if (xmlPatternMatch(rule->pattern, cur) == 1) { + test = rule->tests; + while (test != NULL) { + xmlSchematronRunTest(ctxt, test, instance, cur, pattern); + test = test->next; + } + } + rule = rule->patnext; + } + + cur = xmlSchematronNextNode(cur); + } + pattern = pattern->next; + } + } + return(ctxt->nberrors); +} + +#ifdef STANDALONE +int +main(void) +{ + int ret; + xmlDocPtr instance; + xmlSchematronParserCtxtPtr pctxt; + xmlSchematronValidCtxtPtr vctxt; + xmlSchematronPtr schema = NULL; + + pctxt = xmlSchematronNewParserCtxt("tst.sct"); + if (pctxt == NULL) { + fprintf(stderr, "failed to build schematron parser\n"); + } else { + schema = xmlSchematronParse(pctxt); + if (schema == NULL) { + fprintf(stderr, "failed to compile schematron\n"); + } + xmlSchematronFreeParserCtxt(pctxt); + } + instance = xmlReadFile("tst.sct", NULL, + XML_PARSE_NOENT | XML_PARSE_NOCDATA); + if (instance == NULL) { + fprintf(stderr, "failed to parse instance\n"); + } + if ((schema != NULL) && (instance != NULL)) { + vctxt = xmlSchematronNewValidCtxt(schema); + if (vctxt == NULL) { + fprintf(stderr, "failed to build schematron validator\n"); + } else { + ret = xmlSchematronValidateDoc(vctxt, instance); + xmlSchematronFreeValidCtxt(vctxt); + } + } + xmlSchematronFree(schema); + xmlFreeDoc(instance); + + xmlCleanupParser(); + xmlMemoryDump(); + + return (0); +} +#endif +#define bottom_schematron +#include "elfgcchack.h" +#endif /* LIBXML_SCHEMATRON_ENABLED */ diff --git a/android/native/libxml2/threads.c b/android/native/libxml2/threads.c new file mode 100644 index 0000000000..1eeac0e176 --- /dev/null +++ b/android/native/libxml2/threads.c @@ -0,0 +1,1034 @@ +/** + * threads.c: set of generic threading related routines + * + * See Copyright for the status of this software. + * + * Gary Pennington + * daniel@veillard.com + */ + +#define IN_LIBXML +#include "libxml.h" + +#include + +#include +#include + +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_PTHREAD_H +#include +#elif defined HAVE_WIN32_THREADS +#include +#ifndef HAVE_COMPILER_TLS +#include +#endif +#endif + +#ifdef HAVE_BEOS_THREADS +#include +#include +#endif + +#if defined(SOLARIS) +#include +#endif + +/* #define DEBUG_THREADS */ + +#ifdef HAVE_PTHREAD_H + +static int libxml_is_threaded = -1; +#ifdef __GNUC__ +#ifdef linux +#if (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) || (__GNUC__ > 3) +extern int pthread_once (pthread_once_t *__once_control, + void (*__init_routine) (void)) + __attribute((weak)); +extern void *pthread_getspecific (pthread_key_t __key) + __attribute((weak)); +extern int pthread_setspecific (pthread_key_t __key, + __const void *__pointer) + __attribute((weak)); +extern int pthread_key_create (pthread_key_t *__key, + void (*__destr_function) (void *)) + __attribute((weak)); +extern int pthread_key_delete (pthread_key_t __key) + __attribute((weak)); +extern int pthread_mutex_init () + __attribute((weak)); +extern int pthread_mutex_destroy () + __attribute((weak)); +extern int pthread_mutex_lock () + __attribute((weak)); +extern int pthread_mutex_unlock () + __attribute((weak)); +extern int pthread_cond_init () + __attribute((weak)); +extern int pthread_cond_destroy () + __attribute((weak)); +extern int pthread_cond_wait () + __attribute((weak)); +extern int pthread_equal () + __attribute((weak)); +extern pthread_t pthread_self () + __attribute((weak)); +extern int pthread_key_create () + __attribute((weak)); +extern int pthread_key_delete () + __attribute((weak)); +extern int pthread_cond_signal () + __attribute((weak)); +#endif +#endif /* linux */ +#endif /* __GNUC__ */ +#endif /* HAVE_PTHREAD_H */ + +/* + * TODO: this module still uses malloc/free and not xmlMalloc/xmlFree + * to avoid some crazyness since xmlMalloc/xmlFree may actually + * be hosted on allocated blocks needing them for the allocation ... + */ + +/* + * xmlMutex are a simple mutual exception locks + */ +struct _xmlMutex { +#ifdef HAVE_PTHREAD_H + pthread_mutex_t lock; +#elif defined HAVE_WIN32_THREADS + HANDLE mutex; +#elif defined HAVE_BEOS_THREADS + sem_id sem; + thread_id tid; +#else + int empty; +#endif +}; + +/* + * xmlRMutex are reentrant mutual exception locks + */ +struct _xmlRMutex { +#ifdef HAVE_PTHREAD_H + pthread_mutex_t lock; + unsigned int held; + unsigned int waiters; + pthread_t tid; + pthread_cond_t cv; +#elif defined HAVE_WIN32_THREADS + CRITICAL_SECTION cs; + unsigned int count; +#elif defined HAVE_BEOS_THREADS + xmlMutexPtr lock; + thread_id tid; + int32 count; +#else + int empty; +#endif +}; + +/* + * This module still has some internal static data. + * - xmlLibraryLock a global lock + * - globalkey used for per-thread data + */ + +#ifdef HAVE_PTHREAD_H +static pthread_key_t globalkey; +static pthread_t mainthread; +static pthread_once_t once_control = PTHREAD_ONCE_INIT; +static pthread_mutex_t global_init_lock = PTHREAD_MUTEX_INITIALIZER; +#elif defined HAVE_WIN32_THREADS +#if defined(HAVE_COMPILER_TLS) +static __declspec(thread) xmlGlobalState tlstate; +static __declspec(thread) int tlstate_inited = 0; +#else /* HAVE_COMPILER_TLS */ +static DWORD globalkey = TLS_OUT_OF_INDEXES; +#endif /* HAVE_COMPILER_TLS */ +static DWORD mainthread; +static struct { + DWORD done; + DWORD control; +} run_once = { 0, 0}; +static volatile LPCRITICAL_SECTION global_init_lock = NULL; + +/* endif HAVE_WIN32_THREADS */ +#elif defined HAVE_BEOS_THREADS +int32 globalkey = 0; +thread_id mainthread = 0; +int32 run_once_init = 0; +static int32 global_init_lock = -1; +static vint32 global_init_count = 0; +#endif + +static xmlRMutexPtr xmlLibraryLock = NULL; + +#ifdef LIBXML_THREAD_ENABLED +static void xmlOnceInit(void); +#endif + +/** + * xmlNewMutex: + * + * xmlNewMutex() is used to allocate a libxml2 token struct for use in + * synchronizing access to data. + * + * Returns a new simple mutex pointer or NULL in case of error + */ +xmlMutexPtr +xmlNewMutex(void) +{ + xmlMutexPtr tok; + + if ((tok = malloc(sizeof(xmlMutex))) == NULL) + return (NULL); +#ifdef HAVE_PTHREAD_H + if (libxml_is_threaded != 0) + pthread_mutex_init(&tok->lock, NULL); +#elif defined HAVE_WIN32_THREADS + tok->mutex = CreateMutex(NULL, FALSE, NULL); +#elif defined HAVE_BEOS_THREADS + if ((tok->sem = create_sem(1, "xmlMutex")) < B_OK) { + free(tok); + return NULL; + } + tok->tid = -1; +#endif + return (tok); +} + +/** + * xmlFreeMutex: + * @tok: the simple mutex + * + * xmlFreeMutex() is used to reclaim resources associated with a libxml2 token + * struct. + */ +void +xmlFreeMutex(xmlMutexPtr tok) +{ + if (tok == NULL) + return; + +#ifdef HAVE_PTHREAD_H + if (libxml_is_threaded != 0) + pthread_mutex_destroy(&tok->lock); +#elif defined HAVE_WIN32_THREADS + CloseHandle(tok->mutex); +#elif defined HAVE_BEOS_THREADS + delete_sem(tok->sem); +#endif + free(tok); +} + +/** + * xmlMutexLock: + * @tok: the simple mutex + * + * xmlMutexLock() is used to lock a libxml2 token. + */ +void +xmlMutexLock(xmlMutexPtr tok) +{ + if (tok == NULL) + return; +#ifdef HAVE_PTHREAD_H + if (libxml_is_threaded != 0) + pthread_mutex_lock(&tok->lock); +#elif defined HAVE_WIN32_THREADS + WaitForSingleObject(tok->mutex, INFINITE); +#elif defined HAVE_BEOS_THREADS + if (acquire_sem(tok->sem) != B_NO_ERROR) { +#ifdef DEBUG_THREADS + xmlGenericError(xmlGenericErrorContext, + "xmlMutexLock():BeOS:Couldn't aquire semaphore\n"); + exit(); +#endif + } + tok->tid = find_thread(NULL); +#endif + +} + +/** + * xmlMutexUnlock: + * @tok: the simple mutex + * + * xmlMutexUnlock() is used to unlock a libxml2 token. + */ +void +xmlMutexUnlock(xmlMutexPtr tok) +{ + if (tok == NULL) + return; +#ifdef HAVE_PTHREAD_H + if (libxml_is_threaded != 0) + pthread_mutex_unlock(&tok->lock); +#elif defined HAVE_WIN32_THREADS + ReleaseMutex(tok->mutex); +#elif defined HAVE_BEOS_THREADS + if (tok->tid == find_thread(NULL)) { + tok->tid = -1; + release_sem(tok->sem); + } +#endif +} + +/** + * xmlNewRMutex: + * + * xmlRNewMutex() is used to allocate a reentrant mutex for use in + * synchronizing access to data. token_r is a re-entrant lock and thus useful + * for synchronizing access to data structures that may be manipulated in a + * recursive fashion. + * + * Returns the new reentrant mutex pointer or NULL in case of error + */ +xmlRMutexPtr +xmlNewRMutex(void) +{ + xmlRMutexPtr tok; + + if ((tok = malloc(sizeof(xmlRMutex))) == NULL) + return (NULL); +#ifdef HAVE_PTHREAD_H + if (libxml_is_threaded != 0) { + pthread_mutex_init(&tok->lock, NULL); + tok->held = 0; + tok->waiters = 0; + pthread_cond_init(&tok->cv, NULL); + } +#elif defined HAVE_WIN32_THREADS + InitializeCriticalSection(&tok->cs); + tok->count = 0; +#elif defined HAVE_BEOS_THREADS + if ((tok->lock = xmlNewMutex()) == NULL) { + free(tok); + return NULL; + } + tok->count = 0; +#endif + return (tok); +} + +/** + * xmlFreeRMutex: + * @tok: the reentrant mutex + * + * xmlRFreeMutex() is used to reclaim resources associated with a + * reentrant mutex. + */ +void +xmlFreeRMutex(xmlRMutexPtr tok ATTRIBUTE_UNUSED) +{ + if (tok == NULL) + return; +#ifdef HAVE_PTHREAD_H + if (libxml_is_threaded != 0) { + pthread_mutex_destroy(&tok->lock); + pthread_cond_destroy(&tok->cv); + } +#elif defined HAVE_WIN32_THREADS + DeleteCriticalSection(&tok->cs); +#elif defined HAVE_BEOS_THREADS + xmlFreeMutex(tok->lock); +#endif + free(tok); +} + +/** + * xmlRMutexLock: + * @tok: the reentrant mutex + * + * xmlRMutexLock() is used to lock a libxml2 token_r. + */ +void +xmlRMutexLock(xmlRMutexPtr tok) +{ + if (tok == NULL) + return; +#ifdef HAVE_PTHREAD_H + if (libxml_is_threaded == 0) + return; + + pthread_mutex_lock(&tok->lock); + if (tok->held) { + if (pthread_equal(tok->tid, pthread_self())) { + tok->held++; + pthread_mutex_unlock(&tok->lock); + return; + } else { + tok->waiters++; + while (tok->held) + pthread_cond_wait(&tok->cv, &tok->lock); + tok->waiters--; + } + } + tok->tid = pthread_self(); + tok->held = 1; + pthread_mutex_unlock(&tok->lock); +#elif defined HAVE_WIN32_THREADS + EnterCriticalSection(&tok->cs); + ++tok->count; +#elif defined HAVE_BEOS_THREADS + if (tok->lock->tid == find_thread(NULL)) { + tok->count++; + return; + } else { + xmlMutexLock(tok->lock); + tok->count = 1; + } +#endif +} + +/** + * xmlRMutexUnlock: + * @tok: the reentrant mutex + * + * xmlRMutexUnlock() is used to unlock a libxml2 token_r. + */ +void +xmlRMutexUnlock(xmlRMutexPtr tok ATTRIBUTE_UNUSED) +{ + if (tok == NULL) + return; +#ifdef HAVE_PTHREAD_H + if (libxml_is_threaded == 0) + return; + + pthread_mutex_lock(&tok->lock); + tok->held--; + if (tok->held == 0) { + if (tok->waiters) + pthread_cond_signal(&tok->cv); + memset(&tok->tid, 0, sizeof(tok->tid)); + } + pthread_mutex_unlock(&tok->lock); +#elif defined HAVE_WIN32_THREADS + if (!--tok->count) + LeaveCriticalSection(&tok->cs); +#elif defined HAVE_BEOS_THREADS + if (tok->lock->tid == find_thread(NULL)) { + tok->count--; + if (tok->count == 0) { + xmlMutexUnlock(tok->lock); + } + return; + } +#endif +} + +/** + * xmlGlobalInitMutexLock + * + * Makes sure that the global initialization mutex is initialized and + * locks it. + */ +void +__xmlGlobalInitMutexLock(void) +{ + /* Make sure the global init lock is initialized and then lock it. */ +#ifdef HAVE_PTHREAD_H + /* The mutex is statically initialized, so we just lock it. */ + if (pthread_mutex_lock) + pthread_mutex_lock(&global_init_lock); +#elif defined HAVE_WIN32_THREADS + LPCRITICAL_SECTION cs; + + /* Create a new critical section */ + if (global_init_lock == NULL) { + cs = malloc(sizeof(CRITICAL_SECTION)); + if (cs == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlGlobalInitMutexLock: out of memory\n"); + return; + } + InitializeCriticalSection(cs); + + /* Swap it into the global_init_lock */ +#ifdef InterlockedCompareExchangePointer + InterlockedCompareExchangePointer(&global_init_lock, cs, NULL); +#else /* Use older void* version */ + InterlockedCompareExchange((void **) &global_init_lock, + (void *) cs, NULL); +#endif /* InterlockedCompareExchangePointer */ + + /* If another thread successfully recorded its critical + * section in the global_init_lock then discard the one + * allocated by this thread. */ + if (global_init_lock != cs) { + DeleteCriticalSection(cs); + free(cs); + } + } + + /* Lock the chosen critical section */ + EnterCriticalSection(global_init_lock); +#elif defined HAVE_BEOS_THREADS + int32 sem; + + /* Allocate a new semaphore */ + sem = create_sem(1, "xmlGlobalinitMutex"); + + while (global_init_lock == -1) { + if (atomic_add(&global_init_count, 1) == 0) { + global_init_lock = sem; + } else { + snooze(1); + atomic_add(&global_init_count, -1); + } + } + + /* If another thread successfully recorded its critical + * section in the global_init_lock then discard the one + * allocated by this thread. */ + if (global_init_lock != sem) + delete_sem(sem); + + /* Acquire the chosen semaphore */ + if (acquire_sem(global_init_lock) != B_NO_ERROR) { +#ifdef DEBUG_THREADS + xmlGenericError(xmlGenericErrorContext, + "xmlGlobalInitMutexLock():BeOS:Couldn't acquire semaphore\n"); + exit(); +#endif + } +#endif +} + +void +__xmlGlobalInitMutexUnlock(void) +{ +#ifdef HAVE_PTHREAD_H + if (pthread_mutex_unlock) + pthread_mutex_unlock(&global_init_lock); +#elif defined HAVE_WIN32_THREADS + if (global_init_lock != NULL) { + LeaveCriticalSection(global_init_lock); + } +#elif defined HAVE_BEOS_THREADS + release_sem(global_init_lock); +#endif +} + +/** + * xmlGlobalInitMutexDestroy + * + * Makes sure that the global initialization mutex is destroyed before + * application termination. + */ +void +__xmlGlobalInitMutexDestroy(void) +{ +#ifdef HAVE_PTHREAD_H +#elif defined HAVE_WIN32_THREADS + if (global_init_lock != NULL) { + DeleteCriticalSection(global_init_lock); + free(global_init_lock); + global_init_lock = NULL; + } +#endif +} + +/************************************************************************ + * * + * Per thread global state handling * + * * + ************************************************************************/ + +#ifdef LIBXML_THREAD_ENABLED +#ifdef xmlLastError +#undef xmlLastError +#endif + +/** + * xmlFreeGlobalState: + * @state: a thread global state + * + * xmlFreeGlobalState() is called when a thread terminates with a non-NULL + * global state. It is is used here to reclaim memory resources. + */ +static void +xmlFreeGlobalState(void *state) +{ + xmlGlobalState *gs = (xmlGlobalState *) state; + + /* free any memory allocated in the thread's xmlLastError */ + xmlResetError(&(gs->xmlLastError)); + free(state); +} + +/** + * xmlNewGlobalState: + * + * xmlNewGlobalState() allocates a global state. This structure is used to + * hold all data for use by a thread when supporting backwards compatibility + * of libxml2 to pre-thread-safe behaviour. + * + * Returns the newly allocated xmlGlobalStatePtr or NULL in case of error + */ +static xmlGlobalStatePtr +xmlNewGlobalState(void) +{ + xmlGlobalState *gs; + + gs = malloc(sizeof(xmlGlobalState)); + if (gs == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlGetGlobalState: out of memory\n"); + return (NULL); + } + + memset(gs, 0, sizeof(xmlGlobalState)); + xmlInitializeGlobalState(gs); + return (gs); +} +#endif /* LIBXML_THREAD_ENABLED */ + +#ifdef HAVE_PTHREAD_H +#elif defined HAVE_WIN32_THREADS +#if !defined(HAVE_COMPILER_TLS) +#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL) +typedef struct _xmlGlobalStateCleanupHelperParams { + HANDLE thread; + void *memory; +} xmlGlobalStateCleanupHelperParams; + +static void XMLCDECL +xmlGlobalStateCleanupHelper(void *p) +{ + xmlGlobalStateCleanupHelperParams *params = + (xmlGlobalStateCleanupHelperParams *) p; + WaitForSingleObject(params->thread, INFINITE); + CloseHandle(params->thread); + xmlFreeGlobalState(params->memory); + free(params); + _endthread(); +} +#else /* LIBXML_STATIC && !LIBXML_STATIC_FOR_DLL */ + +typedef struct _xmlGlobalStateCleanupHelperParams { + void *memory; + struct _xmlGlobalStateCleanupHelperParams *prev; + struct _xmlGlobalStateCleanupHelperParams *next; +} xmlGlobalStateCleanupHelperParams; + +static xmlGlobalStateCleanupHelperParams *cleanup_helpers_head = NULL; +static CRITICAL_SECTION cleanup_helpers_cs; + +#endif /* LIBXMLSTATIC && !LIBXML_STATIC_FOR_DLL */ +#endif /* HAVE_COMPILER_TLS */ +#endif /* HAVE_WIN32_THREADS */ + +#if defined HAVE_BEOS_THREADS + +/** + * xmlGlobalStateCleanup: + * @data: unused parameter + * + * Used for Beos only + */ +void +xmlGlobalStateCleanup(void *data) +{ + void *globalval = tls_get(globalkey); + + if (globalval != NULL) + xmlFreeGlobalState(globalval); +} +#endif + +/** + * xmlGetGlobalState: + * + * xmlGetGlobalState() is called to retrieve the global state for a thread. + * + * Returns the thread global state or NULL in case of error + */ +xmlGlobalStatePtr +xmlGetGlobalState(void) +{ +#ifdef HAVE_PTHREAD_H + xmlGlobalState *globalval; + + if (libxml_is_threaded == 0) + return (NULL); + + pthread_once(&once_control, xmlOnceInit); + + if ((globalval = (xmlGlobalState *) + pthread_getspecific(globalkey)) == NULL) { + xmlGlobalState *tsd = xmlNewGlobalState(); + if (tsd == NULL) + return(NULL); + + pthread_setspecific(globalkey, tsd); + return (tsd); + } + return (globalval); +#elif defined HAVE_WIN32_THREADS +#if defined(HAVE_COMPILER_TLS) + if (!tlstate_inited) { + tlstate_inited = 1; + xmlInitializeGlobalState(&tlstate); + } + return &tlstate; +#else /* HAVE_COMPILER_TLS */ + xmlGlobalState *globalval; + xmlGlobalStateCleanupHelperParams *p; + + xmlOnceInit(); +#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL) + globalval = (xmlGlobalState *) TlsGetValue(globalkey); +#else + p = (xmlGlobalStateCleanupHelperParams *) TlsGetValue(globalkey); + globalval = (xmlGlobalState *) (p ? p->memory : NULL); +#endif + if (globalval == NULL) { + xmlGlobalState *tsd = xmlNewGlobalState(); + + if (tsd == NULL) + return(NULL); + p = (xmlGlobalStateCleanupHelperParams *) + malloc(sizeof(xmlGlobalStateCleanupHelperParams)); + if (p == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlGetGlobalState: out of memory\n"); + xmlFreeGlobalState(tsd); + return(NULL); + } + p->memory = tsd; +#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL) + DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), + GetCurrentProcess(), &p->thread, 0, TRUE, + DUPLICATE_SAME_ACCESS); + TlsSetValue(globalkey, tsd); + _beginthread(xmlGlobalStateCleanupHelper, 0, p); +#else + EnterCriticalSection(&cleanup_helpers_cs); + if (cleanup_helpers_head != NULL) { + cleanup_helpers_head->prev = p; + } + p->next = cleanup_helpers_head; + p->prev = NULL; + cleanup_helpers_head = p; + TlsSetValue(globalkey, p); + LeaveCriticalSection(&cleanup_helpers_cs); +#endif + + return (tsd); + } + return (globalval); +#endif /* HAVE_COMPILER_TLS */ +#elif defined HAVE_BEOS_THREADS + xmlGlobalState *globalval; + + xmlOnceInit(); + + if ((globalval = (xmlGlobalState *) tls_get(globalkey)) == NULL) { + xmlGlobalState *tsd = xmlNewGlobalState(); + if (tsd == NULL) + return (NULL); + + tls_set(globalkey, tsd); + on_exit_thread(xmlGlobalStateCleanup, NULL); + return (tsd); + } + return (globalval); +#else + return (NULL); +#endif +} + +/************************************************************************ + * * + * Library wide thread interfaces * + * * + ************************************************************************/ + +/** + * xmlGetThreadId: + * + * xmlGetThreadId() find the current thread ID number + * Note that this is likely to be broken on some platforms using pthreads + * as the specification doesn't mandate pthread_t to be an integer type + * + * Returns the current thread ID number + */ +int +xmlGetThreadId(void) +{ +#ifdef HAVE_PTHREAD_H + pthread_t id; + int ret; + + if (libxml_is_threaded == 0) + return (0); + id = pthread_self(); + /* horrible but preserves compat, see warning above */ + memcpy(&ret, &id, sizeof(ret)); + return (ret); +#elif defined HAVE_WIN32_THREADS + return GetCurrentThreadId(); +#elif defined HAVE_BEOS_THREADS + return find_thread(NULL); +#else + return ((int) 0); +#endif +} + +/** + * xmlIsMainThread: + * + * xmlIsMainThread() check whether the current thread is the main thread. + * + * Returns 1 if the current thread is the main thread, 0 otherwise + */ +int +xmlIsMainThread(void) +{ +#ifdef HAVE_PTHREAD_H + if (libxml_is_threaded == -1) + xmlInitThreads(); + if (libxml_is_threaded == 0) + return (1); + pthread_once(&once_control, xmlOnceInit); +#elif defined HAVE_WIN32_THREADS + xmlOnceInit(); +#elif defined HAVE_BEOS_THREADS + xmlOnceInit(); +#endif + +#ifdef DEBUG_THREADS + xmlGenericError(xmlGenericErrorContext, "xmlIsMainThread()\n"); +#endif +#ifdef HAVE_PTHREAD_H + return (pthread_equal(mainthread,pthread_self())); +#elif defined HAVE_WIN32_THREADS + return (mainthread == GetCurrentThreadId()); +#elif defined HAVE_BEOS_THREADS + return (mainthread == find_thread(NULL)); +#else + return (1); +#endif +} + +/** + * xmlLockLibrary: + * + * xmlLockLibrary() is used to take out a re-entrant lock on the libxml2 + * library. + */ +void +xmlLockLibrary(void) +{ +#ifdef DEBUG_THREADS + xmlGenericError(xmlGenericErrorContext, "xmlLockLibrary()\n"); +#endif + xmlRMutexLock(xmlLibraryLock); +} + +/** + * xmlUnlockLibrary: + * + * xmlUnlockLibrary() is used to release a re-entrant lock on the libxml2 + * library. + */ +void +xmlUnlockLibrary(void) +{ +#ifdef DEBUG_THREADS + xmlGenericError(xmlGenericErrorContext, "xmlUnlockLibrary()\n"); +#endif + xmlRMutexUnlock(xmlLibraryLock); +} + +/** + * xmlInitThreads: + * + * xmlInitThreads() is used to to initialize all the thread related + * data of the libxml2 library. + */ +void +xmlInitThreads(void) +{ +#ifdef HAVE_PTHREAD_H + if (libxml_is_threaded == -1) { + if ((pthread_once != NULL) && + (pthread_getspecific != NULL) && + (pthread_setspecific != NULL) && + (pthread_key_create != NULL) && + (pthread_key_delete != NULL) && + (pthread_mutex_init != NULL) && + (pthread_mutex_destroy != NULL) && + (pthread_mutex_lock != NULL) && + (pthread_mutex_unlock != NULL) && + (pthread_cond_init != NULL) && + (pthread_cond_destroy != NULL) && + (pthread_cond_wait != NULL) && + (pthread_equal != NULL) && + (pthread_self != NULL) && + (pthread_cond_signal != NULL)) { + libxml_is_threaded = 1; + +/* fprintf(stderr, "Running multithreaded\n"); */ + } else { + +/* fprintf(stderr, "Running without multithread\n"); */ + libxml_is_threaded = 0; + } + } +#elif defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL)) + InitializeCriticalSection(&cleanup_helpers_cs); +#endif +} + +/** + * xmlCleanupThreads: + * + * xmlCleanupThreads() is used to to cleanup all the thread related + * data of the libxml2 library once processing has ended. + * + * WARNING: if your application is multithreaded or has plugin support + * calling this may crash the application if another thread or + * a plugin is still using libxml2. It's sometimes very hard to + * guess if libxml2 is in use in the application, some libraries + * or plugins may use it without notice. In case of doubt abstain + * from calling this function or do it just before calling exit() + * to avoid leak reports from valgrind ! + */ +void +xmlCleanupThreads(void) +{ +#ifdef DEBUG_THREADS + xmlGenericError(xmlGenericErrorContext, "xmlCleanupThreads()\n"); +#endif +#ifdef HAVE_PTHREAD_H + if ((libxml_is_threaded) && (pthread_key_delete != NULL)) + pthread_key_delete(globalkey); +#elif defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL)) + if (globalkey != TLS_OUT_OF_INDEXES) { + xmlGlobalStateCleanupHelperParams *p; + + EnterCriticalSection(&cleanup_helpers_cs); + p = cleanup_helpers_head; + while (p != NULL) { + xmlGlobalStateCleanupHelperParams *temp = p; + + p = p->next; + xmlFreeGlobalState(temp->memory); + free(temp); + } + cleanup_helpers_head = 0; + LeaveCriticalSection(&cleanup_helpers_cs); + TlsFree(globalkey); + globalkey = TLS_OUT_OF_INDEXES; + } + DeleteCriticalSection(&cleanup_helpers_cs); +#endif +} + +#ifdef LIBXML_THREAD_ENABLED + +/** + * xmlOnceInit + * + * xmlOnceInit() is used to initialize the value of mainthread for use + * in other routines. This function should only be called using + * pthread_once() in association with the once_control variable to ensure + * that the function is only called once. See man pthread_once for more + * details. + */ +static void +xmlOnceInit(void) +{ +#ifdef HAVE_PTHREAD_H + (void) pthread_key_create(&globalkey, xmlFreeGlobalState); + mainthread = pthread_self(); +#elif defined(HAVE_WIN32_THREADS) + if (!run_once.done) { + if (InterlockedIncrement(&run_once.control) == 1) { +#if !defined(HAVE_COMPILER_TLS) + globalkey = TlsAlloc(); +#endif + mainthread = GetCurrentThreadId(); + run_once.done = 1; + } else { + /* Another thread is working; give up our slice and + * wait until they're done. */ + while (!run_once.done) + Sleep(0); + } + } +#elif defined HAVE_BEOS_THREADS + if (atomic_add(&run_once_init, 1) == 0) { + globalkey = tls_allocate(); + tls_set(globalkey, NULL); + mainthread = find_thread(NULL); + } else + atomic_add(&run_once_init, -1); +#endif +} +#endif + +/** + * DllMain: + * @hinstDLL: handle to DLL instance + * @fdwReason: Reason code for entry + * @lpvReserved: generic pointer (depends upon reason code) + * + * Entry point for Windows library. It is being used to free thread-specific + * storage. + * + * Returns TRUE always + */ +#ifdef HAVE_PTHREAD_H +#elif defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL)) +#if defined(LIBXML_STATIC_FOR_DLL) +BOOL XMLCALL +xmlDllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +#else +BOOL WINAPI +DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +#endif +{ + switch (fdwReason) { + case DLL_THREAD_DETACH: + if (globalkey != TLS_OUT_OF_INDEXES) { + xmlGlobalState *globalval = NULL; + xmlGlobalStateCleanupHelperParams *p = + (xmlGlobalStateCleanupHelperParams *) + TlsGetValue(globalkey); + globalval = (xmlGlobalState *) (p ? p->memory : NULL); + if (globalval) { + xmlFreeGlobalState(globalval); + TlsSetValue(globalkey, NULL); + } + if (p) { + EnterCriticalSection(&cleanup_helpers_cs); + if (p == cleanup_helpers_head) + cleanup_helpers_head = p->next; + else + p->prev->next = p->next; + if (p->next != NULL) + p->next->prev = p->prev; + LeaveCriticalSection(&cleanup_helpers_cs); + free(p); + } + } + break; + } + return TRUE; +} +#endif +#define bottom_threads +#include "elfgcchack.h" diff --git a/android/native/libxml2/tree.c b/android/native/libxml2/tree.c new file mode 100644 index 0000000000..e63ff24755 --- /dev/null +++ b/android/native/libxml2/tree.c @@ -0,0 +1,9913 @@ +/* + * tree.c : implementation of access function for an XML tree. + * + * References: + * XHTML 1.0 W3C REC: http://www.w3.org/TR/2002/REC-xhtml1-20020801/ + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + * + */ + +#define IN_LIBXML +#include "libxml.h" + +#include /* for memset() only ! */ +#include +#ifdef HAVE_CTYPE_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_ZLIB_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef LIBXML_DEBUG_ENABLED +#include +#endif + +int __xmlRegisterCallbacks = 0; + +/************************************************************************ + * * + * Forward declarations * + * * + ************************************************************************/ + +static xmlNsPtr +xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns); + +static xmlChar* xmlGetPropNodeValueInternal(xmlAttrPtr prop); + +/************************************************************************ + * * + * Tree memory error handler * + * * + ************************************************************************/ +/** + * xmlTreeErrMemory: + * @extra: extra informations + * + * Handle an out of memory condition + */ +static void +xmlTreeErrMemory(const char *extra) +{ + __xmlSimpleError(XML_FROM_TREE, XML_ERR_NO_MEMORY, NULL, NULL, extra); +} + +/** + * xmlTreeErr: + * @code: the error number + * @extra: extra informations + * + * 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); +} + +/************************************************************************ + * * + * A few static variables and macros * + * * + ************************************************************************/ +/* #undef xmlStringText */ +const xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 }; +/* #undef xmlStringTextNoenc */ +const xmlChar xmlStringTextNoenc[] = + { 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 }; +/* #undef xmlStringComment */ +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)) + +/* #define DEBUG_BUFFER */ +/* #define DEBUG_TREE */ + +/************************************************************************ + * * + * Functions to move to entities.c once the * + * API freeze is smoothen and they can be made public. * + * * + ************************************************************************/ +#include + +#ifdef LIBXML_TREE_ENABLED +/** + * xmlGetEntityFromDtd: + * @dtd: A pointer to the DTD to search + * @name: The entity name + * + * Do an entity lookup in the DTD entity hash table and + * return the corresponding entity, if found. + * + * Returns A pointer to the entity structure or NULL if not found. + */ +static xmlEntityPtr +xmlGetEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) { + xmlEntitiesTablePtr table; + + if((dtd != NULL) && (dtd->entities != NULL)) { + table = (xmlEntitiesTablePtr) dtd->entities; + return((xmlEntityPtr) xmlHashLookup(table, name)); + /* return(xmlGetEntityFromTable(table, name)); */ + } + return(NULL); +} +/** + * xmlGetParameterEntityFromDtd: + * @dtd: A pointer to the DTD to search + * @name: The entity name + * + * Do an entity lookup in the DTD pararmeter entity hash table and + * return the corresponding entity, if found. + * + * Returns A pointer to the entity structure or NULL if not found. + */ +static xmlEntityPtr +xmlGetParameterEntityFromDtd(xmlDtdPtr dtd, const xmlChar *name) { + xmlEntitiesTablePtr table; + + if ((dtd != NULL) && (dtd->pentities != NULL)) { + table = (xmlEntitiesTablePtr) dtd->pentities; + return((xmlEntityPtr) xmlHashLookup(table, name)); + /* return(xmlGetEntityFromTable(table, name)); */ + } + return(NULL); +} +#endif /* LIBXML_TREE_ENABLED */ + +/************************************************************************ + * * + * QName handling helper * + * * + ************************************************************************/ + +/** + * xmlBuildQName: + * @ncname: the Name + * @prefix: the prefix + * @memory: preallocated memory + * @len: preallocated memory length + * + * Builds the QName @prefix:@ncname in @memory if there is enough space + * and prefix is not NULL nor empty, otherwise allocate a new string. + * If prefix is NULL or empty it returns ncname. + * + * Returns the new string which must be freed by the caller if different from + * @memory and @ncname or NULL in case of error + */ +xmlChar * +xmlBuildQName(const xmlChar *ncname, const xmlChar *prefix, + xmlChar *memory, int len) { + int lenn, lenp; + xmlChar *ret; + + if (ncname == NULL) return(NULL); + if (prefix == NULL) return((xmlChar *) ncname); + + 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"); + return(NULL); + } + } else { + ret = memory; + } + memcpy(&ret[0], prefix, lenp); + ret[lenp] = ':'; + memcpy(&ret[lenp + 1], ncname, lenn); + ret[lenn + lenp + 1] = 0; + return(ret); +} + +/** + * xmlSplitQName2: + * @name: the full QName + * @prefix: a xmlChar ** + * + * parse an XML qualified name string + * + * [NS 5] QName ::= (Prefix ':')? LocalPart + * + * [NS 6] Prefix ::= NCName + * + * [NS 7] LocalPart ::= NCName + * + * Returns NULL if not a QName, otherwise the local part, and prefix + * is updated to get the Prefix if any. + */ + +xmlChar * +xmlSplitQName2(const xmlChar *name, xmlChar **prefix) { + int len = 0; + xmlChar *ret = NULL; + + if (prefix == NULL) return(NULL); + *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); + + /* + * 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[len] != 0) && (name[len] != ':')) + len++; + + if (name[len] == 0) + return(NULL); + + *prefix = xmlStrndup(name, len); + if (*prefix == NULL) { + xmlTreeErrMemory("QName split"); + return(NULL); + } + ret = xmlStrdup(&name[len + 1]); + if (ret == NULL) { + xmlTreeErrMemory("QName split"); + if (*prefix != NULL) { + xmlFree(*prefix); + *prefix = NULL; + } + return(NULL); + } + + return(ret); +} + +/** + * xmlSplitQName3: + * @name: the full QName + * @len: an int * + * + * parse an XML qualified name string,i + * + * returns NULL if it is not a Qualified Name, otherwise, update len + * with the lenght in byte of the prefix and return a pointer + * to the start of the name without the prefix + */ + +const xmlChar * +xmlSplitQName3(const xmlChar *name, int *len) { + int l = 0; + + if (name == NULL) return(NULL); + if (len == NULL) return(NULL); + + /* nasty but valid */ + if (name[0] == ':') + return(NULL); + + /* + * 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++; + + if (name[l] == 0) + return(NULL); + + *len = l; + + return(&name[l+1]); +} + +/************************************************************************ + * * + * Check Name, NCName and QName strings * + * * + ************************************************************************/ + +#define CUR_SCHAR(s, l) xmlStringCurrentChar(NULL, s, &l) + +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_DEBUG_ENABLED) || defined(LIBXML_SAX1_ENABLED) || defined(LIBXML_WRITER_ENABLED) || defined(LIBXML_DOCB_ENABLED) +/** + * xmlValidateNCName: + * @value: the value to check + * @space: allow spaces in front and end of the string + * + * Check that a value conforms to the lexical space of NCName + * + * Returns 0 if this validates, a positive error code number otherwise + * and -1 in case of internal or API error. + */ +int +xmlValidateNCName(const xmlChar *value, int space) { + const xmlChar *cur = value; + int c,l; + + if (value == NULL) + return(-1); + + /* + * First quick algorithm for ASCII range + */ + if (space) + while (IS_BLANK_CH(*cur)) cur++; + if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) || + (*cur == '_')) + cur++; + else + goto try_complex; + while (((*cur >= 'a') && (*cur <= 'z')) || + ((*cur >= 'A') && (*cur <= 'Z')) || + ((*cur >= '0') && (*cur <= '9')) || + (*cur == '_') || (*cur == '-') || (*cur == '.')) + cur++; + if (space) + while (IS_BLANK_CH(*cur)) cur++; + if (*cur == 0) + return(0); + +try_complex: + /* + * Second check for chars outside the ASCII range + */ + cur = value; + c = CUR_SCHAR(cur, l); + if (space) { + while (IS_BLANK(c)) { + cur += l; + c = CUR_SCHAR(cur, l); + } + } + if ((!IS_LETTER(c)) && (c != '_')) + return(1); + cur += l; + c = CUR_SCHAR(cur, l); + while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || + (c == '-') || (c == '_') || IS_COMBINING(c) || + IS_EXTENDER(c)) { + cur += l; + c = CUR_SCHAR(cur, l); + } + if (space) { + while (IS_BLANK(c)) { + cur += l; + c = CUR_SCHAR(cur, l); + } + } + if (c != 0) + return(1); + + return(0); +} +#endif + +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) +/** + * xmlValidateQName: + * @value: the value to check + * @space: allow spaces in front and end of the string + * + * Check that a value conforms to the lexical space of QName + * + * Returns 0 if this validates, a positive error code number otherwise + * and -1 in case of internal or API error. + */ +int +xmlValidateQName(const xmlChar *value, int space) { + const xmlChar *cur = value; + int c,l; + + if (value == NULL) + return(-1); + /* + * First quick algorithm for ASCII range + */ + if (space) + while (IS_BLANK_CH(*cur)) cur++; + if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) || + (*cur == '_')) + cur++; + else + goto try_complex; + while (((*cur >= 'a') && (*cur <= 'z')) || + ((*cur >= 'A') && (*cur <= 'Z')) || + ((*cur >= '0') && (*cur <= '9')) || + (*cur == '_') || (*cur == '-') || (*cur == '.')) + cur++; + if (*cur == ':') { + cur++; + if (((*cur >= 'a') && (*cur <= 'z')) || + ((*cur >= 'A') && (*cur <= 'Z')) || + (*cur == '_')) + cur++; + else + goto try_complex; + while (((*cur >= 'a') && (*cur <= 'z')) || + ((*cur >= 'A') && (*cur <= 'Z')) || + ((*cur >= '0') && (*cur <= '9')) || + (*cur == '_') || (*cur == '-') || (*cur == '.')) + cur++; + } + if (space) + while (IS_BLANK_CH(*cur)) cur++; + if (*cur == 0) + return(0); + +try_complex: + /* + * Second check for chars outside the ASCII range + */ + cur = value; + c = CUR_SCHAR(cur, l); + if (space) { + while (IS_BLANK(c)) { + cur += l; + c = CUR_SCHAR(cur, l); + } + } + if ((!IS_LETTER(c)) && (c != '_')) + return(1); + cur += l; + c = CUR_SCHAR(cur, l); + while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || + (c == '-') || (c == '_') || IS_COMBINING(c) || + IS_EXTENDER(c)) { + cur += l; + c = CUR_SCHAR(cur, l); + } + if (c == ':') { + cur += l; + c = CUR_SCHAR(cur, l); + if ((!IS_LETTER(c)) && (c != '_')) + return(1); + cur += l; + c = CUR_SCHAR(cur, l); + while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || + (c == '-') || (c == '_') || IS_COMBINING(c) || + IS_EXTENDER(c)) { + cur += l; + c = CUR_SCHAR(cur, l); + } + } + if (space) { + while (IS_BLANK(c)) { + cur += l; + c = CUR_SCHAR(cur, l); + } + } + if (c != 0) + return(1); + return(0); +} + +/** + * xmlValidateName: + * @value: the value to check + * @space: allow spaces in front and end of the string + * + * Check that a value conforms to the lexical space of Name + * + * Returns 0 if this validates, a positive error code number otherwise + * and -1 in case of internal or API error. + */ +int +xmlValidateName(const xmlChar *value, int space) { + const xmlChar *cur = value; + int c,l; + + if (value == NULL) + return(-1); + /* + * First quick algorithm for ASCII range + */ + if (space) + while (IS_BLANK_CH(*cur)) cur++; + if (((*cur >= 'a') && (*cur <= 'z')) || ((*cur >= 'A') && (*cur <= 'Z')) || + (*cur == '_') || (*cur == ':')) + cur++; + else + goto try_complex; + while (((*cur >= 'a') && (*cur <= 'z')) || + ((*cur >= 'A') && (*cur <= 'Z')) || + ((*cur >= '0') && (*cur <= '9')) || + (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':')) + cur++; + if (space) + while (IS_BLANK_CH(*cur)) cur++; + if (*cur == 0) + return(0); + +try_complex: + /* + * Second check for chars outside the ASCII range + */ + cur = value; + c = CUR_SCHAR(cur, l); + if (space) { + while (IS_BLANK(c)) { + cur += l; + c = CUR_SCHAR(cur, l); + } + } + if ((!IS_LETTER(c)) && (c != '_') && (c != ':')) + return(1); + cur += l; + c = CUR_SCHAR(cur, l); + while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') || + (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) { + cur += l; + c = CUR_SCHAR(cur, l); + } + if (space) { + while (IS_BLANK(c)) { + cur += l; + c = CUR_SCHAR(cur, l); + } + } + if (c != 0) + return(1); + return(0); +} + +/** + * xmlValidateNMToken: + * @value: the value to check + * @space: allow spaces in front and end of the string + * + * Check that a value conforms to the lexical space of NMToken + * + * Returns 0 if this validates, a positive error code number otherwise + * and -1 in case of internal or API error. + */ +int +xmlValidateNMToken(const xmlChar *value, int space) { + const xmlChar *cur = value; + int c,l; + + if (value == NULL) + return(-1); + /* + * First quick algorithm for ASCII range + */ + if (space) + while (IS_BLANK_CH(*cur)) cur++; + if (((*cur >= 'a') && (*cur <= 'z')) || + ((*cur >= 'A') && (*cur <= 'Z')) || + ((*cur >= '0') && (*cur <= '9')) || + (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':')) + cur++; + else + goto try_complex; + while (((*cur >= 'a') && (*cur <= 'z')) || + ((*cur >= 'A') && (*cur <= 'Z')) || + ((*cur >= '0') && (*cur <= '9')) || + (*cur == '_') || (*cur == '-') || (*cur == '.') || (*cur == ':')) + cur++; + if (space) + while (IS_BLANK_CH(*cur)) cur++; + if (*cur == 0) + return(0); + +try_complex: + /* + * Second check for chars outside the ASCII range + */ + cur = value; + c = CUR_SCHAR(cur, l); + if (space) { + while (IS_BLANK(c)) { + cur += l; + c = CUR_SCHAR(cur, l); + } + } + if (!(IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') || + (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c))) + return(1); + cur += l; + c = CUR_SCHAR(cur, l); + while (IS_LETTER(c) || IS_DIGIT(c) || (c == '.') || (c == ':') || + (c == '-') || (c == '_') || IS_COMBINING(c) || IS_EXTENDER(c)) { + cur += l; + c = CUR_SCHAR(cur, l); + } + if (space) { + while (IS_BLANK(c)) { + cur += l; + c = CUR_SCHAR(cur, l); + } + } + if (c != 0) + return(1); + return(0); +} +#endif /* LIBXML_TREE_ENABLED */ + +/************************************************************************ + * * + * Allocation and deallocation of basic structures * + * * + ************************************************************************/ + +/** + * xmlSetBufferAllocationScheme: + * @scheme: allocation method to use + * + * Set the buffer allocation method. Types are + * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down + * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed, + * improves performance + */ +void +xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) { + if ((scheme == XML_BUFFER_ALLOC_EXACT) || + (scheme == XML_BUFFER_ALLOC_DOUBLEIT)) + xmlBufferAllocScheme = scheme; +} + +/** + * xmlGetBufferAllocationScheme: + * + * Types are + * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down + * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed, + * improves performance + * + * Returns the current allocation scheme + */ +xmlBufferAllocationScheme +xmlGetBufferAllocationScheme(void) { + return(xmlBufferAllocScheme); +} + +/** + * xmlNewNs: + * @node: the element carrying the namespace + * @href: the URI associated + * @prefix: the prefix for the namespace + * + * 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. + * We use href==NULL in the case of an element creation where the namespace + * was not defined. + * Returns a new namespace pointer or NULL + */ +xmlNsPtr +xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) { + xmlNsPtr cur; + + 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"); + return(NULL); + } + memset(cur, 0, sizeof(xmlNs)); + cur->type = XML_LOCAL_NAMESPACE; + + if (href != NULL) + cur->href = xmlStrdup(href); + if (prefix != NULL) + cur->prefix = xmlStrdup(prefix); + + /* + * Add it at the end to preserve parsing order ... + * and checks for existing use of the prefix + */ + if (node != NULL) { + if (node->nsDef == NULL) { + node->nsDef = cur; + } else { + xmlNsPtr prev = node->nsDef; + + if (((prev->prefix == NULL) && (cur->prefix == NULL)) || + (xmlStrEqual(prev->prefix, cur->prefix))) { + xmlFreeNs(cur); + return(NULL); + } + while (prev->next != NULL) { + prev = prev->next; + if (((prev->prefix == NULL) && (cur->prefix == NULL)) || + (xmlStrEqual(prev->prefix, cur->prefix))) { + xmlFreeNs(cur); + return(NULL); + } + } + prev->next = cur; + } + } + return(cur); +} + +/** + * xmlSetNs: + * @node: a node in the document + * @ns: a namespace pointer + * + * Associate a namespace to a node, a posteriori. + */ +void +xmlSetNs(xmlNodePtr node, xmlNsPtr ns) { + if (node == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlSetNs: node == NULL\n"); +#endif + return; + } + node->ns = ns; +} + +/** + * xmlFreeNs: + * @cur: the namespace pointer + * + * Free up the structures associated to a namespace + */ +void +xmlFreeNs(xmlNsPtr cur) { + if (cur == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlFreeNs : ns == NULL\n"); +#endif + return; + } + if (cur->href != NULL) xmlFree((char *) cur->href); + if (cur->prefix != NULL) xmlFree((char *) cur->prefix); + xmlFree(cur); +} + +/** + * xmlFreeNsList: + * @cur: the first namespace pointer + * + * Free up all the structures associated to the chained namespaces. + */ +void +xmlFreeNsList(xmlNsPtr cur) { + xmlNsPtr next; + if (cur == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlFreeNsList : ns == NULL\n"); +#endif + return; + } + while (cur != NULL) { + next = cur->next; + xmlFreeNs(cur); + cur = next; + } +} + +/** + * xmlNewDtd: + * @doc: the document pointer + * @name: the DTD name + * @ExternalID: the external ID + * @SystemID: the system ID + * + * Creation of a new DTD for the external subset. To create an + * internal subset, use xmlCreateIntSubset(). + * + * Returns a pointer to the new DTD structure + */ +xmlDtdPtr +xmlNewDtd(xmlDocPtr doc, const xmlChar *name, + const xmlChar *ExternalID, const xmlChar *SystemID) { + xmlDtdPtr cur; + + if ((doc != NULL) && (doc->extSubset != NULL)) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlNewDtd(%s): document %s already have a DTD %s\n", + /* !!! */ (char *) name, doc->name, + /* !!! */ (char *)doc->extSubset->name); +#endif + return(NULL); + } + + /* + * Allocate a new DTD and fill the fields. + */ + cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd)); + if (cur == NULL) { + xmlTreeErrMemory("building DTD"); + return(NULL); + } + memset(cur, 0 , sizeof(xmlDtd)); + cur->type = XML_DTD_NODE; + + if (name != NULL) + cur->name = xmlStrdup(name); + if (ExternalID != NULL) + cur->ExternalID = xmlStrdup(ExternalID); + if (SystemID != NULL) + cur->SystemID = xmlStrdup(SystemID); + if (doc != NULL) + doc->extSubset = cur; + cur->doc = doc; + + if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) + xmlRegisterNodeDefaultValue((xmlNodePtr)cur); + return(cur); +} + +/** + * xmlGetIntSubset: + * @doc: the document pointer + * + * Get the internal subset of a document + * Returns a pointer to the DTD structure or NULL if not found + */ + +xmlDtdPtr +xmlGetIntSubset(xmlDocPtr doc) { + xmlNodePtr cur; + + if (doc == NULL) + return(NULL); + cur = doc->children; + while (cur != NULL) { + if (cur->type == XML_DTD_NODE) + return((xmlDtdPtr) cur); + cur = cur->next; + } + return((xmlDtdPtr) doc->intSubset); +} + +/** + * xmlCreateIntSubset: + * @doc: the document pointer + * @name: the DTD name + * @ExternalID: the external (PUBLIC) ID + * @SystemID: the system ID + * + * Create the internal subset of a document + * Returns a pointer to the new DTD structure + */ +xmlDtdPtr +xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name, + const xmlChar *ExternalID, const xmlChar *SystemID) { + xmlDtdPtr cur; + + if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + + "xmlCreateIntSubset(): document %s already have an internal subset\n", + doc->name); +#endif + return(NULL); + } + + /* + * Allocate a new DTD and fill the fields. + */ + cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd)); + if (cur == NULL) { + xmlTreeErrMemory("building internal subset"); + 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 (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 (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 (doc != NULL) { + doc->intSubset = cur; + cur->parent = doc; + cur->doc = doc; + if (doc->children == NULL) { + doc->children = (xmlNodePtr) cur; + doc->last = (xmlNodePtr) cur; + } else { + if (doc->type == XML_HTML_DOCUMENT_NODE) { + xmlNodePtr prev; + + prev = doc->children; + prev->prev = (xmlNodePtr) cur; + cur->next = prev; + doc->children = (xmlNodePtr) cur; + } else { + xmlNodePtr next; + + next = doc->children; + while ((next != NULL) && (next->type != XML_ELEMENT_NODE)) + next = next->next; + if (next == NULL) { + cur->prev = doc->last; + cur->prev->next = (xmlNodePtr) cur; + cur->next = NULL; + doc->last = (xmlNodePtr) cur; + } else { + cur->next = next; + cur->prev = next->prev; + if (cur->prev == NULL) + doc->children = (xmlNodePtr) cur; + else + cur->prev->next = (xmlNodePtr) cur; + next->prev = (xmlNodePtr) cur; + } + } + } + } + + if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) + xmlRegisterNodeDefaultValue((xmlNodePtr)cur); + return(cur); +} + +/** + * DICT_FREE: + * @str: a string + * + * Free a string if it is not owned by the "dict" dictionnary in the + * current scope + */ +#define DICT_FREE(str) \ + if ((str) && ((!dict) || \ + (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \ + xmlFree((char *)(str)); + + +/** + * DICT_COPY: + * @str: a string + * + * Copy a string using a "dict" dictionnary in the current scope, + * if availabe. + */ +#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" dictionnary in the current scope, + * if availabe. + */ +#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 + * + * Free a DTD structure. + */ +void +xmlFreeDtd(xmlDtdPtr cur) { + xmlDictPtr dict = NULL; + + if (cur == NULL) { + return; + } + if (cur->doc != NULL) dict = cur->doc->dict; + + if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue)) + xmlDeregisterNodeDefaultValue((xmlNodePtr)cur); + + if (cur->children != NULL) { + xmlNodePtr next, c = cur->children; + + /* + * Cleanup all nodes which are not part of the specific lists + * of notations, elements, attributes and entities. + */ + while (c != NULL) { + next = c->next; + if ((c->type != XML_NOTATION_NODE) && + (c->type != XML_ELEMENT_DECL) && + (c->type != XML_ATTRIBUTE_DECL) && + (c->type != XML_ENTITY_DECL)) { + xmlUnlinkNode(c); + xmlFreeNode(c); + } + c = next; + } + } + DICT_FREE(cur->name) + DICT_FREE(cur->SystemID) + DICT_FREE(cur->ExternalID) + /* TODO !!! */ + if (cur->notations != NULL) + xmlFreeNotationTable((xmlNotationTablePtr) cur->notations); + + if (cur->elements != NULL) + xmlFreeElementTable((xmlElementTablePtr) cur->elements); + if (cur->attributes != NULL) + xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes); + if (cur->entities != NULL) + xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities); + if (cur->pentities != NULL) + xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities); + + xmlFree(cur); +} + +/** + * xmlNewDoc: + * @version: xmlChar string giving the version of XML "1.0" + * + * Creates a new XML document + * + * Returns a new document + */ +xmlDocPtr +xmlNewDoc(const xmlChar *version) { + xmlDocPtr cur; + + if (version == NULL) + version = (const xmlChar *) "1.0"; + + /* + * Allocate a new document and fill the fields. + */ + cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc)); + if (cur == NULL) { + xmlTreeErrMemory("building doc"); + 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); + } + cur->standalone = -1; + cur->compression = -1; /* not initialized */ + cur->doc = cur; + cur->parseFlags = 0; + cur->properties = XML_DOC_USERBUILT; + /* + * The in memory encoding is always UTF8 + * This field will never change and would + * be obsolete if not for binary compatibility. + */ + cur->charset = XML_CHAR_ENCODING_UTF8; + + if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) + xmlRegisterNodeDefaultValue((xmlNodePtr)cur); + return(cur); +} + +/** + * xmlFreeDoc: + * @cur: pointer to the document + * + * Free up all the structures used by a document, tree included. + */ +void +xmlFreeDoc(xmlDocPtr cur) { + xmlDtdPtr extSubset, intSubset; + xmlDictPtr dict = NULL; + + if (cur == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlFreeDoc : document == NULL\n"); +#endif + return; + } +#ifdef LIBXML_DEBUG_RUNTIME +#ifdef LIBXML_DEBUG_ENABLED + xmlDebugCheckDocument(stderr, cur); +#endif +#endif + + if (cur != NULL) dict = cur->dict; + + if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue)) + xmlDeregisterNodeDefaultValue((xmlNodePtr)cur); + + /* + * Do this before freeing the children list to avoid ID lookups + */ + if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids); + cur->ids = NULL; + if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs); + cur->refs = NULL; + extSubset = cur->extSubset; + intSubset = cur->intSubset; + if (intSubset == extSubset) + extSubset = NULL; + if (extSubset != NULL) { + xmlUnlinkNode((xmlNodePtr) cur->extSubset); + cur->extSubset = NULL; + xmlFreeDtd(extSubset); + } + if (intSubset != NULL) { + xmlUnlinkNode((xmlNodePtr) cur->intSubset); + cur->intSubset = NULL; + xmlFreeDtd(intSubset); + } + + if (cur->children != NULL) xmlFreeNodeList(cur->children); + if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs); + + DICT_FREE(cur->version) + DICT_FREE(cur->name) + DICT_FREE(cur->encoding) + DICT_FREE(cur->URL) + xmlFree(cur); + if (dict) xmlDictFree(dict); +} + +/** + * xmlStringLenGetNodeList: + * @doc: the document + * @value: the value of the text + * @len: the length of the string value + * + * 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 + */ +xmlNodePtr +xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) { + xmlNodePtr ret = NULL, last = NULL; + xmlNodePtr node; + xmlChar *val; + const xmlChar *cur = value, *end = cur + len; + const xmlChar *q; + xmlEntityPtr ent; + + if (value == NULL) return(NULL); + + q = cur; + while ((cur < end) && (*cur != 0)) { + if (cur[0] == '&') { + int charval = 0; + xmlChar tmp; + + /* + * Save the current text. + */ + if (cur != q) { + if ((last != NULL) && (last->type == XML_TEXT_NODE)) { + xmlNodeAddContentLen(last, q, cur - q); + } else { + node = xmlNewDocTextLen(doc, q, cur - q); + if (node == NULL) return(ret); + if (last == NULL) + last = ret = node; + else { + last->next = node; + node->prev = last; + last = node; + } + } + } + q = cur; + if ((cur + 2 < end) && (cur[1] == '#') && (cur[2] == 'x')) { + cur += 3; + if (cur < end) + tmp = *cur; + else + tmp = 0; + while (tmp != ';') { /* Non input consuming loop */ + 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++; + if (cur < end) + tmp = *cur; + else + tmp = 0; + } + if (tmp == ';') + cur++; + q = cur; + } else if ((cur + 1 < end) && (cur[1] == '#')) { + cur += 2; + if (cur < end) + tmp = *cur; + else + tmp = 0; + while (tmp != ';') { /* Non input consuming loops */ + if ((tmp >= '0') && (tmp <= '9')) + charval = charval * 10 + (tmp - '0'); + else { + xmlTreeErr(XML_TREE_INVALID_DEC, (xmlNodePtr) doc, + NULL); + charval = 0; + break; + } + cur++; + if (cur < end) + tmp = *cur; + else + tmp = 0; + } + if (tmp == ';') + cur++; + q = cur; + } else { + /* + * Read the entity string + */ + cur++; + q = cur; + while ((cur < end) && (*cur != 0) && (*cur != ';')) cur++; + if ((cur >= end) || (*cur == 0)) { + xmlTreeErr(XML_TREE_UNTERMINATED_ENTITY, (xmlNodePtr) doc, + (const char *) q); + return(ret); + } + 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 (last == NULL) { + node = xmlNewDocText(doc, ent->content); + last = ret = node; + } else if (last->type != XML_TEXT_NODE) { + node = xmlNewDocText(doc, ent->content); + last = xmlAddNextSibling(last, node); + } else + xmlNodeAddContent(last, ent->content); + + } else { + /* + * Create a new REFERENCE_REF node + */ + node = xmlNewReference(doc, val); + if (node == NULL) { + if (val != NULL) xmlFree(val); + return(ret); + } + else if ((ent != NULL) && (ent->children == NULL)) { + xmlNodePtr temp; + + ent->children = xmlStringGetNodeList(doc, + (const xmlChar*)node->content); + ent->owner = 1; + temp = ent->children; + while (temp) { + temp->parent = (xmlNodePtr)ent; + ent->last = temp; + temp = temp->next; + } + } + if (last == NULL) { + last = ret = node; + } else { + last = xmlAddNextSibling(last, node); + } + } + xmlFree(val); + } + cur++; + q = cur; + } + if (charval != 0) { + xmlChar buf[10]; + int l; + + l = xmlCopyCharMultiByte(buf, charval); + buf[l] = 0; + node = xmlNewDocText(doc, buf); + if (node != NULL) { + if (last == NULL) { + last = ret = node; + } else { + last = xmlAddNextSibling(last, node); + } + } + charval = 0; + } + } else + cur++; + } + if ((cur != q) || (ret == NULL)) { + /* + * Handle the last piece of text. + */ + if ((last != NULL) && (last->type == XML_TEXT_NODE)) { + xmlNodeAddContentLen(last, q, cur - q); + } else { + node = xmlNewDocTextLen(doc, q, cur - q); + if (node == NULL) return(ret); + if (last == NULL) { + ret = node; + } else { + xmlAddNextSibling(last, node); + } + } + } + return(ret); +} + +/** + * xmlStringGetNodeList: + * @doc: the document + * @value: the value of the attribute + * + * 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 + */ +xmlNodePtr +xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) { + xmlNodePtr ret = NULL, last = NULL; + xmlNodePtr node; + xmlChar *val; + const xmlChar *cur = value; + const xmlChar *q; + xmlEntityPtr ent; + + if (value == NULL) return(NULL); + + q = cur; + while (*cur != 0) { + if (cur[0] == '&') { + int charval = 0; + xmlChar tmp; + + /* + * Save the current text. + */ + if (cur != q) { + if ((last != NULL) && (last->type == XML_TEXT_NODE)) { + xmlNodeAddContentLen(last, q, cur - q); + } else { + node = xmlNewDocTextLen(doc, q, cur - q); + if (node == NULL) return(ret); + if (last == NULL) + last = ret = node; + else { + last->next = node; + node->prev = last; + last = node; + } + } + } + q = cur; + if ((cur[1] == '#') && (cur[2] == 'x')) { + cur += 3; + tmp = *cur; + while (tmp != ';') { /* Non input consuming loop */ + 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 */ + 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); + return(ret); + } + 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 (last == NULL) { + node = xmlNewDocText(doc, ent->content); + last = ret = node; + } else if (last->type != XML_TEXT_NODE) { + node = xmlNewDocText(doc, ent->content); + last = xmlAddNextSibling(last, node); + } else + xmlNodeAddContent(last, ent->content); + + } else { + /* + * Create a new REFERENCE_REF node + */ + node = xmlNewReference(doc, val); + if (node == NULL) { + if (val != NULL) xmlFree(val); + return(ret); + } + else if ((ent != NULL) && (ent->children == NULL)) { + xmlNodePtr temp; + + ent->children = xmlStringGetNodeList(doc, + (const xmlChar*)node->content); + ent->owner = 1; + temp = ent->children; + while (temp) { + temp->parent = (xmlNodePtr)ent; + temp = temp->next; + } + } + if (last == NULL) { + last = ret = node; + } else { + last = xmlAddNextSibling(last, node); + } + } + xmlFree(val); + } + cur++; + q = cur; + } + if (charval != 0) { + xmlChar buf[10]; + int len; + + len = xmlCopyCharMultiByte(buf, charval); + buf[len] = 0; + node = xmlNewDocText(doc, buf); + if (node != NULL) { + if (last == NULL) { + last = ret = node; + } else { + last = xmlAddNextSibling(last, node); + } + } + } + } else + cur++; + } + if ((cur != q) || (ret == NULL)) { + /* + * Handle the last piece of text. + */ + if ((last != NULL) && (last->type == XML_TEXT_NODE)) { + xmlNodeAddContentLen(last, q, cur - q); + } else { + node = xmlNewDocTextLen(doc, q, cur - q); + if (node == NULL) return(ret); + if (last == NULL) { + last = ret = node; + } else { + last = xmlAddNextSibling(last, node); + } + } + } + return(ret); +} + +/** + * xmlNodeListGetString: + * @doc: the document + * @list: a Node list + * @inLine: should we replace entity contents or show their external form + * + * Build the string equivalent to the text contained in the Node list + * made of TEXTs and ENTITY_REFs + * + * Returns a pointer to the string copy, the caller must free it with xmlFree(). + */ +xmlChar * +xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine) +{ + xmlNodePtr node = list; + xmlChar *ret = NULL; + xmlEntityPtr ent; + + 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; + + 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; + } + return (ret); +} + +#ifdef LIBXML_TREE_ENABLED +/** + * xmlNodeListGetRawString: + * @doc: the document + * @list: a Node list + * @inLine: should we replace entity contents or show their external form + * + * 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. + * + * Returns a pointer to the string copy, the caller must free it with xmlFree(). + */ +xmlChar * +xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine) +{ + xmlNodePtr node = list; + xmlChar *ret = NULL; + xmlEntityPtr ent; + + 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; + + 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); +} +#endif /* LIBXML_TREE_ENABLED */ + +static xmlAttrPtr +xmlNewPropInternal(xmlNodePtr node, xmlNsPtr ns, + const xmlChar * name, const xmlChar * value, + int eatname) +{ + xmlAttrPtr cur; + xmlDocPtr doc = NULL; + + if ((node != NULL) && (node->type != XML_ELEMENT_NODE)) { + if ((eatname == 1) && + ((node->doc == NULL) || + (!(xmlDictOwns(node->doc->dict, name))))) + xmlFree((xmlChar *) name); + return (NULL); + } + + /* + * Allocate a new property and fill the fields. + */ + cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr)); + if (cur == NULL) { + if ((eatname == 1) && + ((node == NULL) || (node->doc == NULL) || + (!(xmlDictOwns(node->doc->dict, name))))) + xmlFree((xmlChar *) name); + xmlTreeErrMemory("building attribute"); + return (NULL); + } + memset(cur, 0, sizeof(xmlAttr)); + cur->type = XML_ATTRIBUTE_NODE; + + cur->parent = node; + if (node != NULL) { + doc = node->doc; + cur->doc = doc; + } + cur->ns = ns; + + if (eatname == 0) { + if ((doc != NULL) && (doc->dict != NULL)) + cur->name = (xmlChar *) xmlDictLookup(doc->dict, name, -1); + else + cur->name = xmlStrdup(name); + } else + cur->name = name; + + if (value != NULL) { + xmlNodePtr tmp; + + if(!xmlCheckUTF8(value)) { + xmlTreeErr(XML_TREE_NOT_UTF8, (xmlNodePtr) doc, + NULL); + if (doc != NULL) + doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1"); + } + cur->children = xmlNewDocText(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; + } + } + + /* + * Add it at the end to preserve parsing order ... + */ + if (node != NULL) { + if (node->properties == NULL) { + node->properties = cur; + } else { + xmlAttrPtr prev = node->properties; + + while (prev->next != NULL) + prev = prev->next; + prev->next = cur; + cur->prev = prev; + } + } + + 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); +} + +#if defined(LIBXML_TREE_ENABLED) || \ + defined(LIBXML_SCHEMAS_ENABLED) +/** + * xmlNewProp: + * @node: the holding node + * @name: the name of the attribute + * @value: the value of the attribute + * + * Create a new property carried by a node. + * Returns a pointer to the attribute + */ +xmlAttrPtr +xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) { + + if (name == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlNewProp : name == NULL\n"); +#endif + return(NULL); + } + + return xmlNewPropInternal(node, NULL, name, value, 0); +} +#endif /* LIBXML_TREE_ENABLED */ + +/** + * xmlNewNsProp: + * @node: the holding node + * @ns: the namespace + * @name: the name of the attribute + * @value: the value of the attribute + * + * Create a new property tagged with a namespace and carried by a node. + * Returns a pointer to the attribute + */ +xmlAttrPtr +xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name, + const xmlChar *value) { + + if (name == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlNewNsProp : name == NULL\n"); +#endif + return(NULL); + } + + return xmlNewPropInternal(node, ns, name, value, 0); +} + +/** + * xmlNewNsPropEatName: + * @node: the holding node + * @ns: the namespace + * @name: the name of the attribute + * @value: the value of the attribute + * + * Create a new property tagged with a namespace and carried by a node. + * Returns a pointer to the attribute + */ +xmlAttrPtr +xmlNewNsPropEatName(xmlNodePtr node, xmlNsPtr ns, xmlChar *name, + const xmlChar *value) { + + if (name == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlNewNsPropEatName : name == NULL\n"); +#endif + return(NULL); + } + + return xmlNewPropInternal(node, ns, name, value, 1); +} + +/** + * xmlNewDocProp: + * @doc: the document + * @name: the name of the attribute + * @value: the value of the attribute + * + * Create a new property carried by a document. + * Returns a pointer to the attribute + */ +xmlAttrPtr +xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) { + xmlAttrPtr cur; + + if (name == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlNewDocProp : name == NULL\n"); +#endif + return(NULL); + } + + /* + * Allocate a new property and fill the fields. + */ + cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr)); + if (cur == NULL) { + xmlTreeErrMemory("building attribute"); + return(NULL); + } + memset(cur, 0, sizeof(xmlAttr)); + cur->type = XML_ATTRIBUTE_NODE; + + if ((doc != NULL) && (doc->dict != NULL)) + cur->name = xmlDictLookup(doc->dict, name, -1); + else + cur->name = xmlStrdup(name); + 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 ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) + xmlRegisterNodeDefaultValue((xmlNodePtr)cur); + return(cur); +} + +/** + * xmlFreePropList: + * @cur: the first property in the list + * + * Free a property and all its siblings, all the children are freed too. + */ +void +xmlFreePropList(xmlAttrPtr cur) { + xmlAttrPtr next; + if (cur == NULL) return; + while (cur != NULL) { + next = cur->next; + xmlFreeProp(cur); + cur = next; + } +} + +/** + * xmlFreeProp: + * @cur: an attribute + * + * Free one attribute, all the content is freed too + */ +void +xmlFreeProp(xmlAttrPtr cur) { + xmlDictPtr dict = NULL; + if (cur == NULL) return; + + if (cur->doc != NULL) dict = cur->doc->dict; + + if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue)) + xmlDeregisterNodeDefaultValue((xmlNodePtr)cur); + + /* Check for ID removal -> leading to invalid references ! */ + if ((cur->doc != NULL) && (cur->atype == XML_ATTRIBUTE_ID)) { + xmlRemoveID(cur->doc, cur); + } + if (cur->children != NULL) xmlFreeNodeList(cur->children); + DICT_FREE(cur->name) + xmlFree(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 + * + * Returns 0 if success and -1 in case of error. + */ +int +xmlRemoveProp(xmlAttrPtr cur) { + xmlAttrPtr tmp; + if (cur == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlRemoveProp : cur == NULL\n"); +#endif + return(-1); + } + if (cur->parent == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlRemoveProp : cur->parent == NULL\n"); +#endif + return(-1); + } + tmp = cur->parent->properties; + if (tmp == cur) { + cur->parent->properties = cur->next; + if (cur->next != NULL) + cur->next->prev = NULL; + xmlFreeProp(cur); + return(0); + } + while (tmp != NULL) { + if (tmp->next == cur) { + tmp->next = cur->next; + if (tmp->next != NULL) + tmp->next->prev = tmp; + xmlFreeProp(cur); + return(0); + } + tmp = tmp->next; + } +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlRemoveProp : attribute not owned by its node\n"); +#endif + return(-1); +} + +/** + * xmlNewDocPI: + * @doc: the target document + * @name: the processing instruction name + * @content: the PI content + * + * Creation of a processing instruction element. + * Returns a pointer to the new node object. + */ +xmlNodePtr +xmlNewDocPI(xmlDocPtr doc, const xmlChar *name, const xmlChar *content) { + xmlNodePtr cur; + + if (name == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlNewPI : name == NULL\n"); +#endif + return(NULL); + } + + /* + * Allocate a new node and fill the fields. + */ + cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); + if (cur == NULL) { + xmlTreeErrMemory("building PI"); + return(NULL); + } + memset(cur, 0, sizeof(xmlNode)); + cur->type = XML_PI_NODE; + + if ((doc != NULL) && (doc->dict != NULL)) + cur->name = xmlDictLookup(doc->dict, name, -1); + else + cur->name = xmlStrdup(name); + if (content != NULL) { + cur->content = xmlStrdup(content); + } + cur->doc = doc; + + if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) + xmlRegisterNodeDefaultValue((xmlNodePtr)cur); + return(cur); +} + +/** + * xmlNewPI: + * @name: the processing instruction name + * @content: the PI content + * + * Creation of a processing instruction element. + * Use xmlDocNewPI preferably to get string interning + * + * Returns a pointer to the new node object. + */ +xmlNodePtr +xmlNewPI(const xmlChar *name, const xmlChar *content) { + return(xmlNewDocPI(NULL, name, content)); +} + +/** + * xmlNewNode: + * @ns: namespace if any + * @name: the node name + * + * Creation of a new node element. @ns is optional (NULL). + * + * Returns a pointer to the new node object. Uses xmlStrdup() to make + * copy of @name. + */ +xmlNodePtr +xmlNewNode(xmlNsPtr ns, const xmlChar *name) { + xmlNodePtr cur; + + if (name == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlNewNode : name == NULL\n"); +#endif + 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); +} + +/** + * xmlNewNodeEatName: + * @ns: namespace if any + * @name: the node name + * + * Creation of a new node element. @ns is optional (NULL). + * + * 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. + */ +xmlNodePtr +xmlNewNodeEatName(xmlNsPtr ns, xmlChar *name) { + xmlNodePtr cur; + + if (name == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlNewNode : name == NULL\n"); +#endif + return(NULL); + } + + /* + * 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 dictionnary */ + return(NULL); + } + memset(cur, 0, sizeof(xmlNode)); + cur->type = XML_ELEMENT_NODE; + + cur->name = name; + cur->ns = ns; + + if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) + xmlRegisterNodeDefaultValue((xmlNodePtr)cur); + return(cur); +} + +/** + * xmlNewDocNode: + * @doc: the document + * @ns: namespace if any + * @name: the node name + * @content: the XML text content if any + * + * 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. + * + * Returns a pointer to the new node object. + */ +xmlNodePtr +xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns, + const xmlChar *name, const xmlChar *content) { + xmlNodePtr cur; + + 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) + } + } + + return(cur); +} + +/** + * xmlNewDocNodeEatName: + * @doc: the document + * @ns: namespace if any + * @name: the node name + * @content: the XML text content if any + * + * 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. + * + * Returns a pointer to the new node object. + */ +xmlNodePtr +xmlNewDocNodeEatName(xmlDocPtr doc, xmlNsPtr ns, + 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 dictionnary free it here */ + if ((name != NULL) && (doc != NULL) && + (!(xmlDictOwns(doc->dict, name)))) + xmlFree(name); + } + return(cur); +} + +#ifdef LIBXML_TREE_ENABLED +/** + * xmlNewDocRawNode: + * @doc: the document + * @ns: namespace if any + * @name: the node name + * @content: the text content if any + * + * Creation of a new node element within a document. @ns and @content + * are optional (NULL). + * + * Returns a pointer to the new node object. + */ +xmlNodePtr +xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns, + const xmlChar *name, const xmlChar *content) { + xmlNodePtr cur; + + cur = xmlNewDocNode(doc, ns, name, NULL); + if (cur != NULL) { + cur->doc = doc; + if (content != NULL) { + cur->children = xmlNewDocText(doc, content); + UPDATE_LAST_CHILD_AND_PARENT(cur) + } + } + return(cur); +} + +/** + * xmlNewDocFragment: + * @doc: the document owning the fragment + * + * Creation of a new Fragment node. + * Returns a pointer to the new node object. + */ +xmlNodePtr +xmlNewDocFragment(xmlDocPtr doc) { + xmlNodePtr cur; + + /* + * Allocate a new DocumentFragment node and fill the fields. + */ + cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); + if (cur == NULL) { + xmlTreeErrMemory("building fragment"); + return(NULL); + } + memset(cur, 0, sizeof(xmlNode)); + cur->type = XML_DOCUMENT_FRAG_NODE; + + cur->doc = doc; + + if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) + xmlRegisterNodeDefaultValue(cur); + return(cur); +} +#endif /* LIBXML_TREE_ENABLED */ + +/** + * xmlNewText: + * @content: the text content + * + * Creation of a new text node. + * Returns a pointer to the new node object. + */ +xmlNodePtr +xmlNewText(const xmlChar *content) { + xmlNodePtr cur; + + /* + * Allocate a new node and fill the fields. + */ + cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); + if (cur == NULL) { + xmlTreeErrMemory("building text"); + return(NULL); + } + memset(cur, 0, sizeof(xmlNode)); + cur->type = XML_TEXT_NODE; + + cur->name = xmlStringText; + if (content != NULL) { + cur->content = xmlStrdup(content); + } + + if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) + xmlRegisterNodeDefaultValue(cur); + return(cur); +} + +#ifdef LIBXML_TREE_ENABLED +/** + * xmlNewTextChild: + * @parent: the parent node + * @ns: a namespace if any + * @name: the name of the child + * @content: the text content of the child if any. + * + * 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. + * + * Returns a pointer to the new node object. + */ +xmlNodePtr +xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns, + const xmlChar *name, const xmlChar *content) { + xmlNodePtr cur, prev; + + if (parent == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlNewTextChild : parent == NULL\n"); +#endif + return(NULL); + } + + if (name == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlNewTextChild : name == NULL\n"); +#endif + return(NULL); + } + + /* + * 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); + } + 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; + } else { + prev = parent->last; + prev->next = cur; + cur->prev = prev; + parent->last = cur; + } + + return(cur); +} +#endif /* LIBXML_TREE_ENABLED */ + +/** + * xmlNewCharRef: + * @doc: the document + * @name: the char ref string, starting with # or "&# ... ;" + * + * Creation of a new character reference node. + * Returns a pointer to the new node object. + */ +xmlNodePtr +xmlNewCharRef(xmlDocPtr doc, 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 character reference"); + return(NULL); + } + memset(cur, 0, sizeof(xmlNode)); + cur->type = XML_ENTITY_REF_NODE; + + cur->doc = doc; + if (name[0] == '&') { + int len; + name++; + len = xmlStrlen(name); + if (name[len - 1] == ';') + cur->name = xmlStrndup(name, len - 1); + else + cur->name = xmlStrndup(name, len); + } else + cur->name = xmlStrdup(name); + + if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) + xmlRegisterNodeDefaultValue(cur); + return(cur); +} + +/** + * xmlNewReference: + * @doc: the document + * @name: the reference name, or the reference string with & and ; + * + * Creation of a new reference node. + * Returns a pointer to the new node object. + */ +xmlNodePtr +xmlNewReference(xmlDocPtr doc, const xmlChar *name) { + xmlNodePtr cur; + xmlEntityPtr ent; + + if (name == NULL) + return(NULL); + + /* + * Allocate a new node and fill the fields. + */ + cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); + if (cur == NULL) { + xmlTreeErrMemory("building reference"); + return(NULL); + } + memset(cur, 0, sizeof(xmlNode)); + cur->type = XML_ENTITY_REF_NODE; + + cur->doc = doc; + if (name[0] == '&') { + int len; + name++; + len = xmlStrlen(name); + if (name[len - 1] == ';') + cur->name = xmlStrndup(name, len - 1); + else + cur->name = xmlStrndup(name, len); + } else + cur->name = xmlStrdup(name); + + ent = xmlGetDocEntity(doc, cur->name); + if (ent != NULL) { + cur->content = ent->content; + /* + * The parent pointer in entity is a DTD pointer and thus is NOT + * updated. Not sure if this is 100% correct. + * -George + */ + cur->children = (xmlNodePtr) ent; + cur->last = (xmlNodePtr) ent; + } + + if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) + xmlRegisterNodeDefaultValue(cur); + return(cur); +} + +/** + * xmlNewDocText: + * @doc: the document + * @content: the text content + * + * Creation of a new text node within a document. + * Returns a pointer to the new node object. + */ +xmlNodePtr +xmlNewDocText(xmlDocPtr doc, const xmlChar *content) { + xmlNodePtr cur; + + cur = xmlNewText(content); + if (cur != NULL) cur->doc = doc; + return(cur); +} + +/** + * xmlNewTextLen: + * @content: the text content + * @len: the text len. + * + * Creation of a new text node with an extra parameter for the content's length + * Returns a pointer to the new node object. + */ +xmlNodePtr +xmlNewTextLen(const xmlChar *content, int len) { + xmlNodePtr cur; + + /* + * Allocate a new node and fill the fields. + */ + cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); + if (cur == NULL) { + xmlTreeErrMemory("building text"); + return(NULL); + } + memset(cur, 0, sizeof(xmlNode)); + cur->type = XML_TEXT_NODE; + + cur->name = xmlStringText; + if (content != NULL) { + cur->content = xmlStrndup(content, len); + } + + if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) + xmlRegisterNodeDefaultValue(cur); + return(cur); +} + +/** + * xmlNewDocTextLen: + * @doc: the document + * @content: the text content + * @len: the text len. + * + * 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. + */ +xmlNodePtr +xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) { + xmlNodePtr cur; + + cur = xmlNewTextLen(content, len); + if (cur != NULL) cur->doc = doc; + return(cur); +} + +/** + * xmlNewComment: + * @content: the comment content + * + * Creation of a new node containing a comment. + * Returns a pointer to the new node object. + */ +xmlNodePtr +xmlNewComment(const xmlChar *content) { + xmlNodePtr cur; + + /* + * Allocate a new node and fill the fields. + */ + cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); + if (cur == NULL) { + xmlTreeErrMemory("building comment"); + return(NULL); + } + memset(cur, 0, sizeof(xmlNode)); + cur->type = XML_COMMENT_NODE; + + cur->name = xmlStringComment; + if (content != NULL) { + cur->content = xmlStrdup(content); + } + + if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) + xmlRegisterNodeDefaultValue(cur); + return(cur); +} + +/** + * xmlNewCDataBlock: + * @doc: the document + * @content: the CDATA block content content + * @len: the length of the block + * + * Creation of a new node containing a CDATA block. + * Returns a pointer to the new node object. + */ +xmlNodePtr +xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) { + xmlNodePtr cur; + + /* + * Allocate a new node and fill the fields. + */ + cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); + if (cur == NULL) { + xmlTreeErrMemory("building CDATA"); + 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 ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) + xmlRegisterNodeDefaultValue(cur); + return(cur); +} + +/** + * xmlNewDocComment: + * @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. + */ +xmlNodePtr +xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) { + xmlNodePtr cur; + + cur = xmlNewComment(content); + if (cur != NULL) cur->doc = doc; + return(cur); +} + +/** + * xmlSetTreeDoc: + * @tree: the top element + * @doc: the document + * + * update all nodes under the tree to point to the right document + */ +void +xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) { + xmlAttrPtr prop; + + if (tree == NULL) + return; + if (tree->doc != doc) { + if(tree->type == XML_ELEMENT_NODE) { + prop = tree->properties; + while (prop != NULL) { + prop->doc = doc; + xmlSetListDoc(prop->children, doc); + prop = prop->next; + } + } + if (tree->children != NULL) + xmlSetListDoc(tree->children, doc); + tree->doc = doc; + } +} + +/** + * xmlSetListDoc: + * @list: the first element + * @doc: the document + * + * update all nodes in the list to point to the right document + */ +void +xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) { + xmlNodePtr cur; + + if (list == NULL) + return; + cur = list; + while (cur != NULL) { + if (cur->doc != doc) + xmlSetTreeDoc(cur, doc); + cur = cur->next; + } +} + +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) +/** + * xmlNewChild: + * @parent: the parent node + * @ns: a namespace if any + * @name: the name of the child + * @content: the XML content of the child if any. + * + * 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. + * + * Returns a pointer to the new node object. + */ +xmlNodePtr +xmlNewChild(xmlNodePtr parent, xmlNsPtr ns, + const xmlChar *name, const xmlChar *content) { + xmlNodePtr cur, prev; + + if (parent == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlNewChild : parent == NULL\n"); +#endif + return(NULL); + } + + if (name == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlNewChild : name == NULL\n"); +#endif + return(NULL); + } + + /* + * 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); + } + 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; + } else { + prev = parent->last; + prev->next = cur; + cur->prev = prev; + parent->last = cur; + } + + return(cur); +} +#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 detroyed prior to adding @prop. + * + * Returns the attribute being inserted or NULL in case of error. + */ +static xmlNodePtr +xmlAddPropSibling(xmlNodePtr prev, xmlNodePtr cur, xmlNodePtr prop) { + xmlAttrPtr attr; + + if (cur->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); + + 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; + } + 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); + } + return prop; +} + +/** + * xmlAddNextSibling: + * @cur: the child node + * @elem: 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. + * + * Returns the new node or NULL in case of error. + */ +xmlNodePtr +xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) { + if (cur == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlAddNextSibling : cur == NULL\n"); +#endif + return(NULL); + } + if (elem == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlAddNextSibling : elem == NULL\n"); +#endif + return(NULL); + } + + if (cur == elem) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlAddNextSibling : cur == elem\n"); +#endif + 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 (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); +} + +#if defined(LIBXML_TREE_ENABLED) || \ + defined(LIBXML_SCHEMAS_ENABLED) +/** + * xmlAddPrevSibling: + * @cur: the child node + * @elem: the new node + * + * 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. + * + * Returns the new node or NULL in case of error. + */ +xmlNodePtr +xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) { + if (cur == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlAddPrevSibling : cur == NULL\n"); +#endif + return(NULL); + } + if (elem == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlAddPrevSibling : elem == NULL\n"); +#endif + return(NULL); + } + + if (cur == elem) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlAddPrevSibling : cur == elem\n"); +#endif + return(NULL); + } + + xmlUnlinkNode(elem); + + 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); +} +#endif /* LIBXML_TREE_ENABLED */ + +/** + * xmlAddSibling: + * @cur: the child node + * @elem: 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. + * + * Returns the new element or NULL in case of error. + */ +xmlNodePtr +xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) { + xmlNodePtr parent; + + if (cur == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlAddSibling : cur == NULL\n"); +#endif + return(NULL); + } + + if (elem == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlAddSibling : elem == NULL\n"); +#endif + return(NULL); + } + + if (cur == elem) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlAddSibling : cur == elem\n"); +#endif + 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; + } 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); + } + + 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; + + return(elem); +} + +/** + * xmlAddChildList: + * @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) + * + * Returns the last child or NULL in case of error. + */ +xmlNodePtr +xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) { + xmlNodePtr prev; + + if (parent == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlAddChildList : parent == NULL\n"); +#endif + return(NULL); + } + + if (cur == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlAddChildList : child == NULL\n"); +#endif + return(NULL); + } + + if ((cur->doc != NULL) && (parent->doc != NULL) && + (cur->doc != parent->doc)) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "Elements moved to a different document\n"); +#endif + } + + /* + * add the first element at the end of the children list. + */ + + if (parent->children == NULL) { + parent->children = cur; + } else { + /* + * 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); + /* + * 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); + } + 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); +} + +/** + * xmlAddChild: + * @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. + * + * Returns the child or NULL in case of error. + */ +xmlNodePtr +xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) { + xmlNodePtr prev; + + if (parent == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlAddChild : parent == NULL\n"); +#endif + return(NULL); + } + + if (cur == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlAddChild : child == NULL\n"); +#endif + return(NULL); + } + + if (parent == cur) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlAddChild : parent == cur\n"); +#endif + 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); + } + } + + /* + * add the new element at the end of the children list. + */ + prev = cur->parent; + cur->parent = parent; + if (cur->doc != parent->doc) { + xmlSetTreeDoc(cur, parent->doc); + } + /* 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; + } + } else { + if (parent->children == NULL) { + parent->children = cur; + parent->last = cur; + } else { + prev = parent->last; + prev->next = cur; + cur->prev = prev; + parent->last = cur; + } + } + return(cur); +} + +/** + * xmlGetLastChild: + * @parent: the parent node + * + * Search the last child of a node. + * Returns the last child or NULL if none. + */ +xmlNodePtr +xmlGetLastChild(xmlNodePtr parent) { + if (parent == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlGetLastChild : parent == NULL\n"); +#endif + return(NULL); + } + return(parent->last); +} + +#ifdef LIBXML_TREE_ENABLED +/* + * 5 interfaces from DOM ElementTraversal + */ + +/** + * 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. + * + * Returns the count of element child or 0 if not available + */ +unsigned long +xmlChildElementCount(xmlNodePtr parent) { + unsigned long ret = 0; + xmlNodePtr cur = NULL; + + if (parent == NULL) + return(0); + switch (parent->type) { + case XML_ELEMENT_NODE: + case XML_ENTITY_NODE: + case XML_DOCUMENT_NODE: + case XML_HTML_DOCUMENT_NODE: + cur = parent->children; + break; + default: + return(0); + } + while (cur != NULL) { + if (cur->type == XML_ELEMENT_NODE) + ret++; + cur = cur->next; + } + return(ret); +} + +/** + * 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. + * + * Returns the first element child or NULL if not available + */ +xmlNodePtr +xmlFirstElementChild(xmlNodePtr parent) { + xmlNodePtr cur = NULL; + + if (parent == NULL) + return(NULL); + switch (parent->type) { + case XML_ELEMENT_NODE: + case XML_ENTITY_NODE: + case XML_DOCUMENT_NODE: + case XML_HTML_DOCUMENT_NODE: + cur = parent->children; + break; + default: + return(NULL); + } + while (cur != NULL) { + if (cur->type == XML_ELEMENT_NODE) + return(cur); + cur = cur->next; + } + return(NULL); +} + +/** + * 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. + * + * Returns the last element child or NULL if not available + */ +xmlNodePtr +xmlLastElementChild(xmlNodePtr parent) { + xmlNodePtr cur = NULL; + + if (parent == NULL) + return(NULL); + switch (parent->type) { + case XML_ELEMENT_NODE: + case XML_ENTITY_NODE: + case XML_DOCUMENT_NODE: + case XML_HTML_DOCUMENT_NODE: + cur = parent->last; + break; + default: + return(NULL); + } + while (cur != NULL) { + if (cur->type == XML_ELEMENT_NODE) + return(cur); + cur = cur->prev; + } + return(NULL); +} + +/** + * 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. + * + * Returns the previous element sibling or NULL if not available + */ +xmlNodePtr +xmlPreviousElementSibling(xmlNodePtr node) { + if (node == NULL) + return(NULL); + switch (node->type) { + case XML_ELEMENT_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: + case XML_XINCLUDE_END: + node = node->prev; + break; + default: + return(NULL); + } + while (node != NULL) { + if (node->type == XML_ELEMENT_NODE) + return(node); + node = node->prev; + } + return(NULL); +} + +/** + * 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. + * + * Returns the next element sibling or NULL if not available + */ +xmlNodePtr +xmlNextElementSibling(xmlNodePtr node) { + if (node == NULL) + return(NULL); + switch (node->type) { + case XML_ELEMENT_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: + case XML_XINCLUDE_START: + case XML_XINCLUDE_END: + node = node->next; + break; + default: + return(NULL); + } + while (node != NULL) { + if (node->type == XML_ELEMENT_NODE) + return(node); + node = node->next; + } + return(NULL); +} + +#endif /* LIBXML_TREE_ENABLED */ + +/** + * 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. + */ +void +xmlFreeNodeList(xmlNodePtr cur) { + xmlNodePtr next; + xmlDictPtr dict = NULL; + + if (cur == NULL) return; + if (cur->type == XML_NAMESPACE_DECL) { + xmlFreeNsList((xmlNsPtr) cur); + return; + } + if ((cur->type == XML_DOCUMENT_NODE) || +#ifdef LIBXML_DOCB_ENABLED + (cur->type == XML_DOCB_DOCUMENT_NODE) || +#endif + (cur->type == XML_HTML_DOCUMENT_NODE)) { + xmlFreeDoc((xmlDocPtr) cur); + return; + } + if (cur->doc != NULL) dict = cur->doc->dict; + while (cur != NULL) { + next = cur->next; + if (cur->type != XML_DTD_NODE) { + + if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue)) + xmlDeregisterNodeDefaultValue(cur); + + if ((cur->children != NULL) && + (cur->type != XML_ENTITY_REF_NODE)) + xmlFreeNodeList(cur->children); + if (((cur->type == XML_ELEMENT_NODE) || + (cur->type == XML_XINCLUDE_START) || + (cur->type == XML_XINCLUDE_END)) && + (cur->properties != NULL)) + xmlFreePropList(cur->properties); + if ((cur->type != XML_ELEMENT_NODE) && + (cur->type != XML_XINCLUDE_START) && + (cur->type != XML_XINCLUDE_END) && + (cur->type != XML_ENTITY_REF_NODE) && + (cur->content != (xmlChar *) &(cur->properties))) { + DICT_FREE(cur->content) + } + if (((cur->type == XML_ELEMENT_NODE) || + (cur->type == XML_XINCLUDE_START) || + (cur->type == XML_XINCLUDE_END)) && + (cur->nsDef != NULL)) + xmlFreeNsList(cur->nsDef); + + /* + * When a node is a text node or a comment, it uses a global static + * variable for the name of the node. + * Otherwise the node name might come from the document's + * dictionnary + */ + if ((cur->name != NULL) && + (cur->type != XML_TEXT_NODE) && + (cur->type != XML_COMMENT_NODE)) + DICT_FREE(cur->name) + xmlFree(cur); + } + cur = next; + } +} + +/** + * 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. + */ +void +xmlFreeNode(xmlNodePtr cur) { + xmlDictPtr dict = NULL; + + if (cur == NULL) return; + + /* use xmlFreeDtd for DTD nodes */ + if (cur->type == XML_DTD_NODE) { + xmlFreeDtd((xmlDtdPtr) cur); + return; + } + if (cur->type == XML_NAMESPACE_DECL) { + xmlFreeNs((xmlNsPtr) cur); + return; + } + if (cur->type == XML_ATTRIBUTE_NODE) { + xmlFreeProp((xmlAttrPtr) 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); + if (((cur->type == XML_ELEMENT_NODE) || + (cur->type == XML_XINCLUDE_START) || + (cur->type == XML_XINCLUDE_END)) && + (cur->properties != NULL)) + xmlFreePropList(cur->properties); + if ((cur->type != XML_ELEMENT_NODE) && + (cur->content != NULL) && + (cur->type != XML_ENTITY_REF_NODE) && + (cur->type != XML_XINCLUDE_END) && + (cur->type != XML_XINCLUDE_START) && + (cur->content != (xmlChar *) &(cur->properties))) { + DICT_FREE(cur->content) + } + + /* + * When a node is a text node or a comment, it uses a global static + * variable for the name of the node. + * Otherwise the node name might come from the document's dictionnary + */ + if ((cur->name != NULL) && + (cur->type != XML_TEXT_NODE) && + (cur->type != XML_COMMENT_NODE)) + DICT_FREE(cur->name) + + if (((cur->type == XML_ELEMENT_NODE) || + (cur->type == XML_XINCLUDE_START) || + (cur->type == XML_XINCLUDE_END)) && + (cur->nsDef != NULL)) + xmlFreeNsList(cur->nsDef); + xmlFree(cur); +} + +/** + * xmlUnlinkNode: + * @cur: the node + * + * Unlink a node from it's current context, the node is not freed + * If one need to free the node, use xmlNodeFree() routine after the + * unlink. + */ +void +xmlUnlinkNode(xmlNodePtr cur) { + if (cur == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlUnlinkNode : node == NULL\n"); +#endif + 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); + } + } + } + if (cur->parent != NULL) { + xmlNodePtr parent; + parent = cur->parent; + if (cur->type == XML_ATTRIBUTE_NODE) { + if (parent->properties == (xmlAttrPtr) cur) + parent->properties = ((xmlAttrPtr) cur)->next; + } else { + if (parent->children == cur) + parent->children = cur->next; + if (parent->last == cur) + parent->last = cur->prev; + } + 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; +} + +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED) +/** + * xmlReplaceNode: + * @old: the old node + * @cur: the node + * + * 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. + * + * Returns the @old node + */ +xmlNodePtr +xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) { + if (old == cur) return(NULL); + if ((old == NULL) || (old->parent == NULL)) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlReplaceNode : old == NULL or without parent\n"); +#endif + return(NULL); + } + if (cur == NULL) { + xmlUnlinkNode(old); + return(old); + } + if (cur == old) { + return(old); + } + if ((old->type==XML_ATTRIBUTE_NODE) && (cur->type!=XML_ATTRIBUTE_NODE)) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlReplaceNode : Trying to replace attribute node with other node type\n"); +#endif + return(old); + } + if ((cur->type==XML_ATTRIBUTE_NODE) && (old->type!=XML_ATTRIBUTE_NODE)) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlReplaceNode : Trying to replace a non-attribute node with attribute node\n"); +#endif + return(old); + } + xmlUnlinkNode(cur); + xmlSetTreeDoc(cur, old->doc); + cur->parent = old->parent; + cur->next = old->next; + if (cur->next != NULL) + cur->next->prev = cur; + cur->prev = old->prev; + if (cur->prev != NULL) + cur->prev->next = cur; + if (cur->parent != NULL) { + if (cur->type == XML_ATTRIBUTE_NODE) { + if (cur->parent->properties == (xmlAttrPtr)old) + cur->parent->properties = ((xmlAttrPtr) cur); + } else { + if (cur->parent->children == old) + cur->parent->children = cur; + if (cur->parent->last == old) + cur->parent->last = cur; + } + } + old->next = old->prev = NULL; + old->parent = NULL; + return(old); +} +#endif /* LIBXML_TREE_ENABLED */ + +/************************************************************************ + * * + * Copy operations * + * * + ************************************************************************/ + +/** + * xmlCopyNamespace: + * @cur: the namespace + * + * Do a copy of the namespace. + * + * Returns: a new #xmlNsPtr, or NULL in case of error. + */ +xmlNsPtr +xmlCopyNamespace(xmlNsPtr cur) { + xmlNsPtr ret; + + if (cur == NULL) return(NULL); + switch (cur->type) { + case XML_LOCAL_NAMESPACE: + ret = xmlNewNs(NULL, cur->href, cur->prefix); + break; + default: +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlCopyNamespace: invalid type %d\n", cur->type); +#endif + return(NULL); + } + return(ret); +} + +/** + * xmlCopyNamespaceList: + * @cur: the first namespace + * + * Do a copy of an namespace list. + * + * Returns: a new #xmlNsPtr, or NULL in case of error. + */ +xmlNsPtr +xmlCopyNamespaceList(xmlNsPtr cur) { + xmlNsPtr ret = NULL; + xmlNsPtr p = NULL,q; + + while (cur != NULL) { + q = xmlCopyNamespace(cur); + if (p == NULL) { + ret = p = q; + } else { + p->next = q; + p = q; + } + cur = cur->next; + } + return(ret); +} + +static xmlNodePtr +xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent); + +static xmlAttrPtr +xmlCopyPropInternal(xmlDocPtr doc, xmlNodePtr target, xmlAttrPtr cur) { + xmlAttrPtr ret; + + if (cur == NULL) return(NULL); + if (target != NULL) + ret = xmlNewDocProp(target->doc, cur->name, NULL); + else if (doc != NULL) + ret = xmlNewDocProp(doc, cur->name, NULL); + else if (cur->parent != NULL) + ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL); + else if (cur->children != NULL) + ret = xmlNewDocProp(cur->children->doc, cur->name, NULL); + else + ret = xmlNewDocProp(NULL, cur->name, NULL); + if (ret == NULL) return(NULL); + ret->parent = target; + + if ((cur->ns != NULL) && (target != NULL)) { + xmlNsPtr ns; + + ns = xmlSearchNs(target->doc, target, cur->ns->prefix); + 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); + if (ns != NULL) { + xmlNodePtr root = target; + xmlNodePtr pred = NULL; + + while (root->parent != NULL) { + pred = root; + root = root->parent; + } + if (root == (xmlNodePtr) target->doc) { + /* correct possibly cycling above the document elt */ + root = pred; + } + ret->ns = xmlNewNs(root, ns->href, ns->prefix); + } + } else { + /* + * we have to find something appropriate here since + * we cant be sure, that the namespce we found is identified + * by the prefix + */ + if (xmlStrEqual(ns->href, cur->ns->href)) { + /* this is the nice case */ + ret->ns = ns; + } else { + /* + * we are in trouble: we need a new reconcilied namespace. + * This is expensive + */ + ret->ns = xmlNewReconciliedNs(target->doc, target, cur->ns); + } + } + + } else + ret->ns = NULL; + + if (cur->children != NULL) { + xmlNodePtr tmp; + + ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret); + ret->last = NULL; + tmp = ret->children; + while (tmp != NULL) { + /* tmp->parent = (xmlNodePtr)ret; */ + if (tmp->next == NULL) + ret->last = tmp; + tmp = tmp->next; + } + } + /* + * Try to handle IDs + */ + 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)) { + xmlChar *id; + + id = xmlNodeListGetString(cur->doc, cur->children, 1); + if (id != NULL) { + xmlAddID(NULL, target->doc, id, ret); + xmlFree(id); + } + } + } + return(ret); +} + +/** + * xmlCopyProp: + * @target: the element where the attribute will be grafted + * @cur: the attribute + * + * Do a copy of the attribute. + * + * Returns: a new #xmlAttrPtr, or NULL in case of error. + */ +xmlAttrPtr +xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) { + return xmlCopyPropInternal(NULL, target, cur); +} + +/** + * xmlCopyPropList: + * @target: the element where the attributes will be grafted + * @cur: the first attribute + * + * Do a copy of an attribute list. + * + * Returns: a new #xmlAttrPtr, or NULL in case of error. + */ +xmlAttrPtr +xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) { + xmlAttrPtr ret = NULL; + xmlAttrPtr p = NULL,q; + + while (cur != NULL) { + q = xmlCopyProp(target, cur); + if (q == NULL) + return(NULL); + if (p == NULL) { + ret = p = q; + } else { + p->next = q; + q->prev = p; + p = q; + } + cur = cur->next; + } + return(ret); +} + +/* + * NOTE about the CopyNode operations ! + * + * They are split into external and internal parts for one + * tricky reason: namespaces. Doing a direct copy of a node + * say RPM:Copyright without changing the namespace pointer to + * something else can produce stale links. One way to do it is + * to keep a reference counter but this doesn't work as soon + * as one move the element or the subtree out of the scope of + * the existing namespace. The actual solution seems to add + * a copy of the namespace at the top of the copied tree if + * not available in the subtree. + * Hence two functions, the public front-end call the inner ones + * The argument "recursive" normally indicates a recursive copy + * of the node with values 0 (no) and 1 (yes). For XInclude, + * however, we allow a value of 2 to indicate copy properties and + * namespace info, but don't recurse on children. + */ + +static xmlNodePtr +xmlStaticCopyNode(const xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent, + int extended) { + xmlNodePtr ret; + + if (node == NULL) return(NULL); + switch (node->type) { + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: + 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: + case XML_XINCLUDE_END: + break; + case XML_ATTRIBUTE_NODE: + return((xmlNodePtr) xmlCopyPropInternal(doc, parent, (xmlAttrPtr) node)); + case XML_NAMESPACE_DECL: + return((xmlNodePtr) xmlCopyNamespaceList((xmlNsPtr) node)); + + case XML_DOCUMENT_NODE: + case XML_HTML_DOCUMENT_NODE: +#ifdef LIBXML_DOCB_ENABLED + case XML_DOCB_DOCUMENT_NODE: +#endif +#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: + return(NULL); + } + + /* + * Allocate a new node and fill the fields. + */ + ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); + if (ret == NULL) { + xmlTreeErrMemory("copying node"); + return(NULL); + } + memset(ret, 0, sizeof(xmlNode)); + ret->type = node->type; + + ret->doc = doc; + ret->parent = parent; + if (node->name == xmlStringText) + ret->name = xmlStringText; + else if (node->name == xmlStringTextNoenc) + ret->name = xmlStringTextNoenc; + else if (node->name == xmlStringComment) + ret->name = xmlStringComment; + else if (node->name != NULL) { + if ((doc != NULL) && (doc->dict != NULL)) + ret->name = xmlDictLookup(doc->dict, node->name, -1); + else + ret->name = xmlStrdup(node->name); + } + if ((node->type != XML_ELEMENT_NODE) && + (node->content != NULL) && + (node->type != XML_ENTITY_REF_NODE) && + (node->type != XML_XINCLUDE_END) && + (node->type != XML_XINCLUDE_START)) { + ret->content = xmlStrdup(node->content); + }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); + + 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)) + ret->nsDef = xmlCopyNamespaceList(node->nsDef); + + if (node->ns != NULL) { + xmlNsPtr ns; + + ns = xmlSearchNs(doc, ret, node->ns->prefix); + 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(node->doc, node, node->ns->prefix); + if (ns != NULL) { + xmlNodePtr root = ret; + + while (root->parent != NULL) root = root->parent; + ret->ns = xmlNewNs(root, ns->href, ns->prefix); + } else { + ret->ns = xmlNewReconciliedNs(doc, ret, node->ns); + } + } else { + /* + * reference the existing namespace definition in our own tree. + */ + ret->ns = ns; + } + } + if (((node->type == XML_ELEMENT_NODE) || + (node->type == XML_XINCLUDE_START)) && (node->properties != NULL)) + ret->properties = xmlCopyPropList(ret, node->properties); + if (node->type == XML_ENTITY_REF_NODE) { + if ((doc == NULL) || (node->doc != doc)) { + /* + * The copied node will go into a separate document, so + * to avoid dangling references to the ENTITY_DECL node + * we cannot keep the reference. Try to find it in the + * target document. + */ + ret->children = (xmlNodePtr) xmlGetDocEntity(doc, ret->name); + } else { + ret->children = node->children; + } + ret->last = ret->children; + } else if ((node->children != NULL) && (extended != 2)) { + ret->children = xmlStaticCopyNodeList(node->children, doc, ret); + UPDATE_LAST_CHILD_AND_PARENT(ret) + } + +out: + /* if parent != NULL we already registered the node above */ + if ((parent == NULL) && + ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue))) + xmlRegisterNodeDefaultValue((xmlNodePtr)ret); + return(ret); +} + +static xmlNodePtr +xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) { + xmlNodePtr ret = NULL; + xmlNodePtr p = NULL,q; + + while (node != NULL) { +#ifdef LIBXML_TREE_ENABLED + if (node->type == XML_DTD_NODE ) { + if (doc == NULL) { + node = node->next; + continue; + } + if (doc->intSubset == NULL) { + q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node ); + q->doc = doc; + q->parent = parent; + doc->intSubset = (xmlDtdPtr) q; + xmlAddChild(parent, q); + } else { + q = (xmlNodePtr) doc->intSubset; + xmlAddChild(parent, q); + } + } else +#endif /* LIBXML_TREE_ENABLED */ + q = xmlStaticCopyNode(node, doc, parent, 1); + if (ret == NULL) { + q->prev = NULL; + ret = p = q; + } else if (p != q) { + /* the test is required if xmlStaticCopyNode coalesced 2 text nodes */ + p->next = q; + q->prev = p; + p = q; + } + node = node->next; + } + return(ret); +} + +/** + * xmlCopyNode: + * @node: the node + * @extended: if 1 do a recursive copy (properties, namespaces and children + * when applicable) + * if 2 copy properties and namespaces (when applicable) + * + * Do a copy of the node. + * + * Returns: a new #xmlNodePtr, or NULL in case of error. + */ +xmlNodePtr +xmlCopyNode(const xmlNodePtr node, int extended) { + xmlNodePtr ret; + + ret = xmlStaticCopyNode(node, NULL, NULL, extended); + return(ret); +} + +/** + * xmlDocCopyNode: + * @node: the node + * @doc: the document + * @extended: if 1 do a recursive copy (properties, namespaces and children + * when applicable) + * if 2 copy properties and namespaces (when applicable) + * + * Do a copy of the node to a given document. + * + * Returns: a new #xmlNodePtr, or NULL in case of error. + */ +xmlNodePtr +xmlDocCopyNode(const xmlNodePtr node, xmlDocPtr doc, int extended) { + xmlNodePtr ret; + + ret = xmlStaticCopyNode(node, doc, NULL, extended); + return(ret); +} + +/** + * xmlDocCopyNodeList: + * @doc: the target document + * @node: the first node in the list. + * + * Do a recursive copy of the node list. + * + * Returns: a new #xmlNodePtr, or NULL in case of error. + */ +xmlNodePtr xmlDocCopyNodeList(xmlDocPtr doc, const xmlNodePtr node) { + xmlNodePtr ret = xmlStaticCopyNodeList(node, doc, NULL); + return(ret); +} + +/** + * xmlCopyNodeList: + * @node: the first node in the list. + * + * Do a recursive copy of the node list. + * Use xmlDocCopyNodeList() if possible to ensure string interning. + * + * Returns: a new #xmlNodePtr, or NULL in case of error. + */ +xmlNodePtr xmlCopyNodeList(const xmlNodePtr node) { + xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL); + return(ret); +} + +#if defined(LIBXML_TREE_ENABLED) +/** + * xmlCopyDtd: + * @dtd: the dtd + * + * Do a copy of the dtd. + * + * Returns: a new #xmlDtdPtr, or NULL in case of error. + */ +xmlDtdPtr +xmlCopyDtd(xmlDtdPtr dtd) { + xmlDtdPtr ret; + xmlNodePtr cur, p = NULL, q; + + if (dtd == NULL) return(NULL); + ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID); + if (ret == NULL) return(NULL); + if (dtd->entities != NULL) + ret->entities = (void *) xmlCopyEntitiesTable( + (xmlEntitiesTablePtr) dtd->entities); + if (dtd->notations != NULL) + ret->notations = (void *) xmlCopyNotationTable( + (xmlNotationTablePtr) dtd->notations); + if (dtd->elements != NULL) + ret->elements = (void *) xmlCopyElementTable( + (xmlElementTablePtr) dtd->elements); + if (dtd->attributes != NULL) + ret->attributes = (void *) xmlCopyAttributeTable( + (xmlAttributeTablePtr) dtd->attributes); + if (dtd->pentities != NULL) + ret->pentities = (void *) xmlCopyEntitiesTable( + (xmlEntitiesTablePtr) dtd->pentities); + + cur = dtd->children; + while (cur != NULL) { + q = NULL; + + if (cur->type == XML_ENTITY_DECL) { + xmlEntityPtr tmp = (xmlEntityPtr) cur; + switch (tmp->etype) { + case XML_INTERNAL_GENERAL_ENTITY: + case XML_EXTERNAL_GENERAL_PARSED_ENTITY: + case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY: + q = (xmlNodePtr) xmlGetEntityFromDtd(ret, tmp->name); + break; + case XML_INTERNAL_PARAMETER_ENTITY: + case XML_EXTERNAL_PARAMETER_ENTITY: + q = (xmlNodePtr) + xmlGetParameterEntityFromDtd(ret, tmp->name); + break; + case XML_INTERNAL_PREDEFINED_ENTITY: + break; + } + } else if (cur->type == XML_ELEMENT_DECL) { + xmlElementPtr tmp = (xmlElementPtr) cur; + q = (xmlNodePtr) + xmlGetDtdQElementDesc(ret, tmp->name, tmp->prefix); + } else if (cur->type == XML_ATTRIBUTE_DECL) { + xmlAttributePtr tmp = (xmlAttributePtr) cur; + q = (xmlNodePtr) + xmlGetDtdQAttrDesc(ret, tmp->elem, tmp->name, tmp->prefix); + } else if (cur->type == XML_COMMENT_NODE) { + q = xmlCopyNode(cur, 0); + } + + if (q == NULL) { + cur = cur->next; + continue; + } + + if (p == NULL) + ret->children = q; + else + p->next = q; + + q->prev = p; + q->parent = (xmlNodePtr) ret; + q->next = NULL; + ret->last = q; + p = q; + cur = cur->next; + } + + return(ret); +} +#endif + +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) +/** + * xmlCopyDoc: + * @doc: the document + * @recursive: if not zero do a recursive copy. + * + * Do a copy of the document info. 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. + */ +xmlDocPtr +xmlCopyDoc(xmlDocPtr doc, int recursive) { + xmlDocPtr ret; + + if (doc == NULL) return(NULL); + ret = xmlNewDoc(doc->version); + if (ret == NULL) return(NULL); + if (doc->name != NULL) + ret->name = xmlMemStrdup(doc->name); + if (doc->encoding != NULL) + ret->encoding = xmlStrdup(doc->encoding); + if (doc->URL != NULL) + ret->URL = xmlStrdup(doc->URL); + ret->charset = doc->charset; + ret->compression = doc->compression; + ret->standalone = doc->standalone; + if (!recursive) return(ret); + + ret->last = NULL; + ret->children = NULL; +#ifdef LIBXML_TREE_ENABLED + if (doc->intSubset != NULL) { + ret->intSubset = xmlCopyDtd(doc->intSubset); + xmlSetTreeDoc((xmlNodePtr)ret->intSubset, ret); + ret->intSubset->parent = ret; + } +#endif + if (doc->oldNs != NULL) + ret->oldNs = xmlCopyNamespaceList(doc->oldNs); + if (doc->children != NULL) { + xmlNodePtr tmp; + + ret->children = xmlStaticCopyNodeList(doc->children, ret, + (xmlNodePtr)ret); + ret->last = NULL; + tmp = ret->children; + while (tmp != NULL) { + if (tmp->next == NULL) + ret->last = tmp; + tmp = tmp->next; + } + } + return(ret); +} +#endif /* LIBXML_TREE_ENABLED */ + +/************************************************************************ + * * + * Content access functions * + * * + ************************************************************************/ + +/** + * xmlGetLineNo: + * @node: valid node + * + * Get line number of @node. This requires activation of this option + * before invoking the parser by calling xmlLineNumbersDefault(1) + * + * Returns the line number if successful, -1 otherwise + */ +long +xmlGetLineNo(xmlNodePtr node) +{ + long result = -1; + + if (!node) + return result; + if ((node->type == XML_ELEMENT_NODE) || + (node->type == XML_TEXT_NODE) || + (node->type == XML_COMMENT_NODE) || + (node->type == XML_PI_NODE)) + result = (long) node->line; + else if ((node->prev != NULL) && + ((node->prev->type == XML_ELEMENT_NODE) || + (node->prev->type == XML_TEXT_NODE) || + (node->prev->type == XML_COMMENT_NODE) || + (node->prev->type == XML_PI_NODE))) + result = xmlGetLineNo(node->prev); + else if ((node->parent != NULL) && + (node->parent->type == XML_ELEMENT_NODE)) + result = xmlGetLineNo(node->parent); + + return result; +} + +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED) +/** + * xmlGetNodePath: + * @node: a node + * + * Build a structure based Path for the given node + * + * Returns the new path or NULL in case of error. The caller must free + * the returned string + */ +xmlChar * +xmlGetNodePath(xmlNodePtr node) +{ + xmlNodePtr cur, tmp, next; + xmlChar *buffer = NULL, *temp; + size_t buf_len; + xmlChar *buf; + const char *sep; + const char *name; + char nametemp[100]; + int occur = 0, generic; + + if (node == NULL) + return (NULL); + + buf_len = 500; + buffer = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar)); + if (buffer == NULL) { + xmlTreeErrMemory("getting node path"); + return (NULL); + } + buf = (xmlChar *) xmlMallocAtomic(buf_len * sizeof(xmlChar)); + if (buf == NULL) { + xmlTreeErrMemory("getting node path"); + xmlFree(buffer); + return (NULL); + } + + buffer[0] = 0; + cur = node; + do { + name = ""; + sep = "?"; + occur = 0; + if ((cur->type == XML_DOCUMENT_NODE) || + (cur->type == XML_HTML_DOCUMENT_NODE)) { + if (buffer[0] == '/') + break; + sep = "/"; + next = NULL; + } else if (cur->type == XML_ELEMENT_NODE) { + generic = 0; + sep = "/"; + name = (const char *) cur->name; + if (cur->ns) { + if (cur->ns->prefix != NULL) { + snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s", + (char *)cur->ns->prefix, (char *)cur->name); + nametemp[sizeof(nametemp) - 1] = 0; + name = nametemp; + } else { + /* + * We cannot express named elements in the default + * namespace, so use "*". + */ + generic = 1; + name = "*"; + } + } + next = cur->parent; + + /* + * Thumbler index computation + * TODO: the ocurence test seems bogus for namespaced names + */ + tmp = cur->prev; + while (tmp != NULL) { + if ((tmp->type == XML_ELEMENT_NODE) && + (generic || + (xmlStrEqual(cur->name, tmp->name) && + ((tmp->ns == cur->ns) || + ((tmp->ns != NULL) && (cur->ns != NULL) && + (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix))))))) + occur++; + tmp = tmp->prev; + } + if (occur == 0) { + tmp = cur->next; + while (tmp != NULL && occur == 0) { + if ((tmp->type == XML_ELEMENT_NODE) && + (generic || + (xmlStrEqual(cur->name, tmp->name) && + ((tmp->ns == cur->ns) || + ((tmp->ns != NULL) && (cur->ns != NULL) && + (xmlStrEqual(cur->ns->prefix, tmp->ns->prefix))))))) + occur++; + tmp = tmp->next; + } + if (occur != 0) + occur = 1; + } else + occur++; + } else if (cur->type == XML_COMMENT_NODE) { + sep = "/"; + name = "comment()"; + next = cur->parent; + + /* + * Thumbler index computation + */ + tmp = cur->prev; + while (tmp != NULL) { + if (tmp->type == XML_COMMENT_NODE) + occur++; + tmp = tmp->prev; + } + if (occur == 0) { + tmp = cur->next; + while (tmp != NULL && occur == 0) { + if (tmp->type == XML_COMMENT_NODE) + occur++; + tmp = tmp->next; + } + if (occur != 0) + occur = 1; + } else + occur++; + } else if ((cur->type == XML_TEXT_NODE) || + (cur->type == XML_CDATA_SECTION_NODE)) { + sep = "/"; + name = "text()"; + next = cur->parent; + + /* + * Thumbler index computation + */ + tmp = cur->prev; + while (tmp != NULL) { + if ((tmp->type == XML_TEXT_NODE) || + (tmp->type == XML_CDATA_SECTION_NODE)) + occur++; + tmp = tmp->prev; + } + /* + * Evaluate if this is the only text- or CDATA-section-node; + * if yes, then we'll get "text()", otherwise "text()[1]". + */ + if (occur == 0) { + tmp = cur->next; + while (tmp != NULL) { + if ((tmp->type == XML_TEXT_NODE) || + (tmp->type == XML_CDATA_SECTION_NODE)) + { + occur = 1; + break; + } + tmp = tmp->next; + } + } else + occur++; + } else if (cur->type == XML_PI_NODE) { + sep = "/"; + snprintf(nametemp, sizeof(nametemp) - 1, + "processing-instruction('%s')", (char *)cur->name); + nametemp[sizeof(nametemp) - 1] = 0; + name = nametemp; + + next = cur->parent; + + /* + * Thumbler index computation + */ + tmp = cur->prev; + while (tmp != NULL) { + if ((tmp->type == XML_PI_NODE) && + (xmlStrEqual(cur->name, tmp->name))) + occur++; + tmp = tmp->prev; + } + if (occur == 0) { + tmp = cur->next; + while (tmp != NULL && occur == 0) { + if ((tmp->type == XML_PI_NODE) && + (xmlStrEqual(cur->name, tmp->name))) + occur++; + tmp = tmp->next; + } + if (occur != 0) + occur = 1; + } else + occur++; + + } else if (cur->type == XML_ATTRIBUTE_NODE) { + sep = "/@"; + name = (const char *) (((xmlAttrPtr) cur)->name); + if (cur->ns) { + if (cur->ns->prefix != NULL) + snprintf(nametemp, sizeof(nametemp) - 1, "%s:%s", + (char *)cur->ns->prefix, (char *)cur->name); + else + snprintf(nametemp, sizeof(nametemp) - 1, "%s", + (char *)cur->name); + nametemp[sizeof(nametemp) - 1] = 0; + name = nametemp; + } + next = ((xmlAttrPtr) cur)->parent; + } else { + next = cur->parent; + } + + /* + * Make sure there is enough room + */ + if (xmlStrlen(buffer) + sizeof(nametemp) + 20 > buf_len) { + buf_len = + 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); + } + buffer = temp; + temp = (xmlChar *) xmlRealloc(buf, buf_len); + if (temp == NULL) { + xmlTreeErrMemory("getting node path"); + xmlFree(buf); + xmlFree(buffer); + return (NULL); + } + buf = temp; + } + if (occur == 0) + snprintf((char *) buf, buf_len, "%s%s%s", + sep, name, (char *) buffer); + else + snprintf((char *) buf, buf_len, "%s%s[%d]%s", + sep, name, occur, (char *) buffer); + snprintf((char *) buffer, buf_len, "%s", (char *)buf); + cur = next; + } while (cur != NULL); + xmlFree(buf); + return (buffer); +} +#endif /* LIBXML_TREE_ENABLED */ + +/** + * xmlDocGetRootElement: + * @doc: the document + * + * 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 + */ +xmlNodePtr +xmlDocGetRootElement(xmlDocPtr doc) { + xmlNodePtr ret; + + if (doc == NULL) return(NULL); + ret = doc->children; + while (ret != NULL) { + if (ret->type == XML_ELEMENT_NODE) + return(ret); + ret = ret->next; + } + return(ret); +} + +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_WRITER_ENABLED) +/** + * xmlDocSetRootElement: + * @doc: the document + * @root: the new document root element, if root is NULL no action is taken, + * to remove a node from a document use xmlUnlinkNode(root) instead. + * + * 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 + */ +xmlNodePtr +xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) { + xmlNodePtr old = NULL; + + if (doc == NULL) return(NULL); + if (root == NULL) + 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 == NULL) { + if (doc->children == NULL) { + doc->children = root; + doc->last = root; + } else { + xmlAddSibling(doc->children, root); + } + } else { + xmlReplaceNode(old, root); + } + return(old); +} +#endif + +#if defined(LIBXML_TREE_ENABLED) +/** + * xmlNodeSetLang: + * @cur: the node being changed + * @lang: the language description + * + * Set the language of a node, i.e. the values of the xml:lang + * attribute. + */ +void +xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) { + xmlNsPtr ns; + + 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: +#ifdef LIBXML_DOCB_ENABLED + case XML_DOCB_DOCUMENT_NODE: +#endif + 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); +} +#endif /* LIBXML_TREE_ENABLED */ + +/** + * xmlNodeGetLang: + * @cur: the node being checked + * + * Searches the language of a node, i.e. the values of the xml:lang + * attribute or the one carried by the nearest ancestor. + * + * Returns a pointer to the lang value, or NULL if not found + * It's up to the caller to free the memory with xmlFree(). + */ +xmlChar * +xmlNodeGetLang(xmlNodePtr cur) { + xmlChar *lang; + + while (cur != NULL) { + lang = xmlGetNsProp(cur, BAD_CAST "lang", XML_XML_NAMESPACE); + if (lang != NULL) + return(lang); + cur = cur->parent; + } + return(NULL); +} + + +#ifdef LIBXML_TREE_ENABLED +/** + * xmlNodeSetSpacePreserve: + * @cur: the node being changed + * @val: the xml:space value ("0": default, 1: "preserve") + * + * Set (or reset) the space preserving behaviour of a node, i.e. the + * value of the xml:space attribute. + */ +void +xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) { + xmlNsPtr ns; + + 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: +#ifdef LIBXML_DOCB_ENABLED + case XML_DOCB_DOCUMENT_NODE: +#endif + 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; + } +} +#endif /* LIBXML_TREE_ENABLED */ + +/** + * xmlNodeGetSpacePreserve: + * @cur: the node being checked + * + * Searches the space preserving behaviour of a node, i.e. the values + * of the xml:space attribute or the one carried by the nearest + * ancestor. + * + * Returns -1 if xml:space is not inherited, 0 if "default", 1 if "preserve" + */ +int +xmlNodeGetSpacePreserve(xmlNodePtr cur) { + xmlChar *space; + + while (cur != NULL) { + space = xmlGetNsProp(cur, BAD_CAST "space", XML_XML_NAMESPACE); + if (space != NULL) { + if (xmlStrEqual(space, BAD_CAST "preserve")) { + xmlFree(space); + return(1); + } + if (xmlStrEqual(space, BAD_CAST "default")) { + xmlFree(space); + return(0); + } + xmlFree(space); + } + cur = cur->parent; + } + return(-1); +} + +#ifdef LIBXML_TREE_ENABLED +/** + * xmlNodeSetName: + * @cur: the node being changed + * @name: the new tag name + * + * Set (or reset) the name of a node. + */ +void +xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) { + xmlDocPtr doc; + xmlDictPtr dict; + + 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: +#ifdef LIBXML_DOCB_ENABLED + case XML_DOCB_DOCUMENT_NODE: +#endif + 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; + } + doc = cur->doc; + if (doc != NULL) + dict = doc->dict; + else + dict = NULL; + if (dict != NULL) { + if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name))) + xmlFree((xmlChar *) cur->name); + cur->name = xmlDictLookup(dict, name, -1); + } else { + if (cur->name != NULL) xmlFree((xmlChar *) cur->name); + cur->name = xmlStrdup(name); + } +} +#endif + +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) +/** + * xmlNodeSetBase: + * @cur: the node being changed + * @uri: the new base URI + * + * Set (or reset) the base URI of a node, i.e. the value of the + * xml:base attribute. + */ +void +xmlNodeSetBase(xmlNodePtr cur, const xmlChar* uri) { + xmlNsPtr ns; + xmlChar* fixed; + + if (cur == 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_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; + case XML_DOCUMENT_NODE: +#ifdef LIBXML_DOCB_ENABLED + case XML_DOCB_DOCUMENT_NODE: +#endif + case XML_HTML_DOCUMENT_NODE: { + xmlDocPtr doc = (xmlDocPtr) cur; + + if (doc->URL != NULL) + xmlFree((xmlChar *) doc->URL); + if (uri == NULL) + doc->URL = NULL; + else + doc->URL = xmlPathToURI(uri); + return; + } + } + + ns = xmlSearchNsByHref(cur->doc, cur, XML_XML_NAMESPACE); + if (ns == NULL) + return; + fixed = xmlPathToURI(uri); + if (fixed != NULL) { + xmlSetNsProp(cur, ns, BAD_CAST "base", fixed); + xmlFree(fixed); + } else { + xmlSetNsProp(cur, ns, BAD_CAST "base", uri); + } +} +#endif /* LIBXML_TREE_ENABLED */ + +/** + * xmlNodeGetBase: + * @doc: the document the node pertains to + * @cur: the node being checked + * + * Searches for the BASE URL. The code should work on both XML + * and HTML document even if base mechanisms are completely different. + * It returns the base as defined in RFC 2396 sections + * 5.1.1. Base URI within Document Content + * and + * 5.1.2. Base URI from the Encapsulating Entity + * 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(). + */ +xmlChar * +xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) { + xmlChar *oldbase = NULL; + xmlChar *base, *newbase; + + if ((cur == NULL) && (doc == NULL)) + return(NULL); + if (doc == NULL) doc = cur->doc; + if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) { + cur = doc->children; + while ((cur != NULL) && (cur->name != NULL)) { + if (cur->type != XML_ELEMENT_NODE) { + cur = cur->next; + continue; + } + if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) { + cur = cur->children; + continue; + } + if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) { + cur = cur->children; + continue; + } + if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) { + return(xmlGetProp(cur, BAD_CAST "href")); + } + cur = cur->next; + } + return(NULL); + } + while (cur != NULL) { + if (cur->type == XML_ENTITY_DECL) { + xmlEntityPtr ent = (xmlEntityPtr) cur; + return(xmlStrdup(ent->URI)); + } + if (cur->type == XML_ELEMENT_NODE) { + base = xmlGetNsProp(cur, BAD_CAST "base", XML_XML_NAMESPACE); + 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); + } + } else { + oldbase = base; + } + if ((!xmlStrncmp(oldbase, BAD_CAST "http://", 7)) || + (!xmlStrncmp(oldbase, BAD_CAST "ftp://", 6)) || + (!xmlStrncmp(oldbase, BAD_CAST "urn:", 4))) + return(oldbase); + } + } + 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); + } + return(oldbase); +} + +/** + * xmlNodeBufGetContent: + * @buffer: a buffer + * @cur: the node being read + * + * Read the value of a node @cur, this can be either the text carried + * directly by this node if it's a TEXT node or the aggregate string + * of the values carried by this node child's (TEXT and ENTITY_REF). + * Entity references are substituted. + * Fills up the buffer @buffer with this value + * + * Returns 0 in case of success and -1 in case of error. + */ +int +xmlNodeBufGetContent(xmlBufferPtr buffer, xmlNodePtr cur) +{ + if ((cur == NULL) || (buffer == NULL)) return(-1); + switch (cur->type) { + case XML_CDATA_SECTION_NODE: + case XML_TEXT_NODE: + xmlBufferCat(buffer, cur->content); + break; + case XML_DOCUMENT_FRAG_NODE: + case XML_ELEMENT_NODE:{ + xmlNodePtr tmp = cur; + + while (tmp != NULL) { + switch (tmp->type) { + case XML_CDATA_SECTION_NODE: + case XML_TEXT_NODE: + if (tmp->content != NULL) + xmlBufferCat(buffer, tmp->content); + break; + case XML_ENTITY_REF_NODE: + xmlNodeBufGetContent(buffer, 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; + + while (tmp != NULL) { + if (tmp->type == XML_TEXT_NODE) + xmlBufferCat(buffer, tmp->content); + else + xmlNodeBufGetContent(buffer, tmp); + tmp = tmp->next; + } + break; + } + case XML_COMMENT_NODE: + case XML_PI_NODE: + xmlBufferCat(buffer, 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) { + xmlNodeBufGetContent(buffer, 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: + break; + case XML_DOCUMENT_NODE: +#ifdef LIBXML_DOCB_ENABLED + case XML_DOCB_DOCUMENT_NODE: +#endif + 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)) { + xmlNodeBufGetContent(buffer, cur); + } + cur = cur->next; + } + break; + case XML_NAMESPACE_DECL: + xmlBufferCat(buffer, ((xmlNsPtr) cur)->href); + break; + case XML_ELEMENT_DECL: + case XML_ATTRIBUTE_DECL: + case XML_ENTITY_DECL: + break; + } + return(0); +} +/** + * xmlNodeGetContent: + * @cur: the node being read + * + * Read the value of a node, this can be either the text carried + * directly by this node if it's a TEXT node or the aggregate string + * of the values carried by this node child's (TEXT and ENTITY_REF). + * Entity references are substituted. + * Returns a new #xmlChar * or NULL if no content is available. + * It's up to the caller to free the memory with xmlFree(). + */ +xmlChar * +xmlNodeGetContent(xmlNodePtr cur) +{ + if (cur == NULL) + return (NULL); + switch (cur->type) { + case XML_DOCUMENT_FRAG_NODE: + case XML_ELEMENT_NODE:{ + xmlBufferPtr buffer; + xmlChar *ret; + + buffer = xmlBufferCreateSize(64); + if (buffer == NULL) + return (NULL); + xmlNodeBufGetContent(buffer, cur); + ret = buffer->content; + buffer->content = NULL; + xmlBufferFree(buffer); + return (ret); + } + 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; + xmlBufferPtr buffer; + xmlChar *ret; + + /* lookup entity declaration */ + ent = xmlGetDocEntity(cur->doc, cur->name); + if (ent == NULL) + return (NULL); + + buffer = xmlBufferCreate(); + if (buffer == NULL) + return (NULL); + + xmlNodeBufGetContent(buffer, cur); + + ret = buffer->content; + buffer->content = NULL; + xmlBufferFree(buffer); + return (ret); + } + 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: +#ifdef LIBXML_DOCB_ENABLED + case XML_DOCB_DOCUMENT_NODE: +#endif + case XML_HTML_DOCUMENT_NODE: { + xmlBufferPtr buffer; + xmlChar *ret; + + buffer = xmlBufferCreate(); + if (buffer == NULL) + return (NULL); + + xmlNodeBufGetContent(buffer, (xmlNodePtr) cur); + + ret = buffer->content; + buffer->content = NULL; + xmlBufferFree(buffer); + return (ret); + } + case XML_NAMESPACE_DECL: { + xmlChar *tmp; + + 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: + if (cur->content != NULL) + return (xmlStrdup(cur->content)); + return (NULL); + } + return (NULL); +} + +/** + * 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) { + if (cur == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlNodeSetContent : node == NULL\n"); +#endif + 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 = xmlStringGetNodeList(cur->doc, content); + 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: + 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; + if (content != NULL) { + cur->content = xmlStrdup(content); + } else + cur->content = NULL; + cur->properties = NULL; + cur->nsDef = NULL; + break; + case XML_DOCUMENT_NODE: + case XML_HTML_DOCUMENT_NODE: + case XML_DOCUMENT_TYPE_NODE: + case XML_XINCLUDE_START: + case XML_XINCLUDE_END: +#ifdef LIBXML_DOCB_ENABLED + case XML_DOCB_DOCUMENT_NODE: +#endif + 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 !!! */ + break; + } +} + +#ifdef LIBXML_TREE_ENABLED +/** + * xmlNodeSetContentLen: + * @cur: the node being modified + * @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(). + */ +void +xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) { + if (cur == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlNodeSetContentLen : node == NULL\n"); +#endif + 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; + cur->nsDef = 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: +#ifdef LIBXML_DOCB_ENABLED + case XML_DOCB_DOCUMENT_NODE: +#endif + break; + case XML_ELEMENT_DECL: + /* TODO !!! */ + break; + case XML_ATTRIBUTE_DECL: + /* TODO !!! */ + break; + case XML_ENTITY_DECL: + /* TODO !!! */ + break; + } +} +#endif /* LIBXML_TREE_ENABLED */ + +/** + * xmlNodeAddContentLen: + * @cur: the node being modified + * @content: extra content + * @len: the size of @content + * + * Append the extra substring to the node content. + * NOTE: In contrast to xmlNodeSetContentLen(), @content is supposed to be + * raw text, so unescaped XML special chars are allowed, entity + * references are not supported. + */ +void +xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) { + if (cur == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlNodeAddContentLen : node == NULL\n"); +#endif + return; + } + if (len <= 0) return; + switch (cur->type) { + case XML_DOCUMENT_FRAG_NODE: + case XML_ELEMENT_NODE: { + xmlNodePtr last, newNode, tmp; + + last = cur->last; + newNode = xmlNewTextLen(content, len); + if (newNode != NULL) { + tmp = xmlAddChild(cur, newNode); + if (tmp != newNode) + return; + if ((last != NULL) && (last->next == newNode)) { + xmlTextMerge(last, newNode); + } + } + 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; + cur->nsDef = NULL; + break; + } + cur->content = xmlStrncat(cur->content, content, len); + } + 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: +#ifdef LIBXML_DOCB_ENABLED + case XML_DOCB_DOCUMENT_NODE: +#endif + break; + case XML_ELEMENT_DECL: + case XML_ATTRIBUTE_DECL: + case XML_ENTITY_DECL: + break; + } +} + +/** + * xmlNodeAddContent: + * @cur: the node being modified + * @content: extra content + * + * Append the extra substring to the node content. + * NOTE: In contrast to xmlNodeSetContent(), @content is supposed to be + * raw text, so unescaped XML special chars are allowed, entity + * references are not supported. + */ +void +xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) { + int len; + + if (cur == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlNodeAddContent : node == NULL\n"); +#endif + return; + } + if (content == NULL) return; + len = xmlStrlen(content); + xmlNodeAddContentLen(cur, content, len); +} + +/** + * xmlTextMerge: + * @first: the first text node + * @second: the second text node being merged + * + * Merge two text nodes into one + * Returns the first text node augmented + */ +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); + xmlFreeNode(second); + return(first); +} + +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) +/** + * xmlGetNsList: + * @doc: the document + * @node: the current node + * + * 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 + */ +xmlNsPtr * +xmlGetNsList(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node) +{ + xmlNsPtr cur; + xmlNsPtr *ret = NULL; + int nbns = 0; + int maxns = 10; + int i; + + while (node != NULL) { + if (node->type == XML_ELEMENT_NODE) { + cur = node->nsDef; + while (cur != NULL) { + if (ret == NULL) { + ret = + (xmlNsPtr *) xmlMalloc((maxns + 1) * + sizeof(xmlNsPtr)); + if (ret == NULL) { + xmlTreeErrMemory("getting namespace list"); + return (NULL); + } + ret[nbns] = NULL; + } + for (i = 0; i < nbns; i++) { + if ((cur->prefix == ret[i]->prefix) || + (xmlStrEqual(cur->prefix, ret[i]->prefix))) + break; + } + if (i >= nbns) { + if (nbns >= maxns) { + maxns *= 2; + ret = (xmlNsPtr *) xmlRealloc(ret, + (maxns + + 1) * + sizeof(xmlNsPtr)); + if (ret == NULL) { + xmlTreeErrMemory("getting namespace list"); + return (NULL); + } + } + ret[nbns++] = cur; + ret[nbns] = NULL; + } + + cur = cur->next; + } + } + node = node->parent; + } + return (ret); +} +#endif /* LIBXML_TREE_ENABLED */ + +/* +* 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. +*/ +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; + return (ns); + } +} + +/** + * xmlSearchNs: + * @doc: the document + * @node: the current node + * @nameSpace: the namespace prefix + * + * Search a Ns registered under a given name space for a document. + * recurse on the parents until it finds the defined namespace + * or return NULL otherwise. + * @nameSpace can be NULL, this is a search for the default namespace. + * We don't allow to cross entities boundaries. If you don't declare + * the namespace within those you will be in troubles !!! A warning + * is generated to cover this case. + * + * Returns the namespace pointer or NULL. + */ +xmlNsPtr +xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) { + + xmlNsPtr cur; + xmlNodePtr orig = node; + + if (node == NULL) 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); +} + +/** + * xmlNsInScope: + * @doc: the document + * @node: the current node + * @ancestor: the ancestor carrying the namespace + * @prefix: the namespace prefix + * + * Verify that the given namespace held on @ancestor is still in scope + * on node. + * + * Returns 1 if true, 0 if false and -1 in case of error. + */ +static int +xmlNsInScope(xmlDocPtr doc ATTRIBUTE_UNUSED, xmlNodePtr node, + xmlNodePtr ancestor, const xmlChar * prefix) +{ + xmlNsPtr tst; + + 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) { + tst = node->nsDef; + while (tst != NULL) { + if ((tst->prefix == NULL) + && (prefix == NULL)) + return (0); + if ((tst->prefix != NULL) + && (prefix != NULL) + && (xmlStrEqual(tst->prefix, prefix))) + return (0); + tst = tst->next; + } + } + node = node->parent; + } + if (node != ancestor) + return (-1); + return (1); +} + +/** + * 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. + */ +xmlNsPtr +xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar * href) +{ + xmlNsPtr cur; + xmlNodePtr orig = node; + int is_attr; + + if ((node == NULL) || (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); + } + 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); + } + 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); + } + } + } + } + node = node->parent; + } + return (NULL); +} + +/** + * xmlNewReconciliedNs: + * @doc: the document + * @tree: a node expected to hold the new namespace + * @ns: the original namespace + * + * This function tries to locate a namespace definition in a tree + * ancestors, or create a new namespace definition node similar to + * @ns trying to reuse the same prefix. However if the given prefix is + * null (default namespace) or reused within the subtree defined by + * @tree or on one of its ancestors then a new prefix is generated. + * Returns the (new) namespace definition or NULL in case of error + */ +static xmlNsPtr +xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) { + xmlNsPtr def; + xmlChar prefix[50]; + int counter = 1; + + if (tree == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlNewReconciliedNs : tree == NULL\n"); +#endif + return(NULL); + } + if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlNewReconciliedNs : ns == NULL\n"); +#endif + return(NULL); + } + /* + * Search an existing namespace definition inherited. + */ + def = xmlSearchNsByHref(doc, tree, ns->href); + if (def != NULL) + return(def); + + /* + * Find a close prefix which is not already in use. + * Let's strip namespace prefixes longer than 20 chars ! + */ + if (ns->prefix == NULL) + snprintf((char *) prefix, sizeof(prefix), "default"); + else + snprintf((char *) prefix, sizeof(prefix), "%.20s", (char *)ns->prefix); + + def = xmlSearchNs(doc, tree, prefix); + while (def != NULL) { + if (counter > 1000) return(NULL); + if (ns->prefix == NULL) + snprintf((char *) prefix, sizeof(prefix), "default%d", counter++); + else + snprintf((char *) prefix, sizeof(prefix), "%.20s%d", + (char *)ns->prefix, counter++); + def = xmlSearchNs(doc, tree, prefix); + } + + /* + * OK, now we are ready to create a new one. + */ + def = xmlNewNs(tree, ns->href, prefix); + return(def); +} + +#ifdef LIBXML_TREE_ENABLED +/** + * xmlReconciliateNs: + * @doc: the document + * @tree: a node defining the subtree to reconciliate + * + * This function checks that all the namespaces declared within the given + * tree are properly declared. This is needed for example after Copy or Cut + * and then paste operations. The subtree may still hold pointers to + * namespace declarations outside the subtree or invalid/masked. As much + * 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. + */ +int +xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) { + xmlNsPtr *oldNs = NULL; + xmlNsPtr *newNs = NULL; + int sizeCache = 0; + int nbCache = 0; + + xmlNsPtr n; + xmlNodePtr node = tree; + xmlAttrPtr attr; + 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]; + break; + } + } + if (i == nbCache) { + /* + * OK we need to recreate a new namespace definition + */ + n = xmlNewReconciliedNs(doc, tree, node->ns); + if (n != NULL) { /* :-( what if 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); + } + } + newNs[nbCache] = n; + oldNs[nbCache++] = node->ns; + node->ns = n; + } + } + } + /* + * now check for namespace hold by attributes on the node. + */ + if (node->type == XML_ELEMENT_NODE) { + 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]; + break; + } + } + if (i == nbCache) { + /* + * OK we need to recreate a new namespace definition + */ + n = xmlNewReconciliedNs(doc, tree, attr->ns); + if (n != NULL) { /* :-( what if 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); + } + } + newNs[nbCache] = n; + oldNs[nbCache++] = attr->ns; + attr->ns = n; + } + } + } + attr = attr->next; + } + } + + /* + * Browse the full subtree, deep first + */ + if ((node->children != NULL) && (node->type != XML_ENTITY_REF_NODE)) { + /* deep first */ + node = node->children; + } else if ((node != tree) && (node->next != NULL)) { + /* then siblings */ + node = node->next; + } else if (node != tree) { + /* go up to parents->next if needed */ + while (node != tree) { + if (node->parent != NULL) + node = node->parent; + if ((node != tree) && (node->next != NULL)) { + node = node->next; + break; + } + if (node->parent == NULL) { + node = NULL; + break; + } + } + /* exit condition */ + if (node == tree) + node = NULL; + } else + break; + } + if (oldNs != NULL) + xmlFree(oldNs); + if (newNs != NULL) + xmlFree(newNs); + return(ret); +} +#endif /* LIBXML_TREE_ENABLED */ + +static xmlAttrPtr +xmlGetPropNodeInternal(xmlNodePtr node, const xmlChar *name, + const xmlChar *nsName, int useDTD) +{ + xmlAttrPtr prop; + + if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL)) + return(NULL); + + if (node->properties != NULL) { + prop = node->properties; + if (nsName == NULL) { + /* + * We want the attr to be in no namespace. + */ + do { + if ((prop->ns == NULL) && xmlStrEqual(prop->name, name)) { + return(prop); + } + prop = prop->next; + } while (prop != NULL); + } else { + /* + * We want the attr to be in the specified namespace. + */ + do { + if ((prop->ns != NULL) && xmlStrEqual(prop->name, name) && + ((prop->ns->href == nsName) || + xmlStrEqual(prop->ns->href, nsName))) + { + return(prop); + } + prop = prop->next; + } while (prop != NULL); + } + } + +#ifdef LIBXML_TREE_ENABLED + if (! useDTD) + return(NULL); + /* + * Check if there is a default/fixed attribute declaration in + * the internal or external subset. + */ + if ((node->doc != NULL) && (node->doc->intSubset != NULL)) { + xmlDocPtr doc = node->doc; + xmlAttributePtr attrDecl = NULL; + xmlChar *elemQName, *tmpstr = NULL; + + /* + * We need the QName of the element for the DTD-lookup. + */ + if ((node->ns != NULL) && (node->ns->prefix != NULL)) { + tmpstr = xmlStrdup(node->ns->prefix); + tmpstr = xmlStrcat(tmpstr, BAD_CAST ":"); + tmpstr = xmlStrcat(tmpstr, node->name); + if (tmpstr == NULL) + return(NULL); + elemQName = tmpstr; + } else + elemQName = (xmlChar *) node->name; + if (nsName == NULL) { + /* + * The common and nice case: Attr in no namespace. + */ + attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, + elemQName, name, NULL); + if ((attrDecl == NULL) && (doc->extSubset != NULL)) { + attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, + elemQName, name, NULL); + } + } else { + xmlNsPtr *nsList, *cur; + + /* + * The ugly case: Search using the prefixes of in-scope + * ns-decls corresponding to @nsName. + */ + nsList = xmlGetNsList(node->doc, node); + if (nsList == NULL) { + if (tmpstr != NULL) + xmlFree(tmpstr); + return(NULL); + } + cur = nsList; + while (*cur != NULL) { + if (xmlStrEqual((*cur)->href, nsName)) { + attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elemQName, + name, (*cur)->prefix); + if (attrDecl) + break; + if (doc->extSubset != NULL) { + attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elemQName, + name, (*cur)->prefix); + if (attrDecl) + break; + } + } + cur++; + } + xmlFree(nsList); + } + if (tmpstr != NULL) + xmlFree(tmpstr); + /* + * Only default/fixed attrs are relevant. + */ + if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL)) + return((xmlAttrPtr) attrDecl); + } +#endif /* LIBXML_TREE_ENABLED */ + return(NULL); +} + +static xmlChar* +xmlGetPropNodeValueInternal(xmlAttrPtr 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 *)"")); + } else if (prop->type == XML_ATTRIBUTE_DECL) { + return(xmlStrdup(((xmlAttributePtr)prop)->defaultValue)); + } + return(NULL); +} + +/** + * xmlHasProp: + * @node: the node + * @name: the attribute name + * + * 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. + * + * Returns the attribute or the attribute declaration or NULL if + * neither was found. + */ +xmlAttrPtr +xmlHasProp(xmlNodePtr node, const xmlChar *name) { + xmlAttrPtr prop; + xmlDocPtr doc; + + if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || (name == NULL)) + return(NULL); + /* + * Check on the properties attached to the node + */ + prop = node->properties; + while (prop != NULL) { + if (xmlStrEqual(prop->name, name)) { + return(prop); + } + prop = prop->next; + } + if (!xmlCheckDTD) return(NULL); + + /* + * Check if there is a default declaration in the internal + * or external subsets + */ + doc = node->doc; + if (doc != NULL) { + xmlAttributePtr attrDecl; + if (doc->intSubset != NULL) { + attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name); + if ((attrDecl == NULL) && (doc->extSubset != NULL)) + attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name); + if ((attrDecl != NULL) && (attrDecl->defaultValue != NULL)) + /* return attribute declaration only if a default value is given + (that includes #FIXED declarations) */ + return((xmlAttrPtr) attrDecl); + } + } + return(NULL); +} + +/** + * xmlHasNsProp: + * @node: the node + * @name: the attribute name + * @nameSpace: the URI of the namespace + * + * Search for an attribute associated to a node + * 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. + * 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. + */ +xmlAttrPtr +xmlHasNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) { + + return(xmlGetPropNodeInternal(node, name, nameSpace, xmlCheckDTD)); +} + +/** + * xmlGetProp: + * @node: the node + * @name: the attribute 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. + * 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(). + */ +xmlChar * +xmlGetProp(xmlNodePtr node, const xmlChar *name) { + xmlAttrPtr prop; + + prop = xmlHasProp(node, name); + if (prop == NULL) + return(NULL); + return(xmlGetPropNodeValueInternal(prop)); +} + +/** + * xmlGetNoNsProp: + * @node: the node + * @name: the attribute 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. + * 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(). + */ +xmlChar * +xmlGetNoNsProp(xmlNodePtr node, const xmlChar *name) { + xmlAttrPtr prop; + + prop = xmlGetPropNodeInternal(node, name, NULL, xmlCheckDTD); + if (prop == NULL) + return(NULL); + return(xmlGetPropNodeValueInternal(prop)); +} + +/** + * xmlGetNsProp: + * @node: the node + * @name: the attribute name + * @nameSpace: the URI of the namespace + * + * 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. + * This function looks in DTD attribute declaration for #FIXED or + * default declaration values unless DTD use has been turned off. + * + * Returns the attribute value or NULL if not found. + * It's up to the caller to free the memory with xmlFree(). + */ +xmlChar * +xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) { + xmlAttrPtr prop; + + prop = xmlGetPropNodeInternal(node, name, nameSpace, xmlCheckDTD); + if (prop == NULL) + return(NULL); + return(xmlGetPropNodeValueInternal(prop)); +} + +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) +/** + * xmlUnsetProp: + * @node: the node + * @name: the attribute name + * + * Remove an attribute carried by a node. + * This handles only attributes in no namespace. + * Returns 0 if successful, -1 if not found + */ +int +xmlUnsetProp(xmlNodePtr node, const xmlChar *name) { + xmlAttrPtr prop; + + prop = xmlGetPropNodeInternal(node, name, NULL, 0); + if (prop == NULL) + return(-1); + xmlUnlinkNode((xmlNodePtr) prop); + xmlFreeProp(prop); + return(0); +} + +/** + * xmlUnsetNsProp: + * @node: the node + * @ns: the namespace definition + * @name: the attribute name + * + * Remove an attribute carried by a node. + * Returns 0 if successful, -1 if not found + */ +int +xmlUnsetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name) { + xmlAttrPtr prop; + + prop = xmlGetPropNodeInternal(node, name, (ns != NULL) ? ns->href : NULL, 0); + if (prop == NULL) + return(-1); + xmlUnlinkNode((xmlNodePtr) prop); + xmlFreeProp(prop); + return(0); +} +#endif + +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_XINCLUDE_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) +/** + * xmlSetProp: + * @node: the node + * @name: the attribute name (a QName) + * @value: the attribute value + * + * Set (or reset) an attribute carried by a node. + * If @name has a prefix, then the corresponding + * namespace-binding will be used, if in scope; it is an + * error it there's no such ns-binding for the prefix in + * scope. + * Returns the attribute pointer. + * + */ +xmlAttrPtr +xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) { + int len; + const xmlChar *nqname; + + if ((node == NULL) || (name == NULL) || (node->type != XML_ELEMENT_NODE)) + return(NULL); + + /* + * 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)); + } + return(xmlSetNsProp(node, NULL, name, value)); +} + +/** + * xmlSetNsProp: + * @node: the node + * @ns: the namespace definition + * @name: the attribute name + * @value: the attribute value + * + * Set (or reset) an attribute carried by a node. + * The ns structure must be in scope, this is not checked + * + * Returns the attribute pointer. + */ +xmlAttrPtr +xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name, + const xmlChar *value) +{ + xmlAttrPtr prop; + + if (ns && (ns->href == NULL)) + return(NULL); + prop = xmlGetPropNodeInternal(node, name, (ns != NULL) ? ns->href : NULL, 0); + if (prop != NULL) { + /* + * Modify the attribute's value. + */ + if (prop->atype == XML_ATTRIBUTE_ID) { + xmlRemoveID(node->doc, prop); + prop->atype = XML_ATTRIBUTE_ID; + } + if (prop->children != NULL) + xmlFreeNodeList(prop->children); + prop->children = NULL; + prop->last = NULL; + prop->ns = ns; + if (value != NULL) { + xmlNodePtr tmp; + + if(!xmlCheckUTF8(value)) { + xmlTreeErr(XML_TREE_NOT_UTF8, (xmlNodePtr) node->doc, + NULL); + if (node->doc != NULL) + node->doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1"); + } + prop->children = xmlNewDocText(node->doc, value); + prop->last = NULL; + tmp = prop->children; + while (tmp != NULL) { + tmp->parent = (xmlNodePtr) prop; + if (tmp->next == NULL) + prop->last = tmp; + tmp = tmp->next; + } + } + if (prop->atype == XML_ATTRIBUTE_ID) + xmlAddID(NULL, node->doc, value, prop); + return(prop); + } + /* + * No equal attr found; create a new one. + */ + return(xmlNewPropInternal(node, ns, name, value, 0)); +} + +#endif /* LIBXML_TREE_ENABLED */ + +/** + * xmlNodeIsText: + * @node: the node + * + * Is this node a Text node ? + * Returns 1 yes, 0 no + */ +int +xmlNodeIsText(xmlNodePtr node) { + if (node == NULL) return(0); + + if (node->type == XML_TEXT_NODE) return(1); + return(0); +} + +/** + * xmlIsBlankNode: + * @node: the node + * + * Checks whether this node is an empty or whitespace only + * (and possibly ignorable) text-node. + * + * Returns 1 yes, 0 no + */ +int +xmlIsBlankNode(xmlNodePtr node) { + const xmlChar *cur; + if (node == NULL) return(0); + + if ((node->type != XML_TEXT_NODE) && + (node->type != XML_CDATA_SECTION_NODE)) + return(0); + if (node->content == NULL) return(1); + cur = node->content; + while (*cur != 0) { + if (!IS_BLANK_CH(*cur)) return(0); + cur++; + } + + return(1); +} + +/** + * xmlTextConcat: + * @node: the node + * @content: the content + * @len: @content length + * + * Concat the given string at the end of the existing node content + * + * Returns -1 in case of error, 0 otherwise + */ + +int +xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) { + 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)) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlTextConcat: node is not text nor CDATA\n"); +#endif + 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); +} + +/************************************************************************ + * * + * Output : to a FILE or in memory * + * * + ************************************************************************/ + +/** + * xmlBufferCreate: + * + * routine to create an XML buffer. + * returns the new structure. + */ +xmlBufferPtr +xmlBufferCreate(void) { + xmlBufferPtr ret; + + ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer)); + if (ret == NULL) { + xmlTreeErrMemory("creating buffer"); + return(NULL); + } + ret->use = 0; + ret->size = xmlDefaultBufferSize; + ret->alloc = xmlBufferAllocScheme; + ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar)); + if (ret->content == NULL) { + xmlTreeErrMemory("creating buffer"); + xmlFree(ret); + return(NULL); + } + ret->content[0] = 0; + ret->contentIO = NULL; + return(ret); +} + +/** + * xmlBufferCreateSize: + * @size: initial size of buffer + * + * routine to create an XML buffer. + * returns the new structure. + */ +xmlBufferPtr +xmlBufferCreateSize(size_t size) { + xmlBufferPtr ret; + + ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer)); + if (ret == NULL) { + xmlTreeErrMemory("creating buffer"); + return(NULL); + } + ret->use = 0; + ret->alloc = xmlBufferAllocScheme; + ret->size = (size ? size+2 : 0); /* +1 for ending null */ + if (ret->size){ + ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar)); + if (ret->content == NULL) { + xmlTreeErrMemory("creating buffer"); + xmlFree(ret); + return(NULL); + } + ret->content[0] = 0; + } else + ret->content = NULL; + ret->contentIO = NULL; + return(ret); +} + +/** + * xmlBufferCreateStatic: + * @mem: the memory area + * @size: the size in byte + * + * routine to create an XML buffer from an immutable memory area. + * The area won't be modified nor copied, and is expected to be + * present until the end of the buffer lifetime. + * + * returns the new structure. + */ +xmlBufferPtr +xmlBufferCreateStatic(void *mem, size_t size) { + xmlBufferPtr ret; + + if ((mem == NULL) || (size == 0)) + return(NULL); + + ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer)); + if (ret == NULL) { + xmlTreeErrMemory("creating buffer"); + return(NULL); + } + ret->use = size; + ret->size = size; + ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE; + ret->content = (xmlChar *) mem; + return(ret); +} + +/** + * xmlBufferSetAllocationScheme: + * @buf: the buffer to tune + * @scheme: allocation scheme to use + * + * Sets the allocation scheme for this buffer + */ +void +xmlBufferSetAllocationScheme(xmlBufferPtr buf, + xmlBufferAllocationScheme scheme) { + if (buf == NULL) { +#ifdef DEBUG_BUFFER + xmlGenericError(xmlGenericErrorContext, + "xmlBufferSetAllocationScheme: buf == NULL\n"); +#endif + return; + } + if ((buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) || + (buf->alloc == XML_BUFFER_ALLOC_IO)) return; + if ((scheme == XML_BUFFER_ALLOC_DOUBLEIT) || + (scheme == XML_BUFFER_ALLOC_EXACT) || + (scheme == XML_BUFFER_ALLOC_IMMUTABLE)) + buf->alloc = scheme; +} + +/** + * xmlBufferFree: + * @buf: the buffer to free + * + * Frees an XML buffer. It frees both the content and the structure which + * encapsulate it. + */ +void +xmlBufferFree(xmlBufferPtr buf) { + if (buf == NULL) { +#ifdef DEBUG_BUFFER + xmlGenericError(xmlGenericErrorContext, + "xmlBufferFree: buf == NULL\n"); +#endif + return; + } + + if ((buf->alloc == XML_BUFFER_ALLOC_IO) && + (buf->contentIO != NULL)) { + xmlFree(buf->contentIO); + } else if ((buf->content != NULL) && + (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) { + xmlFree(buf->content); + } + xmlFree(buf); +} + +/** + * xmlBufferEmpty: + * @buf: the buffer + * + * empty a buffer. + */ +void +xmlBufferEmpty(xmlBufferPtr buf) { + if (buf == NULL) return; + if (buf->content == NULL) return; + buf->use = 0; + if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) { + buf->content = BAD_CAST ""; + } else if ((buf->alloc == XML_BUFFER_ALLOC_IO) && + (buf->contentIO != NULL)) { + size_t start_buf = buf->content - buf->contentIO; + + buf->size += start_buf; + buf->content = buf->contentIO; + buf->content[0] = 0; + } else { + buf->content[0] = 0; + } +} + +/** + * xmlBufferShrink: + * @buf: the buffer to dump + * @len: the number of xmlChar to remove + * + * Remove the beginning of an XML buffer. + * + * Returns the number of #xmlChar removed, or -1 in case of failure. + */ +int +xmlBufferShrink(xmlBufferPtr buf, unsigned int len) { + if (buf == NULL) return(-1); + if (len == 0) return(0); + if (len > buf->use) return(-1); + + buf->use -= len; + if ((buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) || + ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL))) { + /* + * we just move the content pointer, but also make sure + * the perceived buffer size has shrinked accordingly + */ + buf->content += len; + buf->size -= len; + + /* + * sometimes though it maybe be better to really shrink + * on IO buffers + */ + if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) { + size_t start_buf = buf->content - buf->contentIO; + if (start_buf >= buf->size) { + memmove(buf->contentIO, &buf->content[0], buf->use); + buf->content = buf->contentIO; + buf->content[buf->use] = 0; + buf->size += start_buf; + } + } + } else { + memmove(buf->content, &buf->content[len], buf->use); + buf->content[buf->use] = 0; + } + return(len); +} + +/** + * xmlBufferGrow: + * @buf: the buffer + * @len: the minimum free size to allocate + * + * Grow the available space of an XML buffer. + * + * Returns the new available space or -1 in case of error + */ +int +xmlBufferGrow(xmlBufferPtr buf, unsigned int len) { + int size; + xmlChar *newbuf; + + if (buf == NULL) return(-1); + + if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0); + if (len + buf->use < buf->size) return(0); + + /* + * Windows has a BIG problem on realloc timing, so we try to double + * the buffer size (if that's enough) (bug 146697) + * Apparently BSD too, and it's probably best for linux too + * On an embedded system this may be something to change + */ +#if 1 + if (buf->size > len) + size = buf->size * 2; + else + size = buf->use + len + 100; +#else + size = buf->use + len + 100; +#endif + + if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) { + size_t start_buf = buf->content - buf->contentIO; + + newbuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + size); + if (newbuf == NULL) { + xmlTreeErrMemory("growing buffer"); + return(-1); + } + buf->contentIO = newbuf; + buf->content = newbuf + start_buf; + } else { + newbuf = (xmlChar *) xmlRealloc(buf->content, size); + if (newbuf == NULL) { + xmlTreeErrMemory("growing buffer"); + return(-1); + } + buf->content = newbuf; + } + buf->size = size; + return(buf->size - buf->use); +} + +/** + * xmlBufferDump: + * @file: the file output + * @buf: the buffer to dump + * + * Dumps an XML buffer to a FILE *. + * Returns the number of #xmlChar written + */ +int +xmlBufferDump(FILE *file, xmlBufferPtr buf) { + int ret; + + if (buf == NULL) { +#ifdef DEBUG_BUFFER + xmlGenericError(xmlGenericErrorContext, + "xmlBufferDump: buf == NULL\n"); +#endif + return(0); + } + if (buf->content == NULL) { +#ifdef DEBUG_BUFFER + xmlGenericError(xmlGenericErrorContext, + "xmlBufferDump: buf->content == NULL\n"); +#endif + return(0); + } + if (file == NULL) + file = stdout; + ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file); + return(ret); +} + +/** + * xmlBufferContent: + * @buf: the buffer + * + * Function to extract the content of a buffer + * + * Returns the internal content + */ + +const xmlChar * +xmlBufferContent(const xmlBufferPtr buf) +{ + if(!buf) + return NULL; + + return buf->content; +} + +/** + * xmlBufferLength: + * @buf: the buffer + * + * Function to get the length of a buffer + * + * Returns the length of data in the internal content + */ + +int +xmlBufferLength(const xmlBufferPtr buf) +{ + if(!buf) + return 0; + + return buf->use; +} + +/** + * xmlBufferResize: + * @buf: the buffer to resize + * @size: the desired size + * + * Resize a buffer to accommodate minimum size of @size. + * + * Returns 0 in case of problems, 1 otherwise + */ +int +xmlBufferResize(xmlBufferPtr buf, unsigned int size) +{ + unsigned int newSize; + xmlChar* rebuf = NULL; + size_t start_buf; + + if (buf == NULL) + return(0); + + if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0); + + /* Don't resize if we don't have to */ + if (size < buf->size) + return 1; + + /* figure out new size */ + switch (buf->alloc){ + case XML_BUFFER_ALLOC_IO: + case XML_BUFFER_ALLOC_DOUBLEIT: + /*take care of empty case*/ + newSize = (buf->size ? buf->size*2 : size + 10); + while (size > newSize) { + if (newSize > UINT_MAX / 2) { + xmlTreeErrMemory("growing buffer"); + return 0; + } + newSize *= 2; + } + break; + case XML_BUFFER_ALLOC_EXACT: + newSize = size+10; + break; + default: + newSize = size+10; + break; + } + + if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) { + start_buf = buf->content - buf->contentIO; + + if (start_buf > newSize) { + /* move data back to start */ + memmove(buf->contentIO, buf->content, buf->use); + buf->content = buf->contentIO; + buf->content[buf->use] = 0; + buf->size += start_buf; + } else { + rebuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + newSize); + if (rebuf == NULL) { + xmlTreeErrMemory("growing buffer"); + return 0; + } + buf->contentIO = rebuf; + buf->content = rebuf + start_buf; + } + } else { + if (buf->content == NULL) { + rebuf = (xmlChar *) xmlMallocAtomic(newSize); + } else if (buf->size - buf->use < 100) { + rebuf = (xmlChar *) xmlRealloc(buf->content, newSize); + } else { + /* + * if we are reallocating a buffer far from being full, it's + * better to make a new allocation and copy only the used range + * and free the old one. + */ + rebuf = (xmlChar *) xmlMallocAtomic(newSize); + if (rebuf != NULL) { + memcpy(rebuf, buf->content, buf->use); + xmlFree(buf->content); + rebuf[buf->use] = 0; + } + } + if (rebuf == NULL) { + xmlTreeErrMemory("growing buffer"); + return 0; + } + buf->content = rebuf; + } + buf->size = newSize; + + return 1; +} + +/** + * xmlBufferAdd: + * @buf: the buffer to dump + * @str: the #xmlChar string + * @len: the number of #xmlChar to add + * + * 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. + */ +int +xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) { + unsigned int needSize; + + if ((str == NULL) || (buf == NULL)) { + return -1; + } + if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1; + if (len < -1) { +#ifdef DEBUG_BUFFER + xmlGenericError(xmlGenericErrorContext, + "xmlBufferAdd: len < 0\n"); +#endif + return -1; + } + if (len == 0) return 0; + + if (len < 0) + len = xmlStrlen(str); + + if (len < 0) return -1; + if (len == 0) return 0; + + needSize = buf->use + len + 2; + if (needSize > buf->size){ + if (!xmlBufferResize(buf, needSize)){ + xmlTreeErrMemory("growing buffer"); + return XML_ERR_NO_MEMORY; + } + } + + memmove(&buf->content[buf->use], str, len*sizeof(xmlChar)); + buf->use += len; + buf->content[buf->use] = 0; + return 0; +} + +/** + * xmlBufferAddHead: + * @buf: the buffer + * @str: the #xmlChar string + * @len: the number of #xmlChar to add + * + * Add a string range to the beginning of 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. + */ +int +xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) { + unsigned int needSize; + + if (buf == NULL) + return(-1); + if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1; + if (str == NULL) { +#ifdef DEBUG_BUFFER + xmlGenericError(xmlGenericErrorContext, + "xmlBufferAddHead: str == NULL\n"); +#endif + return -1; + } + if (len < -1) { +#ifdef DEBUG_BUFFER + xmlGenericError(xmlGenericErrorContext, + "xmlBufferAddHead: len < 0\n"); +#endif + return -1; + } + if (len == 0) return 0; + + if (len < 0) + len = xmlStrlen(str); + + if (len <= 0) return -1; + + if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) { + size_t start_buf = buf->content - buf->contentIO; + + if (start_buf > (unsigned int) len) { + /* + * We can add it in the space previously shrinked + */ + buf->content -= len; + memmove(&buf->content[0], str, len); + buf->use += len; + buf->size += len; + return(0); + } + } + needSize = buf->use + len + 2; + if (needSize > buf->size){ + if (!xmlBufferResize(buf, needSize)){ + xmlTreeErrMemory("growing buffer"); + return XML_ERR_NO_MEMORY; + } + } + + memmove(&buf->content[len], &buf->content[0], buf->use); + memmove(&buf->content[0], str, len); + buf->use += len; + buf->content[buf->use] = 0; + return 0; +} + +/** + * xmlBufferCat: + * @buf: the buffer to add to + * @str: the #xmlChar string + * + * Append a zero terminated string to an XML buffer. + * + * Returns 0 successful, a positive error code number otherwise + * and -1 in case of internal or API error. + */ +int +xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) { + if (buf == NULL) + return(-1); + if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1; + if (str == NULL) return -1; + return xmlBufferAdd(buf, str, -1); +} + +/** + * xmlBufferCCat: + * @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 +xmlBufferCCat(xmlBufferPtr buf, const char *str) { + const char *cur; + + if (buf == NULL) + return(-1); + if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1; + if (str == NULL) { +#ifdef DEBUG_BUFFER + xmlGenericError(xmlGenericErrorContext, + "xmlBufferCCat: str == NULL\n"); +#endif + return -1; + } + for (cur = str;*cur != 0;cur++) { + if (buf->use + 10 >= buf->size) { + if (!xmlBufferResize(buf, buf->use+10)){ + xmlTreeErrMemory("growing buffer"); + return XML_ERR_NO_MEMORY; + } + } + buf->content[buf->use++] = *cur; + } + buf->content[buf->use] = 0; + return 0; +} + +/** + * xmlBufferWriteCHAR: + * @buf: the XML buffer + * @string: the string to add + * + * routine which manages and grows an output buffer. This one adds + * xmlChars at the end of the buffer. + */ +void +xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) { + if (buf == NULL) + return; + if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return; + xmlBufferCat(buf, string); +} + +/** + * xmlBufferWriteChar: + * @buf: the XML buffer output + * @string: the string to add + * + * routine which manage and grows an output buffer. This one add + * C chars at the end of the array. + */ +void +xmlBufferWriteChar(xmlBufferPtr buf, const char *string) { + if (buf == NULL) + return; + if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return; + xmlBufferCCat(buf, string); +} + + +/** + * xmlBufferWriteQuotedString: + * @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 + */ +void +xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) { + const xmlChar *cur, *base; + if (buf == NULL) + return; + if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return; + if (xmlStrchr(string, '\"')) { + if (xmlStrchr(string, '\'')) { +#ifdef DEBUG_BUFFER + xmlGenericError(xmlGenericErrorContext, + "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n"); +#endif + xmlBufferCCat(buf, "\""); + base = cur = string; + while(*cur != 0){ + 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{ + xmlBufferCCat(buf, "\'"); + xmlBufferCat(buf, string); + xmlBufferCCat(buf, "\'"); + } + } else { + xmlBufferCCat(buf, "\""); + xmlBufferCat(buf, string); + xmlBufferCCat(buf, "\""); + } +} + + +/** + * xmlGetDocCompressMode: + * @doc: the document + * + * get the compression ratio for a document, ZLIB based + * Returns 0 (uncompressed) to 9 (max compression) + */ +int +xmlGetDocCompressMode (xmlDocPtr doc) { + if (doc == NULL) return(-1); + return(doc->compression); +} + +/** + * xmlSetDocCompressMode: + * @doc: the document + * @mode: the compression ratio + * + * set the compression ratio for a document, ZLIB based + * Correct values: 0 (uncompressed) to 9 (max compression) + */ +void +xmlSetDocCompressMode (xmlDocPtr doc, int mode) { + if (doc == NULL) return; + if (mode < 0) doc->compression = 0; + else if (mode > 9) doc->compression = 9; + else doc->compression = mode; +} + +/** + * xmlGetCompressMode: + * + * get the default compression mode used, ZLIB based. + * Returns 0 (uncompressed) to 9 (max compression) + */ +int +xmlGetCompressMode(void) +{ + return (xmlCompressMode); +} + +/** + * xmlSetCompressMode: + * @mode: the compression ratio + * + * set the default compression mode used, ZLIB based + * Correct values: 0 (uncompressed) to 9 (max compression) + */ +void +xmlSetCompressMode(int mode) { + if (mode < 0) xmlCompressMode = 0; + else if (mode > 9) xmlCompressMode = 9; + else xmlCompressMode = mode; +} + +#define XML_TREE_NSMAP_PARENT -1 +#define XML_TREE_NSMAP_XML -2 +#define XML_TREE_NSMAP_DOC -3 +#define XML_TREE_NSMAP_CUSTOM -4 + +typedef struct xmlNsMapItem *xmlNsMapItemPtr; +struct xmlNsMapItem { + xmlNsMapItemPtr next; + xmlNsMapItemPtr prev; + xmlNsPtr oldNs; /* old ns decl reference */ + xmlNsPtr newNs; /* new ns decl reference */ + int shadowDepth; /* Shadowed at this depth */ + /* + * depth: + * >= 0 == @node's ns-decls + * -1 == @parent's ns-decls + * -2 == the doc->oldNs XML ns-decl + * -3 == the doc->oldNs storage ns-decls + * -4 == ns-decls provided via custom ns-handling + */ + int depth; +}; + +typedef struct xmlNsMap *xmlNsMapPtr; +struct xmlNsMap { + xmlNsMapItemPtr first; + xmlNsMapItemPtr last; + xmlNsMapItemPtr pool; +}; + +#define XML_NSMAP_NOTEMPTY(m) (((m) != NULL) && ((m)->first != NULL)) +#define XML_NSMAP_FOREACH(m, i) for (i = (m)->first; i != NULL; i = (i)->next) +#define XML_NSMAP_POP(m, i) \ + i = (m)->last; \ + (m)->last = (i)->prev; \ + if ((m)->last == NULL) \ + (m)->first = NULL; \ + else \ + (m)->last->next = NULL; \ + (i)->next = (m)->pool; \ + (m)->pool = i; + +/* +* xmlDOMWrapNsMapFree: +* @map: the ns-map +* +* Frees the ns-map +*/ +static void +xmlDOMWrapNsMapFree(xmlNsMapPtr nsmap) +{ + xmlNsMapItemPtr cur, tmp; + + if (nsmap == NULL) + return; + cur = nsmap->pool; + while (cur != NULL) { + tmp = cur; + cur = cur->next; + xmlFree(tmp); + } + cur = nsmap->first; + while (cur != NULL) { + tmp = cur; + cur = cur->next; + xmlFree(tmp); + } + xmlFree(nsmap); +} + +/* +* xmlDOMWrapNsMapAddItem: +* @map: the ns-map +* @oldNs: the old ns-struct +* @newNs: the new ns-struct +* @depth: depth and ns-kind information +* +* Adds an ns-mapping item. +*/ +static xmlNsMapItemPtr +xmlDOMWrapNsMapAddItem(xmlNsMapPtr *nsmap, int position, + xmlNsPtr oldNs, xmlNsPtr newNs, int depth) +{ + xmlNsMapItemPtr ret; + xmlNsMapPtr map; + + if (nsmap == NULL) + return(NULL); + if ((position != -1) && (position != 0)) + return(NULL); + map = *nsmap; + + if (map == NULL) { + /* + * Create the ns-map. + */ + map = (xmlNsMapPtr) xmlMalloc(sizeof(struct xmlNsMap)); + if (map == NULL) { + xmlTreeErrMemory("allocating namespace map"); + return (NULL); + } + memset(map, 0, sizeof(struct xmlNsMap)); + *nsmap = map; + } + + if (map->pool != NULL) { + /* + * Reuse an item from the pool. + */ + ret = map->pool; + map->pool = ret->next; + memset(ret, 0, sizeof(struct xmlNsMapItem)); + } else { + /* + * Create a new item. + */ + ret = (xmlNsMapItemPtr) xmlMalloc(sizeof(struct xmlNsMapItem)); + if (ret == NULL) { + xmlTreeErrMemory("allocating namespace map item"); + return (NULL); + } + memset(ret, 0, sizeof(struct xmlNsMapItem)); + } + + if (map->first == NULL) { + /* + * First ever. + */ + map->first = ret; + map->last = ret; + } else if (position == -1) { + /* + * Append. + */ + ret->prev = map->last; + map->last->next = ret; + map->last = ret; + } else if (position == 0) { + /* + * Set on first position. + */ + map->first->prev = ret; + ret->next = map->first; + map->first = ret; + } else + return(NULL); + + ret->oldNs = oldNs; + ret->newNs = newNs; + ret->shadowDepth = -1; + ret->depth = depth; + return (ret); +} + +/* +* xmlDOMWrapStoreNs: +* @doc: the doc +* @nsName: the namespace name +* @prefix: the prefix +* +* Creates or reuses an xmlNs struct on doc->oldNs with +* the given prefix and namespace name. +* +* Returns the aquired ns struct or NULL in case of an API +* or internal error. +*/ +static xmlNsPtr +xmlDOMWrapStoreNs(xmlDocPtr doc, + const xmlChar *nsName, + const xmlChar *prefix) +{ + xmlNsPtr ns; + + if (doc == NULL) + return (NULL); + ns = xmlTreeEnsureXMLDecl(doc); + if (ns == NULL) + return (NULL); + if (ns->next != NULL) { + /* Reuse. */ + ns = ns->next; + while (ns != NULL) { + if (((ns->prefix == prefix) || + xmlStrEqual(ns->prefix, prefix)) && + xmlStrEqual(ns->href, nsName)) { + return (ns); + } + if (ns->next == NULL) + break; + ns = ns->next; + } + } + /* Create. */ + if (ns != NULL) { + ns->next = xmlNewNs(NULL, nsName, prefix); + return (ns->next); + } + return(NULL); +} + +/* +* xmlDOMWrapNewCtxt: +* +* Allocates and initializes a new DOM-wrapper context. +* +* Returns the xmlDOMWrapCtxtPtr or NULL in case of an internal errror. +*/ +xmlDOMWrapCtxtPtr +xmlDOMWrapNewCtxt(void) +{ + xmlDOMWrapCtxtPtr ret; + + ret = xmlMalloc(sizeof(xmlDOMWrapCtxt)); + if (ret == NULL) { + xmlTreeErrMemory("allocating DOM-wrapper context"); + return (NULL); + } + memset(ret, 0, sizeof(xmlDOMWrapCtxt)); + return (ret); +} + +/* +* xmlDOMWrapFreeCtxt: +* @ctxt: the DOM-wrapper context +* +* Frees the DOM-wrapper context. +*/ +void +xmlDOMWrapFreeCtxt(xmlDOMWrapCtxtPtr ctxt) +{ + if (ctxt == NULL) + return; + if (ctxt->namespaceMap != NULL) + xmlDOMWrapNsMapFree((xmlNsMapPtr) ctxt->namespaceMap); + /* + * TODO: Store the namespace map in the context. + */ + xmlFree(ctxt); +} + +/* +* xmlTreeLookupNsListByPrefix: +* @nsList: a list of ns-structs +* @prefix: the searched prefix +* +* Searches for a ns-decl with the given prefix in @nsList. +* +* Returns the ns-decl if found, NULL if not found and on +* API errors. +*/ +static xmlNsPtr +xmlTreeNSListLookupByPrefix(xmlNsPtr nsList, const xmlChar *prefix) +{ + if (nsList == NULL) + return (NULL); + { + xmlNsPtr ns; + ns = nsList; + do { + if ((prefix == ns->prefix) || + xmlStrEqual(prefix, ns->prefix)) { + return (ns); + } + ns = ns->next; + } while (ns != NULL); + } + return (NULL); +} + +/* +* +* xmlDOMWrapNSNormGatherInScopeNs: +* @map: the namespace map +* @node: the node to start with +* +* Puts in-scope namespaces into the ns-map. +* +* Returns 0 on success, -1 on API or internal errors. +*/ +static int +xmlDOMWrapNSNormGatherInScopeNs(xmlNsMapPtr *map, + xmlNodePtr node) +{ + xmlNodePtr cur; + xmlNsPtr ns; + xmlNsMapItemPtr mi; + int shadowed; + + if ((map == NULL) || (*map != NULL)) + return (-1); + /* + * Get in-scope ns-decls of @parent. + */ + cur = node; + while ((cur != NULL) && (cur != (xmlNodePtr) cur->doc)) { + if (cur->type == XML_ELEMENT_NODE) { + if (cur->nsDef != NULL) { + ns = cur->nsDef; + do { + shadowed = 0; + if (XML_NSMAP_NOTEMPTY(*map)) { + /* + * Skip shadowed prefixes. + */ + XML_NSMAP_FOREACH(*map, mi) { + if ((ns->prefix == mi->newNs->prefix) || + xmlStrEqual(ns->prefix, mi->newNs->prefix)) { + shadowed = 1; + break; + } + } + } + /* + * Insert mapping. + */ + mi = xmlDOMWrapNsMapAddItem(map, 0, NULL, + ns, XML_TREE_NSMAP_PARENT); + if (mi == NULL) + return (-1); + if (shadowed) + mi->shadowDepth = 0; + ns = ns->next; + } while (ns != NULL); + } + } + cur = cur->parent; + } + 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: +* +* For internal use. Adds a ns-decl mapping. +* +* Returns 0 on success, -1 on internal errors. +*/ +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); + } + } + (*list)[2 * (*number)] = oldNs; + (*list)[2 * (*number) +1] = newNs; + (*number)++; + return (0); +} + +/* +* xmlDOMWrapRemoveNode: +* @ctxt: a DOM wrapper context +* @doc: the doc +* @node: the node to be removed. +* @options: set of options, unused at the moment +* +* Unlinks the given node from its owner. +* This will substitute ns-references to node->nsDef for +* ns-references to doc->oldNs, thus ensuring the removed +* branch to be autark wrt ns-references. +* +* NOTE: This function was not intensively tested. +* +* Returns 0 on success, 1 if the node is not supported, +* -1 on API and internal errors. +*/ +int +xmlDOMWrapRemoveNode(xmlDOMWrapCtxtPtr ctxt, xmlDocPtr doc, + xmlNodePtr node, int options ATTRIBUTE_UNUSED) +{ + xmlNsPtr *list = NULL; + int sizeList, nbList, i, j; + xmlNsPtr ns; + + if ((node == NULL) || (doc == NULL) || (node->doc != doc)) + return (-1); + + /* TODO: 0 or -1 ? */ + if (node->parent == NULL) + return (0); + + switch (node->type) { + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: + case XML_ENTITY_REF_NODE: + case XML_PI_NODE: + case XML_COMMENT_NODE: + xmlUnlinkNode(node); + return (0); + case XML_ELEMENT_NODE: + case XML_ATTRIBUTE_NODE: + break; + default: + return (1); + } + xmlUnlinkNode(node); + /* + * Save out-of-scope ns-references in doc->oldNs. + */ + do { + switch (node->type) { + case XML_ELEMENT_NODE: + if ((ctxt == NULL) && (node->nsDef != NULL)) { + ns = node->nsDef; + do { + if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList, + &nbList, ns, ns) == -1) + goto internal_error; + ns = ns->next; + } while (ns != NULL); + } + /* No break on purpose. */ + case XML_ATTRIBUTE_NODE: + if (node->ns != NULL) { + /* + * Find a mapping. + */ + if (list != NULL) { + for (i = 0, j = 0; i < nbList; i++, j += 2) { + if (node->ns == list[j]) { + node->ns = list[++j]; + goto next_node; + } + } + } + ns = NULL; + if (ctxt != NULL) { + /* + * User defined. + */ + } else { + /* + * Add to doc's oldNs. + */ + ns = xmlDOMWrapStoreNs(doc, node->ns->href, + node->ns->prefix); + if (ns == NULL) + goto internal_error; + } + if (ns != NULL) { + /* + * Add mapping. + */ + if (xmlDOMWrapNSNormAddNsMapItem2(&list, &sizeList, + &nbList, node->ns, ns) == -1) + goto internal_error; + } + node->ns = ns; + } + if ((node->type == XML_ELEMENT_NODE) && + (node->properties != NULL)) { + node = (xmlNodePtr) node->properties; + continue; + } + break; + default: + goto next_sibling; + } +next_node: + if ((node->type == XML_ELEMENT_NODE) && + (node->children != NULL)) { + node = node->children; + continue; + } +next_sibling: + if (node == NULL) + break; + if (node->next != NULL) + node = node->next; + else { + node = node->parent; + goto next_sibling; + } + } while (node != NULL); + + if (list != NULL) + xmlFree(list); + return (0); + +internal_error: + if (list != NULL) + xmlFree(list); + return (-1); +} + +/* +* xmlSearchNsByNamespaceStrict: +* @doc: the document +* @node: the start node +* @nsName: the searched namespace name +* @retNs: the resulting ns-decl +* @prefixed: if the found ns-decl must have a prefix (for attributes) +* +* Dynamically searches for a ns-declaration which matches +* the given @nsName in the ancestor-or-self axis of @node. +* +* Returns 1 if a ns-decl was found, 0 if not and -1 on API +* and internal errors. +*/ +static int +xmlSearchNsByNamespaceStrict(xmlDocPtr doc, xmlNodePtr node, + const xmlChar* nsName, + xmlNsPtr *retNs, int prefixed) +{ + xmlNodePtr cur, prev = NULL, out = NULL; + xmlNsPtr ns, prevns; + + if ((doc == NULL) || (nsName == NULL) || (retNs == NULL)) + return (-1); + + *retNs = NULL; + if (xmlStrEqual(nsName, XML_XML_NAMESPACE)) { + *retNs = xmlTreeEnsureXMLDecl(doc); + if (*retNs == NULL) + return (-1); + return (1); + } + cur = node; + do { + if (cur->type == XML_ELEMENT_NODE) { + if (cur->nsDef != NULL) { + for (ns = cur->nsDef; ns != NULL; ns = ns->next) { + if (prefixed && (ns->prefix == NULL)) + continue; + if (prev != NULL) { + /* + * Check the last level of ns-decls for a + * shadowing prefix. + */ + prevns = prev->nsDef; + do { + if ((prevns->prefix == ns->prefix) || + ((prevns->prefix != NULL) && + (ns->prefix != NULL) && + xmlStrEqual(prevns->prefix, ns->prefix))) { + /* + * Shadowed. + */ + break; + } + prevns = prevns->next; + } while (prevns != NULL); + if (prevns != NULL) + continue; + } + /* + * Ns-name comparison. + */ + if ((nsName == ns->href) || + xmlStrEqual(nsName, ns->href)) { + /* + * At this point the prefix can only be shadowed, + * if we are the the (at least) 3rd level of + * ns-decls. + */ + if (out) { + int ret; + + ret = xmlNsInScope(doc, node, prev, ns->prefix); + if (ret < 0) + return (-1); + /* + * TODO: Should we try to find a matching ns-name + * only once? This here keeps on searching. + * I think we should try further since, there might + * be an other matching ns-decl with an unshadowed + * prefix. + */ + if (! ret) + continue; + } + *retNs = ns; + return (1); + } + } + out = prev; + prev = cur; + } + } else if ((cur->type == XML_ENTITY_NODE) || + (cur->type == XML_ENTITY_DECL)) + return (0); + cur = cur->parent; + } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur)); + return (0); +} + +/* +* xmlSearchNsByPrefixStrict: +* @doc: the document +* @node: the start node +* @prefix: the searched namespace prefix +* @retNs: the resulting ns-decl +* +* Dynamically searches for a ns-declaration which matches +* the given @nsName in the ancestor-or-self axis of @node. +* +* Returns 1 if a ns-decl was found, 0 if not and -1 on API +* and internal errors. +*/ +static int +xmlSearchNsByPrefixStrict(xmlDocPtr doc, xmlNodePtr node, + const xmlChar* prefix, + xmlNsPtr *retNs) +{ + xmlNodePtr cur; + xmlNsPtr ns; + + if ((doc == NULL) || (node == NULL)) + return (-1); + + if (retNs) + *retNs = NULL; + if (IS_STR_XML(prefix)) { + if (retNs) { + *retNs = xmlTreeEnsureXMLDecl(doc); + if (*retNs == NULL) + return (-1); + } + return (1); + } + cur = node; + do { + if (cur->type == XML_ELEMENT_NODE) { + if (cur->nsDef != NULL) { + ns = cur->nsDef; + do { + if ((prefix == ns->prefix) || + xmlStrEqual(prefix, ns->prefix)) + { + /* + * Disabled namespaces, e.g. xmlns:abc="". + */ + if (ns->href == NULL) + return(0); + if (retNs) + *retNs = ns; + return (1); + } + ns = ns->next; + } while (ns != NULL); + } + } else if ((cur->type == XML_ENTITY_NODE) || + (cur->type == XML_ENTITY_DECL)) + return (0); + cur = cur->parent; + } while ((cur != NULL) && (cur->doc != (xmlDocPtr) cur)); + return (0); +} + +/* +* xmlDOMWrapNSNormDeclareNsForced: +* @doc: the doc +* @elem: the element-node to declare on +* @nsName: the namespace-name of the ns-decl +* @prefix: the preferred prefix of the ns-decl +* @checkShadow: ensure that the new ns-decl doesn't shadow ancestor ns-decls +* +* Declares a new namespace on @elem. It tries to use the +* given @prefix; if a ns-decl with the given prefix is already existent +* on @elem, it will generate an other prefix. +* +* Returns 1 if a ns-decl was found, 0 if not and -1 on API +* and internal errors. +*/ +static xmlNsPtr +xmlDOMWrapNSNormDeclareNsForced(xmlDocPtr doc, + xmlNodePtr elem, + const xmlChar *nsName, + const xmlChar *prefix, + int checkShadow) +{ + + xmlNsPtr ret; + char buf[50]; + const xmlChar *pref; + int counter = 0; + /* + * Create a ns-decl on @anchor. + */ + pref = prefix; + while (1) { + /* + * Lookup whether the prefix is unused in elem's ns-decls. + */ + if ((elem->nsDef != NULL) && + (xmlTreeNSListLookupByPrefix(elem->nsDef, pref) != NULL)) + goto ns_next_prefix; + if (checkShadow && elem->parent && + ((xmlNodePtr) elem->parent->doc != elem->parent)) { + /* + * Does it shadow ancestor ns-decls? + */ + if (xmlSearchNsByPrefixStrict(doc, elem->parent, pref, NULL) == 1) + goto ns_next_prefix; + } + ret = xmlNewNs(NULL, nsName, pref); + if (ret == NULL) + return (NULL); + if (elem->nsDef == NULL) + elem->nsDef = ret; + else { + xmlNsPtr ns2 = elem->nsDef; + while (ns2->next != NULL) + ns2 = ns2->next; + ns2->next = ret; + } + return (ret); +ns_next_prefix: + counter++; + if (counter > 1000) + return (NULL); + if (prefix == NULL) { + snprintf((char *) buf, sizeof(buf), + "ns_%d", counter); + } else + snprintf((char *) buf, sizeof(buf), + "%.30s_%d", (char *)prefix, counter); + pref = BAD_CAST buf; + } +} + +/* +* xmlDOMWrapNSNormAquireNormalizedNs: +* @doc: the doc +* @elem: the element-node to declare namespaces on +* @ns: the ns-struct to use for the search +* @retNs: the found/created ns-struct +* @nsMap: the ns-map +* @depth: the current tree depth +* @ancestorsOnly: search in ancestor ns-decls only +* @prefixed: if the searched ns-decl must have a prefix (for attributes) +* +* Searches for a matching ns-name in the ns-decls of @nsMap, if not +* found it will either declare it on @elem, or store it in doc->oldNs. +* If a new ns-decl needs to be declared on @elem, it tries to use the +* @ns->prefix for it, if this prefix is already in use on @elem, it will +* change the prefix or the new ns-decl. +* +* Returns 0 if succeeded, -1 otherwise and on API/internal errors. +*/ +static int +xmlDOMWrapNSNormAquireNormalizedNs(xmlDocPtr doc, + xmlNodePtr elem, + xmlNsPtr ns, + xmlNsPtr *retNs, + xmlNsMapPtr *nsMap, + + int depth, + int ancestorsOnly, + int prefixed) +{ + xmlNsMapItemPtr mi; + + if ((doc == NULL) || (ns == NULL) || (retNs == NULL) || + (nsMap == NULL)) + return (-1); + + *retNs = NULL; + /* + * Handle XML namespace. + */ + if (IS_STR_XML(ns->prefix)) { + /* + * Insert XML namespace mapping. + */ + *retNs = xmlTreeEnsureXMLDecl(doc); + if (*retNs == NULL) + return (-1); + return (0); + } + /* + * If the search should be done in ancestors only and no + * @elem (the first ancestor) was specified, then skip the search. + */ + if ((XML_NSMAP_NOTEMPTY(*nsMap)) && + (! (ancestorsOnly && (elem == NULL)))) + { + /* + * Try to find an equal ns-name in in-scope ns-decls. + */ + XML_NSMAP_FOREACH(*nsMap, mi) { + if ((mi->depth >= XML_TREE_NSMAP_PARENT) && + /* + * ancestorsOnly: This should be turned on to gain speed, + * if one knows that the branch itself was already + * ns-wellformed and no stale references existed. + * I.e. it searches in the ancestor axis only. + */ + ((! ancestorsOnly) || (mi->depth == XML_TREE_NSMAP_PARENT)) && + /* Skip shadowed prefixes. */ + (mi->shadowDepth == -1) && + /* Skip xmlns="" or xmlns:foo="". */ + ((mi->newNs->href != NULL) && + (mi->newNs->href[0] != 0)) && + /* Ensure a prefix if wanted. */ + ((! prefixed) || (mi->newNs->prefix != NULL)) && + /* Equal ns name */ + ((mi->newNs->href == ns->href) || + xmlStrEqual(mi->newNs->href, ns->href))) { + /* Set the mapping. */ + mi->oldNs = ns; + *retNs = mi->newNs; + return (0); + } + } + } + /* + * No luck, the namespace is out of scope or shadowed. + */ + if (elem == NULL) { + xmlNsPtr tmpns; + + /* + * Store ns-decls in "oldNs" of the document-node. + */ + tmpns = xmlDOMWrapStoreNs(doc, ns->href, ns->prefix); + if (tmpns == NULL) + return (-1); + /* + * Insert mapping. + */ + if (xmlDOMWrapNsMapAddItem(nsMap, -1, ns, + tmpns, XML_TREE_NSMAP_DOC) == NULL) { + xmlFreeNs(tmpns); + return (-1); + } + *retNs = tmpns; + } else { + xmlNsPtr tmpns; + + tmpns = xmlDOMWrapNSNormDeclareNsForced(doc, elem, ns->href, + ns->prefix, 0); + if (tmpns == NULL) + return (-1); + + if (*nsMap != NULL) { + /* + * Does it shadow ancestor ns-decls? + */ + XML_NSMAP_FOREACH(*nsMap, mi) { + if ((mi->depth < depth) && + (mi->shadowDepth == -1) && + ((ns->prefix == mi->newNs->prefix) || + xmlStrEqual(ns->prefix, mi->newNs->prefix))) { + /* + * Shadows. + */ + mi->shadowDepth = depth; + break; + } + } + } + if (xmlDOMWrapNsMapAddItem(nsMap, -1, ns, tmpns, depth) == NULL) { + xmlFreeNs(tmpns); + return (-1); + } + *retNs = tmpns; + } + return (0); +} + +typedef enum { + XML_DOM_RECONNS_REMOVEREDUND = 1<<0 +} xmlDOMReconcileNSOptions; + +/* +* xmlDOMWrapReconcileNamespaces: +* @ctxt: DOM wrapper context, unused at the moment +* @elem: the element-node +* @options: option flags +* +* Ensures that ns-references point to ns-decls hold on element-nodes. +* Ensures that the tree is namespace wellformed by creating additional +* ns-decls where needed. Note that, since prefixes of already existent +* ns-decls can be shadowed by this process, it could break QNames in +* attribute values or element content. +* +* NOTE: This function was not intensively tested. +* +* Returns 0 if succeeded, -1 otherwise and on API/internal errors. +*/ + +int +xmlDOMWrapReconcileNamespaces(xmlDOMWrapCtxtPtr ctxt ATTRIBUTE_UNUSED, + xmlNodePtr elem, + int options) +{ + int depth = -1, adoptns = 0, parnsdone = 0; + xmlNsPtr ns, prevns; + xmlDocPtr doc; + xmlNodePtr cur, curElem = NULL; + xmlNsMapPtr nsMap = NULL; + xmlNsMapItemPtr /* topmi = NULL, */ mi; + /* @ancestorsOnly should be set by an option flag. */ + int ancestorsOnly = 0; + int optRemoveRedundantNS = + ((xmlDOMReconcileNSOptions) options & XML_DOM_RECONNS_REMOVEREDUND) ? 1 : 0; + xmlNsPtr *listRedund = NULL; + int sizeRedund = 0, nbRedund = 0, ret, i, j; + + if ((elem == NULL) || (elem->doc == NULL) || + (elem->type != XML_ELEMENT_NODE)) + return (-1); + + doc = elem->doc; + cur = elem; + do { + switch (cur->type) { + case XML_ELEMENT_NODE: + adoptns = 1; + curElem = cur; + depth++; + /* + * Namespace declarations. + */ + if (cur->nsDef != NULL) { + prevns = NULL; + ns = cur->nsDef; + while (ns != NULL) { + if (! parnsdone) { + if ((elem->parent) && + ((xmlNodePtr) elem->parent->doc != elem->parent)) { + /* + * Gather ancestor in-scope ns-decls. + */ + if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, + elem->parent) == -1) + goto internal_error; + } + parnsdone = 1; + } + + /* + * Lookup the ns ancestor-axis for equal ns-decls in scope. + */ + if (optRemoveRedundantNS && XML_NSMAP_NOTEMPTY(nsMap)) { + XML_NSMAP_FOREACH(nsMap, mi) { + if ((mi->depth >= XML_TREE_NSMAP_PARENT) && + (mi->shadowDepth == -1) && + ((ns->prefix == mi->newNs->prefix) || + xmlStrEqual(ns->prefix, mi->newNs->prefix)) && + ((ns->href == mi->newNs->href) || + xmlStrEqual(ns->href, mi->newNs->href))) + { + /* + * A redundant ns-decl was found. + * 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; + } + } + } + + /* + * Skip ns-references handling if the referenced + * ns-decl is declared on the same element. + */ + if ((cur->ns != NULL) && adoptns && (cur->ns == ns)) + adoptns = 0; + /* + * Does it shadow any ns-decl? + */ + if (XML_NSMAP_NOTEMPTY(nsMap)) { + XML_NSMAP_FOREACH(nsMap, mi) { + if ((mi->depth >= XML_TREE_NSMAP_PARENT) && + (mi->shadowDepth == -1) && + ((ns->prefix == mi->newNs->prefix) || + xmlStrEqual(ns->prefix, mi->newNs->prefix))) { + + mi->shadowDepth = depth; + } + } + } + /* + * Push mapping. + */ + if (xmlDOMWrapNsMapAddItem(&nsMap, -1, ns, ns, + depth) == NULL) + goto internal_error; + + prevns = ns; +next_ns_decl: + ns = ns->next; + } + } + if (! adoptns) + goto ns_end; + /* No break on purpose. */ + case XML_ATTRIBUTE_NODE: + /* No ns, no fun. */ + if (cur->ns == NULL) + goto ns_end; + + if (! parnsdone) { + if ((elem->parent) && + ((xmlNodePtr) elem->parent->doc != elem->parent)) { + if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, + elem->parent) == -1) + goto internal_error; + } + parnsdone = 1; + } + /* + * Adjust the reference if this was a redundant ns-decl. + */ + if (listRedund) { + for (i = 0, j = 0; i < nbRedund; i++, j += 2) { + if (cur->ns == listRedund[j]) { + cur->ns = listRedund[++j]; + break; + } + } + } + /* + * Adopt ns-references. + */ + if (XML_NSMAP_NOTEMPTY(nsMap)) { + /* + * Search for a mapping. + */ + XML_NSMAP_FOREACH(nsMap, mi) { + if ((mi->shadowDepth == -1) && + (cur->ns == mi->oldNs)) { + + cur->ns = mi->newNs; + goto ns_end; + } + } + } + /* + * Aquire a normalized ns-decl and add it to the map. + */ + if (xmlDOMWrapNSNormAquireNormalizedNs(doc, curElem, + cur->ns, &ns, + &nsMap, depth, + ancestorsOnly, + (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1) + goto internal_error; + cur->ns = ns; + +ns_end: + if ((cur->type == XML_ELEMENT_NODE) && + (cur->properties != NULL)) { + /* + * Process attributes. + */ + cur = (xmlNodePtr) cur->properties; + continue; + } + break; + default: + goto next_sibling; + } +into_content: + if ((cur->type == XML_ELEMENT_NODE) && + (cur->children != NULL)) { + /* + * Process content of element-nodes only. + */ + cur = cur->children; + continue; + } +next_sibling: + if (cur == elem) + break; + if (cur->type == XML_ELEMENT_NODE) { + if (XML_NSMAP_NOTEMPTY(nsMap)) { + /* + * Pop mappings. + */ + while ((nsMap->last != NULL) && + (nsMap->last->depth >= depth)) + { + XML_NSMAP_POP(nsMap, mi) + } + /* + * Unshadow. + */ + XML_NSMAP_FOREACH(nsMap, mi) { + if (mi->shadowDepth >= depth) + mi->shadowDepth = -1; + } + } + depth--; + } + if (cur->next != NULL) + cur = cur->next; + else { + if (cur->type == XML_ATTRIBUTE_NODE) { + cur = cur->parent; + goto into_content; + } + cur = cur->parent; + goto 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]); + } + xmlFree(listRedund); + } + if (nsMap != NULL) + xmlDOMWrapNsMapFree(nsMap); + return (ret); +} + +/* +* xmlDOMWrapAdoptBranch: +* @ctxt: the optional context for custom processing +* @sourceDoc: the optional sourceDoc +* @node: the element-node to start with +* @destDoc: the destination doc for adoption +* @destParent: the optional new parent of @node in @destDoc +* @options: option flags +* +* Ensures that ns-references point to @destDoc: either to +* elements->nsDef entries if @destParent is given, or to +* @destDoc->oldNs otherwise. +* If @destParent is given, it ensures that the tree is namespace +* wellformed by creating additional ns-decls where needed. +* Note that, since prefixes of already existent ns-decls can be +* shadowed by this process, it could break QNames in attribute +* values or element content. +* +* NOTE: This function was not intensively tested. +* +* Returns 0 if succeeded, -1 otherwise and on API/internal errors. +*/ +static int +xmlDOMWrapAdoptBranch(xmlDOMWrapCtxtPtr ctxt, + xmlDocPtr sourceDoc, + xmlNodePtr node, + xmlDocPtr destDoc, + xmlNodePtr destParent, + int options ATTRIBUTE_UNUSED) +{ + int ret = 0; + xmlNodePtr cur, curElem = NULL; + xmlNsMapPtr nsMap = NULL; + xmlNsMapItemPtr mi; + xmlNsPtr ns = NULL; + int depth = -1, adoptStr = 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. + */ + if (ctxt) + nsMap = (xmlNsMapPtr) ctxt->namespaceMap; + /* + * Disable search for ns-decls in the parent-axis of the + * desination element, if: + * 1) there's no destination parent + * 2) custom ns-reference handling is used + */ + if ((destParent == NULL) || + (ctxt && ctxt->getNsForNodeFunc)) + { + parnsdone = 1; + } else + parnsdone = 0; + + cur = node; + 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 != node->doc) + goto leave_node; + } + cur->doc = destDoc; + switch (cur->type) { + case XML_XINCLUDE_START: + case XML_XINCLUDE_END: + /* + * TODO + */ + return (-1); + case XML_ELEMENT_NODE: + curElem = cur; + depth++; + /* + * Namespace declarations. + * - ns->href and ns->prefix are never in the dict, so + * we need not move the values over to the destination dict. + * - Note that for custom handling of ns-references, + * the ns-decls need not be stored in the ns-map, + * since they won't be referenced by node->ns. + */ + if ((cur->nsDef) && + ((ctxt == NULL) || (ctxt->getNsForNodeFunc == NULL))) + { + if (! parnsdone) { + /* + * Gather @parent's in-scope ns-decls. + */ + if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, + destParent) == -1) + goto internal_error; + 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? + */ + if (XML_NSMAP_NOTEMPTY(nsMap)) { + XML_NSMAP_FOREACH(nsMap, mi) { + if ((mi->depth >= XML_TREE_NSMAP_PARENT) && + (mi->shadowDepth == -1) && + ((ns->prefix == mi->newNs->prefix) || + xmlStrEqual(ns->prefix, + mi->newNs->prefix))) { + + mi->shadowDepth = depth; + } + } + } + /* + * Push mapping. + */ + if (xmlDOMWrapNsMapAddItem(&nsMap, -1, + ns, ns, depth) == NULL) + goto internal_error; + } + } + /* No break on purpose. */ + case XML_ATTRIBUTE_NODE: + /* No namespace, no fun. */ + if (cur->ns == NULL) + goto ns_end; + + if (! parnsdone) { + if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, + destParent) == -1) + goto internal_error; + parnsdone = 1; + } + /* + * Adopt ns-references. + */ + if (XML_NSMAP_NOTEMPTY(nsMap)) { + /* + * Search for a mapping. + */ + XML_NSMAP_FOREACH(nsMap, mi) { + if ((mi->shadowDepth == -1) && + (cur->ns == mi->oldNs)) { + + cur->ns = mi->newNs; + goto ns_end; + } + } + } + /* + * No matching namespace in scope. We need a new one. + */ + if ((ctxt) && (ctxt->getNsForNodeFunc)) { + /* + * User-defined behaviour. + */ + ns = ctxt->getNsForNodeFunc(ctxt, cur, + cur->ns->href, cur->ns->prefix); + /* + * Insert mapping if ns is available; it's the users fault + * if not. + */ + if (xmlDOMWrapNsMapAddItem(&nsMap, -1, + cur->ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL) + goto internal_error; + cur->ns = ns; + } else { + /* + * Aquire a normalized ns-decl and add it to the map. + */ + if (xmlDOMWrapNSNormAquireNormalizedNs(destDoc, + /* ns-decls on curElem or on destDoc->oldNs */ + destParent ? curElem : NULL, + cur->ns, &ns, + &nsMap, depth, + ancestorsOnly, + /* ns-decls must be prefixed for attributes. */ + (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1) + goto internal_error; + 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; + cur->extra = 0; + /* + * Walk attributes. + */ + if (cur->properties != NULL) { + /* + * Process first attribute node. + */ + 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 entitity-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; + default: + goto internal_error; + } + /* + * Walk the tree. + */ + if (cur->children != NULL) { + cur = cur->children; + continue; + } + +leave_node: + if (cur == node) + break; + if ((cur->type == XML_ELEMENT_NODE) || + (cur->type == XML_XINCLUDE_START) || + (cur->type == XML_XINCLUDE_END)) + { + /* + * TODO: Do we expect nsDefs on XML_XINCLUDE_START? + */ + if (XML_NSMAP_NOTEMPTY(nsMap)) { + /* + * Pop mappings. + */ + while ((nsMap->last != NULL) && + (nsMap->last->depth >= depth)) + { + XML_NSMAP_POP(nsMap, mi) + } + /* + * Unshadow. + */ + XML_NSMAP_FOREACH(nsMap, mi) { + if (mi->shadowDepth >= depth) + mi->shadowDepth = -1; + } + } + depth--; + } + if (cur->next != NULL) + cur = cur->next; + else if ((cur->type == XML_ATTRIBUTE_NODE) && + (cur->parent->children != NULL)) + { + cur = cur->parent->children; + } else { + cur = cur->parent; + goto leave_node; + } + } + + goto exit; + +internal_error: + ret = -1; + +exit: + /* + * Cleanup. + */ + if (nsMap != NULL) { + if ((ctxt) && (ctxt->namespaceMap == nsMap)) { + /* + * Just cleanup the map but don't free. + */ + if (nsMap->first) { + if (nsMap->pool) + nsMap->last->next = nsMap->pool; + nsMap->pool = nsMap->first; + nsMap->first = NULL; + } + } else + xmlDOMWrapNsMapFree(nsMap); + } + return(ret); +} + +/* +* xmlDOMWrapCloneNode: +* @ctxt: the optional context for custom processing +* @sourceDoc: the optional sourceDoc +* @node: the node to start with +* @resNode: the clone of the given @node +* @destDoc: the destination doc +* @destParent: the optional new parent of @node in @destDoc +* @deep: descend into child if set +* @options: option flags +* +* References of out-of scope ns-decls are remapped to point to @destDoc: +* 1) If @destParent is given, then nsDef entries on element-nodes are used +* 2) If *no* @destParent is given, then @destDoc->oldNs entries are used. +* This is the case when you don't know already where the cloned branch +* will be added to. +* +* If @destParent is given, it ensures that the tree is namespace +* wellformed by creating additional ns-decls where needed. +* Note that, since prefixes of already existent ns-decls can be +* shadowed by this process, it could break QNames in attribute +* values or element content. +* TODO: +* 1) What to do with XInclude? Currently this returns an error for XInclude. +* +* Returns 0 if the operation succeeded, +* 1 if a node of unsupported (or not yet supported) type was given, +* -1 on API/internal errors. +*/ + +int +xmlDOMWrapCloneNode(xmlDOMWrapCtxtPtr ctxt, + xmlDocPtr sourceDoc, + xmlNodePtr node, + xmlNodePtr *resNode, + xmlDocPtr destDoc, + xmlNodePtr destParent, + int deep, + int options ATTRIBUTE_UNUSED) +{ + int ret = 0; + xmlNodePtr cur, curElem = NULL; + xmlNsMapPtr nsMap = NULL; + xmlNsMapItemPtr mi; + xmlNsPtr ns; + int depth = -1; + /* int adoptStr = 1; */ + /* gather @parent's ns-decls. */ + int parnsdone = 0; + /* + * @ancestorsOnly: + * TODO: @ancestorsOnly should be set per option. + * + */ + int ancestorsOnly = 0; + xmlNodePtr resultClone = NULL, clone = NULL, parentClone = NULL, prevClone = NULL; + xmlNsPtr cloneNs = NULL, *cloneNsDefSlot = NULL; + xmlDictPtr dict; /* The destination dict */ + + if ((node == NULL) || (resNode == NULL) || (destDoc == NULL)) + return(-1); + /* + * TODO: Initially we support only element-nodes. + */ + if (node->type != XML_ELEMENT_NODE) + return(1); + /* + * Check node->doc sanity. + */ + if ((node->doc != NULL) && (sourceDoc != NULL) && + (node->doc != sourceDoc)) { + /* + * Might be an XIncluded node. + */ + return (-1); + } + if (sourceDoc == NULL) + sourceDoc = node->doc; + if (sourceDoc == NULL) + return (-1); + + dict = destDoc->dict; + /* + * Reuse the namespace map of the context. + */ + if (ctxt) + nsMap = (xmlNsMapPtr) ctxt->namespaceMap; + + *resNode = NULL; + + cur = node; + while (cur != NULL) { + if (cur->doc != sourceDoc) { + /* + * We'll assume XIncluded nodes if the doc differs. + * TODO: Do we need to reconciliate XIncluded nodes? + * TODO: This here returns -1 in this case. + */ + goto internal_error; + } + /* + * Create a new node. + */ + switch (cur->type) { + case XML_XINCLUDE_START: + case XML_XINCLUDE_END: + /* + * TODO: What to do with XInclude? + */ + goto internal_error; + break; + case XML_ELEMENT_NODE: + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: + case XML_COMMENT_NODE: + 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"); + goto internal_error; + } + memset(clone, 0, sizeof(xmlNode)); + /* + * Set hierachical links. + */ + if (resultClone != NULL) { + clone->parent = parentClone; + if (prevClone) { + prevClone->next = clone; + clone->prev = prevClone; + } else + parentClone->children = clone; + } else + resultClone = clone; + + break; + case XML_ATTRIBUTE_NODE: + /* + * Attributes (xmlAttr). + */ + clone = (xmlNodePtr) xmlMalloc(sizeof(xmlAttr)); + if (clone == NULL) { + xmlTreeErrMemory("xmlDOMWrapCloneNode(): allocating an attr-node"); + goto internal_error; + } + memset(clone, 0, sizeof(xmlAttr)); + /* + * Set hierachical links. + * TODO: Change this to add to the end of attributes. + */ + if (resultClone != NULL) { + clone->parent = parentClone; + if (prevClone) { + prevClone->next = clone; + clone->prev = prevClone; + } else + parentClone->properties = (xmlAttrPtr) clone; + } else + resultClone = clone; + break; + default: + /* + * TODO QUESTION: Any other nodes expected? + */ + goto internal_error; + } + + clone->type = cur->type; + clone->doc = destDoc; + + /* + * Clone the name of the node if any. + */ + if (cur->name == xmlStringText) + clone->name = xmlStringText; + else if (cur->name == xmlStringTextNoenc) + /* + * NOTE: Although xmlStringTextNoenc is never assigned to a node + * in tree.c, it might be set in Libxslt via + * "xsl:disable-output-escaping". + */ + clone->name = xmlStringTextNoenc; + else if (cur->name == xmlStringComment) + clone->name = xmlStringComment; + else if (cur->name != NULL) { + DICT_CONST_COPY(cur->name, clone->name); + } + + switch (cur->type) { + case XML_XINCLUDE_START: + case XML_XINCLUDE_END: + /* + * TODO + */ + return (-1); + case XML_ELEMENT_NODE: + curElem = cur; + depth++; + /* + * Namespace declarations. + */ + if (cur->nsDef != NULL) { + if (! parnsdone) { + if (destParent && (ctxt == NULL)) { + /* + * Gather @parent's in-scope ns-decls. + */ + if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, + destParent) == -1) + goto internal_error; + } + parnsdone = 1; + } + /* + * Clone namespace declarations. + */ + cloneNsDefSlot = &(clone->nsDef); + for (ns = cur->nsDef; ns != NULL; ns = ns->next) { + /* + * Create a new xmlNs. + */ + cloneNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); + if (cloneNs == NULL) { + xmlTreeErrMemory("xmlDOMWrapCloneNode(): " + "allocating namespace"); + return(-1); + } + memset(cloneNs, 0, sizeof(xmlNs)); + cloneNs->type = XML_LOCAL_NAMESPACE; + + if (ns->href != NULL) + cloneNs->href = xmlStrdup(ns->href); + if (ns->prefix != NULL) + cloneNs->prefix = xmlStrdup(ns->prefix); + + *cloneNsDefSlot = cloneNs; + cloneNsDefSlot = &(cloneNs->next); + + /* + * Note that for custom handling of ns-references, + * the ns-decls need not be stored in the ns-map, + * since they won't be referenced by node->ns. + */ + if ((ctxt == NULL) || + (ctxt->getNsForNodeFunc == NULL)) + { + /* + * Does it shadow any ns-decl? + */ + if (XML_NSMAP_NOTEMPTY(nsMap)) { + XML_NSMAP_FOREACH(nsMap, mi) { + if ((mi->depth >= XML_TREE_NSMAP_PARENT) && + (mi->shadowDepth == -1) && + ((ns->prefix == mi->newNs->prefix) || + xmlStrEqual(ns->prefix, + mi->newNs->prefix))) { + /* + * Mark as shadowed at the current + * depth. + */ + mi->shadowDepth = depth; + } + } + } + /* + * Push mapping. + */ + if (xmlDOMWrapNsMapAddItem(&nsMap, -1, + ns, cloneNs, depth) == NULL) + goto internal_error; + } + } + } + /* cur->ns will be processed further down. */ + break; + case XML_ATTRIBUTE_NODE: + /* IDs will be processed further down. */ + /* cur->ns will be processed further down. */ + break; + 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? */ + goto leave_node; + case XML_ENTITY_REF_NODE: + if (sourceDoc != destDoc) { + if ((destDoc->intSubset) || (destDoc->extSubset)) { + xmlEntityPtr ent; + /* + * Different doc: Assign new entity-node if available. + */ + ent = xmlGetDocEntity(destDoc, cur->name); + if (ent != NULL) { + clone->content = ent->content; + clone->children = (xmlNodePtr) ent; + clone->last = (xmlNodePtr) ent; + } + } + } else { + /* + * Same doc: Use the current node's entity declaration + * and value. + */ + clone->content = cur->content; + clone->children = cur->children; + 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; + } + + if (cur->ns == NULL) + goto end_ns_reference; + +/* handle_ns_reference: */ + /* + ** The following will take care of references to ns-decls ******** + ** and is intended only for element- and attribute-nodes. + ** + */ + if (! parnsdone) { + if (destParent && (ctxt == NULL)) { + if (xmlDOMWrapNSNormGatherInScopeNs(&nsMap, destParent) == -1) + goto internal_error; + } + parnsdone = 1; + } + /* + * Adopt ns-references. + */ + if (XML_NSMAP_NOTEMPTY(nsMap)) { + /* + * Search for a mapping. + */ + XML_NSMAP_FOREACH(nsMap, mi) { + if ((mi->shadowDepth == -1) && + (cur->ns == mi->oldNs)) { + /* + * This is the nice case: a mapping was found. + */ + clone->ns = mi->newNs; + goto end_ns_reference; + } + } + } + /* + * No matching namespace in scope. We need a new one. + */ + if ((ctxt != NULL) && (ctxt->getNsForNodeFunc != NULL)) { + /* + * User-defined behaviour. + */ + ns = ctxt->getNsForNodeFunc(ctxt, cur, + cur->ns->href, cur->ns->prefix); + /* + * Add user's mapping. + */ + if (xmlDOMWrapNsMapAddItem(&nsMap, -1, + cur->ns, ns, XML_TREE_NSMAP_CUSTOM) == NULL) + goto internal_error; + clone->ns = ns; + } else { + /* + * Aquire a normalized ns-decl and add it to the map. + */ + if (xmlDOMWrapNSNormAquireNormalizedNs(destDoc, + /* ns-decls on curElem or on destDoc->oldNs */ + destParent ? curElem : NULL, + cur->ns, &ns, + &nsMap, depth, + /* if we need to search only in the ancestor-axis */ + ancestorsOnly, + /* ns-decls must be prefixed for attributes. */ + (cur->type == XML_ATTRIBUTE_NODE) ? 1 : 0) == -1) + goto internal_error; + clone->ns = ns; + } + +end_ns_reference: + + /* + * Some post-processing. + * + * Handle ID attributes. + */ + if ((clone->type == XML_ATTRIBUTE_NODE) && + (clone->parent != NULL)) + { + if (xmlIsID(destDoc, clone->parent, (xmlAttrPtr) clone)) { + + 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); + } + } + } + /* + ** + ** The following will traverse the tree ************************** + ** + * + * Walk the element's attributes before descending into child-nodes. + */ + if ((cur->type == XML_ELEMENT_NODE) && (cur->properties != NULL)) { + prevClone = NULL; + parentClone = clone; + cur = (xmlNodePtr) cur->properties; + continue; + } +into_content: + /* + * Descend into child-nodes. + */ + if (cur->children != NULL) { + if (deep || (cur->type == XML_ATTRIBUTE_NODE)) { + prevClone = NULL; + parentClone = clone; + cur = cur->children; + continue; + } + } + +leave_node: + /* + * At this point we are done with the node, its content + * and an element-nodes's attribute-nodes. + */ + if (cur == node) + break; + if ((cur->type == XML_ELEMENT_NODE) || + (cur->type == XML_XINCLUDE_START) || + (cur->type == XML_XINCLUDE_END)) { + /* + * TODO: Do we expect nsDefs on XML_XINCLUDE_START? + */ + if (XML_NSMAP_NOTEMPTY(nsMap)) { + /* + * Pop mappings. + */ + while ((nsMap->last != NULL) && + (nsMap->last->depth >= depth)) + { + XML_NSMAP_POP(nsMap, mi) + } + /* + * Unshadow. + */ + XML_NSMAP_FOREACH(nsMap, mi) { + if (mi->shadowDepth >= depth) + mi->shadowDepth = -1; + } + } + depth--; + } + if (cur->next != NULL) { + 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; + parentClone = clone->parent; + /* + * Process parent --> next; + */ + cur = cur->parent; + goto leave_node; + } else { + /* This is for attributes only. */ + clone = clone->parent; + parentClone = clone->parent; + /* + * Process parent-element --> children. + */ + cur = cur->parent; + goto into_content; + } + } + goto exit; + +internal_error: + ret = -1; + +exit: + /* + * Cleanup. + */ + if (nsMap != NULL) { + if ((ctxt) && (ctxt->namespaceMap == nsMap)) { + /* + * Just cleanup the map but don't free. + */ + if (nsMap->first) { + if (nsMap->pool) + nsMap->last->next = nsMap->pool; + nsMap->pool = nsMap->first; + nsMap->first = NULL; + } + } else + xmlDOMWrapNsMapFree(nsMap); + } + /* + * TODO: Should we try a cleanup of the cloned node in case of a + * fatal error? + */ + *resNode = resultClone; + return (ret); +} + +/* +* xmlDOMWrapAdoptAttr: +* @ctxt: the optional context for custom processing +* @sourceDoc: the optional source document of attr +* @attr: the attribute-node to be adopted +* @destDoc: the destination doc for adoption +* @destParent: the optional new parent of @attr in @destDoc +* @options: option flags +* +* @attr is adopted by @destDoc. +* Ensures that ns-references point to @destDoc: either to +* elements->nsDef entries if @destParent is given, or to +* @destDoc->oldNs otherwise. +* +* Returns 0 if succeeded, -1 otherwise and on API/internal errors. +*/ +static int +xmlDOMWrapAdoptAttr(xmlDOMWrapCtxtPtr ctxt, + xmlDocPtr sourceDoc, + xmlAttrPtr attr, + xmlDocPtr destDoc, + xmlNodePtr destParent, + int options ATTRIBUTE_UNUSED) +{ + xmlNodePtr cur; + int adoptStr = 1; + + if ((attr == NULL) || (destDoc == NULL)) + return (-1); + + attr->doc = destDoc; + if (attr->ns != NULL) { + xmlNsPtr ns = NULL; + + if (ctxt != NULL) { + /* TODO: User defined. */ + } + /* XML Namespace. */ + if (IS_STR_XML(attr->ns->prefix)) { + ns = xmlTreeEnsureXMLDecl(destDoc); + } else if (destParent == NULL) { + /* + * Store in @destDoc->oldNs. + */ + ns = xmlDOMWrapStoreNs(destDoc, attr->ns->href, attr->ns->prefix); + } else { + /* + * Declare on @destParent. + */ + if (xmlSearchNsByNamespaceStrict(destDoc, destParent, attr->ns->href, + &ns, 1) == -1) + goto internal_error; + if (ns == NULL) { + ns = xmlDOMWrapNSNormDeclareNsForced(destDoc, destParent, + attr->ns->href, attr->ns->prefix, 1); + } + } + if (ns == NULL) + goto internal_error; + 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; + 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 entitity-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); +} + +/* +* xmlDOMWrapAdoptNode: +* @ctxt: the optional context for custom processing +* @sourceDoc: the optional sourceDoc +* @node: the node to start with +* @destDoc: the destination doc +* @destParent: the optional new parent of @node in @destDoc +* @options: option flags +* +* References of out-of scope ns-decls are remapped to point to @destDoc: +* 1) If @destParent is given, then nsDef entries on element-nodes are used +* 2) If *no* @destParent is given, then @destDoc->oldNs entries are used +* This is the case when you have an unliked node and just want to move it +* to the context of +* +* If @destParent is given, it ensures that the tree is namespace +* wellformed by creating additional ns-decls where needed. +* Note that, since prefixes of already existent ns-decls can be +* shadowed by this process, it could break QNames in attribute +* values or element content. +* NOTE: This function was not intensively tested. +* +* Returns 0 if the operation succeeded, +* 1 if a node of unsupported type was given, +* 2 if a node of not yet supported type was given and +* -1 on API/internal errors. +*/ +int +xmlDOMWrapAdoptNode(xmlDOMWrapCtxtPtr ctxt, + xmlDocPtr sourceDoc, + xmlNodePtr node, + xmlDocPtr destDoc, + xmlNodePtr destParent, + int options) +{ + if ((node == NULL) || (destDoc == NULL) || + ((destParent != NULL) && (destParent->doc != destDoc))) + return(-1); + /* + * Check node->doc sanity. + */ + if ((node->doc != NULL) && (sourceDoc != NULL) && + (node->doc != sourceDoc)) { + /* + * Might be an XIncluded node. + */ + return (-1); + } + if (sourceDoc == NULL) + sourceDoc = node->doc; + if (sourceDoc == destDoc) + return (-1); + switch (node->type) { + case XML_ELEMENT_NODE: + case XML_ATTRIBUTE_NODE: + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: + case XML_ENTITY_REF_NODE: + case XML_PI_NODE: + case XML_COMMENT_NODE: + break; + case XML_DOCUMENT_FRAG_NODE: + /* TODO: Support document-fragment-nodes. */ + return (2); + default: + return (1); + } + /* + * Unlink only if @node was not already added to @destParent. + */ + if ((node->parent != NULL) && (destParent != node->parent)) + xmlUnlinkNode(node); + + if (node->type == XML_ELEMENT_NODE) { + return (xmlDOMWrapAdoptBranch(ctxt, sourceDoc, node, + destDoc, destParent, options)); + } else if (node->type == XML_ATTRIBUTE_NODE) { + 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 entitity-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; + } + } + return (0); +} + +#define bottom_tree +#include "elfgcchack.h" diff --git a/android/native/libxml2/trio.c b/android/native/libxml2/trio.c new file mode 100644 index 0000000000..b116ccc363 --- /dev/null +++ b/android/native/libxml2/trio.c @@ -0,0 +1,6869 @@ +/************************************************************************* + * + * $Id$ + * + * Copyright (C) 1998 Bjorn Reese and Daniel Stenberg. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND + * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER. + * + ************************************************************************* + * + * A note to trio contributors: + * + * Avoid heap allocation at all costs to ensure that the trio functions + * are async-safe. The exceptions are the printf/fprintf functions, which + * uses fputc, and the asprintf functions and the modifier, which + * by design are required to allocate form the heap. + * + ************************************************************************/ + +/* + * TODO: + * - Scan is probably too permissive about its modifiers. + * - C escapes in %#[] ? + * - Multibyte characters (done for format parsing, except scan groups) + * - Complex numbers? (C99 _Complex) + * - Boolean values? (C99 _Bool) + * - C99 NaN(n-char-sequence) missing. The n-char-sequence can be used + * to print the mantissa, e.g. NaN(0xc000000000000000) + * - Should we support the GNU %a alloc modifier? GNU has an ugly hack + * for %a, because C99 used %a for other purposes. If specified as + * %as or %a[ it is interpreted as the alloc modifier, otherwise as + * the C99 hex-float. This means that you cannot scan %as as a hex-float + * immediately followed by an 's'. + * - Scanning of collating symbols. + */ + +/************************************************************************* + * Trio include files + */ +#include "triodef.h" +#include "trio.h" +#include "triop.h" +#include "trionan.h" +#if !defined(TRIO_MINIMAL) +# include "triostr.h" +#endif + +/************************************************************************** + * + * Definitions + * + *************************************************************************/ + +#include +#include +#include + +#if (defined(__STDC_ISO_10646__) || defined(MB_LEN_MAX) \ + || defined(USE_MULTIBYTE) || TRIO_WIDECHAR) \ + && !defined(_WIN32_WCE) +# define TRIO_COMPILER_SUPPORTS_MULTIBYTE +# if !defined(MB_LEN_MAX) +# define MB_LEN_MAX 6 +# endif +#endif + +#if (defined(TRIO_COMPILER_MSVC) && (_MSC_VER >= 1100)) || defined(TRIO_COMPILER_BCB) +# define TRIO_COMPILER_SUPPORTS_MSVC_INT +#endif + +#if defined(_WIN32_WCE) +#include +#endif + +/************************************************************************* + * Generic definitions + */ + +#if !(defined(DEBUG) || defined(NDEBUG)) +# define NDEBUG +#endif + +#include +#include +#if !defined(TRIO_COMPILER_SUPPORTS_C99) +# define isblank(x) (((x)==32) || ((x)==9)) +#endif +#if defined(TRIO_COMPILER_ANCIENT) +# include +#else +# include +#endif +#include + +#ifdef HAVE_ERRNO_H +#include +#endif + +#ifndef NULL +# define NULL 0 +#endif +#define NIL ((char)0) +#ifndef FALSE +# define FALSE (1 == 0) +# define TRUE (! FALSE) +#endif +#define BOOLEAN_T int + +/* mincore() can be used for debugging purposes */ +#define VALID(x) (NULL != (x)) + +#if TRIO_ERRORS + /* + * Encode the error code and the position. This is decoded + * with TRIO_ERROR_CODE and TRIO_ERROR_POSITION. + */ +# define TRIO_ERROR_RETURN(x,y) (- ((x) + ((y) << 8))) +#else +# define TRIO_ERROR_RETURN(x,y) (-1) +#endif + +typedef unsigned long trio_flags_t; + + +/************************************************************************* + * Platform specific definitions + */ +#if defined(TRIO_PLATFORM_UNIX) +# include +# include +# include +# define USE_LOCALE +#endif /* TRIO_PLATFORM_UNIX */ +#if defined(TRIO_PLATFORM_VMS) +# include +#endif +#if defined(TRIO_PLATFORM_WIN32) +# if defined(_WIN32_WCE) +# include +# else +# include +# define read _read +# define write _write +# endif +#endif /* TRIO_PLATFORM_WIN32 */ + +#if TRIO_WIDECHAR +# if defined(TRIO_COMPILER_SUPPORTS_ISO94) +# include +# include +typedef wchar_t trio_wchar_t; +typedef wint_t trio_wint_t; +# else +typedef char trio_wchar_t; +typedef int trio_wint_t; +# define WCONST(x) L ## x +# define WEOF EOF +# define iswalnum(x) isalnum(x) +# define iswalpha(x) isalpha(x) +# define iswblank(x) isblank(x) +# define iswcntrl(x) iscntrl(x) +# define iswdigit(x) isdigit(x) +# define iswgraph(x) isgraph(x) +# define iswlower(x) islower(x) +# define iswprint(x) isprint(x) +# define iswpunct(x) ispunct(x) +# define iswspace(x) isspace(x) +# define iswupper(x) isupper(x) +# define iswxdigit(x) isxdigit(x) +# endif +#endif + + +/************************************************************************* + * Compiler dependent definitions + */ + +/* Support for long long */ +#ifndef __cplusplus +# if !defined(USE_LONGLONG) +# if defined(TRIO_COMPILER_GCC) && !defined(__STRICT_ANSI__) +# define USE_LONGLONG +# elif defined(TRIO_COMPILER_SUNPRO) +# define USE_LONGLONG +# elif defined(_LONG_LONG) || defined(_LONGLONG) +# define USE_LONGLONG +# endif +# endif +#endif + +/* The extra long numbers */ +#if defined(USE_LONGLONG) +typedef signed long long int trio_longlong_t; +typedef unsigned long long int trio_ulonglong_t; +#elif defined(TRIO_COMPILER_SUPPORTS_MSVC_INT) +typedef signed __int64 trio_longlong_t; +typedef unsigned __int64 trio_ulonglong_t; +#else +typedef TRIO_SIGNED long int trio_longlong_t; +typedef unsigned long int trio_ulonglong_t; +#endif + +/* Maximal and fixed integer types */ +#if defined(TRIO_COMPILER_SUPPORTS_C99) +# include +typedef intmax_t trio_intmax_t; +typedef uintmax_t trio_uintmax_t; +typedef int8_t trio_int8_t; +typedef int16_t trio_int16_t; +typedef int32_t trio_int32_t; +typedef int64_t trio_int64_t; +#elif defined(TRIO_COMPILER_SUPPORTS_UNIX98) +# include +typedef intmax_t trio_intmax_t; +typedef uintmax_t trio_uintmax_t; +typedef int8_t trio_int8_t; +typedef int16_t trio_int16_t; +typedef int32_t trio_int32_t; +typedef int64_t trio_int64_t; +#elif defined(TRIO_COMPILER_SUPPORTS_MSVC_INT) +typedef trio_longlong_t trio_intmax_t; +typedef trio_ulonglong_t trio_uintmax_t; +typedef __int8 trio_int8_t; +typedef __int16 trio_int16_t; +typedef __int32 trio_int32_t; +typedef __int64 trio_int64_t; +#else +typedef trio_longlong_t trio_intmax_t; +typedef trio_ulonglong_t trio_uintmax_t; +# if defined(TRIO_INT8_T) +typedef TRIO_INT8_T trio_int8_t; +# else +typedef TRIO_SIGNED char trio_int8_t; +# endif +# if defined(TRIO_INT16_T) +typedef TRIO_INT16_T trio_int16_t; +# else +typedef TRIO_SIGNED short trio_int16_t; +# endif +# if defined(TRIO_INT32_T) +typedef TRIO_INT32_T trio_int32_t; +# else +typedef TRIO_SIGNED int trio_int32_t; +# endif +# if defined(TRIO_INT64_T) +typedef TRIO_INT64_T trio_int64_t; +# else +typedef trio_longlong_t trio_int64_t; +# endif +#endif + +#if (!(defined(TRIO_COMPILER_SUPPORTS_C99) \ + || defined(TRIO_COMPILER_SUPPORTS_UNIX01))) \ + && !defined(_WIN32_WCE) +# define floorl(x) floor((double)(x)) +# define fmodl(x,y) fmod((double)(x),(double)(y)) +# define powl(x,y) pow((double)(x),(double)(y)) +#endif + +#define TRIO_FABS(x) (((x) < 0.0) ? -(x) : (x)) + +/************************************************************************* + * Internal Definitions + */ + +#ifndef DECIMAL_DIG +# define DECIMAL_DIG DBL_DIG +#endif + +/* Long double sizes */ +#ifdef LDBL_DIG +# define MAX_MANTISSA_DIGITS LDBL_DIG +# define MAX_EXPONENT_DIGITS 4 +# define MAX_DOUBLE_DIGITS LDBL_MAX_10_EXP +#else +# define MAX_MANTISSA_DIGITS DECIMAL_DIG +# define MAX_EXPONENT_DIGITS 3 +# define MAX_DOUBLE_DIGITS DBL_MAX_10_EXP +#endif + +#if defined(TRIO_COMPILER_ANCIENT) || !defined(LDBL_DIG) +# undef LDBL_DIG +# undef LDBL_MANT_DIG +# undef LDBL_EPSILON +# define LDBL_DIG DBL_DIG +# define LDBL_MANT_DIG DBL_MANT_DIG +# define LDBL_EPSILON DBL_EPSILON +#endif + +/* The maximal number of digits is for base 2 */ +#define MAX_CHARS_IN(x) (sizeof(x) * CHAR_BIT) +/* The width of a pointer. The number of bits in a hex digit is 4 */ +#define POINTER_WIDTH ((sizeof("0x") - 1) + sizeof(trio_pointer_t) * CHAR_BIT / 4) + +/* Infinite and Not-A-Number for floating-point */ +#define INFINITE_LOWER "inf" +#define INFINITE_UPPER "INF" +#define LONG_INFINITE_LOWER "infinite" +#define LONG_INFINITE_UPPER "INFINITE" +#define NAN_LOWER "nan" +#define NAN_UPPER "NAN" + +/* Various constants */ +enum { + TYPE_PRINT = 1, + TYPE_SCAN = 2, + + /* Flags. FLAGS_LAST must be less than ULONG_MAX */ + FLAGS_NEW = 0, + FLAGS_STICKY = 1, + FLAGS_SPACE = 2 * FLAGS_STICKY, + FLAGS_SHOWSIGN = 2 * FLAGS_SPACE, + FLAGS_LEFTADJUST = 2 * FLAGS_SHOWSIGN, + FLAGS_ALTERNATIVE = 2 * FLAGS_LEFTADJUST, + FLAGS_SHORT = 2 * FLAGS_ALTERNATIVE, + FLAGS_SHORTSHORT = 2 * FLAGS_SHORT, + FLAGS_LONG = 2 * FLAGS_SHORTSHORT, + FLAGS_QUAD = 2 * FLAGS_LONG, + FLAGS_LONGDOUBLE = 2 * FLAGS_QUAD, + FLAGS_SIZE_T = 2 * FLAGS_LONGDOUBLE, + FLAGS_PTRDIFF_T = 2 * FLAGS_SIZE_T, + FLAGS_INTMAX_T = 2 * FLAGS_PTRDIFF_T, + FLAGS_NILPADDING = 2 * FLAGS_INTMAX_T, + FLAGS_UNSIGNED = 2 * FLAGS_NILPADDING, + FLAGS_UPPER = 2 * FLAGS_UNSIGNED, + FLAGS_WIDTH = 2 * FLAGS_UPPER, + FLAGS_WIDTH_PARAMETER = 2 * FLAGS_WIDTH, + FLAGS_PRECISION = 2 * FLAGS_WIDTH_PARAMETER, + FLAGS_PRECISION_PARAMETER = 2 * FLAGS_PRECISION, + FLAGS_BASE = 2 * FLAGS_PRECISION_PARAMETER, + FLAGS_BASE_PARAMETER = 2 * FLAGS_BASE, + FLAGS_FLOAT_E = 2 * FLAGS_BASE_PARAMETER, + FLAGS_FLOAT_G = 2 * FLAGS_FLOAT_E, + FLAGS_QUOTE = 2 * FLAGS_FLOAT_G, + FLAGS_WIDECHAR = 2 * FLAGS_QUOTE, + FLAGS_ALLOC = 2 * FLAGS_WIDECHAR, + FLAGS_IGNORE = 2 * FLAGS_ALLOC, + FLAGS_IGNORE_PARAMETER = 2 * FLAGS_IGNORE, + FLAGS_VARSIZE_PARAMETER = 2 * FLAGS_IGNORE_PARAMETER, + FLAGS_FIXED_SIZE = 2 * FLAGS_VARSIZE_PARAMETER, + FLAGS_LAST = FLAGS_FIXED_SIZE, + /* Reused flags */ + FLAGS_EXCLUDE = FLAGS_SHORT, + FLAGS_USER_DEFINED = FLAGS_IGNORE, + FLAGS_ROUNDING = FLAGS_INTMAX_T, + /* Compounded flags */ + FLAGS_ALL_VARSIZES = FLAGS_LONG | FLAGS_QUAD | FLAGS_INTMAX_T | FLAGS_PTRDIFF_T | FLAGS_SIZE_T, + FLAGS_ALL_SIZES = FLAGS_ALL_VARSIZES | FLAGS_SHORTSHORT | FLAGS_SHORT, + + NO_POSITION = -1, + NO_WIDTH = 0, + NO_PRECISION = -1, + NO_SIZE = -1, + + /* Do not change these */ + NO_BASE = -1, + MIN_BASE = 2, + MAX_BASE = 36, + BASE_BINARY = 2, + BASE_OCTAL = 8, + BASE_DECIMAL = 10, + BASE_HEX = 16, + + /* Maximal number of allowed parameters */ + MAX_PARAMETERS = 64, + /* Maximal number of characters in class */ + MAX_CHARACTER_CLASS = UCHAR_MAX + 1, + + /* Maximal string lengths for user-defined specifiers */ + MAX_USER_NAME = 64, + MAX_USER_DATA = 256, + + /* Maximal length of locale separator strings */ + MAX_LOCALE_SEPARATOR_LENGTH = MB_LEN_MAX, + /* Maximal number of integers in grouping */ + MAX_LOCALE_GROUPS = 64, + + /* Initial size of asprintf buffer */ + DYNAMIC_START_SIZE = 32 +}; + +#define NO_GROUPING ((int)CHAR_MAX) + +/* Fundamental formatting parameter types */ +#define FORMAT_UNKNOWN 0 +#define FORMAT_INT 1 +#define FORMAT_DOUBLE 2 +#define FORMAT_CHAR 3 +#define FORMAT_STRING 4 +#define FORMAT_POINTER 5 +#define FORMAT_COUNT 6 +#define FORMAT_PARAMETER 7 +#define FORMAT_GROUP 8 +#if TRIO_GNU +# define FORMAT_ERRNO 9 +#endif +#if TRIO_EXTENSION +# define FORMAT_USER_DEFINED 10 +#endif + +/* Character constants */ +#define CHAR_IDENTIFIER '%' +#define CHAR_BACKSLASH '\\' +#define CHAR_QUOTE '\"' +#define CHAR_ADJUST ' ' + +/* Character class expressions */ +#define CLASS_ALNUM "[:alnum:]" +#define CLASS_ALPHA "[:alpha:]" +#define CLASS_BLANK "[:blank:]" +#define CLASS_CNTRL "[:cntrl:]" +#define CLASS_DIGIT "[:digit:]" +#define CLASS_GRAPH "[:graph:]" +#define CLASS_LOWER "[:lower:]" +#define CLASS_PRINT "[:print:]" +#define CLASS_PUNCT "[:punct:]" +#define CLASS_SPACE "[:space:]" +#define CLASS_UPPER "[:upper:]" +#define CLASS_XDIGIT "[:xdigit:]" + +/* + * SPECIFIERS: + * + * + * a Hex-float + * A Hex-float + * c Character + * C Widechar character (wint_t) + * d Decimal + * e Float + * E Float + * F Float + * F Float + * g Float + * G Float + * i Integer + * m Error message + * n Count + * o Octal + * p Pointer + * s String + * S Widechar string (wchar_t *) + * u Unsigned + * x Hex + * X Hex + * [] Group + * <> User-defined + * + * Reserved: + * + * D Binary Coded Decimal %D(length,precision) (OS/390) + */ +#define SPECIFIER_CHAR 'c' +#define SPECIFIER_STRING 's' +#define SPECIFIER_DECIMAL 'd' +#define SPECIFIER_INTEGER 'i' +#define SPECIFIER_UNSIGNED 'u' +#define SPECIFIER_OCTAL 'o' +#define SPECIFIER_HEX 'x' +#define SPECIFIER_HEX_UPPER 'X' +#define SPECIFIER_FLOAT_E 'e' +#define SPECIFIER_FLOAT_E_UPPER 'E' +#define SPECIFIER_FLOAT_F 'f' +#define SPECIFIER_FLOAT_F_UPPER 'F' +#define SPECIFIER_FLOAT_G 'g' +#define SPECIFIER_FLOAT_G_UPPER 'G' +#define SPECIFIER_POINTER 'p' +#define SPECIFIER_GROUP '[' +#define SPECIFIER_UNGROUP ']' +#define SPECIFIER_COUNT 'n' +#if TRIO_UNIX98 +# define SPECIFIER_CHAR_UPPER 'C' +# define SPECIFIER_STRING_UPPER 'S' +#endif +#if TRIO_C99 +# define SPECIFIER_HEXFLOAT 'a' +# define SPECIFIER_HEXFLOAT_UPPER 'A' +#endif +#if TRIO_GNU +# define SPECIFIER_ERRNO 'm' +#endif +#if TRIO_EXTENSION +# define SPECIFIER_BINARY 'b' +# define SPECIFIER_BINARY_UPPER 'B' +# define SPECIFIER_USER_DEFINED_BEGIN '<' +# define SPECIFIER_USER_DEFINED_END '>' +# define SPECIFIER_USER_DEFINED_SEPARATOR ':' +#endif + +/* + * QUALIFIERS: + * + * + * Numbers = d,i,o,u,x,X + * Float = a,A,e,E,f,F,g,G + * String = s + * Char = c + * + * + * 9$ Position + * Use the 9th parameter. 9 can be any number between 1 and + * the maximal argument + * + * 9 Width + * Set width to 9. 9 can be any number, but must not be postfixed + * by '$' + * + * h Short + * Numbers: + * (unsigned) short int + * + * hh Short short + * Numbers: + * (unsigned) char + * + * l Long + * Numbers: + * (unsigned) long int + * String: + * as the S specifier + * Char: + * as the C specifier + * + * ll Long Long + * Numbers: + * (unsigned) long long int + * + * L Long Double + * Float + * long double + * + * # Alternative + * Float: + * Decimal-point is always present + * String: + * non-printable characters are handled as \number + * + * Spacing + * + * + Sign + * + * - Alignment + * + * . Precision + * + * * Parameter + * print: use parameter + * scan: no parameter (ignore) + * + * q Quad + * + * Z size_t + * + * w Widechar + * + * ' Thousands/quote + * Numbers: + * Integer part grouped in thousands + * Binary numbers: + * Number grouped in nibbles (4 bits) + * String: + * Quoted string + * + * j intmax_t + * t prtdiff_t + * z size_t + * + * ! Sticky + * @ Parameter (for both print and scan) + * + * I n-bit Integer + * Numbers: + * The following options exists + * I8 = 8-bit integer + * I16 = 16-bit integer + * I32 = 32-bit integer + * I64 = 64-bit integer + */ +#define QUALIFIER_POSITION '$' +#define QUALIFIER_SHORT 'h' +#define QUALIFIER_LONG 'l' +#define QUALIFIER_LONG_UPPER 'L' +#define QUALIFIER_ALTERNATIVE '#' +#define QUALIFIER_SPACE ' ' +#define QUALIFIER_PLUS '+' +#define QUALIFIER_MINUS '-' +#define QUALIFIER_DOT '.' +#define QUALIFIER_STAR '*' +#define QUALIFIER_CIRCUMFLEX '^' /* For scanlists */ +#if TRIO_C99 +# define QUALIFIER_SIZE_T 'z' +# define QUALIFIER_PTRDIFF_T 't' +# define QUALIFIER_INTMAX_T 'j' +#endif +#if TRIO_BSD || TRIO_GNU +# define QUALIFIER_QUAD 'q' +#endif +#if TRIO_GNU +# define QUALIFIER_SIZE_T_UPPER 'Z' +#endif +#if TRIO_MISC +# define QUALIFIER_WIDECHAR 'w' +#endif +#if TRIO_MICROSOFT +# define QUALIFIER_FIXED_SIZE 'I' +#endif +#if TRIO_EXTENSION +# define QUALIFIER_QUOTE '\'' +# define QUALIFIER_STICKY '!' +# define QUALIFIER_VARSIZE '&' /* This should remain undocumented */ +# define QUALIFIER_PARAM '@' /* Experimental */ +# define QUALIFIER_COLON ':' /* For scanlists */ +# define QUALIFIER_EQUAL '=' /* For scanlists */ +# define QUALIFIER_ROUNDING_UPPER 'R' +#endif + + +/************************************************************************* + * + * Internal Structures + * + *************************************************************************/ + +/* Parameters */ +typedef struct { + /* An indication of which entry in the data union is used */ + int type; + /* The flags */ + trio_flags_t flags; + /* The width qualifier */ + int width; + /* The precision qualifier */ + int precision; + /* The base qualifier */ + int base; + /* The size for the variable size qualifier */ + int varsize; + /* The marker of the end of the specifier */ + int indexAfterSpecifier; + /* The data from the argument list */ + union { + char *string; +#if TRIO_WIDECHAR + trio_wchar_t *wstring; +#endif + trio_pointer_t pointer; + union { + trio_intmax_t as_signed; + trio_uintmax_t as_unsigned; + } number; + double doubleNumber; + double *doublePointer; + trio_long_double_t longdoubleNumber; + trio_long_double_t *longdoublePointer; + int errorNumber; + } data; + /* For the user-defined specifier */ + char user_name[MAX_USER_NAME]; + char user_data[MAX_USER_DATA]; +} trio_parameter_t; + +/* Container for customized functions */ +typedef struct { + union { + trio_outstream_t out; + trio_instream_t in; + } stream; + trio_pointer_t closure; +} trio_custom_t; + +/* General trio "class" */ +typedef struct _trio_class_t { + /* + * The function to write characters to a stream. + */ + void (*OutStream) TRIO_PROTO((struct _trio_class_t *, int)); + /* + * The function to read characters from a stream. + */ + void (*InStream) TRIO_PROTO((struct _trio_class_t *, int *)); + /* + * The current location in the stream. + */ + trio_pointer_t location; + /* + * The character currently being processed. + */ + int current; + /* + * The number of characters that would have been written/read + * if there had been sufficient space. + */ + int processed; + /* + * The number of characters that are actually written/read. + * Processed and committed will only differ for the *nprintf + * and *nscanf functions. + */ + int committed; + /* + * The upper limit of characters that may be written/read. + */ + int max; + /* + * The last output error that was detected. + */ + int error; +} trio_class_t; + +/* References (for user-defined callbacks) */ +typedef struct _trio_reference_t { + trio_class_t *data; + trio_parameter_t *parameter; +} trio_reference_t; + +/* Registered entries (for user-defined callbacks) */ +typedef struct _trio_userdef_t { + struct _trio_userdef_t *next; + trio_callback_t callback; + char *name; +} trio_userdef_t; + +/************************************************************************* + * + * Internal Variables + * + *************************************************************************/ + +static TRIO_CONST char rcsid[] = "@(#)$Id$"; + +/* + * Need this to workaround a parser bug in HP C/iX compiler that fails + * to resolves macro definitions that includes type 'long double', + * e.g: va_arg(arg_ptr, long double) + */ +#if defined(TRIO_PLATFORM_MPEIX) +static TRIO_CONST trio_long_double_t ___dummy_long_double = 0; +#endif + +static TRIO_CONST char internalNullString[] = "(nil)"; + +#if defined(USE_LOCALE) +static struct lconv *internalLocaleValues = NULL; +#endif + +/* + * UNIX98 says "in a locale where the radix character is not defined, + * the radix character defaults to a period (.)" + */ +static int internalDecimalPointLength = 1; +static int internalThousandSeparatorLength = 1; +static char internalDecimalPoint = '.'; +static char internalDecimalPointString[MAX_LOCALE_SEPARATOR_LENGTH + 1] = "."; +static char internalThousandSeparator[MAX_LOCALE_SEPARATOR_LENGTH + 1] = ","; +static char internalGrouping[MAX_LOCALE_GROUPS] = { (char)NO_GROUPING }; + +static TRIO_CONST char internalDigitsLower[] = "0123456789abcdefghijklmnopqrstuvwxyz"; +static TRIO_CONST char internalDigitsUpper[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; +static BOOLEAN_T internalDigitsUnconverted = TRUE; +static int internalDigitArray[128]; +#if TRIO_EXTENSION +static BOOLEAN_T internalCollationUnconverted = TRUE; +static char internalCollationArray[MAX_CHARACTER_CLASS][MAX_CHARACTER_CLASS]; +#endif + +#if TRIO_EXTENSION +static TRIO_VOLATILE trio_callback_t internalEnterCriticalRegion = NULL; +static TRIO_VOLATILE trio_callback_t internalLeaveCriticalRegion = NULL; +static trio_userdef_t *internalUserDef = NULL; +#endif + + +/************************************************************************* + * + * Internal Functions + * + ************************************************************************/ + +#if defined(TRIO_MINIMAL) +# define TRIO_STRING_PUBLIC static +# include "triostr.c" +#endif /* defined(TRIO_MINIMAL) */ + +/************************************************************************* + * TrioIsQualifier + * + * Description: + * Remember to add all new qualifiers to this function. + * QUALIFIER_POSITION must not be added. + */ +TRIO_PRIVATE BOOLEAN_T +TrioIsQualifier +TRIO_ARGS1((character), + TRIO_CONST char character) +{ + /* QUALIFIER_POSITION is not included */ + switch (character) + { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case QUALIFIER_PLUS: + case QUALIFIER_MINUS: + case QUALIFIER_SPACE: + case QUALIFIER_DOT: + case QUALIFIER_STAR: + case QUALIFIER_ALTERNATIVE: + case QUALIFIER_SHORT: + case QUALIFIER_LONG: + case QUALIFIER_LONG_UPPER: + case QUALIFIER_CIRCUMFLEX: +#if defined(QUALIFIER_SIZE_T) + case QUALIFIER_SIZE_T: +#endif +#if defined(QUALIFIER_PTRDIFF_T) + case QUALIFIER_PTRDIFF_T: +#endif +#if defined(QUALIFIER_INTMAX_T) + case QUALIFIER_INTMAX_T: +#endif +#if defined(QUALIFIER_QUAD) + case QUALIFIER_QUAD: +#endif +#if defined(QUALIFIER_SIZE_T_UPPER) + case QUALIFIER_SIZE_T_UPPER: +#endif +#if defined(QUALIFIER_WIDECHAR) + case QUALIFIER_WIDECHAR: +#endif +#if defined(QUALIFIER_QUOTE) + case QUALIFIER_QUOTE: +#endif +#if defined(QUALIFIER_STICKY) + case QUALIFIER_STICKY: +#endif +#if defined(QUALIFIER_VARSIZE) + case QUALIFIER_VARSIZE: +#endif +#if defined(QUALIFIER_PARAM) + case QUALIFIER_PARAM: +#endif +#if defined(QUALIFIER_FIXED_SIZE) + case QUALIFIER_FIXED_SIZE: +#endif +#if defined(QUALIFIER_ROUNDING_UPPER) + case QUALIFIER_ROUNDING_UPPER: +#endif + return TRUE; + default: + return FALSE; + } +} + +/************************************************************************* + * TrioSetLocale + */ +#if defined(USE_LOCALE) +TRIO_PRIVATE void +TrioSetLocale(TRIO_NOARGS) +{ + internalLocaleValues = (struct lconv *)localeconv(); + if (internalLocaleValues) + { + if ((internalLocaleValues->decimal_point) && + (internalLocaleValues->decimal_point[0] != NIL)) + { + internalDecimalPointLength = trio_length(internalLocaleValues->decimal_point); + if (internalDecimalPointLength == 1) + { + internalDecimalPoint = internalLocaleValues->decimal_point[0]; + } + else + { + internalDecimalPoint = NIL; + trio_copy_max(internalDecimalPointString, + sizeof(internalDecimalPointString), + internalLocaleValues->decimal_point); + } + } + if ((internalLocaleValues->thousands_sep) && + (internalLocaleValues->thousands_sep[0] != NIL)) + { + trio_copy_max(internalThousandSeparator, + sizeof(internalThousandSeparator), + internalLocaleValues->thousands_sep); + internalThousandSeparatorLength = trio_length(internalThousandSeparator); + } + if ((internalLocaleValues->grouping) && + (internalLocaleValues->grouping[0] != NIL)) + { + trio_copy_max(internalGrouping, + sizeof(internalGrouping), + internalLocaleValues->grouping); + } + } +} +#endif /* defined(USE_LOCALE) */ + +TRIO_PRIVATE int +TrioCalcThousandSeparatorLength +TRIO_ARGS1((digits), + int digits) +{ +#if TRIO_EXTENSION + int count = 0; + int step = NO_GROUPING; + char *groupingPointer = internalGrouping; + + while (digits > 0) + { + if (*groupingPointer == CHAR_MAX) + { + /* Disable grouping */ + break; /* while */ + } + else if (*groupingPointer == 0) + { + /* Repeat last group */ + if (step == NO_GROUPING) + { + /* Error in locale */ + break; /* while */ + } + } + else + { + step = *groupingPointer++; + } + if (digits > step) + count += internalThousandSeparatorLength; + digits -= step; + } + return count; +#else + return 0; +#endif +} + +TRIO_PRIVATE BOOLEAN_T +TrioFollowedBySeparator +TRIO_ARGS1((position), + int position) +{ +#if TRIO_EXTENSION + int step = 0; + char *groupingPointer = internalGrouping; + + position--; + if (position == 0) + return FALSE; + while (position > 0) + { + if (*groupingPointer == CHAR_MAX) + { + /* Disable grouping */ + break; /* while */ + } + else if (*groupingPointer != 0) + { + step = *groupingPointer++; + } + if (step == 0) + break; + position -= step; + } + return (position == 0); +#else + return FALSE; +#endif +} + +/************************************************************************* + * TrioGetPosition + * + * Get the %n$ position. + */ +TRIO_PRIVATE int +TrioGetPosition +TRIO_ARGS2((format, indexPointer), + TRIO_CONST char *format, + int *indexPointer) +{ +#if TRIO_UNIX98 + char *tmpformat; + int number = 0; + int index = *indexPointer; + + number = (int)trio_to_long(&format[index], &tmpformat, BASE_DECIMAL); + index = (int)(tmpformat - format); + if ((number != 0) && (QUALIFIER_POSITION == format[index++])) + { + *indexPointer = index; + /* + * number is decreased by 1, because n$ starts from 1, whereas + * the array it is indexing starts from 0. + */ + return number - 1; + } +#endif + return NO_POSITION; +} + +#if TRIO_EXTENSION +/************************************************************************* + * TrioFindNamespace + * + * Find registered user-defined specifier. + * The prev argument is used for optimization only. + */ +TRIO_PRIVATE trio_userdef_t * +TrioFindNamespace +TRIO_ARGS2((name, prev), + TRIO_CONST char *name, + trio_userdef_t **prev) +{ + trio_userdef_t *def; + + if (internalEnterCriticalRegion) + (void)internalEnterCriticalRegion(NULL); + + for (def = internalUserDef; def; def = def->next) + { + /* Case-sensitive string comparison */ + if (trio_equal_case(def->name, name)) + break; + + if (prev) + *prev = def; + } + + if (internalLeaveCriticalRegion) + (void)internalLeaveCriticalRegion(NULL); + + return def; +} +#endif + +/************************************************************************* + * TrioPower + * + * Description: + * Calculate pow(base, exponent), where number and exponent are integers. + */ +TRIO_PRIVATE trio_long_double_t +TrioPower +TRIO_ARGS2((number, exponent), + int number, + int exponent) +{ + trio_long_double_t result; + + if (number == 10) + { + switch (exponent) + { + /* Speed up calculation of common cases */ + case 0: + result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E-1); + break; + case 1: + result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+0); + break; + case 2: + result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+1); + break; + case 3: + result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+2); + break; + case 4: + result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+3); + break; + case 5: + result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+4); + break; + case 6: + result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+5); + break; + case 7: + result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+6); + break; + case 8: + result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+7); + break; + case 9: + result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+8); + break; + default: + result = powl((trio_long_double_t)number, + (trio_long_double_t)exponent); + break; + } + } + else + { + return powl((trio_long_double_t)number, (trio_long_double_t)exponent); + } + return result; +} + +/************************************************************************* + * TrioLogarithm + */ +TRIO_PRIVATE double +TrioLogarithm +TRIO_ARGS2((number, base), + double number, + int base) +{ + double result; + + if (number <= 0.0) + { + /* xlC crashes on log(0) */ + result = (number == 0.0) ? trio_ninf() : trio_nan(); + } + else + { + if (base == 10) + { + result = log10(number); + } + else + { + result = log10(number) / log10((double)base); + } + } + return result; +} + +/************************************************************************* + * TrioLogarithmBase + */ +TRIO_PRIVATE double +TrioLogarithmBase +TRIO_ARGS1((base), + int base) +{ + switch (base) + { + case BASE_BINARY : return 1.0; + case BASE_OCTAL : return 3.0; + case BASE_DECIMAL: return 3.321928094887362345; + case BASE_HEX : return 4.0; + default : return TrioLogarithm((double)base, 2); + } +} + +/************************************************************************* + * TrioParse + * + * Description: + * Parse the format string + */ +TRIO_PRIVATE int +TrioParse +TRIO_ARGS5((type, format, parameters, arglist, argarray), + int type, + TRIO_CONST char *format, + trio_parameter_t *parameters, + va_list *arglist, + trio_pointer_t *argarray) +{ + /* Count the number of times a parameter is referenced */ + unsigned short usedEntries[MAX_PARAMETERS]; + /* Parameter counters */ + int parameterPosition; + int currentParam; + int maxParam = -1; + /* Utility variables */ + trio_flags_t flags; + int width; + int precision; + int varsize; + int base; + int index; /* Index into formatting string */ + int dots; /* Count number of dots in modifier part */ + BOOLEAN_T positional; /* Does the specifier have a positional? */ + BOOLEAN_T gotSticky = FALSE; /* Are there any sticky modifiers at all? */ + /* + * indices specifies the order in which the parameters must be + * read from the va_args (this is necessary to handle positionals) + */ + int indices[MAX_PARAMETERS]; + int pos = 0; + /* Various variables */ + char ch; +#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE) + int charlen; +#endif + int save_errno; + int i = -1; + int num; + char *tmpformat; + + /* One and only one of arglist and argarray must be used */ + assert((arglist != NULL) ^ (argarray != NULL)); + + /* + * The 'parameters' array is not initialized, but we need to + * know which entries we have used. + */ + memset(usedEntries, 0, sizeof(usedEntries)); + + save_errno = errno; + index = 0; + parameterPosition = 0; +#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE) + (void)mblen(NULL, 0); +#endif + + while (format[index]) + { +#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE) + if (! isascii(format[index])) + { + /* + * Multibyte characters cannot be legal specifiers or + * modifiers, so we skip over them. + */ + charlen = mblen(&format[index], MB_LEN_MAX); + index += (charlen > 0) ? charlen : 1; + continue; /* while */ + } +#endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */ + if (CHAR_IDENTIFIER == format[index++]) + { + if (CHAR_IDENTIFIER == format[index]) + { + index++; + continue; /* while */ + } + + flags = FLAGS_NEW; + dots = 0; + currentParam = TrioGetPosition(format, &index); + positional = (NO_POSITION != currentParam); + if (!positional) + { + /* We have no positional, get the next counter */ + currentParam = parameterPosition; + } + if(currentParam >= MAX_PARAMETERS) + { + /* Bail out completely to make the error more obvious */ + return TRIO_ERROR_RETURN(TRIO_ETOOMANY, index); + } + + if (currentParam > maxParam) + maxParam = currentParam; + + /* Default values */ + width = NO_WIDTH; + precision = NO_PRECISION; + base = NO_BASE; + varsize = NO_SIZE; + + while (TrioIsQualifier(format[index])) + { + ch = format[index++]; + + switch (ch) + { + case QUALIFIER_SPACE: + flags |= FLAGS_SPACE; + break; + + case QUALIFIER_PLUS: + flags |= FLAGS_SHOWSIGN; + break; + + case QUALIFIER_MINUS: + flags |= FLAGS_LEFTADJUST; + flags &= ~FLAGS_NILPADDING; + break; + + case QUALIFIER_ALTERNATIVE: + flags |= FLAGS_ALTERNATIVE; + break; + + case QUALIFIER_DOT: + if (dots == 0) /* Precision */ + { + dots++; + + /* Skip if no precision */ + if (QUALIFIER_DOT == format[index]) + break; + + /* After the first dot we have the precision */ + flags |= FLAGS_PRECISION; + if ((QUALIFIER_STAR == format[index]) +#if defined(QUALIFIER_PARAM) + || (QUALIFIER_PARAM == format[index]) +#endif + ) + { + index++; + flags |= FLAGS_PRECISION_PARAMETER; + + precision = TrioGetPosition(format, &index); + if (precision == NO_POSITION) + { + parameterPosition++; + if (positional) + precision = parameterPosition; + else + { + precision = currentParam; + currentParam = precision + 1; + } + } + else + { + if (! positional) + currentParam = precision + 1; + if (width > maxParam) + maxParam = precision; + } + if (currentParam > maxParam) + maxParam = currentParam; + } + else + { + precision = trio_to_long(&format[index], + &tmpformat, + BASE_DECIMAL); + index = (int)(tmpformat - format); + } + } + else if (dots == 1) /* Base */ + { + dots++; + + /* After the second dot we have the base */ + flags |= FLAGS_BASE; + if ((QUALIFIER_STAR == format[index]) +#if defined(QUALIFIER_PARAM) + || (QUALIFIER_PARAM == format[index]) +#endif + ) + { + index++; + flags |= FLAGS_BASE_PARAMETER; + base = TrioGetPosition(format, &index); + if (base == NO_POSITION) + { + parameterPosition++; + if (positional) + base = parameterPosition; + else + { + base = currentParam; + currentParam = base + 1; + } + } + else + { + if (! positional) + currentParam = base + 1; + if (base > maxParam) + maxParam = base; + } + if (currentParam > maxParam) + maxParam = currentParam; + } + else + { + base = trio_to_long(&format[index], + &tmpformat, + BASE_DECIMAL); + if (base > MAX_BASE) + return TRIO_ERROR_RETURN(TRIO_EINVAL, index); + index = (int)(tmpformat - format); + } + } + else + { + return TRIO_ERROR_RETURN(TRIO_EINVAL, index); + } + break; /* QUALIFIER_DOT */ + +#if defined(QUALIFIER_PARAM) + case QUALIFIER_PARAM: + type = TYPE_PRINT; + /* FALLTHROUGH */ +#endif + case QUALIFIER_STAR: + /* This has different meanings for print and scan */ + if (TYPE_PRINT == type) + { + /* Read with from parameter */ + flags |= (FLAGS_WIDTH | FLAGS_WIDTH_PARAMETER); + width = TrioGetPosition(format, &index); + if (width == NO_POSITION) + { + parameterPosition++; + if (positional) + width = parameterPosition; + else + { + width = currentParam; + currentParam = width + 1; + } + } + else + { + if (! positional) + currentParam = width + 1; + if (width > maxParam) + maxParam = width; + } + if (currentParam > maxParam) + maxParam = currentParam; + } + else + { + /* Scan, but do not store result */ + flags |= FLAGS_IGNORE; + } + + break; /* QUALIFIER_STAR */ + + case '0': + if (! (flags & FLAGS_LEFTADJUST)) + flags |= FLAGS_NILPADDING; + /* FALLTHROUGH */ + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + flags |= FLAGS_WIDTH; + /* &format[index - 1] is used to "rewind" the read + * character from format + */ + width = trio_to_long(&format[index - 1], + &tmpformat, + BASE_DECIMAL); + index = (int)(tmpformat - format); + break; + + case QUALIFIER_SHORT: + if (flags & FLAGS_SHORTSHORT) + return TRIO_ERROR_RETURN(TRIO_EINVAL, index); + else if (flags & FLAGS_SHORT) + flags |= FLAGS_SHORTSHORT; + else + flags |= FLAGS_SHORT; + break; + + case QUALIFIER_LONG: + if (flags & FLAGS_QUAD) + return TRIO_ERROR_RETURN(TRIO_EINVAL, index); + else if (flags & FLAGS_LONG) + flags |= FLAGS_QUAD; + else + flags |= FLAGS_LONG; + break; + + case QUALIFIER_LONG_UPPER: + flags |= FLAGS_LONGDOUBLE; + break; + +#if defined(QUALIFIER_SIZE_T) + case QUALIFIER_SIZE_T: + flags |= FLAGS_SIZE_T; + /* Modify flags for later truncation of number */ + if (sizeof(size_t) == sizeof(trio_ulonglong_t)) + flags |= FLAGS_QUAD; + else if (sizeof(size_t) == sizeof(long)) + flags |= FLAGS_LONG; + break; +#endif + +#if defined(QUALIFIER_PTRDIFF_T) + case QUALIFIER_PTRDIFF_T: + flags |= FLAGS_PTRDIFF_T; + if (sizeof(ptrdiff_t) == sizeof(trio_ulonglong_t)) + flags |= FLAGS_QUAD; + else if (sizeof(ptrdiff_t) == sizeof(long)) + flags |= FLAGS_LONG; + break; +#endif + +#if defined(QUALIFIER_INTMAX_T) + case QUALIFIER_INTMAX_T: + flags |= FLAGS_INTMAX_T; + if (sizeof(trio_intmax_t) == sizeof(trio_ulonglong_t)) + flags |= FLAGS_QUAD; + else if (sizeof(trio_intmax_t) == sizeof(long)) + flags |= FLAGS_LONG; + break; +#endif + +#if defined(QUALIFIER_QUAD) + case QUALIFIER_QUAD: + flags |= FLAGS_QUAD; + break; +#endif + +#if defined(QUALIFIER_FIXED_SIZE) + case QUALIFIER_FIXED_SIZE: + if (flags & FLAGS_FIXED_SIZE) + return TRIO_ERROR_RETURN(TRIO_EINVAL, index); + + if (flags & (FLAGS_ALL_SIZES | FLAGS_LONGDOUBLE | + FLAGS_WIDECHAR | FLAGS_VARSIZE_PARAMETER)) + return TRIO_ERROR_RETURN(TRIO_EINVAL, index); + + if ((format[index] == '6') && + (format[index + 1] == '4')) + { + varsize = sizeof(trio_int64_t); + index += 2; + } + else if ((format[index] == '3') && + (format[index + 1] == '2')) + { + varsize = sizeof(trio_int32_t); + index += 2; + } + else if ((format[index] == '1') && + (format[index + 1] == '6')) + { + varsize = sizeof(trio_int16_t); + index += 2; + } + else if (format[index] == '8') + { + varsize = sizeof(trio_int8_t); + index++; + } + else + return TRIO_ERROR_RETURN(TRIO_EINVAL, index); + + flags |= FLAGS_FIXED_SIZE; + break; +#endif + +#if defined(QUALIFIER_WIDECHAR) + case QUALIFIER_WIDECHAR: + flags |= FLAGS_WIDECHAR; + break; +#endif + +#if defined(QUALIFIER_SIZE_T_UPPER) + case QUALIFIER_SIZE_T_UPPER: + break; +#endif + +#if defined(QUALIFIER_QUOTE) + case QUALIFIER_QUOTE: + flags |= FLAGS_QUOTE; + break; +#endif + +#if defined(QUALIFIER_STICKY) + case QUALIFIER_STICKY: + flags |= FLAGS_STICKY; + gotSticky = TRUE; + break; +#endif + +#if defined(QUALIFIER_VARSIZE) + case QUALIFIER_VARSIZE: + flags |= FLAGS_VARSIZE_PARAMETER; + parameterPosition++; + if (positional) + varsize = parameterPosition; + else + { + varsize = currentParam; + currentParam = varsize + 1; + } + if (currentParam > maxParam) + maxParam = currentParam; + break; +#endif + +#if defined(QUALIFIER_ROUNDING_UPPER) + case QUALIFIER_ROUNDING_UPPER: + flags |= FLAGS_ROUNDING; + break; +#endif + + default: + /* Bail out completely to make the error more obvious */ + return TRIO_ERROR_RETURN(TRIO_EINVAL, index); + } + } /* while qualifier */ + + /* + * Parameters only need the type and value. The value is + * read later. + */ + if (flags & FLAGS_WIDTH_PARAMETER) + { + usedEntries[width] += 1; + parameters[pos].type = FORMAT_PARAMETER; + parameters[pos].flags = 0; + indices[width] = pos; + width = pos++; + } + if (flags & FLAGS_PRECISION_PARAMETER) + { + usedEntries[precision] += 1; + parameters[pos].type = FORMAT_PARAMETER; + parameters[pos].flags = 0; + indices[precision] = pos; + precision = pos++; + } + if (flags & FLAGS_BASE_PARAMETER) + { + usedEntries[base] += 1; + parameters[pos].type = FORMAT_PARAMETER; + parameters[pos].flags = 0; + indices[base] = pos; + base = pos++; + } + if (flags & FLAGS_VARSIZE_PARAMETER) + { + usedEntries[varsize] += 1; + parameters[pos].type = FORMAT_PARAMETER; + parameters[pos].flags = 0; + indices[varsize] = pos; + varsize = pos++; + } + + indices[currentParam] = pos; + + switch (format[index++]) + { +#if defined(SPECIFIER_CHAR_UPPER) + case SPECIFIER_CHAR_UPPER: + flags |= FLAGS_WIDECHAR; + /* FALLTHROUGH */ +#endif + case SPECIFIER_CHAR: + if (flags & FLAGS_LONG) + flags |= FLAGS_WIDECHAR; + else if (flags & FLAGS_SHORT) + flags &= ~FLAGS_WIDECHAR; + parameters[pos].type = FORMAT_CHAR; + break; + +#if defined(SPECIFIER_STRING_UPPER) + case SPECIFIER_STRING_UPPER: + flags |= FLAGS_WIDECHAR; + /* FALLTHROUGH */ +#endif + case SPECIFIER_STRING: + if (flags & FLAGS_LONG) + flags |= FLAGS_WIDECHAR; + else if (flags & FLAGS_SHORT) + flags &= ~FLAGS_WIDECHAR; + parameters[pos].type = FORMAT_STRING; + break; + + case SPECIFIER_GROUP: + if (TYPE_SCAN == type) + { + int depth = 1; + parameters[pos].type = FORMAT_GROUP; + if (format[index] == QUALIFIER_CIRCUMFLEX) + index++; + if (format[index] == SPECIFIER_UNGROUP) + index++; + if (format[index] == QUALIFIER_MINUS) + index++; + /* Skip nested brackets */ + while (format[index] != NIL) + { + if (format[index] == SPECIFIER_GROUP) + { + depth++; + } + else if (format[index] == SPECIFIER_UNGROUP) + { + if (--depth <= 0) + { + index++; + break; + } + } + index++; + } + } + break; + + case SPECIFIER_INTEGER: + parameters[pos].type = FORMAT_INT; + break; + + case SPECIFIER_UNSIGNED: + flags |= FLAGS_UNSIGNED; + parameters[pos].type = FORMAT_INT; + break; + + case SPECIFIER_DECIMAL: + /* Disable base modifier */ + flags &= ~FLAGS_BASE_PARAMETER; + base = BASE_DECIMAL; + parameters[pos].type = FORMAT_INT; + break; + + case SPECIFIER_OCTAL: + flags |= FLAGS_UNSIGNED; + flags &= ~FLAGS_BASE_PARAMETER; + base = BASE_OCTAL; + parameters[pos].type = FORMAT_INT; + break; + +#if defined(SPECIFIER_BINARY) + case SPECIFIER_BINARY_UPPER: + flags |= FLAGS_UPPER; + /* FALLTHROUGH */ + case SPECIFIER_BINARY: + flags |= FLAGS_NILPADDING; + flags &= ~FLAGS_BASE_PARAMETER; + base = BASE_BINARY; + parameters[pos].type = FORMAT_INT; + break; +#endif + + case SPECIFIER_HEX_UPPER: + flags |= FLAGS_UPPER; + /* FALLTHROUGH */ + case SPECIFIER_HEX: + flags |= FLAGS_UNSIGNED; + flags &= ~FLAGS_BASE_PARAMETER; + base = BASE_HEX; + parameters[pos].type = FORMAT_INT; + break; + + case SPECIFIER_FLOAT_E_UPPER: + flags |= FLAGS_UPPER; + /* FALLTHROUGH */ + case SPECIFIER_FLOAT_E: + flags |= FLAGS_FLOAT_E; + parameters[pos].type = FORMAT_DOUBLE; + break; + + case SPECIFIER_FLOAT_G_UPPER: + flags |= FLAGS_UPPER; + /* FALLTHROUGH */ + case SPECIFIER_FLOAT_G: + flags |= FLAGS_FLOAT_G; + parameters[pos].type = FORMAT_DOUBLE; + break; + + case SPECIFIER_FLOAT_F_UPPER: + flags |= FLAGS_UPPER; + /* FALLTHROUGH */ + case SPECIFIER_FLOAT_F: + parameters[pos].type = FORMAT_DOUBLE; + break; + + case SPECIFIER_POINTER: + if (sizeof(trio_pointer_t) == sizeof(trio_ulonglong_t)) + flags |= FLAGS_QUAD; + else if (sizeof(trio_pointer_t) == sizeof(long)) + flags |= FLAGS_LONG; + parameters[pos].type = FORMAT_POINTER; + break; + + case SPECIFIER_COUNT: + parameters[pos].type = FORMAT_COUNT; + break; + +#if defined(SPECIFIER_HEXFLOAT) +# if defined(SPECIFIER_HEXFLOAT_UPPER) + case SPECIFIER_HEXFLOAT_UPPER: + flags |= FLAGS_UPPER; + /* FALLTHROUGH */ +# endif + case SPECIFIER_HEXFLOAT: + base = BASE_HEX; + parameters[pos].type = FORMAT_DOUBLE; + break; +#endif + +#if defined(FORMAT_ERRNO) + case SPECIFIER_ERRNO: + parameters[pos].type = FORMAT_ERRNO; + break; +#endif + +#if defined(SPECIFIER_USER_DEFINED_BEGIN) + case SPECIFIER_USER_DEFINED_BEGIN: + { + unsigned int max; + int without_namespace = TRUE; + + parameters[pos].type = FORMAT_USER_DEFINED; + parameters[pos].user_name[0] = NIL; + tmpformat = (char *)&format[index]; + + while ((ch = format[index])) + { + index++; + if (ch == SPECIFIER_USER_DEFINED_END) + { + if (without_namespace) + { + /* We must get the handle first */ + parameters[pos].type = FORMAT_PARAMETER; + parameters[pos].indexAfterSpecifier = index; + parameters[pos].flags = FLAGS_USER_DEFINED; + /* Adjust parameters for insertion of new one */ + pos++; + usedEntries[currentParam] += 1; + parameters[pos].type = FORMAT_USER_DEFINED; + currentParam++; + indices[currentParam] = pos; + if (currentParam > maxParam) + maxParam = currentParam; + } + /* Copy the user data */ + max = (unsigned int)(&format[index] - tmpformat); + if (max > MAX_USER_DATA) + max = MAX_USER_DATA; + trio_copy_max(parameters[pos].user_data, + max, + tmpformat); + break; /* while */ + } + if (ch == SPECIFIER_USER_DEFINED_SEPARATOR) + { + without_namespace = FALSE; + /* Copy the namespace for later looking-up */ + max = (int)(&format[index] - tmpformat); + if (max > MAX_USER_NAME) + max = MAX_USER_NAME; + trio_copy_max(parameters[pos].user_name, + max, + tmpformat); + tmpformat = (char *)&format[index]; + } + } + if (ch != SPECIFIER_USER_DEFINED_END) + return TRIO_ERROR_RETURN(TRIO_EINVAL, index); + } + break; +#endif /* defined(SPECIFIER_USER_DEFINED_BEGIN) */ + + default: + /* Bail out completely to make the error more obvious */ + return TRIO_ERROR_RETURN(TRIO_EINVAL, index); + } + + /* Count the number of times this entry has been used */ + usedEntries[currentParam] += 1; + + /* Find last sticky parameters */ + if (gotSticky && !(flags & FLAGS_STICKY)) + { + for (i = pos - 1; i >= 0; i--) + { + if (parameters[i].type == FORMAT_PARAMETER) + continue; + if ((parameters[i].flags & FLAGS_STICKY) && + (parameters[i].type == parameters[pos].type)) + { + /* Do not overwrite current qualifiers */ + flags |= (parameters[i].flags & (unsigned long)~FLAGS_STICKY); + if (width == NO_WIDTH) + width = parameters[i].width; + if (precision == NO_PRECISION) + precision = parameters[i].precision; + if (base == NO_BASE) + base = parameters[i].base; + break; + } + } + } + + parameters[pos].indexAfterSpecifier = index; + parameters[pos].flags = flags; + parameters[pos].width = width; + parameters[pos].precision = precision; + parameters[pos].base = (base == NO_BASE) ? BASE_DECIMAL : base; + parameters[pos].varsize = varsize; + pos++; + + if (! positional) + parameterPosition++; + + } /* if identifier */ + + } /* while format characters left */ + + for (num = 0; num <= maxParam; num++) + { + if (usedEntries[num] != 1) + { + if (usedEntries[num] == 0) /* gap detected */ + return TRIO_ERROR_RETURN(TRIO_EGAP, num); + else /* double references detected */ + return TRIO_ERROR_RETURN(TRIO_EDBLREF, num); + } + + i = indices[num]; + + /* + * FORMAT_PARAMETERS are only present if they must be read, + * so it makes no sense to check the ignore flag (besides, + * the flags variable is not set for that particular type) + */ + if ((parameters[i].type != FORMAT_PARAMETER) && + (parameters[i].flags & FLAGS_IGNORE)) + continue; /* for all arguments */ + + /* + * The stack arguments are read according to ANSI C89 + * default argument promotions: + * + * char = int + * short = int + * unsigned char = unsigned int + * unsigned short = unsigned int + * float = double + * + * In addition to the ANSI C89 these types are read (the + * default argument promotions of C99 has not been + * considered yet) + * + * long long + * long double + * size_t + * ptrdiff_t + * intmax_t + */ + switch (parameters[i].type) + { + case FORMAT_GROUP: + case FORMAT_STRING: +#if TRIO_WIDECHAR + if (flags & FLAGS_WIDECHAR) + { + parameters[i].data.wstring = (argarray == NULL) + ? va_arg(*arglist, trio_wchar_t *) + : (trio_wchar_t *)(argarray[num]); + } + else +#endif + { + parameters[i].data.string = (argarray == NULL) + ? va_arg(*arglist, char *) + : (char *)(argarray[num]); + } + break; + +#if defined(FORMAT_USER_DEFINED) + case FORMAT_USER_DEFINED: +#endif + case FORMAT_POINTER: + case FORMAT_COUNT: + case FORMAT_UNKNOWN: + parameters[i].data.pointer = (argarray == NULL) + ? va_arg(*arglist, trio_pointer_t ) + : argarray[num]; + break; + + case FORMAT_CHAR: + case FORMAT_INT: + if (TYPE_SCAN == type) + { + if (argarray == NULL) + parameters[i].data.pointer = + (trio_pointer_t)va_arg(*arglist, trio_pointer_t); + else + { + if (parameters[i].type == FORMAT_CHAR) + parameters[i].data.pointer = + (trio_pointer_t)((char *)argarray[num]); + else if (parameters[i].flags & FLAGS_SHORT) + parameters[i].data.pointer = + (trio_pointer_t)((short *)argarray[num]); + else + parameters[i].data.pointer = + (trio_pointer_t)((int *)argarray[num]); + } + } + else + { +#if defined(QUALIFIER_VARSIZE) || defined(QUALIFIER_FIXED_SIZE) + if (parameters[i].flags + & (FLAGS_VARSIZE_PARAMETER | FLAGS_FIXED_SIZE)) + { + if (parameters[i].flags & FLAGS_VARSIZE_PARAMETER) + { + /* + * Variable sizes are mapped onto the fixed sizes, in + * accordance with integer promotion. + * + * Please note that this may not be portable, as we + * only guess the size, not the layout of the numbers. + * For example, if int is little-endian, and long is + * big-endian, then this will fail. + */ + varsize = (int)parameters[parameters[i].varsize].data.number.as_unsigned; + } + else + { + /* Used for the I modifiers */ + varsize = parameters[i].varsize; + } + parameters[i].flags &= ~FLAGS_ALL_VARSIZES; + + if (varsize <= (int)sizeof(int)) + ; + else if (varsize <= (int)sizeof(long)) + parameters[i].flags |= FLAGS_LONG; +#if defined(QUALIFIER_INTMAX_T) + else if (varsize <= (int)sizeof(trio_longlong_t)) + parameters[i].flags |= FLAGS_QUAD; + else + parameters[i].flags |= FLAGS_INTMAX_T; +#else + else + parameters[i].flags |= FLAGS_QUAD; +#endif + } +#endif /* defined(QUALIFIER_VARSIZE) */ +#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER) + if (parameters[i].flags & FLAGS_SIZE_T) + parameters[i].data.number.as_unsigned = (argarray == NULL) + ? (trio_uintmax_t)va_arg(*arglist, size_t) + : (trio_uintmax_t)(*((size_t *)argarray[num])); + else +#endif +#if defined(QUALIFIER_PTRDIFF_T) + if (parameters[i].flags & FLAGS_PTRDIFF_T) + parameters[i].data.number.as_unsigned = (argarray == NULL) + ? (trio_uintmax_t)va_arg(*arglist, ptrdiff_t) + : (trio_uintmax_t)(*((ptrdiff_t *)argarray[num])); + else +#endif +#if defined(QUALIFIER_INTMAX_T) + if (parameters[i].flags & FLAGS_INTMAX_T) + parameters[i].data.number.as_unsigned = (argarray == NULL) + ? (trio_uintmax_t)va_arg(*arglist, trio_intmax_t) + : (trio_uintmax_t)(*((trio_intmax_t *)argarray[num])); + else +#endif + if (parameters[i].flags & FLAGS_QUAD) + parameters[i].data.number.as_unsigned = (argarray == NULL) + ? (trio_uintmax_t)va_arg(*arglist, trio_ulonglong_t) + : (trio_uintmax_t)(*((trio_ulonglong_t *)argarray[num])); + else if (parameters[i].flags & FLAGS_LONG) + parameters[i].data.number.as_unsigned = (argarray == NULL) + ? (trio_uintmax_t)va_arg(*arglist, long) + : (trio_uintmax_t)(*((long *)argarray[num])); + else + { + if (argarray == NULL) + parameters[i].data.number.as_unsigned = (trio_uintmax_t)va_arg(*arglist, int); + else + { + if (parameters[i].type == FORMAT_CHAR) + parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((char *)argarray[num])); + else if (parameters[i].flags & FLAGS_SHORT) + parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((short *)argarray[num])); + else + parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((int *)argarray[num])); + } + } + } + break; + + case FORMAT_PARAMETER: + /* + * The parameter for the user-defined specifier is a pointer, + * whereas the rest (width, precision, base) uses an integer. + */ + if (parameters[i].flags & FLAGS_USER_DEFINED) + parameters[i].data.pointer = (argarray == NULL) + ? va_arg(*arglist, trio_pointer_t ) + : argarray[num]; + else + parameters[i].data.number.as_unsigned = (argarray == NULL) + ? (trio_uintmax_t)va_arg(*arglist, int) + : (trio_uintmax_t)(*((int *)argarray[num])); + break; + + case FORMAT_DOUBLE: + if (TYPE_SCAN == type) + { + if (parameters[i].flags & FLAGS_LONGDOUBLE) + parameters[i].data.longdoublePointer = (argarray == NULL) + ? va_arg(*arglist, trio_long_double_t *) + : (trio_long_double_t *)argarray[num]; + else + { + if (parameters[i].flags & FLAGS_LONG) + parameters[i].data.doublePointer = (argarray == NULL) + ? va_arg(*arglist, double *) + : (double *)argarray[num]; + else + parameters[i].data.doublePointer = (argarray == NULL) + ? (double *)va_arg(*arglist, float *) + : (double *)((float *)argarray[num]); + } + } + else + { + if (parameters[i].flags & FLAGS_LONGDOUBLE) + parameters[i].data.longdoubleNumber = (argarray == NULL) + ? va_arg(*arglist, trio_long_double_t) + : (trio_long_double_t)(*((trio_long_double_t *)argarray[num])); + else + { + if (argarray == NULL) + parameters[i].data.longdoubleNumber = + (trio_long_double_t)va_arg(*arglist, double); + else + { + if (parameters[i].flags & FLAGS_SHORT) + parameters[i].data.longdoubleNumber = + (trio_long_double_t)(*((float *)argarray[num])); + else + parameters[i].data.longdoubleNumber = + (trio_long_double_t)(*((double *)argarray[num])); + } + } + } + break; + +#if defined(FORMAT_ERRNO) + case FORMAT_ERRNO: + parameters[i].data.errorNumber = save_errno; + break; +#endif + + default: + break; + } + } /* for all specifiers */ + return num; +} + + +/************************************************************************* + * + * FORMATTING + * + ************************************************************************/ + + +/************************************************************************* + * TrioWriteNumber + * + * Description: + * Output a number. + * The complexity of this function is a result of the complexity + * of the dependencies of the flags. + */ +TRIO_PRIVATE void +TrioWriteNumber +TRIO_ARGS6((self, number, flags, width, precision, base), + trio_class_t *self, + trio_uintmax_t number, + trio_flags_t flags, + int width, + int precision, + int base) +{ + BOOLEAN_T isNegative; + BOOLEAN_T isNumberZero; + BOOLEAN_T isPrecisionZero; + BOOLEAN_T ignoreNumber; + char buffer[MAX_CHARS_IN(trio_uintmax_t) * (1 + MAX_LOCALE_SEPARATOR_LENGTH) + 1]; + char *bufferend; + char *pointer; + TRIO_CONST char *digits; + int i; + int length; + char *p; + int count; + + assert(VALID(self)); + assert(VALID(self->OutStream)); + assert(((base >= MIN_BASE) && (base <= MAX_BASE)) || (base == NO_BASE)); + + digits = (flags & FLAGS_UPPER) ? internalDigitsUpper : internalDigitsLower; + if (base == NO_BASE) + base = BASE_DECIMAL; + + isNumberZero = (number == 0); + isPrecisionZero = (precision == 0); + ignoreNumber = (isNumberZero + && isPrecisionZero + && !((flags & FLAGS_ALTERNATIVE) && (base == BASE_OCTAL))); + + if (flags & FLAGS_UNSIGNED) + { + isNegative = FALSE; + flags &= ~FLAGS_SHOWSIGN; + } + else + { + isNegative = ((trio_intmax_t)number < 0); + if (isNegative) + number = -((trio_intmax_t)number); + } + + if (flags & FLAGS_QUAD) + number &= (trio_ulonglong_t)-1; + else if (flags & FLAGS_LONG) + number &= (unsigned long)-1; + else + number &= (unsigned int)-1; + + /* Build number */ + pointer = bufferend = &buffer[sizeof(buffer) - 1]; + *pointer-- = NIL; + for (i = 1; i < (int)sizeof(buffer); i++) + { + *pointer-- = digits[number % base]; + number /= base; + if (number == 0) + break; + + if ((flags & FLAGS_QUOTE) && TrioFollowedBySeparator(i + 1)) + { + /* + * We are building the number from the least significant + * to the most significant digit, so we have to copy the + * thousand separator backwards + */ + length = internalThousandSeparatorLength; + if (((int)(pointer - buffer) - length) > 0) + { + p = &internalThousandSeparator[length - 1]; + while (length-- > 0) + *pointer-- = *p--; + } + } + } + + if (! ignoreNumber) + { + /* Adjust width */ + width -= (bufferend - pointer) - 1; + } + + /* Adjust precision */ + if (NO_PRECISION != precision) + { + precision -= (bufferend - pointer) - 1; + if (precision < 0) + precision = 0; + flags |= FLAGS_NILPADDING; + } + + /* Calculate padding */ + count = (! ((flags & FLAGS_LEFTADJUST) || (precision == NO_PRECISION))) + ? precision + : 0; + + /* Adjust width further */ + if (isNegative || (flags & FLAGS_SHOWSIGN) || (flags & FLAGS_SPACE)) + width--; + if ((flags & FLAGS_ALTERNATIVE) && !isNumberZero) + { + switch (base) + { + case BASE_BINARY: + case BASE_HEX: + width -= 2; + break; + case BASE_OCTAL: + if (!(flags & FLAGS_NILPADDING) || (count == 0)) + width--; + break; + default: + break; + } + } + + /* Output prefixes spaces if needed */ + if (! ((flags & FLAGS_LEFTADJUST) || + ((flags & FLAGS_NILPADDING) && (precision == NO_PRECISION)))) + { + while (width-- > count) + self->OutStream(self, CHAR_ADJUST); + } + + /* width has been adjusted for signs and alternatives */ + if (isNegative) + self->OutStream(self, '-'); + else if (flags & FLAGS_SHOWSIGN) + self->OutStream(self, '+'); + else if (flags & FLAGS_SPACE) + self->OutStream(self, ' '); + + /* Prefix is not written when the value is zero */ + if ((flags & FLAGS_ALTERNATIVE) && !isNumberZero) + { + switch (base) + { + case BASE_BINARY: + self->OutStream(self, '0'); + self->OutStream(self, (flags & FLAGS_UPPER) ? 'B' : 'b'); + break; + + case BASE_OCTAL: + if (!(flags & FLAGS_NILPADDING) || (count == 0)) + self->OutStream(self, '0'); + break; + + case BASE_HEX: + self->OutStream(self, '0'); + self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x'); + break; + + default: + break; + } /* switch base */ + } + + /* Output prefixed zero padding if needed */ + if (flags & FLAGS_NILPADDING) + { + if (precision == NO_PRECISION) + precision = width; + while (precision-- > 0) + { + self->OutStream(self, '0'); + width--; + } + } + + if (! ignoreNumber) + { + /* Output the number itself */ + while (*(++pointer)) + { + self->OutStream(self, *pointer); + } + } + + /* Output trailing spaces if needed */ + if (flags & FLAGS_LEFTADJUST) + { + while (width-- > 0) + self->OutStream(self, CHAR_ADJUST); + } +} + +/************************************************************************* + * TrioWriteStringCharacter + * + * Description: + * Output a single character of a string + */ +TRIO_PRIVATE void +TrioWriteStringCharacter +TRIO_ARGS3((self, ch, flags), + trio_class_t *self, + int ch, + trio_flags_t flags) +{ + if (flags & FLAGS_ALTERNATIVE) + { + if (! isprint(ch)) + { + /* + * Non-printable characters are converted to C escapes or + * \number, if no C escape exists. + */ + self->OutStream(self, CHAR_BACKSLASH); + switch (ch) + { + case '\007': self->OutStream(self, 'a'); break; + case '\b': self->OutStream(self, 'b'); break; + case '\f': self->OutStream(self, 'f'); break; + case '\n': self->OutStream(self, 'n'); break; + case '\r': self->OutStream(self, 'r'); break; + case '\t': self->OutStream(self, 't'); break; + case '\v': self->OutStream(self, 'v'); break; + case '\\': self->OutStream(self, '\\'); break; + default: + self->OutStream(self, 'x'); + TrioWriteNumber(self, (trio_uintmax_t)ch, + FLAGS_UNSIGNED | FLAGS_NILPADDING, + 2, 2, BASE_HEX); + break; + } + } + else if (ch == CHAR_BACKSLASH) + { + self->OutStream(self, CHAR_BACKSLASH); + self->OutStream(self, CHAR_BACKSLASH); + } + else + { + self->OutStream(self, ch); + } + } + else + { + self->OutStream(self, ch); + } +} + +/************************************************************************* + * TrioWriteString + * + * Description: + * Output a string + */ +TRIO_PRIVATE void +TrioWriteString +TRIO_ARGS5((self, string, flags, width, precision), + trio_class_t *self, + TRIO_CONST char *string, + trio_flags_t flags, + int width, + int precision) +{ + int length; + int ch; + + assert(VALID(self)); + assert(VALID(self->OutStream)); + + if (string == NULL) + { + string = internalNullString; + length = sizeof(internalNullString) - 1; + /* Disable quoting for the null pointer */ + flags &= (~FLAGS_QUOTE); + width = 0; + } + else + { + length = trio_length(string); + } + if ((NO_PRECISION != precision) && + (precision < length)) + { + length = precision; + } + width -= length; + + if (flags & FLAGS_QUOTE) + self->OutStream(self, CHAR_QUOTE); + + if (! (flags & FLAGS_LEFTADJUST)) + { + while (width-- > 0) + self->OutStream(self, CHAR_ADJUST); + } + + while (length-- > 0) + { + /* The ctype parameters must be an unsigned char (or EOF) */ + ch = (int)((unsigned char)(*string++)); + TrioWriteStringCharacter(self, ch, flags); + } + + if (flags & FLAGS_LEFTADJUST) + { + while (width-- > 0) + self->OutStream(self, CHAR_ADJUST); + } + if (flags & FLAGS_QUOTE) + self->OutStream(self, CHAR_QUOTE); +} + +/************************************************************************* + * TrioWriteWideStringCharacter + * + * Description: + * Output a wide string as a multi-byte sequence + */ +#if TRIO_WIDECHAR +TRIO_PRIVATE int +TrioWriteWideStringCharacter +TRIO_ARGS4((self, wch, flags, width), + trio_class_t *self, + trio_wchar_t wch, + trio_flags_t flags, + int width) +{ + int size; + int i; + int ch; + char *string; + char buffer[MB_LEN_MAX + 1]; + + if (width == NO_WIDTH) + width = sizeof(buffer); + + size = wctomb(buffer, wch); + if ((size <= 0) || (size > width) || (buffer[0] == NIL)) + return 0; + + string = buffer; + i = size; + while ((width >= i) && (width-- > 0) && (i-- > 0)) + { + /* The ctype parameters must be an unsigned char (or EOF) */ + ch = (int)((unsigned char)(*string++)); + TrioWriteStringCharacter(self, ch, flags); + } + return size; +} +#endif /* TRIO_WIDECHAR */ + +/************************************************************************* + * TrioWriteWideString + * + * Description: + * Output a wide character string as a multi-byte string + */ +#if TRIO_WIDECHAR +TRIO_PRIVATE void +TrioWriteWideString +TRIO_ARGS5((self, wstring, flags, width, precision), + trio_class_t *self, + TRIO_CONST trio_wchar_t *wstring, + trio_flags_t flags, + int width, + int precision) +{ + int length; + int size; + + assert(VALID(self)); + assert(VALID(self->OutStream)); + +#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE) + (void)mblen(NULL, 0); +#endif + + if (wstring == NULL) + { + TrioWriteString(self, NULL, flags, width, precision); + return; + } + + if (NO_PRECISION == precision) + { + length = INT_MAX; + } + else + { + length = precision; + width -= length; + } + + if (flags & FLAGS_QUOTE) + self->OutStream(self, CHAR_QUOTE); + + if (! (flags & FLAGS_LEFTADJUST)) + { + while (width-- > 0) + self->OutStream(self, CHAR_ADJUST); + } + + while (length > 0) + { + size = TrioWriteWideStringCharacter(self, *wstring++, flags, length); + if (size == 0) + break; /* while */ + length -= size; + } + + if (flags & FLAGS_LEFTADJUST) + { + while (width-- > 0) + self->OutStream(self, CHAR_ADJUST); + } + if (flags & FLAGS_QUOTE) + self->OutStream(self, CHAR_QUOTE); +} +#endif /* TRIO_WIDECHAR */ + +/************************************************************************* + * TrioWriteDouble + * + * http://wwwold.dkuug.dk/JTC1/SC22/WG14/www/docs/dr_211.htm + * + * "5.2.4.2.2 paragraph #4 + * + * The accuracy [...] is implementation defined, as is the accuracy + * of the conversion between floating-point internal representations + * and string representations performed by the libray routine in + * " + */ +/* FIXME: handle all instances of constant long-double number (L) + * and *l() math functions. + */ +TRIO_PRIVATE void +TrioWriteDouble +TRIO_ARGS6((self, number, flags, width, precision, base), + trio_class_t *self, + trio_long_double_t number, + trio_flags_t flags, + int width, + int precision, + int base) +{ + trio_long_double_t integerNumber; + trio_long_double_t fractionNumber; + trio_long_double_t workNumber; + int integerDigits; + int fractionDigits; + int exponentDigits; + int baseDigits; + int integerThreshold; + int fractionThreshold; + int expectedWidth; + int exponent = 0; + unsigned int uExponent = 0; + int exponentBase; + trio_long_double_t dblBase; + trio_long_double_t dblIntegerBase; + trio_long_double_t dblFractionBase; + trio_long_double_t integerAdjust; + trio_long_double_t fractionAdjust; + BOOLEAN_T isNegative; + BOOLEAN_T isExponentNegative = FALSE; + BOOLEAN_T requireTwoDigitExponent; + BOOLEAN_T isHex; + TRIO_CONST char *digits; + char *groupingPointer; + int i; + int index; + BOOLEAN_T hasOnlyZeroes; + int zeroes = 0; + register int trailingZeroes; + BOOLEAN_T keepTrailingZeroes; + BOOLEAN_T keepDecimalPoint; + trio_long_double_t epsilon; + + assert(VALID(self)); + assert(VALID(self->OutStream)); + assert(((base >= MIN_BASE) && (base <= MAX_BASE)) || (base == NO_BASE)); + + /* Determine sign and look for special quantities */ + switch (trio_fpclassify_and_signbit(number, &isNegative)) + { + case TRIO_FP_NAN: + TrioWriteString(self, + (flags & FLAGS_UPPER) + ? NAN_UPPER + : NAN_LOWER, + flags, width, precision); + return; + + case TRIO_FP_INFINITE: + if (isNegative) + { + /* Negative infinity */ + TrioWriteString(self, + (flags & FLAGS_UPPER) + ? "-" INFINITE_UPPER + : "-" INFINITE_LOWER, + flags, width, precision); + return; + } + else + { + /* Positive infinity */ + TrioWriteString(self, + (flags & FLAGS_UPPER) + ? INFINITE_UPPER + : INFINITE_LOWER, + flags, width, precision); + return; + } + + default: + /* Finitude */ + break; + } + + /* Normal numbers */ + if (flags & FLAGS_LONGDOUBLE) + { + baseDigits = (base == 10) + ? LDBL_DIG + : (int)floor(LDBL_MANT_DIG / TrioLogarithmBase(base)); + epsilon = LDBL_EPSILON; + } + else if (flags & FLAGS_SHORT) + { + baseDigits = (base == BASE_DECIMAL) + ? FLT_DIG + : (int)floor(FLT_MANT_DIG / TrioLogarithmBase(base)); + epsilon = FLT_EPSILON; + } + else + { + baseDigits = (base == BASE_DECIMAL) + ? DBL_DIG + : (int)floor(DBL_MANT_DIG / TrioLogarithmBase(base)); + epsilon = DBL_EPSILON; + } + + digits = (flags & FLAGS_UPPER) ? internalDigitsUpper : internalDigitsLower; + isHex = (base == BASE_HEX); + if (base == NO_BASE) + base = BASE_DECIMAL; + dblBase = (trio_long_double_t)base; + keepTrailingZeroes = !( (flags & FLAGS_ROUNDING) || + ( (flags & FLAGS_FLOAT_G) && + !(flags & FLAGS_ALTERNATIVE) ) ); + + if (flags & FLAGS_ROUNDING) + precision = baseDigits; + + if (precision == NO_PRECISION) + { + if (isHex) + { + keepTrailingZeroes = FALSE; + precision = FLT_MANT_DIG; + } + else + { + precision = FLT_DIG; + } + } + + if (isNegative) + number = -number; + + if (isHex) + flags |= FLAGS_FLOAT_E; + + if (flags & FLAGS_FLOAT_G) + { + if (precision == 0) + precision = 1; + + if ((number < 1.0E-4) || (number > powl(base, + (trio_long_double_t)precision))) + { + /* Use scientific notation */ + flags |= FLAGS_FLOAT_E; + } + else if (number < 1.0) + { + /* + * Use normal notation. If the integer part of the number is + * zero, then adjust the precision to include leading fractional + * zeros. + */ + workNumber = TrioLogarithm(number, base); + workNumber = TRIO_FABS(workNumber); + if (workNumber - floorl(workNumber) < 0.001) + workNumber--; + zeroes = (int)floorl(workNumber); + } + } + + if (flags & FLAGS_FLOAT_E) + { + /* Scale the number */ + workNumber = TrioLogarithm(number, base); + if (trio_isinf(workNumber) == -1) + { + exponent = 0; + /* Undo setting */ + if (flags & FLAGS_FLOAT_G) + flags &= ~FLAGS_FLOAT_E; + } + else + { + exponent = (int)floorl(workNumber); + number /= powl(dblBase, (trio_long_double_t)exponent); + isExponentNegative = (exponent < 0); + uExponent = (isExponentNegative) ? -exponent : exponent; + if (isHex) + uExponent *= 4; /* log16(2) */ + /* No thousand separators */ + flags &= ~FLAGS_QUOTE; + } + } + + integerNumber = floorl(number); + fractionNumber = number - integerNumber; + + /* + * Truncated number. + * + * Precision is number of significant digits for FLOAT_G + * and number of fractional digits for others. + */ + integerDigits = (integerNumber > epsilon) + ? 1 + (int)TrioLogarithm(integerNumber, base) + : 1; + fractionDigits = ((flags & FLAGS_FLOAT_G) && (zeroes == 0)) + ? precision - integerDigits + : zeroes + precision; + + dblFractionBase = TrioPower(base, fractionDigits); + + workNumber = number + 0.5 / dblFractionBase; + if (floorl(number) != floorl(workNumber)) + { + if (flags & FLAGS_FLOAT_E) + { + /* Adjust if number was rounded up one digit (ie. 0.99 to 1.00) */ + exponent++; + isExponentNegative = (exponent < 0); + uExponent = (isExponentNegative) ? -exponent : exponent; + if (isHex) + uExponent *= 4; /* log16(2) */ + workNumber = (number + 0.5 / dblFractionBase) / dblBase; + integerNumber = floorl(workNumber); + fractionNumber = workNumber - integerNumber; + } + else + { + /* Adjust if number was rounded up one digit (ie. 99 to 100) */ + integerNumber = floorl(number + 0.5); + fractionNumber = 0.0; + integerDigits = (integerNumber > epsilon) + ? 1 + (int)TrioLogarithm(integerNumber, base) + : 1; + } + } + + /* Estimate accuracy */ + integerAdjust = fractionAdjust = 0.5; + if (flags & FLAGS_ROUNDING) + { + if (integerDigits > baseDigits) + { + integerThreshold = baseDigits; + fractionDigits = 0; + dblFractionBase = 1.0; + fractionThreshold = 0; + precision = 0; /* Disable decimal-point */ + integerAdjust = TrioPower(base, integerDigits - integerThreshold - 1); + fractionAdjust = 0.0; + } + else + { + integerThreshold = integerDigits; + fractionThreshold = fractionDigits - integerThreshold; + fractionAdjust = 1.0; + } + } + else + { + integerThreshold = INT_MAX; + fractionThreshold = INT_MAX; + } + + /* + * Calculate expected width. + * sign + integer part + thousands separators + decimal point + * + fraction + exponent + */ + fractionAdjust /= dblFractionBase; + hasOnlyZeroes = (floorl((fractionNumber + fractionAdjust) * dblFractionBase) < epsilon); + keepDecimalPoint = ( (flags & FLAGS_ALTERNATIVE) || + !((precision == 0) || + (!keepTrailingZeroes && hasOnlyZeroes)) ); + if (flags & FLAGS_FLOAT_E) + { + exponentDigits = (uExponent == 0) + ? 1 + : (int)ceil(TrioLogarithm((double)(uExponent + 1), + (isHex) ? 10.0 : base)); + } + else + exponentDigits = 0; + requireTwoDigitExponent = ((base == BASE_DECIMAL) && (exponentDigits == 1)); + + expectedWidth = integerDigits + fractionDigits + + (keepDecimalPoint + ? internalDecimalPointLength + : 0) + + ((flags & FLAGS_QUOTE) + ? TrioCalcThousandSeparatorLength(integerDigits) + : 0); + if (isNegative || (flags & FLAGS_SHOWSIGN) || (flags & FLAGS_SPACE)) + expectedWidth += sizeof("-") - 1; + if (exponentDigits > 0) + expectedWidth += exponentDigits + + ((requireTwoDigitExponent ? sizeof("E+0") : sizeof("E+")) - 1); + if (isHex) + expectedWidth += sizeof("0X") - 1; + + /* Output prefixing */ + if (flags & FLAGS_NILPADDING) + { + /* Leading zeros must be after sign */ + if (isNegative) + self->OutStream(self, '-'); + else if (flags & FLAGS_SHOWSIGN) + self->OutStream(self, '+'); + else if (flags & FLAGS_SPACE) + self->OutStream(self, ' '); + if (isHex) + { + self->OutStream(self, '0'); + self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x'); + } + if (!(flags & FLAGS_LEFTADJUST)) + { + for (i = expectedWidth; i < width; i++) + { + self->OutStream(self, '0'); + } + } + } + else + { + /* Leading spaces must be before sign */ + if (!(flags & FLAGS_LEFTADJUST)) + { + for (i = expectedWidth; i < width; i++) + { + self->OutStream(self, CHAR_ADJUST); + } + } + if (isNegative) + self->OutStream(self, '-'); + else if (flags & FLAGS_SHOWSIGN) + self->OutStream(self, '+'); + else if (flags & FLAGS_SPACE) + self->OutStream(self, ' '); + if (isHex) + { + self->OutStream(self, '0'); + self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x'); + } + } + + /* Output the integer part and thousand separators */ + dblIntegerBase = 1.0 / TrioPower(base, integerDigits - 1); + for (i = 0; i < integerDigits; i++) + { + workNumber = floorl(((integerNumber + integerAdjust) * dblIntegerBase)); + if (i > integerThreshold) + { + /* Beyond accuracy */ + self->OutStream(self, digits[0]); + } + else + { + self->OutStream(self, digits[(int)fmodl(workNumber, dblBase)]); + } + dblIntegerBase *= dblBase; + + if (((flags & (FLAGS_FLOAT_E | FLAGS_QUOTE)) == FLAGS_QUOTE) + && TrioFollowedBySeparator(integerDigits - i)) + { + for (groupingPointer = internalThousandSeparator; + *groupingPointer != NIL; + groupingPointer++) + { + self->OutStream(self, *groupingPointer); + } + } + } + + /* Insert decimal point and build the fraction part */ + trailingZeroes = 0; + + if (keepDecimalPoint) + { + if (internalDecimalPoint) + { + self->OutStream(self, internalDecimalPoint); + } + else + { + for (i = 0; i < internalDecimalPointLength; i++) + { + self->OutStream(self, internalDecimalPointString[i]); + } + } + } + + for (i = 0; i < fractionDigits; i++) + { + if ((integerDigits > integerThreshold) || (i > fractionThreshold)) + { + /* Beyond accuracy */ + trailingZeroes++; + } + else + { + fractionNumber *= dblBase; + fractionAdjust *= dblBase; + workNumber = floorl(fractionNumber + fractionAdjust); + fractionNumber -= workNumber; + index = (int)fmodl(workNumber, dblBase); + if (index == 0) + { + trailingZeroes++; + } + else + { + while (trailingZeroes > 0) + { + /* Not trailing zeroes after all */ + self->OutStream(self, digits[0]); + trailingZeroes--; + } + self->OutStream(self, digits[index]); + } + } + } + + if (keepTrailingZeroes) + { + while (trailingZeroes > 0) + { + self->OutStream(self, digits[0]); + trailingZeroes--; + } + } + + /* Output exponent */ + if (exponentDigits > 0) + { + self->OutStream(self, + isHex + ? ((flags & FLAGS_UPPER) ? 'P' : 'p') + : ((flags & FLAGS_UPPER) ? 'E' : 'e')); + self->OutStream(self, (isExponentNegative) ? '-' : '+'); + + /* The exponent must contain at least two digits */ + if (requireTwoDigitExponent) + self->OutStream(self, '0'); + + if (isHex) + base = 10.0; + exponentBase = (int)TrioPower(base, exponentDigits - 1); + for (i = 0; i < exponentDigits; i++) + { + self->OutStream(self, digits[(uExponent / exponentBase) % base]); + exponentBase /= base; + } + } + /* Output trailing spaces */ + if (flags & FLAGS_LEFTADJUST) + { + for (i = expectedWidth; i < width; i++) + { + self->OutStream(self, CHAR_ADJUST); + } + } +} + +/************************************************************************* + * TrioFormatProcess + * + * Description: + * This is the main engine for formatting output + */ +TRIO_PRIVATE int +TrioFormatProcess +TRIO_ARGS3((data, format, parameters), + trio_class_t *data, + TRIO_CONST char *format, + trio_parameter_t *parameters) +{ +#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE) + int charlen; +#endif + int i; + TRIO_CONST char *string; + trio_pointer_t pointer; + trio_flags_t flags; + int width; + int precision; + int base; + int index; + + index = 0; + i = 0; +#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE) + (void)mblen(NULL, 0); +#endif + + while (format[index]) + { +#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE) + if (! isascii(format[index])) + { + charlen = mblen(&format[index], MB_LEN_MAX); + /* + * Only valid multibyte characters are handled here. Invalid + * multibyte characters (charlen == -1) are handled as normal + * characters. + */ + if (charlen != -1) + { + while (charlen-- > 0) + { + data->OutStream(data, format[index++]); + } + continue; /* while characters left in formatting string */ + } + } +#endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */ + if (CHAR_IDENTIFIER == format[index]) + { + if (CHAR_IDENTIFIER == format[index + 1]) + { + data->OutStream(data, CHAR_IDENTIFIER); + index += 2; + } + else + { + /* Skip the parameter entries */ + while (parameters[i].type == FORMAT_PARAMETER) + i++; + + flags = parameters[i].flags; + + /* Find width */ + width = parameters[i].width; + if (flags & FLAGS_WIDTH_PARAMETER) + { + /* Get width from parameter list */ + width = (int)parameters[width].data.number.as_signed; + if (width < 0) + { + /* + * A negative width is the same as the - flag and + * a positive width. + */ + flags |= FLAGS_LEFTADJUST; + flags &= ~FLAGS_NILPADDING; + width = -width; + } + } + + /* Find precision */ + if (flags & FLAGS_PRECISION) + { + precision = parameters[i].precision; + if (flags & FLAGS_PRECISION_PARAMETER) + { + /* Get precision from parameter list */ + precision = (int)parameters[precision].data.number.as_signed; + if (precision < 0) + { + /* + * A negative precision is the same as no + * precision + */ + precision = NO_PRECISION; + } + } + } + else + { + precision = NO_PRECISION; + } + + /* Find base */ + base = parameters[i].base; + if (flags & FLAGS_BASE_PARAMETER) + { + /* Get base from parameter list */ + base = (int)parameters[base].data.number.as_signed; + } + + switch (parameters[i].type) + { + case FORMAT_CHAR: + if (flags & FLAGS_QUOTE) + data->OutStream(data, CHAR_QUOTE); + if (! (flags & FLAGS_LEFTADJUST)) + { + while (--width > 0) + data->OutStream(data, CHAR_ADJUST); + } +#if TRIO_WIDECHAR + if (flags & FLAGS_WIDECHAR) + { + TrioWriteWideStringCharacter(data, + (trio_wchar_t)parameters[i].data.number.as_signed, + flags, + NO_WIDTH); + } + else +#endif + { + TrioWriteStringCharacter(data, + (int)parameters[i].data.number.as_signed, + flags); + } + + if (flags & FLAGS_LEFTADJUST) + { + while(--width > 0) + data->OutStream(data, CHAR_ADJUST); + } + if (flags & FLAGS_QUOTE) + data->OutStream(data, CHAR_QUOTE); + + break; /* FORMAT_CHAR */ + + case FORMAT_INT: + TrioWriteNumber(data, + parameters[i].data.number.as_unsigned, + flags, + width, + precision, + base); + + break; /* FORMAT_INT */ + + case FORMAT_DOUBLE: + TrioWriteDouble(data, + parameters[i].data.longdoubleNumber, + flags, + width, + precision, + base); + break; /* FORMAT_DOUBLE */ + + case FORMAT_STRING: +#if TRIO_WIDECHAR + if (flags & FLAGS_WIDECHAR) + { + TrioWriteWideString(data, + parameters[i].data.wstring, + flags, + width, + precision); + } + else +#endif + { + TrioWriteString(data, + parameters[i].data.string, + flags, + width, + precision); + } + break; /* FORMAT_STRING */ + + case FORMAT_POINTER: + { + trio_reference_t reference; + + reference.data = data; + reference.parameter = ¶meters[i]; + trio_print_pointer(&reference, parameters[i].data.pointer); + } + break; /* FORMAT_POINTER */ + + case FORMAT_COUNT: + pointer = parameters[i].data.pointer; + if (NULL != pointer) + { + /* + * C99 paragraph 7.19.6.1.8 says "the number of + * characters written to the output stream so far by + * this call", which is data->committed + */ +#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER) + if (flags & FLAGS_SIZE_T) + *(size_t *)pointer = (size_t)data->committed; + else +#endif +#if defined(QUALIFIER_PTRDIFF_T) + if (flags & FLAGS_PTRDIFF_T) + *(ptrdiff_t *)pointer = (ptrdiff_t)data->committed; + else +#endif +#if defined(QUALIFIER_INTMAX_T) + if (flags & FLAGS_INTMAX_T) + *(trio_intmax_t *)pointer = (trio_intmax_t)data->committed; + else +#endif + if (flags & FLAGS_QUAD) + { + *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)data->committed; + } + else if (flags & FLAGS_LONG) + { + *(long int *)pointer = (long int)data->committed; + } + else if (flags & FLAGS_SHORT) + { + *(short int *)pointer = (short int)data->committed; + } + else + { + *(int *)pointer = (int)data->committed; + } + } + break; /* FORMAT_COUNT */ + + case FORMAT_PARAMETER: + break; /* FORMAT_PARAMETER */ + +#if defined(FORMAT_ERRNO) + case FORMAT_ERRNO: + string = trio_error(parameters[i].data.errorNumber); + if (string) + { + TrioWriteString(data, + string, + flags, + width, + precision); + } + else + { + data->OutStream(data, '#'); + TrioWriteNumber(data, + (trio_uintmax_t)parameters[i].data.errorNumber, + flags, + width, + precision, + BASE_DECIMAL); + } + break; /* FORMAT_ERRNO */ +#endif /* defined(FORMAT_ERRNO) */ + +#if defined(FORMAT_USER_DEFINED) + case FORMAT_USER_DEFINED: + { + trio_reference_t reference; + trio_userdef_t *def = NULL; + + if (parameters[i].user_name[0] == NIL) + { + /* Use handle */ + if ((i > 0) || + (parameters[i - 1].type == FORMAT_PARAMETER)) + def = (trio_userdef_t *)parameters[i - 1].data.pointer; + } + else + { + /* Look up namespace */ + def = TrioFindNamespace(parameters[i].user_name, NULL); + } + if (def) { + reference.data = data; + reference.parameter = ¶meters[i]; + def->callback(&reference); + } + } + break; +#endif /* defined(FORMAT_USER_DEFINED) */ + + default: + break; + } /* switch parameter type */ + + /* Prepare for next */ + index = parameters[i].indexAfterSpecifier; + i++; + } + } + else /* not identifier */ + { + data->OutStream(data, format[index++]); + } + } + return data->processed; +} + +/************************************************************************* + * TrioFormatRef + */ +TRIO_PRIVATE int +TrioFormatRef +TRIO_ARGS4((reference, format, arglist, argarray), + trio_reference_t *reference, + TRIO_CONST char *format, + va_list *arglist, + trio_pointer_t *argarray) +{ + int status; + trio_parameter_t parameters[MAX_PARAMETERS]; + + status = TrioParse(TYPE_PRINT, format, parameters, arglist, argarray); + if (status < 0) + return status; + + status = TrioFormatProcess(reference->data, format, parameters); + if (reference->data->error != 0) + { + status = reference->data->error; + } + return status; +} + +/************************************************************************* + * TrioFormat + */ +TRIO_PRIVATE int +TrioFormat +TRIO_ARGS6((destination, destinationSize, OutStream, format, arglist, argarray), + trio_pointer_t destination, + size_t destinationSize, + void (*OutStream) TRIO_PROTO((trio_class_t *, int)), + TRIO_CONST char *format, + va_list *arglist, + trio_pointer_t *argarray) +{ + int status; + trio_class_t data; + trio_parameter_t parameters[MAX_PARAMETERS]; + + assert(VALID(OutStream)); + assert(VALID(format)); + + memset(&data, 0, sizeof(data)); + data.OutStream = OutStream; + data.location = destination; + data.max = destinationSize; + data.error = 0; + +#if defined(USE_LOCALE) + if (NULL == internalLocaleValues) + { + TrioSetLocale(); + } +#endif + + status = TrioParse(TYPE_PRINT, format, parameters, arglist, argarray); + if (status < 0) + return status; + + status = TrioFormatProcess(&data, format, parameters); + if (data.error != 0) + { + status = data.error; + } + return status; +} + +/************************************************************************* + * TrioOutStreamFile + */ +TRIO_PRIVATE void +TrioOutStreamFile +TRIO_ARGS2((self, output), + trio_class_t *self, + int output) +{ + FILE *file; + + assert(VALID(self)); + assert(VALID(self->location)); + + file = (FILE *)self->location; + self->processed++; + if (fputc(output, file) == EOF) + { + self->error = TRIO_ERROR_RETURN(TRIO_EOF, 0); + } + else + { + self->committed++; + } +} + +/************************************************************************* + * TrioOutStreamFileDescriptor + */ +TRIO_PRIVATE void +TrioOutStreamFileDescriptor +TRIO_ARGS2((self, output), + trio_class_t *self, + int output) +{ + int fd; + char ch; + + assert(VALID(self)); + + fd = *((int *)self->location); + ch = (char)output; + self->processed++; + if (write(fd, &ch, sizeof(char)) == -1) + { + self->error = TRIO_ERROR_RETURN(TRIO_ERRNO, 0); + } + else + { + self->committed++; + } +} + +/************************************************************************* + * TrioOutStreamCustom + */ +TRIO_PRIVATE void +TrioOutStreamCustom +TRIO_ARGS2((self, output), + trio_class_t *self, + int output) +{ + int status; + trio_custom_t *data; + + assert(VALID(self)); + assert(VALID(self->location)); + + data = (trio_custom_t *)self->location; + if (data->stream.out) + { + status = (data->stream.out)(data->closure, output); + if (status >= 0) + { + self->committed++; + } + else + { + if (self->error == 0) + { + self->error = TRIO_ERROR_RETURN(TRIO_ECUSTOM, -status); + } + } + } + self->processed++; +} + +/************************************************************************* + * TrioOutStreamString + */ +TRIO_PRIVATE void +TrioOutStreamString +TRIO_ARGS2((self, output), + trio_class_t *self, + int output) +{ + char **buffer; + + assert(VALID(self)); + assert(VALID(self->location)); + + buffer = (char **)self->location; + **buffer = (char)output; + (*buffer)++; + self->processed++; + self->committed++; +} + +/************************************************************************* + * TrioOutStreamStringMax + */ +TRIO_PRIVATE void +TrioOutStreamStringMax +TRIO_ARGS2((self, output), + trio_class_t *self, + int output) +{ + char **buffer; + + assert(VALID(self)); + assert(VALID(self->location)); + + buffer = (char **)self->location; + + if (self->processed < self->max) + { + **buffer = (char)output; + (*buffer)++; + self->committed++; + } + self->processed++; +} + +/************************************************************************* + * TrioOutStreamStringDynamic + */ +TRIO_PRIVATE void +TrioOutStreamStringDynamic +TRIO_ARGS2((self, output), + trio_class_t *self, + int output) +{ + assert(VALID(self)); + assert(VALID(self->location)); + + if (self->error == 0) + { + trio_xstring_append_char((trio_string_t *)self->location, + (char)output); + self->committed++; + } + /* The processed variable must always be increased */ + self->processed++; +} + +/************************************************************************* + * + * Formatted printing functions + * + ************************************************************************/ + +#if defined(TRIO_DOCUMENTATION) +# include "doc/doc_printf.h" +#endif +/** @addtogroup Printf + @{ +*/ + +/************************************************************************* + * printf + */ + +/** + Print to standard output stream. + + @param format Formatting string. + @param ... Arguments. + @return Number of printed characters. + */ +TRIO_PUBLIC int +trio_printf +TRIO_VARGS2((format, va_alist), + TRIO_CONST char *format, + TRIO_VA_DECL) +{ + int status; + va_list args; + + assert(VALID(format)); + + TRIO_VA_START(args, format); + status = TrioFormat(stdout, 0, TrioOutStreamFile, format, &args, NULL); + TRIO_VA_END(args); + return status; +} + +/** + Print to standard output stream. + + @param format Formatting string. + @param args Arguments. + @return Number of printed characters. + */ +TRIO_PUBLIC int +trio_vprintf +TRIO_ARGS2((format, args), + TRIO_CONST char *format, + va_list args) +{ + assert(VALID(format)); + + return TrioFormat(stdout, 0, TrioOutStreamFile, format, &args, NULL); +} + +/** + Print to standard output stream. + + @param format Formatting string. + @param args Arguments. + @return Number of printed characters. + */ +TRIO_PUBLIC int +trio_printfv +TRIO_ARGS2((format, args), + TRIO_CONST char *format, + trio_pointer_t * args) +{ + assert(VALID(format)); + + return TrioFormat(stdout, 0, TrioOutStreamFile, format, NULL, args); +} + +/************************************************************************* + * fprintf + */ + +/** + Print to file. + + @param file File pointer. + @param format Formatting string. + @param ... Arguments. + @return Number of printed characters. + */ +TRIO_PUBLIC int +trio_fprintf +TRIO_VARGS3((file, format, va_alist), + FILE *file, + TRIO_CONST char *format, + TRIO_VA_DECL) +{ + int status; + va_list args; + + assert(VALID(file)); + assert(VALID(format)); + + TRIO_VA_START(args, format); + status = TrioFormat(file, 0, TrioOutStreamFile, format, &args, NULL); + TRIO_VA_END(args); + return status; +} + +/** + Print to file. + + @param file File pointer. + @param format Formatting string. + @param args Arguments. + @return Number of printed characters. + */ +TRIO_PUBLIC int +trio_vfprintf +TRIO_ARGS3((file, format, args), + FILE *file, + TRIO_CONST char *format, + va_list args) +{ + assert(VALID(file)); + assert(VALID(format)); + + return TrioFormat(file, 0, TrioOutStreamFile, format, &args, NULL); +} + +/** + Print to file. + + @param file File pointer. + @param format Formatting string. + @param args Arguments. + @return Number of printed characters. + */ +TRIO_PUBLIC int +trio_fprintfv +TRIO_ARGS3((file, format, args), + FILE *file, + TRIO_CONST char *format, + trio_pointer_t * args) +{ + assert(VALID(file)); + assert(VALID(format)); + + return TrioFormat(file, 0, TrioOutStreamFile, format, NULL, args); +} + +/************************************************************************* + * dprintf + */ + +/** + Print to file descriptor. + + @param fd File descriptor. + @param format Formatting string. + @param ... Arguments. + @return Number of printed characters. + */ +TRIO_PUBLIC int +trio_dprintf +TRIO_VARGS3((fd, format, va_alist), + int fd, + TRIO_CONST char *format, + TRIO_VA_DECL) +{ + int status; + va_list args; + + assert(VALID(format)); + + TRIO_VA_START(args, format); + status = TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, &args, NULL); + TRIO_VA_END(args); + return status; +} + +/** + Print to file descriptor. + + @param fd File descriptor. + @param format Formatting string. + @param args Arguments. + @return Number of printed characters. + */ +TRIO_PUBLIC int +trio_vdprintf +TRIO_ARGS3((fd, format, args), + int fd, + TRIO_CONST char *format, + va_list args) +{ + assert(VALID(format)); + + return TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, &args, NULL); +} + +/** + Print to file descriptor. + + @param fd File descriptor. + @param format Formatting string. + @param args Arguments. + @return Number of printed characters. + */ +TRIO_PUBLIC int +trio_dprintfv +TRIO_ARGS3((fd, format, args), + int fd, + TRIO_CONST char *format, + trio_pointer_t *args) +{ + assert(VALID(format)); + + return TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, NULL, args); +} + +/************************************************************************* + * cprintf + */ +TRIO_PUBLIC int +trio_cprintf +TRIO_VARGS4((stream, closure, format, va_alist), + trio_outstream_t stream, + trio_pointer_t closure, + TRIO_CONST char *format, + TRIO_VA_DECL) +{ + int status; + va_list args; + trio_custom_t data; + + assert(VALID(stream)); + assert(VALID(format)); + + TRIO_VA_START(args, format); + data.stream.out = stream; + data.closure = closure; + status = TrioFormat(&data, 0, TrioOutStreamCustom, format, &args, NULL); + TRIO_VA_END(args); + return status; +} + +TRIO_PUBLIC int +trio_vcprintf +TRIO_ARGS4((stream, closure, format, args), + trio_outstream_t stream, + trio_pointer_t closure, + TRIO_CONST char *format, + va_list args) +{ + trio_custom_t data; + + assert(VALID(stream)); + assert(VALID(format)); + + data.stream.out = stream; + data.closure = closure; + return TrioFormat(&data, 0, TrioOutStreamCustom, format, &args, NULL); +} + +TRIO_PUBLIC int +trio_cprintfv +TRIO_ARGS4((stream, closure, format, args), + trio_outstream_t stream, + trio_pointer_t closure, + TRIO_CONST char *format, + void **args) +{ + trio_custom_t data; + + assert(VALID(stream)); + assert(VALID(format)); + + data.stream.out = stream; + data.closure = closure; + return TrioFormat(&data, 0, TrioOutStreamCustom, format, NULL, args); +} + +/************************************************************************* + * sprintf + */ + +/** + Print to string. + + @param buffer Output string. + @param format Formatting string. + @param ... Arguments. + @return Number of printed characters. + */ +TRIO_PUBLIC int +trio_sprintf +TRIO_VARGS3((buffer, format, va_alist), + char *buffer, + TRIO_CONST char *format, + TRIO_VA_DECL) +{ + int status; + va_list args; + + assert(VALID(buffer)); + assert(VALID(format)); + + TRIO_VA_START(args, format); + status = TrioFormat(&buffer, 0, TrioOutStreamString, format, &args, NULL); + *buffer = NIL; /* Terminate with NIL character */ + TRIO_VA_END(args); + return status; +} + +/** + Print to string. + + @param buffer Output string. + @param format Formatting string. + @param args Arguments. + @return Number of printed characters. + */ +TRIO_PUBLIC int +trio_vsprintf +TRIO_ARGS3((buffer, format, args), + char *buffer, + TRIO_CONST char *format, + va_list args) +{ + int status; + + assert(VALID(buffer)); + assert(VALID(format)); + + status = TrioFormat(&buffer, 0, TrioOutStreamString, format, &args, NULL); + *buffer = NIL; + return status; +} + +/** + Print to string. + + @param buffer Output string. + @param format Formatting string. + @param args Arguments. + @return Number of printed characters. + */ +TRIO_PUBLIC int +trio_sprintfv +TRIO_ARGS3((buffer, format, args), + char *buffer, + TRIO_CONST char *format, + trio_pointer_t *args) +{ + int status; + + assert(VALID(buffer)); + assert(VALID(format)); + + status = TrioFormat(&buffer, 0, TrioOutStreamString, format, NULL, args); + *buffer = NIL; + return status; +} + +/************************************************************************* + * snprintf + */ + +/** + Print at most @p max characters to string. + + @param buffer Output string. + @param max Maximum number of characters to print. + @param format Formatting string. + @param ... Arguments. + @return Number of printed characters. + */ +TRIO_PUBLIC int +trio_snprintf +TRIO_VARGS4((buffer, max, format, va_alist), + char *buffer, + size_t max, + TRIO_CONST char *format, + TRIO_VA_DECL) +{ + int status; + va_list args; + + assert(VALID(buffer)); + assert(VALID(format)); + + TRIO_VA_START(args, format); + status = TrioFormat(&buffer, max > 0 ? max - 1 : 0, + TrioOutStreamStringMax, format, &args, NULL); + if (max > 0) + *buffer = NIL; + TRIO_VA_END(args); + return status; +} + +/** + Print at most @p max characters to string. + + @param buffer Output string. + @param max Maximum number of characters to print. + @param format Formatting string. + @param args Arguments. + @return Number of printed characters. + */ +TRIO_PUBLIC int +trio_vsnprintf +TRIO_ARGS4((buffer, max, format, args), + char *buffer, + size_t max, + TRIO_CONST char *format, + va_list args) +{ + int status; + + assert(VALID(buffer)); + assert(VALID(format)); + + status = TrioFormat(&buffer, max > 0 ? max - 1 : 0, + TrioOutStreamStringMax, format, &args, NULL); + if (max > 0) + *buffer = NIL; + return status; +} + +/** + Print at most @p max characters to string. + + @param buffer Output string. + @param max Maximum number of characters to print. + @param format Formatting string. + @param args Arguments. + @return Number of printed characters. + */ +TRIO_PUBLIC int +trio_snprintfv +TRIO_ARGS4((buffer, max, format, args), + char *buffer, + size_t max, + TRIO_CONST char *format, + trio_pointer_t *args) +{ + int status; + + assert(VALID(buffer)); + assert(VALID(format)); + + status = TrioFormat(&buffer, max > 0 ? max - 1 : 0, + TrioOutStreamStringMax, format, NULL, args); + if (max > 0) + *buffer = NIL; + return status; +} + +/************************************************************************* + * snprintfcat + * Appends the new string to the buffer string overwriting the '\0' + * character at the end of buffer. + */ +TRIO_PUBLIC int +trio_snprintfcat +TRIO_VARGS4((buffer, max, format, va_alist), + char *buffer, + size_t max, + TRIO_CONST char *format, + TRIO_VA_DECL) +{ + int status; + va_list args; + size_t buf_len; + + TRIO_VA_START(args, format); + + assert(VALID(buffer)); + assert(VALID(format)); + + buf_len = trio_length(buffer); + buffer = &buffer[buf_len]; + + status = TrioFormat(&buffer, max - 1 - buf_len, + TrioOutStreamStringMax, format, &args, NULL); + TRIO_VA_END(args); + *buffer = NIL; + return status; +} + +TRIO_PUBLIC int +trio_vsnprintfcat +TRIO_ARGS4((buffer, max, format, args), + char *buffer, + size_t max, + TRIO_CONST char *format, + va_list args) +{ + int status; + size_t buf_len; + + assert(VALID(buffer)); + assert(VALID(format)); + + buf_len = trio_length(buffer); + buffer = &buffer[buf_len]; + status = TrioFormat(&buffer, max - 1 - buf_len, + TrioOutStreamStringMax, format, &args, NULL); + *buffer = NIL; + return status; +} + +/************************************************************************* + * trio_aprintf + */ + +/* Deprecated */ +TRIO_PUBLIC char * +trio_aprintf +TRIO_VARGS2((format, va_alist), + TRIO_CONST char *format, + TRIO_VA_DECL) +{ + va_list args; + trio_string_t *info; + char *result = NULL; + + assert(VALID(format)); + + info = trio_xstring_duplicate(""); + if (info) + { + TRIO_VA_START(args, format); + (void)TrioFormat(info, 0, TrioOutStreamStringDynamic, + format, &args, NULL); + TRIO_VA_END(args); + + trio_string_terminate(info); + result = trio_string_extract(info); + trio_string_destroy(info); + } + return result; +} + +/* Deprecated */ +TRIO_PUBLIC char * +trio_vaprintf +TRIO_ARGS2((format, args), + TRIO_CONST char *format, + va_list args) +{ + trio_string_t *info; + char *result = NULL; + + assert(VALID(format)); + + info = trio_xstring_duplicate(""); + if (info) + { + (void)TrioFormat(info, 0, TrioOutStreamStringDynamic, + format, &args, NULL); + trio_string_terminate(info); + result = trio_string_extract(info); + trio_string_destroy(info); + } + return result; +} + +TRIO_PUBLIC int +trio_asprintf +TRIO_VARGS3((result, format, va_alist), + char **result, + TRIO_CONST char *format, + TRIO_VA_DECL) +{ + va_list args; + int status; + trio_string_t *info; + + assert(VALID(format)); + + *result = NULL; + + info = trio_xstring_duplicate(""); + if (info == NULL) + { + status = TRIO_ERROR_RETURN(TRIO_ENOMEM, 0); + } + else + { + TRIO_VA_START(args, format); + status = TrioFormat(info, 0, TrioOutStreamStringDynamic, + format, &args, NULL); + TRIO_VA_END(args); + if (status >= 0) + { + trio_string_terminate(info); + *result = trio_string_extract(info); + } + trio_string_destroy(info); + } + return status; +} + +TRIO_PUBLIC int +trio_vasprintf +TRIO_ARGS3((result, format, args), + char **result, + TRIO_CONST char *format, + va_list args) +{ + int status; + trio_string_t *info; + + assert(VALID(format)); + + *result = NULL; + + info = trio_xstring_duplicate(""); + if (info == NULL) + { + status = TRIO_ERROR_RETURN(TRIO_ENOMEM, 0); + } + else + { + status = TrioFormat(info, 0, TrioOutStreamStringDynamic, + format, &args, NULL); + if (status >= 0) + { + trio_string_terminate(info); + *result = trio_string_extract(info); + } + trio_string_destroy(info); + } + return status; +} + +/** @} End of Printf documentation module */ + +/************************************************************************* + * + * CALLBACK + * + ************************************************************************/ + +#if defined(TRIO_DOCUMENTATION) +# include "doc/doc_register.h" +#endif +/** + @addtogroup UserDefined + @{ +*/ + +#if TRIO_EXTENSION + +/************************************************************************* + * trio_register + */ + +/** + Register new user-defined specifier. + + @param callback + @param name + @return Handle. + */ +TRIO_PUBLIC trio_pointer_t +trio_register +TRIO_ARGS2((callback, name), + trio_callback_t callback, + TRIO_CONST char *name) +{ + trio_userdef_t *def; + trio_userdef_t *prev = NULL; + + if (callback == NULL) + return NULL; + + if (name) + { + /* Handle built-in namespaces */ + if (name[0] == ':') + { + if (trio_equal(name, ":enter")) + { + internalEnterCriticalRegion = callback; + } + else if (trio_equal(name, ":leave")) + { + internalLeaveCriticalRegion = callback; + } + return NULL; + } + + /* Bail out if namespace is too long */ + if (trio_length(name) >= MAX_USER_NAME) + return NULL; + + /* Bail out if namespace already is registered */ + def = TrioFindNamespace(name, &prev); + if (def) + return NULL; + } + + def = (trio_userdef_t *)TRIO_MALLOC(sizeof(trio_userdef_t)); + if (def) + { + if (internalEnterCriticalRegion) + (void)internalEnterCriticalRegion(NULL); + + if (name) + { + /* Link into internal list */ + if (prev == NULL) + internalUserDef = def; + else + prev->next = def; + } + /* Initialize */ + def->callback = callback; + def->name = (name == NULL) + ? NULL + : trio_duplicate(name); + def->next = NULL; + + if (internalLeaveCriticalRegion) + (void)internalLeaveCriticalRegion(NULL); + } + return (trio_pointer_t)def; +} + +/** + Unregister an existing user-defined specifier. + + @param handle + */ +void +trio_unregister +TRIO_ARGS1((handle), + trio_pointer_t handle) +{ + trio_userdef_t *self = (trio_userdef_t *)handle; + trio_userdef_t *def; + trio_userdef_t *prev = NULL; + + assert(VALID(self)); + + if (self->name) + { + def = TrioFindNamespace(self->name, &prev); + if (def) + { + if (internalEnterCriticalRegion) + (void)internalEnterCriticalRegion(NULL); + + if (prev == NULL) + internalUserDef = NULL; + else + prev->next = def->next; + + if (internalLeaveCriticalRegion) + (void)internalLeaveCriticalRegion(NULL); + } + trio_destroy(self->name); + } + TRIO_FREE(self); +} + +/************************************************************************* + * trio_get_format [public] + */ +TRIO_CONST char * +trio_get_format +TRIO_ARGS1((ref), + trio_pointer_t ref) +{ +#if defined(FORMAT_USER_DEFINED) + assert(((trio_reference_t *)ref)->parameter->type == FORMAT_USER_DEFINED); +#endif + + return (((trio_reference_t *)ref)->parameter->user_data); +} + +/************************************************************************* + * trio_get_argument [public] + */ +trio_pointer_t +trio_get_argument +TRIO_ARGS1((ref), + trio_pointer_t ref) +{ +#if defined(FORMAT_USER_DEFINED) + assert(((trio_reference_t *)ref)->parameter->type == FORMAT_USER_DEFINED); +#endif + + return ((trio_reference_t *)ref)->parameter->data.pointer; +} + +/************************************************************************* + * trio_get_width / trio_set_width [public] + */ +int +trio_get_width +TRIO_ARGS1((ref), + trio_pointer_t ref) +{ + return ((trio_reference_t *)ref)->parameter->width; +} + +void +trio_set_width +TRIO_ARGS2((ref, width), + trio_pointer_t ref, + int width) +{ + ((trio_reference_t *)ref)->parameter->width = width; +} + +/************************************************************************* + * trio_get_precision / trio_set_precision [public] + */ +int +trio_get_precision +TRIO_ARGS1((ref), + trio_pointer_t ref) +{ + return (((trio_reference_t *)ref)->parameter->precision); +} + +void +trio_set_precision +TRIO_ARGS2((ref, precision), + trio_pointer_t ref, + int precision) +{ + ((trio_reference_t *)ref)->parameter->precision = precision; +} + +/************************************************************************* + * trio_get_base / trio_set_base [public] + */ +int +trio_get_base +TRIO_ARGS1((ref), + trio_pointer_t ref) +{ + return (((trio_reference_t *)ref)->parameter->base); +} + +void +trio_set_base +TRIO_ARGS2((ref, base), + trio_pointer_t ref, + int base) +{ + ((trio_reference_t *)ref)->parameter->base = base; +} + +/************************************************************************* + * trio_get_long / trio_set_long [public] + */ +int +trio_get_long +TRIO_ARGS1((ref), + trio_pointer_t ref) +{ + return (((trio_reference_t *)ref)->parameter->flags & FLAGS_LONG) + ? TRUE + : FALSE; +} + +void +trio_set_long +TRIO_ARGS2((ref, is_long), + trio_pointer_t ref, + int is_long) +{ + if (is_long) + ((trio_reference_t *)ref)->parameter->flags |= FLAGS_LONG; + else + ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_LONG; +} + +/************************************************************************* + * trio_get_longlong / trio_set_longlong [public] + */ +int +trio_get_longlong +TRIO_ARGS1((ref), + trio_pointer_t ref) +{ + return (((trio_reference_t *)ref)->parameter->flags & FLAGS_QUAD) + ? TRUE + : FALSE; +} + +void +trio_set_longlong +TRIO_ARGS2((ref, is_longlong), + trio_pointer_t ref, + int is_longlong) +{ + if (is_longlong) + ((trio_reference_t *)ref)->parameter->flags |= FLAGS_QUAD; + else + ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_QUAD; +} + +/************************************************************************* + * trio_get_longdouble / trio_set_longdouble [public] + */ +int +trio_get_longdouble +TRIO_ARGS1((ref), + trio_pointer_t ref) +{ + return (((trio_reference_t *)ref)->parameter->flags & FLAGS_LONGDOUBLE) + ? TRUE + : FALSE; +} + +void +trio_set_longdouble +TRIO_ARGS2((ref, is_longdouble), + trio_pointer_t ref, + int is_longdouble) +{ + if (is_longdouble) + ((trio_reference_t *)ref)->parameter->flags |= FLAGS_LONGDOUBLE; + else + ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_LONGDOUBLE; +} + +/************************************************************************* + * trio_get_short / trio_set_short [public] + */ +int +trio_get_short +TRIO_ARGS1((ref), + trio_pointer_t ref) +{ + return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SHORT) + ? TRUE + : FALSE; +} + +void +trio_set_short +TRIO_ARGS2((ref, is_short), + trio_pointer_t ref, + int is_short) +{ + if (is_short) + ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SHORT; + else + ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SHORT; +} + +/************************************************************************* + * trio_get_shortshort / trio_set_shortshort [public] + */ +int +trio_get_shortshort +TRIO_ARGS1((ref), + trio_pointer_t ref) +{ + return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SHORTSHORT) + ? TRUE + : FALSE; +} + +void +trio_set_shortshort +TRIO_ARGS2((ref, is_shortshort), + trio_pointer_t ref, + int is_shortshort) +{ + if (is_shortshort) + ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SHORTSHORT; + else + ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SHORTSHORT; +} + +/************************************************************************* + * trio_get_alternative / trio_set_alternative [public] + */ +int +trio_get_alternative +TRIO_ARGS1((ref), + trio_pointer_t ref) +{ + return (((trio_reference_t *)ref)->parameter->flags & FLAGS_ALTERNATIVE) + ? TRUE + : FALSE; +} + +void +trio_set_alternative +TRIO_ARGS2((ref, is_alternative), + trio_pointer_t ref, + int is_alternative) +{ + if (is_alternative) + ((trio_reference_t *)ref)->parameter->flags |= FLAGS_ALTERNATIVE; + else + ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_ALTERNATIVE; +} + +/************************************************************************* + * trio_get_alignment / trio_set_alignment [public] + */ +int +trio_get_alignment +TRIO_ARGS1((ref), + trio_pointer_t ref) +{ + return (((trio_reference_t *)ref)->parameter->flags & FLAGS_LEFTADJUST) + ? TRUE + : FALSE; +} + +void +trio_set_alignment +TRIO_ARGS2((ref, is_leftaligned), + trio_pointer_t ref, + int is_leftaligned) +{ + if (is_leftaligned) + ((trio_reference_t *)ref)->parameter->flags |= FLAGS_LEFTADJUST; + else + ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_LEFTADJUST; +} + +/************************************************************************* + * trio_get_spacing /trio_set_spacing [public] + */ +int +trio_get_spacing +TRIO_ARGS1((ref), + trio_pointer_t ref) +{ + return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SPACE) + ? TRUE + : FALSE; +} + +void +trio_set_spacing +TRIO_ARGS2((ref, is_space), + trio_pointer_t ref, + int is_space) +{ + if (is_space) + ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SPACE; + else + ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SPACE; +} + +/************************************************************************* + * trio_get_sign / trio_set_sign [public] + */ +int +trio_get_sign +TRIO_ARGS1((ref), + trio_pointer_t ref) +{ + return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SHOWSIGN) + ? TRUE + : FALSE; +} + +void +trio_set_sign +TRIO_ARGS2((ref, is_sign), + trio_pointer_t ref, + int is_sign) +{ + if (is_sign) + ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SHOWSIGN; + else + ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SHOWSIGN; +} + +/************************************************************************* + * trio_get_padding / trio_set_padding [public] + */ +int +trio_get_padding +TRIO_ARGS1((ref), + trio_pointer_t ref) +{ + return (((trio_reference_t *)ref)->parameter->flags & FLAGS_NILPADDING) + ? TRUE + : FALSE; +} + +void +trio_set_padding +TRIO_ARGS2((ref, is_padding), + trio_pointer_t ref, + int is_padding) +{ + if (is_padding) + ((trio_reference_t *)ref)->parameter->flags |= FLAGS_NILPADDING; + else + ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_NILPADDING; +} + +/************************************************************************* + * trio_get_quote / trio_set_quote [public] + */ +int +trio_get_quote +TRIO_ARGS1((ref), + trio_pointer_t ref) +{ + return (((trio_reference_t *)ref)->parameter->flags & FLAGS_QUOTE) + ? TRUE + : FALSE; +} + +void +trio_set_quote +TRIO_ARGS2((ref, is_quote), + trio_pointer_t ref, + int is_quote) +{ + if (is_quote) + ((trio_reference_t *)ref)->parameter->flags |= FLAGS_QUOTE; + else + ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_QUOTE; +} + +/************************************************************************* + * trio_get_upper / trio_set_upper [public] + */ +int +trio_get_upper +TRIO_ARGS1((ref), + trio_pointer_t ref) +{ + return (((trio_reference_t *)ref)->parameter->flags & FLAGS_UPPER) + ? TRUE + : FALSE; +} + +void +trio_set_upper +TRIO_ARGS2((ref, is_upper), + trio_pointer_t ref, + int is_upper) +{ + if (is_upper) + ((trio_reference_t *)ref)->parameter->flags |= FLAGS_UPPER; + else + ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_UPPER; +} + +/************************************************************************* + * trio_get_largest / trio_set_largest [public] + */ +#if TRIO_C99 +int +trio_get_largest +TRIO_ARGS1((ref), + trio_pointer_t ref) +{ + return (((trio_reference_t *)ref)->parameter->flags & FLAGS_INTMAX_T) + ? TRUE + : FALSE; +} + +void +trio_set_largest +TRIO_ARGS2((ref, is_largest), + trio_pointer_t ref, + int is_largest) +{ + if (is_largest) + ((trio_reference_t *)ref)->parameter->flags |= FLAGS_INTMAX_T; + else + ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_INTMAX_T; +} +#endif + +/************************************************************************* + * trio_get_ptrdiff / trio_set_ptrdiff [public] + */ +int +trio_get_ptrdiff +TRIO_ARGS1((ref), + trio_pointer_t ref) +{ + return (((trio_reference_t *)ref)->parameter->flags & FLAGS_PTRDIFF_T) + ? TRUE + : FALSE; +} + +void +trio_set_ptrdiff +TRIO_ARGS2((ref, is_ptrdiff), + trio_pointer_t ref, + int is_ptrdiff) +{ + if (is_ptrdiff) + ((trio_reference_t *)ref)->parameter->flags |= FLAGS_PTRDIFF_T; + else + ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_PTRDIFF_T; +} + +/************************************************************************* + * trio_get_size / trio_set_size [public] + */ +#if TRIO_C99 +int +trio_get_size +TRIO_ARGS1((ref), + trio_pointer_t ref) +{ + return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SIZE_T) + ? TRUE + : FALSE; +} + +void +trio_set_size +TRIO_ARGS2((ref, is_size), + trio_pointer_t ref, + int is_size) +{ + if (is_size) + ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SIZE_T; + else + ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SIZE_T; +} +#endif + +/************************************************************************* + * trio_print_int [public] + */ +void +trio_print_int +TRIO_ARGS2((ref, number), + trio_pointer_t ref, + int number) +{ + trio_reference_t *self = (trio_reference_t *)ref; + + TrioWriteNumber(self->data, + (trio_uintmax_t)number, + self->parameter->flags, + self->parameter->width, + self->parameter->precision, + self->parameter->base); +} + +/************************************************************************* + * trio_print_uint [public] + */ +void +trio_print_uint +TRIO_ARGS2((ref, number), + trio_pointer_t ref, + unsigned int number) +{ + trio_reference_t *self = (trio_reference_t *)ref; + + TrioWriteNumber(self->data, + (trio_uintmax_t)number, + self->parameter->flags | FLAGS_UNSIGNED, + self->parameter->width, + self->parameter->precision, + self->parameter->base); +} + +/************************************************************************* + * trio_print_double [public] + */ +void +trio_print_double +TRIO_ARGS2((ref, number), + trio_pointer_t ref, + double number) +{ + trio_reference_t *self = (trio_reference_t *)ref; + + TrioWriteDouble(self->data, + number, + self->parameter->flags, + self->parameter->width, + self->parameter->precision, + self->parameter->base); +} + +/************************************************************************* + * trio_print_string [public] + */ +void +trio_print_string +TRIO_ARGS2((ref, string), + trio_pointer_t ref, + char *string) +{ + trio_reference_t *self = (trio_reference_t *)ref; + + TrioWriteString(self->data, + string, + self->parameter->flags, + self->parameter->width, + self->parameter->precision); +} + +/************************************************************************* + * trio_print_ref [public] + */ +int +trio_print_ref +TRIO_VARGS3((ref, format, va_alist), + trio_pointer_t ref, + TRIO_CONST char *format, + TRIO_VA_DECL) +{ + int status; + va_list arglist; + + assert(VALID(format)); + + TRIO_VA_START(arglist, format); + status = TrioFormatRef((trio_reference_t *)ref, format, &arglist, NULL); + TRIO_VA_END(arglist); + return status; +} + +/************************************************************************* + * trio_vprint_ref [public] + */ +int +trio_vprint_ref +TRIO_ARGS3((ref, format, arglist), + trio_pointer_t ref, + TRIO_CONST char *format, + va_list arglist) +{ + assert(VALID(format)); + + return TrioFormatRef((trio_reference_t *)ref, format, &arglist, NULL); +} + +/************************************************************************* + * trio_printv_ref [public] + */ +int +trio_printv_ref +TRIO_ARGS3((ref, format, argarray), + trio_pointer_t ref, + TRIO_CONST char *format, + trio_pointer_t *argarray) +{ + assert(VALID(format)); + + return TrioFormatRef((trio_reference_t *)ref, format, NULL, argarray); +} + +#endif /* TRIO_EXTENSION */ + +/************************************************************************* + * trio_print_pointer [public] + */ +void +trio_print_pointer +TRIO_ARGS2((ref, pointer), + trio_pointer_t ref, + trio_pointer_t pointer) +{ + trio_reference_t *self = (trio_reference_t *)ref; + trio_flags_t flags; + trio_uintmax_t number; + + if (NULL == pointer) + { + TRIO_CONST char *string = internalNullString; + while (*string) + self->data->OutStream(self->data, *string++); + } + else + { + /* + * The subtraction of the null pointer is a workaround + * to avoid a compiler warning. The performance overhead + * is negligible (and likely to be removed by an + * optimizing compiler). The (char *) casting is done + * to please ANSI C++. + */ + number = (trio_uintmax_t)((char *)pointer - (char *)0); + /* Shrink to size of pointer */ + number &= (trio_uintmax_t)-1; + flags = self->parameter->flags; + flags |= (FLAGS_UNSIGNED | FLAGS_ALTERNATIVE | + FLAGS_NILPADDING); + TrioWriteNumber(self->data, + number, + flags, + POINTER_WIDTH, + NO_PRECISION, + BASE_HEX); + } +} + +/** @} End of UserDefined documentation module */ + +/************************************************************************* + * + * LOCALES + * + ************************************************************************/ + +/************************************************************************* + * trio_locale_set_decimal_point + * + * Decimal point can only be one character. The input argument is a + * string to enable multibyte characters. At most MB_LEN_MAX characters + * will be used. + */ +TRIO_PUBLIC void +trio_locale_set_decimal_point +TRIO_ARGS1((decimalPoint), + char *decimalPoint) +{ +#if defined(USE_LOCALE) + if (NULL == internalLocaleValues) + { + TrioSetLocale(); + } +#endif + internalDecimalPointLength = trio_length(decimalPoint); + if (internalDecimalPointLength == 1) + { + internalDecimalPoint = *decimalPoint; + } + else + { + internalDecimalPoint = NIL; + trio_copy_max(internalDecimalPointString, + sizeof(internalDecimalPointString), + decimalPoint); + } +} + +/************************************************************************* + * trio_locale_set_thousand_separator + * + * See trio_locale_set_decimal_point + */ +TRIO_PUBLIC void +trio_locale_set_thousand_separator +TRIO_ARGS1((thousandSeparator), + char *thousandSeparator) +{ +#if defined(USE_LOCALE) + if (NULL == internalLocaleValues) + { + TrioSetLocale(); + } +#endif + trio_copy_max(internalThousandSeparator, + sizeof(internalThousandSeparator), + thousandSeparator); + internalThousandSeparatorLength = trio_length(internalThousandSeparator); +} + +/************************************************************************* + * trio_locale_set_grouping + * + * Array of bytes. Reversed order. + * + * CHAR_MAX : No further grouping + * 0 : Repeat last group for the remaining digits (not necessary + * as C strings are zero-terminated) + * n : Set current group to n + * + * Same order as the grouping attribute in LC_NUMERIC. + */ +TRIO_PUBLIC void +trio_locale_set_grouping +TRIO_ARGS1((grouping), + char *grouping) +{ +#if defined(USE_LOCALE) + if (NULL == internalLocaleValues) + { + TrioSetLocale(); + } +#endif + trio_copy_max(internalGrouping, + sizeof(internalGrouping), + grouping); +} + + +/************************************************************************* + * + * SCANNING + * + ************************************************************************/ + +/************************************************************************* + * TrioSkipWhitespaces + */ +TRIO_PRIVATE int +TrioSkipWhitespaces +TRIO_ARGS1((self), + trio_class_t *self) +{ + int ch; + + ch = self->current; + while (isspace(ch)) + { + self->InStream(self, &ch); + } + return ch; +} + +/************************************************************************* + * TrioGetCollation + */ +#if TRIO_EXTENSION +TRIO_PRIVATE void +TrioGetCollation(TRIO_NOARGS) +{ + int i; + int j; + int k; + char first[2]; + char second[2]; + + /* This is computationally expensive */ + first[1] = NIL; + second[1] = NIL; + for (i = 0; i < MAX_CHARACTER_CLASS; i++) + { + k = 0; + first[0] = (char)i; + for (j = 0; j < MAX_CHARACTER_CLASS; j++) + { + second[0] = (char)j; + if (trio_equal_locale(first, second)) + internalCollationArray[i][k++] = (char)j; + } + internalCollationArray[i][k] = NIL; + } +} +#endif + +/************************************************************************* + * TrioGetCharacterClass + * + * FIXME: + * multibyte + */ +TRIO_PRIVATE int +TrioGetCharacterClass +TRIO_ARGS4((format, indexPointer, flagsPointer, characterclass), + TRIO_CONST char *format, + int *indexPointer, + trio_flags_t *flagsPointer, + int *characterclass) +{ + int index = *indexPointer; + int i; + char ch; + char range_begin; + char range_end; + + *flagsPointer &= ~FLAGS_EXCLUDE; + + if (format[index] == QUALIFIER_CIRCUMFLEX) + { + *flagsPointer |= FLAGS_EXCLUDE; + index++; + } + /* + * If the ungroup character is at the beginning of the scanlist, + * it will be part of the class, and a second ungroup character + * must follow to end the group. + */ + if (format[index] == SPECIFIER_UNGROUP) + { + characterclass[(int)SPECIFIER_UNGROUP]++; + index++; + } + /* + * Minus is used to specify ranges. To include minus in the class, + * it must be at the beginning of the list + */ + if (format[index] == QUALIFIER_MINUS) + { + characterclass[(int)QUALIFIER_MINUS]++; + index++; + } + /* Collect characters */ + for (ch = format[index]; + (ch != SPECIFIER_UNGROUP) && (ch != NIL); + ch = format[++index]) + { + switch (ch) + { + case QUALIFIER_MINUS: /* Scanlist ranges */ + + /* + * Both C99 and UNIX98 describes ranges as implementation- + * defined. + * + * We support the following behaviour (although this may + * change as we become wiser) + * - only increasing ranges, ie. [a-b] but not [b-a] + * - transitive ranges, ie. [a-b-c] == [a-c] + * - trailing minus, ie. [a-] is interpreted as an 'a' + * and a '-' + * - duplicates (although we can easily convert these + * into errors) + */ + range_begin = format[index - 1]; + range_end = format[++index]; + if (range_end == SPECIFIER_UNGROUP) + { + /* Trailing minus is included */ + characterclass[(int)ch]++; + ch = range_end; + break; /* for */ + } + if (range_end == NIL) + return TRIO_ERROR_RETURN(TRIO_EINVAL, index); + if (range_begin > range_end) + return TRIO_ERROR_RETURN(TRIO_ERANGE, index); + + for (i = (int)range_begin; i <= (int)range_end; i++) + characterclass[i]++; + + ch = range_end; + break; + +#if TRIO_EXTENSION + + case SPECIFIER_GROUP: + + switch (format[index + 1]) + { + case QUALIFIER_DOT: /* Collating symbol */ + /* + * FIXME: This will be easier to implement when multibyte + * characters have been implemented. Until now, we ignore + * this feature. + */ + for (i = index + 2; ; i++) + { + if (format[i] == NIL) + /* Error in syntax */ + return -1; + else if (format[i] == QUALIFIER_DOT) + break; /* for */ + } + if (format[++i] != SPECIFIER_UNGROUP) + return -1; + + index = i; + break; + + case QUALIFIER_EQUAL: /* Equivalence class expressions */ + { + unsigned int j; + unsigned int k; + + if (internalCollationUnconverted) + { + /* Lazy evaluation of collation array */ + TrioGetCollation(); + internalCollationUnconverted = FALSE; + } + for (i = index + 2; ; i++) + { + if (format[i] == NIL) + /* Error in syntax */ + return -1; + else if (format[i] == QUALIFIER_EQUAL) + break; /* for */ + else + { + /* Mark any equivalent character */ + k = (unsigned int)format[i]; + for (j = 0; internalCollationArray[k][j] != NIL; j++) + characterclass[(int)internalCollationArray[k][j]]++; + } + } + if (format[++i] != SPECIFIER_UNGROUP) + return -1; + + index = i; + } + break; + + case QUALIFIER_COLON: /* Character class expressions */ + + if (trio_equal_max(CLASS_ALNUM, sizeof(CLASS_ALNUM) - 1, + &format[index])) + { + for (i = 0; i < MAX_CHARACTER_CLASS; i++) + if (isalnum(i)) + characterclass[i]++; + index += sizeof(CLASS_ALNUM) - 1; + } + else if (trio_equal_max(CLASS_ALPHA, sizeof(CLASS_ALPHA) - 1, + &format[index])) + { + for (i = 0; i < MAX_CHARACTER_CLASS; i++) + if (isalpha(i)) + characterclass[i]++; + index += sizeof(CLASS_ALPHA) - 1; + } + else if (trio_equal_max(CLASS_CNTRL, sizeof(CLASS_CNTRL) - 1, + &format[index])) + { + for (i = 0; i < MAX_CHARACTER_CLASS; i++) + if (iscntrl(i)) + characterclass[i]++; + index += sizeof(CLASS_CNTRL) - 1; + } + else if (trio_equal_max(CLASS_DIGIT, sizeof(CLASS_DIGIT) - 1, + &format[index])) + { + for (i = 0; i < MAX_CHARACTER_CLASS; i++) + if (isdigit(i)) + characterclass[i]++; + index += sizeof(CLASS_DIGIT) - 1; + } + else if (trio_equal_max(CLASS_GRAPH, sizeof(CLASS_GRAPH) - 1, + &format[index])) + { + for (i = 0; i < MAX_CHARACTER_CLASS; i++) + if (isgraph(i)) + characterclass[i]++; + index += sizeof(CLASS_GRAPH) - 1; + } + else if (trio_equal_max(CLASS_LOWER, sizeof(CLASS_LOWER) - 1, + &format[index])) + { + for (i = 0; i < MAX_CHARACTER_CLASS; i++) + if (islower(i)) + characterclass[i]++; + index += sizeof(CLASS_LOWER) - 1; + } + else if (trio_equal_max(CLASS_PRINT, sizeof(CLASS_PRINT) - 1, + &format[index])) + { + for (i = 0; i < MAX_CHARACTER_CLASS; i++) + if (isprint(i)) + characterclass[i]++; + index += sizeof(CLASS_PRINT) - 1; + } + else if (trio_equal_max(CLASS_PUNCT, sizeof(CLASS_PUNCT) - 1, + &format[index])) + { + for (i = 0; i < MAX_CHARACTER_CLASS; i++) + if (ispunct(i)) + characterclass[i]++; + index += sizeof(CLASS_PUNCT) - 1; + } + else if (trio_equal_max(CLASS_SPACE, sizeof(CLASS_SPACE) - 1, + &format[index])) + { + for (i = 0; i < MAX_CHARACTER_CLASS; i++) + if (isspace(i)) + characterclass[i]++; + index += sizeof(CLASS_SPACE) - 1; + } + else if (trio_equal_max(CLASS_UPPER, sizeof(CLASS_UPPER) - 1, + &format[index])) + { + for (i = 0; i < MAX_CHARACTER_CLASS; i++) + if (isupper(i)) + characterclass[i]++; + index += sizeof(CLASS_UPPER) - 1; + } + else if (trio_equal_max(CLASS_XDIGIT, sizeof(CLASS_XDIGIT) - 1, + &format[index])) + { + for (i = 0; i < MAX_CHARACTER_CLASS; i++) + if (isxdigit(i)) + characterclass[i]++; + index += sizeof(CLASS_XDIGIT) - 1; + } + else + { + characterclass[(int)ch]++; + } + break; + + default: + characterclass[(int)ch]++; + break; + } + break; + +#endif /* TRIO_EXTENSION */ + + default: + characterclass[(int)ch]++; + break; + } + } + return 0; +} + +/************************************************************************* + * TrioReadNumber + * + * We implement our own number conversion in preference of strtol and + * strtoul, because we must handle 'long long' and thousand separators. + */ +TRIO_PRIVATE BOOLEAN_T +TrioReadNumber +TRIO_ARGS5((self, target, flags, width, base), + trio_class_t *self, + trio_uintmax_t *target, + trio_flags_t flags, + int width, + int base) +{ + trio_uintmax_t number = 0; + int digit; + int count; + BOOLEAN_T isNegative = FALSE; + BOOLEAN_T gotNumber = FALSE; + int j; + + assert(VALID(self)); + assert(VALID(self->InStream)); + assert((base >= MIN_BASE && base <= MAX_BASE) || (base == NO_BASE)); + + if (internalDigitsUnconverted) + { + /* Lazy evaluation of digits array */ + memset(internalDigitArray, -1, sizeof(internalDigitArray)); + for (j = 0; j < (int)sizeof(internalDigitsLower) - 1; j++) + { + internalDigitArray[(int)internalDigitsLower[j]] = j; + internalDigitArray[(int)internalDigitsUpper[j]] = j; + } + internalDigitsUnconverted = FALSE; + } + + TrioSkipWhitespaces(self); + + if (!(flags & FLAGS_UNSIGNED)) + { + /* Leading sign */ + if (self->current == '+') + { + self->InStream(self, NULL); + } + else if (self->current == '-') + { + self->InStream(self, NULL); + isNegative = TRUE; + } + } + + count = self->processed; + + if (flags & FLAGS_ALTERNATIVE) + { + switch (base) + { + case NO_BASE: + case BASE_OCTAL: + case BASE_HEX: + case BASE_BINARY: + if (self->current == '0') + { + self->InStream(self, NULL); + if (self->current) + { + if ((base == BASE_HEX) && + (trio_to_upper(self->current) == 'X')) + { + self->InStream(self, NULL); + } + else if ((base == BASE_BINARY) && + (trio_to_upper(self->current) == 'B')) + { + self->InStream(self, NULL); + } + } + } + else + return FALSE; + break; + default: + break; + } + } + + while (((width == NO_WIDTH) || (self->processed - count < width)) && + (! ((self->current == EOF) || isspace(self->current)))) + { + if (isascii(self->current)) + { + digit = internalDigitArray[self->current]; + /* Abort if digit is not allowed in the specified base */ + if ((digit == -1) || (digit >= base)) + break; + } + else if (flags & FLAGS_QUOTE) + { + /* Compare with thousands separator */ + for (j = 0; internalThousandSeparator[j] && self->current; j++) + { + if (internalThousandSeparator[j] != self->current) + break; + + self->InStream(self, NULL); + } + if (internalThousandSeparator[j]) + break; /* Mismatch */ + else + continue; /* Match */ + } + else + break; + + number *= base; + number += digit; + gotNumber = TRUE; /* we need at least one digit */ + + self->InStream(self, NULL); + } + + /* Was anything read at all? */ + if (!gotNumber) + return FALSE; + + if (target) + *target = (isNegative) ? -((trio_intmax_t)number) : number; + return TRUE; +} + +/************************************************************************* + * TrioReadChar + */ +TRIO_PRIVATE int +TrioReadChar +TRIO_ARGS4((self, target, flags, width), + trio_class_t *self, + char *target, + trio_flags_t flags, + int width) +{ + int i; + char ch; + trio_uintmax_t number; + + assert(VALID(self)); + assert(VALID(self->InStream)); + + for (i = 0; + (self->current != EOF) && (i < width); + i++) + { + ch = (char)self->current; + self->InStream(self, NULL); + if ((flags & FLAGS_ALTERNATIVE) && (ch == CHAR_BACKSLASH)) + { + switch (self->current) + { + case '\\': ch = '\\'; break; + case 'a': ch = '\007'; break; + case 'b': ch = '\b'; break; + case 'f': ch = '\f'; break; + case 'n': ch = '\n'; break; + case 'r': ch = '\r'; break; + case 't': ch = '\t'; break; + case 'v': ch = '\v'; break; + default: + if (isdigit(self->current)) + { + /* Read octal number */ + if (!TrioReadNumber(self, &number, 0, 3, BASE_OCTAL)) + return 0; + ch = (char)number; + } + else if (trio_to_upper(self->current) == 'X') + { + /* Read hexadecimal number */ + self->InStream(self, NULL); + if (!TrioReadNumber(self, &number, 0, 2, BASE_HEX)) + return 0; + ch = (char)number; + } + else + { + ch = (char)self->current; + } + break; + } + } + + if (target) + target[i] = ch; + } + return i + 1; +} + +/************************************************************************* + * TrioReadString + */ +TRIO_PRIVATE BOOLEAN_T +TrioReadString +TRIO_ARGS4((self, target, flags, width), + trio_class_t *self, + char *target, + trio_flags_t flags, + int width) +{ + int i; + + assert(VALID(self)); + assert(VALID(self->InStream)); + + TrioSkipWhitespaces(self); + + /* + * Continue until end of string is reached, a whitespace is encountered, + * or width is exceeded + */ + for (i = 0; + ((width == NO_WIDTH) || (i < width)) && + (! ((self->current == EOF) || isspace(self->current))); + i++) + { + if (TrioReadChar(self, (target ? &target[i] : 0), flags, 1) == 0) + break; /* for */ + } + if (target) + target[i] = NIL; + return TRUE; +} + +/************************************************************************* + * TrioReadWideChar + */ +#if TRIO_WIDECHAR +TRIO_PRIVATE int +TrioReadWideChar +TRIO_ARGS4((self, target, flags, width), + trio_class_t *self, + trio_wchar_t *target, + trio_flags_t flags, + int width) +{ + int i; + int j; + int size; + int amount = 0; + trio_wchar_t wch; + char buffer[MB_LEN_MAX + 1]; + + assert(VALID(self)); + assert(VALID(self->InStream)); + + for (i = 0; + (self->current != EOF) && (i < width); + i++) + { + if (isascii(self->current)) + { + if (TrioReadChar(self, buffer, flags, 1) == 0) + return 0; + buffer[1] = NIL; + } + else + { + /* + * Collect a multibyte character, by enlarging buffer until + * it contains a fully legal multibyte character, or the + * buffer is full. + */ + j = 0; + do + { + buffer[j++] = (char)self->current; + buffer[j] = NIL; + self->InStream(self, NULL); + } + while ((j < (int)sizeof(buffer)) && (mblen(buffer, (size_t)j) != j)); + } + if (target) + { + size = mbtowc(&wch, buffer, sizeof(buffer)); + if (size > 0) + target[i] = wch; + } + amount += size; + self->InStream(self, NULL); + } + return amount; +} +#endif /* TRIO_WIDECHAR */ + +/************************************************************************* + * TrioReadWideString + */ +#if TRIO_WIDECHAR +TRIO_PRIVATE BOOLEAN_T +TrioReadWideString +TRIO_ARGS4((self, target, flags, width), + trio_class_t *self, + trio_wchar_t *target, + trio_flags_t flags, + int width) +{ + int i; + int size; + + assert(VALID(self)); + assert(VALID(self->InStream)); + + TrioSkipWhitespaces(self); + +#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE) + (void)mblen(NULL, 0); +#endif + + /* + * Continue until end of string is reached, a whitespace is encountered, + * or width is exceeded + */ + for (i = 0; + ((width == NO_WIDTH) || (i < width)) && + (! ((self->current == EOF) || isspace(self->current))); + ) + { + size = TrioReadWideChar(self, &target[i], flags, 1); + if (size == 0) + break; /* for */ + + i += size; + } + if (target) + target[i] = WCONST('\0'); + return TRUE; +} +#endif /* TRIO_WIDECHAR */ + +/************************************************************************* + * TrioReadGroup + * + * FIXME: characterclass does not work with multibyte characters + */ +TRIO_PRIVATE BOOLEAN_T +TrioReadGroup +TRIO_ARGS5((self, target, characterclass, flags, width), + trio_class_t *self, + char *target, + int *characterclass, + trio_flags_t flags, + int width) +{ + int ch; + int i; + + assert(VALID(self)); + assert(VALID(self->InStream)); + + ch = self->current; + for (i = 0; + ((width == NO_WIDTH) || (i < width)) && + (! ((ch == EOF) || + (((flags & FLAGS_EXCLUDE) != 0) ^ (characterclass[ch] == 0)))); + i++) + { + if (target) + target[i] = (char)ch; + self->InStream(self, &ch); + } + + if (target) + target[i] = NIL; + return TRUE; +} + +/************************************************************************* + * TrioReadDouble + * + * FIXME: + * add long double + * handle base + */ +TRIO_PRIVATE BOOLEAN_T +TrioReadDouble +TRIO_ARGS4((self, target, flags, width), + trio_class_t *self, + trio_pointer_t target, + trio_flags_t flags, + int width) +{ + int ch; + char doubleString[512]; + int index = 0; + int start; + int j; + BOOLEAN_T isHex = FALSE; + + doubleString[0] = 0; + + if ((width == NO_WIDTH) || (width > (int)sizeof(doubleString) - 1)) + width = sizeof(doubleString) - 1; + + TrioSkipWhitespaces(self); + + /* + * Read entire double number from stream. trio_to_double requires + * a string as input, but InStream can be anything, so we have to + * collect all characters. + */ + ch = self->current; + if ((ch == '+') || (ch == '-')) + { + doubleString[index++] = (char)ch; + self->InStream(self, &ch); + width--; + } + + start = index; + switch (ch) + { + case 'n': + case 'N': + /* Not-a-number */ + if (index != 0) + break; + /* FALLTHROUGH */ + case 'i': + case 'I': + /* Infinity */ + while (isalpha(ch) && (index - start < width)) + { + doubleString[index++] = (char)ch; + self->InStream(self, &ch); + } + doubleString[index] = NIL; + + /* Case insensitive string comparison */ + if (trio_equal(&doubleString[start], INFINITE_UPPER) || + trio_equal(&doubleString[start], LONG_INFINITE_UPPER)) + { + if (flags & FLAGS_LONGDOUBLE) + { + if ((start == 1) && (doubleString[0] == '-')) + { + *((trio_long_double_t *)target) = trio_ninf(); + } + else + { + *((trio_long_double_t *)target) = trio_pinf(); + } + } + else + { + if ((start == 1) && (doubleString[0] == '-')) + { + *((double *)target) = trio_ninf(); + } + else + { + *((double *)target) = trio_pinf(); + } + } + return TRUE; + } + if (trio_equal(doubleString, NAN_UPPER)) + { + /* NaN must not have a preceeding + nor - */ + if (flags & FLAGS_LONGDOUBLE) + { + *((trio_long_double_t *)target) = trio_nan(); + } + else + { + *((double *)target) = trio_nan(); + } + return TRUE; + } + return FALSE; + + case '0': + doubleString[index++] = (char)ch; + self->InStream(self, &ch); + if (trio_to_upper(ch) == 'X') + { + isHex = TRUE; + doubleString[index++] = (char)ch; + self->InStream(self, &ch); + } + break; + + default: + break; + } + + while ((ch != EOF) && (index - start < width)) + { + /* Integer part */ + if (isHex ? isxdigit(ch) : isdigit(ch)) + { + doubleString[index++] = (char)ch; + self->InStream(self, &ch); + } + else if (flags & FLAGS_QUOTE) + { + /* Compare with thousands separator */ + for (j = 0; internalThousandSeparator[j] && self->current; j++) + { + if (internalThousandSeparator[j] != self->current) + break; + + self->InStream(self, &ch); + } + if (internalThousandSeparator[j]) + break; /* Mismatch */ + else + continue; /* Match */ + } + else + break; /* while */ + } + if (ch == '.') + { + /* Decimal part */ + doubleString[index++] = (char)ch; + self->InStream(self, &ch); + while ((isHex ? isxdigit(ch) : isdigit(ch)) && + (index - start < width)) + { + doubleString[index++] = (char)ch; + self->InStream(self, &ch); + } + if (isHex ? (trio_to_upper(ch) == 'P') : (trio_to_upper(ch) == 'E')) + { + /* Exponent */ + doubleString[index++] = (char)ch; + self->InStream(self, &ch); + if ((ch == '+') || (ch == '-')) + { + doubleString[index++] = (char)ch; + self->InStream(self, &ch); + } + while (isdigit(ch) && (index - start < width)) + { + doubleString[index++] = (char)ch; + self->InStream(self, &ch); + } + } + } + + if ((index == start) || (*doubleString == NIL)) + return FALSE; + + doubleString[index] = 0; + + if (flags & FLAGS_LONGDOUBLE) + { + *((trio_long_double_t *)target) = trio_to_long_double(doubleString, NULL); + } + else + { + *((double *)target) = trio_to_double(doubleString, NULL); + } + return TRUE; +} + +/************************************************************************* + * TrioReadPointer + */ +TRIO_PRIVATE BOOLEAN_T +TrioReadPointer +TRIO_ARGS3((self, target, flags), + trio_class_t *self, + trio_pointer_t *target, + trio_flags_t flags) +{ + trio_uintmax_t number; + char buffer[sizeof(internalNullString)]; + + flags |= (FLAGS_UNSIGNED | FLAGS_ALTERNATIVE | FLAGS_NILPADDING); + + if (TrioReadNumber(self, + &number, + flags, + POINTER_WIDTH, + BASE_HEX)) + { + /* + * The strange assignment of number is a workaround for a compiler + * warning + */ + if (target) + *target = (char *)0 + number; + return TRUE; + } + else if (TrioReadString(self, + (flags & FLAGS_IGNORE) + ? NULL + : buffer, + 0, + sizeof(internalNullString) - 1)) + { + if (trio_equal_case(buffer, internalNullString)) + { + if (target) + *target = NULL; + return TRUE; + } + } + return FALSE; +} + +/************************************************************************* + * TrioScanProcess + */ +TRIO_PRIVATE int +TrioScanProcess +TRIO_ARGS3((data, format, parameters), + trio_class_t *data, + TRIO_CONST char *format, + trio_parameter_t *parameters) +{ +#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE) + int charlen; + int cnt; +#endif + int assignment; + int ch; + int index; /* Index of format string */ + int i; /* Index of current parameter */ + trio_flags_t flags; + int width; + int base; + trio_pointer_t pointer; + + assignment = 0; + i = 0; + index = 0; + data->InStream(data, &ch); + +#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE) + (void)mblen(NULL, 0); +#endif + + while (format[index]) + { +#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE) + if (! isascii(format[index])) + { + charlen = mblen(&format[index], MB_LEN_MAX); + if (charlen != -1) + { + /* Compare multibyte characters in format string */ + for (cnt = 0; cnt < charlen - 1; cnt++) + { + if (ch != format[index + cnt]) + { + return TRIO_ERROR_RETURN(TRIO_EINVAL, index); + } + data->InStream(data, &ch); + } + continue; /* while characters left in formatting string */ + } + } +#endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */ + + if ((EOF == ch) && (parameters[i].type != FORMAT_COUNT)) + { + return (assignment > 0) ? assignment : EOF; + } + + if (CHAR_IDENTIFIER == format[index]) + { + if (CHAR_IDENTIFIER == format[index + 1]) + { + /* Two % in format matches one % in input stream */ + if (CHAR_IDENTIFIER == ch) + { + data->InStream(data, &ch); + index += 2; + continue; /* while format chars left */ + } + else + return TRIO_ERROR_RETURN(TRIO_EINVAL, index); + } + + /* Skip the parameter entries */ + while (parameters[i].type == FORMAT_PARAMETER) + i++; + + flags = parameters[i].flags; + /* Find width */ + width = parameters[i].width; + if (flags & FLAGS_WIDTH_PARAMETER) + { + /* Get width from parameter list */ + width = (int)parameters[width].data.number.as_signed; + } + /* Find base */ + base = parameters[i].base; + if (flags & FLAGS_BASE_PARAMETER) + { + /* Get base from parameter list */ + base = (int)parameters[base].data.number.as_signed; + } + + switch (parameters[i].type) + { + case FORMAT_INT: + { + trio_uintmax_t number; + + if (0 == base) + base = BASE_DECIMAL; + + if (!TrioReadNumber(data, + &number, + flags, + width, + base)) + return assignment; + + if (!(flags & FLAGS_IGNORE)) + { + assignment++; + + pointer = parameters[i].data.pointer; +#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER) + if (flags & FLAGS_SIZE_T) + *(size_t *)pointer = (size_t)number; + else +#endif +#if defined(QUALIFIER_PTRDIFF_T) + if (flags & FLAGS_PTRDIFF_T) + *(ptrdiff_t *)pointer = (ptrdiff_t)number; + else +#endif +#if defined(QUALIFIER_INTMAX_T) + if (flags & FLAGS_INTMAX_T) + *(trio_intmax_t *)pointer = (trio_intmax_t)number; + else +#endif + if (flags & FLAGS_QUAD) + *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)number; + else if (flags & FLAGS_LONG) + *(long int *)pointer = (long int)number; + else if (flags & FLAGS_SHORT) + *(short int *)pointer = (short int)number; + else + *(int *)pointer = (int)number; + } + } + break; /* FORMAT_INT */ + + case FORMAT_STRING: +#if TRIO_WIDECHAR + if (flags & FLAGS_WIDECHAR) + { + if (!TrioReadWideString(data, + (flags & FLAGS_IGNORE) + ? NULL + : parameters[i].data.wstring, + flags, + width)) + return assignment; + } + else +#endif + { + if (!TrioReadString(data, + (flags & FLAGS_IGNORE) + ? NULL + : parameters[i].data.string, + flags, + width)) + return assignment; + } + if (!(flags & FLAGS_IGNORE)) + assignment++; + break; /* FORMAT_STRING */ + + case FORMAT_DOUBLE: + { + trio_pointer_t pointer; + + if (flags & FLAGS_IGNORE) + { + pointer = NULL; + } + else + { + pointer = (flags & FLAGS_LONGDOUBLE) + ? (trio_pointer_t)parameters[i].data.longdoublePointer + : (trio_pointer_t)parameters[i].data.doublePointer; + } + if (!TrioReadDouble(data, pointer, flags, width)) + { + return assignment; + } + if (!(flags & FLAGS_IGNORE)) + { + assignment++; + } + break; /* FORMAT_DOUBLE */ + } + case FORMAT_GROUP: + { + int characterclass[MAX_CHARACTER_CLASS + 1]; + int rc; + + /* Skip over modifiers */ + while (format[index] != SPECIFIER_GROUP) + { + index++; + } + /* Skip over group specifier */ + index++; + + memset(characterclass, 0, sizeof(characterclass)); + rc = TrioGetCharacterClass(format, + &index, + &flags, + characterclass); + if (rc < 0) + return rc; + + if (!TrioReadGroup(data, + (flags & FLAGS_IGNORE) + ? NULL + : parameters[i].data.string, + characterclass, + flags, + parameters[i].width)) + return assignment; + if (!(flags & FLAGS_IGNORE)) + assignment++; + } + break; /* FORMAT_GROUP */ + + case FORMAT_COUNT: + pointer = parameters[i].data.pointer; + if (NULL != pointer) + { + int count = data->committed; + if (ch != EOF) + count--; /* a character is read, but is not consumed yet */ +#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER) + if (flags & FLAGS_SIZE_T) + *(size_t *)pointer = (size_t)count; + else +#endif +#if defined(QUALIFIER_PTRDIFF_T) + if (flags & FLAGS_PTRDIFF_T) + *(ptrdiff_t *)pointer = (ptrdiff_t)count; + else +#endif +#if defined(QUALIFIER_INTMAX_T) + if (flags & FLAGS_INTMAX_T) + *(trio_intmax_t *)pointer = (trio_intmax_t)count; + else +#endif + if (flags & FLAGS_QUAD) + { + *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)count; + } + else if (flags & FLAGS_LONG) + { + *(long int *)pointer = (long int)count; + } + else if (flags & FLAGS_SHORT) + { + *(short int *)pointer = (short int)count; + } + else + { + *(int *)pointer = (int)count; + } + } + break; /* FORMAT_COUNT */ + + case FORMAT_CHAR: +#if TRIO_WIDECHAR + if (flags & FLAGS_WIDECHAR) + { + if (TrioReadWideChar(data, + (flags & FLAGS_IGNORE) + ? NULL + : parameters[i].data.wstring, + flags, + (width == NO_WIDTH) ? 1 : width) == 0) + return assignment; + } + else +#endif + { + if (TrioReadChar(data, + (flags & FLAGS_IGNORE) + ? NULL + : parameters[i].data.string, + flags, + (width == NO_WIDTH) ? 1 : width) == 0) + return assignment; + } + if (!(flags & FLAGS_IGNORE)) + assignment++; + break; /* FORMAT_CHAR */ + + case FORMAT_POINTER: + if (!TrioReadPointer(data, + (flags & FLAGS_IGNORE) + ? NULL + : (trio_pointer_t *)parameters[i].data.pointer, + flags)) + return assignment; + if (!(flags & FLAGS_IGNORE)) + assignment++; + break; /* FORMAT_POINTER */ + + case FORMAT_PARAMETER: + break; /* FORMAT_PARAMETER */ + + default: + return TRIO_ERROR_RETURN(TRIO_EINVAL, index); + } + ch = data->current; + index = parameters[i].indexAfterSpecifier; + i++; + } + else /* Not an % identifier */ + { + if (isspace((int)format[index])) + { + /* Whitespaces may match any amount of whitespaces */ + ch = TrioSkipWhitespaces(data); + } + else if (ch == format[index]) + { + data->InStream(data, &ch); + } + else + return assignment; + + index++; + } + } + return assignment; +} + +/************************************************************************* + * TrioScan + */ +TRIO_PRIVATE int +TrioScan +TRIO_ARGS6((source, sourceSize, InStream, format, arglist, argarray), + trio_pointer_t source, + size_t sourceSize, + void (*InStream) TRIO_PROTO((trio_class_t *, int *)), + TRIO_CONST char *format, + va_list *arglist, + trio_pointer_t *argarray) +{ + int status; + trio_parameter_t parameters[MAX_PARAMETERS]; + trio_class_t data; + + assert(VALID(InStream)); + assert(VALID(format)); + + memset(&data, 0, sizeof(data)); + data.InStream = InStream; + data.location = (trio_pointer_t)source; + data.max = sourceSize; + data.error = 0; + +#if defined(USE_LOCALE) + if (NULL == internalLocaleValues) + { + TrioSetLocale(); + } +#endif + + status = TrioParse(TYPE_SCAN, format, parameters, arglist, argarray); + if (status < 0) + return status; + + status = TrioScanProcess(&data, format, parameters); + if (data.error != 0) + { + status = data.error; + } + return status; +} + +/************************************************************************* + * TrioInStreamFile + */ +TRIO_PRIVATE void +TrioInStreamFile +TRIO_ARGS2((self, intPointer), + trio_class_t *self, + int *intPointer) +{ + FILE *file = (FILE *)self->location; + + assert(VALID(self)); + assert(VALID(file)); + + self->current = fgetc(file); + if (self->current == EOF) + { + self->error = (ferror(file)) + ? TRIO_ERROR_RETURN(TRIO_ERRNO, 0) + : TRIO_ERROR_RETURN(TRIO_EOF, 0); + } + else + { + self->processed++; + self->committed++; + } + + if (VALID(intPointer)) + { + *intPointer = self->current; + } +} + +/************************************************************************* + * TrioInStreamFileDescriptor + */ +TRIO_PRIVATE void +TrioInStreamFileDescriptor +TRIO_ARGS2((self, intPointer), + trio_class_t *self, + int *intPointer) +{ + int fd = *((int *)self->location); + int size; + unsigned char input; + + assert(VALID(self)); + + size = read(fd, &input, sizeof(char)); + if (size == -1) + { + self->error = TRIO_ERROR_RETURN(TRIO_ERRNO, 0); + self->current = EOF; + } + else + { + self->current = (size == 0) ? EOF : input; + } + if (self->current != EOF) + { + self->committed++; + self->processed++; + } + + if (VALID(intPointer)) + { + *intPointer = self->current; + } +} + +/************************************************************************* + * TrioInStreamCustom + */ +TRIO_PRIVATE void +TrioInStreamCustom +TRIO_ARGS2((self, intPointer), + trio_class_t *self, + int *intPointer) +{ + trio_custom_t *data; + + assert(VALID(self)); + assert(VALID(self->location)); + + data = (trio_custom_t *)self->location; + + self->current = (data->stream.in == NULL) + ? NIL + : (data->stream.in)(data->closure); + + if (self->current == NIL) + { + self->current = EOF; + } + else + { + self->processed++; + self->committed++; + } + + if (VALID(intPointer)) + { + *intPointer = self->current; + } +} + +/************************************************************************* + * TrioInStreamString + */ +TRIO_PRIVATE void +TrioInStreamString +TRIO_ARGS2((self, intPointer), + trio_class_t *self, + int *intPointer) +{ + unsigned char **buffer; + + assert(VALID(self)); + assert(VALID(self->location)); + + buffer = (unsigned char **)self->location; + self->current = (*buffer)[0]; + if (self->current == NIL) + { + self->current = EOF; + } + else + { + (*buffer)++; + self->processed++; + self->committed++; + } + + if (VALID(intPointer)) + { + *intPointer = self->current; + } +} + +/************************************************************************* + * + * Formatted scanning functions + * + ************************************************************************/ + +#if defined(TRIO_DOCUMENTATION) +# include "doc/doc_scanf.h" +#endif +/** @addtogroup Scanf + @{ +*/ + +/************************************************************************* + * scanf + */ + +/** + Scan characters from standard input stream. + + @param format Formatting string. + @param ... Arguments. + @return Number of scanned characters. + */ +TRIO_PUBLIC int +trio_scanf +TRIO_VARGS2((format, va_alist), + TRIO_CONST char *format, + TRIO_VA_DECL) +{ + int status; + va_list args; + + assert(VALID(format)); + + TRIO_VA_START(args, format); + status = TrioScan((trio_pointer_t)stdin, 0, + TrioInStreamFile, + format, &args, NULL); + TRIO_VA_END(args); + return status; +} + +TRIO_PUBLIC int +trio_vscanf +TRIO_ARGS2((format, args), + TRIO_CONST char *format, + va_list args) +{ + assert(VALID(format)); + + return TrioScan((trio_pointer_t)stdin, 0, + TrioInStreamFile, + format, &args, NULL); +} + +TRIO_PUBLIC int +trio_scanfv +TRIO_ARGS2((format, args), + TRIO_CONST char *format, + trio_pointer_t *args) +{ + assert(VALID(format)); + + return TrioScan((trio_pointer_t)stdin, 0, + TrioInStreamFile, + format, NULL, args); +} + +/************************************************************************* + * fscanf + */ +TRIO_PUBLIC int +trio_fscanf +TRIO_VARGS3((file, format, va_alist), + FILE *file, + TRIO_CONST char *format, + TRIO_VA_DECL) +{ + int status; + va_list args; + + assert(VALID(file)); + assert(VALID(format)); + + TRIO_VA_START(args, format); + status = TrioScan((trio_pointer_t)file, 0, + TrioInStreamFile, + format, &args, NULL); + TRIO_VA_END(args); + return status; +} + +TRIO_PUBLIC int +trio_vfscanf +TRIO_ARGS3((file, format, args), + FILE *file, + TRIO_CONST char *format, + va_list args) +{ + assert(VALID(file)); + assert(VALID(format)); + + return TrioScan((trio_pointer_t)file, 0, + TrioInStreamFile, + format, &args, NULL); +} + +TRIO_PUBLIC int +trio_fscanfv +TRIO_ARGS3((file, format, args), + FILE *file, + TRIO_CONST char *format, + trio_pointer_t *args) +{ + assert(VALID(file)); + assert(VALID(format)); + + return TrioScan((trio_pointer_t)file, 0, + TrioInStreamFile, + format, NULL, args); +} + +/************************************************************************* + * dscanf + */ +TRIO_PUBLIC int +trio_dscanf +TRIO_VARGS3((fd, format, va_alist), + int fd, + TRIO_CONST char *format, + TRIO_VA_DECL) +{ + int status; + va_list args; + + assert(VALID(format)); + + TRIO_VA_START(args, format); + status = TrioScan((trio_pointer_t)&fd, 0, + TrioInStreamFileDescriptor, + format, &args, NULL); + TRIO_VA_END(args); + return status; +} + +TRIO_PUBLIC int +trio_vdscanf +TRIO_ARGS3((fd, format, args), + int fd, + TRIO_CONST char *format, + va_list args) +{ + assert(VALID(format)); + + return TrioScan((trio_pointer_t)&fd, 0, + TrioInStreamFileDescriptor, + format, &args, NULL); +} + +TRIO_PUBLIC int +trio_dscanfv +TRIO_ARGS3((fd, format, args), + int fd, + TRIO_CONST char *format, + trio_pointer_t *args) +{ + assert(VALID(format)); + + return TrioScan((trio_pointer_t)&fd, 0, + TrioInStreamFileDescriptor, + format, NULL, args); +} + +/************************************************************************* + * cscanf + */ +TRIO_PUBLIC int +trio_cscanf +TRIO_VARGS4((stream, closure, format, va_alist), + trio_instream_t stream, + trio_pointer_t closure, + TRIO_CONST char *format, + TRIO_VA_DECL) +{ + int status; + va_list args; + trio_custom_t data; + + assert(VALID(stream)); + assert(VALID(format)); + + TRIO_VA_START(args, format); + data.stream.in = stream; + data.closure = closure; + status = TrioScan(&data, 0, TrioInStreamCustom, format, &args, NULL); + TRIO_VA_END(args); + return status; +} + +TRIO_PUBLIC int +trio_vcscanf +TRIO_ARGS4((stream, closure, format, args), + trio_instream_t stream, + trio_pointer_t closure, + TRIO_CONST char *format, + va_list args) +{ + trio_custom_t data; + + assert(VALID(stream)); + assert(VALID(format)); + + data.stream.in = stream; + data.closure = closure; + return TrioScan(&data, 0, TrioInStreamCustom, format, &args, NULL); +} + +TRIO_PUBLIC int +trio_cscanfv +TRIO_ARGS4((stream, closure, format, args), + trio_instream_t stream, + trio_pointer_t closure, + TRIO_CONST char *format, + trio_pointer_t *args) +{ + trio_custom_t data; + + assert(VALID(stream)); + assert(VALID(format)); + + data.stream.in = stream; + data.closure = closure; + return TrioScan(&data, 0, TrioInStreamCustom, format, NULL, args); +} + +/************************************************************************* + * sscanf + */ +TRIO_PUBLIC int +trio_sscanf +TRIO_VARGS3((buffer, format, va_alist), + TRIO_CONST char *buffer, + TRIO_CONST char *format, + TRIO_VA_DECL) +{ + int status; + va_list args; + + assert(VALID(buffer)); + assert(VALID(format)); + + TRIO_VA_START(args, format); + status = TrioScan((trio_pointer_t)&buffer, 0, + TrioInStreamString, + format, &args, NULL); + TRIO_VA_END(args); + return status; +} + +TRIO_PUBLIC int +trio_vsscanf +TRIO_ARGS3((buffer, format, args), + TRIO_CONST char *buffer, + TRIO_CONST char *format, + va_list args) +{ + assert(VALID(buffer)); + assert(VALID(format)); + + return TrioScan((trio_pointer_t)&buffer, 0, + TrioInStreamString, + format, &args, NULL); +} + +TRIO_PUBLIC int +trio_sscanfv +TRIO_ARGS3((buffer, format, args), + TRIO_CONST char *buffer, + TRIO_CONST char *format, + trio_pointer_t *args) +{ + assert(VALID(buffer)); + assert(VALID(format)); + + return TrioScan((trio_pointer_t)&buffer, 0, + TrioInStreamString, + format, NULL, args); +} + +/** @} End of Scanf documentation module */ + +/************************************************************************* + * trio_strerror + */ +TRIO_PUBLIC TRIO_CONST char * +trio_strerror +TRIO_ARGS1((errorcode), + int errorcode) +{ + /* Textual versions of the error codes */ + switch (TRIO_ERROR_CODE(errorcode)) + { + case TRIO_EOF: + return "End of file"; + case TRIO_EINVAL: + return "Invalid argument"; + case TRIO_ETOOMANY: + return "Too many arguments"; + case TRIO_EDBLREF: + return "Double reference"; + case TRIO_EGAP: + return "Reference gap"; + case TRIO_ENOMEM: + return "Out of memory"; + case TRIO_ERANGE: + return "Invalid range"; + case TRIO_ECUSTOM: + return "Custom error"; + default: + return "Unknown"; + } +} diff --git a/android/native/libxml2/trio.h b/android/native/libxml2/trio.h new file mode 100644 index 0000000000..eab1b6d8fd --- /dev/null +++ b/android/native/libxml2/trio.h @@ -0,0 +1,216 @@ +/************************************************************************* + * + * $Id$ + * + * Copyright (C) 1998 Bjorn Reese and Daniel Stenberg. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND + * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER. + * + ************************************************************************* + * + * http://ctrio.sourceforge.net/ + * + ************************************************************************/ + +#ifndef TRIO_TRIO_H +#define TRIO_TRIO_H + +#if !defined(WITHOUT_TRIO) + +/* + * Use autoconf defines if present. Packages using trio must define + * HAVE_CONFIG_H as a compiler option themselves. + */ +#if defined(HAVE_CONFIG_H) +# include "config.h" +#endif + +#include "triodef.h" + +#include +#include +#if defined(TRIO_COMPILER_ANCIENT) +# include +#else +# include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Error codes. + * + * Remember to add a textual description to trio_strerror. + */ +enum { + TRIO_EOF = 1, + TRIO_EINVAL = 2, + TRIO_ETOOMANY = 3, + TRIO_EDBLREF = 4, + TRIO_EGAP = 5, + TRIO_ENOMEM = 6, + TRIO_ERANGE = 7, + TRIO_ERRNO = 8, + TRIO_ECUSTOM = 9 +}; + +/* Error macros */ +#define TRIO_ERROR_CODE(x) ((-(x)) & 0x00FF) +#define TRIO_ERROR_POSITION(x) ((-(x)) >> 8) +#define TRIO_ERROR_NAME(x) trio_strerror(x) + +typedef int (*trio_outstream_t) TRIO_PROTO((trio_pointer_t, int)); +typedef int (*trio_instream_t) TRIO_PROTO((trio_pointer_t)); + +TRIO_CONST char *trio_strerror TRIO_PROTO((int)); + +/************************************************************************* + * Print Functions + */ + +int trio_printf TRIO_PROTO((TRIO_CONST char *format, ...)); +int trio_vprintf TRIO_PROTO((TRIO_CONST char *format, va_list args)); +int trio_printfv TRIO_PROTO((TRIO_CONST char *format, void **args)); + +int trio_fprintf TRIO_PROTO((FILE *file, TRIO_CONST char *format, ...)); +int trio_vfprintf TRIO_PROTO((FILE *file, TRIO_CONST char *format, va_list args)); +int trio_fprintfv TRIO_PROTO((FILE *file, TRIO_CONST char *format, void **args)); + +int trio_dprintf TRIO_PROTO((int fd, TRIO_CONST char *format, ...)); +int trio_vdprintf TRIO_PROTO((int fd, TRIO_CONST char *format, va_list args)); +int trio_dprintfv TRIO_PROTO((int fd, TRIO_CONST char *format, void **args)); + +int trio_cprintf TRIO_PROTO((trio_outstream_t stream, trio_pointer_t closure, + TRIO_CONST char *format, ...)); +int trio_vcprintf TRIO_PROTO((trio_outstream_t stream, trio_pointer_t closure, + TRIO_CONST char *format, va_list args)); +int trio_cprintfv TRIO_PROTO((trio_outstream_t stream, trio_pointer_t closure, + TRIO_CONST char *format, void **args)); + +int trio_sprintf TRIO_PROTO((char *buffer, TRIO_CONST char *format, ...)); +int trio_vsprintf TRIO_PROTO((char *buffer, TRIO_CONST char *format, va_list args)); +int trio_sprintfv TRIO_PROTO((char *buffer, TRIO_CONST char *format, void **args)); + +int trio_snprintf TRIO_PROTO((char *buffer, size_t max, TRIO_CONST char *format, ...)); +int trio_vsnprintf TRIO_PROTO((char *buffer, size_t bufferSize, TRIO_CONST char *format, + va_list args)); +int trio_snprintfv TRIO_PROTO((char *buffer, size_t bufferSize, TRIO_CONST char *format, + void **args)); + +int trio_snprintfcat TRIO_PROTO((char *buffer, size_t max, TRIO_CONST char *format, ...)); +int trio_vsnprintfcat TRIO_PROTO((char *buffer, size_t bufferSize, TRIO_CONST char *format, + va_list args)); + +char *trio_aprintf TRIO_PROTO((TRIO_CONST char *format, ...)); +char *trio_vaprintf TRIO_PROTO((TRIO_CONST char *format, va_list args)); + +int trio_asprintf TRIO_PROTO((char **ret, TRIO_CONST char *format, ...)); +int trio_vasprintf TRIO_PROTO((char **ret, TRIO_CONST char *format, va_list args)); + +/************************************************************************* + * Scan Functions + */ +int trio_scanf TRIO_PROTO((TRIO_CONST char *format, ...)); +int trio_vscanf TRIO_PROTO((TRIO_CONST char *format, va_list args)); +int trio_scanfv TRIO_PROTO((TRIO_CONST char *format, void **args)); + +int trio_fscanf TRIO_PROTO((FILE *file, TRIO_CONST char *format, ...)); +int trio_vfscanf TRIO_PROTO((FILE *file, TRIO_CONST char *format, va_list args)); +int trio_fscanfv TRIO_PROTO((FILE *file, TRIO_CONST char *format, void **args)); + +int trio_dscanf TRIO_PROTO((int fd, TRIO_CONST char *format, ...)); +int trio_vdscanf TRIO_PROTO((int fd, TRIO_CONST char *format, va_list args)); +int trio_dscanfv TRIO_PROTO((int fd, TRIO_CONST char *format, void **args)); + +int trio_cscanf TRIO_PROTO((trio_instream_t stream, trio_pointer_t closure, + TRIO_CONST char *format, ...)); +int trio_vcscanf TRIO_PROTO((trio_instream_t stream, trio_pointer_t closure, + TRIO_CONST char *format, va_list args)); +int trio_cscanfv TRIO_PROTO((trio_instream_t stream, trio_pointer_t closure, + TRIO_CONST char *format, void **args)); + +int trio_sscanf TRIO_PROTO((TRIO_CONST char *buffer, TRIO_CONST char *format, ...)); +int trio_vsscanf TRIO_PROTO((TRIO_CONST char *buffer, TRIO_CONST char *format, va_list args)); +int trio_sscanfv TRIO_PROTO((TRIO_CONST char *buffer, TRIO_CONST char *format, void **args)); + +/************************************************************************* + * Locale Functions + */ +void trio_locale_set_decimal_point TRIO_PROTO((char *decimalPoint)); +void trio_locale_set_thousand_separator TRIO_PROTO((char *thousandSeparator)); +void trio_locale_set_grouping TRIO_PROTO((char *grouping)); + +/************************************************************************* + * Renaming + */ +#ifdef TRIO_REPLACE_STDIO +/* Replace the functions */ +#ifndef HAVE_PRINTF +# define printf trio_printf +#endif +#ifndef HAVE_VPRINTF +# define vprintf trio_vprintf +#endif +#ifndef HAVE_FPRINTF +# define fprintf trio_fprintf +#endif +#ifndef HAVE_VFPRINTF +# define vfprintf trio_vfprintf +#endif +#ifndef HAVE_SPRINTF +# define sprintf trio_sprintf +#endif +#ifndef HAVE_VSPRINTF +# define vsprintf trio_vsprintf +#endif +#ifndef HAVE_SNPRINTF +# define snprintf trio_snprintf +#endif +#ifndef HAVE_VSNPRINTF +# define vsnprintf trio_vsnprintf +#endif +#ifndef HAVE_SCANF +# define scanf trio_scanf +#endif +#ifndef HAVE_VSCANF +# define vscanf trio_vscanf +#endif +#ifndef HAVE_FSCANF +# define fscanf trio_fscanf +#endif +#ifndef HAVE_VFSCANF +# define vfscanf trio_vfscanf +#endif +#ifndef HAVE_SSCANF +# define sscanf trio_sscanf +#endif +#ifndef HAVE_VSSCANF +# define vsscanf trio_vsscanf +#endif +/* These aren't stdio functions, but we make them look similar */ +#define dprintf trio_dprintf +#define vdprintf trio_vdprintf +#define aprintf trio_aprintf +#define vaprintf trio_vaprintf +#define asprintf trio_asprintf +#define vasprintf trio_vasprintf +#define dscanf trio_dscanf +#define vdscanf trio_vdscanf +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* WITHOUT_TRIO */ + +#endif /* TRIO_TRIO_H */ diff --git a/android/native/libxml2/triodef.h b/android/native/libxml2/triodef.h new file mode 100644 index 0000000000..fa89416756 --- /dev/null +++ b/android/native/libxml2/triodef.h @@ -0,0 +1,222 @@ +/************************************************************************* + * + * $Id$ + * + * Copyright (C) 2001 Bjorn Reese + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND + * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER. + * + ************************************************************************/ + +#ifndef TRIO_TRIODEF_H +#define TRIO_TRIODEF_H + +/************************************************************************* + * Platform and compiler support detection + */ +#if defined(__GNUC__) +# define TRIO_COMPILER_GCC +#elif defined(__SUNPRO_C) +# define TRIO_COMPILER_SUNPRO +#elif defined(__SUNPRO_CC) +# define TRIO_COMPILER_SUNPRO +# define __SUNPRO_C __SUNPRO_CC +#elif defined(__xlC__) || defined(__IBMC__) || defined(__IBMCPP__) +# define TRIO_COMPILER_XLC +#elif defined(_AIX) && !defined(__GNUC__) +# define TRIO_COMPILER_XLC /* Workaround for old xlc */ +#elif defined(__DECC) || defined(__DECCXX) +# define TRIO_COMPILER_DECC +#elif defined(__osf__) && defined(__LANGUAGE_C__) +# define TRIO_COMPILER_DECC /* Workaround for old DEC C compilers */ +#elif defined(_MSC_VER) +# define TRIO_COMPILER_MSVC +#elif defined(__BORLANDC__) +# define TRIO_COMPILER_BCB +#endif + +#if defined(VMS) || defined(__VMS) +/* + * VMS is placed first to avoid identifying the platform as Unix + * based on the DECC compiler later on. + */ +# define TRIO_PLATFORM_VMS +#elif defined(unix) || defined(__unix) || defined(__unix__) +# define TRIO_PLATFORM_UNIX +#elif defined(TRIO_COMPILER_XLC) || defined(_AIX) +# define TRIO_PLATFORM_UNIX +#elif defined(TRIO_COMPILER_DECC) || defined(__osf___) +# define TRIO_PLATFORM_UNIX +#elif defined(__NetBSD__) +# define TRIO_PLATFORM_UNIX +#elif defined(__Lynx__) +# define TRIO_PLATFORM_UNIX +#elif defined(__QNX__) +# define TRIO_PLATFORM_UNIX +# define TRIO_PLATFORM_QNX +#elif defined(__CYGWIN__) +# define TRIO_PLATFORM_UNIX +#elif defined(AMIGA) && defined(TRIO_COMPILER_GCC) +# define TRIO_PLATFORM_UNIX +#elif defined(TRIO_COMPILER_MSVC) || defined(WIN32) || defined(_WIN32) +# define TRIO_PLATFORM_WIN32 +#elif defined(mpeix) || defined(__mpexl) +# define TRIO_PLATFORM_MPEIX +#endif + +#if defined(_AIX) +# define TRIO_PLATFORM_AIX +#elif defined(__hpux) +# define TRIO_PLATFORM_HPUX +#elif defined(sun) || defined(__sun__) +# if defined(__SVR4) || defined(__svr4__) +# define TRIO_PLATFORM_SOLARIS +# else +# define TRIO_PLATFORM_SUNOS +# endif +#endif + +#if defined(__STDC__) || defined(TRIO_COMPILER_MSVC) || defined(TRIO_COMPILER_BCB) +# define TRIO_COMPILER_SUPPORTS_C89 +# if defined(__STDC_VERSION__) +# define TRIO_COMPILER_SUPPORTS_C90 +# if (__STDC_VERSION__ >= 199409L) +# define TRIO_COMPILER_SUPPORTS_C94 +# endif +# if (__STDC_VERSION__ >= 199901L) +# define TRIO_COMPILER_SUPPORTS_C99 +# endif +# elif defined(TRIO_COMPILER_SUNPRO) +# if (__SUNPRO_C >= 0x420) +# define TRIO_COMPILER_SUPPORTS_C94 +# endif +# endif +#endif + +#if defined(_XOPEN_SOURCE) +# if defined(_XOPEN_SOURCE_EXTENDED) +# define TRIO_COMPILER_SUPPORTS_UNIX95 +# endif +# if (_XOPEN_VERSION >= 500) +# define TRIO_COMPILER_SUPPORTS_UNIX98 +# endif +# if (_XOPEN_VERSION >= 600) +# define TRIO_COMPILER_SUPPORTS_UNIX01 +# endif +#endif + +/************************************************************************* + * Generic defines + */ + +#if !defined(TRIO_PUBLIC) +# define TRIO_PUBLIC +#endif +#if !defined(TRIO_PRIVATE) +# define TRIO_PRIVATE static +#endif + +#if !(defined(TRIO_COMPILER_SUPPORTS_C89) || defined(__cplusplus)) +# define TRIO_COMPILER_ANCIENT +#endif + +#if defined(TRIO_COMPILER_ANCIENT) +# define TRIO_CONST +# define TRIO_VOLATILE +# define TRIO_SIGNED +typedef double trio_long_double_t; +typedef char * trio_pointer_t; +# define TRIO_SUFFIX_LONG(x) x +# define TRIO_PROTO(x) () +# define TRIO_NOARGS +# define TRIO_ARGS1(list,a1) list a1; +# define TRIO_ARGS2(list,a1,a2) list a1; a2; +# define TRIO_ARGS3(list,a1,a2,a3) list a1; a2; a3; +# define TRIO_ARGS4(list,a1,a2,a3,a4) list a1; a2; a3; a4; +# define TRIO_ARGS5(list,a1,a2,a3,a4,a5) list a1; a2; a3; a4; a5; +# define TRIO_ARGS6(list,a1,a2,a3,a4,a5,a6) list a1; a2; a3; a4; a5; a6; +# define TRIO_VARGS2(list,a1,a2) list a1; a2 +# define TRIO_VARGS3(list,a1,a2,a3) list a1; a2; a3 +# define TRIO_VARGS4(list,a1,a2,a3,a4) list a1; a2; a3; a4 +# define TRIO_VARGS5(list,a1,a2,a3,a4,a5) list a1; a2; a3; a4; a5 +# define TRIO_VA_DECL va_dcl +# define TRIO_VA_START(x,y) va_start(x) +# define TRIO_VA_END(x) va_end(x) +#else /* ANSI C */ +# define TRIO_CONST const +# define TRIO_VOLATILE volatile +# define TRIO_SIGNED signed +typedef long double trio_long_double_t; +typedef void * trio_pointer_t; +# define TRIO_SUFFIX_LONG(x) x ## L +# define TRIO_PROTO(x) x +# define TRIO_NOARGS void +# define TRIO_ARGS1(list,a1) (a1) +# define TRIO_ARGS2(list,a1,a2) (a1,a2) +# define TRIO_ARGS3(list,a1,a2,a3) (a1,a2,a3) +# define TRIO_ARGS4(list,a1,a2,a3,a4) (a1,a2,a3,a4) +# define TRIO_ARGS5(list,a1,a2,a3,a4,a5) (a1,a2,a3,a4,a5) +# define TRIO_ARGS6(list,a1,a2,a3,a4,a5,a6) (a1,a2,a3,a4,a5,a6) +# define TRIO_VARGS2 TRIO_ARGS2 +# define TRIO_VARGS3 TRIO_ARGS3 +# define TRIO_VARGS4 TRIO_ARGS4 +# define TRIO_VARGS5 TRIO_ARGS5 +# define TRIO_VA_DECL ... +# define TRIO_VA_START(x,y) va_start(x,y) +# define TRIO_VA_END(x) va_end(x) +#endif + +#if defined(TRIO_COMPILER_SUPPORTS_C99) || defined(__cplusplus) +# define TRIO_INLINE inline +#elif defined(TRIO_COMPILER_GCC) +# define TRIO_INLINE __inline__ +#elif defined(TRIO_COMPILER_MSVC) +# define TRIO_INLINE _inline +#elif defined(TRIO_COMPILER_BCB) +# define TRIO_INLINE __inline +#else +# define TRIO_INLINE +#endif + +/************************************************************************* + * Workarounds + */ + +#if defined(TRIO_PLATFORM_VMS) +/* + * Computations done with constants at compile time can trigger these + * even when compiling with IEEE enabled. + */ +# pragma message disable (UNDERFLOW, FLOATOVERFL) + +# if (__CRTL_VER < 80000000) +/* + * Although the compiler supports C99 language constructs, the C + * run-time library does not contain all C99 functions. + * + * This was the case for 70300022. Update the 80000000 value when + * it has been accurately determined what version of the library + * supports C99. + */ +# if defined(TRIO_COMPILER_SUPPORTS_C99) +# undef TRIO_COMPILER_SUPPORTS_C99 +# endif +# endif +#endif + +/* + * Not all preprocessors supports the LL token. + */ +#if defined(TRIO_COMPILER_BCB) +#else +# define TRIO_COMPILER_SUPPORTS_LL +#endif + +#endif /* TRIO_TRIODEF_H */ diff --git a/android/native/libxml2/trionan.c b/android/native/libxml2/trionan.c new file mode 100644 index 0000000000..95baae1e02 --- /dev/null +++ b/android/native/libxml2/trionan.c @@ -0,0 +1,914 @@ +/************************************************************************* + * + * $Id$ + * + * Copyright (C) 2001 Bjorn Reese + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND + * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER. + * + ************************************************************************ + * + * Functions to handle special quantities in floating-point numbers + * (that is, NaNs and infinity). They provide the capability to detect + * and fabricate special quantities. + * + * Although written to be as portable as possible, it can never be + * guaranteed to work on all platforms, as not all hardware supports + * special quantities. + * + * The approach used here (approximately) is to: + * + * 1. Use C99 functionality when available. + * 2. Use IEEE 754 bit-patterns if possible. + * 3. Use platform-specific techniques. + * + ************************************************************************/ + +/* + * TODO: + * o Put all the magic into trio_fpclassify_and_signbit(), and use this from + * trio_isnan() etc. + */ + +/************************************************************************* + * Include files + */ +#include "triodef.h" +#include "trionan.h" + +#include +#include +#include +#include +#if defined(TRIO_PLATFORM_UNIX) +# include +#endif +#if defined(TRIO_COMPILER_DECC) +# if defined(__linux__) +# include +# else +# include +# endif +#endif +#include + +#if defined(TRIO_DOCUMENTATION) +# include "doc/doc_nan.h" +#endif +/** @addtogroup SpecialQuantities + @{ +*/ + +/************************************************************************* + * Definitions + */ + +#define TRIO_TRUE (1 == 1) +#define TRIO_FALSE (0 == 1) + +/* + * We must enable IEEE floating-point on Alpha + */ +#if defined(__alpha) && !defined(_IEEE_FP) +# if defined(TRIO_COMPILER_DECC) +# if defined(TRIO_PLATFORM_VMS) +# error "Must be compiled with option /IEEE_MODE=UNDERFLOW_TO_ZERO/FLOAT=IEEE" +# else +# if !defined(_CFE) +# error "Must be compiled with option -ieee" +# endif +# endif +# elif defined(TRIO_COMPILER_GCC) && (defined(__osf__) || defined(__linux__)) +# error "Must be compiled with option -mieee" +# endif +#endif /* __alpha && ! _IEEE_FP */ + +/* + * In ANSI/IEEE 754-1985 64-bits double format numbers have the + * following properties (amoungst others) + * + * o FLT_RADIX == 2: binary encoding + * o DBL_MAX_EXP == 1024: 11 bits exponent, where one bit is used + * to indicate special numbers (e.g. NaN and Infinity), so the + * maximum exponent is 10 bits wide (2^10 == 1024). + * o DBL_MANT_DIG == 53: The mantissa is 52 bits wide, but because + * numbers are normalized the initial binary 1 is represented + * implicitly (the so-called "hidden bit"), which leaves us with + * the ability to represent 53 bits wide mantissa. + */ +#if (FLT_RADIX == 2) && (DBL_MAX_EXP == 1024) && (DBL_MANT_DIG == 53) +# define USE_IEEE_754 +#endif + + +/************************************************************************* + * Constants + */ + +static TRIO_CONST char rcsid[] = "@(#)$Id$"; + +#if defined(USE_IEEE_754) + +/* + * Endian-agnostic indexing macro. + * + * The value of internalEndianMagic, when converted into a 64-bit + * integer, becomes 0x0706050403020100 (we could have used a 64-bit + * integer value instead of a double, but not all platforms supports + * that type). The value is automatically encoded with the correct + * endianess by the compiler, which means that we can support any + * kind of endianess. The individual bytes are then used as an index + * for the IEEE 754 bit-patterns and masks. + */ +#define TRIO_DOUBLE_INDEX(x) (((unsigned char *)&internalEndianMagic)[7-(x)]) + +#if (defined(__BORLANDC__) && __BORLANDC__ >= 0x0590) +static TRIO_CONST double internalEndianMagic = 7.949928895127362e-275; +#else +static TRIO_CONST double internalEndianMagic = 7.949928895127363e-275; +#endif + +/* Mask for the exponent */ +static TRIO_CONST unsigned char ieee_754_exponent_mask[] = { + 0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +/* Mask for the mantissa */ +static TRIO_CONST unsigned char ieee_754_mantissa_mask[] = { + 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + +/* Mask for the sign bit */ +static TRIO_CONST unsigned char ieee_754_sign_mask[] = { + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +/* Bit-pattern for negative zero */ +static TRIO_CONST unsigned char ieee_754_negzero_array[] = { + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +/* Bit-pattern for infinity */ +static TRIO_CONST unsigned char ieee_754_infinity_array[] = { + 0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +/* Bit-pattern for quiet NaN */ +static TRIO_CONST unsigned char ieee_754_qnan_array[] = { + 0x7F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + + +/************************************************************************* + * Functions + */ + +/* + * trio_make_double + */ +TRIO_PRIVATE double +trio_make_double +TRIO_ARGS1((values), + TRIO_CONST unsigned char *values) +{ + TRIO_VOLATILE double result; + int i; + + for (i = 0; i < (int)sizeof(double); i++) { + ((TRIO_VOLATILE unsigned char *)&result)[TRIO_DOUBLE_INDEX(i)] = values[i]; + } + return result; +} + +/* + * trio_is_special_quantity + */ +TRIO_PRIVATE int +trio_is_special_quantity +TRIO_ARGS2((number, has_mantissa), + double number, + int *has_mantissa) +{ + unsigned int i; + unsigned char current; + int is_special_quantity = TRIO_TRUE; + + *has_mantissa = 0; + + for (i = 0; i < (unsigned int)sizeof(double); i++) { + current = ((unsigned char *)&number)[TRIO_DOUBLE_INDEX(i)]; + is_special_quantity + &= ((current & ieee_754_exponent_mask[i]) == ieee_754_exponent_mask[i]); + *has_mantissa |= (current & ieee_754_mantissa_mask[i]); + } + return is_special_quantity; +} + +/* + * trio_is_negative + */ +TRIO_PRIVATE int +trio_is_negative +TRIO_ARGS1((number), + double number) +{ + unsigned int i; + int is_negative = TRIO_FALSE; + + for (i = 0; i < (unsigned int)sizeof(double); i++) { + is_negative |= (((unsigned char *)&number)[TRIO_DOUBLE_INDEX(i)] + & ieee_754_sign_mask[i]); + } + return is_negative; +} + +#endif /* USE_IEEE_754 */ + + +/** + Generate negative zero. + + @return Floating-point representation of negative zero. +*/ +TRIO_PUBLIC double +trio_nzero(TRIO_NOARGS) +{ +#if defined(USE_IEEE_754) + return trio_make_double(ieee_754_negzero_array); +#else + TRIO_VOLATILE double zero = 0.0; + + return -zero; +#endif +} + +/** + Generate positive infinity. + + @return Floating-point representation of positive infinity. +*/ +TRIO_PUBLIC double +trio_pinf(TRIO_NOARGS) +{ + /* Cache the result */ + static double result = 0.0; + + if (result == 0.0) { + +#if defined(INFINITY) && defined(__STDC_IEC_559__) + result = (double)INFINITY; + +#elif defined(USE_IEEE_754) + result = trio_make_double(ieee_754_infinity_array); + +#else + /* + * If HUGE_VAL is different from DBL_MAX, then HUGE_VAL is used + * as infinity. Otherwise we have to resort to an overflow + * operation to generate infinity. + */ +# if defined(TRIO_PLATFORM_UNIX) + void (*signal_handler)(int) = signal(SIGFPE, SIG_IGN); +# endif + + result = HUGE_VAL; + if (HUGE_VAL == DBL_MAX) { + /* Force overflow */ + result += HUGE_VAL; + } + +# if defined(TRIO_PLATFORM_UNIX) + signal(SIGFPE, signal_handler); +# endif + +#endif + } + return result; +} + +/** + Generate negative infinity. + + @return Floating-point value of negative infinity. +*/ +TRIO_PUBLIC double +trio_ninf(TRIO_NOARGS) +{ + static double result = 0.0; + + if (result == 0.0) { + /* + * Negative infinity is calculated by negating positive infinity, + * which can be done because it is legal to do calculations on + * infinity (for example, 1 / infinity == 0). + */ + result = -trio_pinf(); + } + return result; +} + +/** + Generate NaN. + + @return Floating-point representation of NaN. +*/ +TRIO_PUBLIC double +trio_nan(TRIO_NOARGS) +{ + /* Cache the result */ + static double result = 0.0; + + if (result == 0.0) { + +#if defined(TRIO_COMPILER_SUPPORTS_C99) + result = nan(""); + +#elif defined(NAN) && defined(__STDC_IEC_559__) + result = (double)NAN; + +#elif defined(USE_IEEE_754) + result = trio_make_double(ieee_754_qnan_array); + +#else + /* + * There are several ways to generate NaN. The one used here is + * to divide infinity by infinity. I would have preferred to add + * negative infinity to positive infinity, but that yields wrong + * result (infinity) on FreeBSD. + * + * This may fail if the hardware does not support NaN, or if + * the Invalid Operation floating-point exception is unmasked. + */ +# if defined(TRIO_PLATFORM_UNIX) + void (*signal_handler)(int) = signal(SIGFPE, SIG_IGN); +# endif + + result = trio_pinf() / trio_pinf(); + +# if defined(TRIO_PLATFORM_UNIX) + signal(SIGFPE, signal_handler); +# endif + +#endif + } + return result; +} + +/** + Check for NaN. + + @param number An arbitrary floating-point number. + @return Boolean value indicating whether or not the number is a NaN. +*/ +TRIO_PUBLIC int +trio_isnan +TRIO_ARGS1((number), + double number) +{ +#if (defined(TRIO_COMPILER_SUPPORTS_C99) && defined(isnan)) \ + || defined(TRIO_COMPILER_SUPPORTS_UNIX95) + /* + * C99 defines isnan() as a macro. UNIX95 defines isnan() as a + * function. This function was already present in XPG4, but this + * is a bit tricky to detect with compiler defines, so we choose + * the conservative approach and only use it for UNIX95. + */ + return isnan(number); + +#elif defined(TRIO_COMPILER_MSVC) || defined(TRIO_COMPILER_BCB) + /* + * Microsoft Visual C++ and Borland C++ Builder have an _isnan() + * function. + */ + return _isnan(number) ? TRIO_TRUE : TRIO_FALSE; + +#elif defined(USE_IEEE_754) + /* + * Examine IEEE 754 bit-pattern. A NaN must have a special exponent + * pattern, and a non-empty mantissa. + */ + int has_mantissa; + int is_special_quantity; + + is_special_quantity = trio_is_special_quantity(number, &has_mantissa); + + return (is_special_quantity && has_mantissa); + +#else + /* + * Fallback solution + */ + int status; + double integral, fraction; + +# if defined(TRIO_PLATFORM_UNIX) + void (*signal_handler)(int) = signal(SIGFPE, SIG_IGN); +# endif + + status = (/* + * NaN is the only number which does not compare to itself + */ + ((TRIO_VOLATILE double)number != (TRIO_VOLATILE double)number) || + /* + * Fallback solution if NaN compares to NaN + */ + ((number != 0.0) && + (fraction = modf(number, &integral), + integral == fraction))); + +# if defined(TRIO_PLATFORM_UNIX) + signal(SIGFPE, signal_handler); +# endif + + return status; + +#endif +} + +/** + Check for infinity. + + @param number An arbitrary floating-point number. + @return 1 if positive infinity, -1 if negative infinity, 0 otherwise. +*/ +TRIO_PUBLIC int +trio_isinf +TRIO_ARGS1((number), + double number) +{ +#if defined(TRIO_COMPILER_DECC) && !defined(__linux__) + /* + * DECC has an isinf() macro, but it works differently than that + * of C99, so we use the fp_class() function instead. + */ + return ((fp_class(number) == FP_POS_INF) + ? 1 + : ((fp_class(number) == FP_NEG_INF) ? -1 : 0)); + +#elif defined(isinf) + /* + * C99 defines isinf() as a macro. + */ + return isinf(number) + ? ((number > 0.0) ? 1 : -1) + : 0; + +#elif defined(TRIO_COMPILER_MSVC) || defined(TRIO_COMPILER_BCB) + /* + * Microsoft Visual C++ and Borland C++ Builder have an _fpclass() + * function that can be used to detect infinity. + */ + return ((_fpclass(number) == _FPCLASS_PINF) + ? 1 + : ((_fpclass(number) == _FPCLASS_NINF) ? -1 : 0)); + +#elif defined(USE_IEEE_754) + /* + * Examine IEEE 754 bit-pattern. Infinity must have a special exponent + * pattern, and an empty mantissa. + */ + int has_mantissa; + int is_special_quantity; + + is_special_quantity = trio_is_special_quantity(number, &has_mantissa); + + return (is_special_quantity && !has_mantissa) + ? ((number < 0.0) ? -1 : 1) + : 0; + +#else + /* + * Fallback solution. + */ + int status; + +# if defined(TRIO_PLATFORM_UNIX) + void (*signal_handler)(int) = signal(SIGFPE, SIG_IGN); +# endif + + double infinity = trio_pinf(); + + status = ((number == infinity) + ? 1 + : ((number == -infinity) ? -1 : 0)); + +# if defined(TRIO_PLATFORM_UNIX) + signal(SIGFPE, signal_handler); +# endif + + return status; + +#endif +} + +#if 0 + /* Temporary fix - this routine is not used anywhere */ +/** + Check for finity. + + @param number An arbitrary floating-point number. + @return Boolean value indicating whether or not the number is a finite. +*/ +TRIO_PUBLIC int +trio_isfinite +TRIO_ARGS1((number), + double number) +{ +#if defined(TRIO_COMPILER_SUPPORTS_C99) && defined(isfinite) + /* + * C99 defines isfinite() as a macro. + */ + return isfinite(number); + +#elif defined(TRIO_COMPILER_MSVC) || defined(TRIO_COMPILER_BCB) + /* + * Microsoft Visual C++ and Borland C++ Builder use _finite(). + */ + return _finite(number); + +#elif defined(USE_IEEE_754) + /* + * Examine IEEE 754 bit-pattern. For finity we do not care about the + * mantissa. + */ + int dummy; + + return (! trio_is_special_quantity(number, &dummy)); + +#else + /* + * Fallback solution. + */ + return ((trio_isinf(number) == 0) && (trio_isnan(number) == 0)); + +#endif +} + +#endif + +/* + * The sign of NaN is always false + */ +TRIO_PUBLIC int +trio_fpclassify_and_signbit +TRIO_ARGS2((number, is_negative), + double number, + int *is_negative) +{ +#if defined(fpclassify) && defined(signbit) + /* + * C99 defines fpclassify() and signbit() as a macros + */ + *is_negative = signbit(number); + switch (fpclassify(number)) { + case FP_NAN: + return TRIO_FP_NAN; + case FP_INFINITE: + return TRIO_FP_INFINITE; + case FP_SUBNORMAL: + return TRIO_FP_SUBNORMAL; + case FP_ZERO: + return TRIO_FP_ZERO; + default: + return TRIO_FP_NORMAL; + } + +#else +# if defined(TRIO_COMPILER_DECC) + /* + * DECC has an fp_class() function. + */ +# define TRIO_FPCLASSIFY(n) fp_class(n) +# define TRIO_QUIET_NAN FP_QNAN +# define TRIO_SIGNALLING_NAN FP_SNAN +# define TRIO_POSITIVE_INFINITY FP_POS_INF +# define TRIO_NEGATIVE_INFINITY FP_NEG_INF +# define TRIO_POSITIVE_SUBNORMAL FP_POS_DENORM +# define TRIO_NEGATIVE_SUBNORMAL FP_NEG_DENORM +# define TRIO_POSITIVE_ZERO FP_POS_ZERO +# define TRIO_NEGATIVE_ZERO FP_NEG_ZERO +# define TRIO_POSITIVE_NORMAL FP_POS_NORM +# define TRIO_NEGATIVE_NORMAL FP_NEG_NORM + +# elif defined(TRIO_COMPILER_MSVC) || defined(TRIO_COMPILER_BCB) + /* + * Microsoft Visual C++ and Borland C++ Builder have an _fpclass() + * function. + */ +# define TRIO_FPCLASSIFY(n) _fpclass(n) +# define TRIO_QUIET_NAN _FPCLASS_QNAN +# define TRIO_SIGNALLING_NAN _FPCLASS_SNAN +# define TRIO_POSITIVE_INFINITY _FPCLASS_PINF +# define TRIO_NEGATIVE_INFINITY _FPCLASS_NINF +# define TRIO_POSITIVE_SUBNORMAL _FPCLASS_PD +# define TRIO_NEGATIVE_SUBNORMAL _FPCLASS_ND +# define TRIO_POSITIVE_ZERO _FPCLASS_PZ +# define TRIO_NEGATIVE_ZERO _FPCLASS_NZ +# define TRIO_POSITIVE_NORMAL _FPCLASS_PN +# define TRIO_NEGATIVE_NORMAL _FPCLASS_NN + +# elif defined(FP_PLUS_NORM) + /* + * HP-UX 9.x and 10.x have an fpclassify() function, that is different + * from the C99 fpclassify() macro supported on HP-UX 11.x. + * + * AIX has class() for C, and _class() for C++, which returns the + * same values as the HP-UX fpclassify() function. + */ +# if defined(TRIO_PLATFORM_AIX) +# if defined(__cplusplus) +# define TRIO_FPCLASSIFY(n) _class(n) +# else +# define TRIO_FPCLASSIFY(n) class(n) +# endif +# else +# define TRIO_FPCLASSIFY(n) fpclassify(n) +# endif +# define TRIO_QUIET_NAN FP_QNAN +# define TRIO_SIGNALLING_NAN FP_SNAN +# define TRIO_POSITIVE_INFINITY FP_PLUS_INF +# define TRIO_NEGATIVE_INFINITY FP_MINUS_INF +# define TRIO_POSITIVE_SUBNORMAL FP_PLUS_DENORM +# define TRIO_NEGATIVE_SUBNORMAL FP_MINUS_DENORM +# define TRIO_POSITIVE_ZERO FP_PLUS_ZERO +# define TRIO_NEGATIVE_ZERO FP_MINUS_ZERO +# define TRIO_POSITIVE_NORMAL FP_PLUS_NORM +# define TRIO_NEGATIVE_NORMAL FP_MINUS_NORM +# endif + +# if defined(TRIO_FPCLASSIFY) + switch (TRIO_FPCLASSIFY(number)) { + case TRIO_QUIET_NAN: + case TRIO_SIGNALLING_NAN: + *is_negative = TRIO_FALSE; /* NaN has no sign */ + return TRIO_FP_NAN; + case TRIO_POSITIVE_INFINITY: + *is_negative = TRIO_FALSE; + return TRIO_FP_INFINITE; + case TRIO_NEGATIVE_INFINITY: + *is_negative = TRIO_TRUE; + return TRIO_FP_INFINITE; + case TRIO_POSITIVE_SUBNORMAL: + *is_negative = TRIO_FALSE; + return TRIO_FP_SUBNORMAL; + case TRIO_NEGATIVE_SUBNORMAL: + *is_negative = TRIO_TRUE; + return TRIO_FP_SUBNORMAL; + case TRIO_POSITIVE_ZERO: + *is_negative = TRIO_FALSE; + return TRIO_FP_ZERO; + case TRIO_NEGATIVE_ZERO: + *is_negative = TRIO_TRUE; + return TRIO_FP_ZERO; + case TRIO_POSITIVE_NORMAL: + *is_negative = TRIO_FALSE; + return TRIO_FP_NORMAL; + case TRIO_NEGATIVE_NORMAL: + *is_negative = TRIO_TRUE; + return TRIO_FP_NORMAL; + default: + /* Just in case... */ + *is_negative = (number < 0.0); + return TRIO_FP_NORMAL; + } + +# else + /* + * Fallback solution. + */ + int rc; + + if (number == 0.0) { + /* + * In IEEE 754 the sign of zero is ignored in comparisons, so we + * have to handle this as a special case by examining the sign bit + * directly. + */ +# if defined(USE_IEEE_754) + *is_negative = trio_is_negative(number); +# else + *is_negative = TRIO_FALSE; /* FIXME */ +# endif + return TRIO_FP_ZERO; + } + if (trio_isnan(number)) { + *is_negative = TRIO_FALSE; + return TRIO_FP_NAN; + } + if ((rc = trio_isinf(number))) { + *is_negative = (rc == -1); + return TRIO_FP_INFINITE; + } + if ((number > 0.0) && (number < DBL_MIN)) { + *is_negative = TRIO_FALSE; + return TRIO_FP_SUBNORMAL; + } + if ((number < 0.0) && (number > -DBL_MIN)) { + *is_negative = TRIO_TRUE; + return TRIO_FP_SUBNORMAL; + } + *is_negative = (number < 0.0); + return TRIO_FP_NORMAL; + +# endif +#endif +} + +/** + Examine the sign of a number. + + @param number An arbitrary floating-point number. + @return Boolean value indicating whether or not the number has the + sign bit set (i.e. is negative). +*/ +TRIO_PUBLIC int +trio_signbit +TRIO_ARGS1((number), + double number) +{ + int is_negative; + + (void)trio_fpclassify_and_signbit(number, &is_negative); + return is_negative; +} + +#if 0 + /* Temporary fix - this routine is not used in libxml */ +/** + Examine the class of a number. + + @param number An arbitrary floating-point number. + @return Enumerable value indicating the class of @p number +*/ +TRIO_PUBLIC int +trio_fpclassify +TRIO_ARGS1((number), + double number) +{ + int dummy; + + return trio_fpclassify_and_signbit(number, &dummy); +} + +#endif + +/** @} SpecialQuantities */ + +/************************************************************************* + * For test purposes. + * + * Add the following compiler option to include this test code. + * + * Unix : -DSTANDALONE + * VMS : /DEFINE=(STANDALONE) + */ +#if defined(STANDALONE) +# include + +static TRIO_CONST char * +getClassification +TRIO_ARGS1((type), + int type) +{ + switch (type) { + case TRIO_FP_INFINITE: + return "FP_INFINITE"; + case TRIO_FP_NAN: + return "FP_NAN"; + case TRIO_FP_NORMAL: + return "FP_NORMAL"; + case TRIO_FP_SUBNORMAL: + return "FP_SUBNORMAL"; + case TRIO_FP_ZERO: + return "FP_ZERO"; + default: + return "FP_UNKNOWN"; + } +} + +static void +print_class +TRIO_ARGS2((prefix, number), + TRIO_CONST char *prefix, + double number) +{ + printf("%-6s: %s %-15s %g\n", + prefix, + trio_signbit(number) ? "-" : "+", + getClassification(TRIO_FPCLASSIFY(number)), + number); +} + +int main(TRIO_NOARGS) +{ + double my_nan; + double my_pinf; + double my_ninf; +# if defined(TRIO_PLATFORM_UNIX) + void (*signal_handler) TRIO_PROTO((int)); +# endif + + my_nan = trio_nan(); + my_pinf = trio_pinf(); + my_ninf = trio_ninf(); + + print_class("Nan", my_nan); + print_class("PInf", my_pinf); + print_class("NInf", my_ninf); + print_class("PZero", 0.0); + print_class("NZero", -0.0); + print_class("PNorm", 1.0); + print_class("NNorm", -1.0); + print_class("PSub", 1.01e-307 - 1.00e-307); + print_class("NSub", 1.00e-307 - 1.01e-307); + + printf("NaN : %4g 0x%02x%02x%02x%02x%02x%02x%02x%02x (%2d, %2d)\n", + my_nan, + ((unsigned char *)&my_nan)[0], + ((unsigned char *)&my_nan)[1], + ((unsigned char *)&my_nan)[2], + ((unsigned char *)&my_nan)[3], + ((unsigned char *)&my_nan)[4], + ((unsigned char *)&my_nan)[5], + ((unsigned char *)&my_nan)[6], + ((unsigned char *)&my_nan)[7], + trio_isnan(my_nan), trio_isinf(my_nan)); + printf("PInf: %4g 0x%02x%02x%02x%02x%02x%02x%02x%02x (%2d, %2d)\n", + my_pinf, + ((unsigned char *)&my_pinf)[0], + ((unsigned char *)&my_pinf)[1], + ((unsigned char *)&my_pinf)[2], + ((unsigned char *)&my_pinf)[3], + ((unsigned char *)&my_pinf)[4], + ((unsigned char *)&my_pinf)[5], + ((unsigned char *)&my_pinf)[6], + ((unsigned char *)&my_pinf)[7], + trio_isnan(my_pinf), trio_isinf(my_pinf)); + printf("NInf: %4g 0x%02x%02x%02x%02x%02x%02x%02x%02x (%2d, %2d)\n", + my_ninf, + ((unsigned char *)&my_ninf)[0], + ((unsigned char *)&my_ninf)[1], + ((unsigned char *)&my_ninf)[2], + ((unsigned char *)&my_ninf)[3], + ((unsigned char *)&my_ninf)[4], + ((unsigned char *)&my_ninf)[5], + ((unsigned char *)&my_ninf)[6], + ((unsigned char *)&my_ninf)[7], + trio_isnan(my_ninf), trio_isinf(my_ninf)); + +# if defined(TRIO_PLATFORM_UNIX) + signal_handler = signal(SIGFPE, SIG_IGN); +# endif + + my_pinf = DBL_MAX + DBL_MAX; + my_ninf = -my_pinf; + my_nan = my_pinf / my_pinf; + +# if defined(TRIO_PLATFORM_UNIX) + signal(SIGFPE, signal_handler); +# endif + + printf("NaN : %4g 0x%02x%02x%02x%02x%02x%02x%02x%02x (%2d, %2d)\n", + my_nan, + ((unsigned char *)&my_nan)[0], + ((unsigned char *)&my_nan)[1], + ((unsigned char *)&my_nan)[2], + ((unsigned char *)&my_nan)[3], + ((unsigned char *)&my_nan)[4], + ((unsigned char *)&my_nan)[5], + ((unsigned char *)&my_nan)[6], + ((unsigned char *)&my_nan)[7], + trio_isnan(my_nan), trio_isinf(my_nan)); + printf("PInf: %4g 0x%02x%02x%02x%02x%02x%02x%02x%02x (%2d, %2d)\n", + my_pinf, + ((unsigned char *)&my_pinf)[0], + ((unsigned char *)&my_pinf)[1], + ((unsigned char *)&my_pinf)[2], + ((unsigned char *)&my_pinf)[3], + ((unsigned char *)&my_pinf)[4], + ((unsigned char *)&my_pinf)[5], + ((unsigned char *)&my_pinf)[6], + ((unsigned char *)&my_pinf)[7], + trio_isnan(my_pinf), trio_isinf(my_pinf)); + printf("NInf: %4g 0x%02x%02x%02x%02x%02x%02x%02x%02x (%2d, %2d)\n", + my_ninf, + ((unsigned char *)&my_ninf)[0], + ((unsigned char *)&my_ninf)[1], + ((unsigned char *)&my_ninf)[2], + ((unsigned char *)&my_ninf)[3], + ((unsigned char *)&my_ninf)[4], + ((unsigned char *)&my_ninf)[5], + ((unsigned char *)&my_ninf)[6], + ((unsigned char *)&my_ninf)[7], + trio_isnan(my_ninf), trio_isinf(my_ninf)); + + return 0; +} +#endif diff --git a/android/native/libxml2/trionan.h b/android/native/libxml2/trionan.h new file mode 100644 index 0000000000..c5de32b0ca --- /dev/null +++ b/android/native/libxml2/trionan.h @@ -0,0 +1,84 @@ +/************************************************************************* + * + * $Id$ + * + * Copyright (C) 2001 Bjorn Reese + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND + * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER. + * + ************************************************************************/ + +#ifndef TRIO_NAN_H +#define TRIO_NAN_H + +#include "triodef.h" + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + TRIO_FP_INFINITE, + TRIO_FP_NAN, + TRIO_FP_NORMAL, + TRIO_FP_SUBNORMAL, + TRIO_FP_ZERO +}; + +/* + * Return NaN (Not-a-Number). + */ +TRIO_PUBLIC double trio_nan TRIO_PROTO((void)); + +/* + * Return positive infinity. + */ +TRIO_PUBLIC double trio_pinf TRIO_PROTO((void)); + +/* + * Return negative infinity. + */ +TRIO_PUBLIC double trio_ninf TRIO_PROTO((void)); + +/* + * Return negative zero. + */ +TRIO_PUBLIC double trio_nzero TRIO_PROTO((TRIO_NOARGS)); + +/* + * If number is a NaN return non-zero, otherwise return zero. + */ +TRIO_PUBLIC int trio_isnan TRIO_PROTO((double number)); + +/* + * If number is positive infinity return 1, if number is negative + * infinity return -1, otherwise return 0. + */ +TRIO_PUBLIC int trio_isinf TRIO_PROTO((double number)); + +/* + * If number is finite return non-zero, otherwise return zero. + */ +#if 0 + /* Temporary fix - these 2 routines not used in libxml */ +TRIO_PUBLIC int trio_isfinite TRIO_PROTO((double number)); + +TRIO_PUBLIC int trio_fpclassify TRIO_PROTO((double number)); +#endif + +TRIO_PUBLIC int trio_signbit TRIO_PROTO((double number)); + +TRIO_PUBLIC int trio_fpclassify_and_signbit TRIO_PROTO((double number, int *is_negative)); + +#ifdef __cplusplus +} +#endif + +#endif /* TRIO_NAN_H */ diff --git a/android/native/libxml2/triop.h b/android/native/libxml2/triop.h new file mode 100644 index 0000000000..8462c56f87 --- /dev/null +++ b/android/native/libxml2/triop.h @@ -0,0 +1,150 @@ +/************************************************************************* + * + * $Id$ + * + * Copyright (C) 2000 Bjorn Reese and Daniel Stenberg. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND + * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER. + * + ************************************************************************ + * + * Private functions, types, etc. used for callback functions. + * + * The ref pointer is an opaque type and should remain as such. + * Private data must only be accessible through the getter and + * setter functions. + * + ************************************************************************/ + +#ifndef TRIO_TRIOP_H +#define TRIO_TRIOP_H + +#include "triodef.h" + +#include +#if defined(TRIO_COMPILER_ANCIENT) +# include +#else +# include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef TRIO_C99 +# define TRIO_C99 1 +#endif +#ifndef TRIO_BSD +# define TRIO_BSD 1 +#endif +#ifndef TRIO_GNU +# define TRIO_GNU 1 +#endif +#ifndef TRIO_MISC +# define TRIO_MISC 1 +#endif +#ifndef TRIO_UNIX98 +# define TRIO_UNIX98 1 +#endif +#ifndef TRIO_MICROSOFT +# define TRIO_MICROSOFT 1 +#endif +#ifndef TRIO_EXTENSION +# define TRIO_EXTENSION 1 +#endif +#ifndef TRIO_WIDECHAR /* Does not work yet. Do not enable */ +# define TRIO_WIDECHAR 0 +#endif +#ifndef TRIO_ERRORS +# define TRIO_ERRORS 1 +#endif + +#ifndef TRIO_MALLOC +# define TRIO_MALLOC(n) malloc(n) +#endif +#ifndef TRIO_REALLOC +# define TRIO_REALLOC(x,n) realloc((x),(n)) +#endif +#ifndef TRIO_FREE +# define TRIO_FREE(x) free(x) +#endif + + +/************************************************************************* + * User-defined specifiers + */ + +typedef int (*trio_callback_t) TRIO_PROTO((trio_pointer_t)); + +trio_pointer_t trio_register TRIO_PROTO((trio_callback_t callback, const char *name)); +void trio_unregister TRIO_PROTO((trio_pointer_t handle)); + +TRIO_CONST char *trio_get_format TRIO_PROTO((trio_pointer_t ref)); +trio_pointer_t trio_get_argument TRIO_PROTO((trio_pointer_t ref)); + +/* Modifiers */ +int trio_get_width TRIO_PROTO((trio_pointer_t ref)); +void trio_set_width TRIO_PROTO((trio_pointer_t ref, int width)); +int trio_get_precision TRIO_PROTO((trio_pointer_t ref)); +void trio_set_precision TRIO_PROTO((trio_pointer_t ref, int precision)); +int trio_get_base TRIO_PROTO((trio_pointer_t ref)); +void trio_set_base TRIO_PROTO((trio_pointer_t ref, int base)); +int trio_get_padding TRIO_PROTO((trio_pointer_t ref)); +void trio_set_padding TRIO_PROTO((trio_pointer_t ref, int is_padding)); +int trio_get_short TRIO_PROTO((trio_pointer_t ref)); /* h */ +void trio_set_shortshort TRIO_PROTO((trio_pointer_t ref, int is_shortshort)); +int trio_get_shortshort TRIO_PROTO((trio_pointer_t ref)); /* hh */ +void trio_set_short TRIO_PROTO((trio_pointer_t ref, int is_short)); +int trio_get_long TRIO_PROTO((trio_pointer_t ref)); /* l */ +void trio_set_long TRIO_PROTO((trio_pointer_t ref, int is_long)); +int trio_get_longlong TRIO_PROTO((trio_pointer_t ref)); /* ll */ +void trio_set_longlong TRIO_PROTO((trio_pointer_t ref, int is_longlong)); +int trio_get_longdouble TRIO_PROTO((trio_pointer_t ref)); /* L */ +void trio_set_longdouble TRIO_PROTO((trio_pointer_t ref, int is_longdouble)); +int trio_get_alternative TRIO_PROTO((trio_pointer_t ref)); /* # */ +void trio_set_alternative TRIO_PROTO((trio_pointer_t ref, int is_alternative)); +int trio_get_alignment TRIO_PROTO((trio_pointer_t ref)); /* - */ +void trio_set_alignment TRIO_PROTO((trio_pointer_t ref, int is_leftaligned)); +int trio_get_spacing TRIO_PROTO((trio_pointer_t ref)); /* TRIO_PROTO((space) */ +void trio_set_spacing TRIO_PROTO((trio_pointer_t ref, int is_space)); +int trio_get_sign TRIO_PROTO((trio_pointer_t ref)); /* + */ +void trio_set_sign TRIO_PROTO((trio_pointer_t ref, int is_showsign)); +int trio_get_quote TRIO_PROTO((trio_pointer_t ref)); /* ' */ +void trio_set_quote TRIO_PROTO((trio_pointer_t ref, int is_quote)); +int trio_get_upper TRIO_PROTO((trio_pointer_t ref)); +void trio_set_upper TRIO_PROTO((trio_pointer_t ref, int is_upper)); +#if TRIO_C99 +int trio_get_largest TRIO_PROTO((trio_pointer_t ref)); /* j */ +void trio_set_largest TRIO_PROTO((trio_pointer_t ref, int is_largest)); +int trio_get_ptrdiff TRIO_PROTO((trio_pointer_t ref)); /* t */ +void trio_set_ptrdiff TRIO_PROTO((trio_pointer_t ref, int is_ptrdiff)); +int trio_get_size TRIO_PROTO((trio_pointer_t ref)); /* z / Z */ +void trio_set_size TRIO_PROTO((trio_pointer_t ref, int is_size)); +#endif + +/* Printing */ +int trio_print_ref TRIO_PROTO((trio_pointer_t ref, const char *format, ...)); +int trio_vprint_ref TRIO_PROTO((trio_pointer_t ref, const char *format, va_list args)); +int trio_printv_ref TRIO_PROTO((trio_pointer_t ref, const char *format, trio_pointer_t *args)); + +void trio_print_int TRIO_PROTO((trio_pointer_t ref, int number)); +void trio_print_uint TRIO_PROTO((trio_pointer_t ref, unsigned int number)); +/* void trio_print_long TRIO_PROTO((trio_pointer_t ref, long number)); */ +/* void trio_print_ulong TRIO_PROTO((trio_pointer_t ref, unsigned long number)); */ +void trio_print_double TRIO_PROTO((trio_pointer_t ref, double number)); +void trio_print_string TRIO_PROTO((trio_pointer_t ref, char *string)); +void trio_print_pointer TRIO_PROTO((trio_pointer_t ref, trio_pointer_t pointer)); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* TRIO_TRIOP_H */ diff --git a/android/native/libxml2/triostr.c b/android/native/libxml2/triostr.c new file mode 100644 index 0000000000..30d13ac062 --- /dev/null +++ b/android/native/libxml2/triostr.c @@ -0,0 +1,2106 @@ +/************************************************************************* + * + * $Id$ + * + * Copyright (C) 2001 Bjorn Reese and Daniel Stenberg. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND + * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER. + * + ************************************************************************/ + +/************************************************************************* + * Include files + */ + +#include +#include +#include +#include +#include +#include "triodef.h" +#include "triostr.h" + +/************************************************************************* + * Definitions + */ + +#if !defined(TRIO_STRING_PUBLIC) +# define TRIO_STRING_PUBLIC TRIO_PUBLIC +#endif +#if !defined(TRIO_STRING_PRIVATE) +# define TRIO_STRING_PRIVATE TRIO_PRIVATE +#endif + +#if !defined(NULL) +# define NULL 0 +#endif +#if !defined(NIL) +# define NIL ((char)0) +#endif +#if !defined(FALSE) +# define FALSE (1 == 0) +# define TRUE (! FALSE) +#endif +#if !defined(BOOLEAN_T) +# define BOOLEAN_T int +#endif + +#if defined(TRIO_COMPILER_SUPPORTS_C99) +# define USE_STRTOD +# define USE_STRTOF +#elif defined(TRIO_COMPILER_MSVC) +# define USE_STRTOD +#endif + +#if defined(TRIO_PLATFORM_UNIX) +# define USE_STRCASECMP +# define USE_STRNCASECMP +# if defined(TRIO_PLATFORM_SUNOS) +# define USE_SYS_ERRLIST +# else +# define USE_STRERROR +# endif +# if defined(TRIO_PLATFORM_QNX) +# define strcasecmp(x,y) stricmp(x,y) +# define strncasecmp(x,y,n) strnicmp(x,y,n) +# endif +#elif defined(TRIO_PLATFORM_WIN32) +# define USE_STRCASECMP +# if defined(_WIN32_WCE) +# define strcasecmp(x,y) _stricmp(x,y) +# else +# define strcasecmp(x,y) strcmpi(x,y) +# endif +#endif + +#if !(defined(TRIO_PLATFORM_SUNOS)) +# define USE_TOLOWER +# define USE_TOUPPER +#endif + +/************************************************************************* + * Structures + */ + +struct _trio_string_t +{ + char *content; + size_t length; + size_t allocated; +}; + +/************************************************************************* + * Constants + */ + +#if !defined(TRIO_MINIMAL) +static TRIO_CONST char rcsid[] = "@(#)$Id$"; +#endif + +/************************************************************************* + * Static String Functions + */ + +#if defined(TRIO_DOCUMENTATION) +# include "doc/doc_static.h" +#endif +/** @addtogroup StaticStrings + @{ +*/ + +/** + Create new string. + + @param size Size of new string. + @return Pointer to string, or NULL if allocation failed. +*/ +TRIO_STRING_PUBLIC char * +trio_create +TRIO_ARGS1((size), + size_t size) +{ + return (char *)TRIO_MALLOC(size); +} + + +/** + Destroy string. + + @param string String to be freed. +*/ +TRIO_STRING_PUBLIC void +trio_destroy +TRIO_ARGS1((string), + char *string) +{ + if (string) + { + TRIO_FREE(string); + } +} + + +/** + Count the number of characters in a string. + + @param string String to measure. + @return Number of characters in @string. +*/ +TRIO_STRING_PUBLIC size_t +trio_length +TRIO_ARGS1((string), + TRIO_CONST char *string) +{ + return strlen(string); +} + + +#if !defined(TRIO_MINIMAL) +/** + Append @p source at the end of @p target. + + @param target Target string. + @param source Source string. + @return Boolean value indicating success or failure. + + @pre @p target must point to a memory chunk with sufficient room to + contain the @p target string and @p source string. + @pre No boundary checking is performed, so insufficient memory will + result in a buffer overrun. + @post @p target will be zero terminated. +*/ +TRIO_STRING_PUBLIC int +trio_append +TRIO_ARGS2((target, source), + char *target, + TRIO_CONST char *source) +{ + assert(target); + assert(source); + + return (strcat(target, source) != NULL); +} +#endif /* !defined(TRIO_MINIMAL) */ + +#if !defined(TRIO_MINIMAL) +/** + Append at most @p max characters from @p source to @p target. + + @param target Target string. + @param max Maximum number of characters to append. + @param source Source string. + @return Boolean value indicating success or failure. + + @pre @p target must point to a memory chuck with sufficient room to + contain the @p target string and the @p source string (at most @p max + characters). + @pre No boundary checking is performed, so insufficient memory will + result in a buffer overrun. + @post @p target will be zero terminated. +*/ +TRIO_STRING_PUBLIC int +trio_append_max +TRIO_ARGS3((target, max, source), + char *target, + size_t max, + TRIO_CONST char *source) +{ + size_t length; + + assert(target); + assert(source); + + length = trio_length(target); + + if (max > length) + { + strncat(target, source, max - length - 1); + } + return TRUE; +} +#endif /* !defined(TRIO_MINIMAL) */ + + +#if !defined(TRIO_MINIMAL) +/** + Determine if a string contains a substring. + + @param string String to be searched. + @param substring String to be found. + @return Boolean value indicating success or failure. +*/ +TRIO_STRING_PUBLIC int +trio_contains +TRIO_ARGS2((string, substring), + TRIO_CONST char *string, + TRIO_CONST char *substring) +{ + assert(string); + assert(substring); + + return (0 != strstr(string, substring)); +} +#endif /* !defined(TRIO_MINIMAL) */ + + +#if !defined(TRIO_MINIMAL) +/** + Copy @p source to @p target. + + @param target Target string. + @param source Source string. + @return Boolean value indicating success or failure. + + @pre @p target must point to a memory chunk with sufficient room to + contain the @p source string. + @pre No boundary checking is performed, so insufficient memory will + result in a buffer overrun. + @post @p target will be zero terminated. +*/ +TRIO_STRING_PUBLIC int +trio_copy +TRIO_ARGS2((target, source), + char *target, + TRIO_CONST char *source) +{ + assert(target); + assert(source); + + (void)strcpy(target, source); + return TRUE; +} +#endif /* !defined(TRIO_MINIMAL) */ + + +/** + Copy at most @p max characters from @p source to @p target. + + @param target Target string. + @param max Maximum number of characters to append. + @param source Source string. + @return Boolean value indicating success or failure. + + @pre @p target must point to a memory chunk with sufficient room to + contain the @p source string (at most @p max characters). + @pre No boundary checking is performed, so insufficient memory will + result in a buffer overrun. + @post @p target will be zero terminated. +*/ +TRIO_STRING_PUBLIC int +trio_copy_max +TRIO_ARGS3((target, max, source), + char *target, + size_t max, + TRIO_CONST char *source) +{ + assert(target); + assert(source); + assert(max > 0); /* Includes != 0 */ + + (void)strncpy(target, source, max - 1); + target[max - 1] = (char)0; + return TRUE; +} + + +/* + * TrioDuplicateMax + */ +TRIO_STRING_PRIVATE char * +TrioDuplicateMax +TRIO_ARGS2((source, size), + TRIO_CONST char *source, + size_t size) +{ + char *target; + + assert(source); + + /* Make room for string plus a terminating zero */ + size++; + target = trio_create(size); + if (target) + { + trio_copy_max(target, size, source); + } + return target; +} + + +/** + Duplicate @p source. + + @param source Source string. + @return A copy of the @p source string. + + @post @p target will be zero terminated. +*/ +TRIO_STRING_PUBLIC char * +trio_duplicate +TRIO_ARGS1((source), + TRIO_CONST char *source) +{ + return TrioDuplicateMax(source, trio_length(source)); +} + + +#if !defined(TRIO_MINIMAL) +/** + Duplicate at most @p max characters of @p source. + + @param source Source string. + @param max Maximum number of characters to duplicate. + @return A copy of the @p source string. + + @post @p target will be zero terminated. +*/ +TRIO_STRING_PUBLIC char * +trio_duplicate_max TRIO_ARGS2((source, max), + TRIO_CONST char *source, + size_t max) +{ + size_t length; + + assert(source); + assert(max > 0); + + length = trio_length(source); + if (length > max) + { + length = max; + } + return TrioDuplicateMax(source, length); +} +#endif /* !defined(TRIO_MINIMAL) */ + + +/** + Compare if two strings are equal. + + @param first First string. + @param second Second string. + @return Boolean indicating whether the two strings are equal or not. + + Case-insensitive comparison. +*/ +TRIO_STRING_PUBLIC int +trio_equal +TRIO_ARGS2((first, second), + TRIO_CONST char *first, + TRIO_CONST char *second) +{ + assert(first); + assert(second); + + if ((first != NULL) && (second != NULL)) + { +#if defined(USE_STRCASECMP) + return (0 == strcasecmp(first, second)); +#else + while ((*first != NIL) && (*second != NIL)) + { + if (trio_to_upper(*first) != trio_to_upper(*second)) + { + break; + } + first++; + second++; + } + return ((*first == NIL) && (*second == NIL)); +#endif + } + return FALSE; +} + + +/** + Compare if two strings are equal. + + @param first First string. + @param second Second string. + @return Boolean indicating whether the two strings are equal or not. + + Case-sensitive comparison. +*/ +TRIO_STRING_PUBLIC int +trio_equal_case +TRIO_ARGS2((first, second), + TRIO_CONST char *first, + TRIO_CONST char *second) +{ + assert(first); + assert(second); + + if ((first != NULL) && (second != NULL)) + { + return (0 == strcmp(first, second)); + } + return FALSE; +} + + +#if !defined(TRIO_MINIMAL) +/** + Compare if two strings up until the first @p max characters are equal. + + @param first First string. + @param max Maximum number of characters to compare. + @param second Second string. + @return Boolean indicating whether the two strings are equal or not. + + Case-sensitive comparison. +*/ +TRIO_STRING_PUBLIC int +trio_equal_case_max +TRIO_ARGS3((first, max, second), + TRIO_CONST char *first, + size_t max, + TRIO_CONST char *second) +{ + assert(first); + assert(second); + + if ((first != NULL) && (second != NULL)) + { + return (0 == strncmp(first, second, max)); + } + return FALSE; +} +#endif /* !defined(TRIO_MINIMAL) */ + + +/** + Compare if two strings are equal. + + @param first First string. + @param second Second string. + @return Boolean indicating whether the two strings are equal or not. + + Collating characters are considered equal. +*/ +TRIO_STRING_PUBLIC int +trio_equal_locale +TRIO_ARGS2((first, second), + TRIO_CONST char *first, + TRIO_CONST char *second) +{ + assert(first); + assert(second); + +#if defined(LC_COLLATE) + return (strcoll(first, second) == 0); +#else + return trio_equal(first, second); +#endif +} + + +/** + Compare if two strings up until the first @p max characters are equal. + + @param first First string. + @param max Maximum number of characters to compare. + @param second Second string. + @return Boolean indicating whether the two strings are equal or not. + + Case-insensitive comparison. +*/ +TRIO_STRING_PUBLIC int +trio_equal_max +TRIO_ARGS3((first, max, second), + TRIO_CONST char *first, + size_t max, + TRIO_CONST char *second) +{ + assert(first); + assert(second); + + if ((first != NULL) && (second != NULL)) + { +#if defined(USE_STRNCASECMP) + return (0 == strncasecmp(first, second, max)); +#else + /* Not adequately tested yet */ + size_t cnt = 0; + while ((*first != NIL) && (*second != NIL) && (cnt <= max)) + { + if (trio_to_upper(*first) != trio_to_upper(*second)) + { + break; + } + first++; + second++; + cnt++; + } + return ((cnt == max) || ((*first == NIL) && (*second == NIL))); +#endif + } + return FALSE; +} + + +/** + Provide a textual description of an error code (errno). + + @param error_number Error number. + @return Textual description of @p error_number. +*/ +TRIO_STRING_PUBLIC TRIO_CONST char * +trio_error +TRIO_ARGS1((error_number), + int error_number) +{ +#if defined(USE_STRERROR) + + return strerror(error_number); + +#elif defined(USE_SYS_ERRLIST) + + extern char *sys_errlist[]; + extern int sys_nerr; + + return ((error_number < 0) || (error_number >= sys_nerr)) + ? "unknown" + : sys_errlist[error_number]; + +#else + + return "unknown"; + +#endif +} + + +#if !defined(TRIO_MINIMAL) && !defined(_WIN32_WCE) +/** + Format the date/time according to @p format. + + @param target Target string. + @param max Maximum number of characters to format. + @param format Formatting string. + @param datetime Date/time structure. + @return Number of formatted characters. + + The formatting string accepts the same specifiers as the standard C + function strftime. +*/ +TRIO_STRING_PUBLIC size_t +trio_format_date_max +TRIO_ARGS4((target, max, format, datetime), + char *target, + size_t max, + TRIO_CONST char *format, + TRIO_CONST struct tm *datetime) +{ + assert(target); + assert(format); + assert(datetime); + assert(max > 0); + + return strftime(target, max, format, datetime); +} +#endif /* !defined(TRIO_MINIMAL) */ + + +#if !defined(TRIO_MINIMAL) +/** + Calculate a hash value for a string. + + @param string String to be calculated on. + @param type Hash function. + @return Calculated hash value. + + @p type can be one of the following + @li @c TRIO_HASH_PLAIN Plain hash function. +*/ +TRIO_STRING_PUBLIC unsigned long +trio_hash +TRIO_ARGS2((string, type), + TRIO_CONST char *string, + int type) +{ + unsigned long value = 0L; + char ch; + + assert(string); + + switch (type) + { + case TRIO_HASH_PLAIN: + while ( (ch = *string++) != NIL ) + { + value *= 31; + value += (unsigned long)ch; + } + break; + default: + assert(FALSE); + break; + } + return value; +} +#endif /* !defined(TRIO_MINIMAL) */ + + +#if !defined(TRIO_MINIMAL) +/** + Find first occurrence of a character in a string. + + @param string String to be searched. + @param character Character to be found. + @param A pointer to the found character, or NULL if character was not found. + */ +TRIO_STRING_PUBLIC char * +trio_index +TRIO_ARGS2((string, character), + TRIO_CONST char *string, + int character) +{ + assert(string); + + return strchr(string, character); +} +#endif /* !defined(TRIO_MINIMAL) */ + + +#if !defined(TRIO_MINIMAL) +/** + Find last occurrence of a character in a string. + + @param string String to be searched. + @param character Character to be found. + @param A pointer to the found character, or NULL if character was not found. + */ +TRIO_STRING_PUBLIC char * +trio_index_last +TRIO_ARGS2((string, character), + TRIO_CONST char *string, + int character) +{ + assert(string); + + return strchr(string, character); +} +#endif /* !defined(TRIO_MINIMAL) */ + + +#if !defined(TRIO_MINIMAL) +/** + Convert the alphabetic letters in the string to lower-case. + + @param target String to be converted. + @return Number of processed characters (converted or not). +*/ +TRIO_STRING_PUBLIC int +trio_lower +TRIO_ARGS1((target), + char *target) +{ + assert(target); + + return trio_span_function(target, target, trio_to_lower); +} +#endif /* !defined(TRIO_MINIMAL) */ + + +#if !defined(TRIO_MINIMAL) +/** + Compare two strings using wildcards. + + @param string String to be searched. + @param pattern Pattern, including wildcards, to search for. + @return Boolean value indicating success or failure. + + Case-insensitive comparison. + + The following wildcards can be used + @li @c * Match any number of characters. + @li @c ? Match a single character. +*/ +TRIO_STRING_PUBLIC int +trio_match +TRIO_ARGS2((string, pattern), + TRIO_CONST char *string, + TRIO_CONST char *pattern) +{ + assert(string); + assert(pattern); + + for (; ('*' != *pattern); ++pattern, ++string) + { + if (NIL == *string) + { + return (NIL == *pattern); + } + if ((trio_to_upper((int)*string) != trio_to_upper((int)*pattern)) + && ('?' != *pattern)) + { + return FALSE; + } + } + /* two-line patch to prevent *too* much recursiveness: */ + while ('*' == pattern[1]) + pattern++; + + do + { + if ( trio_match(string, &pattern[1]) ) + { + return TRUE; + } + } + while (*string++); + + return FALSE; +} +#endif /* !defined(TRIO_MINIMAL) */ + + +#if !defined(TRIO_MINIMAL) +/** + Compare two strings using wildcards. + + @param string String to be searched. + @param pattern Pattern, including wildcards, to search for. + @return Boolean value indicating success or failure. + + Case-sensitive comparison. + + The following wildcards can be used + @li @c * Match any number of characters. + @li @c ? Match a single character. +*/ +TRIO_STRING_PUBLIC int +trio_match_case +TRIO_ARGS2((string, pattern), + TRIO_CONST char *string, + TRIO_CONST char *pattern) +{ + assert(string); + assert(pattern); + + for (; ('*' != *pattern); ++pattern, ++string) + { + if (NIL == *string) + { + return (NIL == *pattern); + } + if ((*string != *pattern) + && ('?' != *pattern)) + { + return FALSE; + } + } + /* two-line patch to prevent *too* much recursiveness: */ + while ('*' == pattern[1]) + pattern++; + + do + { + if ( trio_match_case(string, &pattern[1]) ) + { + return TRUE; + } + } + while (*string++); + + return FALSE; +} +#endif /* !defined(TRIO_MINIMAL) */ + + +#if !defined(TRIO_MINIMAL) +/** + Execute a function on each character in string. + + @param target Target string. + @param source Source string. + @param Function Function to be executed. + @return Number of processed characters. +*/ +TRIO_STRING_PUBLIC size_t +trio_span_function +TRIO_ARGS3((target, source, Function), + char *target, + TRIO_CONST char *source, + int (*Function) TRIO_PROTO((int))) +{ + size_t count = 0; + + assert(target); + assert(source); + assert(Function); + + while (*source != NIL) + { + *target++ = Function(*source++); + count++; + } + return count; +} +#endif /* !defined(TRIO_MINIMAL) */ + + +#if !defined(TRIO_MINIMAL) +/** + Search for a substring in a string. + + @param string String to be searched. + @param substring String to be found. + @return Pointer to first occurrence of @p substring in @p string, or NULL + if no match was found. +*/ +TRIO_STRING_PUBLIC char * +trio_substring +TRIO_ARGS2((string, substring), + TRIO_CONST char *string, + TRIO_CONST char *substring) +{ + assert(string); + assert(substring); + + return strstr(string, substring); +} +#endif /* !defined(TRIO_MINIMAL) */ + + +#if !defined(TRIO_MINIMAL) +/** + Search for a substring in the first @p max characters of a string. + + @param string String to be searched. + @param max Maximum characters to be searched. + @param substring String to be found. + @return Pointer to first occurrence of @p substring in @p string, or NULL + if no match was found. +*/ +TRIO_STRING_PUBLIC char * +trio_substring_max +TRIO_ARGS3((string, max, substring), + TRIO_CONST char *string, + size_t max, + TRIO_CONST char *substring) +{ + size_t count; + size_t size; + char *result = NULL; + + assert(string); + assert(substring); + + size = trio_length(substring); + if (size <= max) + { + for (count = 0; count <= max - size; count++) + { + if (trio_equal_max(substring, size, &string[count])) + { + result = (char *)&string[count]; + break; + } + } + } + return result; +} +#endif /* !defined(TRIO_MINIMAL) */ + + +#if !defined(TRIO_MINIMAL) +/** + Tokenize string. + + @param string String to be tokenized. + @param tokens String containing list of delimiting characters. + @return Start of new token. + + @warning @p string will be destroyed. +*/ +TRIO_STRING_PUBLIC char * +trio_tokenize +TRIO_ARGS2((string, delimiters), + char *string, + TRIO_CONST char *delimiters) +{ + assert(delimiters); + + return strtok(string, delimiters); +} +#endif /* !defined(TRIO_MINIMAL) */ + + +/** + Convert string to floating-point number. + + @param source String to be converted. + @param endp Pointer to end of the converted string. + @return A floating-point number. + + The following Extended Backus-Naur form is used + @verbatim + double ::= [ ] + ( | + | + ) + [ [ ] ] + number ::= 1*( ) + digit ::= ( '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' ) + exponential ::= ( 'e' | 'E' ) + sign ::= ( '-' | '+' ) + decimal_point ::= '.' + @endverbatim +*/ +/* FIXME: Add EBNF for hex-floats */ +TRIO_STRING_PUBLIC trio_long_double_t +trio_to_long_double +TRIO_ARGS2((source, endp), + TRIO_CONST char *source, + char **endp) +{ +#if defined(USE_STRTOLD) + return strtold(source, endp); +#else + int isNegative = FALSE; + int isExponentNegative = FALSE; + trio_long_double_t integer = 0.0; + trio_long_double_t fraction = 0.0; + unsigned long exponent = 0; + trio_long_double_t base; + trio_long_double_t fracdiv = 1.0; + trio_long_double_t value = 0.0; + + /* First try hex-floats */ + if ((source[0] == '0') && ((source[1] == 'x') || (source[1] == 'X'))) + { + base = 16.0; + source += 2; + while (isxdigit((int)*source)) + { + integer *= base; + integer += (isdigit((int)*source) + ? (*source - '0') + : 10 + (trio_to_upper((int)*source) - 'A')); + source++; + } + if (*source == '.') + { + source++; + while (isxdigit((int)*source)) + { + fracdiv /= base; + fraction += fracdiv * (isdigit((int)*source) + ? (*source - '0') + : 10 + (trio_to_upper((int)*source) - 'A')); + source++; + } + if ((*source == 'p') || (*source == 'P')) + { + source++; + if ((*source == '+') || (*source == '-')) + { + isExponentNegative = (*source == '-'); + source++; + } + while (isdigit((int)*source)) + { + exponent *= 10; + exponent += (*source - '0'); + source++; + } + } + } + /* For later use with exponent */ + base = 2.0; + } + else /* Then try normal decimal floats */ + { + base = 10.0; + isNegative = (*source == '-'); + /* Skip sign */ + if ((*source == '+') || (*source == '-')) + source++; + + /* Integer part */ + while (isdigit((int)*source)) + { + integer *= base; + integer += (*source - '0'); + source++; + } + + if (*source == '.') + { + source++; /* skip decimal point */ + while (isdigit((int)*source)) + { + fracdiv /= base; + fraction += (*source - '0') * fracdiv; + source++; + } + } + if ((*source == 'e') + || (*source == 'E') +#if TRIO_MICROSOFT + || (*source == 'd') + || (*source == 'D') +#endif + ) + { + source++; /* Skip exponential indicator */ + isExponentNegative = (*source == '-'); + if ((*source == '+') || (*source == '-')) + source++; + while (isdigit((int)*source)) + { + exponent *= (int)base; + exponent += (*source - '0'); + source++; + } + } + } + + value = integer + fraction; + if (exponent != 0) + { + if (isExponentNegative) + value /= pow(base, (double)exponent); + else + value *= pow(base, (double)exponent); + } + if (isNegative) + value = -value; + + if (endp) + *endp = (char *)source; + return value; +#endif +} + + +/** + Convert string to floating-point number. + + @param source String to be converted. + @param endp Pointer to end of the converted string. + @return A floating-point number. + + See @ref trio_to_long_double. +*/ +TRIO_STRING_PUBLIC double +trio_to_double +TRIO_ARGS2((source, endp), + TRIO_CONST char *source, + char **endp) +{ +#if defined(USE_STRTOD) + return strtod(source, endp); +#else + return (double)trio_to_long_double(source, endp); +#endif +} + +#if !defined(TRIO_MINIMAL) +/** + Convert string to floating-point number. + + @param source String to be converted. + @param endp Pointer to end of the converted string. + @return A floating-point number. + + See @ref trio_to_long_double. +*/ +TRIO_STRING_PUBLIC float +trio_to_float +TRIO_ARGS2((source, endp), + TRIO_CONST char *source, + char **endp) +{ +#if defined(USE_STRTOF) + return strtof(source, endp); +#else + return (float)trio_to_long_double(source, endp); +#endif +} +#endif /* !defined(TRIO_MINIMAL) */ + + +/** + Convert string to signed integer. + + @param string String to be converted. + @param endp Pointer to end of converted string. + @param base Radix number of number. +*/ +TRIO_STRING_PUBLIC long +trio_to_long +TRIO_ARGS3((string, endp, base), + TRIO_CONST char *string, + char **endp, + int base) +{ + assert(string); + assert((base >= 2) && (base <= 36)); + + return strtol(string, endp, base); +} + + +#if !defined(TRIO_MINIMAL) +/** + Convert one alphabetic letter to lower-case. + + @param source The letter to be converted. + @return The converted letter. +*/ +TRIO_STRING_PUBLIC int +trio_to_lower +TRIO_ARGS1((source), + int source) +{ +#if defined(USE_TOLOWER) + + return tolower(source); + +#else + + /* Does not handle locales or non-contiguous alphabetic characters */ + return ((source >= (int)'A') && (source <= (int)'Z')) + ? source - 'A' + 'a' + : source; + +#endif +} +#endif /* !defined(TRIO_MINIMAL) */ + +#if !defined(TRIO_MINIMAL) +/** + Convert string to unsigned integer. + + @param string String to be converted. + @param endp Pointer to end of converted string. + @param base Radix number of number. +*/ +TRIO_STRING_PUBLIC unsigned long +trio_to_unsigned_long +TRIO_ARGS3((string, endp, base), + TRIO_CONST char *string, + char **endp, + int base) +{ + assert(string); + assert((base >= 2) && (base <= 36)); + + return strtoul(string, endp, base); +} +#endif /* !defined(TRIO_MINIMAL) */ + + +/** + Convert one alphabetic letter to upper-case. + + @param source The letter to be converted. + @return The converted letter. +*/ +TRIO_STRING_PUBLIC int +trio_to_upper +TRIO_ARGS1((source), + int source) +{ +#if defined(USE_TOUPPER) + + return toupper(source); + +#else + + /* Does not handle locales or non-contiguous alphabetic characters */ + return ((source >= (int)'a') && (source <= (int)'z')) + ? source - 'a' + 'A' + : source; + +#endif +} + +#if !defined(TRIO_MINIMAL) +/** + Convert the alphabetic letters in the string to upper-case. + + @param target The string to be converted. + @return The number of processed characters (converted or not). +*/ +TRIO_STRING_PUBLIC int +trio_upper +TRIO_ARGS1((target), + char *target) +{ + assert(target); + + return trio_span_function(target, target, trio_to_upper); +} +#endif /* !defined(TRIO_MINIMAL) */ + + +/** @} End of StaticStrings */ + + +/************************************************************************* + * Dynamic String Functions + */ + +#if defined(TRIO_DOCUMENTATION) +# include "doc/doc_dynamic.h" +#endif +/** @addtogroup DynamicStrings + @{ +*/ + +/* + * TrioStringAlloc + */ +TRIO_STRING_PRIVATE trio_string_t * +TrioStringAlloc(TRIO_NOARGS) +{ + trio_string_t *self; + + self = (trio_string_t *)TRIO_MALLOC(sizeof(trio_string_t)); + if (self) + { + self->content = NULL; + self->length = 0; + self->allocated = 0; + } + return self; +} + + +/* + * TrioStringGrow + * + * The size of the string will be increased by 'delta' characters. If + * 'delta' is zero, the size will be doubled. + */ +TRIO_STRING_PRIVATE BOOLEAN_T +TrioStringGrow +TRIO_ARGS2((self, delta), + trio_string_t *self, + size_t delta) +{ + BOOLEAN_T status = FALSE; + char *new_content; + size_t new_size; + + new_size = (delta == 0) + ? ( (self->allocated == 0) ? 1 : self->allocated * 2 ) + : self->allocated + delta; + + new_content = (char *)TRIO_REALLOC(self->content, new_size); + if (new_content) + { + self->content = new_content; + self->allocated = new_size; + status = TRUE; + } + return status; +} + + +#if !defined(TRIO_MINIMAL) +/* + * TrioStringGrowTo + * + * The size of the string will be increased to 'length' plus one characters. + * If 'length' is less than the original size, the original size will be + * used (that is, the size of the string is never decreased). + */ +TRIO_STRING_PRIVATE BOOLEAN_T +TrioStringGrowTo +TRIO_ARGS2((self, length), + trio_string_t *self, + size_t length) +{ + length++; /* Room for terminating zero */ + return (self->allocated < length) + ? TrioStringGrow(self, length - self->allocated) + : TRUE; +} +#endif /* !defined(TRIO_MINIMAL) */ + + +#if !defined(TRIO_MINIMAL) +/** + Create a new dynamic string. + + @param initial_size Initial size of the buffer. + @return Newly allocated dynamic string, or NULL if memory allocation failed. +*/ +TRIO_STRING_PUBLIC trio_string_t * +trio_string_create +TRIO_ARGS1((initial_size), + int initial_size) +{ + trio_string_t *self; + + self = TrioStringAlloc(); + if (self) + { + if (TrioStringGrow(self, + (size_t)((initial_size > 0) ? initial_size : 1))) + { + self->content[0] = (char)0; + self->allocated = initial_size; + } + else + { + trio_string_destroy(self); + self = NULL; + } + } + return self; +} +#endif /* !defined(TRIO_MINIMAL) */ + + +/** + Deallocate the dynamic string and its contents. + + @param self Dynamic string +*/ +TRIO_STRING_PUBLIC void +trio_string_destroy +TRIO_ARGS1((self), + trio_string_t *self) +{ + assert(self); + + if (self) + { + trio_destroy(self->content); + TRIO_FREE(self); + } +} + + +#if !defined(TRIO_MINIMAL) +/** + Get a pointer to the content. + + @param self Dynamic string. + @param offset Offset into content. + @return Pointer to the content. + + @p Offset can be zero, positive, or negative. If @p offset is zero, + then the start of the content will be returned. If @p offset is positive, + then a pointer to @p offset number of characters from the beginning of the + content is returned. If @p offset is negative, then a pointer to @p offset + number of characters from the ending of the string, starting at the + terminating zero, is returned. +*/ +TRIO_STRING_PUBLIC char * +trio_string_get +TRIO_ARGS2((self, offset), + trio_string_t *self, + int offset) +{ + char *result = NULL; + + assert(self); + + if (self->content != NULL) + { + if (self->length == 0) + { + (void)trio_string_length(self); + } + if (offset >= 0) + { + if (offset > (int)self->length) + { + offset = self->length; + } + } + else + { + offset += self->length + 1; + if (offset < 0) + { + offset = 0; + } + } + result = &(self->content[offset]); + } + return result; +} +#endif /* !defined(TRIO_MINIMAL) */ + + +/** + Extract the content. + + @param self Dynamic String + @return Content of dynamic string. + + The content is removed from the dynamic string. This enables destruction + of the dynamic string without deallocation of the content. +*/ +TRIO_STRING_PUBLIC char * +trio_string_extract +TRIO_ARGS1((self), + trio_string_t *self) +{ + char *result; + + assert(self); + + result = self->content; + /* FIXME: Allocate new empty buffer? */ + self->content = NULL; + self->length = self->allocated = 0; + return result; +} + + +#if !defined(TRIO_MINIMAL) +/** + Set the content of the dynamic string. + + @param self Dynamic String + @param buffer The new content. + + Sets the content of the dynamic string to a copy @p buffer. + An existing content will be deallocated first, if necessary. + + @remark + This function will make a copy of @p buffer. + You are responsible for deallocating @p buffer yourself. +*/ +TRIO_STRING_PUBLIC void +trio_xstring_set +TRIO_ARGS2((self, buffer), + trio_string_t *self, + char *buffer) +{ + assert(self); + + trio_destroy(self->content); + self->content = trio_duplicate(buffer); +} +#endif /* !defined(TRIO_MINIMAL) */ + + +/* + * trio_string_size + */ +TRIO_STRING_PUBLIC int +trio_string_size +TRIO_ARGS1((self), + trio_string_t *self) +{ + assert(self); + + return self->allocated; +} + + +/* + * trio_string_terminate + */ +TRIO_STRING_PUBLIC void +trio_string_terminate +TRIO_ARGS1((self), + trio_string_t *self) +{ + trio_xstring_append_char(self, 0); +} + + +#if !defined(TRIO_MINIMAL) +/** + Append the second string to the first. + + @param self Dynamic string to be modified. + @param other Dynamic string to copy from. + @return Boolean value indicating success or failure. +*/ +TRIO_STRING_PUBLIC int +trio_string_append +TRIO_ARGS2((self, other), + trio_string_t *self, + trio_string_t *other) +{ + size_t length; + + assert(self); + assert(other); + + length = self->length + other->length; + if (!TrioStringGrowTo(self, length)) + goto error; + trio_copy(&self->content[self->length], other->content); + self->length = length; + return TRUE; + + error: + return FALSE; +} +#endif /* !defined(TRIO_MINIMAL) */ + + +#if !defined(TRIO_MINIMAL) +/* + * trio_xstring_append + */ +TRIO_STRING_PUBLIC int +trio_xstring_append +TRIO_ARGS2((self, other), + trio_string_t *self, + TRIO_CONST char *other) +{ + size_t length; + + assert(self); + assert(other); + + length = self->length + trio_length(other); + if (!TrioStringGrowTo(self, length)) + goto error; + trio_copy(&self->content[self->length], other); + self->length = length; + return TRUE; + + error: + return FALSE; +} +#endif /* !defined(TRIO_MINIMAL) */ + + +/* + * trio_xstring_append_char + */ +TRIO_STRING_PUBLIC int +trio_xstring_append_char +TRIO_ARGS2((self, character), + trio_string_t *self, + char character) +{ + assert(self); + + if ((int)self->length >= trio_string_size(self)) + { + if (!TrioStringGrow(self, 0)) + goto error; + } + self->content[self->length] = character; + self->length++; + return TRUE; + + error: + return FALSE; +} + + +#if !defined(TRIO_MINIMAL) +/** + Search for the first occurrence of second parameter in the first. + + @param self Dynamic string to be modified. + @param other Dynamic string to copy from. + @return Boolean value indicating success or failure. +*/ +TRIO_STRING_PUBLIC int +trio_string_contains +TRIO_ARGS2((self, other), + trio_string_t *self, + trio_string_t *other) +{ + assert(self); + assert(other); + + return trio_contains(self->content, other->content); +} +#endif /* !defined(TRIO_MINIMAL) */ + + +#if !defined(TRIO_MINIMAL) +/* + * trio_xstring_contains + */ +TRIO_STRING_PUBLIC int +trio_xstring_contains +TRIO_ARGS2((self, other), + trio_string_t *self, + TRIO_CONST char *other) +{ + assert(self); + assert(other); + + return trio_contains(self->content, other); +} +#endif /* !defined(TRIO_MINIMAL) */ + + +#if !defined(TRIO_MINIMAL) +/* + * trio_string_copy + */ +TRIO_STRING_PUBLIC int +trio_string_copy +TRIO_ARGS2((self, other), + trio_string_t *self, + trio_string_t *other) +{ + assert(self); + assert(other); + + self->length = 0; + return trio_string_append(self, other); +} +#endif /* !defined(TRIO_MINIMAL) */ + + +#if !defined(TRIO_MINIMAL) +/* + * trio_xstring_copy + */ +TRIO_STRING_PUBLIC int +trio_xstring_copy +TRIO_ARGS2((self, other), + trio_string_t *self, + TRIO_CONST char *other) +{ + assert(self); + assert(other); + + self->length = 0; + return trio_xstring_append(self, other); +} +#endif /* !defined(TRIO_MINIMAL) */ + + +#if !defined(TRIO_MINIMAL) +/* + * trio_string_duplicate + */ +TRIO_STRING_PUBLIC trio_string_t * +trio_string_duplicate +TRIO_ARGS1((other), + trio_string_t *other) +{ + trio_string_t *self; + + assert(other); + + self = TrioStringAlloc(); + if (self) + { + self->content = TrioDuplicateMax(other->content, other->length); + if (self->content) + { + self->length = other->length; + self->allocated = self->length + 1; + } + else + { + self->length = self->allocated = 0; + } + } + return self; +} +#endif /* !defined(TRIO_MINIMAL) */ + + +/* + * trio_xstring_duplicate + */ +TRIO_STRING_PUBLIC trio_string_t * +trio_xstring_duplicate +TRIO_ARGS1((other), + TRIO_CONST char *other) +{ + trio_string_t *self; + + assert(other); + + self = TrioStringAlloc(); + if (self) + { + self->content = TrioDuplicateMax(other, trio_length(other)); + if (self->content) + { + self->length = trio_length(self->content); + self->allocated = self->length + 1; + } + else + { + self->length = self->allocated = 0; + } + } + return self; +} + + +#if !defined(TRIO_MINIMAL) +/* + * trio_string_equal + */ +TRIO_STRING_PUBLIC int +trio_string_equal +TRIO_ARGS2((self, other), + trio_string_t *self, + trio_string_t *other) +{ + assert(self); + assert(other); + + return trio_equal(self->content, other->content); +} +#endif /* !defined(TRIO_MINIMAL) */ + + +#if !defined(TRIO_MINIMAL) +/* + * trio_xstring_equal + */ +TRIO_STRING_PUBLIC int +trio_xstring_equal +TRIO_ARGS2((self, other), + trio_string_t *self, + TRIO_CONST char *other) +{ + assert(self); + assert(other); + + return trio_equal(self->content, other); +} +#endif /* !defined(TRIO_MINIMAL) */ + + +#if !defined(TRIO_MINIMAL) +/* + * trio_string_equal_max + */ +TRIO_STRING_PUBLIC int +trio_string_equal_max +TRIO_ARGS3((self, max, other), + trio_string_t *self, + size_t max, + trio_string_t *other) +{ + assert(self); + assert(other); + + return trio_equal_max(self->content, max, other->content); +} +#endif /* !defined(TRIO_MINIMAL) */ + + +#if !defined(TRIO_MINIMAL) +/* + * trio_xstring_equal_max + */ +TRIO_STRING_PUBLIC int +trio_xstring_equal_max +TRIO_ARGS3((self, max, other), + trio_string_t *self, + size_t max, + TRIO_CONST char *other) +{ + assert(self); + assert(other); + + return trio_equal_max(self->content, max, other); +} +#endif /* !defined(TRIO_MINIMAL) */ + + +#if !defined(TRIO_MINIMAL) +/* + * trio_string_equal_case + */ +TRIO_STRING_PUBLIC int +trio_string_equal_case +TRIO_ARGS2((self, other), + trio_string_t *self, + trio_string_t *other) +{ + assert(self); + assert(other); + + return trio_equal_case(self->content, other->content); +} +#endif /* !defined(TRIO_MINIMAL) */ + + +#if !defined(TRIO_MINIMAL) +/* + * trio_xstring_equal_case + */ +TRIO_STRING_PUBLIC int +trio_xstring_equal_case +TRIO_ARGS2((self, other), + trio_string_t *self, + TRIO_CONST char *other) +{ + assert(self); + assert(other); + + return trio_equal_case(self->content, other); +} +#endif /* !defined(TRIO_MINIMAL) */ + + +#if !defined(TRIO_MINIMAL) +/* + * trio_string_equal_case_max + */ +TRIO_STRING_PUBLIC int +trio_string_equal_case_max +TRIO_ARGS3((self, max, other), + trio_string_t *self, + size_t max, + trio_string_t *other) +{ + assert(self); + assert(other); + + return trio_equal_case_max(self->content, max, other->content); +} +#endif /* !defined(TRIO_MINIMAL) */ + + +#if !defined(TRIO_MINIMAL) +/* + * trio_xstring_equal_case_max + */ +TRIO_STRING_PUBLIC int +trio_xstring_equal_case_max +TRIO_ARGS3((self, max, other), + trio_string_t *self, + size_t max, + TRIO_CONST char *other) +{ + assert(self); + assert(other); + + return trio_equal_case_max(self->content, max, other); +} +#endif /* !defined(TRIO_MINIMAL) */ + + +#if !defined(TRIO_MINIMAL) && !defined(_WIN32_WCE) +/* + * trio_string_format_data_max + */ +TRIO_STRING_PUBLIC size_t +trio_string_format_date_max +TRIO_ARGS4((self, max, format, datetime), + trio_string_t *self, + size_t max, + TRIO_CONST char *format, + TRIO_CONST struct tm *datetime) +{ + assert(self); + + return trio_format_date_max(self->content, max, format, datetime); +} +#endif /* !defined(TRIO_MINIMAL) */ + + +#if !defined(TRIO_MINIMAL) +/* + * trio_string_index + */ +TRIO_STRING_PUBLIC char * +trio_string_index +TRIO_ARGS2((self, character), + trio_string_t *self, + int character) +{ + assert(self); + + return trio_index(self->content, character); +} +#endif /* !defined(TRIO_MINIMAL) */ + + +#if !defined(TRIO_MINIMAL) +/* + * trio_string_index_last + */ +TRIO_STRING_PUBLIC char * +trio_string_index_last +TRIO_ARGS2((self, character), + trio_string_t *self, + int character) +{ + assert(self); + + return trio_index_last(self->content, character); +} +#endif /* !defined(TRIO_MINIMAL) */ + + +#if !defined(TRIO_MINIMAL) +/* + * trio_string_length + */ +TRIO_STRING_PUBLIC int +trio_string_length +TRIO_ARGS1((self), + trio_string_t *self) +{ + assert(self); + + if (self->length == 0) + { + self->length = trio_length(self->content); + } + return self->length; +} +#endif /* !defined(TRIO_MINIMAL) */ + + +#if !defined(TRIO_MINIMAL) +/* + * trio_string_lower + */ +TRIO_STRING_PUBLIC int +trio_string_lower +TRIO_ARGS1((self), + trio_string_t *self) +{ + assert(self); + + return trio_lower(self->content); +} +#endif /* !defined(TRIO_MINIMAL) */ + + +#if !defined(TRIO_MINIMAL) +/* + * trio_string_match + */ +TRIO_STRING_PUBLIC int +trio_string_match +TRIO_ARGS2((self, other), + trio_string_t *self, + trio_string_t *other) +{ + assert(self); + assert(other); + + return trio_match(self->content, other->content); +} +#endif /* !defined(TRIO_MINIMAL) */ + + +#if !defined(TRIO_MINIMAL) +/* + * trio_xstring_match + */ +TRIO_STRING_PUBLIC int +trio_xstring_match +TRIO_ARGS2((self, other), + trio_string_t *self, + TRIO_CONST char *other) +{ + assert(self); + assert(other); + + return trio_match(self->content, other); +} +#endif /* !defined(TRIO_MINIMAL) */ + + +#if !defined(TRIO_MINIMAL) +/* + * trio_string_match_case + */ +TRIO_STRING_PUBLIC int +trio_string_match_case +TRIO_ARGS2((self, other), + trio_string_t *self, + trio_string_t *other) +{ + assert(self); + assert(other); + + return trio_match_case(self->content, other->content); +} +#endif /* !defined(TRIO_MINIMAL) */ + + +#if !defined(TRIO_MINIMAL) +/* + * trio_xstring_match_case + */ +TRIO_STRING_PUBLIC int +trio_xstring_match_case +TRIO_ARGS2((self, other), + trio_string_t *self, + TRIO_CONST char *other) +{ + assert(self); + assert(other); + + return trio_match_case(self->content, other); +} +#endif /* !defined(TRIO_MINIMAL) */ + + +#if !defined(TRIO_MINIMAL) +/* + * trio_string_substring + */ +TRIO_STRING_PUBLIC char * +trio_string_substring +TRIO_ARGS2((self, other), + trio_string_t *self, + trio_string_t *other) +{ + assert(self); + assert(other); + + return trio_substring(self->content, other->content); +} +#endif /* !defined(TRIO_MINIMAL) */ + + +#if !defined(TRIO_MINIMAL) +/* + * trio_xstring_substring + */ +TRIO_STRING_PUBLIC char * +trio_xstring_substring +TRIO_ARGS2((self, other), + trio_string_t *self, + TRIO_CONST char *other) +{ + assert(self); + assert(other); + + return trio_substring(self->content, other); +} +#endif /* !defined(TRIO_MINIMAL) */ + + +#if !defined(TRIO_MINIMAL) +/* + * trio_string_upper + */ +TRIO_STRING_PUBLIC int +trio_string_upper +TRIO_ARGS1((self), + trio_string_t *self) +{ + assert(self); + + return trio_upper(self->content); +} +#endif /* !defined(TRIO_MINIMAL) */ + +/** @} End of DynamicStrings */ diff --git a/android/native/libxml2/triostr.h b/android/native/libxml2/triostr.h new file mode 100644 index 0000000000..27f4ace236 --- /dev/null +++ b/android/native/libxml2/triostr.h @@ -0,0 +1,144 @@ +/************************************************************************* + * + * $Id$ + * + * Copyright (C) 2001 Bjorn Reese and Daniel Stenberg. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND + * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER. + * + ************************************************************************/ + +#ifndef TRIO_TRIOSTR_H +#define TRIO_TRIOSTR_H + +#include +#include +#include +#include +#include "triodef.h" +#include "triop.h" + +enum { + TRIO_HASH_NONE = 0, + TRIO_HASH_PLAIN, + TRIO_HASH_TWOSIGNED +}; + +#if !defined(TRIO_STRING_PUBLIC) +# if !defined(TRIO_PUBLIC) +# define TRIO_PUBLIC +# endif +# define TRIO_STRING_PUBLIC TRIO_PUBLIC +#endif + +/************************************************************************* + * String functions + */ + +TRIO_STRING_PUBLIC int trio_copy_max TRIO_PROTO((char *target, size_t max, const char *source)); +TRIO_STRING_PUBLIC char *trio_create TRIO_PROTO((size_t size)); +TRIO_STRING_PUBLIC void trio_destroy TRIO_PROTO((char *string)); +TRIO_STRING_PUBLIC char *trio_duplicate TRIO_PROTO((const char *source)); +TRIO_STRING_PUBLIC int trio_equal TRIO_PROTO((const char *first, const char *second)); +TRIO_STRING_PUBLIC int trio_equal_case TRIO_PROTO((const char *first, const char *second)); +TRIO_STRING_PUBLIC int trio_equal_locale TRIO_PROTO((const char *first, const char *second)); +TRIO_STRING_PUBLIC int trio_equal_max TRIO_PROTO((const char *first, size_t max, const char *second)); +TRIO_STRING_PUBLIC TRIO_CONST char *trio_error TRIO_PROTO((int)); +TRIO_STRING_PUBLIC size_t trio_length TRIO_PROTO((const char *string)); +TRIO_STRING_PUBLIC double trio_to_double TRIO_PROTO((const char *source, char **endp)); +TRIO_STRING_PUBLIC long trio_to_long TRIO_PROTO((const char *source, char **endp, int base)); +TRIO_STRING_PUBLIC trio_long_double_t trio_to_long_double TRIO_PROTO((const char *source, char **endp)); +TRIO_STRING_PUBLIC int trio_to_upper TRIO_PROTO((int source)); + +#if !defined(TRIO_MINIMAL) + +TRIO_STRING_PUBLIC int trio_append TRIO_PROTO((char *target, const char *source)); +TRIO_STRING_PUBLIC int trio_append_max TRIO_PROTO((char *target, size_t max, const char *source)); +TRIO_STRING_PUBLIC int trio_contains TRIO_PROTO((const char *string, const char *substring)); +TRIO_STRING_PUBLIC int trio_copy TRIO_PROTO((char *target, const char *source)); +TRIO_STRING_PUBLIC char *trio_duplicate_max TRIO_PROTO((const char *source, size_t max)); +TRIO_STRING_PUBLIC int trio_equal_case_max TRIO_PROTO((const char *first, size_t max, const char *second)); +#if !defined(_WIN32_WCE) +TRIO_STRING_PUBLIC size_t trio_format_date_max TRIO_PROTO((char *target, size_t max, const char *format, const struct tm *datetime)); +#endif +TRIO_STRING_PUBLIC unsigned long trio_hash TRIO_PROTO((const char *string, int type)); +TRIO_STRING_PUBLIC char *trio_index TRIO_PROTO((const char *string, int character)); +TRIO_STRING_PUBLIC char *trio_index_last TRIO_PROTO((const char *string, int character)); +TRIO_STRING_PUBLIC int trio_lower TRIO_PROTO((char *target)); +TRIO_STRING_PUBLIC int trio_match TRIO_PROTO((const char *string, const char *pattern)); +TRIO_STRING_PUBLIC int trio_match_case TRIO_PROTO((const char *string, const char *pattern)); +TRIO_STRING_PUBLIC size_t trio_span_function TRIO_PROTO((char *target, const char *source, int (*Function) TRIO_PROTO((int)))); +TRIO_STRING_PUBLIC char *trio_substring TRIO_PROTO((const char *string, const char *substring)); +TRIO_STRING_PUBLIC char *trio_substring_max TRIO_PROTO((const char *string, size_t max, const char *substring)); +TRIO_STRING_PUBLIC float trio_to_float TRIO_PROTO((const char *source, char **endp)); +TRIO_STRING_PUBLIC int trio_to_lower TRIO_PROTO((int source)); +TRIO_STRING_PUBLIC unsigned long trio_to_unsigned_long TRIO_PROTO((const char *source, char **endp, int base)); +TRIO_STRING_PUBLIC char *trio_tokenize TRIO_PROTO((char *string, const char *delimiters)); +TRIO_STRING_PUBLIC int trio_upper TRIO_PROTO((char *target)); + +#endif /* !defined(TRIO_MINIMAL) */ + +/************************************************************************* + * Dynamic string functions + */ + +/* + * Opaque type for dynamic strings + */ + +typedef struct _trio_string_t trio_string_t; + +TRIO_STRING_PUBLIC void trio_string_destroy TRIO_PROTO((trio_string_t *self)); +TRIO_STRING_PUBLIC char *trio_string_extract TRIO_PROTO((trio_string_t *self)); +TRIO_STRING_PUBLIC int trio_string_size TRIO_PROTO((trio_string_t *self)); +TRIO_STRING_PUBLIC void trio_string_terminate TRIO_PROTO((trio_string_t *self)); +TRIO_STRING_PUBLIC int trio_xstring_append_char TRIO_PROTO((trio_string_t *self, char character)); +TRIO_STRING_PUBLIC trio_string_t *trio_xstring_duplicate TRIO_PROTO((const char *other)); + +#if !defined(TRIO_MINIMAL) + +TRIO_STRING_PUBLIC trio_string_t *trio_string_create TRIO_PROTO((int initial_size)); +TRIO_STRING_PUBLIC char *trio_string_get TRIO_PROTO((trio_string_t *self, int offset)); +TRIO_STRING_PUBLIC void trio_xstring_set TRIO_PROTO((trio_string_t *self, char *buffer)); + +TRIO_STRING_PUBLIC int trio_string_append TRIO_PROTO((trio_string_t *self, trio_string_t *other)); +TRIO_STRING_PUBLIC int trio_string_contains TRIO_PROTO((trio_string_t *self, trio_string_t *other)); +TRIO_STRING_PUBLIC int trio_string_copy TRIO_PROTO((trio_string_t *self, trio_string_t *other)); +TRIO_STRING_PUBLIC trio_string_t *trio_string_duplicate TRIO_PROTO((trio_string_t *other)); +TRIO_STRING_PUBLIC int trio_string_equal TRIO_PROTO((trio_string_t *self, trio_string_t *other)); +TRIO_STRING_PUBLIC int trio_string_equal_max TRIO_PROTO((trio_string_t *self, size_t max, trio_string_t *second)); +TRIO_STRING_PUBLIC int trio_string_equal_case TRIO_PROTO((trio_string_t *self, trio_string_t *other)); +TRIO_STRING_PUBLIC int trio_string_equal_case_max TRIO_PROTO((trio_string_t *self, size_t max, trio_string_t *other)); +#if !defined(_WIN32_WCE) +TRIO_STRING_PUBLIC size_t trio_string_format_date_max TRIO_PROTO((trio_string_t *self, size_t max, const char *format, const struct tm *datetime)); +#endif +TRIO_STRING_PUBLIC char *trio_string_index TRIO_PROTO((trio_string_t *self, int character)); +TRIO_STRING_PUBLIC char *trio_string_index_last TRIO_PROTO((trio_string_t *self, int character)); +TRIO_STRING_PUBLIC int trio_string_length TRIO_PROTO((trio_string_t *self)); +TRIO_STRING_PUBLIC int trio_string_lower TRIO_PROTO((trio_string_t *self)); +TRIO_STRING_PUBLIC int trio_string_match TRIO_PROTO((trio_string_t *self, trio_string_t *other)); +TRIO_STRING_PUBLIC int trio_string_match_case TRIO_PROTO((trio_string_t *self, trio_string_t *other)); +TRIO_STRING_PUBLIC char *trio_string_substring TRIO_PROTO((trio_string_t *self, trio_string_t *other)); +TRIO_STRING_PUBLIC int trio_string_upper TRIO_PROTO((trio_string_t *self)); + +TRIO_STRING_PUBLIC int trio_xstring_append TRIO_PROTO((trio_string_t *self, const char *other)); +TRIO_STRING_PUBLIC int trio_xstring_contains TRIO_PROTO((trio_string_t *self, const char *other)); +TRIO_STRING_PUBLIC int trio_xstring_copy TRIO_PROTO((trio_string_t *self, const char *other)); +TRIO_STRING_PUBLIC int trio_xstring_equal TRIO_PROTO((trio_string_t *self, const char *other)); +TRIO_STRING_PUBLIC int trio_xstring_equal_max TRIO_PROTO((trio_string_t *self, size_t max, const char *other)); +TRIO_STRING_PUBLIC int trio_xstring_equal_case TRIO_PROTO((trio_string_t *self, const char *other)); +TRIO_STRING_PUBLIC int trio_xstring_equal_case_max TRIO_PROTO((trio_string_t *self, size_t max, const char *other)); +TRIO_STRING_PUBLIC int trio_xstring_match TRIO_PROTO((trio_string_t *self, const char *other)); +TRIO_STRING_PUBLIC int trio_xstring_match_case TRIO_PROTO((trio_string_t *self, const char *other)); +TRIO_STRING_PUBLIC char *trio_xstring_substring TRIO_PROTO((trio_string_t *self, const char *other)); + +#endif /* !defined(TRIO_MINIMAL) */ + +#endif /* TRIO_TRIOSTR_H */ diff --git a/android/native/libxml2/uri.c b/android/native/libxml2/uri.c new file mode 100644 index 0000000000..1ae5768b53 --- /dev/null +++ b/android/native/libxml2/uri.c @@ -0,0 +1,2633 @@ +/** + * uri.c: set of generic URI related routines + * + * Reference: RFCs 3986, 2732 and 2373 + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + */ + +#define IN_LIBXML +#include "libxml.h" + +#include + +#include +#include +#include +#include + +static void xmlCleanURI(xmlURIPtr uri); + +/* + * Old rule from 2396 used in legacy handling code + * alpha = lowalpha | upalpha + */ +#define IS_ALPHA(x) (IS_LOWALPHA(x) || IS_UPALPHA(x)) + + +/* + * lowalpha = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | + * "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" | + * "u" | "v" | "w" | "x" | "y" | "z" + */ + +#define IS_LOWALPHA(x) (((x) >= 'a') && ((x) <= 'z')) + +/* + * upalpha = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" | + * "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T" | + * "U" | "V" | "W" | "X" | "Y" | "Z" + */ +#define IS_UPALPHA(x) (((x) >= 'A') && ((x) <= 'Z')) + +#ifdef IS_DIGIT +#undef IS_DIGIT +#endif +/* + * digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" + */ +#define IS_DIGIT(x) (((x) >= '0') && ((x) <= '9')) + +/* + * alphanum = alpha | digit + */ + +#define IS_ALPHANUM(x) (IS_ALPHA(x) || IS_DIGIT(x)) + +/* + * mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")" + */ + +#define IS_MARK(x) (((x) == '-') || ((x) == '_') || ((x) == '.') || \ + ((x) == '!') || ((x) == '~') || ((x) == '*') || ((x) == '\'') || \ + ((x) == '(') || ((x) == ')')) + +/* + * 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) == '[') || \ + ((x) == ']')) + +/* + * 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++) + +/* + * Productions from the spec. + * + * authority = server | reg_name + * reg_name = 1*( unreserved | escaped | "$" | "," | + * ";" | ":" | "@" | "&" | "=" | "+" ) + * + * path = [ abs_path | opaque_part ] + */ + +#define STRNDUP(s, n) (char *) xmlStrndup((const xmlChar *)(s), (n)) + +/************************************************************************ + * * + * RFC 3986 parser * + * * + ************************************************************************/ + +#define ISA_DIGIT(p) ((*(p) >= '0') && (*(p) <= '9')) +#define ISA_ALPHA(p) (((*(p) >= 'a') && (*(p) <= 'z')) || \ + ((*(p) >= 'A') && (*(p) <= 'Z'))) +#define ISA_HEXDIG(p) \ + (ISA_DIGIT(p) || ((*(p) >= 'a') && (*(p) <= 'f')) || \ + ((*(p) >= 'A') && (*(p) <= 'F'))) + +/* + * sub-delims = "!" / "$" / "&" / "'" / "(" / ")" + * / "*" / "+" / "," / ";" / "=" + */ +#define ISA_SUB_DELIM(p) \ + (((*(p) == '!')) || ((*(p) == '$')) || ((*(p) == '&')) || \ + ((*(p) == '(')) || ((*(p) == ')')) || ((*(p) == '*')) || \ + ((*(p) == '+')) || ((*(p) == ',')) || ((*(p) == ';')) || \ + ((*(p) == '=')) || ((*(p) == '\''))) + +/* + * gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@" + */ +#define ISA_GEN_DELIM(p) \ + (((*(p) == ':')) || ((*(p) == '/')) || ((*(p) == '?')) || \ + ((*(p) == '#')) || ((*(p) == '[')) || ((*(p) == ']')) || \ + ((*(p) == '@'))) + +/* + * reserved = gen-delims / sub-delims + */ +#define ISA_RESERVED(p) (ISA_GEN_DELIM(p) || (ISA_SUB_DELIM(p))) + +/* + * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" + */ +#define ISA_UNRESERVED(p) \ + ((ISA_ALPHA(p)) || (ISA_DIGIT(p)) || ((*(p) == '-')) || \ + ((*(p) == '.')) || ((*(p) == '_')) || ((*(p) == '~'))) + +/* + * pct-encoded = "%" HEXDIG HEXDIG + */ +#define ISA_PCT_ENCODED(p) \ + ((*(p) == '%') && (ISA_HEXDIG(p + 1)) && (ISA_HEXDIG(p + 2))) + +/* + * pchar = unreserved / pct-encoded / sub-delims / ":" / "@" + */ +#define ISA_PCHAR(p) \ + (ISA_UNRESERVED(p) || ISA_PCT_ENCODED(p) || ISA_SUB_DELIM(p) || \ + ((*(p) == ':')) || ((*(p) == '@'))) + +/** + * xmlParse3986Scheme: + * @uri: pointer to an URI structure + * @str: pointer to the string to analyze + * + * Parse an URI scheme + * + * ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) + * + * Returns 0 or the error code + */ +static int +xmlParse3986Scheme(xmlURIPtr uri, const char **str) { + const char *cur; + + if (str == NULL) + return(-1); + + cur = *str; + if (!ISA_ALPHA(cur)) + return(2); + cur++; + 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); + } + *str = cur; + return(0); +} + +/** + * xmlParse3986Fragment: + * @uri: pointer to an URI structure + * @str: pointer to the string to analyze + * + * Parse the query part of an URI + * + * fragment = *( pchar / "/" / "?" ) + * NOTE: the strict syntax as defined by 3986 does not allow '[' and ']' + * in the fragment identifier but this is used very broadly for + * xpointer scheme selection, so we are allowing it here to not break + * for example all the DocBook processing chains. + * + * Returns 0 or the error code + */ +static int +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)))) + NEXT(cur); + if (uri != NULL) { + if (uri->fragment != NULL) + xmlFree(uri->fragment); + if (uri->cleanup & 2) + uri->fragment = STRNDUP(*str, cur - *str); + else + uri->fragment = xmlURIUnescapeString(*str, cur - *str, NULL); + } + *str = cur; + return (0); +} + +/** + * xmlParse3986Query: + * @uri: pointer to an URI structure + * @str: pointer to the string to analyze + * + * Parse the query part of an URI + * + * query = *uric + * + * Returns 0 or the error code + */ +static int +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)))) + NEXT(cur); + if (uri != NULL) { + if (uri->query != NULL) + xmlFree(uri->query); + if (uri->cleanup & 2) + uri->query = STRNDUP(*str, cur - *str); + else + uri->query = xmlURIUnescapeString(*str, cur - *str, NULL); + + /* Save the raw bytes of the query as well. + * See: http://mail.gnome.org/archives/xml/2007-April/thread.html#00114 + */ + if (uri->query_raw != NULL) + xmlFree (uri->query_raw); + uri->query_raw = STRNDUP (*str, cur - *str); + } + *str = cur; + return (0); +} + +/** + * xmlParse3986Port: + * @uri: pointer to an URI structure + * @str: the string to analyze + * + * Parse a port part and fills in the appropriate fields + * of the @uri structure + * + * port = *DIGIT + * + * Returns 0 or the error code + */ +static int +xmlParse3986Port(xmlURIPtr uri, const char **str) +{ + const char *cur = *str; + + if (ISA_DIGIT(cur)) { + if (uri != NULL) + uri->port = 0; + while (ISA_DIGIT(cur)) { + if (uri != NULL) + uri->port = uri->port * 10 + (*cur - '0'); + cur++; + } + *str = cur; + return(0); + } + return(1); +} + +/** + * xmlParse3986Userinfo: + * @uri: pointer to an URI structure + * @str: the string to analyze + * + * Parse an user informations part and fills in the appropriate fields + * of the @uri structure + * + * userinfo = *( unreserved / pct-encoded / sub-delims / ":" ) + * + * Returns 0 or the error code + */ +static int +xmlParse3986Userinfo(xmlURIPtr uri, const char **str) +{ + const char *cur; + + cur = *str; + while (ISA_UNRESERVED(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) + uri->user = STRNDUP(*str, cur - *str); + else + uri->user = xmlURIUnescapeString(*str, cur - *str, NULL); + } + *str = cur; + return(0); + } + return(1); +} + +/** + * xmlParse3986DecOctet: + * @str: the string to analyze + * + * dec-octet = DIGIT ; 0-9 + * / %x31-39 DIGIT ; 10-99 + * / "1" 2DIGIT ; 100-199 + * / "2" %x30-34 DIGIT ; 200-249 + * / "25" %x30-35 ; 250-255 + * + * Skip a dec-octet. + * + * Returns 0 if found and skipped, 1 otherwise + */ +static int +xmlParse3986DecOctet(const char **str) { + const char *cur = *str; + + if (!(ISA_DIGIT(cur))) + return(1); + if (!ISA_DIGIT(cur+1)) + cur++; + else if ((*cur != '0') && (ISA_DIGIT(cur + 1)) && (!ISA_DIGIT(cur+2))) + cur += 2; + else if ((*cur == '1') && (ISA_DIGIT(cur + 1)) && (ISA_DIGIT(cur + 2))) + cur += 3; + else if ((*cur == '2') && (*(cur + 1) >= '0') && + (*(cur + 1) <= '4') && (ISA_DIGIT(cur + 2))) + cur += 3; + else if ((*cur == '2') && (*(cur + 1) == '5') && + (*(cur + 2) >= '0') && (*(cur + 1) <= '5')) + cur += 3; + else + return(1); + *str = cur; + return(0); +} +/** + * xmlParse3986Host: + * @uri: pointer to an URI structure + * @str: the string to analyze + * + * Parse an host part and fills in the appropriate fields + * of the @uri structure + * + * host = IP-literal / IPv4address / reg-name + * IP-literal = "[" ( IPv6address / IPvFuture ) "]" + * IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet + * reg-name = *( unreserved / pct-encoded / sub-delims ) + * + * Returns 0 or the error code + */ +static int +xmlParse3986Host(xmlURIPtr uri, const char **str) +{ + const char *cur = *str; + const char *host; + + host = cur; + /* + * IPv6 and future adressing scheme are enclosed between brackets + */ + if (*cur == '[') { + cur++; + while ((*cur != ']') && (*cur != 0)) + cur++; + if (*cur != ']') + return(1); + cur++; + goto found; + } + /* + * try to parse an IPv4 + */ + if (ISA_DIGIT(cur)) { + if (xmlParse3986DecOctet(&cur) != 0) + goto not_ipv4; + if (*cur != '.') + goto not_ipv4; + cur++; + if (xmlParse3986DecOctet(&cur) != 0) + goto not_ipv4; + if (*cur != '.') + goto not_ipv4; + if (xmlParse3986DecOctet(&cur) != 0) + goto not_ipv4; + if (*cur != '.') + goto not_ipv4; + if (xmlParse3986DecOctet(&cur) != 0) + goto not_ipv4; + goto found; +not_ipv4: + cur = *str; + } + /* + * then this should be a hostname which can be empty + */ + while (ISA_UNRESERVED(cur) || ISA_PCT_ENCODED(cur) || ISA_SUB_DELIM(cur)) + NEXT(cur); +found: + if (uri != NULL) { + if (uri->authority != NULL) xmlFree(uri->authority); + uri->authority = NULL; + if (uri->server != NULL) xmlFree(uri->server); + if (cur != host) { + if (uri->cleanup & 2) + uri->server = STRNDUP(host, cur - host); + else + uri->server = xmlURIUnescapeString(host, cur - host, NULL); + } else + uri->server = NULL; + } + *str = cur; + return(0); +} + +/** + * xmlParse3986Authority: + * @uri: pointer to an URI structure + * @str: the string to analyze + * + * Parse an authority part and fills in the appropriate fields + * of the @uri structure + * + * authority = [ userinfo "@" ] host [ ":" port ] + * + * Returns 0 or the error code + */ +static int +xmlParse3986Authority(xmlURIPtr uri, const char **str) +{ + const char *cur; + int ret; + + cur = *str; + /* + * try to parse an userinfo and check for the trailing @ + */ + ret = xmlParse3986Userinfo(uri, &cur); + if ((ret != 0) || (*cur != '@')) + cur = *str; + else + cur++; + ret = xmlParse3986Host(uri, &cur); + if (ret != 0) return(ret); + if (*cur == ':') { + cur++; + ret = xmlParse3986Port(uri, &cur); + if (ret != 0) return(ret); + } + *str = cur; + return(0); +} + +/** + * xmlParse3986Segment: + * @str: the string to analyze + * @forbid: an optional forbidden character + * @empty: allow an empty segment + * + * Parse a segment and fills in the appropriate fields + * of the @uri structure + * + * segment = *pchar + * segment-nz = 1*pchar + * segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" ) + * ; non-zero-length segment without any colon ":" + * + * Returns 0 or the error code + */ +static int +xmlParse3986Segment(const char **str, char forbid, int empty) +{ + const char *cur; + + cur = *str; + if (!ISA_PCHAR(cur)) { + if (empty) + return(0); + return(1); + } + while (ISA_PCHAR(cur) && (*cur != forbid)) + NEXT(cur); + *str = cur; + return (0); +} + +/** + * xmlParse3986PathAbEmpty: + * @uri: pointer to an URI structure + * @str: the string to analyze + * + * Parse an path absolute or empty and fills in the appropriate fields + * of the @uri structure + * + * path-abempty = *( "/" segment ) + * + * Returns 0 or the error code + */ +static int +xmlParse3986PathAbEmpty(xmlURIPtr uri, const char **str) +{ + const char *cur; + int ret; + + cur = *str; + + while (*cur == '/') { + cur++; + ret = xmlParse3986Segment(&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) + uri->path = STRNDUP(*str, cur - *str); + else + uri->path = xmlURIUnescapeString(*str, cur - *str, NULL); + } else { + uri->path = NULL; + } + } + *str = cur; + return (0); +} + +/** + * xmlParse3986PathAbsolute: + * @uri: pointer to an URI structure + * @str: the string to analyze + * + * Parse an path absolute and fills in the appropriate fields + * of the @uri structure + * + * path-absolute = "/" [ segment-nz *( "/" segment ) ] + * + * Returns 0 or the error code + */ +static int +xmlParse3986PathAbsolute(xmlURIPtr uri, const char **str) +{ + const char *cur; + int ret; + + cur = *str; + + if (*cur != '/') + return(1); + cur++; + ret = xmlParse3986Segment(&cur, 0, 0); + if (ret == 0) { + while (*cur == '/') { + cur++; + ret = xmlParse3986Segment(&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) + uri->path = STRNDUP(*str, cur - *str); + else + uri->path = xmlURIUnescapeString(*str, cur - *str, NULL); + } else { + uri->path = NULL; + } + } + *str = cur; + return (0); +} + +/** + * xmlParse3986PathRootless: + * @uri: pointer to an URI structure + * @str: the string to analyze + * + * Parse an path without root and fills in the appropriate fields + * of the @uri structure + * + * path-rootless = segment-nz *( "/" segment ) + * + * Returns 0 or the error code + */ +static int +xmlParse3986PathRootless(xmlURIPtr uri, const char **str) +{ + const char *cur; + int ret; + + cur = *str; + + ret = xmlParse3986Segment(&cur, 0, 0); + if (ret != 0) return(ret); + while (*cur == '/') { + cur++; + ret = xmlParse3986Segment(&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) + uri->path = STRNDUP(*str, cur - *str); + else + uri->path = xmlURIUnescapeString(*str, cur - *str, NULL); + } else { + uri->path = NULL; + } + } + *str = cur; + return (0); +} + +/** + * xmlParse3986PathNoScheme: + * @uri: pointer to an URI structure + * @str: the string to analyze + * + * Parse an path which is not a scheme and fills in the appropriate fields + * of the @uri structure + * + * path-noscheme = segment-nz-nc *( "/" segment ) + * + * Returns 0 or the error code + */ +static int +xmlParse3986PathNoScheme(xmlURIPtr uri, const char **str) +{ + const char *cur; + int ret; + + cur = *str; + + ret = xmlParse3986Segment(&cur, ':', 0); + if (ret != 0) return(ret); + while (*cur == '/') { + cur++; + ret = xmlParse3986Segment(&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) + uri->path = STRNDUP(*str, cur - *str); + else + uri->path = xmlURIUnescapeString(*str, cur - *str, NULL); + } else { + uri->path = NULL; + } + } + *str = cur; + return (0); +} + +/** + * xmlParse3986HierPart: + * @uri: pointer to an URI structure + * @str: the string to analyze + * + * Parse an hierarchical part and fills in the appropriate fields + * of the @uri structure + * + * hier-part = "//" authority path-abempty + * / path-absolute + * / path-rootless + * / path-empty + * + * Returns 0 or the error code + */ +static int +xmlParse3986HierPart(xmlURIPtr uri, const char **str) +{ + const char *cur; + int ret; + + cur = *str; + + if ((*cur == '/') && (*(cur + 1) == '/')) { + cur += 2; + ret = xmlParse3986Authority(uri, &cur); + if (ret != 0) return(ret); + ret = xmlParse3986PathAbEmpty(uri, &cur); + if (ret != 0) return(ret); + *str = cur; + return(0); + } else if (*cur == '/') { + ret = xmlParse3986PathAbsolute(uri, &cur); + if (ret != 0) return(ret); + } else if (ISA_PCHAR(cur)) { + ret = xmlParse3986PathRootless(uri, &cur); + if (ret != 0) return(ret); + } else { + /* path-empty is effectively empty */ + if (uri != NULL) { + if (uri->path != NULL) xmlFree(uri->path); + uri->path = NULL; + } + } + *str = cur; + return (0); +} + +/** + * xmlParse3986RelativeRef: + * @uri: pointer to an URI structure + * @str: the string to analyze + * + * Parse an URI string and fills in the appropriate fields + * of the @uri structure + * + * relative-ref = relative-part [ "?" query ] [ "#" fragment ] + * relative-part = "//" authority path-abempty + * / path-absolute + * / path-noscheme + * / path-empty + * + * Returns 0 or the error code + */ +static int +xmlParse3986RelativeRef(xmlURIPtr uri, const char *str) { + int ret; + + if ((*str == '/') && (*(str + 1) == '/')) { + str += 2; + ret = xmlParse3986Authority(uri, &str); + if (ret != 0) return(ret); + ret = xmlParse3986PathAbEmpty(uri, &str); + if (ret != 0) return(ret); + } else if (*str == '/') { + ret = xmlParse3986PathAbsolute(uri, &str); + if (ret != 0) return(ret); + } else if (ISA_PCHAR(str)) { + ret = xmlParse3986PathNoScheme(uri, &str); + if (ret != 0) return(ret); + } else { + /* path-empty is effectively empty */ + if (uri != NULL) { + if (uri->path != NULL) xmlFree(uri->path); + uri->path = NULL; + } + } + + if (*str == '?') { + str++; + ret = xmlParse3986Query(uri, &str); + if (ret != 0) return(ret); + } + if (*str == '#') { + str++; + ret = xmlParse3986Fragment(uri, &str); + if (ret != 0) return(ret); + } + if (*str != 0) { + xmlCleanURI(uri); + return(1); + } + return(0); +} + + +/** + * xmlParse3986URI: + * @uri: pointer to an URI structure + * @str: the string to analyze + * + * Parse an URI string and fills in the appropriate fields + * of the @uri structure + * + * scheme ":" hier-part [ "?" query ] [ "#" fragment ] + * + * Returns 0 or the error code + */ +static int +xmlParse3986URI(xmlURIPtr uri, const char *str) { + int ret; + + ret = xmlParse3986Scheme(uri, &str); + if (ret != 0) return(ret); + if (*str != ':') { + return(1); + } + str++; + ret = xmlParse3986HierPart(uri, &str); + if (ret != 0) return(ret); + if (*str == '?') { + str++; + ret = xmlParse3986Query(uri, &str); + if (ret != 0) return(ret); + } + if (*str == '#') { + str++; + ret = xmlParse3986Fragment(uri, &str); + if (ret != 0) return(ret); + } + if (*str != 0) { + xmlCleanURI(uri); + return(1); + } + return(0); +} + +/** + * xmlParse3986URIReference: + * @uri: pointer to an URI structure + * @str: the string to analyze + * + * Parse an URI reference string and fills in the appropriate fields + * of the @uri structure + * + * URI-reference = URI / relative-ref + * + * Returns 0 or the error code + */ +static int +xmlParse3986URIReference(xmlURIPtr uri, const char *str) { + int ret; + + if (str == NULL) + return(-1); + xmlCleanURI(uri); + + /* + * Try first to parse absolute refs, then fallback to relative if + * it fails. + */ + ret = xmlParse3986URI(uri, str); + if (ret != 0) { + xmlCleanURI(uri); + ret = xmlParse3986RelativeRef(uri, str); + if (ret != 0) { + xmlCleanURI(uri); + return(ret); + } + } + 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; + int ret; + + if (str == NULL) + return(NULL); + uri = xmlCreateURI(); + if (uri != NULL) { + ret = xmlParse3986URIReference(uri, str); + if (ret) { + xmlFreeURI(uri); + return(NULL); + } + } + return(uri); +} + +/** + * xmlParseURIReference: + * @uri: pointer to an URI structure + * @str: the string to analyze + * + * Parse an URI reference string based on RFC 3986 and fills in the + * appropriate fields of the @uri structure + * + * URI-reference = URI / relative-ref + * + * Returns 0 or the error code + */ +int +xmlParseURIReference(xmlURIPtr uri, const char *str) { + return(xmlParse3986URIReference(uri, str)); +} + +/** + * xmlParseURIRaw: + * @str: the URI string to analyze + * @raw: if 1 unescaping of URI pieces are disabled + * + * Parse an URI but allows to keep intact the original fragments. + * + * URI-reference = URI / relative-ref + * + * Returns a newly built xmlURIPtr or NULL in case of error + */ +xmlURIPtr +xmlParseURIRaw(const char *str, int raw) { + xmlURIPtr uri; + int ret; + + if (str == NULL) + return(NULL); + uri = xmlCreateURI(); + if (uri != NULL) { + if (raw) { + uri->cleanup |= 2; + } + ret = xmlParseURIReference(uri, str); + if (ret) { + xmlFreeURI(uri); + return(NULL); + } + } + return(uri); +} + +/************************************************************************ + * * + * Generic URI structure functions * + * * + ************************************************************************/ + +/** + * xmlCreateURI: + * + * Simply creates an empty xmlURI + * + * Returns the new structure or NULL in case of error + */ +xmlURIPtr +xmlCreateURI(void) { + xmlURIPtr ret; + + ret = (xmlURIPtr) xmlMalloc(sizeof(xmlURI)); + if (ret == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlCreateURI: out of memory\n"); + return(NULL); + } + memset(ret, 0, sizeof(xmlURI)); + return(ret); +} + +/** + * xmlSaveUri: + * @uri: pointer to an xmlURI + * + * Save the URI as an escaped string + * + * Returns a new string (to be deallocated by caller) + */ +xmlChar * +xmlSaveUri(xmlURIPtr uri) { + xmlChar *ret = NULL; + xmlChar *temp; + const char *p; + int len; + int max; + + if (uri == NULL) return(NULL); + + + max = 80; + ret = (xmlChar *) xmlMallocAtomic((max + 1) * sizeof(xmlChar)); + if (ret == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlSaveUri: out of memory\n"); + return(NULL); + } + len = 0; + + if (uri->scheme != NULL) { + p = uri->scheme; + while (*p != 0) { + if (len >= max) { + max *= 2; + temp = (xmlChar *) xmlRealloc(ret, (max + 1) * sizeof(xmlChar)); + if (temp == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlSaveUri: out of memory\n"); + xmlFree(ret); + return(NULL); + } + ret = temp; + } + ret[len++] = *p++; + } + if (len >= max) { + max *= 2; + temp = (xmlChar *) xmlRealloc(ret, (max + 1) * sizeof(xmlChar)); + if (temp == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlSaveUri: out of memory\n"); + xmlFree(ret); + return(NULL); + } + ret = temp; + } + ret[len++] = ':'; + } + if (uri->opaque != NULL) { + p = uri->opaque; + while (*p != 0) { + if (len + 3 >= max) { + max *= 2; + temp = (xmlChar *) xmlRealloc(ret, (max + 1) * sizeof(xmlChar)); + if (temp == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlSaveUri: out of memory\n"); + xmlFree(ret); + return(NULL); + } + ret = temp; + } + if (IS_RESERVED(*(p)) || IS_UNRESERVED(*(p))) + ret[len++] = *p++; + else { + int val = *(unsigned char *)p++; + int hi = val / 0x10, lo = val % 0x10; + ret[len++] = '%'; + ret[len++] = hi + (hi > 9? 'A'-10 : '0'); + ret[len++] = lo + (lo > 9? 'A'-10 : '0'); + } + } + } else { + if (uri->server != NULL) { + if (len + 3 >= max) { + max *= 2; + temp = (xmlChar *) xmlRealloc(ret, (max + 1) * sizeof(xmlChar)); + if (temp == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlSaveUri: out of memory\n"); + xmlFree(ret); + return(NULL); + } + ret = temp; + } + ret[len++] = '/'; + ret[len++] = '/'; + if (uri->user != NULL) { + p = uri->user; + while (*p != 0) { + if (len + 3 >= max) { + max *= 2; + temp = (xmlChar *) xmlRealloc(ret, + (max + 1) * sizeof(xmlChar)); + if (temp == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlSaveUri: out of memory\n"); + xmlFree(ret); + return(NULL); + } + ret = temp; + } + if ((IS_UNRESERVED(*(p))) || + ((*(p) == ';')) || ((*(p) == ':')) || + ((*(p) == '&')) || ((*(p) == '=')) || + ((*(p) == '+')) || ((*(p) == '$')) || + ((*(p) == ','))) + ret[len++] = *p++; + else { + int val = *(unsigned char *)p++; + int hi = val / 0x10, lo = val % 0x10; + ret[len++] = '%'; + ret[len++] = hi + (hi > 9? 'A'-10 : '0'); + ret[len++] = lo + (lo > 9? 'A'-10 : '0'); + } + } + if (len + 3 >= max) { + max *= 2; + temp = (xmlChar *) xmlRealloc(ret, + (max + 1) * sizeof(xmlChar)); + if (temp == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlSaveUri: out of memory\n"); + xmlFree(ret); + return(NULL); + } + ret = temp; + } + ret[len++] = '@'; + } + p = uri->server; + while (*p != 0) { + if (len >= max) { + max *= 2; + temp = (xmlChar *) xmlRealloc(ret, + (max + 1) * sizeof(xmlChar)); + if (temp == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlSaveUri: out of memory\n"); + xmlFree(ret); + return(NULL); + } + ret = temp; + } + ret[len++] = *p++; + } + if (uri->port > 0) { + if (len + 10 >= max) { + max *= 2; + temp = (xmlChar *) xmlRealloc(ret, + (max + 1) * sizeof(xmlChar)); + if (temp == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlSaveUri: out of memory\n"); + xmlFree(ret); + return(NULL); + } + ret = temp; + } + len += snprintf((char *) &ret[len], max - len, ":%d", uri->port); + } + } else if (uri->authority != NULL) { + if (len + 3 >= max) { + max *= 2; + temp = (xmlChar *) xmlRealloc(ret, + (max + 1) * sizeof(xmlChar)); + if (temp == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlSaveUri: out of memory\n"); + xmlFree(ret); + return(NULL); + } + ret = temp; + } + ret[len++] = '/'; + ret[len++] = '/'; + p = uri->authority; + while (*p != 0) { + if (len + 3 >= max) { + max *= 2; + temp = (xmlChar *) xmlRealloc(ret, + (max + 1) * sizeof(xmlChar)); + if (temp == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlSaveUri: out of memory\n"); + xmlFree(ret); + return(NULL); + } + ret = temp; + } + if ((IS_UNRESERVED(*(p))) || + ((*(p) == '$')) || ((*(p) == ',')) || ((*(p) == ';')) || + ((*(p) == ':')) || ((*(p) == '@')) || ((*(p) == '&')) || + ((*(p) == '=')) || ((*(p) == '+'))) + ret[len++] = *p++; + else { + int val = *(unsigned char *)p++; + int hi = val / 0x10, lo = val % 0x10; + ret[len++] = '%'; + ret[len++] = hi + (hi > 9? 'A'-10 : '0'); + ret[len++] = lo + (lo > 9? 'A'-10 : '0'); + } + } + } else if (uri->scheme != NULL) { + if (len + 3 >= max) { + max *= 2; + temp = (xmlChar *) xmlRealloc(ret, + (max + 1) * sizeof(xmlChar)); + if (temp == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlSaveUri: out of memory\n"); + xmlFree(ret); + return(NULL); + } + ret = temp; + } + ret[len++] = '/'; + ret[len++] = '/'; + } + if (uri->path != NULL) { + p = uri->path; + /* + * the colon in file:///d: should not be escaped or + * Windows accesses fail later. + */ + if ((uri->scheme != NULL) && + (p[0] == '/') && + (((p[1] >= 'a') && (p[1] <= 'z')) || + ((p[1] >= 'A') && (p[1] <= 'Z'))) && + (p[2] == ':') && + (xmlStrEqual(BAD_CAST uri->scheme, BAD_CAST "file"))) { + if (len + 3 >= max) { + max *= 2; + ret = (xmlChar *) xmlRealloc(ret, + (max + 1) * sizeof(xmlChar)); + if (ret == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlSaveUri: out of memory\n"); + return(NULL); + } + } + ret[len++] = *p++; + ret[len++] = *p++; + ret[len++] = *p++; + } + while (*p != 0) { + if (len + 3 >= max) { + max *= 2; + temp = (xmlChar *) xmlRealloc(ret, + (max + 1) * sizeof(xmlChar)); + if (temp == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlSaveUri: out of memory\n"); + xmlFree(ret); + return(NULL); + } + ret = temp; + } + if ((IS_UNRESERVED(*(p))) || ((*(p) == '/')) || + ((*(p) == ';')) || ((*(p) == '@')) || ((*(p) == '&')) || + ((*(p) == '=')) || ((*(p) == '+')) || ((*(p) == '$')) || + ((*(p) == ','))) + ret[len++] = *p++; + else { + int val = *(unsigned char *)p++; + int hi = val / 0x10, lo = val % 0x10; + ret[len++] = '%'; + ret[len++] = hi + (hi > 9? 'A'-10 : '0'); + ret[len++] = lo + (lo > 9? 'A'-10 : '0'); + } + } + } + if (uri->query_raw != NULL) { + if (len + 1 >= max) { + max *= 2; + temp = (xmlChar *) xmlRealloc(ret, + (max + 1) * sizeof(xmlChar)); + if (temp == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlSaveUri: out of memory\n"); + xmlFree(ret); + return(NULL); + } + ret = temp; + } + ret[len++] = '?'; + p = uri->query_raw; + while (*p != 0) { + if (len + 1 >= max) { + max *= 2; + temp = (xmlChar *) xmlRealloc(ret, + (max + 1) * sizeof(xmlChar)); + if (temp == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlSaveUri: out of memory\n"); + xmlFree(ret); + return(NULL); + } + ret = temp; + } + ret[len++] = *p++; + } + } else if (uri->query != NULL) { + if (len + 3 >= max) { + max *= 2; + temp = (xmlChar *) xmlRealloc(ret, + (max + 1) * sizeof(xmlChar)); + if (temp == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlSaveUri: out of memory\n"); + xmlFree(ret); + return(NULL); + } + ret = temp; + } + ret[len++] = '?'; + p = uri->query; + while (*p != 0) { + if (len + 3 >= max) { + max *= 2; + temp = (xmlChar *) xmlRealloc(ret, + (max + 1) * sizeof(xmlChar)); + if (temp == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlSaveUri: out of memory\n"); + xmlFree(ret); + return(NULL); + } + ret = temp; + } + if ((IS_UNRESERVED(*(p))) || (IS_RESERVED(*(p)))) + ret[len++] = *p++; + else { + int val = *(unsigned char *)p++; + int hi = val / 0x10, lo = val % 0x10; + ret[len++] = '%'; + ret[len++] = hi + (hi > 9? 'A'-10 : '0'); + ret[len++] = lo + (lo > 9? 'A'-10 : '0'); + } + } + } + } + if (uri->fragment != NULL) { + if (len + 3 >= max) { + max *= 2; + temp = (xmlChar *) xmlRealloc(ret, + (max + 1) * sizeof(xmlChar)); + if (temp == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlSaveUri: out of memory\n"); + xmlFree(ret); + return(NULL); + } + ret = temp; + } + ret[len++] = '#'; + p = uri->fragment; + while (*p != 0) { + if (len + 3 >= max) { + max *= 2; + temp = (xmlChar *) xmlRealloc(ret, + (max + 1) * sizeof(xmlChar)); + if (temp == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlSaveUri: out of memory\n"); + xmlFree(ret); + return(NULL); + } + ret = temp; + } + if ((IS_UNRESERVED(*(p))) || (IS_RESERVED(*(p)))) + ret[len++] = *p++; + else { + int val = *(unsigned char *)p++; + int hi = val / 0x10, lo = val % 0x10; + ret[len++] = '%'; + ret[len++] = hi + (hi > 9? 'A'-10 : '0'); + ret[len++] = lo + (lo > 9? 'A'-10 : '0'); + } + } + } + if (len >= max) { + max *= 2; + temp = (xmlChar *) xmlRealloc(ret, (max + 1) * sizeof(xmlChar)); + if (temp == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlSaveUri: out of memory\n"); + xmlFree(ret); + return(NULL); + } + ret = temp; + } + ret[len] = 0; + return(ret); +} + +/** + * xmlPrintURI: + * @stream: a FILE* for the output + * @uri: pointer to an xmlURI + * + * Prints the URI in the stream @stream. + */ +void +xmlPrintURI(FILE *stream, xmlURIPtr uri) { + xmlChar *out; + + out = xmlSaveUri(uri); + if (out != NULL) { + fprintf(stream, "%s", (char *) out); + xmlFree(out); + } +} + +/** + * xmlCleanURI: + * @uri: pointer to an xmlURI + * + * Make sure the xmlURI struct is free of content + */ +static void +xmlCleanURI(xmlURIPtr uri) { + if (uri == NULL) return; + + if (uri->scheme != NULL) xmlFree(uri->scheme); + uri->scheme = NULL; + if (uri->server != NULL) xmlFree(uri->server); + uri->server = NULL; + if (uri->user != NULL) xmlFree(uri->user); + uri->user = NULL; + if (uri->path != NULL) xmlFree(uri->path); + uri->path = NULL; + if (uri->fragment != NULL) xmlFree(uri->fragment); + uri->fragment = NULL; + if (uri->opaque != NULL) xmlFree(uri->opaque); + uri->opaque = NULL; + if (uri->authority != NULL) xmlFree(uri->authority); + uri->authority = NULL; + if (uri->query != NULL) xmlFree(uri->query); + uri->query = NULL; + if (uri->query_raw != NULL) xmlFree(uri->query_raw); + uri->query_raw = NULL; +} + +/** + * xmlFreeURI: + * @uri: pointer to an xmlURI + * + * Free up the xmlURI struct + */ +void +xmlFreeURI(xmlURIPtr uri) { + if (uri == NULL) return; + + if (uri->scheme != NULL) xmlFree(uri->scheme); + if (uri->server != NULL) xmlFree(uri->server); + if (uri->user != NULL) xmlFree(uri->user); + if (uri->path != NULL) xmlFree(uri->path); + if (uri->fragment != NULL) xmlFree(uri->fragment); + if (uri->opaque != NULL) xmlFree(uri->opaque); + if (uri->authority != NULL) xmlFree(uri->authority); + if (uri->query != NULL) xmlFree(uri->query); + if (uri->query_raw != NULL) xmlFree(uri->query_raw); + xmlFree(uri); +} + +/************************************************************************ + * * + * Helper functions * + * * + ************************************************************************/ + +/** + * 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) { + char *cur, *out; + + 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); + + /* Keep everything we've seen so far. */ + out = cur; + + /* + * 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]; + } + /* nomalize // */ + while ((cur[0] == '/') && (cur[1] == '/')) + cur++; + + (out++)[0] = (cur++)[0]; + } + 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 "/../", where 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 "/..", where + * is a complete path segment not equal to "..", that + * "/.." 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. + */ + ++segp; + if (((cur[0] == '.') && (cur[1] == '.') && (segp == cur+3)) + || ((segp[0] != '.') || (segp[1] != '.') + || ((segp[2] != '/') && (segp[2] != '\0')))) { + cur = segp; + continue; + } + + /* 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 this is the end of the buffer, we're done. */ + if (segp[2] == '\0') { + cur[0] = '\0'; + break; + } + /* 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; + + if (cur != path) { + out = path; + while (cur[0] != '\0') + (out++)[0] = (cur++)[0]; + out[0] = 0; + } + } + + return(0); +} + +static int is_hex(char c) { + if (((c >= '0') && (c <= '9')) || + ((c >= 'a') && (c <= 'f')) || + ((c >= 'A') && (c <= 'F'))) + return(1); + return(0); +} + +/** + * xmlURIUnescapeString: + * @str: the string to unescape + * @len: the length in bytes to unescape (or <= 0 to indicate full string) + * @target: optional destination buffer + * + * Unescaping routine, but does not check that the string is an URI. The + * output is a direct unsigned char translation of %XX values (no encoding) + * Note that the length of the result can only be smaller or same size as + * the input string. + * + * Returns a copy of the string, but unescaped, will return NULL only in case + * of error + */ +char * +xmlURIUnescapeString(const char *str, int len, char *target) { + char *ret, *out; + const char *in; + + if (str == NULL) + return(NULL); + if (len <= 0) len = strlen(str); + if (len < 0) return(NULL); + + if (target == NULL) { + ret = (char *) xmlMallocAtomic(len + 1); + if (ret == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlURIUnescapeString: out of memory\n"); + return(NULL); + } + } else + ret = target; + in = str; + out = ret; + while(len > 0) { + if ((len > 2) && (*in == '%') && (is_hex(in[1])) && (is_hex(in[2]))) { + in++; + if ((*in >= '0') && (*in <= '9')) + *out = (*in - '0'); + else if ((*in >= 'a') && (*in <= 'f')) + *out = (*in - 'a') + 10; + else if ((*in >= 'A') && (*in <= 'F')) + *out = (*in - 'A') + 10; + in++; + if ((*in >= '0') && (*in <= '9')) + *out = *out * 16 + (*in - '0'); + else if ((*in >= 'a') && (*in <= 'f')) + *out = *out * 16 + (*in - 'a') + 10; + else if ((*in >= 'A') && (*in <= 'F')) + *out = *out * 16 + (*in - 'A') + 10; + in++; + len -= 3; + out++; + } else { + *out++ = *in++; + len--; + } + } + *out = 0; + return(ret); +} + +/** + * xmlURIEscapeStr: + * @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) + * and the characters in the exception list. + * + * Returns a new escaped string or NULL in case of error. + */ +xmlChar * +xmlURIEscapeStr(const xmlChar *str, const xmlChar *list) { + xmlChar *ret, ch; + xmlChar *temp; + const xmlChar *in; + + unsigned int len, out; + + if (str == NULL) + return(NULL); + if (str[0] == 0) + return(xmlStrdup(str)); + len = xmlStrlen(str); + if (!(len > 0)) return(NULL); + + len += 20; + ret = (xmlChar *) xmlMallocAtomic(len); + if (ret == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlURIEscapeStr: out of memory\n"); + return(NULL); + } + in = (const xmlChar *) str; + out = 0; + while(*in != 0) { + if (len - out <= 3) { + len += 20; + temp = (xmlChar *) xmlRealloc(ret, len); + if (temp == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlURIEscapeStr: out of memory\n"); + xmlFree(ret); + return(NULL); + } + ret = temp; + } + + ch = *in; + + if ((ch != '@') && (!IS_UNRESERVED(ch)) && (!xmlStrchr(list, ch))) { + unsigned char val; + ret[out++] = '%'; + val = ch >> 4; + if (val <= 9) + ret[out++] = '0' + val; + else + ret[out++] = 'A' + val - 0xA; + val = ch & 0xF; + if (val <= 9) + ret[out++] = '0' + val; + else + ret[out++] = 'A' + val - 0xA; + in++; + } else { + ret[out++] = *in++; + } + + } + ret[out] = 0; + return(ret); +} + +/** + * xmlURIEscape: + * @str: the string of the URI to escape + * + * Escaping routine, does not do validity checks ! + * It will try to escape the chars needing this, but this is heuristic + * based it's impossible to be sure. + * + * Returns an copy of the string, but escaped + * + * 25 May 2001 + * Uses xmlParseURI and xmlURIEscapeStr to try to escape correctly + * according to RFC2396. + * - Carl Douglas + */ +xmlChar * +xmlURIEscape(const xmlChar * str) +{ + xmlChar *ret, *segment = NULL; + xmlURIPtr uri; + int ret2; + +#define NULLCHK(p) if(!p) { \ + xmlGenericError(xmlGenericErrorContext, \ + "xmlURIEscape: out of memory\n"); \ + xmlFreeURI(uri); \ + return NULL; } \ + + if (str == NULL) + return (NULL); + + uri = xmlCreateURI(); + if (uri != NULL) { + /* + * Allow escaping errors in the unescaped form + */ + uri->cleanup = 1; + ret2 = xmlParseURIReference(uri, (const char *)str); + if (ret2) { + xmlFreeURI(uri); + return (NULL); + } + } + + if (!uri) + return NULL; + + ret = NULL; + + if (uri->scheme) { + segment = xmlURIEscapeStr(BAD_CAST uri->scheme, BAD_CAST "+-."); + NULLCHK(segment) + ret = xmlStrcat(ret, segment); + ret = xmlStrcat(ret, BAD_CAST ":"); + xmlFree(segment); + } + + if (uri->authority) { + segment = + xmlURIEscapeStr(BAD_CAST uri->authority, BAD_CAST "/?;:@"); + NULLCHK(segment) + ret = xmlStrcat(ret, BAD_CAST "//"); + ret = xmlStrcat(ret, segment); + xmlFree(segment); + } + + if (uri->user) { + segment = xmlURIEscapeStr(BAD_CAST uri->user, BAD_CAST ";:&=+$,"); + NULLCHK(segment) + ret = xmlStrcat(ret,BAD_CAST "//"); + ret = xmlStrcat(ret, segment); + ret = xmlStrcat(ret, BAD_CAST "@"); + xmlFree(segment); + } + + if (uri->server) { + segment = xmlURIEscapeStr(BAD_CAST uri->server, BAD_CAST "/?;:@"); + NULLCHK(segment) + if (uri->user == NULL) + ret = xmlStrcat(ret, BAD_CAST "//"); + ret = xmlStrcat(ret, segment); + xmlFree(segment); + } + + if (uri->port) { + xmlChar port[10]; + + snprintf((char *) port, 10, "%d", uri->port); + ret = xmlStrcat(ret, BAD_CAST ":"); + ret = xmlStrcat(ret, port); + } + + if (uri->path) { + segment = + xmlURIEscapeStr(BAD_CAST uri->path, BAD_CAST ":@&=+$,/?;"); + NULLCHK(segment) + ret = xmlStrcat(ret, segment); + xmlFree(segment); + } + + if (uri->query_raw) { + ret = xmlStrcat(ret, BAD_CAST "?"); + ret = xmlStrcat(ret, BAD_CAST uri->query_raw); + } + else if (uri->query) { + segment = + xmlURIEscapeStr(BAD_CAST uri->query, BAD_CAST ";/?:@&=+,$"); + NULLCHK(segment) + ret = xmlStrcat(ret, BAD_CAST "?"); + ret = xmlStrcat(ret, segment); + xmlFree(segment); + } + + if (uri->opaque) { + segment = xmlURIEscapeStr(BAD_CAST uri->opaque, BAD_CAST ""); + NULLCHK(segment) + ret = xmlStrcat(ret, segment); + xmlFree(segment); + } + + if (uri->fragment) { + segment = xmlURIEscapeStr(BAD_CAST uri->fragment, BAD_CAST "#"); + NULLCHK(segment) + ret = xmlStrcat(ret, BAD_CAST "#"); + ret = xmlStrcat(ret, segment); + xmlFree(segment); + } + + xmlFreeURI(uri); +#undef NULLCHK + + return (ret); +} + +/************************************************************************ + * * + * Public functions * + * * + ************************************************************************/ + +/** + * 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 *val = NULL; + int ret, len, indx, cur, out; + xmlURIPtr ref = NULL; + xmlURIPtr bas = NULL; + xmlURIPtr res = NULL; + + /* + * 1) The URI reference is parsed into the potential four components and + * fragment identifier, as described in Section 4.3. + * + * NOTE that a completely empty URI is treated by modern browsers + * 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 (ret != 0) + goto done; + if ((ref != NULL) && (ref->scheme != NULL)) { + /* + * The URI is absolute don't modify. + */ + val = xmlStrdup(URI); + goto done; + } + if (base == NULL) + ret = -1; + else { + bas = xmlCreateURI(); + if (bas == NULL) + goto done; + ret = xmlParseURIReference(bas, (const char *) base); + } + if (ret != 0) { + if (ref) + val = xmlSaveUri(ref); + goto done; + } + if (ref == NULL) { + /* + * the base fragment must be ignored + */ + if (bas->fragment != NULL) { + xmlFree(bas->fragment); + bas->fragment = NULL; + } + val = xmlSaveUri(bas); + goto done; + } + + /* + * 2) If the path component is empty and the scheme, authority, and + * query components are undefined, then it is a reference to the + * current document and we are done. Otherwise, the reference URI's + * query and fragment components are defined as found (or not found) + * within the URI reference and not inherited from the base URI. + * + * NOTE that in modern browsers, the parsing differs from the above + * in the following aspect: the query component is allowed to be + * defined while still treating this as a reference to the current + * document. + */ + res = xmlCreateURI(); + if (res == NULL) + goto done; + if ((ref->scheme == NULL) && (ref->path == NULL) && + ((ref->authority == NULL) && (ref->server == NULL))) { + if (bas->scheme != NULL) + res->scheme = xmlMemStrdup(bas->scheme); + if (bas->authority != NULL) + res->authority = xmlMemStrdup(bas->authority); + else if (bas->server != NULL) { + res->server = xmlMemStrdup(bas->server); + if (bas->user != NULL) + res->user = xmlMemStrdup(bas->user); + res->port = bas->port; + } + if (bas->path != NULL) + res->path = xmlMemStrdup(bas->path); + if (ref->query_raw != NULL) + res->query_raw = xmlMemStrdup (ref->query_raw); + else if (ref->query != NULL) + res->query = xmlMemStrdup(ref->query); + else if (bas->query_raw != NULL) + res->query_raw = xmlMemStrdup(bas->query_raw); + else if (bas->query != NULL) + res->query = xmlMemStrdup(bas->query); + if (ref->fragment != NULL) + res->fragment = xmlMemStrdup(ref->fragment); + goto step_7; + } + + /* + * 3) If the scheme component is defined, indicating that the reference + * starts with a scheme name, then the reference is interpreted as an + * absolute URI and we are done. Otherwise, the reference URI's + * scheme is inherited from the base URI's scheme component. + */ + if (ref->scheme != NULL) { + val = xmlSaveUri(ref); + goto done; + } + if (bas->scheme != NULL) + res->scheme = xmlMemStrdup(bas->scheme); + + if (ref->query_raw != NULL) + res->query_raw = xmlMemStrdup(ref->query_raw); + else if (ref->query != NULL) + res->query = xmlMemStrdup(ref->query); + if (ref->fragment != NULL) + res->fragment = xmlMemStrdup(ref->fragment); + + /* + * 4) If the authority component is defined, then the reference is a + * network-path and we skip to step 7. Otherwise, the reference + * URI's authority is inherited from the base URI's authority + * component, which will also be undefined if the URI scheme does not + * use an authority component. + */ + if ((ref->authority != NULL) || (ref->server != NULL)) { + if (ref->authority != NULL) + res->authority = xmlMemStrdup(ref->authority); + else { + res->server = xmlMemStrdup(ref->server); + if (ref->user != NULL) + res->user = xmlMemStrdup(ref->user); + res->port = ref->port; + } + if (ref->path != NULL) + res->path = xmlMemStrdup(ref->path); + goto step_7; + } + if (bas->authority != NULL) + res->authority = xmlMemStrdup(bas->authority); + else if (bas->server != NULL) { + res->server = xmlMemStrdup(bas->server); + if (bas->user != NULL) + res->user = xmlMemStrdup(bas->user); + res->port = bas->port; + } + + /* + * 5) If the path component begins with a slash character ("/"), then + * the reference is an absolute-path and we skip to step 7. + */ + if ((ref->path != NULL) && (ref->path[0] == '/')) { + res->path = xmlMemStrdup(ref->path); + goto step_7; + } + + + /* + * 6) If this step is reached, then we are resolving a relative-path + * reference. The relative path needs to be merged with the base + * URI's path. Although there are many ways to do this, we will + * describe a simple method using a separate string buffer. + * + * Allocate a buffer large enough for the result string. + */ + len = 2; /* extra / and 0 */ + if (ref->path != NULL) + len += strlen(ref->path); + if (bas->path != NULL) + len += strlen(bas->path); + res->path = (char *) xmlMallocAtomic(len); + if (res->path == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlBuildURI: out of memory\n"); + goto done; + } + res->path[0] = 0; + + /* + * a) All but the last segment of the base URI's path component is + * copied to the buffer. In other words, any characters after the + * last (right-most) slash character, if any, are excluded. + */ + cur = 0; + out = 0; + if (bas->path != NULL) { + while (bas->path[cur] != 0) { + while ((bas->path[cur] != 0) && (bas->path[cur] != '/')) + cur++; + if (bas->path[cur] == 0) + break; + + cur++; + while (out < cur) { + res->path[out] = bas->path[out]; + out++; + } + } + } + res->path[out] = 0; + + /* + * b) The reference's path component is appended to the buffer + * string. + */ + if (ref->path != NULL && ref->path[0] != 0) { + indx = 0; + /* + * Ensure the path includes a '/' + */ + if ((out == 0) && (bas->server != NULL)) + res->path[out++] = '/'; + while (ref->path[indx] != 0) { + res->path[out++] = ref->path[indx++]; + } + } + res->path[out] = 0; + + /* + * Steps c) to h) are really path normalization steps + */ + xmlNormalizeURIPath(res->path); + +step_7: + + /* + * 7) The resulting URI components, including any inherited from the + * base URI, are recombined to give the absolute form of the URI + * reference. + */ + val = xmlSaveUri(res); + +done: + if (ref != NULL) + xmlFreeURI(ref); + if (bas != NULL) + xmlFreeURI(bas); + if (res != NULL) + xmlFreeURI(res); + return(val); +} + +/** + * xmlBuildRelativeURI: + * @URI: the URI reference under consideration + * @base: the base value + * + * Expresses the URI of the reference in terms relative to the + * base. Some examples of this operation include: + * base = "http://site1.com/docs/book1.html" + * URI input URI returned + * docs/pic1.gif pic1.gif + * docs/img/pic1.gif img/pic1.gif + * img/pic1.gif ../img/pic1.gif + * http://site1.com/docs/pic1.gif pic1.gif + * http://site2.com/docs/pic1.gif http://site2.com/docs/pic1.gif + * + * base = "docs/book1.html" + * URI input URI returned + * docs/pic1.gif pic1.gif + * docs/img/pic1.gif img/pic1.gif + * img/pic1.gif ../img/pic1.gif + * http://site1.com/docs/pic1.gif http://site1.com/docs/pic1.gif + * + * + * Note: if the URI reference is really wierd or complicated, it may be + * worthwhile to first convert it into a "nice" one by calling + * xmlBuildURI (using 'base') before calling this routine, + * 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. + */ +xmlChar * +xmlBuildRelativeURI (const xmlChar * URI, const xmlChar * base) +{ + xmlChar *val = NULL; + int ret; + int ix; + int pos = 0; + int nbslash = 0; + int len; + xmlURIPtr ref = NULL; + xmlURIPtr bas = NULL; + xmlChar *bptr, *uptr, *vptr; + int remove_path = 0; + + if ((URI == NULL) || (*URI == 0)) + return NULL; + + /* + * 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); + + /* + * Next parse base into the same standard form + */ + if ((base == NULL) || (*base == 0)) { + val = xmlStrdup (URI); + 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)))) { + val = xmlStrdup (URI); + goto done; + } + if (xmlStrEqual((xmlChar *)bas->path, (xmlChar *)ref->path)) { + val = xmlStrdup(BAD_CAST ""); + goto done; + } + if (bas->path == NULL) { + val = xmlStrdup((xmlChar *)ref->path); + goto done; + } + if (ref->path == NULL) { + ref->path = (char *) "/"; + remove_path = 1; + } + + /* + * 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) + */ + if (bas->path == NULL) { + if (ref->path != NULL) { + uptr = (xmlChar *) ref->path; + if (*uptr == '/') + uptr++; + /* exception characters from xmlSaveUri */ + val = xmlURIEscapeStr(uptr, BAD_CAST "/;&=+$,"); + } + goto done; + } + bptr = (xmlChar *)bas->path; + if (ref->path == NULL) { + for (ix = 0; bptr[ix] != 0; ix++) { + if (bptr[ix] == '/') + nbslash++; + } + uptr = NULL; + len = 1; /* this is for a string terminator only */ + } else { + /* + * Next we compare the two strings and find where they first differ + */ + if ((ref->path[pos] == '.') && (ref->path[pos+1] == '/')) + pos += 2; + if ((*bptr == '.') && (bptr[1] == '/')) + bptr += 2; + else if ((*bptr == '/') && (ref->path[pos] != '/')) + bptr++; + while ((bptr[pos] == ref->path[pos]) && (bptr[pos] != 0)) + pos++; + + if (bptr[pos] == ref->path[pos]) { + val = xmlStrdup(BAD_CAST ""); + goto done; /* (I can't imagine why anyone would do this) */ + } + + /* + * In URI, "back up" to the last '/' encountered. This will be the + * beginning of the "unique" suffix of URI + */ + ix = pos; + if ((ref->path[ix] == '/') && (ix > 0)) + ix--; + else if ((ref->path[ix] == 0) && (ix > 1) && (ref->path[ix - 1] == '/')) + ix -= 2; + for (; ix > 0; ix--) { + if (ref->path[ix] == '/') + break; + } + if (ix == 0) { + uptr = (xmlChar *)ref->path; + } else { + ix++; + uptr = (xmlChar *)&ref->path[ix]; + } + + /* + * In base, count the number of '/' from the differing point + */ + if (bptr[pos] != ref->path[pos]) {/* check for trivial URI == base */ + for (; bptr[ix] != 0; ix++) { + if (bptr[ix] == '/') + nbslash++; + } + } + len = xmlStrlen (uptr) + 1; + } + + if (nbslash == 0) { + if (uptr != NULL) + /* exception characters from xmlSaveUri */ + val = xmlURIEscapeStr(uptr, BAD_CAST "/;&=+$,"); + goto done; + } + + /* + * Allocate just enough space for the returned string - + * length of the remainder of the URI, plus enough space + * for the "../" groups, plus one for the terminator + */ + val = (xmlChar *) xmlMalloc (len + 3 * nbslash); + if (val == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlBuildRelativeURI: out of memory\n"); + goto done; + } + vptr = val; + /* + * Put in as many "../" as needed + */ + for (; nbslash>0; nbslash--) { + *vptr++ = '.'; + *vptr++ = '.'; + *vptr++ = '/'; + } + /* + * Finish up with the end of the URI + */ + if (uptr != NULL) { + if ((vptr > val) && (len > 0) && + (uptr[0] == '/') && (vptr[-1] == '/')) { + memcpy (vptr, uptr + 1, len - 1); + vptr[len - 2] = 0; + } else { + memcpy (vptr, uptr, len); + vptr[len - 1] = 0; + } + } else { + vptr[len - 1] = 0; + } + + /* escape the freshly-built path */ + vptr = val; + /* exception characters from xmlSaveUri */ + val = xmlURIEscapeStr(vptr, BAD_CAST "/;&=+$,"); + xmlFree(vptr); + +done: + /* + * Free the working variables + */ + if (remove_path != 0) + ref->path = NULL; + if (ref != NULL) + xmlFreeURI (ref); + if (bas != NULL) + xmlFreeURI (bas); + + return val; +} + +/** + * xmlCanonicPath: + * @path: the resource locator in a filesystem notation + * + * Constructs a canonic path from the specified path. + * + * 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 + * by the returned string. If there is insufficient memory available, or the + * argument is NULL, the function returns NULL. + */ +#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) && !defined(__CYGWIN__) + int len = 0; + int i = 0; + xmlChar *p = NULL; +#endif + xmlURIPtr uri; + xmlChar *ret; + const xmlChar *absuri; + + if (path == NULL) + return(NULL); + + /* 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; + } + } + } + +path_processing: +/* For Windows implementations, replace backslashes with 'forward slashes' */ +#if defined(_WIN32) && !defined(__CYGWIN__) + /* + * 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 = xmlStrdup(BAD_CAST "file"); + /* allocate space for leading '/' + path + string terminator */ + uri->path = xmlMallocAtomic(len + 2); + if (uri->path == NULL) { + xmlFreeURI(uri); /* Guard agains 'out of memory' */ + return(NULL); + } + /* Put in leading '/' plus path */ + uri->path[0] = '/'; + p = uri->path + 1; + strncpy(p, path, len + 1); + } else { + uri->path = xmlStrdup(path); + if (uri->path == NULL) { + xmlFreeURI(uri); + return(NULL); + } + p = uri->path; + } + /* Now change all occurences of '\' to '/' */ + while (*p != '\0') { + if (*p == '\\') + *p = '/'; + p++; + } + + if (uri->scheme == NULL) { + ret = xmlStrdup((const xmlChar *) uri->path); + } else { + ret = xmlSaveUri(uri); + } + + xmlFreeURI(uri); +#else + ret = xmlStrdup((const xmlChar *) path); +#endif + return(ret); +} + +/** + * xmlPathToURI: + * @path: the resource locator in a filesystem notation + * + * Constructs an URI expressing the existing path + * + * Returns a new URI, or a duplicate of the path parameter if the + * construction fails. 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. + */ +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) && !defined(__CYGWIN__) + /* xmlCanonicPath can return an URI on Windows (is that the intended behaviour?) + If 'cal' is a valid URI allready 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); +} +#define bottom_uri +#include "elfgcchack.h" diff --git a/android/native/libxml2/valid.c b/android/native/libxml2/valid.c new file mode 100644 index 0000000000..5de491d75f --- /dev/null +++ b/android/native/libxml2/valid.c @@ -0,0 +1,7048 @@ +/* + * valid.c : part of the code use to do the DTD handling and the validity + * checking + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + */ + +#define IN_LIBXML +#include "libxml.h" + +#include + +#ifdef HAVE_STDLIB_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static xmlElementPtr xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name, + int create); +/* #define DEBUG_VALID_ALGO */ +/* #define DEBUG_REGEXP_ALGO */ + +#define TODO \ + xmlGenericError(xmlGenericErrorContext, \ + "Unimplemented block at %s:%d\n", \ + __FILE__, __LINE__); + +#ifdef LIBXML_VALID_ENABLED +static int +xmlValidateAttributeValueInternal(xmlDocPtr doc, xmlAttributeType type, + const xmlChar *value); +#endif +/************************************************************************ + * * + * Error handling routines * + * * + ************************************************************************/ + +/** + * xmlVErrMemory: + * @ctxt: an XML validation parser context + * @extra: extra informations + * + * Handle an out of memory error + */ +static void +xmlVErrMemory(xmlValidCtxtPtr ctxt, const char *extra) +{ + xmlGenericErrorFunc channel = NULL; + xmlParserCtxtPtr pctxt = NULL; + void *data = NULL; + + if (ctxt != NULL) { + channel = ctxt->error; + data = ctxt->userData; + /* Use the special values to detect if it is part of a parsing + context */ + if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) || + (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) { + long delta = (char *) ctxt - (char *) ctxt->userData; + if ((delta > 0) && (delta < 250)) + pctxt = ctxt->userData; + } + } + 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"); +} + +/** + * xmlErrValid: + * @ctxt: an XML validation parser context + * @error: the error number + * @extra: extra informations + * + * Handle a validation error + */ +static void +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; + /* Use the special values to detect if it is part of a parsing + context */ + if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) || + (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) { + long delta = (char *) ctxt - (char *) ctxt->userData; + if ((delta > 0) && (delta < 250)) + 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); +} + +#if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) +/** + * xmlErrValidNode: + * @ctxt: an XML validation parser context + * @node: the node raising the error + * @error: the error number + * @str1: extra informations + * @str2: extra informations + * @str3: extra informations + * + * Handle a validation error, provide contextual informations + */ +static void +xmlErrValidNode(xmlValidCtxtPtr ctxt, + xmlNodePtr node, xmlParserErrors error, + 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; + /* Use the special values to detect if it is part of a parsing + context */ + if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) || + (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) { + long delta = (char *) ctxt - (char *) ctxt->userData; + if ((delta > 0) && (delta < 250)) + pctxt = ctxt->userData; + } + } + __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error, + XML_ERR_ERROR, NULL, 0, + (const char *) str1, + (const char *) str1, + (const char *) str3, 0, 0, msg, str1, str2, str3); +} +#endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */ + +#ifdef LIBXML_VALID_ENABLED +/** + * xmlErrValidNodeNr: + * @ctxt: an XML validation parser context + * @node: the node raising the error + * @error: the error number + * @str1: extra informations + * @int2: extra informations + * @str3: extra informations + * + * Handle a validation error, provide contextual informations + */ +static void +xmlErrValidNodeNr(xmlValidCtxtPtr ctxt, + xmlNodePtr node, xmlParserErrors error, + 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; + /* Use the special values to detect if it is part of a parsing + context */ + if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) || + (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) { + long delta = (char *) ctxt - (char *) ctxt->userData; + if ((delta > 0) && (delta < 250)) + 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); +} + +/** + * xmlErrValidWarning: + * @ctxt: an XML validation parser context + * @node: the node raising the error + * @error: the error number + * @str1: extra information + * @str2: extra information + * @str3: extra information + * + * Handle a validation error, provide contextual information + */ +static void +xmlErrValidWarning(xmlValidCtxtPtr ctxt, + xmlNodePtr node, xmlParserErrors error, + 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; + /* Use the special values to detect if it is part of a parsing + context */ + if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) || + (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) { + long delta = (char *) ctxt - (char *) ctxt->userData; + if ((delta > 0) && (delta < 250)) + pctxt = ctxt->userData; + } + } + __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error, + XML_ERR_WARNING, NULL, 0, + (const char *) str1, + (const char *) str1, + (const char *) str3, 0, 0, msg, str1, str2, str3); +} + + + +#ifdef LIBXML_REGEXP_ENABLED +/* + * If regexp are enabled we can do continuous validation without the + * need of a tree to validate the content model. this is done in each + * callbacks. + * Each xmlValidState represent the validation state associated to the + * set of nodes currently open from the document root to the current element. + */ + + +typedef struct _xmlValidState { + xmlElementPtr elemDecl; /* pointer to the content model */ + xmlNodePtr node; /* pointer to the current node */ + xmlRegExecCtxtPtr exec; /* regexp runtime */ +} _xmlValidState; + + +static int +vstateVPush(xmlValidCtxtPtr ctxt, xmlElementPtr elemDecl, xmlNodePtr node) { + if ((ctxt->vstateMax == 0) || (ctxt->vstateTab == NULL)) { + ctxt->vstateMax = 10; + ctxt->vstateTab = (xmlValidState *) xmlMalloc(ctxt->vstateMax * + sizeof(ctxt->vstateTab[0])); + if (ctxt->vstateTab == NULL) { + xmlVErrMemory(ctxt, "malloc failed"); + return(-1); + } + } + + if (ctxt->vstateNr >= ctxt->vstateMax) { + xmlValidState *tmp; + + tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab, + 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0])); + if (tmp == NULL) { + xmlVErrMemory(ctxt, "realloc failed"); + return(-1); + } + ctxt->vstateMax *= 2; + ctxt->vstateTab = tmp; + } + ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr]; + ctxt->vstateTab[ctxt->vstateNr].elemDecl = elemDecl; + ctxt->vstateTab[ctxt->vstateNr].node = node; + if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) { + if (elemDecl->contModel == NULL) + xmlValidBuildContentModel(ctxt, elemDecl); + if (elemDecl->contModel != NULL) { + ctxt->vstateTab[ctxt->vstateNr].exec = + xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL); + } else { + ctxt->vstateTab[ctxt->vstateNr].exec = NULL; + xmlErrValidNode(ctxt, (xmlNodePtr) elemDecl, + XML_ERR_INTERNAL_ERROR, + "Failed to build content model regexp for %s\n", + node->name, NULL, NULL); + } + } + return(ctxt->vstateNr++); +} + +static int +vstateVPop(xmlValidCtxtPtr ctxt) { + xmlElementPtr elemDecl; + + if (ctxt->vstateNr < 1) return(-1); + ctxt->vstateNr--; + elemDecl = ctxt->vstateTab[ctxt->vstateNr].elemDecl; + ctxt->vstateTab[ctxt->vstateNr].elemDecl = NULL; + ctxt->vstateTab[ctxt->vstateNr].node = NULL; + if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) { + xmlRegFreeExecCtxt(ctxt->vstateTab[ctxt->vstateNr].exec); + } + ctxt->vstateTab[ctxt->vstateNr].exec = NULL; + if (ctxt->vstateNr >= 1) + ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr - 1]; + else + ctxt->vstate = NULL; + return(ctxt->vstateNr); +} + +#else /* not LIBXML_REGEXP_ENABLED */ +/* + * If regexp are not enabled, it uses a home made algorithm less + * complex and easier to + * debug/maintain than a generic NFA -> DFA state based algo. The + * only restriction is on the deepness of the tree limited by the + * size of the occurs bitfield + * + * this is the content of a saved state for rollbacks + */ + +#define ROLLBACK_OR 0 +#define ROLLBACK_PARENT 1 + +typedef struct _xmlValidState { + xmlElementContentPtr cont; /* pointer to the content model subtree */ + xmlNodePtr node; /* pointer to the current node in the list */ + long occurs;/* bitfield for multiple occurrences */ + unsigned char depth; /* current depth in the overall tree */ + unsigned char state; /* ROLLBACK_XXX */ +} _xmlValidState; + +#define MAX_RECURSE 25000 +#define MAX_DEPTH ((sizeof(_xmlValidState.occurs)) * 8) +#define CONT ctxt->vstate->cont +#define NODE ctxt->vstate->node +#define DEPTH ctxt->vstate->depth +#define OCCURS ctxt->vstate->occurs +#define STATE ctxt->vstate->state + +#define OCCURRENCE (ctxt->vstate->occurs & (1 << DEPTH)) +#define PARENT_OCCURRENCE (ctxt->vstate->occurs & ((1 << DEPTH) - 1)) + +#define SET_OCCURRENCE ctxt->vstate->occurs |= (1 << DEPTH) +#define RESET_OCCURRENCE ctxt->vstate->occurs &= ((1 << DEPTH) - 1) + +static int +vstateVPush(xmlValidCtxtPtr ctxt, xmlElementContentPtr cont, + xmlNodePtr node, unsigned char depth, long occurs, + unsigned char state) { + int i = ctxt->vstateNr - 1; + + if (ctxt->vstateNr > MAX_RECURSE) { + return(-1); + } + if (ctxt->vstateTab == NULL) { + ctxt->vstateMax = 8; + ctxt->vstateTab = (xmlValidState *) xmlMalloc( + ctxt->vstateMax * sizeof(ctxt->vstateTab[0])); + if (ctxt->vstateTab == NULL) { + xmlVErrMemory(ctxt, "malloc failed"); + return(-1); + } + } + if (ctxt->vstateNr >= ctxt->vstateMax) { + xmlValidState *tmp; + + tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab, + 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0])); + if (tmp == NULL) { + xmlVErrMemory(ctxt, "malloc failed"); + return(-1); + } + ctxt->vstateMax *= 2; + ctxt->vstateTab = tmp; + ctxt->vstate = &ctxt->vstateTab[0]; + } + /* + * Don't push on the stack a state already here + */ + if ((i >= 0) && (ctxt->vstateTab[i].cont == cont) && + (ctxt->vstateTab[i].node == node) && + (ctxt->vstateTab[i].depth == depth) && + (ctxt->vstateTab[i].occurs == occurs) && + (ctxt->vstateTab[i].state == state)) + return(ctxt->vstateNr); + ctxt->vstateTab[ctxt->vstateNr].cont = cont; + ctxt->vstateTab[ctxt->vstateNr].node = node; + ctxt->vstateTab[ctxt->vstateNr].depth = depth; + ctxt->vstateTab[ctxt->vstateNr].occurs = occurs; + ctxt->vstateTab[ctxt->vstateNr].state = state; + return(ctxt->vstateNr++); +} + +static int +vstateVPop(xmlValidCtxtPtr ctxt) { + if (ctxt->vstateNr <= 1) return(-1); + ctxt->vstateNr--; + ctxt->vstate = &ctxt->vstateTab[0]; + ctxt->vstate->cont = ctxt->vstateTab[ctxt->vstateNr].cont; + ctxt->vstate->node = ctxt->vstateTab[ctxt->vstateNr].node; + ctxt->vstate->depth = ctxt->vstateTab[ctxt->vstateNr].depth; + ctxt->vstate->occurs = ctxt->vstateTab[ctxt->vstateNr].occurs; + ctxt->vstate->state = ctxt->vstateTab[ctxt->vstateNr].state; + return(ctxt->vstateNr); +} + +#endif /* LIBXML_REGEXP_ENABLED */ + +static int +nodeVPush(xmlValidCtxtPtr ctxt, xmlNodePtr value) +{ + if (ctxt->nodeMax <= 0) { + ctxt->nodeMax = 4; + ctxt->nodeTab = + (xmlNodePtr *) xmlMalloc(ctxt->nodeMax * + sizeof(ctxt->nodeTab[0])); + if (ctxt->nodeTab == NULL) { + xmlVErrMemory(ctxt, "malloc failed"); + ctxt->nodeMax = 0; + return (0); + } + } + if (ctxt->nodeNr >= ctxt->nodeMax) { + xmlNodePtr *tmp; + tmp = (xmlNodePtr *) xmlRealloc(ctxt->nodeTab, + ctxt->nodeMax * 2 * sizeof(ctxt->nodeTab[0])); + if (tmp == NULL) { + xmlVErrMemory(ctxt, "realloc failed"); + return (0); + } + ctxt->nodeMax *= 2; + ctxt->nodeTab = tmp; + } + ctxt->nodeTab[ctxt->nodeNr] = value; + ctxt->node = value; + return (ctxt->nodeNr++); +} +static xmlNodePtr +nodeVPop(xmlValidCtxtPtr ctxt) +{ + xmlNodePtr ret; + + if (ctxt->nodeNr <= 0) + return (NULL); + ctxt->nodeNr--; + if (ctxt->nodeNr > 0) + ctxt->node = ctxt->nodeTab[ctxt->nodeNr - 1]; + else + ctxt->node = NULL; + ret = ctxt->nodeTab[ctxt->nodeNr]; + ctxt->nodeTab[ctxt->nodeNr] = NULL; + return (ret); +} + +#ifdef DEBUG_VALID_ALGO +static void +xmlValidPrintNode(xmlNodePtr cur) { + if (cur == NULL) { + xmlGenericError(xmlGenericErrorContext, "null"); + return; + } + switch (cur->type) { + case XML_ELEMENT_NODE: + xmlGenericError(xmlGenericErrorContext, "%s ", cur->name); + break; + case XML_TEXT_NODE: + xmlGenericError(xmlGenericErrorContext, "text "); + break; + case XML_CDATA_SECTION_NODE: + xmlGenericError(xmlGenericErrorContext, "cdata "); + break; + case XML_ENTITY_REF_NODE: + xmlGenericError(xmlGenericErrorContext, "&%s; ", cur->name); + break; + case XML_PI_NODE: + xmlGenericError(xmlGenericErrorContext, "pi(%s) ", cur->name); + break; + case XML_COMMENT_NODE: + xmlGenericError(xmlGenericErrorContext, "comment "); + break; + case XML_ATTRIBUTE_NODE: + xmlGenericError(xmlGenericErrorContext, "?attr? "); + break; + case XML_ENTITY_NODE: + xmlGenericError(xmlGenericErrorContext, "?ent? "); + break; + case XML_DOCUMENT_NODE: + xmlGenericError(xmlGenericErrorContext, "?doc? "); + break; + case XML_DOCUMENT_TYPE_NODE: + xmlGenericError(xmlGenericErrorContext, "?doctype? "); + break; + case XML_DOCUMENT_FRAG_NODE: + xmlGenericError(xmlGenericErrorContext, "?frag? "); + break; + case XML_NOTATION_NODE: + xmlGenericError(xmlGenericErrorContext, "?nota? "); + break; + case XML_HTML_DOCUMENT_NODE: + xmlGenericError(xmlGenericErrorContext, "?html? "); + break; +#ifdef LIBXML_DOCB_ENABLED + case XML_DOCB_DOCUMENT_NODE: + xmlGenericError(xmlGenericErrorContext, "?docb? "); + break; +#endif + case XML_DTD_NODE: + xmlGenericError(xmlGenericErrorContext, "?dtd? "); + break; + case XML_ELEMENT_DECL: + xmlGenericError(xmlGenericErrorContext, "?edecl? "); + break; + case XML_ATTRIBUTE_DECL: + xmlGenericError(xmlGenericErrorContext, "?adecl? "); + break; + case XML_ENTITY_DECL: + xmlGenericError(xmlGenericErrorContext, "?entdecl? "); + break; + case XML_NAMESPACE_DECL: + xmlGenericError(xmlGenericErrorContext, "?nsdecl? "); + break; + case XML_XINCLUDE_START: + xmlGenericError(xmlGenericErrorContext, "incstart "); + break; + case XML_XINCLUDE_END: + xmlGenericError(xmlGenericErrorContext, "incend "); + break; + } +} + +static void +xmlValidPrintNodeList(xmlNodePtr cur) { + if (cur == NULL) + xmlGenericError(xmlGenericErrorContext, "null "); + while (cur != NULL) { + xmlValidPrintNode(cur); + cur = cur->next; + } +} + +static void +xmlValidDebug(xmlNodePtr cur, xmlElementContentPtr cont) { + char expr[5000]; + + expr[0] = 0; + xmlGenericError(xmlGenericErrorContext, "valid: "); + xmlValidPrintNodeList(cur); + xmlGenericError(xmlGenericErrorContext, "against "); + xmlSnprintfElementContent(expr, 5000, cont, 1); + xmlGenericError(xmlGenericErrorContext, "%s\n", expr); +} + +static void +xmlValidDebugState(xmlValidStatePtr state) { + xmlGenericError(xmlGenericErrorContext, "("); + if (state->cont == NULL) + xmlGenericError(xmlGenericErrorContext, "null,"); + else + switch (state->cont->type) { + case XML_ELEMENT_CONTENT_PCDATA: + xmlGenericError(xmlGenericErrorContext, "pcdata,"); + break; + case XML_ELEMENT_CONTENT_ELEMENT: + xmlGenericError(xmlGenericErrorContext, "%s,", + state->cont->name); + break; + case XML_ELEMENT_CONTENT_SEQ: + xmlGenericError(xmlGenericErrorContext, "seq,"); + break; + case XML_ELEMENT_CONTENT_OR: + xmlGenericError(xmlGenericErrorContext, "or,"); + break; + } + xmlValidPrintNode(state->node); + xmlGenericError(xmlGenericErrorContext, ",%d,%X,%d)", + state->depth, state->occurs, state->state); +} + +static void +xmlValidStateDebug(xmlValidCtxtPtr ctxt) { + int i, j; + + xmlGenericError(xmlGenericErrorContext, "state: "); + xmlValidDebugState(ctxt->vstate); + xmlGenericError(xmlGenericErrorContext, " stack: %d ", + ctxt->vstateNr - 1); + for (i = 0, j = ctxt->vstateNr - 1;(i < 3) && (j > 0);i++,j--) + xmlValidDebugState(&ctxt->vstateTab[j]); + xmlGenericError(xmlGenericErrorContext, "\n"); +} + +/***** +#define DEBUG_VALID_STATE(n,c) xmlValidDebug(n,c); + *****/ + +#define DEBUG_VALID_STATE(n,c) xmlValidStateDebug(ctxt); +#define DEBUG_VALID_MSG(m) \ + xmlGenericError(xmlGenericErrorContext, "%s\n", m); + +#else +#define DEBUG_VALID_STATE(n,c) +#define DEBUG_VALID_MSG(m) +#endif + +/* TODO: use hash table for accesses to elem and attribute definitions */ + + +#define CHECK_DTD \ + if (doc == NULL) return(0); \ + else if ((doc->intSubset == NULL) && \ + (doc->extSubset == NULL)) return(0) + +#ifdef LIBXML_REGEXP_ENABLED + +/************************************************************************ + * * + * Content model validation based on the regexps * + * * + ************************************************************************/ + +/** + * xmlValidBuildAContentModel: + * @content: the content model + * @ctxt: the schema parser context + * @name: the element name whose content is being built + * + * Generate the automata sequence needed for that type + * + * Returns 1 if successful or 0 in case of error. + */ +static int +xmlValidBuildAContentModel(xmlElementContentPtr content, + xmlValidCtxtPtr ctxt, + const xmlChar *name) { + if (content == NULL) { + xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR, + "Found NULL content in content model of %s\n", + name, NULL, NULL); + return(0); + } + switch (content->type) { + case XML_ELEMENT_CONTENT_PCDATA: + xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR, + "Found PCDATA in content model of %s\n", + name, NULL, NULL); + return(0); + break; + case XML_ELEMENT_CONTENT_ELEMENT: { + xmlAutomataStatePtr oldstate = ctxt->state; + xmlChar fn[50]; + xmlChar *fullname; + + fullname = xmlBuildQName(content->name, content->prefix, fn, 50); + if (fullname == NULL) { + xmlVErrMemory(ctxt, "Building content model"); + return(0); + } + + switch (content->ocur) { + case XML_ELEMENT_CONTENT_ONCE: + ctxt->state = xmlAutomataNewTransition(ctxt->am, + ctxt->state, NULL, fullname, NULL); + break; + case XML_ELEMENT_CONTENT_OPT: + ctxt->state = xmlAutomataNewTransition(ctxt->am, + ctxt->state, NULL, fullname, NULL); + xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state); + break; + case XML_ELEMENT_CONTENT_PLUS: + ctxt->state = xmlAutomataNewTransition(ctxt->am, + ctxt->state, NULL, fullname, NULL); + xmlAutomataNewTransition(ctxt->am, ctxt->state, + ctxt->state, fullname, NULL); + break; + case XML_ELEMENT_CONTENT_MULT: + ctxt->state = xmlAutomataNewEpsilon(ctxt->am, + ctxt->state, NULL); + xmlAutomataNewTransition(ctxt->am, + ctxt->state, ctxt->state, fullname, NULL); + break; + } + if ((fullname != fn) && (fullname != content->name)) + xmlFree(fullname); + break; + } + case XML_ELEMENT_CONTENT_SEQ: { + xmlAutomataStatePtr oldstate, oldend; + xmlElementContentOccur ocur; + + /* + * Simply iterate over the content + */ + oldstate = ctxt->state; + ocur = content->ocur; + if (ocur != XML_ELEMENT_CONTENT_ONCE) { + ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL); + oldstate = ctxt->state; + } + do { + xmlValidBuildAContentModel(content->c1, ctxt, name); + content = content->c2; + } while ((content->type == XML_ELEMENT_CONTENT_SEQ) && + (content->ocur == XML_ELEMENT_CONTENT_ONCE)); + xmlValidBuildAContentModel(content, ctxt, name); + oldend = ctxt->state; + ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL); + switch (ocur) { + case XML_ELEMENT_CONTENT_ONCE: + break; + case XML_ELEMENT_CONTENT_OPT: + xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state); + break; + case XML_ELEMENT_CONTENT_MULT: + xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state); + xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate); + break; + case XML_ELEMENT_CONTENT_PLUS: + xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate); + break; + } + break; + } + case XML_ELEMENT_CONTENT_OR: { + xmlAutomataStatePtr oldstate, oldend; + xmlElementContentOccur ocur; + + ocur = content->ocur; + if ((ocur == XML_ELEMENT_CONTENT_PLUS) || + (ocur == XML_ELEMENT_CONTENT_MULT)) { + ctxt->state = xmlAutomataNewEpsilon(ctxt->am, + ctxt->state, NULL); + } + oldstate = ctxt->state; + oldend = xmlAutomataNewState(ctxt->am); + + /* + * iterate over the subtypes and remerge the end with an + * epsilon transition + */ + do { + ctxt->state = oldstate; + xmlValidBuildAContentModel(content->c1, ctxt, name); + 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); + xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend); + ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL); + switch (ocur) { + case XML_ELEMENT_CONTENT_ONCE: + break; + case XML_ELEMENT_CONTENT_OPT: + xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state); + break; + case XML_ELEMENT_CONTENT_MULT: + xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state); + xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate); + break; + case XML_ELEMENT_CONTENT_PLUS: + xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate); + break; + } + break; + } + default: + xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, + "ContentModel broken for element %s\n", + (const char *) name); + return(0); + } + return(1); +} +/** + * xmlValidBuildContentModel: + * @ctxt: a validation context + * @elem: an element declaration node + * + * (Re)Build the automata associated to the content model of this + * element + * + * Returns 1 in case of success, 0 in case of error + */ +int +xmlValidBuildContentModel(xmlValidCtxtPtr ctxt, xmlElementPtr elem) { + + if ((ctxt == NULL) || (elem == NULL)) + return(0); + if (elem->type != XML_ELEMENT_DECL) + return(0); + if (elem->etype != XML_ELEMENT_TYPE_ELEMENT) + return(1); + /* TODO: should we rebuild in this case ? */ + if (elem->contModel != NULL) { + if (!xmlRegexpIsDeterminist(elem->contModel)) { + ctxt->valid = 0; + return(0); + } + return(1); + } + + 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); + return(0); + } + ctxt->state = xmlAutomataGetInitState(ctxt->am); + xmlValidBuildAContentModel(elem->content, ctxt, elem->name); + xmlAutomataSetFinalState(ctxt->am, ctxt->state); + elem->contModel = xmlAutomataCompile(ctxt->am); + if (xmlRegexpIsDeterminist(elem->contModel) != 1) { + char expr[5000]; + expr[0] = 0; + xmlSnprintfElementContent(expr, 5000, elem->content, 1); + xmlErrValidNode(ctxt, (xmlNodePtr) elem, + XML_DTD_CONTENT_NOT_DETERMINIST, + "Content model of %s is not determinist: %s\n", + elem->name, BAD_CAST expr, NULL); +#ifdef DEBUG_REGEXP_ALGO + xmlRegexpPrint(stderr, elem->contModel); +#endif + ctxt->valid = 0; + ctxt->state = NULL; + xmlFreeAutomata(ctxt->am); + ctxt->am = NULL; + return(0); + } + ctxt->state = NULL; + xmlFreeAutomata(ctxt->am); + ctxt->am = NULL; + return(1); +} + +#endif /* LIBXML_REGEXP_ENABLED */ + +/**************************************************************** + * * + * Util functions for data allocation/deallocation * + * * + ****************************************************************/ + +/** + * xmlNewValidCtxt: + * + * Allocate a validation context structure. + * + * Returns NULL if not, otherwise the new validation context structure + */ +xmlValidCtxtPtr xmlNewValidCtxt(void) { + xmlValidCtxtPtr ret; + + if ((ret = xmlMalloc(sizeof (xmlValidCtxt))) == NULL) { + xmlVErrMemory(NULL, "malloc failed"); + return (NULL); + } + + (void) memset(ret, 0, sizeof (xmlValidCtxt)); + + return (ret); +} + +/** + * xmlFreeValidCtxt: + * @cur: the validation context to free + * + * Free a validation context structure. + */ +void +xmlFreeValidCtxt(xmlValidCtxtPtr cur) { + if (cur->vstateTab != NULL) + xmlFree(cur->vstateTab); + if (cur->nodeTab != NULL) + xmlFree(cur->nodeTab); + xmlFree(cur); +} + +#endif /* LIBXML_VALID_ENABLED */ + +/** + * xmlNewDocElementContent: + * @doc: the document + * @name: the subelement name or NULL + * @type: the type of element content decl + * + * Allocate an element content structure for the document. + * + * Returns NULL if not, otherwise the new element content structure + */ +xmlElementContentPtr +xmlNewDocElementContent(xmlDocPtr doc, const xmlChar *name, + xmlElementContentType type) { + xmlElementContentPtr ret; + xmlDictPtr dict = NULL; + + if (doc != NULL) + dict = doc->dict; + + switch(type) { + case XML_ELEMENT_CONTENT_ELEMENT: + if (name == NULL) { + xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, + "xmlNewElementContent : name == NULL !\n", + NULL); + } + break; + case XML_ELEMENT_CONTENT_PCDATA: + case XML_ELEMENT_CONTENT_SEQ: + case XML_ELEMENT_CONTENT_OR: + if (name != NULL) { + xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, + "xmlNewElementContent : name != NULL !\n", + NULL); + } + break; + default: + xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, + "Internal: ELEMENT content corrupted invalid type\n", + NULL); + return(NULL); + } + ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent)); + if (ret == NULL) { + xmlVErrMemory(NULL, "malloc failed"); + return(NULL); + } + memset(ret, 0, sizeof(xmlElementContent)); + ret->type = type; + ret->ocur = XML_ELEMENT_CONTENT_ONCE; + if (name != NULL) { + int l; + const xmlChar *tmp; + + tmp = xmlSplitQName3(name, &l); + if (tmp == NULL) { + if (dict == NULL) + ret->name = xmlStrdup(name); + else + ret->name = xmlDictLookup(dict, name, -1); + } else { + if (dict == NULL) { + ret->prefix = xmlStrndup(name, l); + ret->name = xmlStrdup(tmp); + } else { + ret->prefix = xmlDictLookup(dict, name, l); + ret->name = xmlDictLookup(dict, tmp, -1); + } + } + } + return(ret); +} + +/** + * xmlNewElementContent: + * @name: the subelement name or NULL + * @type: the type of element content decl + * + * Allocate an element content structure. + * Deprecated in favor of xmlNewDocElementContent + * + * Returns NULL if not, otherwise the new element content structure + */ +xmlElementContentPtr +xmlNewElementContent(const xmlChar *name, xmlElementContentType type) { + return(xmlNewDocElementContent(NULL, name, type)); +} + +/** + * xmlCopyDocElementContent: + * @doc: the document owning the element declaration + * @cur: An element content pointer. + * + * Build a copy of an element content description. + * + * Returns the new xmlElementContentPtr or NULL in case of error. + */ +xmlElementContentPtr +xmlCopyDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) { + xmlElementContentPtr ret = NULL, prev = NULL, tmp; + xmlDictPtr dict = NULL; + + if (cur == NULL) return(NULL); + + if (doc != NULL) + dict = doc->dict; + + ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent)); + if (ret == NULL) { + xmlVErrMemory(NULL, "malloc failed"); + return(NULL); + } + memset(ret, 0, sizeof(xmlElementContent)); + ret->type = cur->type; + ret->ocur = cur->ocur; + if (cur->name != NULL) { + if (dict) + ret->name = xmlDictLookup(dict, cur->name, -1); + else + ret->name = xmlStrdup(cur->name); + } + + if (cur->prefix != NULL) { + if (dict) + ret->prefix = xmlDictLookup(dict, cur->prefix, -1); + else + ret->prefix = xmlStrdup(cur->prefix); + } + if (cur->c1 != NULL) + ret->c1 = xmlCopyDocElementContent(doc, cur->c1); + if (ret->c1 != NULL) + 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); + } + memset(tmp, 0, sizeof(xmlElementContent)); + tmp->type = cur->type; + tmp->ocur = cur->ocur; + prev->c2 = tmp; + if (cur->name != NULL) { + if (dict) + tmp->name = xmlDictLookup(dict, cur->name, -1); + else + tmp->name = xmlStrdup(cur->name); + } + + if (cur->prefix != NULL) { + if (dict) + tmp->prefix = xmlDictLookup(dict, cur->prefix, -1); + else + tmp->prefix = xmlStrdup(cur->prefix); + } + if (cur->c1 != NULL) + tmp->c1 = xmlCopyDocElementContent(doc,cur->c1); + if (tmp->c1 != NULL) + tmp->c1->parent = ret; + prev = tmp; + cur = cur->c2; + } + } + return(ret); +} + +/** + * xmlCopyElementContent: + * @cur: An element content pointer. + * + * Build a copy of an element content description. + * Deprecated, use xmlCopyDocElementContent instead + * + * Returns the new xmlElementContentPtr or NULL in case of error. + */ +xmlElementContentPtr +xmlCopyElementContent(xmlElementContentPtr cur) { + return(xmlCopyDocElementContent(NULL, cur)); +} + +/** + * xmlFreeDocElementContent: + * @doc: the document owning the element declaration + * @cur: the element content tree to free + * + * Free an element content structure. The whole subtree is removed. + */ +void +xmlFreeDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) { + xmlElementContentPtr next; + xmlDictPtr dict = NULL; + + if (doc != NULL) + dict = doc->dict; + + while (cur != NULL) { + next = cur->c2; + switch (cur->type) { + case XML_ELEMENT_CONTENT_PCDATA: + case XML_ELEMENT_CONTENT_ELEMENT: + case XML_ELEMENT_CONTENT_SEQ: + case XML_ELEMENT_CONTENT_OR: + break; + default: + xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, + "Internal: ELEMENT content corrupted invalid type\n", + NULL); + return; + } + if (cur->c1 != NULL) xmlFreeDocElementContent(doc, cur->c1); + if (dict) { + if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name))) + xmlFree((xmlChar *) cur->name); + if ((cur->prefix != NULL) && (!xmlDictOwns(dict, cur->prefix))) + xmlFree((xmlChar *) cur->prefix); + } else { + if (cur->name != NULL) xmlFree((xmlChar *) cur->name); + if (cur->prefix != NULL) xmlFree((xmlChar *) cur->prefix); + } + xmlFree(cur); + cur = next; + } +} + +/** + * xmlFreeElementContent: + * @cur: the element content tree to free + * + * Free an element content structure. The whole subtree is removed. + * Deprecated, use xmlFreeDocElementContent instead + */ +void +xmlFreeElementContent(xmlElementContentPtr cur) { + xmlFreeDocElementContent(NULL, cur); +} + +#ifdef LIBXML_OUTPUT_ENABLED +/** + * xmlDumpElementContent: + * @buf: An XML buffer + * @content: An element table + * @glob: 1 if one must print the englobing parenthesis, 0 otherwise + * + * This will dump the content of the element table as an XML DTD definition + */ +static void +xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content, int glob) { + if (content == NULL) return; + + if (glob) xmlBufferWriteChar(buf, "("); + switch (content->type) { + case XML_ELEMENT_CONTENT_PCDATA: + xmlBufferWriteChar(buf, "#PCDATA"); + break; + case XML_ELEMENT_CONTENT_ELEMENT: + if (content->prefix != NULL) { + xmlBufferWriteCHAR(buf, content->prefix); + xmlBufferWriteChar(buf, ":"); + } + xmlBufferWriteCHAR(buf, content->name); + break; + case XML_ELEMENT_CONTENT_SEQ: + if ((content->c1->type == XML_ELEMENT_CONTENT_OR) || + (content->c1->type == XML_ELEMENT_CONTENT_SEQ)) + xmlDumpElementContent(buf, content->c1, 1); + else + xmlDumpElementContent(buf, content->c1, 0); + xmlBufferWriteChar(buf, " , "); + if ((content->c2->type == XML_ELEMENT_CONTENT_OR) || + ((content->c2->type == XML_ELEMENT_CONTENT_SEQ) && + (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE))) + xmlDumpElementContent(buf, content->c2, 1); + else + xmlDumpElementContent(buf, content->c2, 0); + break; + case XML_ELEMENT_CONTENT_OR: + if ((content->c1->type == XML_ELEMENT_CONTENT_OR) || + (content->c1->type == XML_ELEMENT_CONTENT_SEQ)) + xmlDumpElementContent(buf, content->c1, 1); + else + xmlDumpElementContent(buf, content->c1, 0); + xmlBufferWriteChar(buf, " | "); + if ((content->c2->type == XML_ELEMENT_CONTENT_SEQ) || + ((content->c2->type == XML_ELEMENT_CONTENT_OR) && + (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE))) + xmlDumpElementContent(buf, content->c2, 1); + else + xmlDumpElementContent(buf, content->c2, 0); + break; + default: + xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, + "Internal: ELEMENT content corrupted invalid type\n", + NULL); + } + if (glob) + xmlBufferWriteChar(buf, ")"); + switch (content->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; + } +} + +/** + * xmlSprintfElementContent: + * @buf: an output buffer + * @content: An element table + * @englob: 1 if one must print the englobing parenthesis, 0 otherwise + * + * Deprecated, unsafe, use xmlSnprintfElementContent + */ +void +xmlSprintfElementContent(char *buf ATTRIBUTE_UNUSED, + xmlElementContentPtr content ATTRIBUTE_UNUSED, + int englob ATTRIBUTE_UNUSED) { +} +#endif /* LIBXML_OUTPUT_ENABLED */ + +/** + * xmlSnprintfElementContent: + * @buf: an output buffer + * @size: the buffer size + * @content: An element table + * @englob: 1 if one must print the englobing parenthesis, 0 otherwise + * + * This will dump the content of the element content definition + * Intended just for the debug routine + */ +void +xmlSnprintfElementContent(char *buf, int size, xmlElementContentPtr content, int englob) { + int len; + + if (content == NULL) return; + len = strlen(buf); + if (size - len < 50) { + if ((size - len > 4) && (buf[len - 1] != '.')) + strcat(buf, " ..."); + return; + } + if (englob) strcat(buf, "("); + switch (content->type) { + case XML_ELEMENT_CONTENT_PCDATA: + strcat(buf, "#PCDATA"); + break; + case XML_ELEMENT_CONTENT_ELEMENT: + if (content->prefix != NULL) { + if (size - len < xmlStrlen(content->prefix) + 10) { + strcat(buf, " ..."); + return; + } + strcat(buf, (char *) content->prefix); + strcat(buf, ":"); + } + if (size - len < xmlStrlen(content->name) + 10) { + strcat(buf, " ..."); + return; + } + if (content->name != NULL) + strcat(buf, (char *) content->name); + break; + case XML_ELEMENT_CONTENT_SEQ: + if ((content->c1->type == XML_ELEMENT_CONTENT_OR) || + (content->c1->type == XML_ELEMENT_CONTENT_SEQ)) + xmlSnprintfElementContent(buf, size, content->c1, 1); + else + xmlSnprintfElementContent(buf, size, content->c1, 0); + len = strlen(buf); + if (size - len < 50) { + if ((size - len > 4) && (buf[len - 1] != '.')) + strcat(buf, " ..."); + return; + } + strcat(buf, " , "); + if (((content->c2->type == XML_ELEMENT_CONTENT_OR) || + (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) && + (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT)) + xmlSnprintfElementContent(buf, size, content->c2, 1); + else + xmlSnprintfElementContent(buf, size, content->c2, 0); + break; + case XML_ELEMENT_CONTENT_OR: + if ((content->c1->type == XML_ELEMENT_CONTENT_OR) || + (content->c1->type == XML_ELEMENT_CONTENT_SEQ)) + xmlSnprintfElementContent(buf, size, content->c1, 1); + else + xmlSnprintfElementContent(buf, size, content->c1, 0); + len = strlen(buf); + if (size - len < 50) { + if ((size - len > 4) && (buf[len - 1] != '.')) + strcat(buf, " ..."); + return; + } + strcat(buf, " | "); + if (((content->c2->type == XML_ELEMENT_CONTENT_SEQ) || + (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) && + (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT)) + xmlSnprintfElementContent(buf, size, content->c2, 1); + else + xmlSnprintfElementContent(buf, size, content->c2, 0); + break; + } + if (englob) + strcat(buf, ")"); + switch (content->ocur) { + case XML_ELEMENT_CONTENT_ONCE: + break; + case XML_ELEMENT_CONTENT_OPT: + strcat(buf, "?"); + break; + case XML_ELEMENT_CONTENT_MULT: + strcat(buf, "*"); + break; + case XML_ELEMENT_CONTENT_PLUS: + strcat(buf, "+"); + break; + } +} + +/**************************************************************** + * * + * Registration of DTD declarations * + * * + ****************************************************************/ + +/** + * xmlFreeElement: + * @elem: An element + * + * Deallocate the memory used by an element definition + */ +static void +xmlFreeElement(xmlElementPtr elem) { + if (elem == NULL) return; + xmlUnlinkNode((xmlNodePtr) elem); + xmlFreeDocElementContent(elem->doc, elem->content); + if (elem->name != NULL) + xmlFree((xmlChar *) elem->name); + if (elem->prefix != NULL) + xmlFree((xmlChar *) elem->prefix); +#ifdef LIBXML_REGEXP_ENABLED + if (elem->contModel != NULL) + xmlRegFreeRegexp(elem->contModel); +#endif + xmlFree(elem); +} + + +/** + * xmlAddElementDecl: + * @ctxt: the validation context + * @dtd: pointer to the DTD + * @name: the entity name + * @type: the element type + * @content: the element content tree or NULL + * + * Register a new element declaration + * + * Returns NULL if not, otherwise the entity + */ +xmlElementPtr +xmlAddElementDecl(xmlValidCtxtPtr ctxt, + xmlDtdPtr dtd, const xmlChar *name, + xmlElementTypeVal type, + xmlElementContentPtr content) { + xmlElementPtr ret; + xmlElementTablePtr table; + xmlAttributePtr oldAttributes = NULL; + xmlChar *ns, *uqname; + + if (dtd == NULL) { + return(NULL); + } + if (name == NULL) { + return(NULL); + } + + switch (type) { + case XML_ELEMENT_TYPE_EMPTY: + if (content != NULL) { + xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, + "xmlAddElementDecl: content != NULL for EMPTY\n", + NULL); + return(NULL); + } + break; + case XML_ELEMENT_TYPE_ANY: + if (content != NULL) { + xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, + "xmlAddElementDecl: content != NULL for ANY\n", + NULL); + return(NULL); + } + break; + case XML_ELEMENT_TYPE_MIXED: + if (content == NULL) { + xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, + "xmlAddElementDecl: content == NULL for MIXED\n", + NULL); + return(NULL); + } + break; + case XML_ELEMENT_TYPE_ELEMENT: + if (content == NULL) { + xmlErrValid(ctxt, XML_ERR_INTERNAL_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); + return(NULL); + } + + /* + * check if name is a QName + */ + uqname = xmlSplitQName2(name, &ns); + if (uqname != NULL) + name = uqname; + + /* + * Create the Element table if needed. + */ + table = (xmlElementTablePtr) dtd->elements; + if (table == NULL) { + xmlDictPtr dict = NULL; + + if (dtd->doc != NULL) + dict = dtd->doc->dict; + table = xmlHashCreateDict(0, dict); + 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); + if ((ret != NULL) && (ret->etype == XML_ELEMENT_TYPE_UNDEFINED)) { + oldAttributes = ret->attributes; + ret->attributes = NULL; + xmlHashRemoveEntry2(dtd->doc->intSubset->elements, name, ns, NULL); + xmlFreeElement(ret); + } + } + + /* + * The element may already be present if one of its attribute + * was registered first + */ + ret = xmlHashLookup2(table, name, ns); + if (ret != NULL) { + if (ret->etype != XML_ELEMENT_TYPE_UNDEFINED) { +#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 */ + if (uqname != NULL) + xmlFree(uqname); + if (ns != NULL) + xmlFree(ns); + return(NULL); + } + if (ns != NULL) { + xmlFree(ns); + ns = NULL; + } + } else { + ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement)); + if (ret == NULL) { + xmlVErrMemory(ctxt, "malloc failed"); + if (uqname != NULL) + xmlFree(uqname); + if (ns != NULL) + xmlFree(ns); + return(NULL); + } + memset(ret, 0, sizeof(xmlElement)); + ret->type = XML_ELEMENT_DECL; + + /* + * fill the structure. + */ + ret->name = xmlStrdup(name); + if (ret->name == NULL) { + xmlVErrMemory(ctxt, "malloc failed"); + if (uqname != NULL) + xmlFree(uqname); + if (ns != NULL) + xmlFree(ns); + xmlFree(ret); + return(NULL); + } + ret->prefix = ns; + + /* + * 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 */ + xmlFreeElement(ret); + if (uqname != NULL) + xmlFree(uqname); + return(NULL); + } + /* + * For new element, may have attributes from earlier + * definition in internal subset + */ + ret->attributes = oldAttributes; + } + + /* + * Finish to fill the structure. + */ + ret->etype = type; + /* + * Avoid a stupid copy when called by the parser + * and flag it by setting a special parent value + * so the parser doesn't unallocate it. + */ + if ((ctxt != NULL) && + ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) || + (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1))) { + ret->content = content; + if (content != NULL) + content->parent = (xmlElementContentPtr) 1; + } else { + ret->content = xmlCopyDocElementContent(dtd->doc, content); + } + + /* + * 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 (uqname != NULL) + xmlFree(uqname); + return(ret); +} + +/** + * xmlFreeElementTable: + * @table: An element table + * + * Deallocate the memory used by an element hash table. + */ +void +xmlFreeElementTable(xmlElementTablePtr table) { + xmlHashFree(table, (xmlHashDeallocator) xmlFreeElement); +} + +#ifdef LIBXML_TREE_ENABLED +/** + * xmlCopyElement: + * @elem: An element + * + * Build a copy of an element. + * + * Returns the new xmlElementPtr or NULL in case of error. + */ +static xmlElementPtr +xmlCopyElement(xmlElementPtr elem) { + xmlElementPtr cur; + + cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement)); + if (cur == NULL) { + xmlVErrMemory(NULL, "malloc failed"); + return(NULL); + } + memset(cur, 0, sizeof(xmlElement)); + cur->type = XML_ELEMENT_DECL; + cur->etype = elem->etype; + if (elem->name != NULL) + cur->name = xmlStrdup(elem->name); + else + cur->name = NULL; + if (elem->prefix != NULL) + cur->prefix = xmlStrdup(elem->prefix); + else + cur->prefix = NULL; + cur->content = xmlCopyElementContent(elem->content); + /* TODO : rebuild the attribute list on the copy */ + cur->attributes = NULL; + return(cur); +} + +/** + * xmlCopyElementTable: + * @table: An element table + * + * Build a copy of an element table. + * + * Returns the new xmlElementTablePtr or NULL in case of error. + */ +xmlElementTablePtr +xmlCopyElementTable(xmlElementTablePtr table) { + return((xmlElementTablePtr) xmlHashCopy(table, + (xmlHashCopier) xmlCopyElement)); +} +#endif /* LIBXML_TREE_ENABLED */ + +#ifdef LIBXML_OUTPUT_ENABLED +/** + * xmlDumpElementDecl: + * @buf: the XML buffer output + * @elem: An element table + * + * This will dump the content of the element declaration as an XML + * DTD definition + */ +void +xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) { + if ((buf == NULL) || (elem == NULL)) + return; + switch (elem->etype) { + case XML_ELEMENT_TYPE_EMPTY: + xmlBufferWriteChar(buf, "prefix != NULL) { + xmlBufferWriteCHAR(buf, elem->prefix); + xmlBufferWriteChar(buf, ":"); + } + xmlBufferWriteCHAR(buf, elem->name); + xmlBufferWriteChar(buf, " EMPTY>\n"); + break; + case XML_ELEMENT_TYPE_ANY: + xmlBufferWriteChar(buf, "prefix != NULL) { + xmlBufferWriteCHAR(buf, elem->prefix); + xmlBufferWriteChar(buf, ":"); + } + xmlBufferWriteCHAR(buf, elem->name); + xmlBufferWriteChar(buf, " ANY>\n"); + break; + case XML_ELEMENT_TYPE_MIXED: + xmlBufferWriteChar(buf, "prefix != NULL) { + xmlBufferWriteCHAR(buf, elem->prefix); + xmlBufferWriteChar(buf, ":"); + } + xmlBufferWriteCHAR(buf, elem->name); + xmlBufferWriteChar(buf, " "); + xmlDumpElementContent(buf, elem->content, 1); + xmlBufferWriteChar(buf, ">\n"); + break; + case XML_ELEMENT_TYPE_ELEMENT: + xmlBufferWriteChar(buf, "prefix != NULL) { + xmlBufferWriteCHAR(buf, elem->prefix); + xmlBufferWriteChar(buf, ":"); + } + xmlBufferWriteCHAR(buf, elem->name); + xmlBufferWriteChar(buf, " "); + xmlDumpElementContent(buf, elem->content, 1); + xmlBufferWriteChar(buf, ">\n"); + break; + default: + xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR, + "Internal: ELEMENT struct corrupted invalid type\n", + NULL); + } +} + +/** + * xmlDumpElementDeclScan: + * @elem: An element table + * @buf: the XML buffer output + * + * This routine is used by the hash scan function. It just reverses + * the arguments. + */ +static void +xmlDumpElementDeclScan(xmlElementPtr elem, xmlBufferPtr buf) { + xmlDumpElementDecl(buf, elem); +} + +/** + * xmlDumpElementTable: + * @buf: the XML buffer output + * @table: An element table + * + * This will dump the content of the element table as an XML DTD definition + */ +void +xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) { + if ((buf == NULL) || (table == NULL)) + return; + xmlHashScan(table, (xmlHashScanner) xmlDumpElementDeclScan, buf); +} +#endif /* LIBXML_OUTPUT_ENABLED */ + +/** + * xmlCreateEnumeration: + * @name: the enumeration name or NULL + * + * create and initialize an enumeration attribute node. + * + * Returns the xmlEnumerationPtr just created or NULL in case + * of error. + */ +xmlEnumerationPtr +xmlCreateEnumeration(const xmlChar *name) { + xmlEnumerationPtr ret; + + ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration)); + if (ret == NULL) { + xmlVErrMemory(NULL, "malloc failed"); + return(NULL); + } + memset(ret, 0, sizeof(xmlEnumeration)); + + if (name != NULL) + ret->name = xmlStrdup(name); + return(ret); +} + +/** + * xmlFreeEnumeration: + * @cur: the tree to free. + * + * free an enumeration attribute node (recursive). + */ +void +xmlFreeEnumeration(xmlEnumerationPtr cur) { + if (cur == NULL) return; + + if (cur->next != NULL) xmlFreeEnumeration(cur->next); + + if (cur->name != NULL) xmlFree((xmlChar *) cur->name); + xmlFree(cur); +} + +#ifdef LIBXML_TREE_ENABLED +/** + * xmlCopyEnumeration: + * @cur: the tree to copy. + * + * Copy an enumeration attribute node (recursive). + * + * Returns the xmlEnumerationPtr just created or NULL in case + * of error. + */ +xmlEnumerationPtr +xmlCopyEnumeration(xmlEnumerationPtr cur) { + xmlEnumerationPtr ret; + + if (cur == NULL) return(NULL); + ret = xmlCreateEnumeration((xmlChar *) cur->name); + + if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next); + else ret->next = NULL; + + return(ret); +} +#endif /* LIBXML_TREE_ENABLED */ + +#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; + + xmlBufferWriteCHAR(buf, cur->name); + if (cur->next == NULL) + xmlBufferWriteChar(buf, ")"); + else { + xmlBufferWriteChar(buf, " | "); + xmlDumpEnumeration(buf, cur->next); + } +} +#endif /* LIBXML_OUTPUT_ENABLED */ + +#ifdef LIBXML_VALID_ENABLED +/** + * xmlScanIDAttributeDecl: + * @ctxt: the validation context + * @elem: the element name + * @err: whether to raise errors here + * + * Verify that the element don't have too many ID attributes + * declared. + * + * Returns the number of ID attributes found. + */ +static int +xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem, int err) { + xmlAttributePtr cur; + int ret = 0; + + if (elem == NULL) return(0); + cur = elem->attributes; + while (cur != NULL) { + if (cur->atype == XML_ATTRIBUTE_ID) { + ret ++; + if ((ret > 1) && (err)) + xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_MULTIPLE_ID, + "Element %s has too many ID attributes defined : %s\n", + elem->name, cur->name, NULL); + } + cur = cur->nexth; + } + return(ret); +} +#endif /* LIBXML_VALID_ENABLED */ + +/** + * xmlFreeAttribute: + * @elem: An attribute + * + * Deallocate the memory used by an attribute definition + */ +static void +xmlFreeAttribute(xmlAttributePtr attr) { + xmlDictPtr dict; + + if (attr == NULL) return; + if (attr->doc != NULL) + dict = attr->doc->dict; + else + dict = NULL; + xmlUnlinkNode((xmlNodePtr) attr); + if (attr->tree != NULL) + xmlFreeEnumeration(attr->tree); + if (dict) { + if ((attr->elem != NULL) && (!xmlDictOwns(dict, attr->elem))) + xmlFree((xmlChar *) attr->elem); + if ((attr->name != NULL) && (!xmlDictOwns(dict, attr->name))) + xmlFree((xmlChar *) attr->name); + if ((attr->prefix != NULL) && (!xmlDictOwns(dict, attr->prefix))) + xmlFree((xmlChar *) attr->prefix); + if ((attr->defaultValue != NULL) && + (!xmlDictOwns(dict, attr->defaultValue))) + xmlFree((xmlChar *) attr->defaultValue); + } else { + if (attr->elem != NULL) + xmlFree((xmlChar *) attr->elem); + if (attr->name != NULL) + xmlFree((xmlChar *) attr->name); + if (attr->defaultValue != NULL) + xmlFree((xmlChar *) attr->defaultValue); + if (attr->prefix != NULL) + xmlFree((xmlChar *) attr->prefix); + } + xmlFree(attr); +} + + +/** + * xmlAddAttributeDecl: + * @ctxt: the validation context + * @dtd: pointer to the DTD + * @elem: the element name + * @name: the attribute name + * @ns: the attribute namespace prefix + * @type: the attribute type + * @def: the attribute default type + * @defaultValue: the attribute default value + * @tree: if it's an enumeration, the associated list + * + * Register a new attribute declaration + * Note that @tree becomes the ownership of the DTD + * + * Returns NULL if not new, otherwise the attribute decl + */ +xmlAttributePtr +xmlAddAttributeDecl(xmlValidCtxtPtr ctxt, + xmlDtdPtr dtd, const xmlChar *elem, + const xmlChar *name, const xmlChar *ns, + xmlAttributeType type, xmlAttributeDefault def, + const xmlChar *defaultValue, xmlEnumerationPtr tree) { + xmlAttributePtr ret; + xmlAttributeTablePtr table; + xmlElementPtr elemDef; + xmlDictPtr dict = NULL; + + if (dtd == NULL) { + xmlFreeEnumeration(tree); + return(NULL); + } + if (name == NULL) { + xmlFreeEnumeration(tree); + return(NULL); + } + if (elem == NULL) { + xmlFreeEnumeration(tree); + return(NULL); + } + if (dtd->doc != NULL) + dict = dtd->doc->dict; + +#ifdef LIBXML_VALID_ENABLED + /* + * Check the type and possibly the default value. + */ + switch (type) { + case XML_ATTRIBUTE_CDATA: + break; + case XML_ATTRIBUTE_ID: + break; + case XML_ATTRIBUTE_IDREF: + break; + case XML_ATTRIBUTE_IDREFS: + break; + case XML_ATTRIBUTE_ENTITY: + break; + case XML_ATTRIBUTE_ENTITIES: + break; + case XML_ATTRIBUTE_NMTOKEN: + break; + case XML_ATTRIBUTE_NMTOKENS: + break; + case XML_ATTRIBUTE_ENUMERATION: + break; + case XML_ATTRIBUTE_NOTATION: + break; + default: + xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, + "Internal: ATTRIBUTE struct corrupted invalid type\n", + NULL); + xmlFreeEnumeration(tree); + return(NULL); + } + if ((defaultValue != NULL) && + (!xmlValidateAttributeValueInternal(dtd->doc, type, defaultValue))) { + xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_DEFAULT, + "Attribute %s of %s: invalid default value\n", + elem, name, defaultValue); + defaultValue = NULL; + if (ctxt != NULL) + ctxt->valid = 0; + } +#endif /* LIBXML_VALID_ENABLED */ + + /* + * Check first that an attribute defined in the external subset wasn't + * already defined in the internal subset + */ + if ((dtd->doc != NULL) && (dtd->doc->extSubset == dtd) && + (dtd->doc->intSubset != NULL) && + (dtd->doc->intSubset->attributes != NULL)) { + ret = xmlHashLookup3(dtd->doc->intSubset->attributes, name, ns, elem); + if (ret != NULL) { + xmlFreeEnumeration(tree); + return(NULL); + } + } + + /* + * Create the Attribute table if needed. + */ + table = (xmlAttributeTablePtr) dtd->attributes; + if (table == NULL) { + table = xmlHashCreateDict(0, dict); + dtd->attributes = (void *) table; + } + if (table == NULL) { + xmlVErrMemory(ctxt, + "xmlAddAttributeDecl: Table creation failed!\n"); + xmlFreeEnumeration(tree); + return(NULL); + } + + + ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute)); + if (ret == NULL) { + xmlVErrMemory(ctxt, "malloc failed"); + xmlFreeEnumeration(tree); + return(NULL); + } + memset(ret, 0, sizeof(xmlAttribute)); + ret->type = XML_ATTRIBUTE_DECL; + + /* + * fill the structure. + */ + ret->atype = type; + /* + * doc must be set before possible error causes call + * to xmlFreeAttribute (because it's used to check on + * dict use) + */ + 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); + } + ret->def = def; + ret->tree = tree; + if (defaultValue != NULL) { + if (dict) + ret->defaultValue = xmlDictLookup(dict, defaultValue, -1); + else + ret->defaultValue = xmlStrdup(defaultValue); + } + + /* + * Validity Check: + * Search the DTD for previous declarations of the ATTLIST + */ + if (xmlHashAddEntry3(table, ret->name, ret->prefix, ret->elem, ret) < 0) { +#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); +#endif /* LIBXML_VALID_ENABLED */ + xmlFreeAttribute(ret); + return(NULL); + } + + /* + * Validity Check: + * Multiple ID per element + */ + elemDef = xmlGetDtdElementDesc2(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; + } +#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; + + 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; + } + } + } + + /* + * Link it to the DTD + */ + ret->parent = dtd; + if (dtd->last == NULL) { + dtd->children = dtd->last = (xmlNodePtr) ret; + } else { + dtd->last->next = (xmlNodePtr) ret; + ret->prev = dtd->last; + dtd->last = (xmlNodePtr) ret; + } + return(ret); +} + +/** + * xmlFreeAttributeTable: + * @table: An attribute table + * + * Deallocate the memory used by an entities hash table. + */ +void +xmlFreeAttributeTable(xmlAttributeTablePtr table) { + xmlHashFree(table, (xmlHashDeallocator) xmlFreeAttribute); +} + +#ifdef LIBXML_TREE_ENABLED +/** + * xmlCopyAttribute: + * @attr: An attribute + * + * Build a copy of an attribute. + * + * Returns the new xmlAttributePtr or NULL in case of error. + */ +static xmlAttributePtr +xmlCopyAttribute(xmlAttributePtr attr) { + xmlAttributePtr cur; + + cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute)); + if (cur == NULL) { + xmlVErrMemory(NULL, "malloc failed"); + 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) + cur->elem = xmlStrdup(attr->elem); + if (attr->name != NULL) + cur->name = xmlStrdup(attr->name); + if (attr->prefix != NULL) + cur->prefix = xmlStrdup(attr->prefix); + if (attr->defaultValue != NULL) + cur->defaultValue = xmlStrdup(attr->defaultValue); + return(cur); +} + +/** + * xmlCopyAttributeTable: + * @table: An attribute table + * + * Build a copy of an attribute table. + * + * Returns the new xmlAttributeTablePtr or NULL in case of error. + */ +xmlAttributeTablePtr +xmlCopyAttributeTable(xmlAttributeTablePtr table) { + return((xmlAttributeTablePtr) xmlHashCopy(table, + (xmlHashCopier) xmlCopyAttribute)); +} +#endif /* LIBXML_TREE_ENABLED */ + +#ifdef LIBXML_OUTPUT_ENABLED +/** + * xmlDumpAttributeDecl: + * @buf: the XML buffer output + * @attr: An attribute declaration + * + * This will dump the content of the attribute declaration as an XML + * DTD definition + */ +void +xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) { + if ((buf == NULL) || (attr == NULL)) + return; + xmlBufferWriteChar(buf, "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"); +} + +/** + * xmlDumpAttributeDeclScan: + * @attr: An attribute declaration + * @buf: the XML buffer output + * + * This is used with the hash scan function - just reverses arguments + */ +static void +xmlDumpAttributeDeclScan(xmlAttributePtr attr, xmlBufferPtr buf) { + xmlDumpAttributeDecl(buf, attr); +} + +/** + * xmlDumpAttributeTable: + * @buf: the XML buffer output + * @table: An attribute table + * + * This will dump the content of the attribute table as an XML DTD definition + */ +void +xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) { + if ((buf == NULL) || (table == NULL)) + return; + xmlHashScan(table, (xmlHashScanner) xmlDumpAttributeDeclScan, buf); +} +#endif /* LIBXML_OUTPUT_ENABLED */ + +/************************************************************************ + * * + * NOTATIONs * + * * + ************************************************************************/ +/** + * xmlFreeNotation: + * @not: A notation + * + * Deallocate the memory used by an notation definition + */ +static void +xmlFreeNotation(xmlNotationPtr nota) { + if (nota == NULL) return; + if (nota->name != NULL) + xmlFree((xmlChar *) nota->name); + if (nota->PublicID != NULL) + xmlFree((xmlChar *) nota->PublicID); + if (nota->SystemID != NULL) + xmlFree((xmlChar *) nota->SystemID); + xmlFree(nota); +} + + +/** + * xmlAddNotationDecl: + * @dtd: pointer to the DTD + * @ctxt: the validation context + * @name: the entity name + * @PublicID: the public identifier or NULL + * @SystemID: the system identifier or NULL + * + * Register a new notation declaration + * + * Returns NULL if not, otherwise the entity + */ +xmlNotationPtr +xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, + const xmlChar *name, + const xmlChar *PublicID, const xmlChar *SystemID) { + xmlNotationPtr ret; + xmlNotationTablePtr table; + + if (dtd == NULL) { + return(NULL); + } + if (name == NULL) { + return(NULL); + } + if ((PublicID == NULL) && (SystemID == NULL)) { + return(NULL); + } + + /* + * Create the Notation table if needed. + */ + table = (xmlNotationTablePtr) dtd->notations; + if (table == NULL) { + xmlDictPtr dict = NULL; + if (dtd->doc != NULL) + dict = dtd->doc->dict; + + dtd->notations = table = xmlHashCreateDict(0, dict); + } + if (table == NULL) { + xmlVErrMemory(ctxt, + "xmlAddNotationDecl: Table creation failed!\n"); + return(NULL); + } + + ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation)); + if (ret == NULL) { + xmlVErrMemory(ctxt, "malloc failed"); + return(NULL); + } + memset(ret, 0, sizeof(xmlNotation)); + + /* + * fill the structure. + */ + ret->name = xmlStrdup(name); + if (SystemID != NULL) + ret->SystemID = xmlStrdup(SystemID); + if (PublicID != NULL) + ret->PublicID = xmlStrdup(PublicID); + + /* + * Validity Check: + * Check the DTD for previous declarations of the ATTLIST + */ + if (xmlHashAddEntry(table, name, ret)) { +#ifdef LIBXML_VALID_ENABLED + xmlErrValid(NULL, XML_DTD_NOTATION_REDEFINED, + "xmlAddNotationDecl: %s already defined\n", + (const char *) name); +#endif /* LIBXML_VALID_ENABLED */ + xmlFreeNotation(ret); + return(NULL); + } + return(ret); +} + +/** + * xmlFreeNotationTable: + * @table: An notation table + * + * Deallocate the memory used by an entities hash table. + */ +void +xmlFreeNotationTable(xmlNotationTablePtr table) { + xmlHashFree(table, (xmlHashDeallocator) xmlFreeNotation); +} + +#ifdef LIBXML_TREE_ENABLED +/** + * xmlCopyNotation: + * @nota: A notation + * + * Build a copy of a notation. + * + * Returns the new xmlNotationPtr or NULL in case of error. + */ +static xmlNotationPtr +xmlCopyNotation(xmlNotationPtr nota) { + xmlNotationPtr cur; + + cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation)); + if (cur == NULL) { + xmlVErrMemory(NULL, "malloc failed"); + return(NULL); + } + if (nota->name != NULL) + cur->name = xmlStrdup(nota->name); + else + cur->name = NULL; + if (nota->PublicID != NULL) + cur->PublicID = xmlStrdup(nota->PublicID); + else + cur->PublicID = NULL; + if (nota->SystemID != NULL) + cur->SystemID = xmlStrdup(nota->SystemID); + else + cur->SystemID = NULL; + return(cur); +} + +/** + * xmlCopyNotationTable: + * @table: A notation table + * + * Build a copy of a notation table. + * + * Returns the new xmlNotationTablePtr or NULL in case of error. + */ +xmlNotationTablePtr +xmlCopyNotationTable(xmlNotationTablePtr table) { + return((xmlNotationTablePtr) xmlHashCopy(table, + (xmlHashCopier) xmlCopyNotation)); +} +#endif /* LIBXML_TREE_ENABLED */ + +#ifdef LIBXML_OUTPUT_ENABLED +/** + * xmlDumpNotationDecl: + * @buf: the XML buffer output + * @nota: A notation declaration + * + * This will dump the content the notation declaration as an XML DTD definition + */ +void +xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) { + if ((buf == NULL) || (nota == NULL)) + return; + xmlBufferWriteChar(buf, "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(xmlNotationPtr nota, xmlBufferPtr buf) { + xmlDumpNotationDecl(buf, nota); +} + +/** + * xmlDumpNotationTable: + * @buf: the XML buffer output + * @table: A notation table + * + * This will dump the content of the notation table as an XML DTD definition + */ +void +xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) { + if ((buf == NULL) || (table == NULL)) + return; + xmlHashScan(table, (xmlHashScanner) xmlDumpNotationDeclScan, buf); +} +#endif /* LIBXML_OUTPUT_ENABLED */ + +/************************************************************************ + * * + * IDs * + * * + ************************************************************************/ +/** + * DICT_FREE: + * @str: a string + * + * Free a string if it is not owned by the "dict" dictionnary in the + * current scope + */ +#define DICT_FREE(str) \ + if ((str) && ((!dict) || \ + (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \ + xmlFree((char *)(str)); + +/** + * xmlFreeID: + * @not: A id + * + * Deallocate the memory used by an id definition + */ +static void +xmlFreeID(xmlIDPtr id) { + xmlDictPtr dict = NULL; + + if (id == NULL) return; + + if (id->doc != NULL) + dict = id->doc->dict; + + if (id->value != NULL) + DICT_FREE(id->value) + if (id->name != NULL) + DICT_FREE(id->name) + xmlFree(id); +} + + +/** + * 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 ret; + xmlIDTablePtr table; + + if (doc == NULL) { + return(NULL); + } + if (value == NULL) { + return(NULL); + } + if (attr == NULL) { + return(NULL); + } + + /* + * Create the ID table if needed. + */ + 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); + } + + ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID)); + if (ret == NULL) { + xmlVErrMemory(ctxt, "malloc failed"); + return(NULL); + } + + /* + * fill the structure. + */ + ret->value = xmlStrdup(value); + ret->doc = doc; + if ((ctxt != NULL) && (ctxt->vstateNr != 0)) { + /* + * Operating in streaming mode, attr is gonna disapear + */ + 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; + } + 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) && (ctxt->error != 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 != NULL) + attr->atype = XML_ATTRIBUTE_ID; + return(ret); +} + +/** + * xmlFreeIDTable: + * @table: An id table + * + * Deallocate the memory used by an ID hash table. + */ +void +xmlFreeIDTable(xmlIDTablePtr table) { + xmlHashFree(table, (xmlHashDeallocator) xmlFreeID); +} + +/** + * xmlIsID: + * @doc: the document + * @elem: the element carrying the attribute + * @attr: the attribute + * + * Determine whether an attribute is of type ID. In case we have DTD(s) + * then this is done if DTD loading has been requested. In the case + * of HTML documents parsed with the HTML parser, then ID detection is + * done systematically. + * + * Returns 0 or 1 depending on the lookup result + */ +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"))))) + return(1); + return(0); + } else if (elem == NULL) { + return(0); + } else { + xmlAttributePtr attrDecl = NULL; + + xmlChar felem[50], fattr[50]; + xmlChar *fullelemname, *fullattrname; + + fullelemname = (elem->ns != NULL && elem->ns->prefix != NULL) ? + xmlBuildQName(elem->name, elem->ns->prefix, felem, 50) : + (xmlChar *)elem->name; + + fullattrname = (attr->ns != NULL && attr->ns->prefix != NULL) ? + xmlBuildQName(attr->name, attr->ns->prefix, fattr, 50) : + (xmlChar *)attr->name; + + if (fullelemname != NULL && fullattrname != NULL) { + attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullelemname, + fullattrname); + if ((attrDecl == NULL) && (doc->extSubset != NULL)) + attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullelemname, + fullattrname); + } + + 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); +} + +/** + * xmlRemoveID: + * @doc: the document + * @attr: the attribute + * + * Remove the given attribute from the ID table maintained internally. + * + * Returns -1 if the lookup failed and 0 otherwise + */ +int +xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) { + xmlIDTablePtr table; + xmlIDPtr id; + xmlChar *ID; + + if (doc == NULL) return(-1); + if (attr == NULL) return(-1); + table = (xmlIDTablePtr) doc->ids; + if (table == NULL) + return(-1); + + if (attr == NULL) + return(-1); + ID = xmlNodeListGetString(doc, attr->children, 1); + if (ID == NULL) + return(-1); + id = xmlHashLookup(table, ID); + if (id == NULL || id->attr != attr) { + xmlFree(ID); + return(-1); + } + xmlHashRemoveEntry(table, ID, (xmlHashDeallocator) xmlFreeID); + xmlFree(ID); + attr->atype = 0; + return(0); +} + +/** + * xmlGetID: + * @doc: pointer to the document + * @ID: the ID value + * + * Search the attribute declaring the given ID + * + * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID + */ +xmlAttrPtr +xmlGetID(xmlDocPtr doc, const xmlChar *ID) { + xmlIDTablePtr table; + xmlIDPtr id; + + if (doc == NULL) { + return(NULL); + } + + if (ID == NULL) { + return(NULL); + } + + table = (xmlIDTablePtr) doc->ids; + if (table == NULL) + return(NULL); + + id = xmlHashLookup(table, ID); + if (id == NULL) + return(NULL); + if (id->attr == NULL) { + /* + * We are operating on a stream, return a well known reference + * since the attribute node doesn't exist anymore + */ + return((xmlAttrPtr) doc); + } + return(id->attr); +} + +/************************************************************************ + * * + * Refs * + * * + ************************************************************************/ +typedef struct xmlRemoveMemo_t +{ + xmlListPtr l; + xmlAttrPtr ap; +} xmlRemoveMemo; + +typedef xmlRemoveMemo *xmlRemoveMemoPtr; + +typedef struct xmlValidateMemo_t +{ + xmlValidCtxtPtr ctxt; + const xmlChar *name; +} xmlValidateMemo; + +typedef xmlValidateMemo *xmlValidateMemoPtr; + +/** + * xmlFreeRef: + * @lk: A list link + * + * Deallocate the memory used by a ref definition + */ +static void +xmlFreeRef(xmlLinkPtr lk) { + xmlRefPtr ref = (xmlRefPtr)xmlLinkGetData(lk); + if (ref == NULL) return; + if (ref->value != NULL) + xmlFree((xmlChar *)ref->value); + if (ref->name != NULL) + xmlFree((xmlChar *)ref->name); + xmlFree(ref); +} + +/** + * xmlFreeRefList: + * @list_ref: A list of references. + * + * Deallocate the memory used by a list of references + */ +static void +xmlFreeRefList(xmlListPtr list_ref) { + if (list_ref == NULL) return; + xmlListDelete(list_ref); +} + +/** + * xmlWalkRemoveRef: + * @data: Contents of current link + * @user: Value supplied by the user + * + * Returns 0 to abort the walk or 1 to continue + */ +static int +xmlWalkRemoveRef(const void *data, const void *user) +{ + xmlAttrPtr attr0 = ((xmlRefPtr)data)->attr; + xmlAttrPtr attr1 = ((xmlRemoveMemoPtr)user)->ap; + xmlListPtr ref_list = ((xmlRemoveMemoPtr)user)->l; + + if (attr0 == attr1) { /* Matched: remove and terminate walk */ + xmlListRemoveFirst(ref_list, (void *)data); + return 0; + } + return 1; +} + +/** + * xmlDummyCompare + * @data0: Value supplied by the user + * @data1: Value supplied by the user + * + * Do nothing, return 0. Used to create unordered lists. + */ +static int +xmlDummyCompare(const void *data0 ATTRIBUTE_UNUSED, + const void *data1 ATTRIBUTE_UNUSED) +{ + return (0); +} + +/** + * xmlAddRef: + * @ctxt: the validation context + * @doc: pointer to the document + * @value: the value name + * @attr: the attribute holding the Ref + * + * Register a new ref declaration + * + * Returns NULL if not, otherwise the new xmlRefPtr + */ +xmlRefPtr +xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value, + xmlAttrPtr attr) { + xmlRefPtr ret; + xmlRefTablePtr table; + xmlListPtr ref_list; + + if (doc == NULL) { + return(NULL); + } + if (value == NULL) { + return(NULL); + } + if (attr == NULL) { + return(NULL); + } + + /* + * Create the Ref table if needed. + */ + 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); + } + + ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef)); + if (ret == NULL) { + xmlVErrMemory(ctxt, "malloc failed"); + return(NULL); + } + + /* + * fill the structure. + */ + ret->value = xmlStrdup(value); + if ((ctxt != NULL) && (ctxt->vstateNr != 0)) { + /* + * Operating in streaming mode, attr is gonna disapear + */ + ret->name = xmlStrdup(attr->name); + ret->attr = NULL; + } else { + ret->name = NULL; + ret->attr = attr; + } + ret->lineno = xmlGetLineNo(attr->parent); + + /* To add a reference :- + * References are maintained as a list of references, + * Lookup the entry, if no entry create new nodelist + * Add the owning node to the NodeList + * Return the ref + */ + + 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); + goto failed; + } + if (xmlHashAddEntry(table, value, ref_list) < 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); + goto failed; + } + return(ret); +failed: + if (ret != NULL) { + if (ret->value != NULL) + xmlFree((char *)ret->value); + if (ret->name != NULL) + xmlFree((char *)ret->name); + xmlFree(ret); + } + return(NULL); +} + +/** + * xmlFreeRefTable: + * @table: An ref table + * + * Deallocate the memory used by an Ref hash table. + */ +void +xmlFreeRefTable(xmlRefTablePtr table) { + xmlHashFree(table, (xmlHashDeallocator) xmlFreeRefList); +} + +/** + * xmlIsRef: + * @doc: the document + * @elem: the element carrying the attribute + * @attr: the attribute + * + * Determine whether an attribute is of type Ref. In case we have DTD(s) + * then this is simple, otherwise we use an heuristic: name Ref (upper + * or lowercase). + * + * Returns 0 or 1 depending on the lookup result + */ +int +xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) { + if (attr == NULL) + return(0); + if (doc == NULL) { + doc = attr->doc; + if (doc == NULL) return(0); + } + + if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) { + return(0); + } else if (doc->type == XML_HTML_DOCUMENT_NODE) { + /* TODO @@@ */ + return(0); + } else { + xmlAttributePtr attrDecl; + + if (elem == NULL) return(0); + attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name); + if ((attrDecl == NULL) && (doc->extSubset != NULL)) + attrDecl = xmlGetDtdAttrDesc(doc->extSubset, + elem->name, attr->name); + + if ((attrDecl != NULL) && + (attrDecl->atype == XML_ATTRIBUTE_IDREF || + attrDecl->atype == XML_ATTRIBUTE_IDREFS)) + return(1); + } + return(0); +} + +/** + * xmlRemoveRef: + * @doc: the document + * @attr: the attribute + * + * Remove the given attribute from the Ref table maintained internally. + * + * Returns -1 if the lookup failed and 0 otherwise + */ +int +xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) { + xmlListPtr ref_list; + xmlRefTablePtr table; + xmlChar *ID; + xmlRemoveMemo target; + + if (doc == NULL) return(-1); + if (attr == NULL) return(-1); + table = (xmlRefTablePtr) doc->refs; + if (table == NULL) + return(-1); + + if (attr == NULL) + return(-1); + ID = xmlNodeListGetString(doc, attr->children, 1); + if (ID == NULL) + return(-1); + ref_list = xmlHashLookup(table, ID); + + if(ref_list == NULL) { + xmlFree(ID); + return (-1); + } + /* At this point, ref_list refers to a list of references which + * have the same key as the supplied attr. Our list of references + * is ordered by reference address and we don't have that information + * here to use when removing. We'll have to walk the list and + * check for a matching attribute, when we find one stop the walk + * and remove the entry. + * The list is ordered by reference, so that means we don't have the + * key. Passing the list and the reference to the walker means we + * will have enough data to be able to remove the entry. + */ + target.l = ref_list; + target.ap = attr; + + /* Remove the supplied attr from our list */ + xmlListWalk(ref_list, xmlWalkRemoveRef, &target); + + /*If the list is empty then remove the list entry in the hash */ + if (xmlListEmpty(ref_list)) + xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator) + xmlFreeRefList); + xmlFree(ID); + return(0); +} + +/** + * xmlGetRefs: + * @doc: pointer to the document + * @ID: the ID value + * + * Find the set of references for the supplied ID. + * + * Returns NULL if not found, otherwise node set for the ID. + */ +xmlListPtr +xmlGetRefs(xmlDocPtr doc, const xmlChar *ID) { + xmlRefTablePtr table; + + if (doc == NULL) { + return(NULL); + } + + if (ID == NULL) { + return(NULL); + } + + table = (xmlRefTablePtr) doc->refs; + if (table == NULL) + return(NULL); + + return (xmlHashLookup(table, ID)); +} + +/************************************************************************ + * * + * Routines for validity checking * + * * + ************************************************************************/ + +/** + * xmlGetDtdElementDesc: + * @dtd: a pointer to the DtD to search + * @name: the element name + * + * Search the DTD for the description of this element + * + * returns the xmlElementPtr if found or NULL + */ + +xmlElementPtr +xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) { + xmlElementTablePtr table; + xmlElementPtr cur; + xmlChar *uqname = NULL, *prefix = NULL; + + if ((dtd == NULL) || (name == NULL)) return(NULL); + if (dtd->elements == NULL) + return(NULL); + table = (xmlElementTablePtr) dtd->elements; + + uqname = xmlSplitQName2(name, &prefix); + if (uqname != NULL) + name = uqname; + cur = xmlHashLookup2(table, name, prefix); + if (prefix != NULL) xmlFree(prefix); + if (uqname != NULL) xmlFree(uqname); + return(cur); +} +/** + * xmlGetDtdElementDesc2: + * @dtd: a pointer to the DtD to search + * @name: the element name + * @create: create an empty description if not found + * + * Search the DTD for the description of this element + * + * returns the xmlElementPtr if found or NULL + */ + +static xmlElementPtr +xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name, int create) { + xmlElementTablePtr table; + xmlElementPtr cur; + xmlChar *uqname = NULL, *prefix = NULL; + + if (dtd == NULL) return(NULL); + 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(NULL, "element table allocation failed"); + return(NULL); + } + } + table = (xmlElementTablePtr) dtd->elements; + + uqname = xmlSplitQName2(name, &prefix); + if (uqname != NULL) + name = uqname; + cur = xmlHashLookup2(table, name, prefix); + if ((cur == NULL) && (create)) { + cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement)); + if (cur == NULL) { + xmlVErrMemory(NULL, "malloc failed"); + return(NULL); + } + memset(cur, 0, sizeof(xmlElement)); + cur->type = XML_ELEMENT_DECL; + + /* + * fill the structure. + */ + cur->name = xmlStrdup(name); + cur->prefix = xmlStrdup(prefix); + cur->etype = XML_ELEMENT_TYPE_UNDEFINED; + + xmlHashAddEntry2(table, name, prefix, cur); + } + if (prefix != NULL) xmlFree(prefix); + if (uqname != NULL) xmlFree(uqname); + return(cur); +} + +/** + * xmlGetDtdQElementDesc: + * @dtd: a pointer to the DtD to search + * @name: the element name + * @prefix: the element namespace prefix + * + * Search the DTD for the description of this element + * + * returns the xmlElementPtr if found or NULL + */ + +xmlElementPtr +xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name, + const xmlChar *prefix) { + xmlElementTablePtr table; + + if (dtd == NULL) return(NULL); + if (dtd->elements == NULL) return(NULL); + table = (xmlElementTablePtr) dtd->elements; + + return(xmlHashLookup2(table, name, prefix)); +} + +/** + * xmlGetDtdAttrDesc: + * @dtd: a pointer to the DtD to search + * @elem: the element name + * @name: the attribute name + * + * Search the DTD for the description of this attribute on + * this element. + * + * returns the xmlAttributePtr if found or NULL + */ + +xmlAttributePtr +xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) { + xmlAttributeTablePtr table; + xmlAttributePtr cur; + xmlChar *uqname = NULL, *prefix = NULL; + + if (dtd == NULL) return(NULL); + if (dtd->attributes == 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); + return(cur); +} + +/** + * xmlGetDtdQAttrDesc: + * @dtd: a pointer to the DtD to search + * @elem: the element name + * @name: the attribute name + * @prefix: the attribute namespace prefix + * + * Search the DTD for the description of this qualified attribute on + * this element. + * + * returns the xmlAttributePtr if found or NULL + */ + +xmlAttributePtr +xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name, + const xmlChar *prefix) { + xmlAttributeTablePtr table; + + if (dtd == NULL) return(NULL); + if (dtd->attributes == NULL) return(NULL); + table = (xmlAttributeTablePtr) dtd->attributes; + + return(xmlHashLookup3(table, name, prefix, elem)); +} + +/** + * xmlGetDtdNotationDesc: + * @dtd: a pointer to the DtD to search + * @name: the notation name + * + * Search the DTD for the description of this notation + * + * returns the xmlNotationPtr if found or NULL + */ + +xmlNotationPtr +xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) { + xmlNotationTablePtr table; + + if (dtd == NULL) return(NULL); + if (dtd->notations == NULL) return(NULL); + table = (xmlNotationTablePtr) dtd->notations; + + return(xmlHashLookup(table, name)); +} + +#if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) +/** + * xmlValidateNotationUse: + * @ctxt: the validation context + * @doc: the document + * @notationName: the notation name to check + * + * Validate that the given name match a notation declaration. + * - [ VC: Notation Declared ] + * + * returns 1 if valid or 0 otherwise + */ + +int +xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc, + const xmlChar *notationName) { + xmlNotationPtr notaDecl; + if ((doc == NULL) || (doc->intSubset == NULL) || + (notationName == NULL)) return(-1); + + notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName); + if ((notaDecl == NULL) && (doc->extSubset != NULL)) + notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName); + + if ((notaDecl == NULL) && (ctxt != NULL)) { + xmlErrValidNode(ctxt, (xmlNodePtr) doc, XML_DTD_UNKNOWN_NOTATION, + "NOTATION %s is not declared\n", + notationName, NULL, NULL); + return(0); + } + return(1); +} +#endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */ + +/** + * xmlIsMixedElement: + * @doc: the document + * @name: the element name + * + * Search in the DtDs whether an element accept Mixed content (or ANY) + * basically if it is supposed to accept text childs + * + * returns 0 if no, 1 if yes, and -1 if no element description is available + */ + +int +xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) { + xmlElementPtr elemDecl; + + if ((doc == NULL) || (doc->intSubset == NULL)) return(-1); + + elemDecl = xmlGetDtdElementDesc(doc->intSubset, name); + if ((elemDecl == NULL) && (doc->extSubset != NULL)) + elemDecl = xmlGetDtdElementDesc(doc->extSubset, name); + if (elemDecl == NULL) return(-1); + switch (elemDecl->etype) { + case XML_ELEMENT_TYPE_UNDEFINED: + return(-1); + case XML_ELEMENT_TYPE_ELEMENT: + return(0); + case XML_ELEMENT_TYPE_EMPTY: + /* + * return 1 for EMPTY since we want VC error to pop up + * on for example + */ + case XML_ELEMENT_TYPE_ANY: + case XML_ELEMENT_TYPE_MIXED: + return(1); + } + return(1); +} + +#ifdef LIBXML_VALID_ENABLED + +static int +xmlIsDocNameStartChar(xmlDocPtr doc, int c) { + if ((doc == NULL) || (doc->properties & XML_DOC_OLD10) == 0) { + /* + * Use the new checks of production [4] [4a] amd [5] of the + * Update 5 of XML-1.0 + */ + if (((c >= 'a') && (c <= 'z')) || + ((c >= 'A') && (c <= 'Z')) || + (c == '_') || (c == ':') || + ((c >= 0xC0) && (c <= 0xD6)) || + ((c >= 0xD8) && (c <= 0xF6)) || + ((c >= 0xF8) && (c <= 0x2FF)) || + ((c >= 0x370) && (c <= 0x37D)) || + ((c >= 0x37F) && (c <= 0x1FFF)) || + ((c >= 0x200C) && (c <= 0x200D)) || + ((c >= 0x2070) && (c <= 0x218F)) || + ((c >= 0x2C00) && (c <= 0x2FEF)) || + ((c >= 0x3001) && (c <= 0xD7FF)) || + ((c >= 0xF900) && (c <= 0xFDCF)) || + ((c >= 0xFDF0) && (c <= 0xFFFD)) || + ((c >= 0x10000) && (c <= 0xEFFFF))) + return(1); + } else { + if (IS_LETTER(c) || (c == '_') || (c == ':')) + return(1); + } + return(0); +} + +static int +xmlIsDocNameChar(xmlDocPtr doc, int c) { + if ((doc == NULL) || (doc->properties & XML_DOC_OLD10) == 0) { + /* + * Use the new checks of production [4] [4a] amd [5] of the + * Update 5 of XML-1.0 + */ + if (((c >= 'a') && (c <= 'z')) || + ((c >= 'A') && (c <= 'Z')) || + ((c >= '0') && (c <= '9')) || /* !start */ + (c == '_') || (c == ':') || + (c == '-') || (c == '.') || (c == 0xB7) || /* !start */ + ((c >= 0xC0) && (c <= 0xD6)) || + ((c >= 0xD8) && (c <= 0xF6)) || + ((c >= 0xF8) && (c <= 0x2FF)) || + ((c >= 0x300) && (c <= 0x36F)) || /* !start */ + ((c >= 0x370) && (c <= 0x37D)) || + ((c >= 0x37F) && (c <= 0x1FFF)) || + ((c >= 0x200C) && (c <= 0x200D)) || + ((c >= 0x203F) && (c <= 0x2040)) || /* !start */ + ((c >= 0x2070) && (c <= 0x218F)) || + ((c >= 0x2C00) && (c <= 0x2FEF)) || + ((c >= 0x3001) && (c <= 0xD7FF)) || + ((c >= 0xF900) && (c <= 0xFDCF)) || + ((c >= 0xFDF0) && (c <= 0xFFFD)) || + ((c >= 0x10000) && (c <= 0xEFFFF))) + return(1); + } else { + if ((IS_LETTER(c)) || (IS_DIGIT(c)) || + (c == '.') || (c == '-') || + (c == '_') || (c == ':') || + (IS_COMBINING(c)) || + (IS_EXTENDER(c))) + return(1); + } + return(0); +} + +/** + * xmlValidateNameValue: + * @doc: pointer to the document or NULL + * @value: an Name value + * + * Validate that the given value match Name production + * + * returns 1 if valid or 0 otherwise + */ + +static int +xmlValidateNameValueInternal(xmlDocPtr doc, const xmlChar *value) { + const xmlChar *cur; + int val, len; + + if (value == NULL) return(0); + cur = value; + val = xmlStringCurrentChar(NULL, cur, &len); + cur += len; + if (!xmlIsDocNameStartChar(doc, val)) + return(0); + + val = xmlStringCurrentChar(NULL, cur, &len); + cur += len; + while (xmlIsDocNameChar(doc, val)) { + val = xmlStringCurrentChar(NULL, cur, &len); + cur += len; + } + + if (val != 0) return(0); + + return(1); +} + +/** + * xmlValidateNameValue: + * @value: an Name value + * + * Validate that the given value match Name production + * + * returns 1 if valid or 0 otherwise + */ + +int +xmlValidateNameValue(const xmlChar *value) { + return(xmlValidateNameValueInternal(NULL, value)); +} + +/** + * xmlValidateNamesValueInternal: + * @doc: pointer to the document or NULL + * @value: an Names value + * + * Validate that the given value match Names production + * + * returns 1 if valid or 0 otherwise + */ + +static int +xmlValidateNamesValueInternal(xmlDocPtr doc, const xmlChar *value) { + const xmlChar *cur; + int val, len; + + if (value == NULL) return(0); + cur = value; + val = xmlStringCurrentChar(NULL, cur, &len); + cur += len; + + if (!xmlIsDocNameStartChar(doc, val)) + return(0); + + val = xmlStringCurrentChar(NULL, cur, &len); + cur += len; + while (xmlIsDocNameChar(doc, val)) { + val = xmlStringCurrentChar(NULL, cur, &len); + cur += len; + } + + /* Should not test IS_BLANK(val) here -- see erratum E20*/ + while (val == 0x20) { + while (val == 0x20) { + val = xmlStringCurrentChar(NULL, cur, &len); + cur += len; + } + + if (!xmlIsDocNameStartChar(doc, val)) + return(0); + + val = xmlStringCurrentChar(NULL, cur, &len); + cur += len; + + while (xmlIsDocNameChar(doc, val)) { + val = xmlStringCurrentChar(NULL, cur, &len); + cur += len; + } + } + + if (val != 0) return(0); + + return(1); +} + +/** + * xmlValidateNamesValue: + * @value: an Names value + * + * Validate that the given value match Names production + * + * returns 1 if valid or 0 otherwise + */ + +int +xmlValidateNamesValue(const xmlChar *value) { + return(xmlValidateNamesValueInternal(NULL, value)); +} + +/** + * xmlValidateNmtokenValueInternal: + * @doc: pointer to the document or NULL + * @value: an Nmtoken value + * + * Validate that the given value match Nmtoken production + * + * [ VC: Name Token ] + * + * returns 1 if valid or 0 otherwise + */ + +static int +xmlValidateNmtokenValueInternal(xmlDocPtr doc, const xmlChar *value) { + const xmlChar *cur; + int val, len; + + if (value == NULL) return(0); + cur = value; + val = xmlStringCurrentChar(NULL, cur, &len); + cur += len; + + if (!xmlIsDocNameChar(doc, val)) + return(0); + + val = xmlStringCurrentChar(NULL, cur, &len); + cur += len; + while (xmlIsDocNameChar(doc, val)) { + val = xmlStringCurrentChar(NULL, cur, &len); + cur += len; + } + + if (val != 0) return(0); + + return(1); +} + +/** + * xmlValidateNmtokenValue: + * @value: an Nmtoken value + * + * Validate that the given value match Nmtoken production + * + * [ VC: Name Token ] + * + * returns 1 if valid or 0 otherwise + */ + +int +xmlValidateNmtokenValue(const xmlChar *value) { + return(xmlValidateNmtokenValueInternal(NULL, value)); +} + +/** + * xmlValidateNmtokensValueInternal: + * @doc: pointer to the document or NULL + * @value: an Nmtokens value + * + * Validate that the given value match Nmtokens production + * + * [ VC: Name Token ] + * + * returns 1 if valid or 0 otherwise + */ + +static int +xmlValidateNmtokensValueInternal(xmlDocPtr doc, const xmlChar *value) { + const xmlChar *cur; + int val, len; + + if (value == NULL) return(0); + cur = value; + val = xmlStringCurrentChar(NULL, cur, &len); + cur += len; + + while (IS_BLANK(val)) { + val = xmlStringCurrentChar(NULL, cur, &len); + cur += len; + } + + if (!xmlIsDocNameChar(doc, val)) + return(0); + + while (xmlIsDocNameChar(doc, val)) { + val = xmlStringCurrentChar(NULL, cur, &len); + cur += len; + } + + /* Should not test IS_BLANK(val) here -- see erratum E20*/ + while (val == 0x20) { + while (val == 0x20) { + val = xmlStringCurrentChar(NULL, cur, &len); + cur += len; + } + if (val == 0) return(1); + + if (!xmlIsDocNameChar(doc, val)) + return(0); + + val = xmlStringCurrentChar(NULL, cur, &len); + cur += len; + + while (xmlIsDocNameChar(doc, val)) { + val = xmlStringCurrentChar(NULL, cur, &len); + cur += len; + } + } + + if (val != 0) return(0); + + return(1); +} + +/** + * xmlValidateNmtokensValue: + * @value: an Nmtokens value + * + * Validate that the given value match Nmtokens production + * + * [ VC: Name Token ] + * + * returns 1 if valid or 0 otherwise + */ + +int +xmlValidateNmtokensValue(const xmlChar *value) { + return(xmlValidateNmtokensValueInternal(NULL, value)); +} + +/** + * xmlValidateNotationDecl: + * @ctxt: the validation context + * @doc: a document instance + * @nota: a notation definition + * + * Try to validate a single notation definition + * basically it does the following checks as described by the + * XML-1.0 recommendation: + * - it seems that no validity constraint exists on notation declarations + * But this function get called anyway ... + * + * returns 1 if valid or 0 otherwise + */ + +int +xmlValidateNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDocPtr doc ATTRIBUTE_UNUSED, + xmlNotationPtr nota ATTRIBUTE_UNUSED) { + int ret = 1; + + return(ret); +} + +/** + * xmlValidateAttributeValueInternal: + * @doc: the document + * @type: an attribute type + * @value: an attribute value + * + * Validate that the given attribute value match the proper production + * + * returns 1 if valid or 0 otherwise + */ + +static int +xmlValidateAttributeValueInternal(xmlDocPtr doc, xmlAttributeType type, + const xmlChar *value) { + switch (type) { + case XML_ATTRIBUTE_ENTITIES: + case XML_ATTRIBUTE_IDREFS: + return(xmlValidateNamesValueInternal(doc, value)); + case XML_ATTRIBUTE_ENTITY: + case XML_ATTRIBUTE_IDREF: + case XML_ATTRIBUTE_ID: + case XML_ATTRIBUTE_NOTATION: + return(xmlValidateNameValueInternal(doc, value)); + case XML_ATTRIBUTE_NMTOKENS: + case XML_ATTRIBUTE_ENUMERATION: + return(xmlValidateNmtokensValueInternal(doc, value)); + case XML_ATTRIBUTE_NMTOKEN: + return(xmlValidateNmtokenValueInternal(doc, value)); + case XML_ATTRIBUTE_CDATA: + break; + } + return(1); +} + +/** + * xmlValidateAttributeValue: + * @type: an attribute type + * @value: an attribute value + * + * Validate that the given attribute value match the proper production + * + * [ VC: ID ] + * Values of type ID must match the Name production.... + * + * [ VC: IDREF ] + * Values of type IDREF must match the Name production, and values + * of type IDREFS must match Names ... + * + * [ VC: Entity Name ] + * Values of type ENTITY must match the Name production, values + * of type ENTITIES must match Names ... + * + * [ VC: Name Token ] + * Values of type NMTOKEN must match the Nmtoken production; values + * of type NMTOKENS must match Nmtokens. + * + * returns 1 if valid or 0 otherwise + */ +int +xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) { + return(xmlValidateAttributeValueInternal(NULL, type, value)); +} + +/** + * xmlValidateAttributeValue2: + * @ctxt: the validation context + * @doc: the document + * @name: the attribute name (used for error reporting only) + * @type: the attribute type + * @value: the attribute value + * + * Validate that the given attribute value match a given type. + * This typically cannot be done before having finished parsing + * the subsets. + * + * [ VC: IDREF ] + * Values of type IDREF must match one of the declared IDs + * Values of type IDREFS must match a sequence of the declared IDs + * each Name must match the value of an ID attribute on some element + * in the XML document; i.e. IDREF values must match the value of + * some ID attribute + * + * [ VC: Entity Name ] + * Values of type ENTITY must match one declared entity + * Values of type ENTITIES must match a sequence of declared entities + * + * [ VC: Notation Attributes ] + * all notation names in the declaration must be declared. + * + * returns 1 if valid or 0 otherwise + */ + +static int +xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc, + const xmlChar *name, xmlAttributeType type, const xmlChar *value) { + int ret = 1; + switch (type) { + case XML_ATTRIBUTE_IDREFS: + case XML_ATTRIBUTE_IDREF: + case XML_ATTRIBUTE_ID: + case XML_ATTRIBUTE_NMTOKENS: + case XML_ATTRIBUTE_ENUMERATION: + case XML_ATTRIBUTE_NMTOKEN: + case XML_ATTRIBUTE_CDATA: + break; + case XML_ATTRIBUTE_ENTITY: { + xmlEntityPtr ent; + + ent = xmlGetDocEntity(doc, value); + /* yeah it's a bit messy... */ + if ((ent == NULL) && (doc->standalone == 1)) { + doc->standalone = 0; + ent = xmlGetDocEntity(doc, value); + } + if (ent == NULL) { + xmlErrValidNode(ctxt, (xmlNodePtr) doc, + XML_DTD_UNKNOWN_ENTITY, + "ENTITY attribute %s reference an unknown entity \"%s\"\n", + name, value, NULL); + ret = 0; + } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) { + xmlErrValidNode(ctxt, (xmlNodePtr) doc, + XML_DTD_ENTITY_TYPE, + "ENTITY attribute %s reference an entity \"%s\" of wrong type\n", + name, value, NULL); + ret = 0; + } + break; + } + case XML_ATTRIBUTE_ENTITIES: { + xmlChar *dup, *nam = NULL, *cur, save; + xmlEntityPtr ent; + + dup = xmlStrdup(value); + if (dup == NULL) + return(0); + cur = dup; + while (*cur != 0) { + nam = cur; + while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++; + save = *cur; + *cur = 0; + ent = xmlGetDocEntity(doc, nam); + if (ent == NULL) { + xmlErrValidNode(ctxt, (xmlNodePtr) doc, + XML_DTD_UNKNOWN_ENTITY, + "ENTITIES attribute %s reference an unknown entity \"%s\"\n", + name, nam, NULL); + ret = 0; + } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) { + xmlErrValidNode(ctxt, (xmlNodePtr) doc, + XML_DTD_ENTITY_TYPE, + "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n", + name, nam, NULL); + ret = 0; + } + if (save == 0) + break; + *cur = save; + while (IS_BLANK_CH(*cur)) cur++; + } + xmlFree(dup); + break; + } + case XML_ATTRIBUTE_NOTATION: { + xmlNotationPtr nota; + + nota = xmlGetDtdNotationDesc(doc->intSubset, value); + if ((nota == NULL) && (doc->extSubset != NULL)) + nota = xmlGetDtdNotationDesc(doc->extSubset, value); + + if (nota == NULL) { + xmlErrValidNode(ctxt, (xmlNodePtr) doc, + XML_DTD_UNKNOWN_NOTATION, + "NOTATION attribute %s reference an unknown notation \"%s\"\n", + name, value, NULL); + ret = 0; + } + break; + } + } + return(ret); +} + +/** + * xmlValidCtxtNormalizeAttributeValue: + * @ctxt: the validation context + * @doc: the document + * @elem: the parent + * @name: the attribute name + * @value: the attribute value + * @ctxt: the validation context or NULL + * + * Does the validation related extra step of the normalization of attribute + * values: + * + * 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 single space (#x20) character. + * + * Also check VC: Standalone Document Declaration in P32, and update + * ctxt->valid accordingly + * + * returns a new normalized string if normalization is needed, NULL otherwise + * the caller must free the returned value. + */ + +xmlChar * +xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc, + xmlNodePtr elem, const xmlChar *name, const xmlChar *value) { + xmlChar *ret, *dst; + const xmlChar *src; + xmlAttributePtr attrDecl = NULL; + int extsubset = 0; + + if (doc == NULL) return(NULL); + if (elem == NULL) return(NULL); + if (name == NULL) return(NULL); + if (value == NULL) return(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) + return(NULL); + attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name); + if ((attrDecl == NULL) && (doc->extSubset != NULL)) { + attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name); + if (attrDecl != NULL) + extsubset = 1; + } + if ((fullname != fn) && (fullname != elem->name)) + xmlFree(fullname); + } + if ((attrDecl == NULL) && (doc->intSubset != NULL)) + attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name); + if ((attrDecl == NULL) && (doc->extSubset != NULL)) { + attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name); + if (attrDecl != NULL) + extsubset = 1; + } + + if (attrDecl == NULL) + return(NULL); + if (attrDecl->atype == XML_ATTRIBUTE_CDATA) + return(NULL); + + ret = xmlStrdup(value); + if (ret == NULL) + return(NULL); + src = value; + dst = ret; + while (*src == 0x20) src++; + while (*src != 0) { + if (*src == 0x20) { + while (*src == 0x20) src++; + if (*src != 0) + *dst++ = 0x20; + } else { + *dst++ = *src++; + } + } + *dst = 0; + if ((doc->standalone) && (extsubset == 1) && (!xmlStrEqual(value, ret))) { + xmlErrValidNode(ctxt, elem, XML_DTD_NOT_STANDALONE, +"standalone: %s on %s value had to be normalized based on external subset declaration\n", + name, elem->name, NULL); + ctxt->valid = 0; + } + return(ret); +} + +/** + * xmlValidNormalizeAttributeValue: + * @doc: the document + * @elem: the parent + * @name: the attribute name + * @value: the attribute value + * + * Does the validation related extra step of the normalization of attribute + * values: + * + * 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 single space (#x20) character. + * + * Returns a new normalized string if normalization is needed, NULL otherwise + * the caller must free the returned value. + */ + +xmlChar * +xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem, + const xmlChar *name, const xmlChar *value) { + xmlChar *ret, *dst; + const xmlChar *src; + xmlAttributePtr attrDecl = NULL; + + if (doc == NULL) return(NULL); + if (elem == NULL) return(NULL); + if (name == NULL) return(NULL); + if (value == NULL) return(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) + return(NULL); + if ((fullname != fn) && (fullname != elem->name)) + xmlFree(fullname); + } + attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name); + if ((attrDecl == NULL) && (doc->extSubset != NULL)) + attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name); + + if (attrDecl == NULL) + return(NULL); + if (attrDecl->atype == XML_ATTRIBUTE_CDATA) + return(NULL); + + ret = xmlStrdup(value); + if (ret == NULL) + return(NULL); + src = value; + dst = ret; + while (*src == 0x20) src++; + while (*src != 0) { + if (*src == 0x20) { + while (*src == 0x20) src++; + if (*src != 0) + *dst++ = 0x20; + } else { + *dst++ = *src++; + } + } + *dst = 0; + return(ret); +} + +static void +xmlValidateAttributeIdCallback(xmlAttributePtr attr, int *count, + const xmlChar* name ATTRIBUTE_UNUSED) { + if (attr->atype == XML_ATTRIBUTE_ID) (*count)++; +} + +/** + * xmlValidateAttributeDecl: + * @ctxt: the validation context + * @doc: a document instance + * @attr: an attribute definition + * + * Try to validate a single attribute definition + * basically it does the following checks as described by the + * XML-1.0 recommendation: + * - [ VC: Attribute Default Legal ] + * - [ VC: Enumeration ] + * - [ VC: ID Attribute Default ] + * + * The ID/IDREF uniqueness and matching are done separately + * + * returns 1 if valid or 0 otherwise + */ + +int +xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc, + xmlAttributePtr attr) { + int ret = 1; + int val; + CHECK_DTD; + if(attr == NULL) return(1); + + /* Attribute Default Legal */ + /* Enumeration */ + if (attr->defaultValue != NULL) { + val = xmlValidateAttributeValueInternal(doc, attr->atype, + attr->defaultValue); + if (val == 0) { + xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_DEFAULT, + "Syntax of default value for attribute %s of %s is not valid\n", + attr->name, attr->elem, NULL); + } + ret &= val; + } + + /* ID Attribute Default */ + if ((attr->atype == XML_ATTRIBUTE_ID)&& + (attr->def != XML_ATTRIBUTE_IMPLIED) && + (attr->def != XML_ATTRIBUTE_REQUIRED)) { + xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_FIXED, + "ID attribute %s of %s is not valid must be #IMPLIED or #REQUIRED\n", + attr->name, attr->elem, NULL); + ret = 0; + } + + /* One ID per Element Type */ + if (attr->atype == XML_ATTRIBUTE_ID) { + int nbId; + + /* the trick is that we parse DtD as their own internal subset */ + xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset, + attr->elem); + if (elem != NULL) { + nbId = xmlScanIDAttributeDecl(NULL, elem, 0); + } else { + xmlAttributeTablePtr table; + + /* + * The attribute may be declared in the internal subset and the + * element in the external subset. + */ + nbId = 0; + if (doc->intSubset != NULL) { + table = (xmlAttributeTablePtr) doc->intSubset->attributes; + xmlHashScan3(table, NULL, NULL, attr->elem, (xmlHashScanner) + xmlValidateAttributeIdCallback, &nbId); + } + } + if (nbId > 1) { + + 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); + } else if (doc->extSubset != NULL) { + int extId = 0; + elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem); + if (elem != NULL) { + extId = xmlScanIDAttributeDecl(NULL, 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); + } 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); + } + } + } + + /* Validity Constraint: Enumeration */ + if ((attr->defaultValue != NULL) && (attr->tree != NULL)) { + xmlEnumerationPtr tree = attr->tree; + while (tree != NULL) { + if (xmlStrEqual(tree->name, attr->defaultValue)) break; + tree = tree->next; + } + if (tree == NULL) { + xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_VALUE, +"Default value \"%s\" for attribute %s of %s is not among the enumerated set\n", + attr->defaultValue, attr->name, attr->elem); + ret = 0; + } + } + + return(ret); +} + +/** + * xmlValidateElementDecl: + * @ctxt: the validation context + * @doc: a document instance + * @elem: an element definition + * + * Try to validate a single element definition + * basically it does the following checks as described by the + * XML-1.0 recommendation: + * - [ VC: One ID per Element Type ] + * - [ VC: No Duplicate Types ] + * - [ VC: Unique Element Type Declaration ] + * + * returns 1 if valid or 0 otherwise + */ + +int +xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc, + xmlElementPtr elem) { + int ret = 1; + xmlElementPtr tst; + + CHECK_DTD; + + if (elem == NULL) return(1); + +#if 0 +#ifdef LIBXML_REGEXP_ENABLED + /* Build the regexp associated to the content model */ + ret = xmlValidBuildContentModel(ctxt, elem); +#endif +#endif + + /* No Duplicate Types */ + if (elem->etype == XML_ELEMENT_TYPE_MIXED) { + xmlElementContentPtr cur, next; + const xmlChar *name; + + cur = elem->content; + while (cur != NULL) { + if (cur->type != XML_ELEMENT_CONTENT_OR) break; + if (cur->c1 == NULL) break; + if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) { + name = cur->c1->name; + next = cur->c2; + while (next != NULL) { + if (next->type == XML_ELEMENT_CONTENT_ELEMENT) { + if ((xmlStrEqual(next->name, name)) && + (xmlStrEqual(next->prefix, cur->c1->prefix))) { + if (cur->c1->prefix == NULL) { + xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR, + "Definition of %s has duplicate references of %s\n", + elem->name, name, NULL); + } else { + xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR, + "Definition of %s has duplicate references of %s:%s\n", + elem->name, cur->c1->prefix, name); + } + ret = 0; + } + break; + } + if (next->c1 == NULL) break; + if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break; + if ((xmlStrEqual(next->c1->name, name)) && + (xmlStrEqual(next->c1->prefix, cur->c1->prefix))) { + if (cur->c1->prefix == NULL) { + xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR, + "Definition of %s has duplicate references to %s\n", + elem->name, name, NULL); + } else { + xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR, + "Definition of %s has duplicate references to %s:%s\n", + elem->name, cur->c1->prefix, name); + } + ret = 0; + } + next = next->c2; + } + } + cur = cur->c2; + } + } + + /* 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; + } + 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; + } + /* One ID per Element Type + * already done when registering the attribute + if (xmlScanIDAttributeDecl(ctxt, elem) > 1) { + ret = 0; + } */ + return(ret); +} + +/** + * xmlValidateOneAttribute: + * @ctxt: the validation context + * @doc: a document instance + * @elem: an element instance + * @attr: an attribute instance + * @value: the attribute value (without entities processing) + * + * Try to validate a single attribute for an element + * basically it does the following checks as described by the + * XML-1.0 recommendation: + * - [ VC: Attribute Value Type ] + * - [ VC: Fixed Attribute Default ] + * - [ VC: Entity Name ] + * - [ VC: Name Token ] + * - [ VC: ID ] + * - [ VC: IDREF ] + * - [ VC: Entity Name ] + * - [ VC: Notation Attributes ] + * + * The ID/IDREF uniqueness and matching are done separately + * + * returns 1 if valid or 0 otherwise + */ + +int +xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc, + xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value) +{ + xmlAttributePtr attrDecl = NULL; + int val; + int ret = 1; + + CHECK_DTD; + if ((elem == NULL) || (elem->name == NULL)) return(0); + if ((attr == NULL) || (attr->name == NULL)) return(0); + + 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) + 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); + } + 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); + } + } + + + /* Validity Constraint: Attribute Value Type */ + if (attrDecl == NULL) { + xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE, + "No declaration for attribute %s of element %s\n", + attr->name, elem->name, NULL); + return(0); + } + attr->atype = attrDecl->atype; + + val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value); + if (val == 0) { + xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE, + "Syntax of value for attribute %s of %s is not valid\n", + attr->name, elem->name, NULL); + ret = 0; + } + + /* Validity constraint: Fixed Attribute Default */ + if (attrDecl->def == XML_ATTRIBUTE_FIXED) { + if (!xmlStrEqual(value, attrDecl->defaultValue)) { + xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT, + "Value for attribute %s of %s is different from default \"%s\"\n", + attr->name, elem->name, attrDecl->defaultValue); + ret = 0; + } + } + + /* Validity Constraint: ID uniqueness */ + if (attrDecl->atype == XML_ATTRIBUTE_ID) { + if (xmlAddID(ctxt, doc, value, attr) == NULL) + ret = 0; + } + + if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) || + (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) { + if (xmlAddRef(ctxt, doc, value, attr) == NULL) + ret = 0; + } + + /* Validity Constraint: Notation Attributes */ + if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) { + xmlEnumerationPtr tree = attrDecl->tree; + xmlNotationPtr nota; + + /* First check that the given NOTATION was declared */ + nota = xmlGetDtdNotationDesc(doc->intSubset, value); + if (nota == NULL) + nota = xmlGetDtdNotationDesc(doc->extSubset, value); + + if (nota == NULL) { + xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION, + "Value \"%s\" for attribute %s of %s is not a declared Notation\n", + value, attr->name, elem->name); + ret = 0; + } + + /* Second, verify that it's among the list */ + while (tree != NULL) { + if (xmlStrEqual(tree->name, value)) break; + tree = tree->next; + } + if (tree == NULL) { + xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE, +"Value \"%s\" for attribute %s of %s is not among the enumerated notations\n", + value, attr->name, elem->name); + ret = 0; + } + } + + /* Validity Constraint: Enumeration */ + if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) { + xmlEnumerationPtr tree = attrDecl->tree; + while (tree != NULL) { + if (xmlStrEqual(tree->name, value)) break; + tree = tree->next; + } + if (tree == NULL) { + xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE, + "Value \"%s\" for attribute %s of %s is not among the enumerated set\n", + value, attr->name, elem->name); + ret = 0; + } + } + + /* Fixed Attribute Default */ + if ((attrDecl->def == XML_ATTRIBUTE_FIXED) && + (!xmlStrEqual(attrDecl->defaultValue, value))) { + xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE, + "Value for attribute %s of %s must be \"%s\"\n", + attr->name, elem->name, attrDecl->defaultValue); + ret = 0; + } + + /* Extra check for the attribute value */ + ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name, + attrDecl->atype, value); + + return(ret); +} + +/** + * xmlValidateOneNamespace: + * @ctxt: the validation context + * @doc: a document instance + * @elem: an element instance + * @prefix: the namespace prefix + * @ns: an namespace declaration instance + * @value: the attribute value (without entities processing) + * + * Try to validate a single namespace declaration for an element + * basically it does the following checks as described by the + * XML-1.0 recommendation: + * - [ VC: Attribute Value Type ] + * - [ VC: Fixed Attribute Default ] + * - [ VC: Entity Name ] + * - [ VC: Name Token ] + * - [ VC: ID ] + * - [ VC: IDREF ] + * - [ VC: Entity Name ] + * - [ VC: Notation Attributes ] + * + * The ID/IDREF uniqueness and matching are done separately + * + * returns 1 if valid or 0 otherwise + */ + +int +xmlValidateOneNamespace(xmlValidCtxtPtr ctxt, xmlDocPtr doc, +xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) { + /* xmlElementPtr elemDecl; */ + xmlAttributePtr attrDecl = NULL; + int val; + int ret = 1; + + CHECK_DTD; + if ((elem == NULL) || (elem->name == NULL)) return(0); + if ((ns == NULL) || (ns->href == NULL)) return(0); + + if (prefix != NULL) { + xmlChar fn[50]; + xmlChar *fullname; + + fullname = xmlBuildQName(elem->name, prefix, fn, 50); + if (fullname == NULL) { + xmlVErrMemory(ctxt, "Validating namespace"); + return(0); + } + if (ns->prefix != NULL) { + attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname, + ns->prefix, BAD_CAST "xmlns"); + if ((attrDecl == NULL) && (doc->extSubset != NULL)) + attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname, + ns->prefix, BAD_CAST "xmlns"); + } else { + attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, + BAD_CAST "xmlns"); + if ((attrDecl == NULL) && (doc->extSubset != NULL)) + attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, + BAD_CAST "xmlns"); + } + if ((fullname != fn) && (fullname != elem->name)) + xmlFree(fullname); + } + if (attrDecl == NULL) { + if (ns->prefix != NULL) { + attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name, + ns->prefix, BAD_CAST "xmlns"); + if ((attrDecl == NULL) && (doc->extSubset != NULL)) + attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name, + ns->prefix, BAD_CAST "xmlns"); + } else { + attrDecl = xmlGetDtdAttrDesc(doc->intSubset, + elem->name, BAD_CAST "xmlns"); + if ((attrDecl == NULL) && (doc->extSubset != NULL)) + attrDecl = xmlGetDtdAttrDesc(doc->extSubset, + elem->name, BAD_CAST "xmlns"); + } + } + + + /* Validity Constraint: Attribute Value Type */ + if (attrDecl == NULL) { + if (ns->prefix != NULL) { + xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE, + "No declaration for attribute xmlns:%s of element %s\n", + ns->prefix, elem->name, NULL); + } else { + xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE, + "No declaration for attribute xmlns of element %s\n", + elem->name, NULL, NULL); + } + return(0); + } + + val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value); + if (val == 0) { + if (ns->prefix != NULL) { + xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT, + "Syntax of value for attribute xmlns:%s of %s is not valid\n", + ns->prefix, elem->name, NULL); + } else { + xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT, + "Syntax of value for attribute xmlns of %s is not valid\n", + elem->name, NULL, NULL); + } + ret = 0; + } + + /* Validity constraint: Fixed Attribute Default */ + if (attrDecl->def == XML_ATTRIBUTE_FIXED) { + if (!xmlStrEqual(value, attrDecl->defaultValue)) { + if (ns->prefix != NULL) { + xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT, + "Value for attribute xmlns:%s of %s is different from default \"%s\"\n", + ns->prefix, elem->name, attrDecl->defaultValue); + } else { + xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT, + "Value for attribute xmlns of %s is different from default \"%s\"\n", + elem->name, attrDecl->defaultValue, NULL); + } + ret = 0; + } + } + + /* Validity Constraint: ID uniqueness */ + if (attrDecl->atype == XML_ATTRIBUTE_ID) { + if (xmlAddID(ctxt, doc, value, (xmlAttrPtr) ns) == NULL) + ret = 0; + } + + if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) || + (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) { + if (xmlAddRef(ctxt, doc, value, (xmlAttrPtr) ns) == NULL) + ret = 0; + } + + /* Validity Constraint: Notation Attributes */ + if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) { + xmlEnumerationPtr tree = attrDecl->tree; + xmlNotationPtr nota; + + /* First check that the given NOTATION was declared */ + nota = xmlGetDtdNotationDesc(doc->intSubset, value); + if (nota == NULL) + nota = xmlGetDtdNotationDesc(doc->extSubset, value); + + if (nota == NULL) { + if (ns->prefix != NULL) { + xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION, + "Value \"%s\" for attribute xmlns:%s of %s is not a declared Notation\n", + value, ns->prefix, elem->name); + } else { + xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION, + "Value \"%s\" for attribute xmlns of %s is not a declared Notation\n", + value, elem->name, NULL); + } + ret = 0; + } + + /* Second, verify that it's among the list */ + while (tree != NULL) { + if (xmlStrEqual(tree->name, value)) break; + tree = tree->next; + } + if (tree == NULL) { + if (ns->prefix != NULL) { + xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE, +"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated notations\n", + value, ns->prefix, elem->name); + } else { + xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE, +"Value \"%s\" for attribute xmlns of %s is not among the enumerated notations\n", + value, elem->name, NULL); + } + ret = 0; + } + } + + /* Validity Constraint: Enumeration */ + if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) { + xmlEnumerationPtr tree = attrDecl->tree; + while (tree != NULL) { + if (xmlStrEqual(tree->name, value)) break; + tree = tree->next; + } + if (tree == NULL) { + if (ns->prefix != NULL) { + xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE, +"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated set\n", + value, ns->prefix, elem->name); + } else { + xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE, +"Value \"%s\" for attribute xmlns of %s is not among the enumerated set\n", + value, elem->name, NULL); + } + ret = 0; + } + } + + /* Fixed Attribute Default */ + if ((attrDecl->def == XML_ATTRIBUTE_FIXED) && + (!xmlStrEqual(attrDecl->defaultValue, value))) { + if (ns->prefix != NULL) { + xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE, + "Value for attribute xmlns:%s of %s must be \"%s\"\n", + ns->prefix, elem->name, attrDecl->defaultValue); + } else { + xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE, + "Value for attribute xmlns of %s must be \"%s\"\n", + elem->name, attrDecl->defaultValue, NULL); + } + ret = 0; + } + + /* Extra check for the attribute value */ + if (ns->prefix != NULL) { + ret &= xmlValidateAttributeValue2(ctxt, doc, ns->prefix, + attrDecl->atype, value); + } else { + ret &= xmlValidateAttributeValue2(ctxt, doc, BAD_CAST "xmlns", + attrDecl->atype, value); + } + + return(ret); +} + +#ifndef LIBXML_REGEXP_ENABLED +/** + * xmlValidateSkipIgnorable: + * @ctxt: the validation context + * @child: the child list + * + * Skip ignorable elements w.r.t. the validation process + * + * returns the first element to consider for validation of the content model + */ + +static xmlNodePtr +xmlValidateSkipIgnorable(xmlNodePtr child) { + while (child != NULL) { + switch (child->type) { + /* These things are ignored (skipped) during validation. */ + case XML_PI_NODE: + case XML_COMMENT_NODE: + case XML_XINCLUDE_START: + case XML_XINCLUDE_END: + child = child->next; + break; + case XML_TEXT_NODE: + if (xmlIsBlankNode(child)) + child = child->next; + else + return(child); + break; + /* keep current node */ + default: + return(child); + } + } + return(child); +} + +/** + * xmlValidateElementType: + * @ctxt: the validation context + * + * Try to validate the content model of an element internal function + * + * returns 1 if valid or 0 ,-1 in case of error, -2 if an entity + * reference is found and -3 if the validation succeeded but + * the content model is not determinist. + */ + +static int +xmlValidateElementType(xmlValidCtxtPtr ctxt) { + int ret = -1; + int determinist = 1; + + NODE = xmlValidateSkipIgnorable(NODE); + if ((NODE == NULL) && (CONT == NULL)) + return(1); + if ((NODE == NULL) && + ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) || + (CONT->ocur == XML_ELEMENT_CONTENT_OPT))) { + return(1); + } + if (CONT == NULL) return(-1); + if ((NODE != NULL) && (NODE->type == XML_ENTITY_REF_NODE)) + return(-2); + + /* + * We arrive here when more states need to be examined + */ +cont: + + /* + * We just recovered from a rollback generated by a possible + * epsilon transition, go directly to the analysis phase + */ + if (STATE == ROLLBACK_PARENT) { + DEBUG_VALID_MSG("restored parent branch"); + DEBUG_VALID_STATE(NODE, CONT) + ret = 1; + goto analyze; + } + + DEBUG_VALID_STATE(NODE, CONT) + /* + * we may have to save a backup state here. This is the equivalent + * of handling epsilon transition in NFAs. + */ + if ((CONT != NULL) && + ((CONT->parent == NULL) || + (CONT->parent->type != XML_ELEMENT_CONTENT_OR)) && + ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) || + (CONT->ocur == XML_ELEMENT_CONTENT_OPT) || + ((CONT->ocur == XML_ELEMENT_CONTENT_PLUS) && (OCCURRENCE)))) { + DEBUG_VALID_MSG("saving parent branch"); + if (vstateVPush(ctxt, CONT, NODE, DEPTH, OCCURS, ROLLBACK_PARENT) < 0) + return(0); + } + + + /* + * Check first if the content matches + */ + switch (CONT->type) { + case XML_ELEMENT_CONTENT_PCDATA: + if (NODE == NULL) { + DEBUG_VALID_MSG("pcdata failed no node"); + ret = 0; + break; + } + if (NODE->type == XML_TEXT_NODE) { + DEBUG_VALID_MSG("pcdata found, skip to next"); + /* + * go to next element in the content model + * skipping ignorable elems + */ + do { + NODE = NODE->next; + NODE = xmlValidateSkipIgnorable(NODE); + if ((NODE != NULL) && + (NODE->type == XML_ENTITY_REF_NODE)) + return(-2); + } while ((NODE != NULL) && + ((NODE->type != XML_ELEMENT_NODE) && + (NODE->type != XML_TEXT_NODE) && + (NODE->type != XML_CDATA_SECTION_NODE))); + ret = 1; + break; + } else { + DEBUG_VALID_MSG("pcdata failed"); + ret = 0; + break; + } + break; + case XML_ELEMENT_CONTENT_ELEMENT: + if (NODE == NULL) { + DEBUG_VALID_MSG("element failed no node"); + ret = 0; + break; + } + ret = ((NODE->type == XML_ELEMENT_NODE) && + (xmlStrEqual(NODE->name, CONT->name))); + if (ret == 1) { + if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) { + ret = (CONT->prefix == NULL); + } else if (CONT->prefix == NULL) { + ret = 0; + } else { + ret = xmlStrEqual(NODE->ns->prefix, CONT->prefix); + } + } + if (ret == 1) { + DEBUG_VALID_MSG("element found, skip to next"); + /* + * go to next element in the content model + * skipping ignorable elems + */ + do { + NODE = NODE->next; + NODE = xmlValidateSkipIgnorable(NODE); + if ((NODE != NULL) && + (NODE->type == XML_ENTITY_REF_NODE)) + return(-2); + } while ((NODE != NULL) && + ((NODE->type != XML_ELEMENT_NODE) && + (NODE->type != XML_TEXT_NODE) && + (NODE->type != XML_CDATA_SECTION_NODE))); + } else { + DEBUG_VALID_MSG("element failed"); + ret = 0; + break; + } + break; + case XML_ELEMENT_CONTENT_OR: + /* + * Small optimization. + */ + if (CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) { + if ((NODE == NULL) || + (!xmlStrEqual(NODE->name, CONT->c1->name))) { + DEPTH++; + CONT = CONT->c2; + goto cont; + } + if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) { + ret = (CONT->c1->prefix == NULL); + } else if (CONT->c1->prefix == NULL) { + ret = 0; + } else { + ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix); + } + if (ret == 0) { + DEPTH++; + CONT = CONT->c2; + goto cont; + } + } + + /* + * save the second branch 'or' branch + */ + DEBUG_VALID_MSG("saving 'or' branch"); + if (vstateVPush(ctxt, CONT->c2, NODE, (unsigned char)(DEPTH + 1), + OCCURS, ROLLBACK_OR) < 0) + return(-1); + DEPTH++; + CONT = CONT->c1; + goto cont; + case XML_ELEMENT_CONTENT_SEQ: + /* + * Small optimization. + */ + if ((CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) && + ((CONT->c1->ocur == XML_ELEMENT_CONTENT_OPT) || + (CONT->c1->ocur == XML_ELEMENT_CONTENT_MULT))) { + if ((NODE == NULL) || + (!xmlStrEqual(NODE->name, CONT->c1->name))) { + DEPTH++; + CONT = CONT->c2; + goto cont; + } + if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) { + ret = (CONT->c1->prefix == NULL); + } else if (CONT->c1->prefix == NULL) { + ret = 0; + } else { + ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix); + } + if (ret == 0) { + DEPTH++; + CONT = CONT->c2; + goto cont; + } + } + DEPTH++; + CONT = CONT->c1; + goto cont; + } + + /* + * At this point handle going up in the tree + */ + if (ret == -1) { + DEBUG_VALID_MSG("error found returning"); + return(ret); + } +analyze: + while (CONT != NULL) { + /* + * First do the analysis depending on the occurrence model at + * this level. + */ + if (ret == 0) { + switch (CONT->ocur) { + xmlNodePtr cur; + + case XML_ELEMENT_CONTENT_ONCE: + cur = ctxt->vstate->node; + DEBUG_VALID_MSG("Once branch failed, rollback"); + if (vstateVPop(ctxt) < 0 ) { + DEBUG_VALID_MSG("exhaustion, failed"); + return(0); + } + if (cur != ctxt->vstate->node) + determinist = -3; + goto cont; + case XML_ELEMENT_CONTENT_PLUS: + if (OCCURRENCE == 0) { + cur = ctxt->vstate->node; + DEBUG_VALID_MSG("Plus branch failed, rollback"); + if (vstateVPop(ctxt) < 0 ) { + DEBUG_VALID_MSG("exhaustion, failed"); + return(0); + } + if (cur != ctxt->vstate->node) + determinist = -3; + goto cont; + } + DEBUG_VALID_MSG("Plus branch found"); + ret = 1; + break; + case XML_ELEMENT_CONTENT_MULT: +#ifdef DEBUG_VALID_ALGO + if (OCCURRENCE == 0) { + DEBUG_VALID_MSG("Mult branch failed"); + } else { + DEBUG_VALID_MSG("Mult branch found"); + } +#endif + ret = 1; + break; + case XML_ELEMENT_CONTENT_OPT: + DEBUG_VALID_MSG("Option branch failed"); + ret = 1; + break; + } + } else { + switch (CONT->ocur) { + case XML_ELEMENT_CONTENT_OPT: + DEBUG_VALID_MSG("Option branch succeeded"); + ret = 1; + break; + case XML_ELEMENT_CONTENT_ONCE: + DEBUG_VALID_MSG("Once branch succeeded"); + ret = 1; + break; + case XML_ELEMENT_CONTENT_PLUS: + if (STATE == ROLLBACK_PARENT) { + DEBUG_VALID_MSG("Plus branch rollback"); + ret = 1; + break; + } + if (NODE == NULL) { + DEBUG_VALID_MSG("Plus branch exhausted"); + ret = 1; + break; + } + DEBUG_VALID_MSG("Plus branch succeeded, continuing"); + SET_OCCURRENCE; + goto cont; + case XML_ELEMENT_CONTENT_MULT: + if (STATE == ROLLBACK_PARENT) { + DEBUG_VALID_MSG("Mult branch rollback"); + ret = 1; + break; + } + if (NODE == NULL) { + DEBUG_VALID_MSG("Mult branch exhausted"); + ret = 1; + break; + } + DEBUG_VALID_MSG("Mult branch succeeded, continuing"); + /* SET_OCCURRENCE; */ + goto cont; + } + } + STATE = 0; + + /* + * Then act accordingly at the parent level + */ + RESET_OCCURRENCE; + if (CONT->parent == NULL) + break; + + switch (CONT->parent->type) { + case XML_ELEMENT_CONTENT_PCDATA: + DEBUG_VALID_MSG("Error: parent pcdata"); + return(-1); + case XML_ELEMENT_CONTENT_ELEMENT: + DEBUG_VALID_MSG("Error: parent element"); + return(-1); + case XML_ELEMENT_CONTENT_OR: + if (ret == 1) { + DEBUG_VALID_MSG("Or succeeded"); + CONT = CONT->parent; + DEPTH--; + } else { + DEBUG_VALID_MSG("Or failed"); + CONT = CONT->parent; + DEPTH--; + } + break; + case XML_ELEMENT_CONTENT_SEQ: + if (ret == 0) { + DEBUG_VALID_MSG("Sequence failed"); + CONT = CONT->parent; + DEPTH--; + } else if (CONT == CONT->parent->c1) { + DEBUG_VALID_MSG("Sequence testing 2nd branch"); + CONT = CONT->parent->c2; + goto cont; + } else { + DEBUG_VALID_MSG("Sequence succeeded"); + CONT = CONT->parent; + DEPTH--; + } + } + } + if (NODE != NULL) { + xmlNodePtr cur; + + cur = ctxt->vstate->node; + DEBUG_VALID_MSG("Failed, remaining input, rollback"); + if (vstateVPop(ctxt) < 0 ) { + DEBUG_VALID_MSG("exhaustion, failed"); + return(0); + } + if (cur != ctxt->vstate->node) + determinist = -3; + goto cont; + } + if (ret == 0) { + xmlNodePtr cur; + + cur = ctxt->vstate->node; + DEBUG_VALID_MSG("Failure, rollback"); + if (vstateVPop(ctxt) < 0 ) { + DEBUG_VALID_MSG("exhaustion, failed"); + return(0); + } + if (cur != ctxt->vstate->node) + determinist = -3; + goto cont; + } + return(determinist); +} +#endif + +/** + * xmlSnprintfElements: + * @buf: an output buffer + * @size: the size of the buffer + * @content: An element + * @glob: 1 if one must print the englobing parenthesis, 0 otherwise + * + * This will dump the list of elements to the buffer + * Intended just for the debug routine + */ +static void +xmlSnprintfElements(char *buf, int size, xmlNodePtr node, int glob) { + xmlNodePtr cur; + int len; + + if (node == NULL) return; + if (glob) strcat(buf, "("); + cur = node; + while (cur != NULL) { + len = strlen(buf); + if (size - len < 50) { + if ((size - len > 4) && (buf[len - 1] != '.')) + strcat(buf, " ..."); + return; + } + switch (cur->type) { + case XML_ELEMENT_NODE: + if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) { + if (size - len < xmlStrlen(cur->ns->prefix) + 10) { + if ((size - len > 4) && (buf[len - 1] != '.')) + strcat(buf, " ..."); + return; + } + strcat(buf, (char *) cur->ns->prefix); + strcat(buf, ":"); + } + if (size - len < xmlStrlen(cur->name) + 10) { + if ((size - len > 4) && (buf[len - 1] != '.')) + strcat(buf, " ..."); + return; + } + strcat(buf, (char *) cur->name); + if (cur->next != NULL) + strcat(buf, " "); + break; + case XML_TEXT_NODE: + if (xmlIsBlankNode(cur)) + break; + case XML_CDATA_SECTION_NODE: + case XML_ENTITY_REF_NODE: + strcat(buf, "CDATA"); + if (cur->next != NULL) + strcat(buf, " "); + break; + case XML_ATTRIBUTE_NODE: + case XML_DOCUMENT_NODE: +#ifdef LIBXML_DOCB_ENABLED + case XML_DOCB_DOCUMENT_NODE: +#endif + case XML_HTML_DOCUMENT_NODE: + case XML_DOCUMENT_TYPE_NODE: + case XML_DOCUMENT_FRAG_NODE: + case XML_NOTATION_NODE: + case XML_NAMESPACE_DECL: + strcat(buf, "???"); + if (cur->next != NULL) + strcat(buf, " "); + break; + case XML_ENTITY_NODE: + case XML_PI_NODE: + case XML_DTD_NODE: + case XML_COMMENT_NODE: + case XML_ELEMENT_DECL: + case XML_ATTRIBUTE_DECL: + case XML_ENTITY_DECL: + case XML_XINCLUDE_START: + case XML_XINCLUDE_END: + break; + } + cur = cur->next; + } + if (glob) strcat(buf, ")"); +} + +/** + * xmlValidateElementContent: + * @ctxt: the validation context + * @child: the child list + * @elemDecl: pointer to the element declaration + * @warn: emit the error message + * @parent: the parent element (for error reporting) + * + * Try to validate the content model of an element + * + * returns 1 if valid or 0 if not and -1 in case of error + */ + +static int +xmlValidateElementContent(xmlValidCtxtPtr ctxt, xmlNodePtr child, + xmlElementPtr elemDecl, int warn, xmlNodePtr parent) { + int ret = 1; +#ifndef LIBXML_REGEXP_ENABLED + xmlNodePtr repl = NULL, last = NULL, tmp; +#endif + xmlNodePtr cur; + xmlElementContentPtr cont; + const xmlChar *name; + + if (elemDecl == NULL) + return(-1); + cont = elemDecl->content; + name = elemDecl->name; + +#ifdef LIBXML_REGEXP_ENABLED + /* Build the regexp associated to the content model */ + if (elemDecl->contModel == NULL) + ret = xmlValidBuildContentModel(ctxt, elemDecl); + if (elemDecl->contModel == NULL) { + return(-1); + } else { + xmlRegExecCtxtPtr exec; + + if (!xmlRegexpIsDeterminist(elemDecl->contModel)) { + return(-1); + } + ctxt->nodeMax = 0; + 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); +fail: + xmlRegFreeExecCtxt(exec); + } + } +#else /* LIBXML_REGEXP_ENABLED */ + /* + * Allocate the stack + */ + ctxt->vstateMax = 8; + ctxt->vstateTab = (xmlValidState *) xmlMalloc( + ctxt->vstateMax * sizeof(ctxt->vstateTab[0])); + if (ctxt->vstateTab == NULL) { + xmlVErrMemory(ctxt, "malloc failed"); + return(-1); + } + /* + * The first entry in the stack is reserved to the current state + */ + ctxt->nodeMax = 0; + ctxt->nodeNr = 0; + ctxt->nodeTab = NULL; + ctxt->vstate = &ctxt->vstateTab[0]; + ctxt->vstateNr = 1; + CONT = cont; + NODE = child; + DEPTH = 0; + OCCURS = 0; + STATE = 0; + ret = xmlValidateElementType(ctxt); + if ((ret == -3) && (warn)) { + xmlErrValidWarning(ctxt, child, XML_DTD_CONTENT_NOT_DETERMINIST, + "Content model for Element %s is ambiguous\n", + name, NULL, NULL); + } else if (ret == -2) { + /* + * An entities reference appeared at this level. + * Buid a minimal representation of this node content + * sufficient to run the validation process on it + */ + DEBUG_VALID_MSG("Found an entity reference, linearizing"); + 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; + /* no break on purpose */ + case XML_CDATA_SECTION_NODE: + /* no break on purpose */ + case XML_ELEMENT_NODE: + /* + * Allocate a new node and minimally fills in + * what's required + */ + tmp = (xmlNodePtr) xmlMalloc(sizeof(xmlNode)); + if (tmp == NULL) { + xmlVErrMemory(ctxt, "malloc failed"); + xmlFreeNodeList(repl); + ret = -1; + goto done; + } + tmp->type = cur->type; + tmp->name = cur->name; + tmp->ns = cur->ns; + tmp->next = NULL; + tmp->content = NULL; + if (repl == NULL) + repl = last = tmp; + else { + last->next = tmp; + last = tmp; + } + if (cur->type == XML_CDATA_SECTION_NODE) { + /* + * E59 spaces in CDATA does not match the + * nonterminal S + */ + tmp->content = xmlStrdup(BAD_CAST "CDATA"); + } + break; + default: + break; + } + /* + * Switch to next element + */ + cur = cur->next; + while (cur == NULL) { + cur = nodeVPop(ctxt); + if (cur == NULL) + break; + cur = cur->next; + } + } + + /* + * Relaunch the validation + */ + ctxt->vstate = &ctxt->vstateTab[0]; + ctxt->vstateNr = 1; + CONT = cont; + NODE = repl; + DEPTH = 0; + OCCURS = 0; + STATE = 0; + ret = xmlValidateElementType(ctxt); + } +#endif /* LIBXML_REGEXP_ENABLED */ + if ((warn) && ((ret != 1) && (ret != -3))) { + if (ctxt != NULL) { + char expr[5000]; + char list[5000]; + + expr[0] = 0; + xmlSnprintfElementContent(&expr[0], 5000, cont, 1); + list[0] = 0; +#ifndef LIBXML_REGEXP_ENABLED + if (repl != NULL) + xmlSnprintfElements(&list[0], 5000, repl, 1); + else +#endif /* LIBXML_REGEXP_ENABLED */ + xmlSnprintfElements(&list[0], 5000, child, 1); + + if (name != NULL) { + xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL, + "Element %s content does not follow the DTD, expecting %s, got %s\n", + name, BAD_CAST expr, BAD_CAST list); + } else { + xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL, + "Element content does not follow the DTD, expecting %s, got %s\n", + BAD_CAST expr, BAD_CAST list, NULL); + } + } else { + if (name != NULL) { + xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL, + "Element %s content does not follow the DTD\n", + name, NULL, NULL); + } else { + xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL, + "Element content does not follow the DTD\n", + NULL, NULL, NULL); + } + } + ret = 0; + } + if (ret == -3) + ret = 1; + +#ifndef LIBXML_REGEXP_ENABLED +done: + /* + * Deallocate the copy if done, and free up the validation stack + */ + while (repl != NULL) { + tmp = repl->next; + xmlFree(repl); + repl = tmp; + } + ctxt->vstateMax = 0; + if (ctxt->vstateTab != NULL) { + xmlFree(ctxt->vstateTab); + ctxt->vstateTab = NULL; + } +#endif + ctxt->nodeMax = 0; + ctxt->nodeNr = 0; + if (ctxt->nodeTab != NULL) { + xmlFree(ctxt->nodeTab); + ctxt->nodeTab = NULL; + } + return(ret); + +} + +/** + * xmlValidateCdataElement: + * @ctxt: the validation context + * @doc: a document instance + * @elem: an element instance + * + * Check that an element follows #CDATA + * + * returns 1 if valid or 0 otherwise + */ +static int +xmlValidateOneCdataElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, + xmlNodePtr elem) { + int ret = 1; + xmlNodePtr cur, child; + + if ((ctxt == NULL) || (doc == NULL) || (elem == NULL)) + return(0); + + child = elem->children; + + 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_COMMENT_NODE: + case XML_PI_NODE: + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: + break; + default: + ret = 0; + goto done; + } + /* + * Switch to next element + */ + cur = cur->next; + while (cur == NULL) { + cur = nodeVPop(ctxt); + if (cur == NULL) + break; + cur = cur->next; + } + } +done: + ctxt->nodeMax = 0; + ctxt->nodeNr = 0; + if (ctxt->nodeTab != NULL) { + xmlFree(ctxt->nodeTab); + ctxt->nodeTab = NULL; + } + return(ret); +} + +/** + * xmlValidateCheckMixed: + * @ctxt: the validation context + * @cont: the mixed content model + * @qname: the qualified name as appearing in the serialization + * + * Check if the given node is part of the content model. + * + * Returns 1 if yes, 0 if no, -1 in case of error + */ +static int +xmlValidateCheckMixed(xmlValidCtxtPtr ctxt, + xmlElementContentPtr cont, const xmlChar *qname) { + const xmlChar *name; + int plen; + name = xmlSplitQName3(qname, &plen); + + if (name == NULL) { + while (cont != NULL) { + if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) { + if ((cont->prefix == NULL) && (xmlStrEqual(cont->name, qname))) + return(1); + } else if ((cont->type == XML_ELEMENT_CONTENT_OR) && + (cont->c1 != NULL) && + (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){ + if ((cont->c1->prefix == NULL) && + (xmlStrEqual(cont->c1->name, qname))) + return(1); + } else if ((cont->type != XML_ELEMENT_CONTENT_OR) || + (cont->c1 == NULL) || + (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){ + xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT, + "Internal: MIXED struct corrupted\n", + NULL); + break; + } + cont = cont->c2; + } + } else { + while (cont != NULL) { + if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) { + if ((cont->prefix != NULL) && + (xmlStrncmp(cont->prefix, qname, plen) == 0) && + (xmlStrEqual(cont->name, name))) + return(1); + } else if ((cont->type == XML_ELEMENT_CONTENT_OR) && + (cont->c1 != NULL) && + (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){ + if ((cont->c1->prefix != NULL) && + (xmlStrncmp(cont->c1->prefix, qname, plen) == 0) && + (xmlStrEqual(cont->c1->name, name))) + return(1); + } else if ((cont->type != XML_ELEMENT_CONTENT_OR) || + (cont->c1 == NULL) || + (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){ + xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT, + "Internal: MIXED struct corrupted\n", + NULL); + break; + } + cont = cont->c2; + } + } + return(0); +} + +/** + * xmlValidGetElemDecl: + * @ctxt: the validation context + * @doc: a document instance + * @elem: an element instance + * @extsubset: pointer, (out) indicate if the declaration was found + * in the external subset. + * + * Finds a declaration associated to an element in the document. + * + * returns the pointer to the declaration or NULL if not found. + */ +static xmlElementPtr +xmlValidGetElemDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc, + xmlNodePtr elem, int *extsubset) { + xmlElementPtr elemDecl = NULL; + const xmlChar *prefix = NULL; + + if ((ctxt == NULL) || (doc == NULL) || + (elem == NULL) || (elem->name == NULL)) + return(NULL); + if (extsubset != NULL) + *extsubset = 0; + + /* + * Fetch the declaration for the qualified name + */ + if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) + prefix = elem->ns->prefix; + + if (prefix != NULL) { + elemDecl = xmlGetDtdQElementDesc(doc->intSubset, + elem->name, prefix); + if ((elemDecl == NULL) && (doc->extSubset != NULL)) { + elemDecl = xmlGetDtdQElementDesc(doc->extSubset, + elem->name, prefix); + if ((elemDecl != NULL) && (extsubset != NULL)) + *extsubset = 1; + } + } + + /* + * Fetch the declaration for the non qualified name + * This is "non-strict" validation should be done on the + * full QName but in that case being flexible makes sense. + */ + if (elemDecl == NULL) { + elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name); + if ((elemDecl == NULL) && (doc->extSubset != NULL)) { + elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name); + if ((elemDecl != NULL) && (extsubset != NULL)) + *extsubset = 1; + } + } + if (elemDecl == NULL) { + xmlErrValidNode(ctxt, elem, + XML_DTD_UNKNOWN_ELEM, + "No declaration for element %s\n", + elem->name, NULL, NULL); + } + return(elemDecl); +} + +#ifdef LIBXML_REGEXP_ENABLED +/** + * xmlValidatePushElement: + * @ctxt: the validation context + * @doc: a document instance + * @elem: an element instance + * @qname: the qualified name as appearing in the serialization + * + * Push a new element start on the validation stack. + * + * returns 1 if no validation problem was found or 0 otherwise + */ +int +xmlValidatePushElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, + xmlNodePtr elem, const xmlChar *qname) { + int ret = 1; + xmlElementPtr eDecl; + int extsubset = 0; + + if (ctxt == NULL) + return(0); +/* printf("PushElem %s\n", qname); */ + if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) { + xmlValidStatePtr state = ctxt->vstate; + xmlElementPtr elemDecl; + + /* + * Check the new element agaisnt the content model of the new elem. + */ + if (state->elemDecl != NULL) { + elemDecl = state->elemDecl; + + switch(elemDecl->etype) { + case XML_ELEMENT_TYPE_UNDEFINED: + ret = 0; + break; + case XML_ELEMENT_TYPE_EMPTY: + xmlErrValidNode(ctxt, state->node, + XML_DTD_NOT_EMPTY, + "Element %s was declared EMPTY this one has content\n", + state->node->name, NULL, NULL); + ret = 0; + break; + case XML_ELEMENT_TYPE_ANY: + /* I don't think anything is required then */ + break; + case XML_ELEMENT_TYPE_MIXED: + /* simple case of declared as #PCDATA */ + if ((elemDecl->content != NULL) && + (elemDecl->content->type == + XML_ELEMENT_CONTENT_PCDATA)) { + xmlErrValidNode(ctxt, state->node, + XML_DTD_NOT_PCDATA, + "Element %s was declared #PCDATA but contains non text nodes\n", + state->node->name, NULL, NULL); + ret = 0; + } else { + ret = xmlValidateCheckMixed(ctxt, elemDecl->content, + qname); + if (ret != 1) { + xmlErrValidNode(ctxt, state->node, + XML_DTD_INVALID_CHILD, + "Element %s is not declared in %s list of possible children\n", + qname, state->node->name, NULL); + } + } + break; + case XML_ELEMENT_TYPE_ELEMENT: + /* + * TODO: + * VC: Standalone Document Declaration + * - element types with element content, if white space + * occurs directly within any instance of those types. + */ + if (state->exec != NULL) { + ret = xmlRegExecPushString(state->exec, qname, NULL); + if (ret < 0) { + xmlErrValidNode(ctxt, state->node, + XML_DTD_CONTENT_MODEL, + "Element %s content does not follow the DTD, Misplaced %s\n", + state->node->name, qname, NULL); + ret = 0; + } else { + ret = 1; + } + } + break; + } + } + } + eDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset); + vstateVPush(ctxt, eDecl, elem); + return(ret); +} + +/** + * xmlValidatePushCData: + * @ctxt: the validation context + * @data: some character data read + * @len: the lenght of the data + * + * check the CData parsed for validation in the current stack + * + * returns 1 if no validation problem was found or 0 otherwise + */ +int +xmlValidatePushCData(xmlValidCtxtPtr ctxt, const xmlChar *data, int len) { + int ret = 1; + +/* printf("CDATA %s %d\n", data, len); */ + if (ctxt == NULL) + return(0); + if (len <= 0) + return(ret); + if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) { + xmlValidStatePtr state = ctxt->vstate; + xmlElementPtr elemDecl; + + /* + * Check the new element agaisnt the content model of the new elem. + */ + if (state->elemDecl != NULL) { + elemDecl = state->elemDecl; + + switch(elemDecl->etype) { + case XML_ELEMENT_TYPE_UNDEFINED: + ret = 0; + break; + case XML_ELEMENT_TYPE_EMPTY: + xmlErrValidNode(ctxt, state->node, + XML_DTD_NOT_EMPTY, + "Element %s was declared EMPTY this one has content\n", + state->node->name, NULL, NULL); + ret = 0; + break; + case XML_ELEMENT_TYPE_ANY: + break; + case XML_ELEMENT_TYPE_MIXED: + break; + case XML_ELEMENT_TYPE_ELEMENT: + if (len > 0) { + int i; + + for (i = 0;i < len;i++) { + if (!IS_BLANK_CH(data[i])) { + xmlErrValidNode(ctxt, state->node, + XML_DTD_CONTENT_MODEL, + "Element %s content does not follow the DTD, Text not allowed\n", + state->node->name, NULL, NULL); + ret = 0; + goto done; + } + } + /* + * TODO: + * VC: Standalone Document Declaration + * element types with element content, if white space + * occurs directly within any instance of those types. + */ + } + break; + } + } + } +done: + return(ret); +} + +/** + * xmlValidatePopElement: + * @ctxt: the validation context + * @doc: a document instance + * @elem: an element instance + * @qname: the qualified name as appearing in the serialization + * + * Pop the element end from the validation stack. + * + * returns 1 if no validation problem was found or 0 otherwise + */ +int +xmlValidatePopElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc ATTRIBUTE_UNUSED, + xmlNodePtr elem ATTRIBUTE_UNUSED, + const xmlChar *qname ATTRIBUTE_UNUSED) { + int ret = 1; + + if (ctxt == NULL) + return(0); +/* printf("PopElem %s\n", qname); */ + if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) { + xmlValidStatePtr state = ctxt->vstate; + xmlElementPtr elemDecl; + + /* + * Check the new element agaisnt the content model of the new elem. + */ + if (state->elemDecl != NULL) { + elemDecl = state->elemDecl; + + if (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT) { + if (state->exec != NULL) { + ret = xmlRegExecPushString(state->exec, NULL, NULL); + if (ret == 0) { + xmlErrValidNode(ctxt, state->node, + XML_DTD_CONTENT_MODEL, + "Element %s content does not follow the DTD, Expecting more child\n", + state->node->name, NULL,NULL); + } else { + /* + * previous validation errors should not generate + * a new one here + */ + ret = 1; + } + } + } + } + vstateVPop(ctxt); + } + return(ret); +} +#endif /* LIBXML_REGEXP_ENABLED */ + +/** + * xmlValidateOneElement: + * @ctxt: the validation context + * @doc: a document instance + * @elem: an element instance + * + * Try to validate a single element and it's attributes, + * basically it does the following checks as described by the + * XML-1.0 recommendation: + * - [ VC: Element Valid ] + * - [ VC: Required Attribute ] + * Then call xmlValidateOneAttribute() for each attribute present. + * + * The ID/IDREF checkings are done separately + * + * returns 1 if valid or 0 otherwise + */ + +int +xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, + xmlNodePtr elem) { + xmlElementPtr elemDecl = NULL; + xmlElementContentPtr cont; + xmlAttributePtr attr; + xmlNodePtr child; + int ret = 1, tmp; + const xmlChar *name; + int extsubset = 0; + + CHECK_DTD; + + 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: + 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); + return(0); + } + + /* + * Fetch the declaration + */ + elemDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset); + if (elemDecl == NULL) + return(0); + + /* + * If vstateNr is not zero that means continuous validation is + * activated, do not try to check the content model at that level. + */ + if (ctxt->vstateNr == 0) { + /* Check that the element content matches the definition */ + switch (elemDecl->etype) { + case XML_ELEMENT_TYPE_UNDEFINED: + xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ELEM, + "No declaration for element %s\n", + elem->name, NULL, NULL); + return(0); + case XML_ELEMENT_TYPE_EMPTY: + if (elem->children != NULL) { + xmlErrValidNode(ctxt, elem, XML_DTD_NOT_EMPTY, + "Element %s was declared EMPTY this one has content\n", + elem->name, NULL, NULL); + ret = 0; + } + break; + case XML_ELEMENT_TYPE_ANY: + /* I don't think anything is required then */ + break; + case XML_ELEMENT_TYPE_MIXED: + + /* simple case of declared as #PCDATA */ + if ((elemDecl->content != NULL) && + (elemDecl->content->type == XML_ELEMENT_CONTENT_PCDATA)) { + ret = xmlValidateOneCdataElement(ctxt, doc, elem); + if (!ret) { + xmlErrValidNode(ctxt, elem, XML_DTD_NOT_PCDATA, + "Element %s was declared #PCDATA but contains non text nodes\n", + elem->name, NULL, NULL); + } + break; + } + child = elem->children; + /* Hum, this start to get messy */ + while (child != NULL) { + if (child->type == XML_ELEMENT_NODE) { + name = child->name; + if ((child->ns != NULL) && (child->ns->prefix != NULL)) { + xmlChar fn[50]; + xmlChar *fullname; + + fullname = xmlBuildQName(child->name, child->ns->prefix, + fn, 50); + if (fullname == NULL) + return(0); + cont = elemDecl->content; + while (cont != NULL) { + if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) { + if (xmlStrEqual(cont->name, fullname)) + break; + } else if ((cont->type == XML_ELEMENT_CONTENT_OR) && + (cont->c1 != NULL) && + (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){ + if (xmlStrEqual(cont->c1->name, fullname)) + break; + } else if ((cont->type != XML_ELEMENT_CONTENT_OR) || + (cont->c1 == NULL) || + (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){ + xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT, + "Internal: MIXED struct corrupted\n", + NULL); + break; + } + cont = cont->c2; + } + if ((fullname != fn) && (fullname != child->name)) + xmlFree(fullname); + if (cont != NULL) + goto child_ok; + } + cont = elemDecl->content; + while (cont != NULL) { + if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) { + if (xmlStrEqual(cont->name, name)) break; + } else if ((cont->type == XML_ELEMENT_CONTENT_OR) && + (cont->c1 != NULL) && + (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) { + if (xmlStrEqual(cont->c1->name, name)) break; + } else if ((cont->type != XML_ELEMENT_CONTENT_OR) || + (cont->c1 == NULL) || + (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) { + xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT, + "Internal: MIXED struct corrupted\n", + NULL); + break; + } + cont = cont->c2; + } + if (cont == NULL) { + xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_CHILD, + "Element %s is not declared in %s list of possible children\n", + name, elem->name, NULL); + ret = 0; + } + } +child_ok: + child = child->next; + } + break; + case XML_ELEMENT_TYPE_ELEMENT: + if ((doc->standalone == 1) && (extsubset == 1)) { + /* + * VC: Standalone Document Declaration + * - element types with element content, if white space + * occurs directly within any instance of those types. + */ + child = elem->children; + while (child != NULL) { + if (child->type == XML_TEXT_NODE) { + const xmlChar *content = child->content; + + while (IS_BLANK_CH(*content)) + content++; + if (*content == 0) { + xmlErrValidNode(ctxt, elem, + XML_DTD_STANDALONE_WHITE_SPACE, +"standalone: %s declared in the external subset contains white spaces nodes\n", + elem->name, NULL, NULL); + ret = 0; + break; + } + } + child =child->next; + } + } + child = elem->children; + cont = elemDecl->content; + tmp = xmlValidateElementContent(ctxt, child, elemDecl, 1, elem); + if (tmp <= 0) + ret = tmp; + break; + } + } /* not continuous */ + + /* [ VC: Required Attribute ] */ + attr = elemDecl->attributes; + while (attr != NULL) { + if (attr->def == XML_ATTRIBUTE_REQUIRED) { + int qualified = -1; + + if ((attr->prefix == NULL) && + (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) { + xmlNsPtr ns; + + ns = elem->nsDef; + while (ns != NULL) { + if (ns->prefix == NULL) + goto found; + ns = ns->next; + } + } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) { + xmlNsPtr ns; + + ns = elem->nsDef; + while (ns != NULL) { + if (xmlStrEqual(attr->name, ns->prefix)) + goto found; + ns = ns->next; + } + } else { + xmlAttrPtr attrib; + + attrib = elem->properties; + while (attrib != NULL) { + if (xmlStrEqual(attrib->name, attr->name)) { + if (attr->prefix != NULL) { + xmlNsPtr nameSpace = attrib->ns; + + if (nameSpace == NULL) + nameSpace = elem->ns; + /* + * qualified names handling is problematic, having a + * different prefix should be possible but DTDs don't + * allow to define the URI instead of the prefix :-( + */ + if (nameSpace == NULL) { + if (qualified < 0) + qualified = 0; + } else if (!xmlStrEqual(nameSpace->prefix, + attr->prefix)) { + if (qualified < 1) + qualified = 1; + } else + goto found; + } else { + /* + * We should allow applications to define namespaces + * for their application even if the DTD doesn't + * carry one, otherwise, basically we would always + * break. + */ + goto found; + } + } + attrib = attrib->next; + } + } + if (qualified == -1) { + if (attr->prefix == NULL) { + xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE, + "Element %s does not carry attribute %s\n", + elem->name, attr->name, NULL); + ret = 0; + } else { + xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE, + "Element %s does not carry attribute %s:%s\n", + elem->name, attr->prefix,attr->name); + ret = 0; + } + } else if (qualified == 0) { + xmlErrValidWarning(ctxt, elem, XML_DTD_NO_PREFIX, + "Element %s required attribute %s:%s has no prefix\n", + elem->name, attr->prefix, attr->name); + } else if (qualified == 1) { + xmlErrValidWarning(ctxt, elem, XML_DTD_DIFFERENT_PREFIX, + "Element %s required attribute %s:%s has different prefix\n", + elem->name, attr->prefix, attr->name); + } + } else if (attr->def == XML_ATTRIBUTE_FIXED) { + /* + * Special tests checking #FIXED namespace declarations + * have the right value since this is not done as an + * attribute checking + */ + if ((attr->prefix == NULL) && + (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) { + xmlNsPtr ns; + + ns = elem->nsDef; + while (ns != NULL) { + if (ns->prefix == NULL) { + if (!xmlStrEqual(attr->defaultValue, ns->href)) { + xmlErrValidNode(ctxt, elem, + XML_DTD_ELEM_DEFAULT_NAMESPACE, + "Element %s namespace name for default namespace does not match the DTD\n", + elem->name, NULL, NULL); + ret = 0; + } + goto found; + } + ns = ns->next; + } + } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) { + xmlNsPtr ns; + + ns = elem->nsDef; + while (ns != NULL) { + if (xmlStrEqual(attr->name, ns->prefix)) { + if (!xmlStrEqual(attr->defaultValue, ns->href)) { + xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE, + "Element %s namespace name for %s does not match the DTD\n", + elem->name, ns->prefix, NULL); + ret = 0; + } + goto found; + } + ns = ns->next; + } + } + } +found: + attr = attr->nexth; + } + return(ret); +} + +/** + * xmlValidateRoot: + * @ctxt: the validation context + * @doc: a document instance + * + * Try to validate a the root element + * basically it does the following check as described by the + * XML-1.0 recommendation: + * - [ VC: Root Element Type ] + * it doesn't try to recurse or apply other check to the element + * + * returns 1 if valid or 0 otherwise + */ + +int +xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) { + xmlNodePtr root; + int ret; + + if (doc == NULL) return(0); + + root = xmlDocGetRootElement(doc); + if ((root == NULL) || (root->name == NULL)) { + xmlErrValid(ctxt, XML_DTD_NO_ROOT, + "no root element\n", NULL); + return(0); + } + + /* + * When doing post validation against a separate DTD, those may + * no internal subset has been generated + */ + if ((doc->intSubset != NULL) && + (doc->intSubset->name != NULL)) { + /* + * Check first the document root against the NQName + */ + if (!xmlStrEqual(doc->intSubset->name, root->name)) { + if ((root->ns != NULL) && (root->ns->prefix != NULL)) { + xmlChar fn[50]; + xmlChar *fullname; + + fullname = xmlBuildQName(root->name, root->ns->prefix, fn, 50); + if (fullname == NULL) { + xmlVErrMemory(ctxt, NULL); + return(0); + } + ret = xmlStrEqual(doc->intSubset->name, fullname); + if ((fullname != fn) && (fullname != root->name)) + xmlFree(fullname); + if (ret == 1) + goto name_ok; + } + if ((xmlStrEqual(doc->intSubset->name, BAD_CAST "HTML")) && + (xmlStrEqual(root->name, BAD_CAST "html"))) + goto name_ok; + xmlErrValidNode(ctxt, root, XML_DTD_ROOT_NAME, + "root and DTD name do not match '%s' and '%s'\n", + root->name, doc->intSubset->name, NULL); + return(0); + } + } +name_ok: + return(1); +} + + +/** + * xmlValidateElement: + * @ctxt: the validation context + * @doc: a document instance + * @elem: an element instance + * + * Try to validate the subtree under an element + * + * returns 1 if valid or 0 otherwise + */ + +int +xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) { + xmlNodePtr child; + xmlAttrPtr attr; + xmlNsPtr ns; + const xmlChar *value; + int ret = 1; + + if (elem == NULL) return(0); + + /* + * XInclude elements were added after parsing in the infoset, + * they don't really mean anything validation wise. + */ + if ((elem->type == XML_XINCLUDE_START) || + (elem->type == XML_XINCLUDE_END)) + return(1); + + CHECK_DTD; + + /* + * Entities references have to be handled separately + */ + if (elem->type == XML_ENTITY_REF_NODE) { + return(1); + } + + ret &= xmlValidateOneElement(ctxt, doc, elem); + 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) + xmlFree((char *)value); + attr= attr->next; + } + ns = elem->nsDef; + while (ns != NULL) { + if (elem->ns == NULL) + ret &= xmlValidateOneNamespace(ctxt, doc, elem, NULL, + ns, ns->href); + else + ret &= xmlValidateOneNamespace(ctxt, doc, elem, + elem->ns->prefix, ns, ns->href); + ns = ns->next; + } + } + child = elem->children; + while (child != NULL) { + ret &= xmlValidateElement(ctxt, doc, child); + child = child->next; + } + + return(ret); +} + +/** + * xmlValidateRef: + * @ref: A reference to be validated + * @ctxt: Validation context + * @name: Name of ID we are searching for + * + */ +static void +xmlValidateRef(xmlRefPtr ref, xmlValidCtxtPtr ctxt, + const xmlChar *name) { + xmlAttrPtr id; + xmlAttrPtr attr; + + if (ref == NULL) + return; + if ((ref->attr == NULL) && (ref->name == NULL)) + return; + attr = ref->attr; + if (attr == NULL) { + xmlChar *dup, *str = NULL, *cur, save; + + dup = xmlStrdup(name); + if (dup == NULL) { + ctxt->valid = 0; + return; + } + cur = dup; + while (*cur != 0) { + str = cur; + while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++; + save = *cur; + *cur = 0; + id = xmlGetID(ctxt->doc, str); + if (id == NULL) { + xmlErrValidNodeNr(ctxt, NULL, XML_DTD_UNKNOWN_ID, + "attribute %s line %d references an unknown ID \"%s\"\n", + ref->name, ref->lineno, str); + ctxt->valid = 0; + } + if (save == 0) + break; + *cur = save; + while (IS_BLANK_CH(*cur)) cur++; + } + xmlFree(dup); + } else if (attr->atype == XML_ATTRIBUTE_IDREF) { + id = xmlGetID(ctxt->doc, name); + if (id == NULL) { + xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID, + "IDREF attribute %s references an unknown ID \"%s\"\n", + attr->name, name, NULL); + ctxt->valid = 0; + } + } else if (attr->atype == XML_ATTRIBUTE_IDREFS) { + xmlChar *dup, *str = NULL, *cur, save; + + dup = xmlStrdup(name); + if (dup == NULL) { + xmlVErrMemory(ctxt, "IDREFS split"); + ctxt->valid = 0; + return; + } + cur = dup; + while (*cur != 0) { + str = cur; + while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++; + save = *cur; + *cur = 0; + id = xmlGetID(ctxt->doc, str); + if (id == NULL) { + xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID, + "IDREFS attribute %s references an unknown ID \"%s\"\n", + attr->name, str, NULL); + ctxt->valid = 0; + } + if (save == 0) + break; + *cur = save; + while (IS_BLANK_CH(*cur)) cur++; + } + xmlFree(dup); + } +} + +/** + * xmlWalkValidateList: + * @data: Contents of current link + * @user: Value supplied by the user + * + * Returns 0 to abort the walk or 1 to continue + */ +static int +xmlWalkValidateList(const void *data, const void *user) +{ + xmlValidateMemoPtr memo = (xmlValidateMemoPtr)user; + xmlValidateRef((xmlRefPtr)data, memo->ctxt, memo->name); + return 1; +} + +/** + * xmlValidateCheckRefCallback: + * @ref_list: List of references + * @ctxt: Validation context + * @name: Name of ID we are searching for + * + */ +static void +xmlValidateCheckRefCallback(xmlListPtr ref_list, xmlValidCtxtPtr ctxt, + const xmlChar *name) { + xmlValidateMemo memo; + + if (ref_list == NULL) + return; + memo.ctxt = ctxt; + memo.name = name; + + xmlListWalk(ref_list, xmlWalkValidateList, &memo); + +} + +/** + * xmlValidateDocumentFinal: + * @ctxt: the validation context + * @doc: a document instance + * + * Does the final step for the document validation once all the + * incremental validation steps have been completed + * + * basically it does the following checks described by the XML Rec + * + * Check all the IDREF/IDREFS attributes definition for validity + * + * returns 1 if valid or 0 otherwise + */ + +int +xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) { + xmlRefTablePtr table; + unsigned int save; + + if (ctxt == NULL) + return(0); + if (doc == NULL) { + xmlErrValid(ctxt, XML_DTD_NO_DOC, + "xmlValidateDocumentFinal: doc == NULL\n", NULL); + return(0); + } + + /* trick to get correct line id report */ + save = ctxt->finishDtd; + ctxt->finishDtd = 0; + + /* + * Check all the NOTATION/NOTATIONS attributes + */ + /* + * Check all the ENTITY/ENTITIES attributes definition for validity + */ + /* + * Check all the IDREF/IDREFS attributes definition for validity + */ + table = (xmlRefTablePtr) doc->refs; + ctxt->doc = doc; + ctxt->valid = 1; + xmlHashScan(table, (xmlHashScanner) xmlValidateCheckRefCallback, ctxt); + + ctxt->finishDtd = save; + return(ctxt->valid); +} + +/** + * xmlValidateDtd: + * @ctxt: the validation context + * @doc: a document instance + * @dtd: a dtd instance + * + * Try to validate the document against the dtd instance + * + * Basically it does check all the definitions in the DtD. + * Note the the internal subset (if present) is de-coupled + * (i.e. not used), which could give problems if ID or IDREF + * is present. + * + * returns 1 if valid or 0 otherwise + */ + +int +xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) { + int ret; + xmlDtdPtr oldExt, oldInt; + xmlNodePtr root; + + 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; + } + if (doc->refs != NULL) { + xmlFreeRefTable(doc->refs); + doc->refs = NULL; + } + root = xmlDocGetRootElement(doc); + ret = xmlValidateElement(ctxt, doc, root); + ret &= xmlValidateDocumentFinal(ctxt, doc); + doc->extSubset = oldExt; + doc->intSubset = oldInt; + return(ret); +} + +static void +xmlValidateNotationCallback(xmlEntityPtr cur, xmlValidCtxtPtr ctxt, + const xmlChar *name ATTRIBUTE_UNUSED) { + if (cur == NULL) + return; + if (cur->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) { + xmlChar *notation = cur->content; + + if (notation != NULL) { + int ret; + + ret = xmlValidateNotationUse(ctxt, cur->doc, notation); + if (ret != 1) { + ctxt->valid = 0; + } + } + } +} + +static void +xmlValidateAttributeCallback(xmlAttributePtr cur, xmlValidCtxtPtr ctxt, + const xmlChar *name ATTRIBUTE_UNUSED) { + int ret; + xmlDocPtr doc; + xmlElementPtr elem = NULL; + + if (cur == NULL) + return; + switch (cur->atype) { + case XML_ATTRIBUTE_CDATA: + case XML_ATTRIBUTE_ID: + case XML_ATTRIBUTE_IDREF : + case XML_ATTRIBUTE_IDREFS: + case XML_ATTRIBUTE_NMTOKEN: + case XML_ATTRIBUTE_NMTOKENS: + case XML_ATTRIBUTE_ENUMERATION: + break; + case XML_ATTRIBUTE_ENTITY: + case XML_ATTRIBUTE_ENTITIES: + case XML_ATTRIBUTE_NOTATION: + if (cur->defaultValue != NULL) { + + ret = xmlValidateAttributeValue2(ctxt, ctxt->doc, cur->name, + cur->atype, cur->defaultValue); + if ((ret == 0) && (ctxt->valid == 1)) + ctxt->valid = 0; + } + if (cur->tree != NULL) { + xmlEnumerationPtr tree = cur->tree; + while (tree != NULL) { + ret = xmlValidateAttributeValue2(ctxt, ctxt->doc, + cur->name, cur->atype, tree->name); + if ((ret == 0) && (ctxt->valid == 1)) + ctxt->valid = 0; + tree = tree->next; + } + } + } + if (cur->atype == XML_ATTRIBUTE_NOTATION) { + doc = cur->doc; + if (cur->elem == NULL) { + xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, + "xmlValidateAttributeCallback(%s): internal error\n", + (const char *) cur->name); + return; + } + + if (doc != NULL) + elem = xmlGetDtdElementDesc(doc->intSubset, cur->elem); + if ((elem == NULL) && (doc != NULL)) + elem = xmlGetDtdElementDesc(doc->extSubset, cur->elem); + if ((elem == NULL) && (cur->parent != NULL) && + (cur->parent->type == XML_DTD_NODE)) + elem = xmlGetDtdElementDesc((xmlDtdPtr) cur->parent, cur->elem); + if (elem == NULL) { + xmlErrValidNode(ctxt, NULL, XML_DTD_UNKNOWN_ELEM, + "attribute %s: could not find decl for element %s\n", + cur->name, cur->elem, NULL); + return; + } + if (elem->etype == XML_ELEMENT_TYPE_EMPTY) { + xmlErrValidNode(ctxt, NULL, XML_DTD_EMPTY_NOTATION, + "NOTATION attribute %s declared for EMPTY element %s\n", + cur->name, cur->elem, NULL); + ctxt->valid = 0; + } + } +} + +/** + * xmlValidateDtdFinal: + * @ctxt: the validation context + * @doc: a document instance + * + * Does the final step for the dtds validation once all the + * subsets have been parsed + * + * basically it does the following checks described by the XML Rec + * - check that ENTITY and ENTITIES type attributes default or + * possible values matches one of the defined entities. + * - check that NOTATION type attributes default or + * possible values matches one of the defined notations. + * + * returns 1 if valid or 0 if invalid and -1 if not well-formed + */ + +int +xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) { + xmlDtdPtr dtd; + xmlAttributeTablePtr table; + xmlEntitiesTablePtr entities; + + if ((doc == NULL) || (ctxt == NULL)) return(0); + if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) + return(0); + ctxt->doc = doc; + ctxt->valid = 1; + dtd = doc->intSubset; + if ((dtd != NULL) && (dtd->attributes != NULL)) { + table = (xmlAttributeTablePtr) dtd->attributes; + xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt); + } + if ((dtd != NULL) && (dtd->entities != NULL)) { + entities = (xmlEntitiesTablePtr) dtd->entities; + xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback, + ctxt); + } + dtd = doc->extSubset; + if ((dtd != NULL) && (dtd->attributes != NULL)) { + table = (xmlAttributeTablePtr) dtd->attributes; + xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt); + } + if ((dtd != NULL) && (dtd->entities != NULL)) { + entities = (xmlEntitiesTablePtr) dtd->entities; + xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback, + ctxt); + } + return(ctxt->valid); +} + +/** + * xmlValidateDocument: + * @ctxt: the validation context + * @doc: a document instance + * + * Try to validate the document instance + * + * basically it does the all the checks described by the XML Rec + * i.e. validates the internal and external subset (if present) + * and validate the document tree. + * + * returns 1 if valid or 0 otherwise + */ + +int +xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) { + int ret; + xmlNodePtr root; + + if (doc == NULL) + return(0); + if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) { + xmlErrValid(ctxt, XML_DTD_NO_DTD, + "no DTD found!\n", NULL); + return(0); + } + if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) || + (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) { + xmlChar *sysID; + if (doc->intSubset->SystemID != NULL) { + sysID = xmlBuildURI(doc->intSubset->SystemID, + doc->URL); + if (sysID == NULL) { + xmlErrValid(ctxt, XML_DTD_LOAD_ERROR, + "Could not build URI for external subset \"%s\"\n", + (const char *) doc->intSubset->SystemID); + return 0; + } + } else + sysID = NULL; + doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID, + (const xmlChar *)sysID); + if (sysID != NULL) + xmlFree(sysID); + if (doc->extSubset == NULL) { + if (doc->intSubset->SystemID != NULL) { + xmlErrValid(ctxt, XML_DTD_LOAD_ERROR, + "Could not load the external subset \"%s\"\n", + (const char *) doc->intSubset->SystemID); + } else { + xmlErrValid(ctxt, XML_DTD_LOAD_ERROR, + "Could not load the external subset \"%s\"\n", + (const char *) doc->intSubset->ExternalID); + } + return(0); + } + } + + if (doc->ids != NULL) { + xmlFreeIDTable(doc->ids); + doc->ids = NULL; + } + if (doc->refs != NULL) { + xmlFreeRefTable(doc->refs); + doc->refs = NULL; + } + ret = xmlValidateDtdFinal(ctxt, doc); + if (!xmlValidateRoot(ctxt, doc)) return(0); + + root = xmlDocGetRootElement(doc); + ret &= xmlValidateElement(ctxt, doc, root); + ret &= xmlValidateDocumentFinal(ctxt, doc); + return(ret); +} + +/************************************************************************ + * * + * Routines for dynamic validation editing * + * * + ************************************************************************/ + +/** + * xmlValidGetPotentialChildren: + * @ctree: an element content tree + * @names: an array to store the list of child names + * @len: a pointer to the number of element in the list + * @max: the size of the array + * + * Build/extend a list of potential children allowed by the content tree + * + * returns the number of element in the list, or -1 in case of error. + */ + +int +xmlValidGetPotentialChildren(xmlElementContent *ctree, + const xmlChar **names, + int *len, int max) { + int i; + + if ((ctree == NULL) || (names == NULL) || (len == NULL)) + return(-1); + if (*len >= max) return(*len); + + switch (ctree->type) { + case XML_ELEMENT_CONTENT_PCDATA: + for (i = 0; i < *len;i++) + if (xmlStrEqual(BAD_CAST "#PCDATA", names[i])) return(*len); + names[(*len)++] = BAD_CAST "#PCDATA"; + break; + case XML_ELEMENT_CONTENT_ELEMENT: + for (i = 0; i < *len;i++) + if (xmlStrEqual(ctree->name, names[i])) return(*len); + names[(*len)++] = ctree->name; + break; + case XML_ELEMENT_CONTENT_SEQ: + xmlValidGetPotentialChildren(ctree->c1, names, len, max); + xmlValidGetPotentialChildren(ctree->c2, names, len, max); + break; + case XML_ELEMENT_CONTENT_OR: + xmlValidGetPotentialChildren(ctree->c1, names, len, max); + xmlValidGetPotentialChildren(ctree->c2, names, len, max); + break; + } + + return(*len); +} + +/* + * Dummy function to suppress messages while we try out valid elements + */ +static void XMLCDECL xmlNoValidityErr(void *ctx ATTRIBUTE_UNUSED, + const char *msg ATTRIBUTE_UNUSED, ...) { + return; +} + +/** + * xmlValidGetValidElements: + * @prev: an element to insert after + * @next: an element to insert next + * @names: an array to store the list of child names + * @max: the size of the array + * + * This function returns the list of authorized children to insert + * within an existing tree while respecting the validity constraints + * forced by the Dtd. The insertion point is defined using @prev and + * @next in the following ways: + * to insert before 'node': xmlValidGetValidElements(node->prev, node, ... + * to insert next 'node': xmlValidGetValidElements(node, node->next, ... + * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ... + * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs, + * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ... + * + * pointers to the element names are inserted at the beginning of the array + * and do not need to be freed. + * + * returns the number of element in the list, or -1 in case of error. If + * the function returns the value @max the caller is invited to grow the + * receiving array and retry. + */ + +int +xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **names, + int max) { + xmlValidCtxt vctxt; + int nb_valid_elements = 0; + const xmlChar *elements[256]; + int nb_elements = 0, i; + const xmlChar *name; + + xmlNode *ref_node; + xmlNode *parent; + xmlNode *test_node; + + xmlNode *prev_next; + xmlNode *next_prev; + xmlNode *parent_childs; + xmlNode *parent_last; + + xmlElement *element_desc; + + if (prev == NULL && next == NULL) + return(-1); + + if (names == NULL) return(-1); + if (max <= 0) return(-1); + + memset(&vctxt, 0, sizeof (xmlValidCtxt)); + vctxt.error = xmlNoValidityErr; /* this suppresses err/warn output */ + + nb_valid_elements = 0; + ref_node = prev ? prev : next; + parent = ref_node->parent; + + /* + * Retrieves the parent element declaration + */ + element_desc = xmlGetDtdElementDesc(parent->doc->intSubset, + parent->name); + if ((element_desc == NULL) && (parent->doc->extSubset != NULL)) + element_desc = xmlGetDtdElementDesc(parent->doc->extSubset, + parent->name); + if (element_desc == NULL) return(-1); + + /* + * Do a backup of the current tree structure + */ + prev_next = prev ? prev->next : NULL; + next_prev = next ? next->prev : NULL; + parent_childs = parent->children; + parent_last = parent->last; + + /* + * Creates a dummy node and insert it into the tree + */ + test_node = xmlNewDocNode (ref_node->doc, NULL, BAD_CAST "", NULL); + test_node->parent = parent; + test_node->prev = prev; + test_node->next = next; + name = test_node->name; + + if (prev) prev->next = test_node; + else parent->children = test_node; + + if (next) next->prev = test_node; + else parent->last = test_node; + + /* + * Insert each potential child node and check if the parent is + * still valid + */ + nb_elements = xmlValidGetPotentialChildren(element_desc->content, + elements, &nb_elements, 256); + + for (i = 0;i < nb_elements;i++) { + test_node->name = elements[i]; + if (xmlValidateOneElement(&vctxt, parent->doc, parent)) { + int j; + + for (j = 0; j < nb_valid_elements;j++) + if (xmlStrEqual(elements[i], names[j])) break; + names[nb_valid_elements++] = elements[i]; + if (nb_valid_elements >= max) break; + } + } + + /* + * Restore the tree structure + */ + if (prev) prev->next = prev_next; + if (next) next->prev = next_prev; + parent->children = parent_childs; + parent->last = parent_last; + + /* + * Free up the dummy node + */ + test_node->name = name; + xmlFreeNode(test_node); + + return(nb_valid_elements); +} +#endif /* LIBXML_VALID_ENABLED */ + +#define bottom_valid +#include "elfgcchack.h" diff --git a/android/native/libxml2/xinclude.c b/android/native/libxml2/xinclude.c new file mode 100644 index 0000000000..2916ffaab1 --- /dev/null +++ b/android/native/libxml2/xinclude.c @@ -0,0 +1,2591 @@ +/* + * xinclude.c : Code to implement XInclude processing + * + * World Wide Web Consortium W3C Last Call Working Draft 10 November 2003 + * http://www.w3.org/TR/2003/WD-xinclude-20031110 + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + */ + +#define IN_LIBXML +#include "libxml.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef LIBXML_XINCLUDE_ENABLED +#include + + +#define XINCLUDE_MAX_DEPTH 40 + +/* #define DEBUG_XINCLUDE */ +#ifdef DEBUG_XINCLUDE +#ifdef LIBXML_DEBUG_ENABLED +#include +#endif +#endif + +/************************************************************************ + * * + * XInclude context handling * + * * + ************************************************************************/ + +/* + * An XInclude context + */ +typedef xmlChar *xmlURL; + +typedef struct _xmlXIncludeRef xmlXIncludeRef; +typedef xmlXIncludeRef *xmlXIncludeRefPtr; +struct _xmlXIncludeRef { + xmlChar *URI; /* the fully resolved resource URL */ + xmlChar *fragment; /* the fragment in the URI */ + xmlDocPtr doc; /* the parsed document */ + xmlNodePtr ref; /* the node making the reference in the source */ + xmlNodePtr inc; /* the included copy */ + int xml; /* xml or txt */ + int count; /* how many refs use that specific doc */ + xmlXPathObjectPtr xptr; /* the xpointer if needed */ + int emptyFb; /* flag to show fallback empty */ +}; + +struct _xmlXIncludeCtxt { + xmlDocPtr doc; /* the source document */ + int incBase; /* the first include for this document */ + int incNr; /* number of includes */ + int incMax; /* size of includes tab */ + xmlXIncludeRefPtr *incTab; /* array of included references */ + + int txtNr; /* number of unparsed documents */ + int txtMax; /* size of unparsed documents tab */ + xmlNodePtr *txtTab; /* array of unparsed text nodes */ + xmlURL *txturlTab; /* array of unparsed text URLs */ + + xmlChar * url; /* the current URL processed */ + int urlNr; /* number of URLs stacked */ + int urlMax; /* size of URL stack */ + xmlChar * *urlTab; /* URL stack */ + + int nbErrors; /* the number of errors detected */ + 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 */ +}; + +static int +xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree); + + +/************************************************************************ + * * + * XInclude error handler * + * * + ************************************************************************/ + +/** + * xmlXIncludeErrMemory: + * @extra: extra information + * + * Handle an out of memory condition + */ +static void +xmlXIncludeErrMemory(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node, + const char *extra) +{ + 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); +} + +/** + * xmlXIncludeErr: + * @ctxt: the XInclude context + * @node: the context node + * @msg: the error message + * @extra: extra information + * + * Handle an XInclude error + */ +static void +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); +} + +#if 0 +/** + * xmlXIncludeWarn: + * @ctxt: the XInclude context + * @node: the context node + * @msg: the error message + * @extra: extra information + * + * Emit an XInclude warning. + */ +static void +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); +} +#endif + +/** + * xmlXIncludeGetProp: + * @ctxt: the XInclude context + * @cur: the node + * @name: the attribute name + * + * Get an XInclude attribute + * + * Returns the value (to be freed) or NULL if not found + */ +static xmlChar * +xmlXIncludeGetProp(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur, + const xmlChar *name) { + xmlChar *ret; + + ret = xmlGetNsProp(cur, XINCLUDE_NS, name); + if (ret != NULL) + return(ret); + if (ctxt->legacy != 0) { + ret = xmlGetNsProp(cur, XINCLUDE_OLD_NS, name); + if (ret != NULL) + return(ret); + } + ret = xmlGetProp(cur, name); + return(ret); +} +/** + * xmlXIncludeFreeRef: + * @ref: the XInclude reference + * + * Free an XInclude reference + */ +static void +xmlXIncludeFreeRef(xmlXIncludeRefPtr ref) { + if (ref == NULL) + return; +#ifdef DEBUG_XINCLUDE + xmlGenericError(xmlGenericErrorContext, "Freeing ref\n"); +#endif + if (ref->doc != NULL) { +#ifdef DEBUG_XINCLUDE + xmlGenericError(xmlGenericErrorContext, "Freeing doc %s\n", ref->URI); +#endif + xmlFreeDoc(ref->doc); + } + if (ref->URI != NULL) + xmlFree(ref->URI); + if (ref->fragment != NULL) + xmlFree(ref->fragment); + if (ref->xptr != NULL) + xmlXPathFreeObject(ref->xptr); + xmlFree(ref); +} + +/** + * xmlXIncludeNewRef: + * @ctxt: the XInclude context + * @URI: the resource URI + * + * Creates a new reference within an XInclude context + * + * Returns the new set + */ +static xmlXIncludeRefPtr +xmlXIncludeNewRef(xmlXIncludeCtxtPtr ctxt, const xmlChar *URI, + xmlNodePtr ref) { + xmlXIncludeRefPtr ret; + +#ifdef DEBUG_XINCLUDE + xmlGenericError(xmlGenericErrorContext, "New ref %s\n", URI); +#endif + ret = (xmlXIncludeRefPtr) xmlMalloc(sizeof(xmlXIncludeRef)); + if (ret == NULL) { + xmlXIncludeErrMemory(ctxt, ref, "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->ref = ref; + ret->doc = NULL; + ret->count = 0; + ret->xml = 0; + ret->inc = NULL; + if (ctxt->incMax == 0) { + ctxt->incMax = 4; + ctxt->incTab = (xmlXIncludeRefPtr *) xmlMalloc(ctxt->incMax * + sizeof(ctxt->incTab[0])); + if (ctxt->incTab == NULL) { + xmlXIncludeErrMemory(ctxt, ref, "growing XInclude context"); + xmlXIncludeFreeRef(ret); + return(NULL); + } + } + if (ctxt->incNr >= ctxt->incMax) { + ctxt->incMax *= 2; + ctxt->incTab = (xmlXIncludeRefPtr *) xmlRealloc(ctxt->incTab, + ctxt->incMax * sizeof(ctxt->incTab[0])); + if (ctxt->incTab == NULL) { + xmlXIncludeErrMemory(ctxt, ref, "growing XInclude context"); + xmlXIncludeFreeRef(ret); + return(NULL); + } + } + ctxt->incTab[ctxt->incNr++] = ret; + return(ret); +} + +/** + * xmlXIncludeNewContext: + * @doc: an XML Document + * + * Creates a new XInclude context + * + * Returns the new set + */ +xmlXIncludeCtxtPtr +xmlXIncludeNewContext(xmlDocPtr doc) { + xmlXIncludeCtxtPtr ret; + +#ifdef DEBUG_XINCLUDE + xmlGenericError(xmlGenericErrorContext, "New context\n"); +#endif + if (doc == NULL) + return(NULL); + ret = (xmlXIncludeCtxtPtr) xmlMalloc(sizeof(xmlXIncludeCtxt)); + if (ret == NULL) { + xmlXIncludeErrMemory(NULL, (xmlNodePtr) doc, + "creating XInclude context"); + return(NULL); + } + memset(ret, 0, sizeof(xmlXIncludeCtxt)); + ret->doc = doc; + ret->incNr = 0; + ret->incBase = 0; + ret->incMax = 0; + ret->incTab = NULL; + ret->nbErrors = 0; + return(ret); +} + +/** + * xmlXIncludeURLPush: + * @ctxt: the parser context + * @value: the url + * + * Pushes a new url on top of the url stack + * + * Returns -1 in case of error, the index in the stack otherwise + */ +static int +xmlXIncludeURLPush(xmlXIncludeCtxtPtr ctxt, + const xmlChar *value) +{ + if (ctxt->urlNr > XINCLUDE_MAX_DEPTH) { + xmlXIncludeErr(ctxt, NULL, XML_XINCLUDE_RECURSION, + "detected a recursion in %s\n", value); + return(-1); + } + if (ctxt->urlTab == NULL) { + ctxt->urlMax = 4; + ctxt->urlNr = 0; + ctxt->urlTab = (xmlChar * *) xmlMalloc( + ctxt->urlMax * sizeof(ctxt->urlTab[0])); + if (ctxt->urlTab == NULL) { + xmlXIncludeErrMemory(ctxt, NULL, "adding URL"); + return (-1); + } + } + if (ctxt->urlNr >= ctxt->urlMax) { + ctxt->urlMax *= 2; + ctxt->urlTab = + (xmlChar * *) xmlRealloc(ctxt->urlTab, + ctxt->urlMax * + sizeof(ctxt->urlTab[0])); + if (ctxt->urlTab == NULL) { + xmlXIncludeErrMemory(ctxt, NULL, "adding URL"); + return (-1); + } + } + ctxt->url = ctxt->urlTab[ctxt->urlNr] = xmlStrdup(value); + return (ctxt->urlNr++); +} + +/** + * xmlXIncludeURLPop: + * @ctxt: the parser context + * + * Pops the top URL from the URL stack + */ +static void +xmlXIncludeURLPop(xmlXIncludeCtxtPtr ctxt) +{ + xmlChar * ret; + + if (ctxt->urlNr <= 0) + return; + ctxt->urlNr--; + if (ctxt->urlNr > 0) + ctxt->url = ctxt->urlTab[ctxt->urlNr - 1]; + else + ctxt->url = NULL; + ret = ctxt->urlTab[ctxt->urlNr]; + ctxt->urlTab[ctxt->urlNr] = NULL; + if (ret != NULL) + xmlFree(ret); +} + +/** + * xmlXIncludeFreeContext: + * @ctxt: the XInclude context + * + * Free an XInclude context + */ +void +xmlXIncludeFreeContext(xmlXIncludeCtxtPtr ctxt) { + int i; + +#ifdef DEBUG_XINCLUDE + xmlGenericError(xmlGenericErrorContext, "Freeing context\n"); +#endif + if (ctxt == NULL) + return; + while (ctxt->urlNr > 0) + xmlXIncludeURLPop(ctxt); + if (ctxt->urlTab != NULL) + xmlFree(ctxt->urlTab); + for (i = 0;i < ctxt->incNr;i++) { + if (ctxt->incTab[i] != NULL) + xmlXIncludeFreeRef(ctxt->incTab[i]); + } + if (ctxt->txturlTab != NULL) { + for (i = 0;i < ctxt->txtNr;i++) { + if (ctxt->txturlTab[i] != NULL) + xmlFree(ctxt->txturlTab[i]); + } + } + if (ctxt->incTab != NULL) + xmlFree(ctxt->incTab); + if (ctxt->txtTab != NULL) + xmlFree(ctxt->txtTab); + if (ctxt->txturlTab != NULL) + xmlFree(ctxt->txturlTab); + if (ctxt->base != NULL) { + xmlFree(ctxt->base); + } + xmlFree(ctxt); +} + +/** + * xmlXIncludeParseFile: + * @ctxt: the XInclude context + * @URL: the URL or file path + * + * parse a document for XInclude + */ +static xmlDocPtr +xmlXIncludeParseFile(xmlXIncludeCtxtPtr ctxt, const char *URL) { + xmlDocPtr ret; + xmlParserCtxtPtr pctxt; + xmlParserInputPtr inputStream; + + xmlInitParser(); + + pctxt = xmlNewParserCtxt(); + if (pctxt == NULL) { + xmlXIncludeErrMemory(ctxt, NULL, "cannot allocate parser context"); + return(NULL); + } + + /* + * pass in the application data to the parser context. + */ + pctxt->_private = ctxt->_private; + + /* + * try to ensure that new documents included are actually + * built with the same dictionary as the including document. + */ + if ((ctxt->doc != NULL) && (ctxt->doc->dict != NULL)) { + if (pctxt->dict != NULL) + xmlDictFree(pctxt->dict); + pctxt->dict = ctxt->doc->dict; + xmlDictReference(pctxt->dict); + } + + xmlCtxtUseOptions(pctxt, ctxt->parseFlags | XML_PARSE_DTDLOAD); + + inputStream = xmlLoadExternalEntity(URL, NULL, pctxt); + if (inputStream == NULL) { + xmlFreeParserCtxt(pctxt); + return(NULL); + } + + inputPush(pctxt, inputStream); + + if (pctxt->directory == NULL) + pctxt->directory = xmlParserGetDirectory(URL); + + pctxt->loadsubset |= XML_DETECT_IDS; + + xmlParseDocument(pctxt); + + if (pctxt->wellFormed) { + ret = pctxt->myDoc; + } + else { + ret = NULL; + if (pctxt->myDoc != NULL) + xmlFreeDoc(pctxt->myDoc); + pctxt->myDoc = NULL; + } + xmlFreeParserCtxt(pctxt); + + return(ret); +} + +/** + * xmlXIncludeAddNode: + * @ctxt: the XInclude context + * @cur: the new node + * + * Add a new node to process to an XInclude context + */ +static int +xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur) { + xmlXIncludeRefPtr ref; + xmlURIPtr uri; + xmlChar *URL; + xmlChar *fragment = NULL; + xmlChar *href; + xmlChar *parse; + xmlChar *base; + xmlChar *URI; + int xml = 1, i; /* default Issue 64 */ + int local = 0; + + + if (ctxt == NULL) + return(-1); + if (cur == NULL) + return(-1); + +#ifdef DEBUG_XINCLUDE + xmlGenericError(xmlGenericErrorContext, "Add node\n"); +#endif + /* + * 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); + } + if ((href[0] == '#') || (href[0] == 0)) + local = 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 (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(-1); + } + fragment = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE_XPOINTER); + + /* + * Check the URL and remove any fragment identifier + */ + uri = xmlParseURI((const char *)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(-1); + } + + if (uri->fragment != NULL) { + if (ctxt->legacy != 0) { + if (fragment == NULL) { + fragment = (xmlChar *) uri->fragment; + } else { + xmlFree(uri->fragment); + } + } 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(-1); + } + uri->fragment = NULL; + } + URL = xmlSaveUri(uri); + xmlFreeURI(uri); + xmlFree(URI); + if (URL == NULL) { + xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI, + "invalid value URI %s\n", URI); + if (fragment != NULL) + xmlFree(fragment); + return(-1); + } + + /* + * If local and xml then we need a fragment + */ + if ((local == 1) && (xml == 1) && + ((fragment == NULL) || (fragment[0] == 0))) { + xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_RECURSION, + "detected a local recursion with no xpointer in %s\n", + URL); + if (fragment != NULL) + xmlFree(fragment); + return(-1); + } + + /* + * Check the URL against the stack for recursions + */ + if ((!local) && (xml == 1)) { + for (i = 0;i < ctxt->urlNr;i++) { + if (xmlStrEqual(URL, ctxt->urlTab[i])) { + xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_RECURSION, + "detected a recursion in %s\n", URL); + return(-1); + } + } + } + + ref = xmlXIncludeNewRef(ctxt, URL, cur); + if (ref == NULL) { + return(-1); + } + ref->fragment = fragment; + ref->doc = NULL; + ref->xml = xml; + ref->count = 1; + xmlFree(URL); + return(0); +} + +/** + * xmlXIncludeRecurseDoc: + * @ctxt: the XInclude context + * @doc: the new document + * @url: the associated URL + * + * The XInclude recursive nature is handled at this point. + */ +static void +xmlXIncludeRecurseDoc(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, + const xmlURL url ATTRIBUTE_UNUSED) { + xmlXIncludeCtxtPtr newctxt; + int i; + + /* + * Avoid recursion in already substitued resources + for (i = 0;i < ctxt->urlNr;i++) { + if (xmlStrEqual(doc->URL, ctxt->urlTab[i])) + return; + } + */ + +#ifdef DEBUG_XINCLUDE + xmlGenericError(xmlGenericErrorContext, "Recursing in doc %s\n", doc->URL); +#endif + /* + * Handle recursion here. + */ + + newctxt = xmlXIncludeNewContext(doc); + if (newctxt != NULL) { + /* + * Copy the private user data + */ + newctxt->_private = ctxt->_private; + /* + * Copy the existing document set + */ + newctxt->incMax = ctxt->incMax; + newctxt->incNr = ctxt->incNr; + newctxt->incTab = (xmlXIncludeRefPtr *) xmlMalloc(newctxt->incMax * + sizeof(newctxt->incTab[0])); + if (newctxt->incTab == NULL) { + xmlXIncludeErrMemory(ctxt, (xmlNodePtr) doc, "processing doc"); + xmlFree(newctxt); + return; + } + /* + * copy the urlTab + */ + newctxt->urlMax = ctxt->urlMax; + newctxt->urlNr = ctxt->urlNr; + newctxt->urlTab = ctxt->urlTab; + + /* + * Inherit the existing base + */ + newctxt->base = xmlStrdup(ctxt->base); + + /* + * Inherit the documents already in use by other includes + */ + newctxt->incBase = ctxt->incNr; + for (i = 0;i < ctxt->incNr;i++) { + newctxt->incTab[i] = ctxt->incTab[i]; + newctxt->incTab[i]->count++; /* prevent the recursion from + freeing it */ + } + /* + * The new context should also inherit the Parse Flags + * (bug 132597) + */ + newctxt->parseFlags = ctxt->parseFlags; + xmlXIncludeDoProcess(newctxt, doc, xmlDocGetRootElement(doc)); + for (i = 0;i < ctxt->incNr;i++) { + newctxt->incTab[i]->count--; + newctxt->incTab[i] = NULL; + } + + /* urlTab may have been reallocated */ + ctxt->urlTab = newctxt->urlTab; + ctxt->urlMax = newctxt->urlMax; + + newctxt->urlMax = 0; + newctxt->urlNr = 0; + newctxt->urlTab = NULL; + + xmlXIncludeFreeContext(newctxt); + } +#ifdef DEBUG_XINCLUDE + xmlGenericError(xmlGenericErrorContext, "Done recursing in doc %s\n", url); +#endif +} + +/** + * xmlXIncludeAddTxt: + * @ctxt: the XInclude context + * @txt: the new text node + * @url: the associated URL + * + * Add a new txtument to the list + */ +static void +xmlXIncludeAddTxt(xmlXIncludeCtxtPtr ctxt, xmlNodePtr txt, const xmlURL url) { +#ifdef DEBUG_XINCLUDE + xmlGenericError(xmlGenericErrorContext, "Adding text %s\n", url); +#endif + if (ctxt->txtMax == 0) { + ctxt->txtMax = 4; + ctxt->txtTab = (xmlNodePtr *) xmlMalloc(ctxt->txtMax * + sizeof(ctxt->txtTab[0])); + if (ctxt->txtTab == NULL) { + xmlXIncludeErrMemory(ctxt, NULL, "processing text"); + return; + } + ctxt->txturlTab = (xmlURL *) xmlMalloc(ctxt->txtMax * + sizeof(ctxt->txturlTab[0])); + if (ctxt->txturlTab == NULL) { + xmlXIncludeErrMemory(ctxt, NULL, "processing text"); + return; + } + } + if (ctxt->txtNr >= ctxt->txtMax) { + ctxt->txtMax *= 2; + ctxt->txtTab = (xmlNodePtr *) xmlRealloc(ctxt->txtTab, + ctxt->txtMax * sizeof(ctxt->txtTab[0])); + if (ctxt->txtTab == NULL) { + xmlXIncludeErrMemory(ctxt, NULL, "processing text"); + return; + } + ctxt->txturlTab = (xmlURL *) xmlRealloc(ctxt->txturlTab, + ctxt->txtMax * sizeof(ctxt->txturlTab[0])); + if (ctxt->txturlTab == NULL) { + xmlXIncludeErrMemory(ctxt, NULL, "processing text"); + return; + } + } + ctxt->txtTab[ctxt->txtNr] = txt; + ctxt->txturlTab[ctxt->txtNr] = xmlStrdup(url); + ctxt->txtNr++; +} + +/************************************************************************ + * * + * Node copy with specific semantic * + * * + ************************************************************************/ + +static xmlNodePtr +xmlXIncludeCopyNodeList(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target, + xmlDocPtr source, xmlNodePtr elem); + +/** + * xmlXIncludeCopyNode: + * @ctxt: the XInclude context + * @target: the document target + * @source: the document source + * @elem: the element + * + * Make a copy of the node while preserving the XInclude semantic + * of the Infoset copy + */ +static xmlNodePtr +xmlXIncludeCopyNode(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target, + xmlDocPtr source, xmlNodePtr elem) { + xmlNodePtr result = NULL; + + if ((ctxt == NULL) || (target == NULL) || (source == NULL) || + (elem == NULL)) + return(NULL); + if (elem->type == XML_DTD_NODE) + return(NULL); + if (elem->type == XML_DOCUMENT_NODE) + result = xmlXIncludeCopyNodeList(ctxt, target, source, elem->children); + else + result = xmlDocCopyNode(elem, target, 1); + return(result); +} + +/** + * xmlXIncludeCopyNodeList: + * @ctxt: the XInclude context + * @target: the document target + * @source: the document source + * @elem: the element list + * + * Make a copy of the node list while preserving the XInclude semantic + * of the Infoset copy + */ +static xmlNodePtr +xmlXIncludeCopyNodeList(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target, + xmlDocPtr source, xmlNodePtr elem) { + xmlNodePtr cur, res, result = NULL, last = NULL; + + if ((ctxt == NULL) || (target == NULL) || (source == NULL) || + (elem == NULL)) + return(NULL); + cur = elem; + while (cur != NULL) { + res = xmlXIncludeCopyNode(ctxt, target, source, cur); + if (res != NULL) { + if (result == NULL) { + result = last = res; + } else { + last->next = res; + res->prev = last; + last = res; + } + } + cur = cur->next; + } + return(result); +} + +/** + * xmlXIncludeGetNthChild: + * @cur: the node + * @no: the child number + * + * Returns the @n'th element child of @cur or NULL + */ +static xmlNodePtr +xmlXIncludeGetNthChild(xmlNodePtr cur, int no) { + int i; + if (cur == NULL) + return(cur); + cur = cur->children; + for (i = 0;i <= no;cur = cur->next) { + if (cur == NULL) + return(cur); + if ((cur->type == XML_ELEMENT_NODE) || + (cur->type == XML_DOCUMENT_NODE) || + (cur->type == XML_HTML_DOCUMENT_NODE)) { + i++; + if (i == no) + break; + } + } + return(cur); +} + +xmlNodePtr xmlXPtrAdvanceNode(xmlNodePtr cur, int *level); /* in xpointer.c */ +/** + * xmlXIncludeCopyRange: + * @ctxt: the XInclude context + * @target: the document target + * @source: the document source + * @obj: the XPointer result from the evaluation. + * + * Build a node list tree copy of the XPointer result. + * + * Returns an xmlNodePtr list or NULL. + * The caller has to free the node tree. + */ +static xmlNodePtr +xmlXIncludeCopyRange(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target, + xmlDocPtr source, xmlXPathObjectPtr range) { + /* pointers to generated nodes */ + xmlNodePtr list = NULL, last = NULL, listParent = NULL; + xmlNodePtr tmp, tmp2; + /* pointers to traversal nodes */ + xmlNodePtr start, cur, end; + int index1, index2; + int level = 0, lastLevel = 0, endLevel = 0, endFlag = 0; + + if ((ctxt == NULL) || (target == NULL) || (source == NULL) || + (range == NULL)) + return(NULL); + if (range->type != XPATH_RANGE) + return(NULL); + start = (xmlNodePtr) range->user; + + if (start == NULL) + return(NULL); + end = range->user2; + if (end == NULL) + return(xmlDocCopyNode(start, target, 1)); + + cur = start; + index1 = range->index; + index2 = range->index2; + /* + * level is depth of the current node under consideration + * list is the pointer to the root of the output tree + * listParent is a pointer to the parent of output tree (within + the included file) in case we need to add another level + * last is a pointer to the last node added to the output tree + * lastLevel is the depth of last (relative to the root) + */ + while (cur != NULL) { + /* + * Check if our output tree needs a parent + */ + if (level < 0) { + while (level < 0) { + /* copy must include namespaces and properties */ + tmp2 = xmlDocCopyNode(listParent, target, 2); + xmlAddChild(tmp2, list); + list = tmp2; + listParent = listParent->parent; + level++; + } + last = list; + lastLevel = 0; + } + /* + * Check whether we need to change our insertion point + */ + while (level < lastLevel) { + last = last->parent; + lastLevel --; + } + if (cur == end) { /* Are we at the end of the range? */ + if (cur->type == XML_TEXT_NODE) { + const xmlChar *content = cur->content; + int len; + + if (content == NULL) { + tmp = xmlNewTextLen(NULL, 0); + } else { + len = index2; + if ((cur == start) && (index1 > 1)) { + content += (index1 - 1); + len -= (index1 - 1); + } else { + len = index2; + } + tmp = xmlNewTextLen(content, len); + } + /* single sub text node selection */ + if (list == NULL) + return(tmp); + /* prune and return full set */ + if (level == lastLevel) + xmlAddNextSibling(last, tmp); + else + xmlAddChild(last, tmp); + return(list); + } else { /* ending node not a text node */ + endLevel = level; /* remember the level of the end node */ + endFlag = 1; + /* last node - need to take care of properties + namespaces */ + tmp = xmlDocCopyNode(cur, target, 2); + if (list == NULL) { + list = tmp; + listParent = cur->parent; + } else { + if (level == lastLevel) + xmlAddNextSibling(last, tmp); + else { + xmlAddChild(last, tmp); + lastLevel = level; + } + } + last = tmp; + + if (index2 > 1) { + end = xmlXIncludeGetNthChild(cur, index2 - 1); + index2 = 0; + } + if ((cur == start) && (index1 > 1)) { + cur = xmlXIncludeGetNthChild(cur, index1 - 1); + index1 = 0; + } else { + cur = cur->children; + } + level++; /* increment level to show change */ + /* + * Now gather the remaining nodes from cur to end + */ + continue; /* while */ + } + } else if (cur == start) { /* Not at the end, are we at start? */ + if ((cur->type == XML_TEXT_NODE) || + (cur->type == XML_CDATA_SECTION_NODE)) { + const xmlChar *content = cur->content; + + if (content == NULL) { + tmp = xmlNewTextLen(NULL, 0); + } else { + if (index1 > 1) { + content += (index1 - 1); + index1 = 0; + } + tmp = xmlNewText(content); + } + last = list = tmp; + listParent = cur->parent; + } else { /* Not text node */ + /* + * start of the range - need to take care of + * properties and namespaces + */ + tmp = xmlDocCopyNode(cur, target, 2); + list = last = tmp; + listParent = cur->parent; + if (index1 > 1) { /* Do we need to position? */ + cur = xmlXIncludeGetNthChild(cur, index1 - 1); + level = lastLevel = 1; + index1 = 0; + /* + * Now gather the remaining nodes from cur to end + */ + continue; /* while */ + } + } + } else { + tmp = NULL; + switch (cur->type) { + case XML_DTD_NODE: + case XML_ELEMENT_DECL: + case XML_ATTRIBUTE_DECL: + case XML_ENTITY_NODE: + /* Do not copy DTD informations */ + break; + case XML_ENTITY_DECL: + /* handle crossing entities -> stack needed */ + break; + case XML_XINCLUDE_START: + case XML_XINCLUDE_END: + /* don't consider it part of the tree content */ + break; + case XML_ATTRIBUTE_NODE: + /* Humm, should not happen ! */ + break; + default: + /* + * Middle of the range - need to take care of + * properties and namespaces + */ + tmp = xmlDocCopyNode(cur, target, 2); + break; + } + if (tmp != NULL) { + if (level == lastLevel) + xmlAddNextSibling(last, tmp); + else { + xmlAddChild(last, tmp); + lastLevel = level; + } + last = tmp; + } + } + /* + * Skip to next node in document order + */ + cur = xmlXPtrAdvanceNode(cur, &level); + if (endFlag && (level >= endLevel)) + break; + } + return(list); +} + +/** + * xmlXIncludeBuildNodeList: + * @ctxt: the XInclude context + * @target: the document target + * @source: the document source + * @obj: the XPointer result from the evaluation. + * + * Build a node list tree copy of the XPointer result. + * This will drop Attributes and Namespace declarations. + * + * Returns an xmlNodePtr list or NULL. + * the caller has to free the node tree. + */ +static xmlNodePtr +xmlXIncludeCopyXPointer(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target, + xmlDocPtr source, xmlXPathObjectPtr obj) { + xmlNodePtr list = NULL, last = NULL; + int i; + + if (source == NULL) + source = ctxt->doc; + if ((ctxt == NULL) || (target == NULL) || (source == NULL) || + (obj == NULL)) + return(NULL); + switch (obj->type) { + case XPATH_NODESET: { + xmlNodeSetPtr set = obj->nodesetval; + if (set == NULL) + return(NULL); + for (i = 0;i < set->nodeNr;i++) { + if (set->nodeTab[i] == NULL) + continue; + switch (set->nodeTab[i]->type) { + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: + case XML_ELEMENT_NODE: + case XML_ENTITY_REF_NODE: + case XML_ENTITY_NODE: + case XML_PI_NODE: + case XML_COMMENT_NODE: + case XML_DOCUMENT_NODE: + case XML_HTML_DOCUMENT_NODE: +#ifdef LIBXML_DOCB_ENABLED + case XML_DOCB_DOCUMENT_NODE: +#endif + case XML_XINCLUDE_END: + break; + case XML_XINCLUDE_START: { + xmlNodePtr tmp, cur = set->nodeTab[i]; + + cur = cur->next; + while (cur != NULL) { + switch(cur->type) { + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: + case XML_ELEMENT_NODE: + case XML_ENTITY_REF_NODE: + case XML_ENTITY_NODE: + case XML_PI_NODE: + case XML_COMMENT_NODE: + tmp = xmlXIncludeCopyNode(ctxt, target, + source, cur); + if (last == NULL) { + list = last = tmp; + } else { + xmlAddNextSibling(last, tmp); + last = tmp; + } + cur = cur->next; + continue; + default: + break; + } + break; + } + continue; + } + case XML_ATTRIBUTE_NODE: + case XML_NAMESPACE_DECL: + 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: + continue; /* for */ + } + if (last == NULL) + list = last = xmlXIncludeCopyNode(ctxt, target, source, + set->nodeTab[i]); + else { + xmlAddNextSibling(last, + xmlXIncludeCopyNode(ctxt, target, source, + set->nodeTab[i])); + if (last->next != NULL) + last = last->next; + } + } + break; + } + case XPATH_LOCATIONSET: { + xmlLocationSetPtr set = (xmlLocationSetPtr) obj->user; + if (set == NULL) + return(NULL); + for (i = 0;i < set->locNr;i++) { + if (last == NULL) + list = last = xmlXIncludeCopyXPointer(ctxt, target, source, + set->locTab[i]); + else + xmlAddNextSibling(last, + xmlXIncludeCopyXPointer(ctxt, target, source, + set->locTab[i])); + if (last != NULL) { + while (last->next != NULL) + last = last->next; + } + } + break; + } +#ifdef LIBXML_XPTR_ENABLED + case XPATH_RANGE: + return(xmlXIncludeCopyRange(ctxt, target, source, obj)); +#endif + case XPATH_POINT: + /* points are ignored in XInclude */ + break; + default: + break; + } + return(list); +} +/************************************************************************ + * * + * XInclude I/O handling * + * * + ************************************************************************/ + +typedef struct _xmlXIncludeMergeData xmlXIncludeMergeData; +typedef xmlXIncludeMergeData *xmlXIncludeMergeDataPtr; +struct _xmlXIncludeMergeData { + xmlDocPtr doc; + xmlXIncludeCtxtPtr ctxt; +}; + +/** + * xmlXIncludeMergeOneEntity: + * @ent: the entity + * @doc: the including doc + * @nr: the entity name + * + * Inplements the merge of one entity + */ +static void +xmlXIncludeMergeEntity(xmlEntityPtr ent, xmlXIncludeMergeDataPtr data, + xmlChar *name ATTRIBUTE_UNUSED) { + xmlEntityPtr ret, prev; + xmlDocPtr doc; + xmlXIncludeCtxtPtr ctxt; + + if ((ent == NULL) || (data == NULL)) + return; + ctxt = data->ctxt; + doc = data->doc; + if ((ctxt == NULL) || (doc == NULL)) + return; + switch (ent->etype) { + case XML_INTERNAL_PARAMETER_ENTITY: + case XML_EXTERNAL_PARAMETER_ENTITY: + case XML_INTERNAL_PREDEFINED_ENTITY: + return; + case XML_INTERNAL_GENERAL_ENTITY: + case XML_EXTERNAL_GENERAL_PARSED_ENTITY: + 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) + ret->URI = xmlStrdup(ent->URI); + } 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; + } + + } + } + return; +error: + switch (ent->etype) { + case XML_INTERNAL_PARAMETER_ENTITY: + case XML_EXTERNAL_PARAMETER_ENTITY: + case XML_INTERNAL_PREDEFINED_ENTITY: + case XML_INTERNAL_GENERAL_ENTITY: + case XML_EXTERNAL_GENERAL_PARSED_ENTITY: + return; + case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY: + break; + } + xmlXIncludeErr(ctxt, (xmlNodePtr) ent, XML_XINCLUDE_ENTITY_DEF_MISMATCH, + "mismatch in redefinition of entity %s\n", + ent->name); +} + +/** + * xmlXIncludeMergeEntities: + * @ctxt: an XInclude context + * @doc: the including doc + * @from: the included doc + * + * Inplements the entity merge + * + * Returns 0 if merge succeeded, -1 if some processing failed + */ +static int +xmlXIncludeMergeEntities(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, + xmlDocPtr from) { + xmlNodePtr cur; + xmlDtdPtr target, source; + + if (ctxt == NULL) + return(-1); + + if ((from == NULL) || (from->intSubset == NULL)) + return(0); + + target = doc->intSubset; + if (target == NULL) { + cur = xmlDocGetRootElement(doc); + if (cur == NULL) + return(-1); + target = xmlCreateIntSubset(doc, cur->name, NULL, NULL); + if (target == NULL) + return(-1); + } + + source = from->intSubset; + if ((source != NULL) && (source->entities != NULL)) { + xmlXIncludeMergeData data; + + data.ctxt = ctxt; + data.doc = doc; + + xmlHashScan((xmlHashTablePtr) source->entities, + (xmlHashScanner) xmlXIncludeMergeEntity, &data); + } + source = from->extSubset; + if ((source != NULL) && (source->entities != NULL)) { + xmlXIncludeMergeData data; + + data.ctxt = ctxt; + data.doc = doc; + + /* + * don't duplicate existing stuff when external subsets are the same + */ + if ((!xmlStrEqual(target->ExternalID, source->ExternalID)) && + (!xmlStrEqual(target->SystemID, source->SystemID))) { + xmlHashScan((xmlHashTablePtr) source->entities, + (xmlHashScanner) xmlXIncludeMergeEntity, &data); + } + } + return(0); +} + +/** + * xmlXIncludeLoadDoc: + * @ctxt: the XInclude context + * @url: the associated URL + * @nr: the xinclude node number + * + * Load the document, and store the result in the XInclude context + * + * Returns 0 in case of success, -1 in case of failure + */ +static int +xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) { + xmlDocPtr doc; + xmlURIPtr uri; + xmlChar *URL; + xmlChar *fragment = NULL; + int i = 0; +#ifdef LIBXML_XPTR_ENABLED + int saveFlags; +#endif + +#ifdef DEBUG_XINCLUDE + xmlGenericError(xmlGenericErrorContext, "Loading doc %s:%d\n", url, nr); +#endif + /* + * Check the URL and remove any fragment identifier + */ + uri = xmlParseURI((const char *)url); + if (uri == NULL) { + xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, + XML_XINCLUDE_HREF_URI, + "invalid value URI %s\n", url); + return(-1); + } + if (uri->fragment != NULL) { + fragment = (xmlChar *) uri->fragment; + uri->fragment = NULL; + } + if ((ctxt->incTab != NULL) && (ctxt->incTab[nr] != NULL) && + (ctxt->incTab[nr]->fragment != NULL)) { + if (fragment != NULL) xmlFree(fragment); + fragment = xmlStrdup(ctxt->incTab[nr]->fragment); + } + URL = xmlSaveUri(uri); + xmlFreeURI(uri); + if (URL == NULL) { + if (ctxt->incTab != NULL) + xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, + XML_XINCLUDE_HREF_URI, + "invalid value URI %s\n", url); + else + xmlXIncludeErr(ctxt, NULL, + XML_XINCLUDE_HREF_URI, + "invalid value URI %s\n", url); + if (fragment != NULL) + xmlFree(fragment); + return(-1); + } + + /* + * 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)))) { + doc = NULL; + goto loaded; + } + + /* + * Prevent reloading twice the document. + */ + for (i = 0; i < ctxt->incNr; i++) { + if ((xmlStrEqual(URL, ctxt->incTab[i]->URI)) && + (ctxt->incTab[i]->doc != NULL)) { + doc = ctxt->incTab[i]->doc; +#ifdef DEBUG_XINCLUDE + printf("Already loaded %s\n", URL); +#endif + goto loaded; + } + } + + /* + * Load it. + */ +#ifdef DEBUG_XINCLUDE + printf("loading %s\n", URL); +#endif +#ifdef LIBXML_XPTR_ENABLED + /* + * If this is an XPointer evaluation, we want to assure that + * all entities have been resolved prior to processing the + * referenced document + */ + saveFlags = ctxt->parseFlags; + if (fragment != NULL) { /* if this is an XPointer eval */ + ctxt->parseFlags |= XML_PARSE_NOENT; + } +#endif + + doc = xmlXIncludeParseFile(ctxt, (const char *)URL); +#ifdef LIBXML_XPTR_ENABLED + ctxt->parseFlags = saveFlags; +#endif + if (doc == NULL) { + xmlFree(URL); + if (fragment != NULL) + xmlFree(fragment); + return(-1); + } + ctxt->incTab[nr]->doc = doc; + /* + * It's possible that the requested URL has been mapped to a + * completely different location (e.g. through a catalog entry). + * 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); + } + for (i = nr + 1; i < ctxt->incNr; i++) { + if (xmlStrEqual(URL, ctxt->incTab[i]->URI)) { + ctxt->incTab[nr]->count++; +#ifdef DEBUG_XINCLUDE + printf("Increasing %s count since reused\n", URL); +#endif + break; + } + } + + /* + * Make sure we have all entities fixed up + */ + xmlXIncludeMergeEntities(ctxt, ctxt->doc, doc); + + /* + * We don't need the DTD anymore, free up space + if (doc->intSubset != NULL) { + xmlUnlinkNode((xmlNodePtr) doc->intSubset); + xmlFreeNode((xmlNodePtr) doc->intSubset); + doc->intSubset = NULL; + } + if (doc->extSubset != NULL) { + xmlUnlinkNode((xmlNodePtr) doc->extSubset); + xmlFreeNode((xmlNodePtr) doc->extSubset); + doc->extSubset = NULL; + } + */ + xmlXIncludeRecurseDoc(ctxt, doc, URL); + +loaded: + if (fragment == NULL) { + /* + * Add the top children list as the replacement copy. + */ + if (doc == NULL) + { + /* Hopefully a DTD declaration won't be copied from + * the same document */ + ctxt->incTab[nr]->inc = xmlCopyNodeList(ctxt->doc->children); + } else { + ctxt->incTab[nr]->inc = xmlXIncludeCopyNodeList(ctxt, ctxt->doc, + doc, doc->children); + } + } +#ifdef LIBXML_XPTR_ENABLED + else { + /* + * Computes the XPointer expression and make a copy used + * as the replacement copy. + */ + xmlXPathObjectPtr xptr; + xmlXPathContextPtr xptrctxt; + xmlNodeSetPtr set; + + if (doc == NULL) { + xptrctxt = xmlXPtrNewContext(ctxt->doc, ctxt->incTab[nr]->ref, + NULL); + } else { + xptrctxt = xmlXPtrNewContext(doc, NULL, NULL); + } + if (xptrctxt == NULL) { + xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, + XML_XINCLUDE_XPTR_FAILED, + "could not create XPointer context\n", NULL); + xmlFree(URL); + xmlFree(fragment); + return(-1); + } + xptr = xmlXPtrEval(fragment, xptrctxt); + if (xptr == NULL) { + xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, + XML_XINCLUDE_XPTR_FAILED, + "XPointer evaluation failed: #%s\n", + fragment); + xmlXPathFreeContext(xptrctxt); + xmlFree(URL); + xmlFree(fragment); + return(-1); + } + switch (xptr->type) { + case XPATH_UNDEFINED: + case XPATH_BOOLEAN: + case XPATH_NUMBER: + case XPATH_STRING: + case XPATH_POINT: + case XPATH_USERS: + case XPATH_XSLT_TREE: + xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, + XML_XINCLUDE_XPTR_RESULT, + "XPointer is not a range: #%s\n", + fragment); + xmlXPathFreeContext(xptrctxt); + xmlFree(URL); + xmlFree(fragment); + return(-1); + case XPATH_NODESET: + if ((xptr->nodesetval == NULL) || + (xptr->nodesetval->nodeNr <= 0)) { + xmlXPathFreeContext(xptrctxt); + xmlFree(URL); + xmlFree(fragment); + return(-1); + } + + case XPATH_RANGE: + case XPATH_LOCATIONSET: + break; + } + set = xptr->nodesetval; + if (set != NULL) { + for (i = 0;i < set->nodeNr;i++) { + if (set->nodeTab[i] == NULL) + continue; + switch (set->nodeTab[i]->type) { + case XML_ELEMENT_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_DOCUMENT_NODE: + case XML_HTML_DOCUMENT_NODE: +#ifdef LIBXML_DOCB_ENABLED + case XML_DOCB_DOCUMENT_NODE: +#endif + continue; + + case XML_ATTRIBUTE_NODE: + xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, + XML_XINCLUDE_XPTR_RESULT, + "XPointer selects an attribute: #%s\n", + fragment); + set->nodeTab[i] = NULL; + continue; + case XML_NAMESPACE_DECL: + xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, + XML_XINCLUDE_XPTR_RESULT, + "XPointer selects a namespace: #%s\n", + fragment); + set->nodeTab[i] = NULL; + continue; + 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_XINCLUDE_START: + case XML_XINCLUDE_END: + xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, + XML_XINCLUDE_XPTR_RESULT, + "XPointer selects unexpected nodes: #%s\n", + fragment); + set->nodeTab[i] = NULL; + set->nodeTab[i] = NULL; + continue; /* for */ + } + } + } + if (doc == NULL) { + ctxt->incTab[nr]->xptr = xptr; + ctxt->incTab[nr]->inc = NULL; + } else { + ctxt->incTab[nr]->inc = + xmlXIncludeCopyXPointer(ctxt, ctxt->doc, doc, xptr); + xmlXPathFreeObject(xptr); + } + xmlXPathFreeContext(xptrctxt); + xmlFree(fragment); + } +#endif + + /* + * Do the xml:base fixup if needed + */ + if ((doc != NULL) && (URL != NULL) && (xmlStrchr(URL, (xmlChar) '/')) && + (!(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(ctxt->incTab[nr]->ref, 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, ctxt->incTab[nr]->ref, + 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, (xmlChar) '/')) + xmlFree(curBase); + else + base = curBase; + } + } + if (base != NULL) { /* Adjustment may be needed */ + node = ctxt->incTab[nr]->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, + ctxt->incTab[nr]->ref, + 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); + } + } + if ((nr < ctxt->incNr) && (ctxt->incTab[nr]->doc != NULL) && + (ctxt->incTab[nr]->count <= 1)) { +#ifdef DEBUG_XINCLUDE + printf("freeing %s\n", ctxt->incTab[nr]->doc->URL); +#endif + xmlFreeDoc(ctxt->incTab[nr]->doc); + ctxt->incTab[nr]->doc = NULL; + } + xmlFree(URL); + return(0); +} + +/** + * xmlXIncludeLoadTxt: + * @ctxt: the XInclude context + * @url: the associated URL + * @nr: the xinclude node number + * + * Load the content, and store the result in the XInclude context + * + * Returns 0 in case of success, -1 in case of failure + */ +static int +xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) { + xmlParserInputBufferPtr buf; + xmlNodePtr node; + xmlURIPtr uri; + xmlChar *URL; + int i; + xmlChar *encoding = NULL; + xmlCharEncoding enc = (xmlCharEncoding) 0; + + /* + * Check the URL and remove any fragment identifier + */ + uri = xmlParseURI((const char *)url); + if (uri == NULL) { + xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_HREF_URI, + "invalid value URI %s\n", url); + return(-1); + } + if (uri->fragment != NULL) { + xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_TEXT_FRAGMENT, + "fragment identifier forbidden for text: %s\n", + (const xmlChar *) uri->fragment); + xmlFreeURI(uri); + return(-1); + } + URL = xmlSaveUri(uri); + xmlFreeURI(uri); + if (URL == NULL) { + xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_HREF_URI, + "invalid value URI %s\n", url); + return(-1); + } + + /* + * Handling of references to the local document are done + * directly through ctxt->doc. + */ + if (URL[0] == 0) { + xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, + XML_XINCLUDE_TEXT_DOCUMENT, + "text serialization of document not available\n", NULL); + xmlFree(URL); + return(-1); + } + + /* + * Prevent reloading twice the document. + */ + for (i = 0; i < ctxt->txtNr; i++) { + if (xmlStrEqual(URL, ctxt->txturlTab[i])) { + node = xmlCopyNode(ctxt->txtTab[i], 1); + goto loaded; + } + } + /* + * Try to get the encoding if available + */ + if ((ctxt->incTab[nr] != NULL) && (ctxt->incTab[nr]->ref != NULL)) { + encoding = xmlGetProp(ctxt->incTab[nr]->ref, 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, ctxt->incTab[nr]->ref, + XML_XINCLUDE_UNKNOWN_ENCODING, + "encoding %s not supported\n", encoding); + xmlFree(encoding); + xmlFree(URL); + return(-1); + } + xmlFree(encoding); + } + + /* + * Load it. + */ + buf = xmlParserInputBufferCreateFilename((const char *)URL, enc); + if (buf == NULL) { + xmlFree(URL); + return(-1); + } + node = xmlNewText(NULL); + + /* + * Scan all chars from the resource and add the to the node + */ + while (xmlParserInputBufferRead(buf, 128) > 0) { + int len; + const xmlChar *content; + + content = xmlBufferContent(buf->buffer); + len = xmlBufferLength(buf->buffer); + for (i = 0;i < len;) { + int cur; + int l; + + cur = xmlStringCurrentChar(NULL, &content[i], &l); + if (!IS_CHAR(cur)) { + xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, + XML_XINCLUDE_INVALID_CHAR, + "%s contains invalid char\n", URL); + xmlFreeParserInputBuffer(buf); + xmlFree(URL); + return(-1); + } else { + xmlNodeAddContentLen(node, &content[i], l); + } + i += l; + } + xmlBufferShrink(buf->buffer, len); + } + xmlFreeParserInputBuffer(buf); + xmlXIncludeAddTxt(ctxt, node, URL); + +loaded: + /* + * Add the element as the replacement copy. + */ + ctxt->incTab[nr]->inc = node; + xmlFree(URL); + return(0); +} + +/** + * xmlXIncludeLoadFallback: + * @ctxt: the XInclude context + * @fallback: the fallback node + * @nr: the xinclude node number + * + * Load the content of the fallback node, and store the result + * in the XInclude context + * + * Returns 0 in case of success, -1 in case of failure + */ +static int +xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, int nr) { + xmlXIncludeCtxtPtr newctxt; + int ret = 0; + + if ((fallback == NULL) || (ctxt == NULL)) + return(-1); + if (fallback->children != NULL) { + /* + * It's possible that the fallback also has 'includes' + * (Bug 129969), so we re-process the fallback just in case + */ + newctxt = xmlXIncludeNewContext(ctxt->doc); + if (newctxt == NULL) + return (-1); + newctxt->_private = ctxt->_private; + newctxt->base = xmlStrdup(ctxt->base); /* Inherit the base from the existing context */ + xmlXIncludeSetFlags(newctxt, ctxt->parseFlags); + ret = xmlXIncludeDoProcess(newctxt, ctxt->doc, fallback->children); + if (ctxt->nbErrors > 0) + ret = -1; + else if (ret > 0) + ret = 0; /* xmlXIncludeDoProcess can return +ve number */ + xmlXIncludeFreeContext(newctxt); + + ctxt->incTab[nr]->inc = xmlDocCopyNodeList(ctxt->doc, + fallback->children); + } else { + ctxt->incTab[nr]->inc = NULL; + ctxt->incTab[nr]->emptyFb = 1; /* flag empty callback */ + } + return(ret); +} + +/************************************************************************ + * * + * XInclude Processing * + * * + ************************************************************************/ + +/** + * xmlXIncludePreProcessNode: + * @ctxt: an XInclude context + * @node: an XInclude node + * + * Implement the XInclude preprocessing, currently just adding the element + * for further processing. + * + * Returns the result list or NULL in case of error + */ +static xmlNodePtr +xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) { + xmlXIncludeAddNode(ctxt, node); + return(NULL); +} + +/** + * xmlXIncludeLoadNode: + * @ctxt: an XInclude context + * @nr: the node number + * + * Find and load the infoset replacement for the given node. + * + * Returns 0 if substitution succeeded, -1 if some processing failed + */ +static int +xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) { + xmlNodePtr cur; + xmlChar *href; + xmlChar *parse; + xmlChar *base; + xmlChar *oldBase; + xmlChar *URI; + int xml = 1; /* default Issue 64 */ + int ret; + + if (ctxt == NULL) + return(-1); + if ((nr < 0) || (nr >= ctxt->incNr)) + return(-1); + cur = ctxt->incTab[nr]->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, ctxt->incTab[nr]->ref, + 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, ctxt->incTab[nr]->ref, + 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); + } +#ifdef DEBUG_XINCLUDE + xmlGenericError(xmlGenericErrorContext, "parse: %s\n", + xml ? "xml": "text"); + xmlGenericError(xmlGenericErrorContext, "URI: %s\n", URI); +#endif + + /* + * Save the base for this include (saving the current one) + */ + oldBase = ctxt->base; + ctxt->base = base; + + if (xml) { + ret = xmlXIncludeLoadDoc(ctxt, URI, nr); + /* xmlXIncludeGetFragment(ctxt, cur, URI); */ + } else { + ret = xmlXIncludeLoadTxt(ctxt, URI, nr); + } + + /* + * Restore the original base before checking for fallback + */ + ctxt->base = oldBase; + + if (ret < 0) { + xmlNodePtr children; + + /* + * Time to try a fallback if availble + */ +#ifdef DEBUG_XINCLUDE + xmlGenericError(xmlGenericErrorContext, "error looking for fallback\n"); +#endif + children = cur->children; + while (children != NULL) { + if ((children->type == XML_ELEMENT_NODE) && + (children->ns != NULL) && + (xmlStrEqual(children->name, XINCLUDE_FALLBACK)) && + ((xmlStrEqual(children->ns->href, XINCLUDE_NS)) || + (xmlStrEqual(children->ns->href, XINCLUDE_OLD_NS)))) { + ret = xmlXIncludeLoadFallback(ctxt, children, nr); + if (ret == 0) + break; + } + children = children->next; + } + } + if (ret < 0) { + xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, + XML_XINCLUDE_NO_FALLBACK, + "could not load %s, and no fallback was found\n", + URI); + } + + /* + * Cleanup + */ + if (URI != NULL) + xmlFree(URI); + if (parse != NULL) + xmlFree(parse); + if (href != NULL) + xmlFree(href); + if (base != NULL) + xmlFree(base); + return(0); +} + +/** + * xmlXIncludeIncludeNode: + * @ctxt: an XInclude context + * @nr: the node number + * + * Inplement the infoset replacement for the given node + * + * Returns 0 if substitution succeeded, -1 if some processing failed + */ +static int +xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) { + xmlNodePtr cur, end, list, tmp; + + if (ctxt == NULL) + return(-1); + if ((nr < 0) || (nr >= ctxt->incNr)) + return(-1); + cur = ctxt->incTab[nr]->ref; + if (cur == NULL) + return(-1); + + /* + * If we stored an XPointer a late computation may be needed + */ + if ((ctxt->incTab[nr]->inc == NULL) && + (ctxt->incTab[nr]->xptr != NULL)) { + ctxt->incTab[nr]->inc = + xmlXIncludeCopyXPointer(ctxt, ctxt->doc, ctxt->doc, + ctxt->incTab[nr]->xptr); + xmlXPathFreeObject(ctxt->incTab[nr]->xptr); + ctxt->incTab[nr]->xptr = NULL; + } + list = ctxt->incTab[nr]->inc; + ctxt->incTab[nr]->inc = NULL; + + /* + * Check against the risk of generating a multi-rooted document + */ + if ((cur->parent != NULL) && + (cur->parent->type != XML_ELEMENT_NODE)) { + int nb_elem = 0; + + tmp = list; + while (tmp != NULL) { + if (tmp->type == XML_ELEMENT_NODE) + nb_elem++; + tmp = tmp->next; + } + if (nb_elem > 1) { + xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, + XML_XINCLUDE_MULTIPLE_ROOT, + "XInclude error: would result in multiple root nodes\n", + NULL); + return(-1); + } + } + + if (ctxt->parseFlags & XML_PARSE_NOXINCNODE) { + /* + * Add the list of nodes + */ + while (list != NULL) { + end = list; + list = list->next; + + xmlAddPrevSibling(cur, end); + } + xmlUnlinkNode(cur); + xmlFreeNode(cur); + } else { + /* + * Change the current node as an XInclude start one, and add an + * XInclude end one + */ + cur->type = XML_XINCLUDE_START; + end = xmlNewDocNode(cur->doc, cur->ns, cur->name, NULL); + if (end == NULL) { + xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, + XML_XINCLUDE_BUILD_FAILED, + "failed to build node\n", NULL); + return(-1); + } + end->type = XML_XINCLUDE_END; + xmlAddNextSibling(cur, end); + + /* + * Add the list of nodes + */ + while (list != NULL) { + cur = list; + list = list->next; + + xmlAddPrevSibling(end, cur); + } + } + + + return(0); +} + +/** + * xmlXIncludeTestNode: + * @ctxt: the XInclude processing context + * @node: an XInclude node + * + * test if the node is an XInclude node + * + * Returns 1 true, 0 otherwise + */ +static int +xmlXIncludeTestNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) { + if (node == NULL) + return(0); + if (node->type != XML_ELEMENT_NODE) + return(0); + if (node->ns == NULL) + return(0); + if ((xmlStrEqual(node->ns->href, XINCLUDE_NS)) || + (xmlStrEqual(node->ns->href, XINCLUDE_OLD_NS))) { + if (xmlStrEqual(node->ns->href, XINCLUDE_OLD_NS)) { + if (ctxt->legacy == 0) { +#if 0 /* wait for the XML Core Working Group to get something stable ! */ + xmlXIncludeWarn(ctxt, node, XML_XINCLUDE_DEPRECATED_NS, + "Deprecated XInclude namespace found, use %s", + XINCLUDE_NS); +#endif + ctxt->legacy = 1; + } + } + if (xmlStrEqual(node->name, XINCLUDE_NODE)) { + xmlNodePtr child = node->children; + int nb_fallback = 0; + + while (child != NULL) { + if ((child->type == XML_ELEMENT_NODE) && + (child->ns != NULL) && + ((xmlStrEqual(child->ns->href, XINCLUDE_NS)) || + (xmlStrEqual(child->ns->href, XINCLUDE_OLD_NS)))) { + if (xmlStrEqual(child->name, XINCLUDE_NODE)) { + xmlXIncludeErr(ctxt, node, + XML_XINCLUDE_INCLUDE_IN_INCLUDE, + "%s has an 'include' child\n", + XINCLUDE_NODE); + return(0); + } + if (xmlStrEqual(child->name, XINCLUDE_FALLBACK)) { + nb_fallback++; + } + } + child = child->next; + } + if (nb_fallback > 1) { + xmlXIncludeErr(ctxt, node, XML_XINCLUDE_FALLBACKS_IN_INCLUDE, + "%s has multiple fallback children\n", + XINCLUDE_NODE); + return(0); + } + return(1); + } + if (xmlStrEqual(node->name, XINCLUDE_FALLBACK)) { + if ((node->parent == NULL) || + (node->parent->type != XML_ELEMENT_NODE) || + (node->parent->ns == NULL) || + ((!xmlStrEqual(node->parent->ns->href, XINCLUDE_NS)) && + (!xmlStrEqual(node->parent->ns->href, XINCLUDE_OLD_NS))) || + (!xmlStrEqual(node->parent->name, XINCLUDE_NODE))) { + xmlXIncludeErr(ctxt, node, + XML_XINCLUDE_FALLBACK_NOT_IN_INCLUDE, + "%s is not the child of an 'include'\n", + XINCLUDE_FALLBACK); + } + } + } + return(0); +} + +/** + * xmlXIncludeDoProcess: + * @ctxt: the XInclude processing context + * @doc: an XML document + * @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 +xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree) { + xmlNodePtr cur; + int ret = 0; + int i, start; + + if ((doc == NULL) || (tree == NULL)) + return(-1); + if (ctxt == NULL) + return(-1); + + if (doc->URL != NULL) { + ret = xmlXIncludeURLPush(ctxt, doc->URL); + if (ret < 0) + return(-1); + } + start = ctxt->incNr; + + /* + * First phase: lookup the elements in the document + */ + cur = tree; + if (xmlXIncludeTestNode(ctxt, cur) == 1) + xmlXIncludePreProcessNode(ctxt, cur); + while ((cur != NULL) && (cur != tree->parent)) { + /* TODO: need to work on entities -> stack */ + if ((cur->children != NULL) && + (cur->children->type != XML_ENTITY_DECL) && + (cur->children->type != XML_XINCLUDE_START) && + (cur->children->type != XML_XINCLUDE_END)) { + cur = cur->children; + if (xmlXIncludeTestNode(ctxt, cur)) + xmlXIncludePreProcessNode(ctxt, cur); + } else if (cur->next != NULL) { + cur = cur->next; + if (xmlXIncludeTestNode(ctxt, cur)) + xmlXIncludePreProcessNode(ctxt, cur); + } else { + if (cur == tree) + break; + do { + cur = cur->parent; + if ((cur == NULL) || (cur == tree->parent)) + break; /* do */ + if (cur->next != NULL) { + cur = cur->next; + if (xmlXIncludeTestNode(ctxt, cur)) + xmlXIncludePreProcessNode(ctxt, cur); + break; /* do */ + } + } while (cur != NULL); + } + } + + /* + * Second Phase : collect the infosets fragments + */ + for (i = start;i < ctxt->incNr; i++) { + xmlXIncludeLoadNode(ctxt, i); + ret++; + } + + /* + * Third phase: extend the original document infoset. + * + * Originally we bypassed the inclusion if there were any errors + * encountered on any of the XIncludes. A bug was raised (bug + * 132588) requesting that we output the XIncludes without error, + * so the check for inc!=NULL || xptr!=NULL was put in. This may + * give some other problems in the future, but for now it seems to + * work ok. + * + */ + for (i = ctxt->incBase;i < ctxt->incNr; i++) { + if ((ctxt->incTab[i]->inc != NULL) || + (ctxt->incTab[i]->xptr != NULL) || + (ctxt->incTab[i]->emptyFb != 0)) /* (empty fallback) */ + xmlXIncludeIncludeNode(ctxt, i); + } + + if (doc->URL != NULL) + xmlXIncludeURLPop(ctxt); + return(ret); +} + +/** + * xmlXIncludeSetFlags: + * @ctxt: an XInclude processing context + * @flags: a set of xmlParserOption used for parsing XML includes + * + * Set the flags used for further processing of XML resources. + * + * Returns 0 in case of success and -1 in case of error. + */ +int +xmlXIncludeSetFlags(xmlXIncludeCtxtPtr ctxt, int flags) { + if (ctxt == NULL) + return(-1); + ctxt->parseFlags = flags; + return(0); +} + +/** + * xmlXIncludeProcessTreeFlagsData: + * @tree: an XML node + * @flags: a set of xmlParserOption used for parsing XML includes + * @data: application data that will be passed to the parser context + * in the _private field of the parser context(s) + * + * Implement the XInclude substitution on the XML node @tree + * + * Returns 0 if no substitution were done, -1 if some processing failed + * or the number of substitutions done. + */ + +int +xmlXIncludeProcessTreeFlagsData(xmlNodePtr tree, int flags, void *data) { + xmlXIncludeCtxtPtr ctxt; + int ret = 0; + + if ((tree == NULL) || (tree->doc == NULL)) + return(-1); + + ctxt = xmlXIncludeNewContext(tree->doc); + if (ctxt == NULL) + return(-1); + ctxt->_private = data; + ctxt->base = xmlStrdup((xmlChar *)tree->doc->URL); + xmlXIncludeSetFlags(ctxt, flags); + ret = xmlXIncludeDoProcess(ctxt, tree->doc, tree); + if ((ret >= 0) && (ctxt->nbErrors > 0)) + ret = -1; + + xmlXIncludeFreeContext(ctxt); + return(ret); +} + +/** + * xmlXIncludeProcessFlagsData: + * @doc: an XML document + * @flags: a set of xmlParserOption used for parsing XML includes + * @data: application data that will be passed to the parser context + * in the _private field of the parser context(s) + * + * 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. + */ +int +xmlXIncludeProcessFlagsData(xmlDocPtr doc, int flags, void *data) { + xmlNodePtr tree; + + if (doc == NULL) + return(-1); + tree = xmlDocGetRootElement(doc); + if (tree == NULL) + return(-1); + return(xmlXIncludeProcessTreeFlagsData(tree, flags, data)); +} + +/** + * xmlXIncludeProcessFlags: + * @doc: an XML document + * @flags: a set of xmlParserOption used for parsing XML includes + * + * 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. + */ +int +xmlXIncludeProcessFlags(xmlDocPtr doc, int flags) { + return xmlXIncludeProcessFlagsData(doc, flags, NULL); +} + +/** + * xmlXIncludeProcess: + * @doc: an XML document + * + * 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. + */ +int +xmlXIncludeProcess(xmlDocPtr doc) { + return(xmlXIncludeProcessFlags(doc, 0)); +} + +/** + * xmlXIncludeProcessTreeFlags: + * @tree: a node in an XML document + * @flags: a set of xmlParserOption used for parsing XML includes + * + * Implement the XInclude substitution for the given subtree + * + * Returns 0 if no substitution were done, -1 if some processing failed + * or the number of substitutions done. + */ +int +xmlXIncludeProcessTreeFlags(xmlNodePtr tree, int flags) { + xmlXIncludeCtxtPtr ctxt; + int ret = 0; + + if ((tree == NULL) || (tree->doc == NULL)) + return(-1); + ctxt = xmlXIncludeNewContext(tree->doc); + if (ctxt == NULL) + return(-1); + ctxt->base = xmlNodeGetBase(tree->doc, tree); + xmlXIncludeSetFlags(ctxt, flags); + ret = xmlXIncludeDoProcess(ctxt, tree->doc, tree); + if ((ret >= 0) && (ctxt->nbErrors > 0)) + ret = -1; + + xmlXIncludeFreeContext(ctxt); + return(ret); +} + +/** + * xmlXIncludeProcessTree: + * @tree: a node in an XML document + * + * Implement the XInclude substitution for the given subtree + * + * Returns 0 if no substitution were done, -1 if some processing failed + * or the number of substitutions done. + */ +int +xmlXIncludeProcessTree(xmlNodePtr tree) { + return(xmlXIncludeProcessTreeFlags(tree, 0)); +} + +/** + * xmlXIncludeProcessNode: + * @ctxt: an existing XInclude context + * @node: a node in an XML document + * + * Implement the XInclude substitution for the given subtree reusing + * the informations and data coming from the given context. + * + * Returns 0 if no substitution were done, -1 if some processing failed + * or the number of substitutions done. + */ +int +xmlXIncludeProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) { + int ret = 0; + + if ((node == NULL) || (node->doc == NULL) || (ctxt == NULL)) + return(-1); + ret = xmlXIncludeDoProcess(ctxt, node->doc, node); + if ((ret >= 0) && (ctxt->nbErrors > 0)) + ret = -1; + return(ret); +} + +#else /* !LIBXML_XINCLUDE_ENABLED */ +#endif +#define bottom_xinclude +#include "elfgcchack.h" diff --git a/android/native/libxml2/xlink.c b/android/native/libxml2/xlink.c new file mode 100644 index 0000000000..0d9be738cd --- /dev/null +++ b/android/native/libxml2/xlink.c @@ -0,0 +1,183 @@ +/* + * xlink.c : implementation of the hyperlinks detection module + * This version supports both XML XLinks and HTML simple links + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + */ + + +#define IN_LIBXML +#include "libxml.h" + +#ifdef LIBXML_XPTR_ENABLED +#include /* for memset() only */ +#ifdef HAVE_CTYPE_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_ZLIB_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#define XLINK_NAMESPACE (BAD_CAST "http://www.w3.org/1999/xlink/namespace/") +#define XHTML_NAMESPACE (BAD_CAST "http://www.w3.org/1999/xhtml/") + +/**************************************************************** + * * + * Default setting and related functions * + * * + ****************************************************************/ + +static xlinkHandlerPtr xlinkDefaultHandler = NULL; +static xlinkNodeDetectFunc xlinkDefaultDetect = NULL; + +/** + * xlinkGetDefaultHandler: + * + * Get the default xlink handler. + * + * Returns the current xlinkHandlerPtr value. + */ +xlinkHandlerPtr +xlinkGetDefaultHandler(void) { + return(xlinkDefaultHandler); +} + + +/** + * xlinkSetDefaultHandler: + * @handler: the new value for the xlink handler block + * + * Set the default xlink handlers + */ +void +xlinkSetDefaultHandler(xlinkHandlerPtr handler) { + xlinkDefaultHandler = handler; +} + +/** + * xlinkGetDefaultDetect: + * + * Get the default xlink detection routine + * + * Returns the current function or NULL; + */ +xlinkNodeDetectFunc +xlinkGetDefaultDetect (void) { + return(xlinkDefaultDetect); +} + +/** + * xlinkSetDefaultDetect: + * @func: pointer to the new detection routine. + * + * Set the default xlink detection routine + */ +void +xlinkSetDefaultDetect (xlinkNodeDetectFunc func) { + xlinkDefaultDetect = func; +} + +/**************************************************************** + * * + * The detection routines * + * * + ****************************************************************/ + + +/** + * xlinkIsLink: + * @doc: the document containing the node + * @node: the node pointer itself + * + * Check whether the given node carries the attributes needed + * to be a link element (or is one of the linking elements issued + * from the (X)HTML DtDs). + * This routine don't try to do full checking of the link validity + * but tries to detect and return the appropriate link type. + * + * Returns the xlinkType of the node (XLINK_TYPE_NONE if there is no + * link detected. + */ +xlinkType +xlinkIsLink (xmlDocPtr doc, xmlNodePtr node) { + xmlChar *type = NULL, *role = NULL; + xlinkType ret = XLINK_TYPE_NONE; + + if (node == NULL) return(XLINK_TYPE_NONE); + if (doc == NULL) doc = node->doc; + if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) { + /* + * This is an HTML document. + */ + } else if ((node->ns != NULL) && + (xmlStrEqual(node->ns->href, XHTML_NAMESPACE))) { + /* + * !!!! We really need an IS_XHTML_ELEMENT function from HTMLtree.h @@@ + */ + /* + * This is an XHTML element within an XML document + * Check whether it's one of the element able to carry links + * and in that case if it holds the attributes. + */ + } + + /* + * We don't prevent a-priori having XML Linking constructs on + * XHTML elements + */ + type = xmlGetNsProp(node, BAD_CAST"type", XLINK_NAMESPACE); + if (type != NULL) { + if (xmlStrEqual(type, BAD_CAST "simple")) { + ret = XLINK_TYPE_SIMPLE; + } if (xmlStrEqual(type, BAD_CAST "extended")) { + role = xmlGetNsProp(node, BAD_CAST "role", XLINK_NAMESPACE); + if (role != NULL) { + xmlNsPtr xlink; + xlink = xmlSearchNs(doc, node, XLINK_NAMESPACE); + if (xlink == NULL) { + /* Humm, fallback method */ + if (xmlStrEqual(role, BAD_CAST"xlink:external-linkset")) + ret = XLINK_TYPE_EXTENDED_SET; + } else { + xmlChar buf[200]; + snprintf((char *) buf, sizeof(buf), "%s:external-linkset", + (char *) xlink->prefix); + buf[sizeof(buf) - 1] = 0; + if (xmlStrEqual(role, buf)) + ret = XLINK_TYPE_EXTENDED_SET; + + } + + } + ret = XLINK_TYPE_EXTENDED; + } + } + + if (type != NULL) xmlFree(type); + if (role != NULL) xmlFree(role); + return(ret); +} +#endif /* LIBXML_XPTR_ENABLED */ +#define bottom_xlink +#include "elfgcchack.h" diff --git a/android/native/libxml2/xmlIO.c b/android/native/libxml2/xmlIO.c new file mode 100644 index 0000000000..88f4089178 --- /dev/null +++ b/android/native/libxml2/xmlIO.c @@ -0,0 +1,3209 @@ +/* + * xmlIO.c : implementation of the I/O interfaces used by the parser + * + * 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 +#include "libxml.h" + +#include +#ifdef HAVE_ERRNO_H +#include +#endif + + +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_ZLIB_H +#include +#endif +#ifdef HAVE_LZMA_H +#include +#endif + +#if defined(WIN32) || defined(_WIN32) +#include +#endif + +#if defined(_WIN32_WCE) +#include /* for CP_UTF8 */ +#endif + +/* Figure a portable way to know if a file is a directory. */ +#ifndef HAVE_STAT +# ifdef HAVE__STAT + /* MS C library seems to define stat and _stat. The definition + is identical. Still, mapping them to each other causes a warning. */ +# ifndef _MSC_VER +# define stat(x,y) _stat(x,y) +# endif +# define HAVE_STAT +# endif +#else +# ifdef HAVE__STAT +# if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__) +# define stat _stat +# endif +# endif +#endif +#ifdef HAVE_STAT +# ifndef S_ISDIR +# ifdef _S_ISDIR +# define S_ISDIR(x) _S_ISDIR(x) +# else +# ifdef S_IFDIR +# ifndef S_IFMT +# ifdef _S_IFMT +# define S_IFMT _S_IFMT +# endif +# endif +# ifdef S_IFMT +# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +# endif +# endif +# endif +# endif +#endif + +#include +#include +#include +#include +#include +#include +#include +#ifdef LIBXML_CATALOG_ENABLED +#include +#endif +#include + +/* #define VERBOSE_FAILURE */ +/* #define DEBUG_EXTERNAL_ENTITIES */ +/* #define DEBUG_INPUT */ + +#ifdef DEBUG_INPUT +#define MINLEN 40 +#else +#define MINLEN 4000 +#endif + +/* + * Input I/O callback sets + */ +typedef struct _xmlInputCallback { + xmlInputMatchCallback matchcallback; + xmlInputOpenCallback opencallback; + xmlInputReadCallback readcallback; + xmlInputCloseCallback closecallback; +} xmlInputCallback; + +#define MAX_INPUT_CALLBACK 15 + +static xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK]; +static int xmlInputCallbackNr = 0; +static int xmlInputCallbackInitialized = 0; + +#ifdef LIBXML_OUTPUT_ENABLED +/* + * Output I/O callback sets + */ +typedef struct _xmlOutputCallback { + xmlOutputMatchCallback matchcallback; + xmlOutputOpenCallback opencallback; + xmlOutputWriteCallback writecallback; + xmlOutputCloseCallback closecallback; +} xmlOutputCallback; + +#define MAX_OUTPUT_CALLBACK 15 + +static xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK]; +static int xmlOutputCallbackNr = 0; +static int xmlOutputCallbackInitialized = 0; + +xmlOutputBufferPtr +xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder); +#endif /* LIBXML_OUTPUT_ENABLED */ + +/************************************************************************ + * * + * Tree memory error handler * + * * + ************************************************************************/ + +static const char *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 */ + "adddress in use", /* EADDRINUSE */ + "already in use", /* EALREADY */ + "unknown address familly", /* EAFNOSUPPORT */ +}; + +#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__) +/** + * __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 + +/** + * xmlIOErrMemory: + * @extra: extra informations + * + * Handle an out of memory condition + */ +static void +xmlIOErrMemory(const char *extra) +{ + __xmlSimpleError(XML_FROM_IO, XML_ERR_NO_MEMORY, NULL, NULL, extra); +} + +/** + * __xmlIOErr: + * @code: the error number + * @ + * @extra: extra informations + * + * Handle an I/O error + */ +void +__xmlIOErr(int domain, int code, const char *extra) +{ + unsigned int idx; + + if (code == 0) { +#ifdef HAVE_ERRNO_H + if (errno == 0) code = 0; +#ifdef EACCES + else if (errno == EACCES) code = XML_IO_EACCES; +#endif +#ifdef EAGAIN + else if (errno == EAGAIN) code = XML_IO_EAGAIN; +#endif +#ifdef EBADF + else if (errno == EBADF) code = XML_IO_EBADF; +#endif +#ifdef EBADMSG + else if (errno == EBADMSG) code = XML_IO_EBADMSG; +#endif +#ifdef EBUSY + else if (errno == EBUSY) code = XML_IO_EBUSY; +#endif +#ifdef ECANCELED + else if (errno == ECANCELED) code = XML_IO_ECANCELED; +#endif +#ifdef ECHILD + else if (errno == ECHILD) code = XML_IO_ECHILD; +#endif +#ifdef EDEADLK + else if (errno == EDEADLK) code = XML_IO_EDEADLK; +#endif +#ifdef EDOM + else if (errno == EDOM) code = XML_IO_EDOM; +#endif +#ifdef EEXIST + else if (errno == EEXIST) code = XML_IO_EEXIST; +#endif +#ifdef EFAULT + else if (errno == EFAULT) code = XML_IO_EFAULT; +#endif +#ifdef EFBIG + else if (errno == EFBIG) code = XML_IO_EFBIG; +#endif +#ifdef EINPROGRESS + else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS; +#endif +#ifdef EINTR + else if (errno == EINTR) code = XML_IO_EINTR; +#endif +#ifdef EINVAL + else if (errno == EINVAL) code = XML_IO_EINVAL; +#endif +#ifdef EIO + else if (errno == EIO) code = XML_IO_EIO; +#endif +#ifdef EISDIR + else if (errno == EISDIR) code = XML_IO_EISDIR; +#endif +#ifdef EMFILE + else if (errno == EMFILE) code = XML_IO_EMFILE; +#endif +#ifdef EMLINK + else if (errno == EMLINK) code = XML_IO_EMLINK; +#endif +#ifdef EMSGSIZE + else if (errno == EMSGSIZE) code = XML_IO_EMSGSIZE; +#endif +#ifdef ENAMETOOLONG + else if (errno == ENAMETOOLONG) code = XML_IO_ENAMETOOLONG; +#endif +#ifdef ENFILE + else if (errno == ENFILE) code = XML_IO_ENFILE; +#endif +#ifdef ENODEV + else if (errno == ENODEV) code = XML_IO_ENODEV; +#endif +#ifdef ENOENT + else if (errno == ENOENT) code = XML_IO_ENOENT; +#endif +#ifdef ENOEXEC + else if (errno == ENOEXEC) code = XML_IO_ENOEXEC; +#endif +#ifdef ENOLCK + else if (errno == ENOLCK) code = XML_IO_ENOLCK; +#endif +#ifdef ENOMEM + else if (errno == ENOMEM) code = XML_IO_ENOMEM; +#endif +#ifdef ENOSPC + else if (errno == ENOSPC) code = XML_IO_ENOSPC; +#endif +#ifdef ENOSYS + else if (errno == ENOSYS) code = XML_IO_ENOSYS; +#endif +#ifdef ENOTDIR + else if (errno == ENOTDIR) code = XML_IO_ENOTDIR; +#endif +#ifdef ENOTEMPTY + else if (errno == ENOTEMPTY) code = XML_IO_ENOTEMPTY; +#endif +#ifdef ENOTSUP + else if (errno == ENOTSUP) code = XML_IO_ENOTSUP; +#endif +#ifdef ENOTTY + else if (errno == ENOTTY) code = XML_IO_ENOTTY; +#endif +#ifdef ENXIO + else if (errno == ENXIO) code = XML_IO_ENXIO; +#endif +#ifdef EPERM + else if (errno == EPERM) code = XML_IO_EPERM; +#endif +#ifdef EPIPE + else if (errno == EPIPE) code = XML_IO_EPIPE; +#endif +#ifdef ERANGE + else if (errno == ERANGE) code = XML_IO_ERANGE; +#endif +#ifdef EROFS + else if (errno == EROFS) code = XML_IO_EROFS; +#endif +#ifdef ESPIPE + else if (errno == ESPIPE) code = XML_IO_ESPIPE; +#endif +#ifdef ESRCH + else if (errno == ESRCH) code = XML_IO_ESRCH; +#endif +#ifdef ETIMEDOUT + else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT; +#endif +#ifdef EXDEV + else if (errno == EXDEV) code = XML_IO_EXDEV; +#endif +#ifdef ENOTSOCK + else if (errno == ENOTSOCK) code = XML_IO_ENOTSOCK; +#endif +#ifdef EISCONN + else if (errno == EISCONN) code = XML_IO_EISCONN; +#endif +#ifdef ECONNREFUSED + else if (errno == ECONNREFUSED) code = XML_IO_ECONNREFUSED; +#endif +#ifdef ETIMEDOUT + else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT; +#endif +#ifdef ENETUNREACH + else if (errno == ENETUNREACH) code = XML_IO_ENETUNREACH; +#endif +#ifdef EADDRINUSE + else if (errno == EADDRINUSE) code = XML_IO_EADDRINUSE; +#endif +#ifdef EINPROGRESS + else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS; +#endif +#ifdef EALREADY + else if (errno == EALREADY) code = XML_IO_EALREADY; +#endif +#ifdef EAFNOSUPPORT + else if (errno == EAFNOSUPPORT) code = XML_IO_EAFNOSUPPORT; +#endif + else code = XML_IO_UNKNOWN; +#endif /* HAVE_ERRNO_H */ + } + 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 informations + * + * 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 informations + * + * 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; + } + __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; + } + + 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; + + for (i = xmlOutputCallbackNr - 1; i >= 0; i--) { + xmlOutputCallbackTable[i].matchcallback = NULL; + xmlOutputCallbackTable[i].opencallback = NULL; + xmlOutputCallbackTable[i].writecallback = NULL; + xmlOutputCallbackTable[i].closecallback = NULL; + } + + xmlOutputCallbackNr = 0; + xmlOutputCallbackInitialized = 0; +} +#endif /* LIBXML_OUTPUT_ENABLED */ + +/************************************************************************ + * * + * Standard I/O for file accesses * + * * + ************************************************************************/ + +#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__) + +/** + * xmlWrapOpenUtf8: + * @path: the path in utf-8 encoding + * @mode: type of access (0 - read, 1 - write) + * + * function opens the file specified by @path + * + */ +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 HAVE_ZLIB_H +static gzFile +xmlWrapGzOpenUtf8(const char *path, const char *mode) +{ + gzFile fd; + wchar_t *wPath; + + fd = gzopen (path, mode); + if (fd) + return fd; + + 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); + } + + return fd; +} +#endif + +/** + * xmlWrapStatUtf8: + * @path: the path in utf-8 encoding + * @info: structure that stores results + * + * function obtains information about the file or directory + * + */ +static int +xmlWrapStatUtf8(const char *path,struct stat *info) +{ +#ifdef HAVE_STAT + 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; +#else + return -1; +#endif +} + +/** + * xmlWrapOpenNative: + * @path: the path + * @mode: type of access (0 - read, 1 - write) + * + * function opens the file specified by @path + * + */ +static FILE* +xmlWrapOpenNative(const char *path,int mode) +{ + return fopen(path,mode ? "wb" : "rb"); +} + +/** + * xmlWrapStatNative: + * @path: the path + * @info: structure that stores results + * + * function obtains information about the file or directory + * + */ +static int +xmlWrapStatNative(const char *path,struct stat *info) +{ +#ifdef HAVE_STAT + return stat(path,info); +#else + return -1; +#endif +} + +typedef int (* xmlWrapStatFunc) (const char *f, struct stat *s); +static xmlWrapStatFunc xmlWrapStat = xmlWrapStatNative; +typedef FILE* (* xmlWrapOpenFunc)(const char *f,int mode); +static xmlWrapOpenFunc xmlWrapOpen = xmlWrapOpenNative; +#ifdef HAVE_ZLIB_H +typedef gzFile (* xmlWrapGzOpenFunc) (const char *f, const char *mode); +static xmlWrapGzOpenFunc xmlWrapGzOpen = gzopen; +#endif +/** + * xmlInitPlatformSpecificIo: + * + * Initialize platform specific features. + */ +static void +xmlInitPlatformSpecificIo(void) +{ + static int xmlPlatformIoInitialized = 0; + OSVERSIONINFO osvi; + + if(xmlPlatformIoInitialized) + return; + + osvi.dwOSVersionInfoSize = sizeof(osvi); + + if(GetVersionEx(&osvi) && (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)) { + xmlWrapStat = xmlWrapStatUtf8; + xmlWrapOpen = xmlWrapOpenUtf8; +#ifdef HAVE_ZLIB_H + xmlWrapGzOpen = xmlWrapGzOpenUtf8; +#endif + } else { + xmlWrapStat = xmlWrapStatNative; + xmlWrapOpen = xmlWrapOpenNative; +#ifdef HAVE_ZLIB_H + xmlWrapGzOpen = gzopen; +#endif + } + + xmlPlatformIoInitialized = 1; + return; +} + +#endif + +/** + * xmlCheckFilename: + * @path: the path to check + * + * function checks to see if @path is a valid source + * (file, socket...) for XML. + * + * if stat is not available on the target machine, + * returns 1. if stat fails, returns 0 (if calling + * stat on the filename fails, it can't be right). + * if stat succeeds and the file is a directory, + * returns 2. otherwise returns 1. + */ + +int +xmlCheckFilename (const char *path) +{ +#ifdef HAVE_STAT + struct stat stat_buffer; +#endif + if (path == NULL) + return(0); + +#ifdef HAVE_STAT +#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__) + if (xmlWrapStat(path, &stat_buffer) == -1) + return 0; +#else + if (stat(path, &stat_buffer) == -1) + return 0; +#endif +#ifdef S_ISDIR + if (S_ISDIR(stat_buffer.st_mode)) + return 2; +#endif +#endif /* HAVE_STAT */ + return 1; +} + +static int +xmlNop(void) { + return(0); +} + +/** + * 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 +xmlFdRead (void * context, char * buffer, int len) { + int ret; + + ret = read((int) (long) context, &buffer[0], len); + if (ret < 0) xmlIOErr(0, "read()"); + return(ret); +} + +#ifdef LIBXML_OUTPUT_ENABLED +/** + * xmlFdWrite: + * @context: the I/O context + * @buffer: where to get data + * @len: number of bytes to write + * + * Write @len bytes from @buffer to the I/O channel. + * + * Returns the number of bytes written + */ +static int +xmlFdWrite (void * context, const char * buffer, int len) { + int ret = 0; + + if (len > 0) { + ret = write((int) (long) context, &buffer[0], len); + if (ret < 0) xmlIOErr(0, "write()"); + } + return(ret); +} +#endif /* LIBXML_OUTPUT_ENABLED */ + +/** + * xmlFdClose: + * @context: the I/O context + * + * Close an I/O channel + * + * Returns 0 in case of success and error code otherwise + */ +static int +xmlFdClose (void * context) { + int ret; + ret = close((int) (long) context); + if (ret < 0) xmlIOErr(0, "close()"); + return(ret); +} + +/** + * xmlFileMatch: + * @filename: the URI for matching + * + * input from FILE * + * + * Returns 1 if matches, 0 otherwise + */ +int +xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) { + return(1); +} + +/** + * xmlFileOpen_real: + * @filename: the URI for matching + * + * input from FILE *, supports compressed input + * if @filename is " " then the standard input is used + * + * Returns an I/O context or NULL in case of error + */ +static void * +xmlFileOpen_real (const char *filename) { + const char *path = NULL; + FILE *fd; + + if (filename == NULL) + return(NULL); + + if (!strcmp(filename, "-")) { + fd = stdin; + return((void *) fd); + } + + if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) { +#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__) + path = &filename[17]; +#else + path = &filename[16]; +#endif + } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) { +#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__) + 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) || defined (__DJGPP__) && !defined(__CYGWIN__) + path = &filename[6]; +#else + path = &filename[5]; +#endif + } else + path = filename; + + if (path == NULL) + return(NULL); + if (!xmlCheckFilename(path)) + return(NULL); + +#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__) + fd = xmlWrapOpen(path, 0); +#else + fd = fopen(path, "r"); +#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); + } + } + + return retval; +} + +#ifdef LIBXML_OUTPUT_ENABLED +/** + * xmlFileOpenW: + * @filename: the URI for matching + * + * output to from FILE *, + * if @filename is "-" then the standard output is used + * + * Returns an I/O context or NULL in case of error + */ +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) || defined (__DJGPP__) && !defined(__CYGWIN__) + path = &filename[17]; +#else + path = &filename[16]; +#endif + else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) { +#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__) + path = &filename[8]; +#else + path = &filename[7]; +#endif + } else + path = filename; + + if (path == NULL) + return(NULL); + +#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__) + fd = xmlWrapOpen(path, 1); +#else + fd = fopen(path, "wb"); +#endif /* WIN32 */ + + if (fd == NULL) xmlIOErr(0, path); + return((void *) fd); +} +#endif /* LIBXML_OUTPUT_ENABLED */ + +/** + * xmlFileRead: + * @context: the I/O context + * @buffer: where to drop data + * @len: number of bytes to write + * + * Read @len bytes to @buffer from the I/O channel. + * + * Returns the number of bytes written or < 0 in case of failure + */ +int +xmlFileRead (void * context, char * buffer, int len) { + int ret; + if ((context == NULL) || (buffer == NULL)) + return(-1); + ret = fread(&buffer[0], 1, len, (FILE *) context); + if (ret < 0) xmlIOErr(0, "fread()"); + return(ret); +} + +#ifdef LIBXML_OUTPUT_ENABLED +/** + * xmlFileWrite: + * @context: the I/O context + * @buffer: where to drop data + * @len: number of bytes to write + * + * Write @len bytes from @buffer to the I/O channel. + * + * Returns the number of bytes written + */ +static int +xmlFileWrite (void * context, const char * buffer, int len) { + int items; + + 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); +} +#endif /* LIBXML_OUTPUT_ENABLED */ + +/** + * xmlFileClose: + * @context: the I/O context + * + * Close an I/O channel + * + * Returns 0 or -1 in case of error + */ +int +xmlFileClose (void * context) { + FILE *fil; + int ret; + + if (context == 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); +} + +/** + * xmlFileFlush: + * @context: the I/O context + * + * Flush an I/O channel + */ +static int +xmlFileFlush (void * context) { + int ret; + + if (context == NULL) + return(-1); + ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0; + if (ret < 0) + xmlIOErr(0, "fflush()"); + return(ret); +} + +#ifdef LIBXML_OUTPUT_ENABLED +/** + * xmlBufferWrite: + * @context: the xmlBuffer + * @buffer: the data to write + * @len: number of bytes to write + * + * Write @len bytes from @buffer to the xml buffer + * + * Returns the number of bytes written + */ +static int +xmlBufferWrite (void * context, const char * buffer, int len) { + int ret; + + ret = xmlBufferAdd((xmlBufferPtr) context, (const xmlChar *) buffer, len); + if (ret != 0) + return(-1); + return(len); +} +#endif + +#ifdef HAVE_ZLIB_H +/************************************************************************ + * * + * 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, "-")) { + fd = gzdopen(dup(0), "rb"); + return((void *) fd); + } + + if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) +#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__) + path = &filename[17]; +#else + path = &filename[16]; +#endif + else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) { +#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__) + path = &filename[8]; +#else + path = &filename[7]; +#endif + } else + path = filename; + + if (path == NULL) + return(NULL); + if (!xmlCheckFilename(path)) + return(NULL); + +#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__) + fd = xmlWrapGzOpen(path, "rb"); +#else + fd = gzopen(path, "rb"); +#endif + return((void *) fd); +} + +/** + * xmlGzfileOpen: + * @filename: the URI for matching + * + * Wrapper around xmlGzfileOpen if the open fais, 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, "-")) { + fd = gzdopen(dup(1), mode); + return((void *) fd); + } + + if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) +#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__) + path = &filename[17]; +#else + path = &filename[16]; +#endif + else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) { +#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__) + path = &filename[8]; +#else + path = &filename[7]; +#endif + } else + path = filename; + + if (path == NULL) + return(NULL); + +#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__) + fd = xmlWrapGzOpen(path, mode); +#else + fd = gzopen(path, mode); +#endif + return((void *) fd); +} +#endif /* LIBXML_OUTPUT_ENABLED */ + +/** + * xmlGzfileRead: + * @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 +xmlGzfileRead (void * context, char * buffer, int len) { + int ret; + + ret = gzread((gzFile) context, &buffer[0], len); + if (ret < 0) xmlIOErr(0, "gzread()"); + return(ret); +} + +#ifdef LIBXML_OUTPUT_ENABLED +/** + * xmlGzfileWrite: + * @context: the I/O context + * @buffer: where to drop data + * @len: number of bytes to write + * + * Write @len bytes from @buffer to the compressed I/O channel. + * + * Returns the number of bytes written + */ +static int +xmlGzfileWrite (void * context, const char * buffer, int len) { + int ret; + + ret = gzwrite((gzFile) context, (char *) &buffer[0], len); + if (ret < 0) xmlIOErr(0, "gzwrite()"); + return(ret); +} +#endif /* LIBXML_OUTPUT_ENABLED */ + +/** + * xmlGzfileClose: + * @context: the I/O context + * + * Close a compressed I/O channel + */ +static int +xmlGzfileClose (void * context) { + int ret; + + ret = (gzclose((gzFile) context) == Z_OK ) ? 0 : -1; + if (ret < 0) xmlIOErr(0, "gzclose()"); + return(ret); +} +#endif /* HAVE_ZLIB_H */ + +#ifdef HAVE_LZMA_H +/************************************************************************ + * * + * I/O for compressed file accesses * + * * + ************************************************************************/ +#include "xzlib.h" +/** + * xmlXzfileMatch: + * @filename: the URI for matching + * + * input from compressed file test + * + * Returns 1 if matches, 0 otherwise + */ +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(0), "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; + + ret = __libxml2_xzread((xzFile) context, &buffer[0], len); + if (ret < 0) xmlIOErr(0, "xzread()"); + return(ret); +} + +/** + * xmlXzfileClose: + * @context: the I/O context + * + * Close a compressed I/O channel + */ +static int +xmlXzfileClose (void * context) { + int ret; + + ret = (__libxml2_xzclose((xzFile) context) == LZMA_OK ) ? 0 : -1; + if (ret < 0) xmlIOErr(0, "xzclose()"); + return(ret); +} +#endif /* HAVE_LZMA_H */ + +/** + * 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++); +} + +#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); + } + xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc; + xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc; + xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc; + xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc; + xmlOutputCallbackInitialized = 1; + return(xmlOutputCallbackNr++); +} +#endif /* LIBXML_OUTPUT_ENABLED */ + +/** + * xmlRegisterDefaultInputCallbacks: + * + * Registers the default compiled-in I/O handlers. + */ +void +xmlRegisterDefaultInputCallbacks(void) { + if (xmlInputCallbackInitialized) + return; + +#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__) + xmlInitPlatformSpecificIo(); +#endif + + xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen, + xmlFileRead, xmlFileClose); +#ifdef HAVE_ZLIB_H + xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen, + xmlGzfileRead, xmlGzfileClose); +#endif /* HAVE_ZLIB_H */ +#ifdef HAVE_LZMA_H + xmlRegisterInputCallbacks(xmlXzfileMatch, xmlXzfileOpen, + xmlXzfileRead, xmlXzfileClose); +#endif /* HAVE_ZLIB_H */ + + xmlInputCallbackInitialized = 1; +} + +#ifdef LIBXML_OUTPUT_ENABLED +/** + * xmlRegisterDefaultOutputCallbacks: + * + * Registers the default compiled-in I/O handlers. + */ +void +xmlRegisterDefaultOutputCallbacks (void) { + if (xmlOutputCallbackInitialized) + return; + +#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__) + xmlInitPlatformSpecificIo(); +#endif + + xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW, + xmlFileWrite, xmlFileClose); + +/********************************* + 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. + +#ifdef HAVE_ZLIB_H + xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen, + xmlGzfileWrite, xmlGzfileClose); +#endif + + Nor FTP PUT .... + **********************************/ + xmlOutputCallbackInitialized = 1; +} + +#endif /* LIBXML_OUTPUT_ENABLED */ + +/** + * xmlAllocParserInputBuffer: + * @enc: the charset encoding if known + * + * Create a buffered parser input for progressive parsing + * + * Returns the new parser input or NULL + */ +xmlParserInputBufferPtr +xmlAllocParserInputBuffer(xmlCharEncoding enc) { + xmlParserInputBufferPtr ret; + + ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer)); + if (ret == NULL) { + xmlIOErrMemory("creating input buffer"); + return(NULL); + } + memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer)); + ret->buffer = xmlBufferCreateSize(2 * xmlDefaultBufferSize); + if (ret->buffer == NULL) { + xmlFree(ret); + return(NULL); + } + ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT; + ret->encoder = xmlGetCharEncodingHandler(enc); + if (ret->encoder != NULL) + ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize); + else + ret->raw = NULL; + ret->readcallback = NULL; + ret->closecallback = NULL; + ret->context = NULL; + ret->compressed = -1; + ret->rawconsumed = 0; + + return(ret); +} + +#ifdef LIBXML_OUTPUT_ENABLED +/** + * xmlAllocOutputBuffer: + * @encoder: the encoding converter or NULL + * + * Create a buffered parser output + * + * Returns the new parser output or NULL + */ +xmlOutputBufferPtr +xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) { + xmlOutputBufferPtr ret; + + ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer)); + if (ret == NULL) { + xmlIOErrMemory("creating output buffer"); + return(NULL); + } + memset(ret, 0, (size_t) sizeof(xmlOutputBuffer)); + ret->buffer = xmlBufferCreate(); + if (ret->buffer == NULL) { + xmlFree(ret); + return(NULL); + } + + /* try to avoid a performance problem with Windows realloc() */ + if (ret->buffer->alloc == XML_BUFFER_ALLOC_EXACT) + ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT; + + ret->encoder = encoder; + if (encoder != NULL) { + ret->conv = xmlBufferCreateSize(4000); + if (ret->conv == NULL) { + xmlFree(ret); + return(NULL); + } + + /* + * This call is designed to initiate the encoder state + */ + xmlCharEncOutFunc(encoder, ret->conv, NULL); + } else + ret->conv = NULL; + ret->writecallback = NULL; + ret->closecallback = NULL; + ret->context = NULL; + ret->written = 0; + + return(ret); +} + +/** + * xmlAllocOutputBufferInternal: + * @encoder: the encoding converter or NULL + * + * Create a buffered parser output + * + * Returns the new parser output or NULL + */ +xmlOutputBufferPtr +xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder) { + xmlOutputBufferPtr ret; + + ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer)); + if (ret == NULL) { + xmlIOErrMemory("creating output buffer"); + return(NULL); + } + memset(ret, 0, (size_t) sizeof(xmlOutputBuffer)); + ret->buffer = xmlBufferCreate(); + if (ret->buffer == NULL) { + xmlFree(ret); + return(NULL); + } + + + /* + * For conversion buffers we use the special IO handling + * We don't do that from the exported API to avoid confusing + * user's code. + */ + ret->buffer->alloc = XML_BUFFER_ALLOC_IO; + ret->buffer->contentIO = ret->buffer->content; + + ret->encoder = encoder; + if (encoder != NULL) { + ret->conv = xmlBufferCreateSize(4000); + if (ret->conv == NULL) { + xmlFree(ret); + return(NULL); + } + + /* + * This call is designed to initiate the encoder state + */ + xmlCharEncOutFunc(encoder, ret->conv, NULL); + } else + ret->conv = NULL; + ret->writecallback = NULL; + ret->closecallback = NULL; + ret->context = NULL; + ret->written = 0; + + return(ret); +} + +#endif /* LIBXML_OUTPUT_ENABLED */ + +/** + * xmlFreeParserInputBuffer: + * @in: a buffered parser input + * + * Free up the memory used by a buffered parser input + */ +void +xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) { + if (in == NULL) return; + + if (in->raw) { + xmlBufferFree(in->raw); + in->raw = NULL; + } + if (in->encoder != NULL) { + xmlCharEncCloseFunc(in->encoder); + } + if (in->closecallback != NULL) { + in->closecallback(in->context); + } + if (in->buffer != NULL) { + xmlBufferFree(in->buffer); + in->buffer = NULL; + } + + xmlFree(in); +} + +#ifdef LIBXML_OUTPUT_ENABLED +/** + * xmlOutputBufferClose: + * @out: a buffered output + * + * 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. + */ +int +xmlOutputBufferClose(xmlOutputBufferPtr out) +{ + int written; + int err_rc = 0; + + if (out == NULL) + return (-1); + if (out->writecallback != NULL) + xmlOutputBufferFlush(out); + if (out->closecallback != NULL) { + err_rc = out->closecallback(out->context); + } + written = out->written; + if (out->conv) { + xmlBufferFree(out->conv); + out->conv = NULL; + } + if (out->encoder != NULL) { + xmlCharEncCloseFunc(out->encoder); + } + if (out->buffer != NULL) { + xmlBufferFree(out->buffer); + out->buffer = NULL; + } + + if (out->error) + err_rc = -1; + xmlFree(out); + return ((err_rc == 0) ? written : err_rc); +} +#endif /* LIBXML_OUTPUT_ENABLED */ + +xmlParserInputBufferPtr +__xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) { + xmlParserInputBufferPtr ret; + int i = 0; + void *context = NULL; + + if (xmlInputCallbackInitialized == 0) + xmlRegisterDefaultInputCallbacks(); + + if (URI == NULL) return(NULL); + + /* + * 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; + } + } + } + } + if (context == NULL) { + return(NULL); + } + + /* + * 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 HAVE_ZLIB_H + 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 + } + else + xmlInputCallbackTable[i].closecallback (context); + + return(ret); +} + +/** + * xmlParserInputBufferCreateFilename: + * @URI: a C string containing the URI or filename + * @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 + * + * Returns the new parser input or NULL + */ +xmlParserInputBufferPtr +xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) { + if ((xmlParserInputBufferCreateFilenameValue)) { + return xmlParserInputBufferCreateFilenameValue(URI, enc); + } + return __xmlParserInputBufferCreateFilename(URI, enc); +} + +#ifdef LIBXML_OUTPUT_ENABLED +xmlOutputBufferPtr +__xmlOutputBufferCreateFilename(const char *URI, + xmlCharEncodingHandlerPtr encoder, + int compression ATTRIBUTE_UNUSED) { + xmlOutputBufferPtr ret; + xmlURIPtr puri; + int i = 0; + void *context = NULL; + char *unescaped = NULL; +#ifdef HAVE_ZLIB_H + int is_file_uri = 1; +#endif + + if (xmlOutputCallbackInitialized == 0) + xmlRegisterDefaultOutputCallbacks(); + + if (URI == NULL) return(NULL); + + puri = xmlParseURI(URI); + if (puri != NULL) { +#ifdef HAVE_ZLIB_H + 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 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 + */ + if (unescaped != NULL) { +#ifdef HAVE_ZLIB_H + 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)) { + context = xmlOutputCallbackTable[i].opencallback(unescaped); + if (context != NULL) + break; + } + } + xmlFree(unescaped); + } + + /* + * If this failed try with a non-escaped URI this may be a strange + * filename + */ + if (context == NULL) { +#ifdef HAVE_ZLIB_H + 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; + } + return(ret); + } + } +#endif + for (i = xmlOutputCallbackNr - 1;i >= 0;i--) { + if ((xmlOutputCallbackTable[i].matchcallback != NULL) && + (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) { + context = xmlOutputCallbackTable[i].opencallback(URI); + if (context != NULL) + break; + } + } + } + + if (context == NULL) { + return(NULL); + } + + /* + * 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; + } + return(ret); +} + +/** + * xmlOutputBufferCreateFilename: + * @URI: a C string containing the URI or filename + * @encoder: the encoding converter or NULL + * @compression: the compression ration (0 none, 9 max). + * + * Create a buffered output for the progressive saving of a file + * If filename is "-' then we use stdout as the output. + * Automatic support for ZLIB/Compress compressed document is provided + * by default if found at compile-time. + * TODO: currently if compression is set, the library only support + * writing to a local file. + * + * Returns the new output or NULL + */ +xmlOutputBufferPtr +xmlOutputBufferCreateFilename(const char *URI, + xmlCharEncodingHandlerPtr encoder, + int compression ATTRIBUTE_UNUSED) { + if ((xmlOutputBufferCreateFilenameValue)) { + return xmlOutputBufferCreateFilenameValue(URI, encoder, compression); + } + return __xmlOutputBufferCreateFilename(URI, encoder, compression); +} +#endif /* LIBXML_OUTPUT_ENABLED */ + +/** + * xmlParserInputBufferCreateFile: + * @file: a FILE* + * @enc: the charset encoding if known + * + * Create a buffered parser input for the progressive parsing of a FILE * + * buffered C I/O + * + * 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; + } + + return(ret); +} + +#ifdef LIBXML_OUTPUT_ENABLED +/** + * xmlOutputBufferCreateFile: + * @file: a FILE* + * @encoder: the encoding converter or NULL + * + * Create a buffered output for the progressive saving to a FILE * + * buffered C I/O + * + * Returns the new parser output or NULL + */ +xmlOutputBufferPtr +xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) { + xmlOutputBufferPtr ret; + + if (xmlOutputCallbackInitialized == 0) + xmlRegisterDefaultOutputCallbacks(); + + if (file == NULL) return(NULL); + + ret = xmlAllocOutputBufferInternal(encoder); + if (ret != NULL) { + ret->context = file; + ret->writecallback = xmlFileWrite; + ret->closecallback = xmlFileFlush; + } + + return(ret); +} + +/** + * xmlOutputBufferCreateBuffer: + * @buffer: a xmlBufferPtr + * @encoder: the encoding converter or NULL + * + * Create a buffered output for the progressive saving to a xmlBuffer + * + * Returns the new parser output or NULL + */ +xmlOutputBufferPtr +xmlOutputBufferCreateBuffer(xmlBufferPtr buffer, + xmlCharEncodingHandlerPtr encoder) { + xmlOutputBufferPtr ret; + + if (buffer == NULL) return(NULL); + + ret = xmlOutputBufferCreateIO((xmlOutputWriteCallback) + xmlBufferWrite, + (xmlOutputCloseCallback) + NULL, (void *) buffer, encoder); + + return(ret); +} + +#endif /* LIBXML_OUTPUT_ENABLED */ + +/** + * xmlParserInputBufferCreateFd: + * @fd: a file descriptor number + * @enc: the charset encoding if known + * + * Create a buffered parser input for the progressive parsing for the input + * from a file descriptor + * + * Returns the new parser input or NULL + */ +xmlParserInputBufferPtr +xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) { + xmlParserInputBufferPtr ret; + + if (fd < 0) return(NULL); + + ret = xmlAllocParserInputBuffer(enc); + if (ret != NULL) { + ret->context = (void *) (long) fd; + ret->readcallback = xmlFdRead; + ret->closecallback = xmlFdClose; + } + + return(ret); +} + +/** + * xmlParserInputBufferCreateMem: + * @mem: the memory input + * @size: the length of the memory block + * @enc: the charset encoding if known + * + * Create a buffered parser input for the progressive parsing for the input + * from a memory area. + * + * Returns the new parser input or NULL + */ +xmlParserInputBufferPtr +xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) { + xmlParserInputBufferPtr ret; + int errcode; + + if (size <= 0) return(NULL); + if (mem == NULL) return(NULL); + + ret = xmlAllocParserInputBuffer(enc); + if (ret != NULL) { + ret->context = (void *) mem; + ret->readcallback = (xmlInputReadCallback) xmlNop; + ret->closecallback = NULL; + errcode = xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size); + if (errcode != 0) { + xmlFree(ret); + return(NULL); + } + } + + return(ret); +} + +/** + * xmlParserInputBufferCreateStatic: + * @mem: the memory input + * @size: the length of the memory block + * @enc: the charset encoding if known + * + * Create a buffered parser input for the progressive parsing for the input + * from an immutable memory area. This will not copy the memory area to + * the buffer, but the memory is expected to be available until the end of + * the parsing, this is useful for example when using mmap'ed file. + * + * Returns the new parser input or NULL + */ +xmlParserInputBufferPtr +xmlParserInputBufferCreateStatic(const char *mem, int size, + xmlCharEncoding enc) { + xmlParserInputBufferPtr ret; + + if (size <= 0) return(NULL); + if (mem == NULL) return(NULL); + + ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer)); + if (ret == NULL) { + xmlIOErrMemory("creating input buffer"); + return(NULL); + } + memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer)); + ret->buffer = xmlBufferCreateStatic((void *)mem, (size_t) size); + if (ret->buffer == NULL) { + xmlFree(ret); + return(NULL); + } + ret->encoder = xmlGetCharEncodingHandler(enc); + if (ret->encoder != NULL) + ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize); + else + ret->raw = NULL; + ret->compressed = -1; + ret->context = (void *) mem; + ret->readcallback = NULL; + ret->closecallback = NULL; + + return(ret); +} + +#ifdef LIBXML_OUTPUT_ENABLED +/** + * xmlOutputBufferCreateFd: + * @fd: a file descriptor number + * @encoder: the encoding converter or NULL + * + * Create a buffered output for the progressive saving + * to a file descriptor + * + * Returns the new parser output or NULL + */ +xmlOutputBufferPtr +xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) { + xmlOutputBufferPtr ret; + + if (fd < 0) return(NULL); + + ret = xmlAllocOutputBufferInternal(encoder); + if (ret != NULL) { + ret->context = (void *) (long) fd; + ret->writecallback = xmlFdWrite; + ret->closecallback = NULL; + } + + return(ret); +} +#endif /* LIBXML_OUTPUT_ENABLED */ + +/** + * xmlParserInputBufferCreateIO: + * @ioread: an I/O read function + * @ioclose: an I/O close function + * @ioctx: an I/O handler + * @enc: the charset encoding if known + * + * Create a buffered parser input for the progressive parsing for the input + * from an I/O handler + * + * Returns the new parser input or NULL + */ +xmlParserInputBufferPtr +xmlParserInputBufferCreateIO(xmlInputReadCallback ioread, + xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) { + xmlParserInputBufferPtr ret; + + if (ioread == NULL) return(NULL); + + ret = xmlAllocParserInputBuffer(enc); + if (ret != NULL) { + ret->context = (void *) ioctx; + ret->readcallback = ioread; + ret->closecallback = ioclose; + } + + return(ret); +} + +#ifdef LIBXML_OUTPUT_ENABLED +/** + * xmlOutputBufferCreateIO: + * @iowrite: an I/O write function + * @ioclose: an I/O close function + * @ioctx: an I/O handler + * @encoder: the charset encoding if known + * + * Create a buffered output for the progressive saving + * to an I/O handler + * + * Returns the new parser output or NULL + */ +xmlOutputBufferPtr +xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite, + xmlOutputCloseCallback ioclose, void *ioctx, + xmlCharEncodingHandlerPtr encoder) { + xmlOutputBufferPtr ret; + + if (iowrite == NULL) return(NULL); + + ret = xmlAllocOutputBufferInternal(encoder); + if (ret != NULL) { + ret->context = (void *) ioctx; + ret->writecallback = iowrite; + ret->closecallback = ioclose; + } + + return(ret); +} +#endif /* LIBXML_OUTPUT_ENABLED */ + +/** + * xmlParserInputBufferCreateFilenameDefault: + * @func: function pointer to the new ParserInputBufferCreateFilenameFunc + * + * Registers a callback for URI input file handling + * + * Returns the old value of the registration function + */ +xmlParserInputBufferCreateFilenameFunc +xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func) +{ + xmlParserInputBufferCreateFilenameFunc old = xmlParserInputBufferCreateFilenameValue; + if (old == NULL) { + old = __xmlParserInputBufferCreateFilename; + } + + xmlParserInputBufferCreateFilenameValue = func; + return(old); +} + +/** + * xmlOutputBufferCreateFilenameDefault: + * @func: function pointer to the new OutputBufferCreateFilenameFunc + * + * Registers a callback for URI output file handling + * + * Returns the old value of the registration function + */ +xmlOutputBufferCreateFilenameFunc +xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func) +{ + xmlOutputBufferCreateFilenameFunc old = xmlOutputBufferCreateFilenameValue; +#ifdef LIBXML_OUTPUT_ENABLED + if (old == NULL) { + old = __xmlOutputBufferCreateFilename; + } +#endif + xmlOutputBufferCreateFilenameValue = func; + return(old); +} + +/** + * xmlParserInputBufferPush: + * @in: a buffered parser input + * @len: the size in bytes of the array. + * @buf: an char array + * + * Push the content of the arry in the input buffer + * This routine handle the I18N transcoding to internal UTF-8 + * This is used when operating the parser in progressive (push) mode. + * + * Returns the number of chars read and stored in the buffer, or -1 + * in case of error. + */ +int +xmlParserInputBufferPush(xmlParserInputBufferPtr in, + int len, const char *buf) { + int nbchars = 0; + int ret; + + if (len < 0) return(0); + if ((in == NULL) || (in->error)) return(-1); + if (in->encoder != NULL) { + unsigned int use; + + /* + * Store the data in the incoming raw buffer + */ + if (in->raw == NULL) { + in->raw = xmlBufferCreate(); + } + ret = xmlBufferAdd(in->raw, (const xmlChar *) buf, len); + if (ret != 0) + return(-1); + + /* + * convert as much as possible to the parser reading buffer. + */ + use = in->raw->use; + nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw); + if (nbchars < 0) { + xmlIOErr(XML_IO_ENCODER, NULL); + in->error = XML_IO_ENCODER; + return(-1); + } + in->rawconsumed += (use - in->raw->use); + } else { + nbchars = len; + ret = xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars); + if (ret != 0) + return(-1); + } +#ifdef DEBUG_INPUT + xmlGenericError(xmlGenericErrorContext, + "I/O: pushed %d chars, buffer %d/%d\n", + nbchars, in->buffer->use, in->buffer->size); +#endif + return(nbchars); +} + +/** + * endOfInput: + * + * When reading from an Input channel indicated end of file or error + * don't reread from it again. + */ +static int +endOfInput (void * context ATTRIBUTE_UNUSED, + char * buffer ATTRIBUTE_UNUSED, + int len ATTRIBUTE_UNUSED) { + return(0); +} + +/** + * xmlParserInputBufferGrow: + * @in: a buffered parser input + * @len: indicative value of the amount of chars to read + * + * Grow up the content of the input buffer, the old data are preserved + * This routine handle the I18N transcoding to internal UTF-8 + * This routine is used when operating the parser in normal (pull) mode + * + * TODO: one should be able to remove one extra copy by copying directly + * onto in->buffer or in->raw + * + * Returns the number of chars read and stored in the buffer, or -1 + * in case of error. + */ +int +xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) { + char *buffer = NULL; + int res = 0; + int nbchars = 0; + int buffree; + unsigned int needSize; + + if ((in == NULL) || (in->error)) return(-1); + if ((len <= MINLEN) && (len != 4)) + len = MINLEN; + + buffree = in->buffer->size - in->buffer->use; + if (buffree <= 0) { + xmlIOErr(XML_IO_BUFFER_FULL, NULL); + in->error = XML_IO_BUFFER_FULL; + return(-1); + } + + needSize = in->buffer->use + len + 1; + if (needSize > in->buffer->size){ + if (!xmlBufferResize(in->buffer, needSize)){ + xmlIOErrMemory("growing input buffer"); + in->error = XML_ERR_NO_MEMORY; + return(-1); + } + } + buffer = (char *)&in->buffer->content[in->buffer->use]; + + /* + * Call the read method for this I/O type. + */ + if (in->readcallback != NULL) { + res = in->readcallback(in->context, &buffer[0], len); + if (res <= 0) + in->readcallback = endOfInput; + } else { + xmlIOErr(XML_IO_NO_INPUT, NULL); + in->error = XML_IO_NO_INPUT; + return(-1); + } + if (res < 0) { + return(-1); + } + len = res; + if (in->encoder != NULL) { + unsigned int use; + + /* + * Store the data in the incoming raw buffer + */ + if (in->raw == NULL) { + in->raw = xmlBufferCreate(); + } + res = xmlBufferAdd(in->raw, (const xmlChar *) buffer, len); + if (res != 0) + return(-1); + + /* + * convert as much as possible to the parser reading buffer. + */ + use = in->raw->use; + nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw); + if (nbchars < 0) { + xmlIOErr(XML_IO_ENCODER, NULL); + in->error = XML_IO_ENCODER; + return(-1); + } + in->rawconsumed += (use - in->raw->use); + } else { + nbchars = len; + in->buffer->use += nbchars; + buffer[nbchars] = 0; + } +#ifdef DEBUG_INPUT + xmlGenericError(xmlGenericErrorContext, + "I/O: read %d chars, buffer %d/%d\n", + nbchars, in->buffer->use, in->buffer->size); +#endif + return(nbchars); +} + +/** + * xmlParserInputBufferRead: + * @in: a buffered parser input + * @len: indicative value of the amount of chars to read + * + * Refresh the content of the input buffer, the old data are considered + * consumed + * This routine handle the I18N transcoding to internal UTF-8 + * + * Returns the number of chars read and stored in the buffer, or -1 + * in case of error. + */ +int +xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) { + if ((in == NULL) || (in->error)) return(-1); + if (in->readcallback != NULL) + return(xmlParserInputBufferGrow(in, len)); + else if ((in->buffer != NULL) && + (in->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE)) + return(0); + else + return(-1); +} + +#ifdef LIBXML_OUTPUT_ENABLED +/** + * xmlOutputBufferWrite: + * @out: a buffered parser output + * @len: the size in bytes of the array. + * @buf: an char array + * + * Write the content of the array in the output I/O buffer + * This routine handle the I18N transcoding from internal UTF-8 + * The buffer is lossless, i.e. will store in case of partial + * or delayed writes. + * + * Returns the number of chars immediately written, or -1 + * in case of error. + */ +int +xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) { + int nbchars = 0; /* number of chars to output to I/O */ + int ret; /* return from function call */ + int written = 0; /* number of char written to I/O so far */ + int chunk; /* number of byte curreent processed from buf */ + + if ((out == NULL) || (out->error)) return(-1); + if (len < 0) return(0); + if (out->error) return(-1); + + do { + chunk = len; + if (chunk > 4 * MINLEN) + chunk = 4 * MINLEN; + + /* + * first handle encoding stuff. + */ + if (out->encoder != NULL) { + /* + * Store the data in the incoming raw buffer + */ + if (out->conv == NULL) { + out->conv = xmlBufferCreate(); + } + ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk); + if (ret != 0) + return(-1); + + if ((out->buffer->use < MINLEN) && (chunk == len)) + goto done; + + /* + * convert as much as possible to the parser reading buffer. + */ + ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer); + if ((ret < 0) && (ret != -3)) { + xmlIOErr(XML_IO_ENCODER, NULL); + out->error = XML_IO_ENCODER; + return(-1); + } + nbchars = out->conv->use; + } else { + ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk); + if (ret != 0) + return(-1); + nbchars = out->buffer->use; + } + buf += chunk; + len -= chunk; + + if ((nbchars < MINLEN) && (len <= 0)) + goto done; + + if (out->writecallback) { + /* + * second write the stuff to the I/O channel + */ + if (out->encoder != NULL) { + ret = out->writecallback(out->context, + (const char *)out->conv->content, nbchars); + if (ret >= 0) + xmlBufferShrink(out->conv, ret); + } else { + ret = out->writecallback(out->context, + (const char *)out->buffer->content, nbchars); + if (ret >= 0) + xmlBufferShrink(out->buffer, ret); + } + if (ret < 0) { + xmlIOErr(XML_IO_WRITE, NULL); + out->error = XML_IO_WRITE; + return(ret); + } + out->written += ret; + } + written += nbchars; + } while (len > 0); + +done: +#ifdef DEBUG_INPUT + xmlGenericError(xmlGenericErrorContext, + "I/O: wrote %d chars\n", written); +#endif + return(written); +} + +/** + * xmlEscapeContent: + * @out: a pointer to an array of bytes to store the result + * @outlen: the length of @out + * @in: a pointer to an array of unescaped UTF-8 bytes + * @inlen: the length of @in + * + * Take a block of UTF-8 chars in and escape them. + * Returns 0 if success, or -1 otherwise + * The value of @inlen after return is the number of octets consumed + * if the return value is positive, else unpredictable. + * The value of @outlen after return is the number of octets consumed. + */ +static int +xmlEscapeContent(unsigned char* out, int *outlen, + const xmlChar* in, int *inlen) { + unsigned char* outstart = out; + const unsigned char* base = in; + unsigned char* outend = out + *outlen; + const unsigned char* inend; + + inend = in + (*inlen); + + while ((in < inend) && (out < outend)) { + if (*in == '<') { + if (outend - out < 4) break; + *out++ = '&'; + *out++ = 'l'; + *out++ = 't'; + *out++ = ';'; + } else if (*in == '>') { + if (outend - out < 4) break; + *out++ = '&'; + *out++ = 'g'; + *out++ = 't'; + *out++ = ';'; + } else if (*in == '&') { + if (outend - out < 5) break; + *out++ = '&'; + *out++ = 'a'; + *out++ = 'm'; + *out++ = 'p'; + *out++ = ';'; + } else if (*in == '\r') { + if (outend - out < 5) break; + *out++ = '&'; + *out++ = '#'; + *out++ = '1'; + *out++ = '3'; + *out++ = ';'; + } else { + *out++ = (unsigned char) *in; + } + ++in; + } + *outlen = out - outstart; + *inlen = in - base; + return(0); +} + +/** + * xmlOutputBufferWriteEscape: + * @out: a buffered parser output + * @str: a zero terminated UTF-8 string + * @escaping: an optional escaping function (or NULL) + * + * Write the content of the string in the output I/O buffer + * This routine escapes the caracters and then handle the I18N + * transcoding from internal UTF-8 + * The buffer is lossless, i.e. will store in case of partial + * or delayed writes. + * + * Returns the number of chars immediately written, or -1 + * in case of error. + */ +int +xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str, + xmlCharEncodingOutputFunc escaping) { + int nbchars = 0; /* number of chars to output to I/O */ + int ret; /* return from function call */ + int written = 0; /* number of char written to I/O so far */ + int oldwritten=0;/* loop guard */ + int chunk; /* number of byte currently processed from str */ + int len; /* number of bytes in str */ + int cons; /* byte from str consumed */ + + if ((out == NULL) || (out->error) || (str == NULL) || + (out->buffer == NULL) || + (out->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE)) return(-1); + len = strlen((const char *)str); + if (len < 0) return(0); + if (out->error) return(-1); + if (escaping == NULL) escaping = xmlEscapeContent; + + do { + oldwritten = written; + + /* + * how many bytes to consume and how many bytes to store. + */ + cons = len; + chunk = (out->buffer->size - out->buffer->use) - 1; + + /* + * make sure we have enough room to save first, if this is + * not the case force a flush, but make sure we stay in the loop + */ + if (chunk < 40) { + if (xmlBufferGrow(out->buffer, out->buffer->size + 100) < 0) + return(-1); + oldwritten = -1; + continue; + } + + /* + * first handle encoding stuff. + */ + if (out->encoder != NULL) { + /* + * Store the data in the incoming raw buffer + */ + if (out->conv == NULL) { + out->conv = xmlBufferCreate(); + } + ret = escaping(out->buffer->content + out->buffer->use , + &chunk, str, &cons); + if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */ + return(-1); + out->buffer->use += chunk; + out->buffer->content[out->buffer->use] = 0; + + if ((out->buffer->use < MINLEN) && (cons == len)) + goto done; + + /* + * convert as much as possible to the output buffer. + */ + ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer); + if ((ret < 0) && (ret != -3)) { + xmlIOErr(XML_IO_ENCODER, NULL); + out->error = XML_IO_ENCODER; + return(-1); + } + nbchars = out->conv->use; + } else { + ret = escaping(out->buffer->content + out->buffer->use , + &chunk, str, &cons); + if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */ + return(-1); + out->buffer->use += chunk; + out->buffer->content[out->buffer->use] = 0; + nbchars = out->buffer->use; + } + str += cons; + len -= cons; + + if ((nbchars < MINLEN) && (len <= 0)) + goto done; + + if (out->writecallback) { + /* + * second write the stuff to the I/O channel + */ + if (out->encoder != NULL) { + ret = out->writecallback(out->context, + (const char *)out->conv->content, nbchars); + if (ret >= 0) + xmlBufferShrink(out->conv, ret); + } else { + ret = out->writecallback(out->context, + (const char *)out->buffer->content, nbchars); + if (ret >= 0) + xmlBufferShrink(out->buffer, ret); + } + if (ret < 0) { + xmlIOErr(XML_IO_WRITE, NULL); + out->error = XML_IO_WRITE; + return(ret); + } + out->written += ret; + } else if (out->buffer->size - out->buffer->use < MINLEN) { + xmlBufferResize(out->buffer, out->buffer->size + MINLEN); + } + written += nbchars; + } while ((len > 0) && (oldwritten != written)); + +done: +#ifdef DEBUG_INPUT + xmlGenericError(xmlGenericErrorContext, + "I/O: wrote %d chars\n", written); +#endif + return(written); +} + +/** + * xmlOutputBufferWriteString: + * @out: a buffered parser output + * @str: a zero terminated C string + * + * Write the content of the string in the output I/O buffer + * This routine handle the I18N transcoding from internal UTF-8 + * The buffer is lossless, i.e. will store in case of partial + * or delayed writes. + * + * Returns the number of chars immediately written, or -1 + * in case of error. + */ +int +xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) { + int len; + + if ((out == NULL) || (out->error)) return(-1); + if (str == NULL) + return(-1); + len = strlen(str); + + if (len > 0) + return(xmlOutputBufferWrite(out, len, str)); + return(len); +} + +/** + * xmlOutputBufferFlush: + * @out: a buffered output + * + * flushes the output I/O channel + * + * Returns the number of byte written or -1 in case of error. + */ +int +xmlOutputBufferFlush(xmlOutputBufferPtr out) { + int nbchars = 0, ret = 0; + + if ((out == NULL) || (out->error)) return(-1); + /* + * first handle encoding stuff. + */ + if ((out->conv != NULL) && (out->encoder != NULL)) { + /* + * convert as much as possible to the parser reading buffer. + */ + nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer); + if (nbchars < 0) { + xmlIOErr(XML_IO_ENCODER, NULL); + out->error = XML_IO_ENCODER; + return(-1); + } + } + + /* + * second flush the stuff to the I/O channel + */ + if ((out->conv != NULL) && (out->encoder != NULL) && + (out->writecallback != NULL)) { + ret = out->writecallback(out->context, + (const char *)out->conv->content, out->conv->use); + if (ret >= 0) + xmlBufferShrink(out->conv, ret); + } else if (out->writecallback != NULL) { + ret = out->writecallback(out->context, + (const char *)out->buffer->content, out->buffer->use); + if (ret >= 0) + xmlBufferShrink(out->buffer, ret); + } + if (ret < 0) { + xmlIOErr(XML_IO_FLUSH, NULL); + out->error = XML_IO_FLUSH; + return(ret); + } + out->written += ret; + +#ifdef DEBUG_INPUT + xmlGenericError(xmlGenericErrorContext, + "I/O: flushed %d chars\n", ret); +#endif + return(ret); +} +#endif /* LIBXML_OUTPUT_ENABLED */ + +/** + * xmlParserGetDirectory: + * @filename: the path to a file + * + * lookup the directory for that file + * + * Returns a new allocated string containing the directory, or NULL. + */ +char * +xmlParserGetDirectory(const char *filename) { + char *ret = NULL; + char dir[1024]; + char *cur; + +#ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */ + return NULL; +#endif + + if (xmlInputCallbackInitialized == 0) + xmlRegisterDefaultInputCallbacks(); + + if (filename == NULL) return(NULL); + +#if defined(WIN32) && !defined(__CYGWIN__) +# define IS_XMLPGD_SEP(ch) ((ch=='/')||(ch=='\\')) +#else +# define IS_XMLPGD_SEP(ch) (ch=='/') +#endif + + strncpy(dir, filename, 1023); + dir[1023] = 0; + cur = &dir[strlen(dir)]; + while (cur > dir) { + if (IS_XMLPGD_SEP(*cur)) break; + cur --; + } + if (IS_XMLPGD_SEP(*cur)) { + if (cur == dir) dir[1] = 0; + else *cur = 0; + ret = xmlMemStrdup(dir); + } else { + if (getcwd(dir, 1024) != NULL) { + dir[1023] = 0; + ret = xmlMemStrdup(dir); + } + } + return(ret); +#undef IS_XMLPGD_SEP +} + +/**************************************************************** + * * + * External entities loading * + * * + ****************************************************************/ + +/** + * xmlCheckHTTPInput: + * @ctxt: an XML parser context + * @ret: an XML parser input + * + * 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) { + return(ret); +} + +static int xmlNoNetExists(const char *URL) { + const char *path; + + if (URL == NULL) + return(0); + + if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17)) +#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__) + path = &URL[17]; +#else + path = &URL[16]; +#endif + else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) { +#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__) + path = &URL[8]; +#else + path = &URL[7]; +#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 + * + * 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 + +/** + * 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 entitites, 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; + +#ifdef DEBUG_EXTERNAL_ENTITIES + xmlGenericError(xmlGenericErrorContext, + "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL); +#endif + 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; + + 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); +} + +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 + * + * Load an external entity, note that the use of this function for + * unparsed entities may generate problems + * + * Returns the xmlParserInputPtr or NULL + */ +xmlParserInputPtr +xmlLoadExternalEntity(const char *URL, const char *ID, + xmlParserCtxtPtr ctxt) { + if ((URL != NULL) && (xmlNoNetExists(URL) == 0)) { + char *canonicFilename; + xmlParserInputPtr ret; + + canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL); + if (canonicFilename == NULL) { + xmlIOErrMemory("building canonical path\n"); + return(NULL); + } + + ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt); + xmlFree(canonicFilename); + return(ret); + } + return(xmlCurrentExternalEntityLoader(URL, ID, ctxt)); +} + +/************************************************************************ + * * + * Disabling Network access * + * * + ************************************************************************/ + +/** + * 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))) { + 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); +} + +#define bottom_xmlIO +#include "elfgcchack.h" diff --git a/android/native/libxml2/xmlcatalog.c b/android/native/libxml2/xmlcatalog.c new file mode 100644 index 0000000000..489509f5bf --- /dev/null +++ b/android/native/libxml2/xmlcatalog.c @@ -0,0 +1,614 @@ +/* + * xmlcatalog.c : a small utility program to handle XML catalogs + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + */ + +#include "libxml.h" + +#include +#include +#include + +#ifdef HAVE_STDLIB_H +#include +#endif + +#ifdef HAVE_LIBREADLINE +#include +#ifdef HAVE_LIBHISTORY +#include +#endif +#endif + +#include +#include +#include +#include +#include + +#if defined(LIBXML_CATALOG_ENABLED) && defined(LIBXML_OUTPUT_ENABLED) +static int shell = 0; +static int sgml = 0; +static int noout = 0; +static int create = 0; +static int add = 0; +static int del = 0; +static int convert = 0; +static int no_super_update = 0; +static int verbose = 0; +static char *filename = NULL; + + +#ifndef XML_SGML_DEFAULT_CATALOG +#define XML_SGML_DEFAULT_CATALOG "/etc/sgml/catalog" +#endif + +/************************************************************************ + * * + * Shell Interface * + * * + ************************************************************************/ +/** + * xmlShellReadline: + * @prompt: the prompt value + * + * Read a string + * + * Returns a pointer to it or NULL on EOF the caller is expected to + * free the returned string. + */ +static char * +xmlShellReadline(const char *prompt) { +#ifdef HAVE_LIBREADLINE + char *line_read; + + /* Get a line from the user. */ + line_read = readline (prompt); + + /* If the line has any text in it, save it on the history. */ + if (line_read && *line_read) + add_history (line_read); + + return (line_read); +#else + char line_read[501]; + char *ret; + int len; + + if (prompt != NULL) + fprintf(stdout, "%s", prompt); + if (!fgets(line_read, 500, stdin)) + return(NULL); + line_read[500] = 0; + len = strlen(line_read); + ret = (char *) malloc(len + 1); + if (ret != NULL) { + memcpy (ret, line_read, len + 1); + } + return(ret); +#endif +} + +static void usershell(void) { + char *cmdline = NULL, *cur; + int nbargs; + char command[100]; + char arg[400]; + char *argv[20]; + int i, ret; + xmlChar *ans; + + while (1) { + cmdline = xmlShellReadline("> "); + if (cmdline == NULL) + return; + + /* + * Parse the command itself + */ + cur = cmdline; + nbargs = 0; + while ((*cur == ' ') || (*cur == '\t')) cur++; + i = 0; + while ((*cur != ' ') && (*cur != '\t') && + (*cur != '\n') && (*cur != '\r')) { + if (*cur == 0) + break; + command[i++] = *cur++; + } + command[i] = 0; + if (i == 0) { + free(cmdline); + continue; + } + + /* + * Parse the argument string + */ + memset(arg, 0, sizeof(arg)); + while ((*cur == ' ') || (*cur == '\t')) cur++; + i = 0; + while ((*cur != '\n') && (*cur != '\r') && (*cur != 0)) { + if (*cur == 0) + break; + arg[i++] = *cur++; + } + arg[i] = 0; + + /* + * Parse the arguments + */ + i = 0; + nbargs = 0; + cur = arg; + memset(argv, 0, sizeof(argv)); + while (*cur != 0) { + while ((*cur == ' ') || (*cur == '\t')) cur++; + if (*cur == '\'') { + cur++; + argv[i] = cur; + while ((*cur != 0) && (*cur != '\'')) cur++; + if (*cur == '\'') { + *cur = 0; + nbargs++; + i++; + cur++; + } + } else if (*cur == '"') { + cur++; + argv[i] = cur; + while ((*cur != 0) && (*cur != '"')) cur++; + if (*cur == '"') { + *cur = 0; + nbargs++; + i++; + cur++; + } + } else { + argv[i] = cur; + while ((*cur != 0) && (*cur != ' ') && (*cur != '\t')) + cur++; + *cur = 0; + nbargs++; + i++; + cur++; + } + } + + /* + * start interpreting the command + */ + if (!strcmp(command, "exit")) + break; + if (!strcmp(command, "quit")) + break; + if (!strcmp(command, "bye")) + break; + if (!strcmp(command, "public")) { + if (nbargs != 1) { + printf("public requires 1 arguments\n"); + } else { + ans = xmlCatalogResolvePublic((const xmlChar *) argv[0]); + if (ans == NULL) { + printf("No entry for PUBLIC %s\n", argv[0]); + } else { + printf("%s\n", (char *) ans); + xmlFree(ans); + } + } + } else if (!strcmp(command, "system")) { + if (nbargs != 1) { + printf("system requires 1 arguments\n"); + } else { + ans = xmlCatalogResolveSystem((const xmlChar *) argv[0]); + if (ans == NULL) { + printf("No entry for SYSTEM %s\n", argv[0]); + } else { + printf("%s\n", (char *) ans); + xmlFree(ans); + } + } + } else if (!strcmp(command, "add")) { + if (sgml) { + if ((nbargs != 3) && (nbargs != 2)) { + printf("add requires 2 or 3 arguments\n"); + } else { + if (argv[2] == NULL) + ret = xmlCatalogAdd(BAD_CAST argv[0], NULL, + BAD_CAST argv[1]); + else + ret = xmlCatalogAdd(BAD_CAST argv[0], BAD_CAST argv[1], + BAD_CAST argv[2]); + if (ret != 0) + printf("add command failed\n"); + } + } else { + if ((nbargs != 3) && (nbargs != 2)) { + printf("add requires 2 or 3 arguments\n"); + } else { + if (argv[2] == NULL) + ret = xmlCatalogAdd(BAD_CAST argv[0], NULL, + BAD_CAST argv[1]); + else + ret = xmlCatalogAdd(BAD_CAST argv[0], BAD_CAST argv[1], + BAD_CAST argv[2]); + if (ret != 0) + printf("add command failed\n"); + } + } + } else if (!strcmp(command, "del")) { + if (nbargs != 1) { + printf("del requires 1\n"); + } else { + ret = xmlCatalogRemove(BAD_CAST argv[0]); + if (ret <= 0) + printf("del command failed\n"); + + } + } else if (!strcmp(command, "resolve")) { + if (nbargs != 2) { + printf("resolve requires 2 arguments\n"); + } else { + ans = xmlCatalogResolve(BAD_CAST argv[0], + BAD_CAST argv[1]); + if (ans == NULL) { + printf("Resolver failed to find an answer\n"); + } else { + printf("%s\n", (char *) ans); + xmlFree(ans); + } + } + } else if (!strcmp(command, "dump")) { + if (nbargs != 0) { + printf("dump has no arguments\n"); + } else { + xmlCatalogDump(stdout); + } + } else if (!strcmp(command, "debug")) { + if (nbargs != 0) { + printf("debug has no arguments\n"); + } else { + verbose++; + xmlCatalogSetDebug(verbose); + } + } else if (!strcmp(command, "quiet")) { + if (nbargs != 0) { + printf("quiet has no arguments\n"); + } else { + if (verbose > 0) + verbose--; + xmlCatalogSetDebug(verbose); + } + } else { + if (strcmp(command, "help")) { + printf("Unrecognized command %s\n", command); + } + printf("Commands available:\n"); + printf("\tpublic PublicID: make a PUBLIC identifier lookup\n"); + printf("\tsystem SystemID: make a SYSTEM identifier lookup\n"); + printf("\tresolve PublicID SystemID: do a full resolver lookup\n"); + printf("\tadd 'type' 'orig' 'replace' : add an entry\n"); + printf("\tdel 'values' : remove values\n"); + printf("\tdump: print the current catalog state\n"); + printf("\tdebug: increase the verbosity level\n"); + printf("\tquiet: decrease the verbosity level\n"); + printf("\texit: quit the shell\n"); + } + free(cmdline); /* not xmlFree here ! */ + } +} + +/************************************************************************ + * * + * Main * + * * + ************************************************************************/ +static void usage(const char *name) { + /* split into 2 printf's to avoid overly long string (gcc warning) */ + printf("\ +Usage : %s [options] catalogfile entities...\n\ +\tParse the catalog file and query it for the entities\n\ +\t--sgml : handle SGML Super catalogs for --add and --del\n\ +\t--shell : run a shell allowing interactive queries\n\ +\t--create : create a new catalog\n\ +\t--add 'type' 'orig' 'replace' : add an XML entry\n\ +\t--add 'entry' : add an SGML entry\n", name); + printf("\ +\t--del 'values' : remove values\n\ +\t--noout: avoid dumping the result on stdout\n\ +\t used with --add or --del, it saves the catalog changes\n\ +\t and with --sgml it automatically updates the super catalog\n\ +\t--no-super-update: do not update the SGML super catalog\n\ +\t-v --verbose : provide debug informations\n"); +} +int main(int argc, char **argv) { + int i; + int ret; + int exit_value = 0; + + + if (argc <= 1) { + usage(argv[0]); + return(1); + } + + LIBXML_TEST_VERSION + for (i = 1; i < argc ; i++) { + if (!strcmp(argv[i], "-")) + break; + + if (argv[i][0] != '-') + break; + if ((!strcmp(argv[i], "-verbose")) || + (!strcmp(argv[i], "-v")) || + (!strcmp(argv[i], "--verbose"))) { + verbose++; + xmlCatalogSetDebug(verbose); + } else if ((!strcmp(argv[i], "-noout")) || + (!strcmp(argv[i], "--noout"))) { + noout = 1; + } else if ((!strcmp(argv[i], "-shell")) || + (!strcmp(argv[i], "--shell"))) { + shell++; + noout = 1; + } else if ((!strcmp(argv[i], "-sgml")) || + (!strcmp(argv[i], "--sgml"))) { + sgml++; + } else if ((!strcmp(argv[i], "-create")) || + (!strcmp(argv[i], "--create"))) { + create++; + } else if ((!strcmp(argv[i], "-convert")) || + (!strcmp(argv[i], "--convert"))) { + convert++; + } else if ((!strcmp(argv[i], "-no-super-update")) || + (!strcmp(argv[i], "--no-super-update"))) { + no_super_update++; + } else if ((!strcmp(argv[i], "-add")) || + (!strcmp(argv[i], "--add"))) { + if (sgml) + i += 2; + else + i += 3; + add++; + } else if ((!strcmp(argv[i], "-del")) || + (!strcmp(argv[i], "--del"))) { + i += 1; + del++; + } else { + fprintf(stderr, "Unknown option %s\n", argv[i]); + usage(argv[0]); + return(1); + } + } + + for (i = 1; i < argc; i++) { + if ((!strcmp(argv[i], "-add")) || + (!strcmp(argv[i], "--add"))) { + if (sgml) + i += 2; + else + i += 3; + continue; + } else if ((!strcmp(argv[i], "-del")) || + (!strcmp(argv[i], "--del"))) { + i += 1; + + /* No catalog entry specified */ + if (i == argc || (sgml && i + 1 == argc)) { + fprintf(stderr, "No catalog entry specified to remove from\n"); + usage (argv[0]); + return(1); + } + + continue; + } else if (argv[i][0] == '-') + continue; + filename = argv[i]; + ret = xmlLoadCatalog(argv[i]); + if ((ret < 0) && (create)) { + xmlCatalogAdd(BAD_CAST "catalog", BAD_CAST argv[i], NULL); + } + break; + } + + if (convert) + ret = xmlCatalogConvert(); + + if ((add) || (del)) { + for (i = 1; i < argc ; i++) { + if (!strcmp(argv[i], "-")) + break; + + if (argv[i][0] != '-') + continue; + if (strcmp(argv[i], "-add") && strcmp(argv[i], "--add") && + strcmp(argv[i], "-del") && strcmp(argv[i], "--del")) + continue; + + if (sgml) { + /* + * Maintenance of SGML catalogs. + */ + xmlCatalogPtr catal = NULL; + xmlCatalogPtr super = NULL; + + catal = xmlLoadSGMLSuperCatalog(argv[i + 1]); + + if ((!strcmp(argv[i], "-add")) || + (!strcmp(argv[i], "--add"))) { + if (catal == NULL) + catal = xmlNewCatalog(1); + xmlACatalogAdd(catal, BAD_CAST "CATALOG", + BAD_CAST argv[i + 2], NULL); + + if (!no_super_update) { + super = xmlLoadSGMLSuperCatalog(XML_SGML_DEFAULT_CATALOG); + if (super == NULL) + super = xmlNewCatalog(1); + + xmlACatalogAdd(super, BAD_CAST "CATALOG", + BAD_CAST argv[i + 1], NULL); + } + } else { + if (catal != NULL) + ret = xmlACatalogRemove(catal, BAD_CAST argv[i + 2]); + else + ret = -1; + if (ret < 0) { + fprintf(stderr, "Failed to remove entry from %s\n", + argv[i + 1]); + exit_value = 1; + } + if ((!no_super_update) && (noout) && (catal != NULL) && + (xmlCatalogIsEmpty(catal))) { + super = xmlLoadSGMLSuperCatalog( + XML_SGML_DEFAULT_CATALOG); + if (super != NULL) { + ret = xmlACatalogRemove(super, + BAD_CAST argv[i + 1]); + if (ret < 0) { + fprintf(stderr, + "Failed to remove entry from %s\n", + XML_SGML_DEFAULT_CATALOG); + exit_value = 1; + } + } + } + } + if (noout) { + FILE *out; + + if (xmlCatalogIsEmpty(catal)) { + remove(argv[i + 1]); + } else { + out = fopen(argv[i + 1], "w"); + if (out == NULL) { + fprintf(stderr, "could not open %s for saving\n", + argv[i + 1]); + exit_value = 2; + noout = 0; + } else { + xmlACatalogDump(catal, out); + fclose(out); + } + } + if (!no_super_update && super != NULL) { + if (xmlCatalogIsEmpty(super)) { + remove(XML_SGML_DEFAULT_CATALOG); + } else { + out = fopen(XML_SGML_DEFAULT_CATALOG, "w"); + if (out == NULL) { + fprintf(stderr, + "could not open %s for saving\n", + XML_SGML_DEFAULT_CATALOG); + exit_value = 2; + noout = 0; + } else { + + xmlACatalogDump(super, out); + fclose(out); + } + } + } + } else { + xmlACatalogDump(catal, stdout); + } + i += 2; + } else { + if ((!strcmp(argv[i], "-add")) || + (!strcmp(argv[i], "--add"))) { + if ((argv[i + 3] == NULL) || (argv[i + 3][0] == 0)) + ret = xmlCatalogAdd(BAD_CAST argv[i + 1], NULL, + BAD_CAST argv[i + 2]); + else + ret = xmlCatalogAdd(BAD_CAST argv[i + 1], + BAD_CAST argv[i + 2], + BAD_CAST argv[i + 3]); + if (ret != 0) { + printf("add command failed\n"); + exit_value = 3; + } + i += 3; + } else if ((!strcmp(argv[i], "-del")) || + (!strcmp(argv[i], "--del"))) { + ret = xmlCatalogRemove(BAD_CAST argv[i + 1]); + if (ret < 0) { + fprintf(stderr, "Failed to remove entry %s\n", + argv[i + 1]); + exit_value = 1; + } + i += 1; + } + } + } + + } else if (shell) { + usershell(); + } else { + for (i++; i < argc; i++) { + xmlURIPtr uri; + xmlChar *ans; + + uri = xmlParseURI(argv[i]); + if (uri == NULL) { + ans = xmlCatalogResolvePublic((const xmlChar *) argv[i]); + if (ans == NULL) { + printf("No entry for PUBLIC %s\n", argv[i]); + exit_value = 4; + } else { + printf("%s\n", (char *) ans); + xmlFree(ans); + } + } else { + xmlFreeURI(uri); + ans = xmlCatalogResolveSystem((const xmlChar *) argv[i]); + if (ans == NULL) { + printf("No entry for SYSTEM %s\n", argv[i]); + ans = xmlCatalogResolveURI ((const xmlChar *) argv[i]); + if (ans == NULL) { + printf ("No entry for URI %s\n", argv[i]); + exit_value = 4; + } else { + printf("%s\n", (char *) ans); + xmlFree (ans); + } + } else { + printf("%s\n", (char *) ans); + xmlFree(ans); + } + } + } + } + if ((!sgml) && ((add) || (del) || (create) || (convert))) { + if (noout && filename && *filename) { + FILE *out; + + out = fopen(filename, "w"); + if (out == NULL) { + fprintf(stderr, "could not open %s for saving\n", filename); + exit_value = 2; + noout = 0; + } else { + xmlCatalogDump(out); + } + } else { + xmlCatalogDump(stdout); + } + } + + /* + * Cleanup and check for memory leaks + */ + xmlCleanupParser(); + xmlMemoryDump(); + return(exit_value); +} +#else +int main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) { + fprintf(stderr, "libxml was not compiled with catalog and output support\n"); + return(1); +} +#endif diff --git a/android/native/libxml2/xmllint.c b/android/native/libxml2/xmllint.c new file mode 100644 index 0000000000..be06e4bab2 --- /dev/null +++ b/android/native/libxml2/xmllint.c @@ -0,0 +1,3646 @@ +/* + * xmllint.c : a small tester program for XML input. + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + */ + +#include "libxml.h" + +#include +#include +#include + +#if defined (_WIN32) && !defined(__CYGWIN__) +#if defined (_MSC_VER) || defined(__BORLANDC__) +#include +#pragma comment(lib, "ws2_32.lib") +#define gettimeofday(p1,p2) +#endif /* _MSC_VER */ +#endif /* _WIN32 */ + +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_TIME_H +#include +#endif + +#ifdef __MINGW32__ +#define _WINSOCKAPI_ +#include +#include +#undef XML_SOCKLEN_T +#define XML_SOCKLEN_T unsigned int +#endif + +#ifdef HAVE_SYS_TIMEB_H +#include +#endif + +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_SYS_MMAN_H +#include +/* seems needed for Solaris */ +#ifndef MAP_FAILED +#define MAP_FAILED ((void *) -1) +#endif +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_LIBREADLINE +#include +#ifdef HAVE_LIBHISTORY +#include +#endif +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef LIBXML_XINCLUDE_ENABLED +#include +#endif +#ifdef LIBXML_CATALOG_ENABLED +#include +#endif +#include +#include +#ifdef LIBXML_SCHEMATRON_ENABLED +#include +#endif +#ifdef LIBXML_SCHEMAS_ENABLED +#include +#include +#endif +#ifdef LIBXML_PATTERN_ENABLED +#include +#endif +#ifdef LIBXML_C14N_ENABLED +#include +#endif +#ifdef LIBXML_OUTPUT_ENABLED +#include +#endif + +#ifndef XML_XML_DEFAULT_CATALOG +#define XML_XML_DEFAULT_CATALOG "file:///etc/xml/catalog" +#endif + +typedef enum { + XMLLINT_RETURN_OK = 0, /* No error */ + XMLLINT_ERR_UNCLASS = 1, /* Unclassified */ + XMLLINT_ERR_DTD = 2, /* Error in DTD */ + XMLLINT_ERR_VALID = 3, /* Validation error */ + XMLLINT_ERR_RDFILE = 4, /* CtxtReadFile error */ + XMLLINT_ERR_SCHEMACOMP = 5, /* Schema compilation */ + XMLLINT_ERR_OUT = 6, /* Error writing output */ + XMLLINT_ERR_SCHEMAPAT = 7, /* Error in schema pattern */ + XMLLINT_ERR_RDREGIS = 8, /* Error in Reader registration */ + XMLLINT_ERR_MEM = 9, /* Out of memory error */ + XMLLINT_ERR_XPATH = 10 /* XPath evaluation error */ +} xmllintReturnCode; +#ifdef LIBXML_DEBUG_ENABLED +static int shell = 0; +static int debugent = 0; +#endif +static int debug = 0; +static int maxmem = 0; +#ifdef LIBXML_TREE_ENABLED +static int copy = 0; +#endif /* LIBXML_TREE_ENABLED */ +static int recovery = 0; +static int noent = 0; +static int noenc = 0; +static int noblanks = 0; +static int noout = 0; +static int nowrap = 0; +#ifdef LIBXML_OUTPUT_ENABLED +static int format = 0; +static const char *output = NULL; +static int compress = 0; +static int oldout = 0; +#endif /* LIBXML_OUTPUT_ENABLED */ +#ifdef LIBXML_VALID_ENABLED +static int valid = 0; +static int postvalid = 0; +static char * dtdvalid = NULL; +static char * dtdvalidfpi = NULL; +#endif +#ifdef LIBXML_SCHEMAS_ENABLED +static char * relaxng = NULL; +static xmlRelaxNGPtr relaxngschemas = NULL; +static char * schema = NULL; +static xmlSchemaPtr wxschemas = NULL; +#endif +#ifdef LIBXML_SCHEMATRON_ENABLED +static char * schematron = NULL; +static xmlSchematronPtr wxschematron = NULL; +#endif +static int repeat = 0; +static int insert = 0; +static int htmlout = 0; +#ifdef LIBXML_PUSH_ENABLED +static int push = 0; +#endif /* LIBXML_PUSH_ENABLED */ +#ifdef HAVE_SYS_MMAN_H +static int memory = 0; +#endif +static int testIO = 0; +static char *encoding = NULL; +#ifdef LIBXML_XINCLUDE_ENABLED +static int xinclude = 0; +#endif +static int dtdattrs = 0; +static int loaddtd = 0; +static xmllintReturnCode progresult = XMLLINT_RETURN_OK; +static int timing = 0; +static int generate = 0; +static int dropdtd = 0; +#ifdef LIBXML_CATALOG_ENABLED +static int catalogs = 0; +static int nocatalogs = 0; +#endif +#ifdef LIBXML_C14N_ENABLED +static int canonical = 0; +static int canonical_11 = 0; +static int exc_canonical = 0; +#endif +#ifdef LIBXML_READER_ENABLED +static int stream = 0; +static int walker = 0; +#endif /* LIBXML_READER_ENABLED */ +static int chkregister = 0; +static int nbregister = 0; +#ifdef LIBXML_SAX1_ENABLED +static int sax1 = 0; +#endif /* LIBXML_SAX1_ENABLED */ +#ifdef LIBXML_PATTERN_ENABLED +static const char *pattern = NULL; +static xmlPatternPtr patternc = NULL; +static xmlStreamCtxtPtr patstream = NULL; +#endif +#ifdef LIBXML_XPATH_ENABLED +static const char *xpathquery = NULL; +#endif +static int options = XML_PARSE_COMPACT; +static int sax = 0; +static int oldxml10 = 0; + +/************************************************************************ + * * + * Entity loading control and customization. * + * * + ************************************************************************/ +#define MAX_PATHS 64 +#ifdef _WIN32 +# define PATH_SEPARATOR ';' +#else +# define PATH_SEPARATOR ':' +#endif +static xmlChar *paths[MAX_PATHS + 1]; +static int nbpaths = 0; +static int load_trace = 0; + +static +void parsePath(const xmlChar *path) { + const xmlChar *cur; + + if (path == NULL) + return; + while (*path != 0) { + if (nbpaths >= MAX_PATHS) { + fprintf(stderr, "MAX_PATHS reached: too many paths\n"); + return; + } + cur = path; + while ((*cur == ' ') || (*cur == PATH_SEPARATOR)) + cur++; + path = cur; + while ((*cur != 0) && (*cur != ' ') && (*cur != PATH_SEPARATOR)) + cur++; + if (cur != path) { + paths[nbpaths] = xmlStrndup(path, cur - path); + if (paths[nbpaths] != NULL) + nbpaths++; + path = cur; + } + } +} + +static xmlExternalEntityLoader defaultEntityLoader = NULL; + +static xmlParserInputPtr +xmllintExternalEntityLoader(const char *URL, const char *ID, + xmlParserCtxtPtr ctxt) { + xmlParserInputPtr ret; + warningSAXFunc warning = NULL; + errorSAXFunc err = NULL; + + int i; + const char *lastsegment = URL; + const char *iter = URL; + + if ((nbpaths > 0) && (iter != NULL)) { + while (*iter != 0) { + if (*iter == '/') + lastsegment = iter + 1; + iter++; + } + } + + if ((ctxt != NULL) && (ctxt->sax != NULL)) { + warning = ctxt->sax->warning; + err = ctxt->sax->error; + ctxt->sax->warning = NULL; + ctxt->sax->error = NULL; + } + + if (defaultEntityLoader != NULL) { + ret = defaultEntityLoader(URL, ID, ctxt); + if (ret != NULL) { + if (warning != NULL) + ctxt->sax->warning = warning; + if (err != NULL) + ctxt->sax->error = err; + if (load_trace) { + fprintf \ + (stderr, + "Loaded URL=\"%s\" ID=\"%s\"\n", + URL ? URL : "(null)", + ID ? ID : "(null)"); + } + return(ret); + } + } + for (i = 0;i < nbpaths;i++) { + xmlChar *newURL; + + newURL = xmlStrdup((const xmlChar *) paths[i]); + newURL = xmlStrcat(newURL, (const xmlChar *) "/"); + newURL = xmlStrcat(newURL, (const xmlChar *) lastsegment); + if (newURL != NULL) { + ret = defaultEntityLoader((const char *)newURL, ID, ctxt); + if (ret != NULL) { + if (warning != NULL) + ctxt->sax->warning = warning; + if (err != NULL) + ctxt->sax->error = err; + if (load_trace) { + fprintf \ + (stderr, + "Loaded URL=\"%s\" ID=\"%s\"\n", + newURL, + ID ? ID : "(null)"); + } + xmlFree(newURL); + return(ret); + } + xmlFree(newURL); + } + } + if (err != NULL) + ctxt->sax->error = err; + if (warning != NULL) { + ctxt->sax->warning = warning; + if (URL != NULL) + warning(ctxt, "failed to load external entity \"%s\"\n", URL); + else if (ID != NULL) + warning(ctxt, "failed to load external entity \"%s\"\n", ID); + } + return(NULL); +} +/************************************************************************ + * * + * Memory allocation consumption debugging * + * * + ************************************************************************/ + +static void +OOM(void) +{ + fprintf(stderr, "Ran out of memory needs > %d bytes\n", maxmem); + progresult = XMLLINT_ERR_MEM; +} + +static void +myFreeFunc(void *mem) +{ + xmlMemFree(mem); +} +static void * +myMallocFunc(size_t size) +{ + void *ret; + + ret = xmlMemMalloc(size); + if (ret != NULL) { + if (xmlMemUsed() > maxmem) { + OOM(); + xmlMemFree(ret); + return (NULL); + } + } + return (ret); +} +static void * +myReallocFunc(void *mem, size_t size) +{ + void *ret; + + ret = xmlMemRealloc(mem, size); + if (ret != NULL) { + if (xmlMemUsed() > maxmem) { + OOM(); + xmlMemFree(ret); + return (NULL); + } + } + return (ret); +} +static char * +myStrdupFunc(const char *str) +{ + char *ret; + + ret = xmlMemoryStrdup(str); + if (ret != NULL) { + if (xmlMemUsed() > maxmem) { + OOM(); + xmlFree(ret); + return (NULL); + } + } + return (ret); +} +/************************************************************************ + * * + * Internal timing routines to remove the necessity to have * + * unix-specific function calls. * + * * + ************************************************************************/ + +#ifndef HAVE_GETTIMEOFDAY +#ifdef HAVE_SYS_TIMEB_H +#ifdef HAVE_SYS_TIME_H +#ifdef HAVE_FTIME + +static int +my_gettimeofday(struct timeval *tvp, void *tzp) +{ + struct timeb timebuffer; + + ftime(&timebuffer); + if (tvp) { + tvp->tv_sec = timebuffer.time; + tvp->tv_usec = timebuffer.millitm * 1000L; + } + return (0); +} +#define HAVE_GETTIMEOFDAY 1 +#define gettimeofday my_gettimeofday + +#endif /* HAVE_FTIME */ +#endif /* HAVE_SYS_TIME_H */ +#endif /* HAVE_SYS_TIMEB_H */ +#endif /* !HAVE_GETTIMEOFDAY */ + +#if defined(HAVE_GETTIMEOFDAY) +static struct timeval begin, end; + +/* + * startTimer: call where you want to start timing + */ +static void +startTimer(void) +{ + gettimeofday(&begin, NULL); +} + +/* + * endTimer: call where you want to stop timing and to print out a + * message about the timing performed; format is a printf + * type argument + */ +static void XMLCDECL +endTimer(const char *fmt, ...) +{ + long msec; + va_list ap; + + gettimeofday(&end, NULL); + msec = end.tv_sec - begin.tv_sec; + msec *= 1000; + msec += (end.tv_usec - begin.tv_usec) / 1000; + +#ifndef HAVE_STDARG_H +#error "endTimer required stdarg functions" +#endif + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + + fprintf(stderr, " took %ld ms\n", msec); +} +#elif defined(HAVE_TIME_H) +/* + * No gettimeofday function, so we have to make do with calling clock. + * This is obviously less accurate, but there's little we can do about + * that. + */ +#ifndef CLOCKS_PER_SEC +#define CLOCKS_PER_SEC 100 +#endif + +static clock_t begin, end; +static void +startTimer(void) +{ + begin = clock(); +} +static void XMLCDECL +endTimer(const char *fmt, ...) +{ + long msec; + va_list ap; + + end = clock(); + msec = ((end - begin) * 1000) / CLOCKS_PER_SEC; + +#ifndef HAVE_STDARG_H +#error "endTimer required stdarg functions" +#endif + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, " took %ld ms\n", msec); +} +#else + +/* + * We don't have a gettimeofday or time.h, so we just don't do timing + */ +static void +startTimer(void) +{ + /* + * Do nothing + */ +} +static void XMLCDECL +endTimer(char *format, ...) +{ + /* + * We cannot do anything because we don't have a timing function + */ +#ifdef HAVE_STDARG_H + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); + fprintf(stderr, " was not timed\n", msec); +#else + /* We don't have gettimeofday, time or stdarg.h, what crazy world is + * this ?! + */ +#endif +} +#endif +/************************************************************************ + * * + * HTML ouput * + * * + ************************************************************************/ +static char buffer[50000]; + +static void +xmlHTMLEncodeSend(void) { + char *result; + + result = (char *) xmlEncodeEntitiesReentrant(NULL, BAD_CAST buffer); + if (result) { + xmlGenericError(xmlGenericErrorContext, "%s", result); + xmlFree(result); + } + buffer[0] = 0; +} + +/** + * xmlHTMLPrintFileInfo: + * @input: an xmlParserInputPtr input + * + * Displays the associated file and line informations for the current input + */ + +static void +xmlHTMLPrintFileInfo(xmlParserInputPtr input) { + int len; + xmlGenericError(xmlGenericErrorContext, "

"); + + len = strlen(buffer); + if (input != NULL) { + if (input->filename) { + snprintf(&buffer[len], sizeof(buffer) - len, "%s:%d: ", input->filename, + input->line); + } else { + snprintf(&buffer[len], sizeof(buffer) - len, "Entity: line %d: ", input->line); + } + } + xmlHTMLEncodeSend(); +} + +/** + * xmlHTMLPrintFileContext: + * @input: an xmlParserInputPtr input + * + * Displays current context within the input content for error tracking + */ + +static void +xmlHTMLPrintFileContext(xmlParserInputPtr input) { + const xmlChar *cur, *base; + int len; + int n; + + if (input == NULL) return; + xmlGenericError(xmlGenericErrorContext, "

\n");
+    cur = input->cur;
+    base = input->base;
+    while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
+	cur--;
+    }
+    n = 0;
+    while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
+        cur--;
+    if ((*cur == '\n') || (*cur == '\r')) cur++;
+    base = cur;
+    n = 0;
+    while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
+	len = strlen(buffer);
+        snprintf(&buffer[len], sizeof(buffer) - len, "%c",
+		    (unsigned char) *cur++);
+	n++;
+    }
+    len = strlen(buffer);
+    snprintf(&buffer[len], sizeof(buffer) - len, "\n");
+    cur = input->cur;
+    while ((*cur == '\n') || (*cur == '\r'))
+	cur--;
+    n = 0;
+    while ((cur != base) && (n++ < 80)) {
+	len = strlen(buffer);
+        snprintf(&buffer[len], sizeof(buffer) - len, " ");
+        base++;
+    }
+    len = strlen(buffer);
+    snprintf(&buffer[len], sizeof(buffer) - len, "^\n");
+    xmlHTMLEncodeSend();
+    xmlGenericError(xmlGenericErrorContext, "
"); +} + +/** + * xmlHTMLError: + * @ctx: an XML parser context + * @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. + */ +static void XMLCDECL +xmlHTMLError(void *ctx, const char *msg, ...) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + xmlParserInputPtr input; + va_list args; + int len; + + buffer[0] = 0; + input = ctxt->input; + if ((input != NULL) && (input->filename == NULL) && (ctxt->inputNr > 1)) { + input = ctxt->inputTab[ctxt->inputNr - 2]; + } + + xmlHTMLPrintFileInfo(input); + + xmlGenericError(xmlGenericErrorContext, "error: "); + va_start(args, msg); + len = strlen(buffer); + vsnprintf(&buffer[len], sizeof(buffer) - len, msg, args); + va_end(args); + xmlHTMLEncodeSend(); + xmlGenericError(xmlGenericErrorContext, "

\n"); + + xmlHTMLPrintFileContext(input); + xmlHTMLEncodeSend(); +} + +/** + * xmlHTMLWarning: + * @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. + */ +static void XMLCDECL +xmlHTMLWarning(void *ctx, const char *msg, ...) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + xmlParserInputPtr input; + va_list args; + int len; + + buffer[0] = 0; + input = ctxt->input; + if ((input != NULL) && (input->filename == NULL) && (ctxt->inputNr > 1)) { + input = ctxt->inputTab[ctxt->inputNr - 2]; + } + + + xmlHTMLPrintFileInfo(input); + + xmlGenericError(xmlGenericErrorContext, "warning: "); + va_start(args, msg); + len = strlen(buffer); + vsnprintf(&buffer[len], sizeof(buffer) - len, msg, args); + va_end(args); + xmlHTMLEncodeSend(); + xmlGenericError(xmlGenericErrorContext, "

\n"); + + xmlHTMLPrintFileContext(input); + xmlHTMLEncodeSend(); +} + +/** + * xmlHTMLValidityError: + * @ctx: an XML parser context + * @msg: the message to display/transmit + * @...: extra parameters for the message display + * + * Display and format an validity error messages, gives file, + * line, position and extra parameters. + */ +static void XMLCDECL +xmlHTMLValidityError(void *ctx, const char *msg, ...) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + xmlParserInputPtr input; + va_list args; + int len; + + buffer[0] = 0; + input = ctxt->input; + if ((input->filename == NULL) && (ctxt->inputNr > 1)) + input = ctxt->inputTab[ctxt->inputNr - 2]; + + xmlHTMLPrintFileInfo(input); + + xmlGenericError(xmlGenericErrorContext, "validity error: "); + len = strlen(buffer); + va_start(args, msg); + vsnprintf(&buffer[len], sizeof(buffer) - len, msg, args); + va_end(args); + xmlHTMLEncodeSend(); + xmlGenericError(xmlGenericErrorContext, "

\n"); + + xmlHTMLPrintFileContext(input); + xmlHTMLEncodeSend(); + progresult = XMLLINT_ERR_VALID; +} + +/** + * xmlHTMLValidityWarning: + * @ctx: an XML parser context + * @msg: the message to display/transmit + * @...: extra parameters for the message display + * + * Display and format a validity warning messages, gives file, line, + * position and extra parameters. + */ +static void XMLCDECL +xmlHTMLValidityWarning(void *ctx, const char *msg, ...) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + xmlParserInputPtr input; + va_list args; + int len; + + buffer[0] = 0; + input = ctxt->input; + if ((input->filename == NULL) && (ctxt->inputNr > 1)) + input = ctxt->inputTab[ctxt->inputNr - 2]; + + xmlHTMLPrintFileInfo(input); + + xmlGenericError(xmlGenericErrorContext, "validity warning: "); + va_start(args, msg); + len = strlen(buffer); + vsnprintf(&buffer[len], sizeof(buffer) - len, msg, args); + va_end(args); + xmlHTMLEncodeSend(); + xmlGenericError(xmlGenericErrorContext, "

\n"); + + xmlHTMLPrintFileContext(input); + xmlHTMLEncodeSend(); +} + +/************************************************************************ + * * + * Shell Interface * + * * + ************************************************************************/ +#ifdef LIBXML_DEBUG_ENABLED +#ifdef LIBXML_XPATH_ENABLED +/** + * xmlShellReadline: + * @prompt: the prompt value + * + * Read a string + * + * Returns a pointer to it or NULL on EOF the caller is expected to + * free the returned string. + */ +static char * +xmlShellReadline(char *prompt) { +#ifdef HAVE_LIBREADLINE + char *line_read; + + /* Get a line from the user. */ + line_read = readline (prompt); + + /* If the line has any text in it, save it on the history. */ + if (line_read && *line_read) + add_history (line_read); + + return (line_read); +#else + char line_read[501]; + char *ret; + int len; + + if (prompt != NULL) + fprintf(stdout, "%s", prompt); + if (!fgets(line_read, 500, stdin)) + return(NULL); + line_read[500] = 0; + len = strlen(line_read); + ret = (char *) malloc(len + 1); + if (ret != NULL) { + memcpy (ret, line_read, len + 1); + } + return(ret); +#endif +} +#endif /* LIBXML_XPATH_ENABLED */ +#endif /* LIBXML_DEBUG_ENABLED */ + +/************************************************************************ + * * + * I/O Interfaces * + * * + ************************************************************************/ + +static int myRead(FILE *f, char * buf, int len) { + return(fread(buf, 1, len, f)); +} +static void myClose(FILE *f) { + if (f != stdin) { + fclose(f); + } +} + +/************************************************************************ + * * + * SAX based tests * + * * + ************************************************************************/ + +/* + * empty SAX block + */ +static xmlSAXHandler emptySAXHandlerStruct = { + NULL, /* internalSubset */ + NULL, /* isStandalone */ + NULL, /* hasInternalSubset */ + NULL, /* hasExternalSubset */ + NULL, /* resolveEntity */ + NULL, /* getEntity */ + NULL, /* entityDecl */ + NULL, /* notationDecl */ + NULL, /* attributeDecl */ + NULL, /* elementDecl */ + NULL, /* unparsedEntityDecl */ + NULL, /* setDocumentLocator */ + NULL, /* startDocument */ + NULL, /* endDocument */ + NULL, /* startElement */ + NULL, /* endElement */ + NULL, /* reference */ + NULL, /* characters */ + NULL, /* ignorableWhitespace */ + NULL, /* processingInstruction */ + NULL, /* comment */ + NULL, /* xmlParserWarning */ + NULL, /* xmlParserError */ + NULL, /* xmlParserError */ + NULL, /* getParameterEntity */ + NULL, /* cdataBlock; */ + NULL, /* externalSubset; */ + XML_SAX2_MAGIC, + NULL, + NULL, /* startElementNs */ + NULL, /* endElementNs */ + NULL /* xmlStructuredErrorFunc */ +}; + +static xmlSAXHandlerPtr emptySAXHandler = &emptySAXHandlerStruct; +extern xmlSAXHandlerPtr debugSAXHandler; +static int callbacks; + +/** + * isStandaloneDebug: + * @ctxt: An XML parser context + * + * Is this document tagged standalone ? + * + * Returns 1 if true + */ +static int +isStandaloneDebug(void *ctx ATTRIBUTE_UNUSED) +{ + callbacks++; + if (noout) + return(0); + fprintf(stdout, "SAX.isStandalone()\n"); + return(0); +} + +/** + * hasInternalSubsetDebug: + * @ctxt: An XML parser context + * + * Does this document has an internal subset + * + * Returns 1 if true + */ +static int +hasInternalSubsetDebug(void *ctx ATTRIBUTE_UNUSED) +{ + callbacks++; + if (noout) + return(0); + fprintf(stdout, "SAX.hasInternalSubset()\n"); + return(0); +} + +/** + * hasExternalSubsetDebug: + * @ctxt: An XML parser context + * + * Does this document has an external subset + * + * Returns 1 if true + */ +static int +hasExternalSubsetDebug(void *ctx ATTRIBUTE_UNUSED) +{ + callbacks++; + if (noout) + return(0); + fprintf(stdout, "SAX.hasExternalSubset()\n"); + return(0); +} + +/** + * internalSubsetDebug: + * @ctxt: An XML parser context + * + * Does this document has an internal subset + */ +static void +internalSubsetDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, + const xmlChar *ExternalID, const xmlChar *SystemID) +{ + callbacks++; + if (noout) + return; + fprintf(stdout, "SAX.internalSubset(%s,", name); + if (ExternalID == NULL) + fprintf(stdout, " ,"); + else + fprintf(stdout, " %s,", ExternalID); + if (SystemID == NULL) + fprintf(stdout, " )\n"); + else + fprintf(stdout, " %s)\n", SystemID); +} + +/** + * externalSubsetDebug: + * @ctxt: An XML parser context + * + * Does this document has an external subset + */ +static void +externalSubsetDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, + const xmlChar *ExternalID, const xmlChar *SystemID) +{ + callbacks++; + if (noout) + return; + fprintf(stdout, "SAX.externalSubset(%s,", name); + if (ExternalID == NULL) + fprintf(stdout, " ,"); + else + fprintf(stdout, " %s,", ExternalID); + if (SystemID == NULL) + fprintf(stdout, " )\n"); + else + fprintf(stdout, " %s)\n", SystemID); +} + +/** + * resolveEntityDebug: + * @ctxt: An XML parser context + * @publicId: The public ID of the entity + * @systemId: The system ID of the entity + * + * Special entity resolver, better left to the parser, it has + * more context than the application layer. + * The default behaviour is to NOT resolve the entities, in that case + * the ENTITY_REF nodes are built in the structure (and the parameter + * values). + * + * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour. + */ +static xmlParserInputPtr +resolveEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *publicId, const xmlChar *systemId) +{ + callbacks++; + if (noout) + return(NULL); + /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */ + + + fprintf(stdout, "SAX.resolveEntity("); + if (publicId != NULL) + fprintf(stdout, "%s", (char *)publicId); + else + fprintf(stdout, " "); + if (systemId != NULL) + fprintf(stdout, ", %s)\n", (char *)systemId); + else + fprintf(stdout, ", )\n"); + return(NULL); +} + +/** + * getEntityDebug: + * @ctxt: An XML parser context + * @name: The entity name + * + * Get an entity by name + * + * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour. + */ +static xmlEntityPtr +getEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name) +{ + callbacks++; + if (noout) + return(NULL); + fprintf(stdout, "SAX.getEntity(%s)\n", name); + return(NULL); +} + +/** + * getParameterEntityDebug: + * @ctxt: An XML parser context + * @name: The entity name + * + * Get a parameter entity by name + * + * Returns the xmlParserInputPtr + */ +static xmlEntityPtr +getParameterEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name) +{ + callbacks++; + if (noout) + return(NULL); + fprintf(stdout, "SAX.getParameterEntity(%s)\n", name); + return(NULL); +} + + +/** + * entityDeclDebug: + * @ctxt: An XML parser context + * @name: the entity name + * @type: the entity type + * @publicId: The public ID of the entity + * @systemId: The system ID of the entity + * @content: the entity value (without processing). + * + * An entity definition has been parsed + */ +static void +entityDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, int type, + const xmlChar *publicId, const xmlChar *systemId, xmlChar *content) +{ +const xmlChar *nullstr = BAD_CAST "(null)"; + /* not all libraries handle printing null pointers nicely */ + if (publicId == NULL) + publicId = nullstr; + if (systemId == NULL) + systemId = nullstr; + if (content == NULL) + content = (xmlChar *)nullstr; + callbacks++; + if (noout) + return; + fprintf(stdout, "SAX.entityDecl(%s, %d, %s, %s, %s)\n", + name, type, publicId, systemId, content); +} + +/** + * attributeDeclDebug: + * @ctxt: An XML parser context + * @name: the attribute name + * @type: the attribute type + * + * An attribute definition has been parsed + */ +static void +attributeDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar * elem, + const xmlChar * name, int type, int def, + const xmlChar * defaultValue, xmlEnumerationPtr tree) +{ + callbacks++; + if (noout) + return; + if (defaultValue == NULL) + fprintf(stdout, "SAX.attributeDecl(%s, %s, %d, %d, NULL, ...)\n", + elem, name, type, def); + else + fprintf(stdout, "SAX.attributeDecl(%s, %s, %d, %d, %s, ...)\n", + elem, name, type, def, defaultValue); + xmlFreeEnumeration(tree); +} + +/** + * elementDeclDebug: + * @ctxt: An XML parser context + * @name: the element name + * @type: the element type + * @content: the element value (without processing). + * + * An element definition has been parsed + */ +static void +elementDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, int type, + xmlElementContentPtr content ATTRIBUTE_UNUSED) +{ + callbacks++; + if (noout) + return; + fprintf(stdout, "SAX.elementDecl(%s, %d, ...)\n", + name, type); +} + +/** + * notationDeclDebug: + * @ctxt: An XML parser context + * @name: The name of the notation + * @publicId: The public ID of the entity + * @systemId: The system ID of the entity + * + * What to do when a notation declaration has been parsed. + */ +static void +notationDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, + const xmlChar *publicId, const xmlChar *systemId) +{ + callbacks++; + if (noout) + return; + fprintf(stdout, "SAX.notationDecl(%s, %s, %s)\n", + (char *) name, (char *) publicId, (char *) systemId); +} + +/** + * unparsedEntityDeclDebug: + * @ctxt: An XML parser context + * @name: The name of the entity + * @publicId: The public ID of the entity + * @systemId: The system ID of the entity + * @notationName: the name of the notation + * + * What to do when an unparsed entity declaration is parsed + */ +static void +unparsedEntityDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, + const xmlChar *publicId, const xmlChar *systemId, + const xmlChar *notationName) +{ +const xmlChar *nullstr = BAD_CAST "(null)"; + + if (publicId == NULL) + publicId = nullstr; + if (systemId == NULL) + systemId = nullstr; + if (notationName == NULL) + notationName = nullstr; + callbacks++; + if (noout) + return; + fprintf(stdout, "SAX.unparsedEntityDecl(%s, %s, %s, %s)\n", + (char *) name, (char *) publicId, (char *) systemId, + (char *) notationName); +} + +/** + * setDocumentLocatorDebug: + * @ctxt: An XML parser context + * @loc: A SAX Locator + * + * Receive the document locator at startup, actually xmlDefaultSAXLocator + * Everything is available on the context, so this is useless in our case. + */ +static void +setDocumentLocatorDebug(void *ctx ATTRIBUTE_UNUSED, xmlSAXLocatorPtr loc ATTRIBUTE_UNUSED) +{ + callbacks++; + if (noout) + return; + fprintf(stdout, "SAX.setDocumentLocator()\n"); +} + +/** + * startDocumentDebug: + * @ctxt: An XML parser context + * + * called when the document start being processed. + */ +static void +startDocumentDebug(void *ctx ATTRIBUTE_UNUSED) +{ + callbacks++; + if (noout) + return; + fprintf(stdout, "SAX.startDocument()\n"); +} + +/** + * endDocumentDebug: + * @ctxt: An XML parser context + * + * called when the document end has been detected. + */ +static void +endDocumentDebug(void *ctx ATTRIBUTE_UNUSED) +{ + callbacks++; + if (noout) + return; + fprintf(stdout, "SAX.endDocument()\n"); +} + +/** + * startElementDebug: + * @ctxt: An XML parser context + * @name: The element name + * + * called when an opening tag has been processed. + */ +static void +startElementDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, const xmlChar **atts) +{ + int i; + + callbacks++; + if (noout) + return; + fprintf(stdout, "SAX.startElement(%s", (char *) name); + if (atts != NULL) { + for (i = 0;(atts[i] != NULL);i++) { + fprintf(stdout, ", %s='", atts[i++]); + if (atts[i] != NULL) + fprintf(stdout, "%s'", atts[i]); + } + } + fprintf(stdout, ")\n"); +} + +/** + * endElementDebug: + * @ctxt: An XML parser context + * @name: The element name + * + * called when the end of an element has been detected. + */ +static void +endElementDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name) +{ + callbacks++; + if (noout) + return; + fprintf(stdout, "SAX.endElement(%s)\n", (char *) name); +} + +/** + * charactersDebug: + * @ctxt: An XML parser context + * @ch: a xmlChar string + * @len: the number of xmlChar + * + * receiving some chars from the parser. + * Question: how much at a time ??? + */ +static void +charactersDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len) +{ + char out[40]; + int i; + + callbacks++; + if (noout) + return; + for (i = 0;(i 0) { + fprintf(stderr, "%s fails to validate\n", filename); + progresult = XMLLINT_ERR_VALID; + } else { + fprintf(stderr, "%s validation generated an internal error\n", + filename); + progresult = XMLLINT_ERR_VALID; + } + } + xmlSchemaFreeValidCtxt(vctxt); + } else +#endif + { + /* + * Create the parser context amd hook the input + */ + ctxt = xmlNewParserCtxt(); + if (ctxt == NULL) { + xmlFreeParserInputBuffer(buf); + goto error; + } + old_sax = ctxt->sax; + ctxt->sax = handler; + ctxt->userData = (void *) user_data; + inputStream = xmlNewIOInputStream(ctxt, buf, XML_CHAR_ENCODING_NONE); + if (inputStream == NULL) { + xmlFreeParserInputBuffer(buf); + goto error; + } + inputPush(ctxt, inputStream); + + /* do the parsing */ + xmlParseDocument(ctxt); + + if (ctxt->myDoc != NULL) { + fprintf(stderr, "SAX generated a doc !\n"); + xmlFreeDoc(ctxt->myDoc); + ctxt->myDoc = NULL; + } + } + +error: + if (ctxt != NULL) { + ctxt->sax = old_sax; + xmlFreeParserCtxt(ctxt); + } +} + +/************************************************************************ + * * + * Stream Test processing * + * * + ************************************************************************/ +#ifdef LIBXML_READER_ENABLED +static void processNode(xmlTextReaderPtr reader) { + const xmlChar *name, *value; + int type, empty; + + type = xmlTextReaderNodeType(reader); + empty = xmlTextReaderIsEmptyElement(reader); + + if (debug) { + name = xmlTextReaderConstName(reader); + if (name == NULL) + name = BAD_CAST "--"; + + value = xmlTextReaderConstValue(reader); + + + printf("%d %d %s %d %d", + xmlTextReaderDepth(reader), + type, + name, + empty, + xmlTextReaderHasValue(reader)); + if (value == NULL) + printf("\n"); + else { + printf(" %s\n", value); + } + } +#ifdef LIBXML_PATTERN_ENABLED + if (patternc) { + xmlChar *path = NULL; + int match = -1; + + if (type == XML_READER_TYPE_ELEMENT) { + /* do the check only on element start */ + match = xmlPatternMatch(patternc, xmlTextReaderCurrentNode(reader)); + + if (match) { +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED) + path = xmlGetNodePath(xmlTextReaderCurrentNode(reader)); + printf("Node %s matches pattern %s\n", path, pattern); +#else + printf("Node %s matches pattern %s\n", + xmlTextReaderConstName(reader), pattern); +#endif + } + } + if (patstream != NULL) { + int ret; + + if (type == XML_READER_TYPE_ELEMENT) { + ret = xmlStreamPush(patstream, + xmlTextReaderConstLocalName(reader), + xmlTextReaderConstNamespaceUri(reader)); + if (ret < 0) { + fprintf(stderr, "xmlStreamPush() failure\n"); + xmlFreeStreamCtxt(patstream); + patstream = NULL; + } else if (ret != match) { +#if defined(LIBXML_TREE_ENABLED) || defined(LIBXML_DEBUG_ENABLED) + if (path == NULL) { + path = xmlGetNodePath( + xmlTextReaderCurrentNode(reader)); + } +#endif + fprintf(stderr, + "xmlPatternMatch and xmlStreamPush disagree\n"); + if (path != NULL) + fprintf(stderr, " pattern %s node %s\n", + pattern, path); + else + fprintf(stderr, " pattern %s node %s\n", + pattern, xmlTextReaderConstName(reader)); + } + + } + if ((type == XML_READER_TYPE_END_ELEMENT) || + ((type == XML_READER_TYPE_ELEMENT) && (empty))) { + ret = xmlStreamPop(patstream); + if (ret < 0) { + fprintf(stderr, "xmlStreamPop() failure\n"); + xmlFreeStreamCtxt(patstream); + patstream = NULL; + } + } + } + if (path != NULL) + xmlFree(path); + } +#endif +} + +static void streamFile(char *filename) { + xmlTextReaderPtr reader; + int ret; +#ifdef HAVE_SYS_MMAN_H + int fd = -1; + struct stat info; + const char *base = NULL; + xmlParserInputBufferPtr input = NULL; + + if (memory) { + if (stat(filename, &info) < 0) + return; + if ((fd = open(filename, O_RDONLY)) < 0) + return; + base = mmap(NULL, info.st_size, PROT_READ, MAP_SHARED, fd, 0) ; + if (base == (void *) MAP_FAILED) + return; + + reader = xmlReaderForMemory(base, info.st_size, filename, + NULL, options); + } else +#endif + reader = xmlReaderForFile(filename, NULL, options); +#ifdef LIBXML_PATTERN_ENABLED + if (pattern != NULL) { + patternc = xmlPatterncompile((const xmlChar *) pattern, NULL, 0, NULL); + if (patternc == NULL) { + xmlGenericError(xmlGenericErrorContext, + "Pattern %s failed to compile\n", pattern); + progresult = XMLLINT_ERR_SCHEMAPAT; + pattern = NULL; + } + } + if (patternc != NULL) { + patstream = xmlPatternGetStreamCtxt(patternc); + if (patstream != NULL) { + ret = xmlStreamPush(patstream, NULL, NULL); + if (ret < 0) { + fprintf(stderr, "xmlStreamPush() failure\n"); + xmlFreeStreamCtxt(patstream); + patstream = NULL; + } + } + } +#endif + + + if (reader != NULL) { +#ifdef LIBXML_VALID_ENABLED + if (valid) + xmlTextReaderSetParserProp(reader, XML_PARSER_VALIDATE, 1); + else +#endif /* LIBXML_VALID_ENABLED */ + xmlTextReaderSetParserProp(reader, XML_PARSER_LOADDTD, 1); +#ifdef LIBXML_SCHEMAS_ENABLED + if (relaxng != NULL) { + if ((timing) && (!repeat)) { + startTimer(); + } + ret = xmlTextReaderRelaxNGValidate(reader, relaxng); + if (ret < 0) { + xmlGenericError(xmlGenericErrorContext, + "Relax-NG schema %s failed to compile\n", relaxng); + progresult = XMLLINT_ERR_SCHEMACOMP; + relaxng = NULL; + } + if ((timing) && (!repeat)) { + endTimer("Compiling the schemas"); + } + } + if (schema != NULL) { + if ((timing) && (!repeat)) { + startTimer(); + } + ret = xmlTextReaderSchemaValidate(reader, schema); + if (ret < 0) { + xmlGenericError(xmlGenericErrorContext, + "XSD schema %s failed to compile\n", schema); + progresult = XMLLINT_ERR_SCHEMACOMP; + schema = NULL; + } + if ((timing) && (!repeat)) { + endTimer("Compiling the schemas"); + } + } +#endif + + /* + * Process all nodes in sequence + */ + if ((timing) && (!repeat)) { + startTimer(); + } + ret = xmlTextReaderRead(reader); + while (ret == 1) { + if ((debug) +#ifdef LIBXML_PATTERN_ENABLED + || (patternc) +#endif + ) + processNode(reader); + ret = xmlTextReaderRead(reader); + } + if ((timing) && (!repeat)) { +#ifdef LIBXML_SCHEMAS_ENABLED + if (relaxng != NULL) + endTimer("Parsing and validating"); + else +#endif +#ifdef LIBXML_VALID_ENABLED + if (valid) + endTimer("Parsing and validating"); + else +#endif + endTimer("Parsing"); + } + +#ifdef LIBXML_VALID_ENABLED + if (valid) { + if (xmlTextReaderIsValid(reader) != 1) { + xmlGenericError(xmlGenericErrorContext, + "Document %s does not validate\n", filename); + progresult = XMLLINT_ERR_VALID; + } + } +#endif /* LIBXML_VALID_ENABLED */ +#ifdef LIBXML_SCHEMAS_ENABLED + if ((relaxng != NULL) || (schema != NULL)) { + if (xmlTextReaderIsValid(reader) != 1) { + fprintf(stderr, "%s fails to validate\n", filename); + progresult = XMLLINT_ERR_VALID; + } else { + fprintf(stderr, "%s validates\n", filename); + } + } +#endif + /* + * Done, cleanup and status + */ + xmlFreeTextReader(reader); + if (ret != 0) { + fprintf(stderr, "%s : failed to parse\n", filename); + progresult = XMLLINT_ERR_UNCLASS; + } + } else { + fprintf(stderr, "Unable to open %s\n", filename); + progresult = XMLLINT_ERR_UNCLASS; + } +#ifdef LIBXML_PATTERN_ENABLED + if (patstream != NULL) { + xmlFreeStreamCtxt(patstream); + patstream = NULL; + } +#endif +#ifdef HAVE_SYS_MMAN_H + if (memory) { + xmlFreeParserInputBuffer(input); + munmap((char *) base, info.st_size); + close(fd); + } +#endif +} + +static void walkDoc(xmlDocPtr doc) { + xmlTextReaderPtr reader; + int ret; + +#ifdef LIBXML_PATTERN_ENABLED + xmlNodePtr root; + const xmlChar *namespaces[22]; + int i; + xmlNsPtr ns; + + root = xmlDocGetRootElement(doc); + for (ns = root->nsDef, i = 0;ns != NULL && i < 20;ns=ns->next) { + namespaces[i++] = ns->href; + namespaces[i++] = ns->prefix; + } + namespaces[i++] = NULL; + namespaces[i] = NULL; + + if (pattern != NULL) { + patternc = xmlPatterncompile((const xmlChar *) pattern, doc->dict, + 0, &namespaces[0]); + if (patternc == NULL) { + xmlGenericError(xmlGenericErrorContext, + "Pattern %s failed to compile\n", pattern); + progresult = XMLLINT_ERR_SCHEMAPAT; + pattern = NULL; + } + } + if (patternc != NULL) { + patstream = xmlPatternGetStreamCtxt(patternc); + if (patstream != NULL) { + ret = xmlStreamPush(patstream, NULL, NULL); + if (ret < 0) { + fprintf(stderr, "xmlStreamPush() failure\n"); + xmlFreeStreamCtxt(patstream); + patstream = NULL; + } + } + } +#endif /* LIBXML_PATTERN_ENABLED */ + reader = xmlReaderWalker(doc); + if (reader != NULL) { + if ((timing) && (!repeat)) { + startTimer(); + } + ret = xmlTextReaderRead(reader); + while (ret == 1) { + if ((debug) +#ifdef LIBXML_PATTERN_ENABLED + || (patternc) +#endif + ) + processNode(reader); + ret = xmlTextReaderRead(reader); + } + if ((timing) && (!repeat)) { + endTimer("walking through the doc"); + } + xmlFreeTextReader(reader); + if (ret != 0) { + fprintf(stderr, "failed to walk through the doc\n"); + progresult = XMLLINT_ERR_UNCLASS; + } + } else { + fprintf(stderr, "Failed to crate a reader from the document\n"); + progresult = XMLLINT_ERR_UNCLASS; + } +#ifdef LIBXML_PATTERN_ENABLED + if (patstream != NULL) { + xmlFreeStreamCtxt(patstream); + patstream = NULL; + } +#endif +} +#endif /* LIBXML_READER_ENABLED */ + +#ifdef LIBXML_XPATH_ENABLED +/************************************************************************ + * * + * XPath Query * + * * + ************************************************************************/ + +static void doXPathDump(xmlXPathObjectPtr cur) { + switch(cur->type) { + case XPATH_NODESET: { + int i; + xmlNodePtr node; +#ifdef LIBXML_OUTPUT_ENABLED + xmlSaveCtxtPtr ctxt; + + if (cur->nodesetval->nodeNr <= 0) { + fprintf(stderr, "XPath set is empty\n"); + progresult = XMLLINT_ERR_XPATH; + break; + } + ctxt = xmlSaveToFd(1, NULL, 0); + if (ctxt == NULL) { + fprintf(stderr, "Out of memory for XPath\n"); + progresult = XMLLINT_ERR_MEM; + return; + } + for (i = 0;i < cur->nodesetval->nodeNr;i++) { + node = cur->nodesetval->nodeTab[i]; + xmlSaveTree(ctxt, node); + } + xmlSaveClose(ctxt); +#else + printf("xpath returned %d nodes\n", cur->nodesetval->nodeNr); +#endif + break; + } + case XPATH_BOOLEAN: + if (cur->boolval) printf("true"); + else printf("false"); + break; + case XPATH_NUMBER: + switch (xmlXPathIsInf(cur->floatval)) { + case 1: + printf("Infinity"); + break; + case -1: + printf("-Infinity"); + break; + default: + if (xmlXPathIsNaN(cur->floatval)) { + printf("NaN"); + } else { + printf("%0g", cur->floatval); + } + } + break; + case XPATH_STRING: + printf("%s", (const char *) cur->stringval); + break; + case XPATH_UNDEFINED: + fprintf(stderr, "XPath Object is uninitialized\n"); + progresult = XMLLINT_ERR_XPATH; + break; + default: + fprintf(stderr, "XPath object of unexpected type\n"); + progresult = XMLLINT_ERR_XPATH; + break; + } +} + +static void doXPathQuery(xmlDocPtr doc, const char *query) { + xmlXPathContextPtr ctxt; + xmlXPathObjectPtr res; + + ctxt = xmlXPathNewContext(doc); + if (ctxt == NULL) { + fprintf(stderr, "Out of memory for XPath\n"); + progresult = XMLLINT_ERR_MEM; + return; + } + ctxt->node = xmlDocGetRootElement(doc); + res = xmlXPathEval(BAD_CAST query, ctxt); + xmlXPathFreeContext(ctxt); + + if (res == NULL) { + fprintf(stderr, "XPath evaluation failure\n"); + progresult = XMLLINT_ERR_XPATH; + return; + } + doXPathDump(res); + xmlXPathFreeObject(res); +} +#endif /* LIBXML_XPATH_ENABLED */ + +/************************************************************************ + * * + * Tree Test processing * + * * + ************************************************************************/ +static void parseAndPrintFile(char *filename, xmlParserCtxtPtr rectxt) { + xmlDocPtr doc = NULL; +#ifdef LIBXML_TREE_ENABLED + xmlDocPtr tmp; +#endif /* LIBXML_TREE_ENABLED */ + + if ((timing) && (!repeat)) + startTimer(); + + +#ifdef LIBXML_TREE_ENABLED + if (filename == NULL) { + if (generate) { + xmlNodePtr n; + + doc = xmlNewDoc(BAD_CAST "1.0"); + n = xmlNewDocNode(doc, NULL, BAD_CAST "info", NULL); + xmlNodeSetContent(n, BAD_CAST "abc"); + xmlDocSetRootElement(doc, n); + } + } +#endif /* LIBXML_TREE_ENABLED */ + else { +#ifdef LIBXML_PUSH_ENABLED + /* + * build an XML tree from a string; + */ + if (push) { + FILE *f; + + /* '-' Usually means stdin - */ + if ((filename[0] == '-') && (filename[1] == 0)) { + f = stdin; + } else { +#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__) + f = fopen(filename, "rb"); +#else + f = fopen(filename, "r"); +#endif + } + if (f != NULL) { + int ret; + int res, size = 1024; + char chars[1024]; + xmlParserCtxtPtr ctxt; + + /* if (repeat) size = 1024; */ + res = fread(chars, 1, 4, f); + if (res > 0) { + ctxt = xmlCreatePushParserCtxt(NULL, NULL, + chars, res, filename); + xmlCtxtUseOptions(ctxt, options); + while ((res = fread(chars, 1, size, f)) > 0) { + xmlParseChunk(ctxt, chars, res, 0); + } + xmlParseChunk(ctxt, chars, 0, 1); + doc = ctxt->myDoc; + ret = ctxt->wellFormed; + xmlFreeParserCtxt(ctxt); + if (!ret) { + xmlFreeDoc(doc); + doc = NULL; + } + } + if (f != stdin) + fclose(f); + } + } else +#endif /* LIBXML_PUSH_ENABLED */ + if (testIO) { + if ((filename[0] == '-') && (filename[1] == 0)) { + doc = xmlReadFd(0, NULL, NULL, options); + } else { + FILE *f; + +#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__) + f = fopen(filename, "rb"); +#else + f = fopen(filename, "r"); +#endif + if (f != NULL) { + if (rectxt == NULL) + doc = xmlReadIO((xmlInputReadCallback) myRead, + (xmlInputCloseCallback) myClose, f, + filename, NULL, options); + else + doc = xmlCtxtReadIO(rectxt, + (xmlInputReadCallback) myRead, + (xmlInputCloseCallback) myClose, f, + filename, NULL, options); + } else + doc = NULL; + } + } else if (htmlout) { + xmlParserCtxtPtr ctxt; + + if (rectxt == NULL) + ctxt = xmlNewParserCtxt(); + else + ctxt = rectxt; + if (ctxt == NULL) { + doc = NULL; + } else { + ctxt->sax->error = xmlHTMLError; + ctxt->sax->warning = xmlHTMLWarning; + ctxt->vctxt.error = xmlHTMLValidityError; + ctxt->vctxt.warning = xmlHTMLValidityWarning; + + doc = xmlCtxtReadFile(ctxt, filename, NULL, options); + + if (rectxt == NULL) + xmlFreeParserCtxt(ctxt); + } +#ifdef HAVE_SYS_MMAN_H + } else if (memory) { + int fd; + struct stat info; + const char *base; + if (stat(filename, &info) < 0) + return; + if ((fd = open(filename, O_RDONLY)) < 0) + return; + base = mmap(NULL, info.st_size, PROT_READ, MAP_SHARED, fd, 0) ; + if (base == (void *) MAP_FAILED) + return; + + if (rectxt == NULL) + doc = xmlReadMemory((char *) base, info.st_size, + filename, NULL, options); + else + doc = xmlCtxtReadMemory(rectxt, (char *) base, info.st_size, + filename, NULL, options); + + munmap((char *) base, info.st_size); + close(fd); +#endif +#ifdef LIBXML_VALID_ENABLED + } else if (valid) { + xmlParserCtxtPtr ctxt = NULL; + + if (rectxt == NULL) + ctxt = xmlNewParserCtxt(); + else + ctxt = rectxt; + if (ctxt == NULL) { + doc = NULL; + } else { + doc = xmlCtxtReadFile(ctxt, filename, NULL, options); + + if (ctxt->valid == 0) + progresult = XMLLINT_ERR_RDFILE; + if (rectxt == NULL) + xmlFreeParserCtxt(ctxt); + } +#endif /* LIBXML_VALID_ENABLED */ + } else { + if (rectxt != NULL) + doc = xmlCtxtReadFile(rectxt, filename, NULL, options); + else { +#ifdef LIBXML_SAX1_ENABLED + if (sax1) + doc = xmlParseFile(filename); + else +#endif /* LIBXML_SAX1_ENABLED */ + doc = xmlReadFile(filename, NULL, options); + } + } + } + + /* + * If we don't have a document we might as well give up. Do we + * want an error message here? */ + if (doc == NULL) { + progresult = XMLLINT_ERR_UNCLASS; + return; + } + + if ((timing) && (!repeat)) { + endTimer("Parsing"); + } + + /* + * Remove DOCTYPE nodes + */ + if (dropdtd) { + xmlDtdPtr dtd; + + dtd = xmlGetIntSubset(doc); + if (dtd != NULL) { + xmlUnlinkNode((xmlNodePtr)dtd); + xmlFreeDtd(dtd); + } + } + +#ifdef LIBXML_XINCLUDE_ENABLED + if (xinclude) { + if ((timing) && (!repeat)) { + startTimer(); + } + if (xmlXIncludeProcessFlags(doc, options) < 0) + progresult = XMLLINT_ERR_UNCLASS; + if ((timing) && (!repeat)) { + endTimer("Xinclude processing"); + } + } +#endif + +#ifdef LIBXML_XPATH_ENABLED + if (xpathquery != NULL) { + doXPathQuery(doc, xpathquery); + } +#endif + +#ifdef LIBXML_DEBUG_ENABLED +#ifdef LIBXML_XPATH_ENABLED + /* + * shell interaction + */ + if (shell) { + xmlXPathOrderDocElems(doc); + xmlShell(doc, filename, xmlShellReadline, stdout); + } +#endif +#endif + +#ifdef LIBXML_TREE_ENABLED + /* + * test intermediate copy if needed. + */ + if (copy) { + tmp = doc; + if (timing) { + startTimer(); + } + doc = xmlCopyDoc(doc, 1); + if (timing) { + endTimer("Copying"); + } + if (timing) { + startTimer(); + } + xmlFreeDoc(tmp); + if (timing) { + endTimer("Freeing original"); + } + } +#endif /* LIBXML_TREE_ENABLED */ + +#ifdef LIBXML_VALID_ENABLED + if ((insert) && (!html)) { + const xmlChar* list[256]; + int nb, i; + xmlNodePtr node; + + if (doc->children != NULL) { + node = doc->children; + while ((node != NULL) && (node->last == NULL)) node = node->next; + if (node != NULL) { + nb = xmlValidGetValidElements(node->last, NULL, list, 256); + if (nb < 0) { + fprintf(stderr, "could not get valid list of elements\n"); + } else if (nb == 0) { + fprintf(stderr, "No element can be inserted under root\n"); + } else { + fprintf(stderr, "%d element types can be inserted under root:\n", + nb); + for (i = 0;i < nb;i++) { + fprintf(stderr, "%s\n", (char *) list[i]); + } + } + } + } + }else +#endif /* LIBXML_VALID_ENABLED */ +#ifdef LIBXML_READER_ENABLED + if (walker) { + walkDoc(doc); + } +#endif /* LIBXML_READER_ENABLED */ +#ifdef LIBXML_OUTPUT_ENABLED + if (noout == 0) { + int ret; + + /* + * print it. + */ +#ifdef LIBXML_DEBUG_ENABLED + if (!debug) { +#endif + if ((timing) && (!repeat)) { + startTimer(); + } +#ifdef LIBXML_C14N_ENABLED + if (canonical) { + xmlChar *result = NULL; + int size; + + size = xmlC14NDocDumpMemory(doc, NULL, XML_C14N_1_0, NULL, 1, &result); + if (size >= 0) { + if (write(1, result, size) == -1) { + fprintf(stderr, "Can't write data\n"); + } + xmlFree(result); + } else { + fprintf(stderr, "Failed to canonicalize\n"); + progresult = XMLLINT_ERR_OUT; + } + } else if (canonical) { + xmlChar *result = NULL; + int size; + + size = xmlC14NDocDumpMemory(doc, NULL, XML_C14N_1_1, NULL, 1, &result); + if (size >= 0) { + if (write(1, result, size) == -1) { + fprintf(stderr, "Can't write data\n"); + } + xmlFree(result); + } else { + fprintf(stderr, "Failed to canonicalize\n"); + progresult = XMLLINT_ERR_OUT; + } + } else + if (exc_canonical) { + xmlChar *result = NULL; + int size; + + size = xmlC14NDocDumpMemory(doc, NULL, XML_C14N_EXCLUSIVE_1_0, NULL, 1, &result); + if (size >= 0) { + if (write(1, result, size) == -1) { + fprintf(stderr, "Can't write data\n"); + } + xmlFree(result); + } else { + fprintf(stderr, "Failed to canonicalize\n"); + progresult = XMLLINT_ERR_OUT; + } + } else +#endif +#ifdef HAVE_SYS_MMAN_H + if (memory) { + xmlChar *result; + int len; + + if (encoding != NULL) { + if (format == 1) { + xmlDocDumpFormatMemoryEnc(doc, &result, &len, encoding, 1); + } else { + xmlDocDumpMemoryEnc(doc, &result, &len, encoding); + } + } else { + if (format == 1) + xmlDocDumpFormatMemory(doc, &result, &len, 1); + else + xmlDocDumpMemory(doc, &result, &len); + } + if (result == NULL) { + fprintf(stderr, "Failed to save\n"); + progresult = XMLLINT_ERR_OUT; + } else { + if (write(1, result, len) == -1) { + fprintf(stderr, "Can't write data\n"); + } + xmlFree(result); + } + + } else +#endif /* HAVE_SYS_MMAN_H */ + if (compress) { + xmlSaveFile(output ? output : "-", doc); + } else if (oldout) { + if (encoding != NULL) { + if (format == 1) { + ret = xmlSaveFormatFileEnc(output ? output : "-", doc, + encoding, 1); + } + else { + ret = xmlSaveFileEnc(output ? output : "-", doc, + encoding); + } + if (ret < 0) { + fprintf(stderr, "failed save to %s\n", + output ? output : "-"); + progresult = XMLLINT_ERR_OUT; + } + } else if (format == 1) { + ret = xmlSaveFormatFile(output ? output : "-", doc, 1); + if (ret < 0) { + fprintf(stderr, "failed save to %s\n", + output ? output : "-"); + progresult = XMLLINT_ERR_OUT; + } + } else { + FILE *out; + if (output == NULL) + out = stdout; + else { + out = fopen(output,"wb"); + } + if (out != NULL) { + if (xmlDocDump(out, doc) < 0) + progresult = XMLLINT_ERR_OUT; + + if (output != NULL) + fclose(out); + } else { + fprintf(stderr, "failed to open %s\n", output); + progresult = XMLLINT_ERR_OUT; + } + } + } else { + xmlSaveCtxtPtr ctxt; + int saveOpts = 0; + + if (format == 1) + saveOpts |= XML_SAVE_FORMAT; + else if (format == 2) + saveOpts |= XML_SAVE_WSNONSIG; + +#if defined(LIBXML_VALID_ENABLED) + if (xmlout) + saveOpts |= XML_SAVE_AS_XML; +#endif + + if (output == NULL) + ctxt = xmlSaveToFd(1, encoding, saveOpts); + else + ctxt = xmlSaveToFilename(output, encoding, saveOpts); + + if (ctxt != NULL) { + if (xmlSaveDoc(ctxt, doc) < 0) { + fprintf(stderr, "failed save to %s\n", + output ? output : "-"); + progresult = XMLLINT_ERR_OUT; + } + xmlSaveClose(ctxt); + } else { + progresult = XMLLINT_ERR_OUT; + } + } + if ((timing) && (!repeat)) { + endTimer("Saving"); + } +#ifdef LIBXML_DEBUG_ENABLED + } else { + FILE *out; + if (output == NULL) + out = stdout; + else { + out = fopen(output,"wb"); + } + if (out != NULL) { + xmlDebugDumpDocument(out, doc); + + if (output != NULL) + fclose(out); + } else { + fprintf(stderr, "failed to open %s\n", output); + progresult = XMLLINT_ERR_OUT; + } + } +#endif + } +#endif /* LIBXML_OUTPUT_ENABLED */ + +#ifdef LIBXML_VALID_ENABLED + /* + * A posteriori validation test + */ + if ((dtdvalid != NULL) || (dtdvalidfpi != NULL)) { + xmlDtdPtr dtd; + + if ((timing) && (!repeat)) { + startTimer(); + } + if (dtdvalid != NULL) + dtd = xmlParseDTD(NULL, (const xmlChar *)dtdvalid); + else + dtd = xmlParseDTD((const xmlChar *)dtdvalidfpi, NULL); + if ((timing) && (!repeat)) { + endTimer("Parsing DTD"); + } + if (dtd == NULL) { + if (dtdvalid != NULL) + xmlGenericError(xmlGenericErrorContext, + "Could not parse DTD %s\n", dtdvalid); + else + xmlGenericError(xmlGenericErrorContext, + "Could not parse DTD %s\n", dtdvalidfpi); + progresult = XMLLINT_ERR_DTD; + } else { + xmlValidCtxtPtr cvp; + + if ((cvp = xmlNewValidCtxt()) == NULL) { + xmlGenericError(xmlGenericErrorContext, + "Couldn't allocate validation context\n"); + exit(-1); + } + cvp->userData = (void *) stderr; + cvp->error = (xmlValidityErrorFunc) fprintf; + cvp->warning = (xmlValidityWarningFunc) fprintf; + + if ((timing) && (!repeat)) { + startTimer(); + } + if (!xmlValidateDtd(cvp, doc, dtd)) { + if (dtdvalid != NULL) + xmlGenericError(xmlGenericErrorContext, + "Document %s does not validate against %s\n", + filename, dtdvalid); + else + xmlGenericError(xmlGenericErrorContext, + "Document %s does not validate against %s\n", + filename, dtdvalidfpi); + progresult = XMLLINT_ERR_VALID; + } + if ((timing) && (!repeat)) { + endTimer("Validating against DTD"); + } + xmlFreeValidCtxt(cvp); + xmlFreeDtd(dtd); + } + } else if (postvalid) { + xmlValidCtxtPtr cvp; + + if ((cvp = xmlNewValidCtxt()) == NULL) { + xmlGenericError(xmlGenericErrorContext, + "Couldn't allocate validation context\n"); + exit(-1); + } + + if ((timing) && (!repeat)) { + startTimer(); + } + cvp->userData = (void *) stderr; + cvp->error = (xmlValidityErrorFunc) fprintf; + cvp->warning = (xmlValidityWarningFunc) fprintf; + if (!xmlValidateDocument(cvp, doc)) { + xmlGenericError(xmlGenericErrorContext, + "Document %s does not validate\n", filename); + progresult = XMLLINT_ERR_VALID; + } + if ((timing) && (!repeat)) { + endTimer("Validating"); + } + xmlFreeValidCtxt(cvp); + } +#endif /* LIBXML_VALID_ENABLED */ +#ifdef LIBXML_SCHEMATRON_ENABLED + if (wxschematron != NULL) { + xmlSchematronValidCtxtPtr ctxt; + int ret; + int flag; + + if ((timing) && (!repeat)) { + startTimer(); + } + + if (debug) + flag = XML_SCHEMATRON_OUT_XML; + else + flag = XML_SCHEMATRON_OUT_TEXT; + if (noout) + flag |= XML_SCHEMATRON_OUT_QUIET; + ctxt = xmlSchematronNewValidCtxt(wxschematron, flag); +#if 0 + xmlSchematronSetValidErrors(ctxt, + (xmlSchematronValidityErrorFunc) fprintf, + (xmlSchematronValidityWarningFunc) fprintf, + stderr); +#endif + ret = xmlSchematronValidateDoc(ctxt, doc); + if (ret == 0) { + fprintf(stderr, "%s validates\n", filename); + } else if (ret > 0) { + fprintf(stderr, "%s fails to validate\n", filename); + progresult = XMLLINT_ERR_VALID; + } else { + fprintf(stderr, "%s validation generated an internal error\n", + filename); + progresult = XMLLINT_ERR_VALID; + } + xmlSchematronFreeValidCtxt(ctxt); + if ((timing) && (!repeat)) { + endTimer("Validating"); + } + } +#endif +#ifdef LIBXML_SCHEMAS_ENABLED + if (relaxngschemas != NULL) { + xmlRelaxNGValidCtxtPtr ctxt; + int ret; + + if ((timing) && (!repeat)) { + startTimer(); + } + + ctxt = xmlRelaxNGNewValidCtxt(relaxngschemas); + xmlRelaxNGSetValidErrors(ctxt, + (xmlRelaxNGValidityErrorFunc) fprintf, + (xmlRelaxNGValidityWarningFunc) fprintf, + stderr); + ret = xmlRelaxNGValidateDoc(ctxt, doc); + if (ret == 0) { + fprintf(stderr, "%s validates\n", filename); + } else if (ret > 0) { + fprintf(stderr, "%s fails to validate\n", filename); + progresult = XMLLINT_ERR_VALID; + } else { + fprintf(stderr, "%s validation generated an internal error\n", + filename); + progresult = XMLLINT_ERR_VALID; + } + xmlRelaxNGFreeValidCtxt(ctxt); + if ((timing) && (!repeat)) { + endTimer("Validating"); + } + } else if (wxschemas != NULL) { + xmlSchemaValidCtxtPtr ctxt; + int ret; + + if ((timing) && (!repeat)) { + startTimer(); + } + + ctxt = xmlSchemaNewValidCtxt(wxschemas); + xmlSchemaSetValidErrors(ctxt, + (xmlSchemaValidityErrorFunc) fprintf, + (xmlSchemaValidityWarningFunc) fprintf, + stderr); + ret = xmlSchemaValidateDoc(ctxt, doc); + if (ret == 0) { + fprintf(stderr, "%s validates\n", filename); + } else if (ret > 0) { + fprintf(stderr, "%s fails to validate\n", filename); + progresult = XMLLINT_ERR_VALID; + } else { + fprintf(stderr, "%s validation generated an internal error\n", + filename); + progresult = XMLLINT_ERR_VALID; + } + xmlSchemaFreeValidCtxt(ctxt); + if ((timing) && (!repeat)) { + endTimer("Validating"); + } + } +#endif + +#ifdef LIBXML_DEBUG_ENABLED +#if defined(LIBXML_VALID_ENABLED) + if ((debugent) && (!html)) + xmlDebugDumpEntities(stderr, doc); +#endif +#endif + + /* + * free it. + */ + if ((timing) && (!repeat)) { + startTimer(); + } + xmlFreeDoc(doc); + if ((timing) && (!repeat)) { + endTimer("Freeing"); + } +} + +/************************************************************************ + * * + * Usage and Main * + * * + ************************************************************************/ + +static void showVersion(const char *name) { + fprintf(stderr, "%s: using libxml version %s\n", name, xmlParserVersion); + fprintf(stderr, " compiled with: "); + if (xmlHasFeature(XML_WITH_THREAD)) fprintf(stderr, "Threads "); + if (xmlHasFeature(XML_WITH_TREE)) fprintf(stderr, "Tree "); + if (xmlHasFeature(XML_WITH_OUTPUT)) fprintf(stderr, "Output "); + if (xmlHasFeature(XML_WITH_PUSH)) fprintf(stderr, "Push "); + if (xmlHasFeature(XML_WITH_READER)) fprintf(stderr, "Reader "); + if (xmlHasFeature(XML_WITH_PATTERN)) fprintf(stderr, "Patterns "); + if (xmlHasFeature(XML_WITH_WRITER)) fprintf(stderr, "Writer "); + if (xmlHasFeature(XML_WITH_SAX1)) fprintf(stderr, "SAXv1 "); + if (xmlHasFeature(XML_WITH_FTP)) fprintf(stderr, "FTP "); + if (xmlHasFeature(XML_WITH_HTTP)) fprintf(stderr, "HTTP "); + if (xmlHasFeature(XML_WITH_VALID)) fprintf(stderr, "DTDValid "); + if (xmlHasFeature(XML_WITH_HTML)) fprintf(stderr, "HTML "); + if (xmlHasFeature(XML_WITH_LEGACY)) fprintf(stderr, "Legacy "); + if (xmlHasFeature(XML_WITH_C14N)) fprintf(stderr, "C14N "); + if (xmlHasFeature(XML_WITH_CATALOG)) fprintf(stderr, "Catalog "); + if (xmlHasFeature(XML_WITH_XPATH)) fprintf(stderr, "XPath "); + if (xmlHasFeature(XML_WITH_XPTR)) fprintf(stderr, "XPointer "); + if (xmlHasFeature(XML_WITH_XINCLUDE)) fprintf(stderr, "XInclude "); + if (xmlHasFeature(XML_WITH_ICONV)) fprintf(stderr, "Iconv "); + if (xmlHasFeature(XML_WITH_ISO8859X)) fprintf(stderr, "ISO8859X "); + if (xmlHasFeature(XML_WITH_UNICODE)) fprintf(stderr, "Unicode "); + if (xmlHasFeature(XML_WITH_REGEXP)) fprintf(stderr, "Regexps "); + if (xmlHasFeature(XML_WITH_AUTOMATA)) fprintf(stderr, "Automata "); + if (xmlHasFeature(XML_WITH_EXPR)) fprintf(stderr, "Expr "); + if (xmlHasFeature(XML_WITH_SCHEMAS)) fprintf(stderr, "Schemas "); + if (xmlHasFeature(XML_WITH_SCHEMATRON)) fprintf(stderr, "Schematron "); + if (xmlHasFeature(XML_WITH_MODULES)) fprintf(stderr, "Modules "); + if (xmlHasFeature(XML_WITH_DEBUG)) fprintf(stderr, "Debug "); + if (xmlHasFeature(XML_WITH_DEBUG_MEM)) fprintf(stderr, "MemDebug "); + if (xmlHasFeature(XML_WITH_DEBUG_RUN)) fprintf(stderr, "RunDebug "); + if (xmlHasFeature(XML_WITH_ZLIB)) fprintf(stderr, "Zlib "); + if (xmlHasFeature(XML_WITH_LZMA)) fprintf(stderr, "Lzma "); + fprintf(stderr, "\n"); +} + +static void usage(const char *name) { + printf("Usage : %s [options] XMLfiles ...\n", name); +#ifdef LIBXML_OUTPUT_ENABLED + printf("\tParse the XML files and output the result of the parsing\n"); +#else + printf("\tParse the XML files\n"); +#endif /* LIBXML_OUTPUT_ENABLED */ + printf("\t--version : display the version of the XML library used\n"); +#ifdef LIBXML_DEBUG_ENABLED + printf("\t--debug : dump a debug tree of the in-memory document\n"); + printf("\t--shell : run a navigating shell\n"); + printf("\t--debugent : debug the entities defined in the document\n"); +#else +#ifdef LIBXML_READER_ENABLED + printf("\t--debug : dump the nodes content when using --stream\n"); +#endif /* LIBXML_READER_ENABLED */ +#endif +#ifdef LIBXML_TREE_ENABLED + printf("\t--copy : used to test the internal copy implementation\n"); +#endif /* LIBXML_TREE_ENABLED */ + printf("\t--recover : output what was parsable on broken XML documents\n"); + printf("\t--huge : remove any internal arbitrary parser limits\n"); + printf("\t--noent : substitute entity references by their value\n"); + printf("\t--noenc : ignore any encoding specified inside the document\n"); + printf("\t--noout : don't output the result tree\n"); + printf("\t--path 'paths': provide a set of paths for resources\n"); + printf("\t--load-trace : print trace of all external entites loaded\n"); + printf("\t--nonet : refuse to fetch DTDs or entities over network\n"); + printf("\t--nocompact : do not generate compact text nodes\n"); + printf("\t--htmlout : output results as HTML\n"); + printf("\t--nowrap : do not put HTML doc wrapper\n"); +#ifdef LIBXML_VALID_ENABLED + printf("\t--valid : validate the document in addition to std well-formed check\n"); + printf("\t--postvalid : do a posteriori validation, i.e after parsing\n"); + printf("\t--dtdvalid URL : do a posteriori validation against a given DTD\n"); + printf("\t--dtdvalidfpi FPI : same but name the DTD with a Public Identifier\n"); +#endif /* LIBXML_VALID_ENABLED */ + printf("\t--timing : print some timings\n"); + printf("\t--output file or -o file: save to a given file\n"); + printf("\t--repeat : repeat 100 times, for timing or profiling\n"); + printf("\t--insert : ad-hoc test for valid insertions\n"); +#ifdef LIBXML_OUTPUT_ENABLED +#ifdef HAVE_ZLIB_H + printf("\t--compress : turn on gzip compression of output\n"); +#endif +#endif /* LIBXML_OUTPUT_ENABLED */ +#ifdef LIBXML_PUSH_ENABLED + printf("\t--push : use the push mode of the parser\n"); +#endif /* LIBXML_PUSH_ENABLED */ +#ifdef HAVE_SYS_MMAN_H + printf("\t--memory : parse from memory\n"); +#endif + printf("\t--maxmem nbbytes : limits memory allocation to nbbytes bytes\n"); + printf("\t--nowarning : do not emit warnings from parser/validator\n"); + printf("\t--noblanks : drop (ignorable?) blanks spaces\n"); + printf("\t--nocdata : replace cdata section with text nodes\n"); +#ifdef LIBXML_OUTPUT_ENABLED + printf("\t--format : reformat/reindent the input\n"); + printf("\t--encode encoding : output in the given encoding\n"); + printf("\t--dropdtd : remove the DOCTYPE of the input docs\n"); + printf("\t--pretty STYLE : pretty-print in a particular style\n"); + printf("\t 0 Do not pretty print\n"); + printf("\t 1 Format the XML content, as --format\n"); + printf("\t 2 Add whitespace inside tags, preserving content\n"); +#endif /* LIBXML_OUTPUT_ENABLED */ + printf("\t--c14n : save in W3C canonical format v1.0 (with comments)\n"); + printf("\t--c14n11 : save in W3C canonical format v1.1 (with comments)\n"); + printf("\t--exc-c14n : save in W3C exclusive canonical format (with comments)\n"); +#ifdef LIBXML_C14N_ENABLED +#endif /* LIBXML_C14N_ENABLED */ + printf("\t--nsclean : remove redundant namespace declarations\n"); + printf("\t--testIO : test user I/O support\n"); +#ifdef LIBXML_CATALOG_ENABLED + printf("\t--catalogs : use SGML catalogs from $SGML_CATALOG_FILES\n"); + printf("\t otherwise XML Catalogs starting from \n"); + printf("\t %s are activated by default\n", XML_XML_DEFAULT_CATALOG); + printf("\t--nocatalogs: deactivate all catalogs\n"); +#endif + printf("\t--auto : generate a small doc on the fly\n"); +#ifdef LIBXML_XINCLUDE_ENABLED + printf("\t--xinclude : do XInclude processing\n"); + printf("\t--noxincludenode : same but do not generate XInclude nodes\n"); + printf("\t--nofixup-base-uris : do not fixup xml:base uris\n"); +#endif + printf("\t--loaddtd : fetch external DTD\n"); + printf("\t--dtdattr : loaddtd + populate the tree with inherited attributes \n"); +#ifdef LIBXML_READER_ENABLED + printf("\t--stream : use the streaming interface to process very large files\n"); + printf("\t--walker : create a reader and walk though the resulting doc\n"); +#endif /* LIBXML_READER_ENABLED */ +#ifdef LIBXML_PATTERN_ENABLED + printf("\t--pattern pattern_value : test the pattern support\n"); +#endif + printf("\t--chkregister : verify the node registration code\n"); +#ifdef LIBXML_SCHEMAS_ENABLED + printf("\t--relaxng schema : do RelaxNG validation against the schema\n"); + printf("\t--schema schema : do validation against the WXS schema\n"); +#endif +#ifdef LIBXML_SCHEMATRON_ENABLED + printf("\t--schematron schema : do validation against a schematron\n"); +#endif +#ifdef LIBXML_SAX1_ENABLED + printf("\t--sax1: use the old SAX1 interfaces for processing\n"); +#endif + printf("\t--sax: do not build a tree but work just at the SAX level\n"); + printf("\t--oldxml10: use XML-1.0 parsing rules before the 5th edition\n"); +#ifdef LIBXML_XPATH_ENABLED + printf("\t--xpath expr: evaluate the XPath expression, inply --noout\n"); +#endif + + printf("\nLibxml project home page: http://xmlsoft.org/\n"); + printf("To report bugs or get some help check: http://xmlsoft.org/bugs.html\n"); +} + +static void registerNode(xmlNodePtr node) +{ + node->_private = malloc(sizeof(long)); + *(long*)node->_private = (long) 0x81726354; + nbregister++; +} + +static void deregisterNode(xmlNodePtr node) +{ + assert(node->_private != NULL); + assert(*(long*)node->_private == (long) 0x81726354); + free(node->_private); + nbregister--; +} + +int +main(int argc, char **argv) { + int i, acount; + int files = 0; + int version = 0; + const char* indent; + + if (argc <= 1) { + usage(argv[0]); + return(1); + } + LIBXML_TEST_VERSION + for (i = 1; i < argc ; i++) { + if (!strcmp(argv[i], "-")) + break; + + if (argv[i][0] != '-') + continue; + if ((!strcmp(argv[i], "-debug")) || (!strcmp(argv[i], "--debug"))) + debug++; + else +#ifdef LIBXML_DEBUG_ENABLED + if ((!strcmp(argv[i], "-shell")) || + (!strcmp(argv[i], "--shell"))) { + shell++; + noout = 1; + } else +#endif +#ifdef LIBXML_TREE_ENABLED + if ((!strcmp(argv[i], "-copy")) || (!strcmp(argv[i], "--copy"))) + copy++; + else +#endif /* LIBXML_TREE_ENABLED */ + if ((!strcmp(argv[i], "-recover")) || + (!strcmp(argv[i], "--recover"))) { + recovery++; + options |= XML_PARSE_RECOVER; + } else if ((!strcmp(argv[i], "-huge")) || + (!strcmp(argv[i], "--huge"))) { + options |= XML_PARSE_HUGE; + } else if ((!strcmp(argv[i], "-noent")) || + (!strcmp(argv[i], "--noent"))) { + noent++; + options |= XML_PARSE_NOENT; + } else if ((!strcmp(argv[i], "-noenc")) || + (!strcmp(argv[i], "--noenc"))) { + noenc++; + options |= XML_PARSE_IGNORE_ENC; + } else if ((!strcmp(argv[i], "-nsclean")) || + (!strcmp(argv[i], "--nsclean"))) { + options |= XML_PARSE_NSCLEAN; + } else if ((!strcmp(argv[i], "-nocdata")) || + (!strcmp(argv[i], "--nocdata"))) { + options |= XML_PARSE_NOCDATA; + } else if ((!strcmp(argv[i], "-nodict")) || + (!strcmp(argv[i], "--nodict"))) { + options |= XML_PARSE_NODICT; + } else if ((!strcmp(argv[i], "-version")) || + (!strcmp(argv[i], "--version"))) { + showVersion(argv[0]); + version = 1; + } else if ((!strcmp(argv[i], "-noout")) || + (!strcmp(argv[i], "--noout"))) + noout++; +#ifdef LIBXML_OUTPUT_ENABLED + else if ((!strcmp(argv[i], "-o")) || + (!strcmp(argv[i], "-output")) || + (!strcmp(argv[i], "--output"))) { + i++; + output = argv[i]; + } +#endif /* LIBXML_OUTPUT_ENABLED */ + else if ((!strcmp(argv[i], "-htmlout")) || + (!strcmp(argv[i], "--htmlout"))) + htmlout++; + else if ((!strcmp(argv[i], "-nowrap")) || + (!strcmp(argv[i], "--nowrap"))) + nowrap++; + else if ((!strcmp(argv[i], "-loaddtd")) || + (!strcmp(argv[i], "--loaddtd"))) { + loaddtd++; + options |= XML_PARSE_DTDLOAD; + } else if ((!strcmp(argv[i], "-dtdattr")) || + (!strcmp(argv[i], "--dtdattr"))) { + loaddtd++; + dtdattrs++; + options |= XML_PARSE_DTDATTR; + } +#ifdef LIBXML_VALID_ENABLED + else if ((!strcmp(argv[i], "-valid")) || + (!strcmp(argv[i], "--valid"))) { + valid++; + options |= XML_PARSE_DTDVALID; + } else if ((!strcmp(argv[i], "-postvalid")) || + (!strcmp(argv[i], "--postvalid"))) { + postvalid++; + loaddtd++; + options |= XML_PARSE_DTDLOAD; + } else if ((!strcmp(argv[i], "-dtdvalid")) || + (!strcmp(argv[i], "--dtdvalid"))) { + i++; + dtdvalid = argv[i]; + loaddtd++; + options |= XML_PARSE_DTDLOAD; + } else if ((!strcmp(argv[i], "-dtdvalidfpi")) || + (!strcmp(argv[i], "--dtdvalidfpi"))) { + i++; + dtdvalidfpi = argv[i]; + loaddtd++; + options |= XML_PARSE_DTDLOAD; + } +#endif /* LIBXML_VALID_ENABLED */ + else if ((!strcmp(argv[i], "-dropdtd")) || + (!strcmp(argv[i], "--dropdtd"))) + dropdtd++; + else if ((!strcmp(argv[i], "-insert")) || + (!strcmp(argv[i], "--insert"))) + insert++; + else if ((!strcmp(argv[i], "-timing")) || + (!strcmp(argv[i], "--timing"))) + timing++; + else if ((!strcmp(argv[i], "-auto")) || + (!strcmp(argv[i], "--auto"))) + generate++; + else if ((!strcmp(argv[i], "-repeat")) || + (!strcmp(argv[i], "--repeat"))) { + if (repeat) + repeat *= 10; + else + repeat = 100; + } +#ifdef LIBXML_PUSH_ENABLED + else if ((!strcmp(argv[i], "-push")) || + (!strcmp(argv[i], "--push"))) + push++; +#endif /* LIBXML_PUSH_ENABLED */ +#ifdef HAVE_SYS_MMAN_H + else if ((!strcmp(argv[i], "-memory")) || + (!strcmp(argv[i], "--memory"))) + memory++; +#endif + else if ((!strcmp(argv[i], "-testIO")) || + (!strcmp(argv[i], "--testIO"))) + testIO++; +#ifdef LIBXML_XINCLUDE_ENABLED + else if ((!strcmp(argv[i], "-xinclude")) || + (!strcmp(argv[i], "--xinclude"))) { + xinclude++; + options |= XML_PARSE_XINCLUDE; + } + else if ((!strcmp(argv[i], "-noxincludenode")) || + (!strcmp(argv[i], "--noxincludenode"))) { + xinclude++; + options |= XML_PARSE_XINCLUDE; + options |= XML_PARSE_NOXINCNODE; + } + else if ((!strcmp(argv[i], "-nofixup-base-uris")) || + (!strcmp(argv[i], "--nofixup-base-uris"))) { + xinclude++; + options |= XML_PARSE_XINCLUDE; + options |= XML_PARSE_NOBASEFIX; + } +#endif +#ifdef LIBXML_OUTPUT_ENABLED +#ifdef HAVE_ZLIB_H + else if ((!strcmp(argv[i], "-compress")) || + (!strcmp(argv[i], "--compress"))) { + compress++; + xmlSetCompressMode(9); + } +#endif +#endif /* LIBXML_OUTPUT_ENABLED */ + else if ((!strcmp(argv[i], "-nowarning")) || + (!strcmp(argv[i], "--nowarning"))) { + xmlGetWarningsDefaultValue = 0; + xmlPedanticParserDefault(0); + options |= XML_PARSE_NOWARNING; + } + else if ((!strcmp(argv[i], "-pedantic")) || + (!strcmp(argv[i], "--pedantic"))) { + xmlGetWarningsDefaultValue = 1; + xmlPedanticParserDefault(1); + options |= XML_PARSE_PEDANTIC; + } +#ifdef LIBXML_DEBUG_ENABLED + else if ((!strcmp(argv[i], "-debugent")) || + (!strcmp(argv[i], "--debugent"))) { + debugent++; + xmlParserDebugEntities = 1; + } +#endif +#ifdef LIBXML_C14N_ENABLED + else if ((!strcmp(argv[i], "-c14n")) || + (!strcmp(argv[i], "--c14n"))) { + canonical++; + options |= XML_PARSE_NOENT | XML_PARSE_DTDATTR | XML_PARSE_DTDLOAD; + } + else if ((!strcmp(argv[i], "-c14n11")) || + (!strcmp(argv[i], "--c14n11"))) { + canonical_11++; + options |= XML_PARSE_NOENT | XML_PARSE_DTDATTR | XML_PARSE_DTDLOAD; + } + else if ((!strcmp(argv[i], "-exc-c14n")) || + (!strcmp(argv[i], "--exc-c14n"))) { + exc_canonical++; + options |= XML_PARSE_NOENT | XML_PARSE_DTDATTR | XML_PARSE_DTDLOAD; + } +#endif +#ifdef LIBXML_CATALOG_ENABLED + else if ((!strcmp(argv[i], "-catalogs")) || + (!strcmp(argv[i], "--catalogs"))) { + catalogs++; + } else if ((!strcmp(argv[i], "-nocatalogs")) || + (!strcmp(argv[i], "--nocatalogs"))) { + nocatalogs++; + } +#endif + else if ((!strcmp(argv[i], "-encode")) || + (!strcmp(argv[i], "--encode"))) { + i++; + encoding = argv[i]; + /* + * OK it's for testing purposes + */ + xmlAddEncodingAlias("UTF-8", "DVEnc"); + } + else if ((!strcmp(argv[i], "-noblanks")) || + (!strcmp(argv[i], "--noblanks"))) { + noblanks++; + xmlKeepBlanksDefault(0); + } + else if ((!strcmp(argv[i], "-maxmem")) || + (!strcmp(argv[i], "--maxmem"))) { + i++; + if (sscanf(argv[i], "%d", &maxmem) == 1) { + xmlMemSetup(myFreeFunc, myMallocFunc, myReallocFunc, + myStrdupFunc); + } else { + maxmem = 0; + } + } + else if ((!strcmp(argv[i], "-format")) || + (!strcmp(argv[i], "--format"))) { + noblanks++; +#ifdef LIBXML_OUTPUT_ENABLED + format = 1; +#endif /* LIBXML_OUTPUT_ENABLED */ + xmlKeepBlanksDefault(0); + } + else if ((!strcmp(argv[i], "-pretty")) || + (!strcmp(argv[i], "--pretty"))) { + i++; +#ifdef LIBXML_OUTPUT_ENABLED + format = atoi(argv[i]); +#endif /* LIBXML_OUTPUT_ENABLED */ + if (format == 1) { + noblanks++; + xmlKeepBlanksDefault(0); + } + } +#ifdef LIBXML_READER_ENABLED + else if ((!strcmp(argv[i], "-stream")) || + (!strcmp(argv[i], "--stream"))) { + stream++; + } + else if ((!strcmp(argv[i], "-walker")) || + (!strcmp(argv[i], "--walker"))) { + walker++; + noout++; + } +#endif /* LIBXML_READER_ENABLED */ +#ifdef LIBXML_SAX1_ENABLED + else if ((!strcmp(argv[i], "-sax1")) || + (!strcmp(argv[i], "--sax1"))) { + sax1++; + options |= XML_PARSE_SAX1; + } +#endif /* LIBXML_SAX1_ENABLED */ + else if ((!strcmp(argv[i], "-sax")) || + (!strcmp(argv[i], "--sax"))) { + sax++; + } + else if ((!strcmp(argv[i], "-chkregister")) || + (!strcmp(argv[i], "--chkregister"))) { + chkregister++; +#ifdef LIBXML_SCHEMAS_ENABLED + } else if ((!strcmp(argv[i], "-relaxng")) || + (!strcmp(argv[i], "--relaxng"))) { + i++; + relaxng = argv[i]; + noent++; + options |= XML_PARSE_NOENT; + } else if ((!strcmp(argv[i], "-schema")) || + (!strcmp(argv[i], "--schema"))) { + i++; + schema = argv[i]; + noent++; +#endif +#ifdef LIBXML_SCHEMATRON_ENABLED + } else if ((!strcmp(argv[i], "-schematron")) || + (!strcmp(argv[i], "--schematron"))) { + i++; + schematron = argv[i]; + noent++; +#endif + } else if ((!strcmp(argv[i], "-nonet")) || + (!strcmp(argv[i], "--nonet"))) { + options |= XML_PARSE_NONET; + xmlSetExternalEntityLoader(xmlNoNetExternalEntityLoader); + } else if ((!strcmp(argv[i], "-nocompact")) || + (!strcmp(argv[i], "--nocompact"))) { + options &= ~XML_PARSE_COMPACT; + } else if ((!strcmp(argv[i], "-load-trace")) || + (!strcmp(argv[i], "--load-trace"))) { + load_trace++; + } else if ((!strcmp(argv[i], "-path")) || + (!strcmp(argv[i], "--path"))) { + i++; + parsePath(BAD_CAST argv[i]); +#ifdef LIBXML_PATTERN_ENABLED + } else if ((!strcmp(argv[i], "-pattern")) || + (!strcmp(argv[i], "--pattern"))) { + i++; + pattern = argv[i]; +#endif +#ifdef LIBXML_XPATH_ENABLED + } else if ((!strcmp(argv[i], "-xpath")) || + (!strcmp(argv[i], "--xpath"))) { + i++; + noout++; + xpathquery = argv[i]; +#endif + } else if ((!strcmp(argv[i], "-oldxml10")) || + (!strcmp(argv[i], "--oldxml10"))) { + oldxml10++; + options |= XML_PARSE_OLD10; + } else { + fprintf(stderr, "Unknown option %s\n", argv[i]); + usage(argv[0]); + return(1); + } + } + +#ifdef LIBXML_CATALOG_ENABLED + if (nocatalogs == 0) { + if (catalogs) { + const char *catal; + + catal = getenv("SGML_CATALOG_FILES"); + if (catal != NULL) { + xmlLoadCatalogs(catal); + } else { + fprintf(stderr, "Variable $SGML_CATALOG_FILES not set\n"); + } + } + } +#endif + +#ifdef LIBXML_SAX1_ENABLED + if (sax1) + xmlSAXDefaultVersion(1); + else + xmlSAXDefaultVersion(2); +#endif /* LIBXML_SAX1_ENABLED */ + + if (chkregister) { + xmlRegisterNodeDefault(registerNode); + xmlDeregisterNodeDefault(deregisterNode); + } + + indent = getenv("XMLLINT_INDENT"); + if(indent != NULL) { + xmlTreeIndentString = indent; + } + + + defaultEntityLoader = xmlGetExternalEntityLoader(); + xmlSetExternalEntityLoader(xmllintExternalEntityLoader); + + xmlLineNumbersDefault(1); + if (loaddtd != 0) + xmlLoadExtDtdDefaultValue |= XML_DETECT_IDS; + if (dtdattrs) + xmlLoadExtDtdDefaultValue |= XML_COMPLETE_ATTRS; + if (noent != 0) xmlSubstituteEntitiesDefault(1); +#ifdef LIBXML_VALID_ENABLED + if (valid != 0) xmlDoValidityCheckingDefaultValue = 1; +#endif /* LIBXML_VALID_ENABLED */ + if ((htmlout) && (!nowrap)) { + xmlGenericError(xmlGenericErrorContext, + "\n"); + xmlGenericError(xmlGenericErrorContext, + "%s output\n", + argv[0]); + xmlGenericError(xmlGenericErrorContext, + "

%s output

\n", + argv[0]); + } + +#ifdef LIBXML_SCHEMATRON_ENABLED + if ((schematron != NULL) && (sax == 0) +#ifdef LIBXML_READER_ENABLED + && (stream == 0) +#endif /* LIBXML_READER_ENABLED */ + ) { + xmlSchematronParserCtxtPtr ctxt; + + /* forces loading the DTDs */ + xmlLoadExtDtdDefaultValue |= 1; + options |= XML_PARSE_DTDLOAD; + if (timing) { + startTimer(); + } + ctxt = xmlSchematronNewParserCtxt(schematron); +#if 0 + xmlSchematronSetParserErrors(ctxt, + (xmlSchematronValidityErrorFunc) fprintf, + (xmlSchematronValidityWarningFunc) fprintf, + stderr); +#endif + wxschematron = xmlSchematronParse(ctxt); + if (wxschematron == NULL) { + xmlGenericError(xmlGenericErrorContext, + "Schematron schema %s failed to compile\n", schematron); + progresult = XMLLINT_ERR_SCHEMACOMP; + schematron = NULL; + } + xmlSchematronFreeParserCtxt(ctxt); + if (timing) { + endTimer("Compiling the schemas"); + } + } +#endif +#ifdef LIBXML_SCHEMAS_ENABLED + if ((relaxng != NULL) && (sax == 0) +#ifdef LIBXML_READER_ENABLED + && (stream == 0) +#endif /* LIBXML_READER_ENABLED */ + ) { + xmlRelaxNGParserCtxtPtr ctxt; + + /* forces loading the DTDs */ + xmlLoadExtDtdDefaultValue |= 1; + options |= XML_PARSE_DTDLOAD; + if (timing) { + startTimer(); + } + ctxt = xmlRelaxNGNewParserCtxt(relaxng); + xmlRelaxNGSetParserErrors(ctxt, + (xmlRelaxNGValidityErrorFunc) fprintf, + (xmlRelaxNGValidityWarningFunc) fprintf, + stderr); + relaxngschemas = xmlRelaxNGParse(ctxt); + if (relaxngschemas == NULL) { + xmlGenericError(xmlGenericErrorContext, + "Relax-NG schema %s failed to compile\n", relaxng); + progresult = XMLLINT_ERR_SCHEMACOMP; + relaxng = NULL; + } + xmlRelaxNGFreeParserCtxt(ctxt); + if (timing) { + endTimer("Compiling the schemas"); + } + } else if ((schema != NULL) +#ifdef LIBXML_READER_ENABLED + && (stream == 0) +#endif + ) { + xmlSchemaParserCtxtPtr ctxt; + + if (timing) { + startTimer(); + } + ctxt = xmlSchemaNewParserCtxt(schema); + xmlSchemaSetParserErrors(ctxt, + (xmlSchemaValidityErrorFunc) fprintf, + (xmlSchemaValidityWarningFunc) fprintf, + stderr); + wxschemas = xmlSchemaParse(ctxt); + if (wxschemas == NULL) { + xmlGenericError(xmlGenericErrorContext, + "WXS schema %s failed to compile\n", schema); + progresult = XMLLINT_ERR_SCHEMACOMP; + schema = NULL; + } + xmlSchemaFreeParserCtxt(ctxt); + if (timing) { + endTimer("Compiling the schemas"); + } + } +#endif /* LIBXML_SCHEMAS_ENABLED */ +#ifdef LIBXML_PATTERN_ENABLED + if ((pattern != NULL) +#ifdef LIBXML_READER_ENABLED + && (walker == 0) +#endif + ) { + patternc = xmlPatterncompile((const xmlChar *) pattern, NULL, 0, NULL); + if (patternc == NULL) { + xmlGenericError(xmlGenericErrorContext, + "Pattern %s failed to compile\n", pattern); + progresult = XMLLINT_ERR_SCHEMAPAT; + pattern = NULL; + } + } +#endif /* LIBXML_PATTERN_ENABLED */ + for (i = 1; i < argc ; i++) { + if ((!strcmp(argv[i], "-encode")) || + (!strcmp(argv[i], "--encode"))) { + i++; + continue; + } else if ((!strcmp(argv[i], "-o")) || + (!strcmp(argv[i], "-output")) || + (!strcmp(argv[i], "--output"))) { + i++; + continue; + } +#ifdef LIBXML_VALID_ENABLED + if ((!strcmp(argv[i], "-dtdvalid")) || + (!strcmp(argv[i], "--dtdvalid"))) { + i++; + continue; + } + if ((!strcmp(argv[i], "-path")) || + (!strcmp(argv[i], "--path"))) { + i++; + continue; + } + if ((!strcmp(argv[i], "-dtdvalidfpi")) || + (!strcmp(argv[i], "--dtdvalidfpi"))) { + i++; + continue; + } +#endif /* LIBXML_VALID_ENABLED */ + if ((!strcmp(argv[i], "-relaxng")) || + (!strcmp(argv[i], "--relaxng"))) { + i++; + continue; + } + if ((!strcmp(argv[i], "-maxmem")) || + (!strcmp(argv[i], "--maxmem"))) { + i++; + continue; + } + if ((!strcmp(argv[i], "-pretty")) || + (!strcmp(argv[i], "--pretty"))) { + i++; + continue; + } + if ((!strcmp(argv[i], "-schema")) || + (!strcmp(argv[i], "--schema"))) { + i++; + continue; + } + if ((!strcmp(argv[i], "-schematron")) || + (!strcmp(argv[i], "--schematron"))) { + i++; + continue; + } +#ifdef LIBXML_PATTERN_ENABLED + if ((!strcmp(argv[i], "-pattern")) || + (!strcmp(argv[i], "--pattern"))) { + i++; + continue; + } +#endif +#ifdef LIBXML_XPATH_ENABLED + if ((!strcmp(argv[i], "-xpath")) || + (!strcmp(argv[i], "--xpath"))) { + i++; + continue; + } +#endif + if ((timing) && (repeat)) + startTimer(); + /* Remember file names. "-" means stdin. */ + if ((argv[i][0] != '-') || (strcmp(argv[i], "-") == 0)) { + if (repeat) { + xmlParserCtxtPtr ctxt = NULL; + + for (acount = 0;acount < repeat;acount++) { +#ifdef LIBXML_READER_ENABLED + if (stream != 0) { + streamFile(argv[i]); + } else { +#endif /* LIBXML_READER_ENABLED */ + if (sax) { + testSAX(argv[i]); + } else { + if (ctxt == NULL) + ctxt = xmlNewParserCtxt(); + parseAndPrintFile(argv[i], ctxt); + } +#ifdef LIBXML_READER_ENABLED + } +#endif /* LIBXML_READER_ENABLED */ + } + if (ctxt != NULL) + xmlFreeParserCtxt(ctxt); + } else { + nbregister = 0; + +#ifdef LIBXML_READER_ENABLED + if (stream != 0) + streamFile(argv[i]); + else +#endif /* LIBXML_READER_ENABLED */ + if (sax) { + testSAX(argv[i]); + } else { + parseAndPrintFile(argv[i], NULL); + } + + if ((chkregister) && (nbregister != 0)) { + fprintf(stderr, "Registration count off: %d\n", nbregister); + progresult = XMLLINT_ERR_RDREGIS; + } + } + files ++; + if ((timing) && (repeat)) { + endTimer("%d iterations", repeat); + } + } + } + if (generate) + parseAndPrintFile(NULL, NULL); + if ((htmlout) && (!nowrap)) { + xmlGenericError(xmlGenericErrorContext, "\n"); + } + if ((files == 0) && (!generate) && (version == 0)) { + usage(argv[0]); + } +#ifdef LIBXML_SCHEMATRON_ENABLED + if (wxschematron != NULL) + xmlSchematronFree(wxschematron); +#endif +#ifdef LIBXML_SCHEMAS_ENABLED + if (relaxngschemas != NULL) + xmlRelaxNGFree(relaxngschemas); + if (wxschemas != NULL) + xmlSchemaFree(wxschemas); + xmlRelaxNGCleanupTypes(); +#endif +#ifdef LIBXML_PATTERN_ENABLED + if (patternc != NULL) + xmlFreePattern(patternc); +#endif + xmlCleanupParser(); + xmlMemoryDump(); + + return(progresult); +} + diff --git a/android/native/libxml2/xmlmemory.c b/android/native/libxml2/xmlmemory.c new file mode 100644 index 0000000000..a0ab9539cd --- /dev/null +++ b/android/native/libxml2/xmlmemory.c @@ -0,0 +1,1123 @@ +/* + * xmlmemory.c: libxml memory allocator wrapper. + * + * daniel@veillard.com + */ + +#define IN_LIBXML +#include "libxml.h" + +#include + +#ifdef HAVE_SYS_TYPES_H +#include +#endif + +#ifdef HAVE_TIME_H +#include +#endif + +#ifdef HAVE_STDLIB_H +#include +#else +#ifdef HAVE_MALLOC_H +#include +#endif +#endif + +#ifdef HAVE_CTYPE_H +#include +#endif + +/* #define DEBUG_MEMORY */ + +/** + * 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 /* must come before xmlmemory.h */ +#include +#include +#include + +static int xmlMemInitialized = 0; +static unsigned long debugMemSize = 0; +static unsigned long debugMemBlocks = 0; +static unsigned long debugMaxMemSize = 0; +static xmlMutexPtr xmlMemMutex = NULL; + +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 informations + */ + +#define MEMTAG 0x5aa5 + +#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; + + +#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)) \ + / ALIGN_SIZE ) * ALIGN_SIZE) + + +#define CLIENT_2_HDR(a) ((MEMHDR *) (((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. + * + * 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) +{ + MEMHDR *p; + void *ret; + + if (!xmlMemInitialized) xmlInitMemory(); +#ifdef DEBUG_MEMORY + xmlGenericError(xmlGenericErrorContext, + "Malloc(%d)\n",size); +#endif + + TEST_POINT + + p = (MEMHDR *) malloc(RESERVE_SIZE+size); + + if (!p) { + xmlGenericError(xmlGenericErrorContext, + "xmlMallocLoc : Out of free space\n"); + xmlMemoryDump(); + 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); + +#ifdef DEBUG_MEMORY + xmlGenericError(xmlGenericErrorContext, + "Malloc(%d) Ok\n",size); +#endif + + 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); +} + +/** + * xmlMallocAtomicLoc: + * @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. + * + * 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) +{ + MEMHDR *p; + void *ret; + + if (!xmlMemInitialized) xmlInitMemory(); +#ifdef DEBUG_MEMORY + xmlGenericError(xmlGenericErrorContext, + "Malloc(%d)\n",size); +#endif + + TEST_POINT + + p = (MEMHDR *) malloc(RESERVE_SIZE+size); + + if (!p) { + xmlGenericError(xmlGenericErrorContext, + "xmlMallocLoc : Out of free space\n"); + xmlMemoryDump(); + 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); + +#ifdef DEBUG_MEMORY + xmlGenericError(xmlGenericErrorContext, + "Malloc(%d) Ok\n",size); +#endif + + 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); +} +/** + * 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 * +xmlMemMalloc(size_t size) +{ + return(xmlMallocLoc(size, "none", 0)); +} + +/** + * 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 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) +{ + MEMHDR *p; + unsigned long number; +#ifdef DEBUG_MEMORY + size_t oldsize; +#endif + + if (ptr == NULL) + return(xmlMallocLoc(size, file, line)); + + if (!xmlMemInitialized) xmlInitMemory(); + TEST_POINT + + p = CLIENT_2_HDR(ptr); + number = p->mh_number; + if (xmlMemStopAtBlock == number) xmlMallocBreakpoint(); + if (p->mh_tag != MEMTAG) { + Mem_Tag_Err(p); + goto error; + } + p->mh_tag = ~MEMTAG; + xmlMutexLock(xmlMemMutex); + debugMemSize -= p->mh_size; + debugMemBlocks--; +#ifdef DEBUG_MEMORY + oldsize = p->mh_size; +#endif +#ifdef MEM_LIST + debugmem_list_delete(p); +#endif + xmlMutexUnlock(xmlMemMutex); + + p = (MEMHDR *) realloc(p,RESERVE_SIZE+size); + if (!p) { + goto error; + } + 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 += size; + debugMemBlocks++; + if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize; +#ifdef MEM_LIST + debugmem_list_add(p); +#endif + xmlMutexUnlock(xmlMemMutex); + + TEST_POINT + +#ifdef DEBUG_MEMORY + xmlGenericError(xmlGenericErrorContext, + "Realloced(%d to %d) Ok\n", oldsize, size); +#endif + 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)); +} + +/** + * xmlMemFree: + * @ptr: the memory block pointer + * + * a free() equivalent, with error checking. + */ +void +xmlMemFree(void *ptr) +{ + MEMHDR *p; + char *target; +#ifdef DEBUG_MEMORY + size_t size; +#endif + + if (ptr == NULL) + 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(); + } + + TEST_POINT + + target = (char *) ptr; + + p = CLIENT_2_HDR(ptr); + if (p->mh_tag != MEMTAG) { + Mem_Tag_Err(p); + goto error; + } + if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint(); + p->mh_tag = ~MEMTAG; + memset(target, -1, p->mh_size); + xmlMutexLock(xmlMemMutex); + debugMemSize -= p->mh_size; + debugMemBlocks--; +#ifdef DEBUG_MEMORY + size = p->mh_size; +#endif +#ifdef MEM_LIST + debugmem_list_delete(p); +#endif + xmlMutexUnlock(xmlMemMutex); + + free(p); + + TEST_POINT + +#ifdef DEBUG_MEMORY + xmlGenericError(xmlGenericErrorContext, + "Freed(%d) Ok\n", size); +#endif + + return; + +error: + xmlGenericError(xmlGenericErrorContext, + "xmlMemFree(%lX) error\n", (unsigned long) ptr); + xmlMallocBreakpoint(); + return; +} + +/** + * xmlMemStrdupLoc: + * @str: the initial string pointer + * @file: the file name or NULL + * @line: the line number + * + * a strdup() equivalent, with logging of the allocation info. + * + * Returns a pointer to the new string or NULL if allocation error occurred. + */ + +char * +xmlMemStrdupLoc(const char *str, const char *file, int line) +{ + char *s; + size_t size = strlen(str) + 1; + MEMHDR *p; + + if (!xmlMemInitialized) xmlInitMemory(); + TEST_POINT + + p = (MEMHDR *) malloc(RESERVE_SIZE+size); + if (!p) { + goto error; + } + 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(); + + if (s != NULL) + strcpy(s,str); + else + goto error; + + TEST_POINT + + if (xmlMemTraceBlockAt == s) { + xmlGenericError(xmlGenericErrorContext, + "%p : Strdup() Ok\n", xmlMemTraceBlockAt); + xmlMallocBreakpoint(); + } + + 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)); +} + +/** + * xmlMemUsed: + * + * Provides the amount of memory currently allocated + * + * Returns an int representing the amount of memory allocated. + */ + +int +xmlMemUsed(void) { + return(debugMemSize); +} + +/** + * xmlMemBlocks: + * + * Provides the number of memory areas currently allocated + * + * Returns an int representing the number of blocks + */ + +int +xmlMemBlocks(void) { + return(debugMemBlocks); +} + +#ifdef MEM_LIST +/** + * xmlMemContentShow: + * @fp: a FILE descriptor used as the output file + * @p: a memory block header + * + * tries to show some content from the memory block + */ + +static void +xmlMemContentShow(FILE *fp, MEMHDR *p) +{ + int i,j,k,len = p->mh_size; + const char *buf = (const char *) HDR_2_CLIENT(p); + + if (p == NULL) { + fprintf(fp, " NULL"); + return; + } + + for (i = 0;i < len;i++) { + if (buf[i] == 0) break; + if (!isprint((unsigned char) buf[i])) break; + } + if ((i < 4) && ((buf[i] != 0) || (i == 0))) { + if (len >= 4) { + MEMHDR *q; + void *cur; + + for (j = 0;(j < len -3) && (j < 40);j += 4) { + cur = *((void **) &buf[j]); + q = CLIENT_2_HDR(cur); + p = memlist; + k = 0; + while (p != NULL) { + if (p == q) break; + p = p->mh_next; + if (k++ > 100) break; + } + if ((p != NULL) && (p == q)) { + fprintf(fp, " pointer to #%lu at index %d", + p->mh_number, j); + return; + } + } + } + } else if ((i == 0) && (buf[i] == 0)) { + fprintf(fp," null"); + } else { + if (buf[i] == 0) fprintf(fp," \"%.25s\"", buf); + else { + fprintf(fp," ["); + for (j = 0;j < i;j++) + fprintf(fp,"%c", buf[j]); + fprintf(fp,"]"); + } + } +} +#endif + +/** + * xmlMemDisplayLast: + * @fp: a FILE descriptor used as the output file, if NULL, the result is + * written to the file .memorylist + * @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. + */ + +void +xmlMemDisplayLast(FILE *fp, long nbBytes) +{ +#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++; + if (nb < 100) + xmlMemContentShow(fp, p); + else + fprintf(fp," skip"); + + 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 + * + * show in-extenso the memory blocks allocated + */ + +void +xmlMemDisplay(FILE *fp) +{ +#ifdef MEM_LIST + MEMHDR *p; + unsigned idx; + int nb = 0; +#if defined(HAVE_LOCALTIME) && defined(HAVE_STRFTIME) + time_t currentTime; + char buf[500]; + struct tm * tstruct; +#endif +#endif + FILE *old_fp = fp; + + if (fp == NULL) { + fp = fopen(".memorylist", "w"); + if (fp == NULL) + return; + } + +#ifdef MEM_LIST +#if defined(HAVE_LOCALTIME) && defined(HAVE_STRFTIME) + currentTime = time(NULL); + tstruct = localtime(¤tTime); + strftime(buf, sizeof(buf) - 1, "%I:%M:%S %p", tstruct); + fprintf(fp," %s\n\n", buf); +#endif + + + 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++; + if (nb < 100) + xmlMemContentShow(fp, p); + else + fprintf(fp," skip"); + + 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; +#ifdef MEM_LIST_DEBUG + if (stderr) + Mem_Display(stderr); +#endif +} + +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; +#ifdef MEM_LIST_DEBUG + if (stderr) + Mem_Display(stderr); +#endif +} + +#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 + * @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 + */ + +void +xmlMemShow(FILE *fp, 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"); + xmlMemContentShow(fp, p); + 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 + */ + +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 */ +} + + +/**************************************************************** + * * + * Initialization Routines * + * * + ****************************************************************/ + +/** + * xmlInitMemory: + * + * Initialize the memory layer. + * + * Returns 0 on success + */ +int +xmlInitMemory(void) +{ +#ifdef HAVE_STDLIB_H + char *breakpoint; +#endif +#ifdef DEBUG_MEMORY + xmlGenericError(xmlGenericErrorContext, + "xmlInitMemory()\n"); +#endif + /* + This is really not good code (see Bug 130419). Suggestions for + improvement will be welcome! + */ + if (xmlMemInitialized) return(-1); + xmlMemInitialized = 1; + xmlMemMutex = xmlNewMutex(); + +#ifdef HAVE_STDLIB_H + breakpoint = getenv("XML_MEM_BREAKPOINT"); + if (breakpoint != NULL) { + sscanf(breakpoint, "%ud", &xmlMemStopAtBlock); + } +#endif +#ifdef HAVE_STDLIB_H + breakpoint = getenv("XML_MEM_TRACE"); + if (breakpoint != NULL) { + sscanf(breakpoint, "%p", &xmlMemTraceBlockAt); + } +#endif + +#ifdef DEBUG_MEMORY + xmlGenericError(xmlGenericErrorContext, + "xmlInitMemory() Ok\n"); +#endif + return(0); +} + +/** + * xmlCleanupMemory: + * + * Free up all the memory allocated by the library for its own + * use. This should not be called by user level code. + */ +void +xmlCleanupMemory(void) { +#ifdef DEBUG_MEMORY + xmlGenericError(xmlGenericErrorContext, + "xmlCleanupMemory()\n"); +#endif + if (xmlMemInitialized == 0) + return; + + xmlFreeMutex(xmlMemMutex); + xmlMemMutex = NULL; + xmlMemInitialized = 0; +#ifdef DEBUG_MEMORY + xmlGenericError(xmlGenericErrorContext, + "xmlCleanupMemory() Ok\n"); +#endif +} + +/** + * xmlMemSetup: + * @freeFunc: the free() function to use + * @mallocFunc: the malloc() function to use + * @reallocFunc: the realloc() function to use + * @strdupFunc: the strdup() function to use + * + * Override the default memory access functions with a new set + * This has to be called before any other libxml routines ! + * + * Should this be blocked if there was already some allocations + * done ? + * + * Returns 0 on success + */ +int +xmlMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc, + xmlReallocFunc reallocFunc, xmlStrdupFunc strdupFunc) { +#ifdef DEBUG_MEMORY + xmlGenericError(xmlGenericErrorContext, + "xmlMemSetup()\n"); +#endif + if (freeFunc == NULL) + return(-1); + if (mallocFunc == NULL) + return(-1); + if (reallocFunc == NULL) + return(-1); + if (strdupFunc == NULL) + return(-1); + xmlFree = freeFunc; + xmlMalloc = mallocFunc; + xmlMallocAtomic = mallocFunc; + xmlRealloc = reallocFunc; + xmlMemStrdup = strdupFunc; +#ifdef DEBUG_MEMORY + xmlGenericError(xmlGenericErrorContext, + "xmlMemSetup() Ok\n"); +#endif + return(0); +} + +/** + * xmlMemGet: + * @freeFunc: place to save the free() function in use + * @mallocFunc: place to save the malloc() function in use + * @reallocFunc: place to save the realloc() function in use + * @strdupFunc: place to save the strdup() function in use + * + * Provides the memory access functions set currently in use + * + * Returns 0 on success + */ +int +xmlMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc, + xmlReallocFunc *reallocFunc, xmlStrdupFunc *strdupFunc) { + if (freeFunc != NULL) *freeFunc = xmlFree; + if (mallocFunc != NULL) *mallocFunc = xmlMalloc; + if (reallocFunc != NULL) *reallocFunc = xmlRealloc; + if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup; + return(0); +} + +/** + * xmlGcMemSetup: + * @freeFunc: the free() function to use + * @mallocFunc: the malloc() function to use + * @mallocAtomicFunc: the malloc() function to use for atomic allocations + * @reallocFunc: the realloc() function to use + * @strdupFunc: the strdup() function to use + * + * Override the default memory access functions with a new set + * This has to be called before any other libxml routines ! + * The mallocAtomicFunc is specialized for atomic block + * allocations (i.e. of areas useful for garbage collected memory allocators + * + * Should this be blocked if there was already some allocations + * done ? + * + * Returns 0 on success + */ +int +xmlGcMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc, + xmlMallocFunc mallocAtomicFunc, xmlReallocFunc reallocFunc, + xmlStrdupFunc strdupFunc) { +#ifdef DEBUG_MEMORY + xmlGenericError(xmlGenericErrorContext, + "xmlGcMemSetup()\n"); +#endif + if (freeFunc == NULL) + return(-1); + if (mallocFunc == NULL) + return(-1); + if (mallocAtomicFunc == NULL) + return(-1); + if (reallocFunc == NULL) + return(-1); + if (strdupFunc == NULL) + return(-1); + xmlFree = freeFunc; + xmlMalloc = mallocFunc; + xmlMallocAtomic = mallocAtomicFunc; + xmlRealloc = reallocFunc; + xmlMemStrdup = strdupFunc; +#ifdef DEBUG_MEMORY + xmlGenericError(xmlGenericErrorContext, + "xmlGcMemSetup() Ok\n"); +#endif + return(0); +} + +/** + * xmlGcMemGet: + * @freeFunc: place to save the free() function in use + * @mallocFunc: place to save the malloc() function in use + * @mallocAtomicFunc: place to save the atomic malloc() function in use + * @reallocFunc: place to save the realloc() function in use + * @strdupFunc: place to save the strdup() function in use + * + * Provides the memory access functions set currently in use + * The mallocAtomicFunc is specialized for atomic block + * allocations (i.e. of areas useful for garbage collected memory allocators + * + * Returns 0 on success + */ +int +xmlGcMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc, + xmlMallocFunc *mallocAtomicFunc, xmlReallocFunc *reallocFunc, + xmlStrdupFunc *strdupFunc) { + if (freeFunc != NULL) *freeFunc = xmlFree; + if (mallocFunc != NULL) *mallocFunc = xmlMalloc; + if (mallocAtomicFunc != NULL) *mallocAtomicFunc = xmlMallocAtomic; + if (reallocFunc != NULL) *reallocFunc = xmlRealloc; + if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup; + return(0); +} + +#define bottom_xmlmemory +#include "elfgcchack.h" diff --git a/android/native/libxml2/xmlmodule.c b/android/native/libxml2/xmlmodule.c new file mode 100644 index 0000000000..9ffd610cae --- /dev/null +++ b/android/native/libxml2/xmlmodule.c @@ -0,0 +1,445 @@ +/* + * xmlmodule.c : basic API for dynamic module loading added 2.6.17 + * + * See Copyright for the status of this software. + * + * joelwreed@comcast.net + * + * http://www.fortran-2000.com/ArnaudRecipes/sharedlib.html + */ + +#define IN_LIBXML +#include "libxml.h" + +#include +#include +#include +#include +#include + +#ifdef LIBXML_MODULES_ENABLED + +struct _xmlModule { + unsigned char *name; + void *handle; +}; + +static void *xmlModulePlatformOpen(const char *name); +static int xmlModulePlatformClose(void *handle); +static int xmlModulePlatformSymbol(void *handle, const char *name, void **result); + +/************************************************************************ + * * + * module memory error handler * + * * + ************************************************************************/ + +/** + * xmlModuleErrMemory: + * @extra: extra information + * + * Handle an out of memory condition + */ +static void +xmlModuleErrMemory(xmlModulePtr module, const char *extra) +{ + const char *name = NULL; + + if (module != NULL) { + name = (const char *) module->name; + } + + __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_MODULE, + XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra, + name, NULL, 0, 0, + "Memory allocation failed : %s\n", extra); +} + +/** + * xmlModuleOpen: + * @name: the module name + * @options: a set of xmlModuleOption + * + * Opens a module/shared library given its name or path + * TODO: options are not yet implemented. + * + * Returns a handle for the module or NULL in case of error + */ +xmlModulePtr +xmlModuleOpen(const char *name, int options ATTRIBUTE_UNUSED) +{ + xmlModulePtr module; + + module = (xmlModulePtr) xmlMalloc(sizeof(xmlModule)); + if (module == NULL) { + xmlModuleErrMemory(NULL, "creating module"); + return (NULL); + } + + memset(module, 0, sizeof(xmlModule)); + + module->handle = xmlModulePlatformOpen(name); + + if (module->handle == NULL) { + xmlFree(module); + __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_MODULE, + XML_MODULE_OPEN, XML_ERR_FATAL, NULL, 0, 0, + name, NULL, 0, 0, "failed to open %s\n", name); + return(NULL); + } + + module->name = xmlStrdup((const xmlChar *) name); + return (module); +} + +/** + * xmlModuleSymbol: + * @module: the module + * @name: the name of the symbol + * @symbol: the resulting symbol address + * + * Lookup for a symbol address in the given module + * + * Returns 0 if the symbol was found, or -1 in case of error + */ +int +xmlModuleSymbol(xmlModulePtr module, const char *name, void **symbol) +{ + int rc = -1; + + if ((NULL == module) || (symbol == NULL)) { + __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_MODULE, + XML_MODULE_OPEN, XML_ERR_FATAL, NULL, 0, 0, + NULL, NULL, 0, 0, "null parameter\n"); + return rc; + } + + rc = xmlModulePlatformSymbol(module->handle, name, symbol); + + if (rc == -1) { + __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_MODULE, + XML_MODULE_OPEN, XML_ERR_FATAL, NULL, 0, 0, + name, NULL, 0, 0, + "failed to find symbol: %s\n", + (name == NULL ? "NULL" : name)); + return rc; + } + + return rc; +} + +/** + * xmlModuleClose: + * @module: the module handle + * + * The close operations unload the associated module and free the + * data associated to the module. + * + * Returns 0 in case of success, -1 in case of argument error and -2 + * if the module could not be closed/unloaded. + */ +int +xmlModuleClose(xmlModulePtr module) +{ + int rc; + + if (NULL == module) { + __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_MODULE, + XML_MODULE_CLOSE, XML_ERR_FATAL, NULL, 0, 0, + NULL, NULL, 0, 0, "null module pointer\n"); + return -1; + } + + rc = xmlModulePlatformClose(module->handle); + + if (rc != 0) { + __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_MODULE, + XML_MODULE_CLOSE, XML_ERR_FATAL, NULL, 0, 0, + (const char *) module->name, NULL, 0, 0, + "failed to close: %s\n", module->name); + return -2; + } + + rc = xmlModuleFree(module); + return (rc); +} + +/** + * xmlModuleFree: + * @module: the module handle + * + * The free operations free the data associated to the module + * but does not unload the associated shared library which may still + * be in use. + * + * Returns 0 in case of success, -1 in case of argument error + */ +int +xmlModuleFree(xmlModulePtr module) +{ + if (NULL == module) { + __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_MODULE, + XML_MODULE_CLOSE, XML_ERR_FATAL, NULL, 0, NULL, + NULL, NULL, 0, 0, "null module pointer\n"); + return -1; + } + + xmlFree(module->name); + xmlFree(module); + + return (0); +} + +#if defined(HAVE_DLOPEN) && !defined(_WIN32) +#ifdef HAVE_DLFCN_H +#include +#endif + +#ifndef RTLD_GLOBAL /* For Tru64 UNIX 4.0 */ +#define RTLD_GLOBAL 0 +#endif + +/** + * xmlModulePlatformOpen: + * @name: path to the module + * + * returns a handle on success, and zero on error. + */ + +static void * +xmlModulePlatformOpen(const char *name) +{ + return dlopen(name, RTLD_GLOBAL | RTLD_NOW); +} + +/* + * xmlModulePlatformClose: + * @handle: handle to the module + * + * returns 0 on success, and non-zero on error. + */ + +static int +xmlModulePlatformClose(void *handle) +{ + return dlclose(handle); +} + +/* + * xmlModulePlatformSymbol: + * http://www.opengroup.org/onlinepubs/009695399/functions/dlsym.html + * returns 0 on success and the loaded symbol in result, and -1 on error. + */ + +static int +xmlModulePlatformSymbol(void *handle, const char *name, void **symbol) +{ + *symbol = dlsym(handle, name); + if (dlerror() != NULL) { + return -1; + } + return 0; +} + +#else /* ! HAVE_DLOPEN */ + +#ifdef HAVE_SHLLOAD /* HAVE_SHLLOAD */ +#ifdef HAVE_DL_H +#include +#endif +/* + * xmlModulePlatformOpen: + * returns a handle on success, and zero on error. + */ + +static void * +xmlModulePlatformOpen(const char *name) +{ + return shl_load(name, BIND_IMMEDIATE, 0L); +} + +/* + * xmlModulePlatformClose: + * returns 0 on success, and non-zero on error. + */ + +static int +xmlModulePlatformClose(void *handle) +{ + return shl_unload(handle); +} + +/* + * xmlModulePlatformSymbol: + * http://docs.hp.com/en/B2355-90683/shl_load.3X.html + * returns 0 on success and the loaded symbol in result, and -1 on error. + */ + +static int +xmlModulePlatformSymbol(void *handle, const char *name, void **symbol) +{ + int rc; + + errno = 0; + rc = shl_findsym(&handle, name, TYPE_UNDEFINED, symbol); + return rc; +} + +#endif /* HAVE_SHLLOAD */ +#endif /* ! HAVE_DLOPEN */ + +#ifdef _WIN32 + +#include + +/* + * xmlModulePlatformOpen: + * returns a handle on success, and zero on error. + */ + +static void * +xmlModulePlatformOpen(const char *name) +{ + return LoadLibrary(name); +} + +/* + * xmlModulePlatformClose: + * returns 0 on success, and non-zero on error. + */ + +static int +xmlModulePlatformClose(void *handle) +{ + int rc; + + rc = FreeLibrary(handle); + return (0 == rc); +} + +/* + * xmlModulePlatformSymbol: + * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/getprocaddress.asp + * returns 0 on success and the loaded symbol in result, and -1 on error. + */ + +static int +xmlModulePlatformSymbol(void *handle, const char *name, void **symbol) +{ + *symbol = GetProcAddress(handle, name); + return (NULL == *symbol) ? -1 : 0; +} + +#endif /* _WIN32 */ + +#ifdef HAVE_BEOS + +#include + +/* + * xmlModulePlatformOpen: + * beos api info: http://www.beunited.org/bebook/The%20Kernel%20Kit/Images.html + * returns a handle on success, and zero on error. + */ + +static void * +xmlModulePlatformOpen(const char *name) +{ + return (void *) load_add_on(name); +} + +/* + * xmlModulePlatformClose: + * beos api info: http://www.beunited.org/bebook/The%20Kernel%20Kit/Images.html + * returns 0 on success, and non-zero on error. + */ + +static int +xmlModulePlatformClose(void *handle) +{ + status_t rc; + + rc = unload_add_on((image_id) handle); + + if (rc == B_OK) + return 0; + else + return -1; +} + +/* + * xmlModulePlatformSymbol: + * beos api info: http://www.beunited.org/bebook/The%20Kernel%20Kit/Images.html + * returns 0 on success and the loaded symbol in result, and -1 on error. + */ + +static int +xmlModulePlatformSymbol(void *handle, const char *name, void **symbol) +{ + status_t rc; + + rc = get_image_symbol((image_id) handle, name, B_SYMBOL_TYPE_ANY, symbol); + + return (rc == B_OK) ? 0 : -1; +} + +#endif /* HAVE_BEOS */ + +#ifdef HAVE_OS2 + +#include + +/* + * xmlModulePlatformOpen: + * os2 api info: http://www.edm2.com/os2api/Dos/DosLoadModule.html + * returns a handle on success, and zero on error. + */ + +static void * +xmlModulePlatformOpen(const char *name) +{ + char errbuf[256]; + void *handle; + int rc; + + rc = DosLoadModule(errbuf, sizeof(errbuf) - 1, name, &handle); + + if (rc) + return 0; + else + return (handle); +} + +/* + * xmlModulePlatformClose: + * os2 api info: http://www.edm2.com/os2api/Dos/DosFreeModule.html + * returns 0 on success, and non-zero on error. + */ + +static int +xmlModulePlatformClose(void *handle) +{ + return DosFreeModule(handle); +} + +/* + * xmlModulePlatformSymbol: + * os2 api info: http://www.edm2.com/os2api/Dos/DosQueryProcAddr.html + * returns 0 on success and the loaded symbol in result, and -1 on error. + */ + +static int +xmlModulePlatformSymbol(void *handle, const char *name, void **symbol) +{ + int rc; + + rc = DosQueryProcAddr(handle, 0, name, symbol); + + return (rc == NO_ERROR) ? 0 : -1; +} + +#endif /* HAVE_OS2 */ + +#define bottom_xmlmodule +#include "elfgcchack.h" +#endif /* LIBXML_MODULES_ENABLED */ diff --git a/android/native/libxml2/xmlreader.c b/android/native/libxml2/xmlreader.c new file mode 100644 index 0000000000..97c71abbf3 --- /dev/null +++ b/android/native/libxml2/xmlreader.c @@ -0,0 +1,5766 @@ +/* + * xmlreader.c: implements the xmlTextReader streaming node API + * + * NOTE: + * XmlTextReader.Normalization Property won't be supported, since + * it makes the parser non compliant to the XML recommendation + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + */ + +/* + * TODOs: + * - XML Schemas validation + */ +#define IN_LIBXML +#include "libxml.h" + +#ifdef LIBXML_READER_ENABLED +#include /* for memset() only ! */ +#include + +#ifdef HAVE_CTYPE_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif + +#include +#include +#include +#include +#ifdef LIBXML_SCHEMAS_ENABLED +#include +#include +#endif +#include +#ifdef LIBXML_XINCLUDE_ENABLED +#include +#endif +#ifdef LIBXML_PATTERN_ENABLED +#include +#endif + +#define MAX_ERR_MSG_SIZE 64000 + +/* + * 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 (i.e. it may need + * something involving a memcpy) but (hopefully) will be + * sufficient for libxml2. + */ +#ifndef VA_COPY + #ifdef HAVE_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 + #define VA_COPY(dest,src) (dest) = (src) + #endif + #endif +#endif + +/* #define DEBUG_CALLBACKS */ +/* #define DEBUG_READER */ + +/** + * TODO: + * + * macro to flag unimplemented blocks + */ +#define TODO \ + xmlGenericError(xmlGenericErrorContext, \ + "Unimplemented block at %s:%d\n", \ + __FILE__, __LINE__); + +#ifdef DEBUG_READER +#define DUMP_READER xmlTextReaderDebug(reader); +#else +#define DUMP_READER +#endif + +#define CHUNK_SIZE 512 +/************************************************************************ + * * + * The parser: maps the Text Reader API on top of the existing * + * parsing routines building a tree * + * * + ************************************************************************/ + +#define XML_TEXTREADER_INPUT 1 +#define XML_TEXTREADER_CTXT 2 + +typedef enum { + XML_TEXTREADER_NONE = -1, + XML_TEXTREADER_START= 0, + XML_TEXTREADER_ELEMENT= 1, + XML_TEXTREADER_END= 2, + XML_TEXTREADER_EMPTY= 3, + XML_TEXTREADER_BACKTRACK= 4, + XML_TEXTREADER_DONE= 5, + XML_TEXTREADER_ERROR= 6 +} xmlTextReaderState; + +typedef enum { + XML_TEXTREADER_NOT_VALIDATE = 0, + XML_TEXTREADER_VALIDATE_DTD = 1, + XML_TEXTREADER_VALIDATE_RNG = 2, + XML_TEXTREADER_VALIDATE_XSD = 4 +} xmlTextReaderValidate; + +struct _xmlTextReader { + int mode; /* the parsing mode */ + xmlDocPtr doc; /* when walking an existing doc */ + xmlTextReaderValidate validate;/* is there any validation */ + int allocs; /* what structure were deallocated */ + xmlTextReaderState state; + xmlParserCtxtPtr ctxt; /* the parser context */ + xmlSAXHandlerPtr sax; /* the parser SAX callbacks */ + xmlParserInputBufferPtr input; /* the input */ + startElementSAXFunc startElement;/* initial SAX callbacks */ + endElementSAXFunc endElement; /* idem */ + startElementNsSAX2Func startElementNs;/* idem */ + endElementNsSAX2Func endElementNs; /* idem */ + charactersSAXFunc characters; + cdataBlockSAXFunc cdataBlock; + unsigned int base; /* base of the segment in the input */ + unsigned int cur; /* current position in the input */ + xmlNodePtr node; /* current node */ + xmlNodePtr curnode;/* current attribute node */ + int depth; /* depth of the current node */ + xmlNodePtr faketext;/* fake xmlNs chld */ + int preserve;/* preserve the resulting document */ + xmlBufferPtr buffer; /* used to return const xmlChar * */ + xmlDictPtr dict; /* the context dictionnary */ + + /* entity stack when traversing entities content */ + xmlNodePtr ent; /* Current Entity Ref Node */ + int entNr; /* Depth of the entities stack */ + int entMax; /* Max depth of the entities stack */ + xmlNodePtr *entTab; /* array of entities */ + + /* error handling */ + xmlTextReaderErrorFunc errorFunc; /* callback function */ + void *errorFuncArg; /* callback function user argument */ + +#ifdef LIBXML_SCHEMAS_ENABLED + /* Handling of RelaxNG validation */ + xmlRelaxNGPtr rngSchemas; /* The Relax NG schemas */ + xmlRelaxNGValidCtxtPtr rngValidCtxt;/* The Relax NG validation context */ + int rngValidErrors;/* The number of errors detected */ + xmlNodePtr rngFullNode; /* the node if RNG not progressive */ + /* Handling of Schemas validation */ + xmlSchemaPtr xsdSchemas; /* The Schemas schemas */ + xmlSchemaValidCtxtPtr xsdValidCtxt;/* The Schemas validation context */ + int xsdPreserveCtxt; /* 1 if the context was provided by the user */ + int xsdValidErrors;/* The number of errors detected */ + xmlSchemaSAXPlugPtr xsdPlug; /* the schemas plug in SAX pipeline */ +#endif +#ifdef LIBXML_XINCLUDE_ENABLED + /* Handling of XInclude processing */ + int xinclude; /* is xinclude asked for */ + const xmlChar * xinclude_name; /* the xinclude name from dict */ + xmlXIncludeCtxtPtr xincctxt; /* the xinclude context */ + int in_xinclude; /* counts for xinclude */ +#endif +#ifdef LIBXML_PATTERN_ENABLED + int patternNr; /* number of preserve patterns */ + int patternMax; /* max preserve patterns */ + xmlPatternPtr *patternTab; /* array of preserve patterns */ +#endif + int preserves; /* level of preserves */ + int parserFlags; /* the set of options set */ + /* Structured error handling */ + xmlStructuredErrorFunc sErrorFunc; /* callback function */ +}; + +#define NODE_IS_EMPTY 0x1 +#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 + * + * Free a string if it is not owned by the "dict" dictionnary in the + * current scope + */ +#define DICT_FREE(str) \ + if ((str) && ((!dict) || \ + (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \ + xmlFree((char *)(str)); + +static void xmlTextReaderFreeNode(xmlTextReaderPtr reader, xmlNodePtr cur); +static void xmlTextReaderFreeNodeList(xmlTextReaderPtr reader, xmlNodePtr cur); + +/** + * xmlFreeID: + * @not: A id + * + * Deallocate the memory used by an id definition + */ +static void +xmlFreeID(xmlIDPtr id) { + xmlDictPtr dict = NULL; + + if (id == NULL) return; + + if (id->doc != NULL) + dict = id->doc->dict; + + if (id->value != NULL) + DICT_FREE(id->value) + xmlFree(id); +} + +/** + * xmlTextReaderRemoveID: + * @doc: the document + * @attr: the attribute + * + * Remove the given attribute from the ID table maintained internally. + * + * Returns -1 if the lookup failed and 0 otherwise + */ +static int +xmlTextReaderRemoveID(xmlDocPtr doc, xmlAttrPtr attr) { + xmlIDTablePtr table; + xmlIDPtr id; + xmlChar *ID; + + if (doc == NULL) return(-1); + if (attr == NULL) return(-1); + table = (xmlIDTablePtr) doc->ids; + if (table == NULL) + return(-1); + + ID = xmlNodeListGetString(doc, attr->children, 1); + if (ID == NULL) + return(-1); + id = xmlHashLookup(table, ID); + xmlFree(ID); + if (id == NULL || id->attr != attr) { + return(-1); + } + id->name = attr->name; + id->attr = NULL; + return(0); +} + +/** + * xmlTextReaderFreeProp: + * @reader: the xmlTextReaderPtr used + * @cur: the node + * + * Free a node. + */ +static void +xmlTextReaderFreeProp(xmlTextReaderPtr reader, xmlAttrPtr cur) { + xmlDictPtr dict; + + dict = reader->ctxt->dict; + if (cur == NULL) return; + + if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue)) + xmlDeregisterNodeDefaultValue((xmlNodePtr) cur); + + /* Check for ID removal -> leading to invalid references ! */ + if ((cur->parent != NULL) && (cur->parent->doc != NULL) && + ((cur->parent->doc->intSubset != NULL) || + (cur->parent->doc->extSubset != NULL))) { + if (xmlIsID(cur->parent->doc, cur->parent, cur)) + xmlTextReaderRemoveID(cur->parent->doc, cur); + } + if (cur->children != NULL) + xmlTextReaderFreeNodeList(reader, cur->children); + + DICT_FREE(cur->name); + if ((reader != NULL) && (reader->ctxt != NULL) && + (reader->ctxt->freeAttrsNr < 100)) { + cur->next = reader->ctxt->freeAttrs; + reader->ctxt->freeAttrs = cur; + reader->ctxt->freeAttrsNr++; + } else { + xmlFree(cur); + } +} + +/** + * xmlTextReaderFreePropList: + * @reader: the xmlTextReaderPtr used + * @cur: the first property in the list + * + * Free a property and all its siblings, all the children are freed too. + */ +static void +xmlTextReaderFreePropList(xmlTextReaderPtr reader, xmlAttrPtr cur) { + xmlAttrPtr next; + if (cur == NULL) return; + while (cur != NULL) { + next = cur->next; + xmlTextReaderFreeProp(reader, cur); + cur = next; + } +} + +/** + * xmlTextReaderFreeNodeList: + * @reader: the xmlTextReaderPtr used + * @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. + */ +static void +xmlTextReaderFreeNodeList(xmlTextReaderPtr reader, xmlNodePtr cur) { + xmlNodePtr next; + xmlDictPtr dict; + + dict = reader->ctxt->dict; + if (cur == NULL) return; + if (cur->type == XML_NAMESPACE_DECL) { + xmlFreeNsList((xmlNsPtr) cur); + return; + } + if ((cur->type == XML_DOCUMENT_NODE) || + (cur->type == XML_HTML_DOCUMENT_NODE)) { + xmlFreeDoc((xmlDocPtr) cur); + return; + } + while (cur != NULL) { + next = cur->next; + /* unroll to speed up freeing the document */ + if (cur->type != XML_DTD_NODE) { + + if ((cur->children != NULL) && + (cur->type != XML_ENTITY_REF_NODE)) { + if (cur->children->parent == cur) + xmlTextReaderFreeNodeList(reader, cur->children); + cur->children = NULL; + } + + if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue)) + xmlDeregisterNodeDefaultValue(cur); + + if (((cur->type == XML_ELEMENT_NODE) || + (cur->type == XML_XINCLUDE_START) || + (cur->type == XML_XINCLUDE_END)) && + (cur->properties != NULL)) + xmlTextReaderFreePropList(reader, cur->properties); + if ((cur->content != (xmlChar *) &(cur->properties)) && + (cur->type != XML_ELEMENT_NODE) && + (cur->type != XML_XINCLUDE_START) && + (cur->type != XML_XINCLUDE_END) && + (cur->type != XML_ENTITY_REF_NODE)) { + DICT_FREE(cur->content); + } + if (((cur->type == XML_ELEMENT_NODE) || + (cur->type == XML_XINCLUDE_START) || + (cur->type == XML_XINCLUDE_END)) && + (cur->nsDef != NULL)) + xmlFreeNsList(cur->nsDef); + + /* + * we don't free element names here they are interned now + */ + if ((cur->type != XML_TEXT_NODE) && + (cur->type != XML_COMMENT_NODE)) + DICT_FREE(cur->name); + if (((cur->type == XML_ELEMENT_NODE) || + (cur->type == XML_TEXT_NODE)) && + (reader != NULL) && (reader->ctxt != NULL) && + (reader->ctxt->freeElemsNr < 100)) { + cur->next = reader->ctxt->freeElems; + reader->ctxt->freeElems = cur; + reader->ctxt->freeElemsNr++; + } else { + xmlFree(cur); + } + } + cur = next; + } +} + +/** + * xmlTextReaderFreeNode: + * @reader: the xmlTextReaderPtr used + * @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. + */ +static void +xmlTextReaderFreeNode(xmlTextReaderPtr reader, xmlNodePtr cur) { + xmlDictPtr dict; + + dict = reader->ctxt->dict; + if (cur->type == XML_DTD_NODE) { + xmlFreeDtd((xmlDtdPtr) cur); + return; + } + if (cur->type == XML_NAMESPACE_DECL) { + xmlFreeNs((xmlNsPtr) cur); + return; + } + if (cur->type == XML_ATTRIBUTE_NODE) { + xmlTextReaderFreeProp(reader, (xmlAttrPtr) cur); + return; + } + + if ((cur->children != NULL) && + (cur->type != XML_ENTITY_REF_NODE)) { + if (cur->children->parent == cur) + xmlTextReaderFreeNodeList(reader, cur->children); + cur->children = NULL; + } + + if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue)) + xmlDeregisterNodeDefaultValue(cur); + + if (((cur->type == XML_ELEMENT_NODE) || + (cur->type == XML_XINCLUDE_START) || + (cur->type == XML_XINCLUDE_END)) && + (cur->properties != NULL)) + xmlTextReaderFreePropList(reader, cur->properties); + if ((cur->content != (xmlChar *) &(cur->properties)) && + (cur->type != XML_ELEMENT_NODE) && + (cur->type != XML_XINCLUDE_START) && + (cur->type != XML_XINCLUDE_END) && + (cur->type != XML_ENTITY_REF_NODE)) { + DICT_FREE(cur->content); + } + if (((cur->type == XML_ELEMENT_NODE) || + (cur->type == XML_XINCLUDE_START) || + (cur->type == XML_XINCLUDE_END)) && + (cur->nsDef != NULL)) + xmlFreeNsList(cur->nsDef); + + /* + * we don't free names here they are interned now + */ + if ((cur->type != XML_TEXT_NODE) && + (cur->type != XML_COMMENT_NODE)) + DICT_FREE(cur->name); + + if (((cur->type == XML_ELEMENT_NODE) || + (cur->type == XML_TEXT_NODE)) && + (reader != NULL) && (reader->ctxt != NULL) && + (reader->ctxt->freeElemsNr < 100)) { + cur->next = reader->ctxt->freeElems; + reader->ctxt->freeElems = cur; + reader->ctxt->freeElemsNr++; + } else { + xmlFree(cur); + } +} + +/** + * xmlTextReaderFreeIDTable: + * @table: An id table + * + * Deallocate the memory used by an ID hash table. + */ +static void +xmlTextReaderFreeIDTable(xmlIDTablePtr table) { + xmlHashFree(table, (xmlHashDeallocator) xmlFreeID); +} + +/** + * xmlTextReaderFreeDoc: + * @reader: the xmlTextReaderPtr used + * @cur: pointer to the document + * + * Free up all the structures used by a document, tree included. + */ +static void +xmlTextReaderFreeDoc(xmlTextReaderPtr reader, xmlDocPtr cur) { + xmlDtdPtr extSubset, intSubset; + + if (cur == NULL) return; + + if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue)) + xmlDeregisterNodeDefaultValue((xmlNodePtr) cur); + + /* + * Do this before freeing the children list to avoid ID lookups + */ + if (cur->ids != NULL) xmlTextReaderFreeIDTable((xmlIDTablePtr) cur->ids); + cur->ids = NULL; + if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs); + cur->refs = NULL; + extSubset = cur->extSubset; + intSubset = cur->intSubset; + if (intSubset == extSubset) + extSubset = NULL; + if (extSubset != NULL) { + xmlUnlinkNode((xmlNodePtr) cur->extSubset); + cur->extSubset = NULL; + xmlFreeDtd(extSubset); + } + if (intSubset != NULL) { + xmlUnlinkNode((xmlNodePtr) cur->intSubset); + cur->intSubset = NULL; + xmlFreeDtd(intSubset); + } + + if (cur->children != NULL) xmlTextReaderFreeNodeList(reader, cur->children); + + if (cur->version != NULL) xmlFree((char *) cur->version); + if (cur->name != NULL) xmlFree((char *) cur->name); + if (cur->encoding != NULL) xmlFree((char *) cur->encoding); + if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs); + if (cur->URL != NULL) xmlFree((char *) cur->URL); + if (cur->dict != NULL) xmlDictFree(cur->dict); + + xmlFree(cur); +} + +/************************************************************************ + * * + * The reader core parser * + * * + ************************************************************************/ +#ifdef DEBUG_READER +static void +xmlTextReaderDebug(xmlTextReaderPtr reader) { + if ((reader == NULL) || (reader->ctxt == NULL)) { + fprintf(stderr, "xmlTextReader NULL\n"); + return; + } + fprintf(stderr, "xmlTextReader: state %d depth %d ", + reader->state, reader->depth); + if (reader->node == NULL) { + fprintf(stderr, "node = NULL\n"); + } else { + fprintf(stderr, "node %s\n", reader->node->name); + } + fprintf(stderr, " input: base %d, cur %d, depth %d: ", + reader->base, reader->cur, reader->ctxt->nodeNr); + if (reader->input->buffer == NULL) { + fprintf(stderr, "buffer is NULL\n"); + } else { +#ifdef LIBXML_DEBUG_ENABLED + xmlDebugDumpString(stderr, + &reader->input->buffer->content[reader->cur]); +#endif + fprintf(stderr, "\n"); + } +} +#endif + +/** + * xmlTextReaderEntPush: + * @reader: the xmlTextReaderPtr used + * @value: the entity reference node + * + * Pushes a new entity reference node on top of the entities stack + * + * Returns 0 in case of error, the index in the stack otherwise + */ +static int +xmlTextReaderEntPush(xmlTextReaderPtr reader, xmlNodePtr value) +{ + if (reader->entMax <= 0) { + reader->entMax = 10; + reader->entTab = (xmlNodePtr *) xmlMalloc(reader->entMax * + sizeof(reader->entTab[0])); + if (reader->entTab == NULL) { + xmlGenericError(xmlGenericErrorContext, "xmlMalloc failed !\n"); + return (0); + } + } + if (reader->entNr >= reader->entMax) { + reader->entMax *= 2; + reader->entTab = + (xmlNodePtr *) xmlRealloc(reader->entTab, + reader->entMax * + sizeof(reader->entTab[0])); + if (reader->entTab == NULL) { + xmlGenericError(xmlGenericErrorContext, "xmlRealloc failed !\n"); + return (0); + } + } + reader->entTab[reader->entNr] = value; + reader->ent = value; + return (reader->entNr++); +} + +/** + * xmlTextReaderEntPop: + * @reader: the xmlTextReaderPtr used + * + * Pops the top element entity from the entities stack + * + * Returns the entity just removed + */ +static xmlNodePtr +xmlTextReaderEntPop(xmlTextReaderPtr reader) +{ + xmlNodePtr ret; + + if (reader->entNr <= 0) + return (NULL); + reader->entNr--; + if (reader->entNr > 0) + reader->ent = reader->entTab[reader->entNr - 1]; + else + reader->ent = NULL; + ret = reader->entTab[reader->entNr]; + reader->entTab[reader->entNr] = NULL; + return (ret); +} + +/** + * xmlTextReaderStartElement: + * @ctx: the user data (XML parser context) + * @fullname: The element name, including namespace prefix + * @atts: An array of name/value attributes pairs, NULL terminated + * + * called when an opening tag has been processed. + */ +static void +xmlTextReaderStartElement(void *ctx, const xmlChar *fullname, + const xmlChar **atts) { + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + xmlTextReaderPtr reader = ctxt->_private; + +#ifdef DEBUG_CALLBACKS + printf("xmlTextReaderStartElement(%s)\n", fullname); +#endif + if ((reader != NULL) && (reader->startElement != NULL)) { + reader->startElement(ctx, fullname, atts); + if ((ctxt->node != NULL) && (ctxt->input != NULL) && + (ctxt->input->cur != NULL) && (ctxt->input->cur[0] == '/') && + (ctxt->input->cur[1] == '>')) + ctxt->node->extra = NODE_IS_EMPTY; + } + if (reader != NULL) + reader->state = XML_TEXTREADER_ELEMENT; +} + +/** + * xmlTextReaderEndElement: + * @ctx: the user data (XML parser context) + * @fullname: The element name, including namespace prefix + * + * called when an ending tag has been processed. + */ +static void +xmlTextReaderEndElement(void *ctx, const xmlChar *fullname) { + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + xmlTextReaderPtr reader = ctxt->_private; + +#ifdef DEBUG_CALLBACKS + printf("xmlTextReaderEndElement(%s)\n", fullname); +#endif + if ((reader != NULL) && (reader->endElement != NULL)) { + reader->endElement(ctx, fullname); + } +} + +/** + * xmlTextReaderStartElementNs: + * @ctx: the user data (XML parser context) + * @localname: the local name of the element + * @prefix: the element namespace prefix if available + * @URI: the element namespace name if available + * @nb_namespaces: number of namespace definitions on that node + * @namespaces: pointer to the array of prefix/URI pairs namespace definitions + * @nb_attributes: the number of attributes on that node + * nb_defaulted: the number of defaulted attributes. + * @attributes: pointer to the array of (localname/prefix/URI/value/end) + * attribute values. + * + * called when an opening tag has been processed. + */ +static void +xmlTextReaderStartElementNs(void *ctx, + const xmlChar *localname, + const xmlChar *prefix, + const xmlChar *URI, + int nb_namespaces, + const xmlChar **namespaces, + int nb_attributes, + int nb_defaulted, + const xmlChar **attributes) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + xmlTextReaderPtr reader = ctxt->_private; + +#ifdef DEBUG_CALLBACKS + printf("xmlTextReaderStartElementNs(%s)\n", localname); +#endif + if ((reader != NULL) && (reader->startElementNs != NULL)) { + reader->startElementNs(ctx, localname, prefix, URI, nb_namespaces, + namespaces, nb_attributes, nb_defaulted, + attributes); + if ((ctxt->node != NULL) && (ctxt->input != NULL) && + (ctxt->input->cur != NULL) && (ctxt->input->cur[0] == '/') && + (ctxt->input->cur[1] == '>')) + ctxt->node->extra = NODE_IS_EMPTY; + } + if (reader != NULL) + reader->state = XML_TEXTREADER_ELEMENT; +} + +/** + * xmlTextReaderEndElementNs: + * @ctx: the user data (XML parser context) + * @localname: the local name of the element + * @prefix: the element namespace prefix if available + * @URI: the element namespace name if available + * + * called when an ending tag has been processed. + */ +static void +xmlTextReaderEndElementNs(void *ctx, + const xmlChar * localname, + const xmlChar * prefix, + const xmlChar * URI) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + xmlTextReaderPtr reader = ctxt->_private; + +#ifdef DEBUG_CALLBACKS + printf("xmlTextReaderEndElementNs(%s)\n", localname); +#endif + if ((reader != NULL) && (reader->endElementNs != NULL)) { + reader->endElementNs(ctx, localname, prefix, URI); + } +} + + +/** + * xmlTextReaderCharacters: + * @ctx: the user data (XML parser context) + * @ch: a xmlChar string + * @len: the number of xmlChar + * + * receiving some chars from the parser. + */ +static void +xmlTextReaderCharacters(void *ctx, const xmlChar *ch, int len) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + xmlTextReaderPtr reader = ctxt->_private; + +#ifdef DEBUG_CALLBACKS + printf("xmlTextReaderCharacters()\n"); +#endif + if ((reader != NULL) && (reader->characters != NULL)) { + reader->characters(ctx, ch, len); + } +} + +/** + * xmlTextReaderCDataBlock: + * @ctx: the user data (XML parser context) + * @value: The pcdata content + * @len: the block length + * + * called when a pcdata block has been parsed + */ +static void +xmlTextReaderCDataBlock(void *ctx, const xmlChar *ch, int len) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + xmlTextReaderPtr reader = ctxt->_private; + +#ifdef DEBUG_CALLBACKS + printf("xmlTextReaderCDataBlock()\n"); +#endif + if ((reader != NULL) && (reader->cdataBlock != NULL)) { + reader->cdataBlock(ctx, ch, len); + } +} + +/** + * xmlTextReaderPushData: + * @reader: the xmlTextReaderPtr used + * + * Push data down the progressive parser until a significant callback + * got raised. + * + * Returns -1 in case of failure, 0 otherwise + */ +static int +xmlTextReaderPushData(xmlTextReaderPtr reader) { + xmlBufferPtr inbuf; + int val, s; + xmlTextReaderState oldstate; + + if ((reader->input == NULL) || (reader->input->buffer == NULL)) + return(-1); + + oldstate = reader->state; + reader->state = XML_TEXTREADER_NONE; + inbuf = reader->input->buffer; + + while (reader->state == XML_TEXTREADER_NONE) { + if (inbuf->use < reader->cur + CHUNK_SIZE) { + /* + * Refill the buffer unless we are at the end of the stream + */ + if (reader->mode != XML_TEXTREADER_MODE_EOF) { + val = xmlParserInputBufferRead(reader->input, 4096); + if ((val == 0) && + (inbuf->alloc == XML_BUFFER_ALLOC_IMMUTABLE)) { + if (inbuf->use == reader->cur) { + reader->mode = XML_TEXTREADER_MODE_EOF; + reader->state = oldstate; + } + } else if (val < 0) { + reader->mode = XML_TEXTREADER_MODE_EOF; + reader->state = oldstate; + if ((oldstate != XML_TEXTREADER_START) || + (reader->ctxt->myDoc != NULL)) + return(val); + } else if (val == 0) { + /* mark the end of the stream and process the remains */ + reader->mode = XML_TEXTREADER_MODE_EOF; + break; + } + + } else + break; + } + /* + * parse by block of CHUNK_SIZE bytes, various tests show that + * it's the best tradeoff at least on a 1.2GH Duron + */ + if (inbuf->use >= reader->cur + CHUNK_SIZE) { + val = xmlParseChunk(reader->ctxt, + (const char *) &inbuf->content[reader->cur], + CHUNK_SIZE, 0); + reader->cur += CHUNK_SIZE; + if ((val != 0) || (reader->ctxt->wellFormed == 0)) + return(-1); + } else { + s = inbuf->use - reader->cur; + val = xmlParseChunk(reader->ctxt, + (const char *) &inbuf->content[reader->cur], + s, 0); + reader->cur += s; + if ((val != 0) || (reader->ctxt->wellFormed == 0)) + return(-1); + break; + } + } + + /* + * Discard the consumed input when needed and possible + */ + if (reader->mode == XML_TEXTREADER_MODE_INTERACTIVE) { + if (inbuf->alloc != XML_BUFFER_ALLOC_IMMUTABLE) { + if ((reader->cur >= 4096) && + (inbuf->use - reader->cur <= CHUNK_SIZE)) { + val = xmlBufferShrink(inbuf, reader->cur); + if (val >= 0) { + reader->cur -= val; + } + } + } + } + + /* + * At the end of the stream signal that the work is done to the Push + * parser. + */ + else if (reader->mode == XML_TEXTREADER_MODE_EOF) { + if (reader->state != XML_TEXTREADER_DONE) { + s = inbuf->use - reader->cur; + val = xmlParseChunk(reader->ctxt, + (const char *) &inbuf->content[reader->cur], + s, 1); + reader->cur = inbuf->use; + reader->state = XML_TEXTREADER_DONE; + if ((val != 0) || (reader->ctxt->wellFormed == 0)) + return(-1); + } + } + reader->state = oldstate; + return(0); +} + +#ifdef LIBXML_REGEXP_ENABLED +/** + * xmlTextReaderValidatePush: + * @reader: the xmlTextReaderPtr used + * + * Push the current node for validation + */ +static void +xmlTextReaderValidatePush(xmlTextReaderPtr reader ATTRIBUTE_UNUSED) { + xmlNodePtr node = reader->node; + +#ifdef LIBXML_VALID_ENABLED + if ((reader->validate == XML_TEXTREADER_VALIDATE_DTD) && + (reader->ctxt != NULL) && (reader->ctxt->validate == 1)) { + if ((node->ns == NULL) || (node->ns->prefix == NULL)) { + reader->ctxt->valid &= xmlValidatePushElement(&reader->ctxt->vctxt, + reader->ctxt->myDoc, node, node->name); + } else { + /* TODO use the BuildQName interface */ + xmlChar *qname; + + qname = xmlStrdup(node->ns->prefix); + qname = xmlStrcat(qname, BAD_CAST ":"); + qname = xmlStrcat(qname, node->name); + reader->ctxt->valid &= xmlValidatePushElement(&reader->ctxt->vctxt, + reader->ctxt->myDoc, node, qname); + if (qname != NULL) + xmlFree(qname); + } + } +#endif /* LIBXML_VALID_ENABLED */ +#ifdef LIBXML_SCHEMAS_ENABLED + if ((reader->validate == XML_TEXTREADER_VALIDATE_RNG) && + (reader->rngValidCtxt != NULL)) { + int ret; + + if (reader->rngFullNode != NULL) return; + ret = xmlRelaxNGValidatePushElement(reader->rngValidCtxt, + reader->ctxt->myDoc, + node); + if (ret == 0) { + /* + * this element requires a full tree + */ + node = xmlTextReaderExpand(reader); + if (node == NULL) { +printf("Expand failed !\n"); + ret = -1; + } else { + ret = xmlRelaxNGValidateFullElement(reader->rngValidCtxt, + reader->ctxt->myDoc, + node); + reader->rngFullNode = node; + } + } + if (ret != 1) + reader->rngValidErrors++; + } +#endif +} + +/** + * xmlTextReaderValidateCData: + * @reader: the xmlTextReaderPtr used + * @data: pointer to the CData + * @len: lenght of the CData block in bytes. + * + * Push some CData for validation + */ +static void +xmlTextReaderValidateCData(xmlTextReaderPtr reader, + const xmlChar *data, int len) { +#ifdef LIBXML_VALID_ENABLED + if ((reader->validate == XML_TEXTREADER_VALIDATE_DTD) && + (reader->ctxt != NULL) && (reader->ctxt->validate == 1)) { + reader->ctxt->valid &= xmlValidatePushCData(&reader->ctxt->vctxt, + data, len); + } +#endif /* LIBXML_VALID_ENABLED */ +#ifdef LIBXML_SCHEMAS_ENABLED + if ((reader->validate == XML_TEXTREADER_VALIDATE_RNG) && + (reader->rngValidCtxt != NULL)) { + int ret; + + if (reader->rngFullNode != NULL) return; + ret = xmlRelaxNGValidatePushCData(reader->rngValidCtxt, data, len); + if (ret != 1) + reader->rngValidErrors++; + } +#endif +} + +/** + * xmlTextReaderValidatePop: + * @reader: the xmlTextReaderPtr used + * + * Pop the current node from validation + */ +static void +xmlTextReaderValidatePop(xmlTextReaderPtr reader) { + xmlNodePtr node = reader->node; + +#ifdef LIBXML_VALID_ENABLED + if ((reader->validate == XML_TEXTREADER_VALIDATE_DTD) && + (reader->ctxt != NULL) && (reader->ctxt->validate == 1)) { + if ((node->ns == NULL) || (node->ns->prefix == NULL)) { + reader->ctxt->valid &= xmlValidatePopElement(&reader->ctxt->vctxt, + reader->ctxt->myDoc, node, node->name); + } else { + /* TODO use the BuildQName interface */ + xmlChar *qname; + + qname = xmlStrdup(node->ns->prefix); + qname = xmlStrcat(qname, BAD_CAST ":"); + qname = xmlStrcat(qname, node->name); + reader->ctxt->valid &= xmlValidatePopElement(&reader->ctxt->vctxt, + reader->ctxt->myDoc, node, qname); + if (qname != NULL) + xmlFree(qname); + } + } +#endif /* LIBXML_VALID_ENABLED */ +#ifdef LIBXML_SCHEMAS_ENABLED + if ((reader->validate == XML_TEXTREADER_VALIDATE_RNG) && + (reader->rngValidCtxt != NULL)) { + int ret; + + if (reader->rngFullNode != NULL) { + if (node == reader->rngFullNode) + reader->rngFullNode = NULL; + return; + } + ret = xmlRelaxNGValidatePopElement(reader->rngValidCtxt, + reader->ctxt->myDoc, + node); + if (ret != 1) + reader->rngValidErrors++; + } +#endif +} + +/** + * xmlTextReaderValidateEntity: + * @reader: the xmlTextReaderPtr used + * + * Handle the validation when an entity reference is encountered and + * entity substitution is not activated. As a result the parser interface + * must walk through the entity and do the validation calls + */ +static void +xmlTextReaderValidateEntity(xmlTextReaderPtr reader) { + xmlNodePtr oldnode = reader->node; + xmlNodePtr node = reader->node; + xmlParserCtxtPtr ctxt = reader->ctxt; + + do { + if (node->type == XML_ENTITY_REF_NODE) { + /* + * Case where the underlying tree is not availble, lookup the entity + * and walk it. + */ + if ((node->children == NULL) && (ctxt->sax != NULL) && + (ctxt->sax->getEntity != NULL)) { + node->children = (xmlNodePtr) + ctxt->sax->getEntity(ctxt, node->name); + } + + if ((node->children != NULL) && + (node->children->type == XML_ENTITY_DECL) && + (node->children->children != NULL)) { + xmlTextReaderEntPush(reader, node); + node = node->children->children; + continue; + } else { + /* + * The error has probably be raised already. + */ + if (node == oldnode) + break; + node = node->next; + } +#ifdef LIBXML_REGEXP_ENABLED + } else if (node->type == XML_ELEMENT_NODE) { + reader->node = node; + xmlTextReaderValidatePush(reader); + } else if ((node->type == XML_TEXT_NODE) || + (node->type == XML_CDATA_SECTION_NODE)) { + xmlTextReaderValidateCData(reader, node->content, + xmlStrlen(node->content)); +#endif + } + + /* + * go to next node + */ + if (node->children != NULL) { + node = node->children; + continue; + } else if (node->type == XML_ELEMENT_NODE) { + xmlTextReaderValidatePop(reader); + } + if (node->next != NULL) { + node = node->next; + continue; + } + do { + node = node->parent; + if (node->type == XML_ELEMENT_NODE) { + xmlNodePtr tmp; + if (reader->entNr == 0) { + while ((tmp = node->last) != NULL) { + if ((tmp->extra & NODE_IS_PRESERVED) == 0) { + xmlUnlinkNode(tmp); + xmlTextReaderFreeNode(reader, tmp); + } else + break; + } + } + reader->node = node; + xmlTextReaderValidatePop(reader); + } + if ((node->type == XML_ENTITY_DECL) && + (reader->ent != NULL) && (reader->ent->children == node)) { + node = xmlTextReaderEntPop(reader); + } + if (node == oldnode) + break; + if (node->next != NULL) { + node = node->next; + break; + } + } while ((node != NULL) && (node != oldnode)); + } while ((node != NULL) && (node != oldnode)); + reader->node = oldnode; +} +#endif /* LIBXML_REGEXP_ENABLED */ + + +/** + * xmlTextReaderGetSuccessor: + * @cur: the current node + * + * Get the successor of a node if available. + * + * Returns the successor node or NULL + */ +static xmlNodePtr +xmlTextReaderGetSuccessor(xmlNodePtr cur) { + if (cur == NULL) return(NULL) ; /* ERROR */ + if (cur->next != NULL) return(cur->next) ; + do { + cur = cur->parent; + if (cur == NULL) break; + if (cur->next != NULL) return(cur->next); + } while (cur != NULL); + return(cur); +} + +/** + * xmlTextReaderDoExpand: + * @reader: the xmlTextReaderPtr used + * + * Makes sure that the current node is fully read as well as all its + * descendant. It means the full DOM subtree must be available at the + * end of the call. + * + * Returns 1 if the node was expanded successfully, 0 if there is no more + * nodes to read, or -1 in case of error + */ +static int +xmlTextReaderDoExpand(xmlTextReaderPtr reader) { + int val; + + if ((reader == NULL) || (reader->node == NULL) || (reader->ctxt == NULL)) + return(-1); + do { + if (reader->ctxt->instate == XML_PARSER_EOF) return(1); + + if (xmlTextReaderGetSuccessor(reader->node) != NULL) + return(1); + if (reader->ctxt->nodeNr < reader->depth) + return(1); + if (reader->mode == XML_TEXTREADER_MODE_EOF) + return(1); + val = xmlTextReaderPushData(reader); + if (val < 0){ + reader->mode = XML_TEXTREADER_MODE_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; + + buffer = xmlBufferCreate(); + if (buffer == NULL) + return NULL; + + 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 + * + * Moves the position of the current instance to the next node in + * the stream, exposing its properties. + * + * Returns 1 if the node was read successfully, 0 if there is no more + * nodes to read, or -1 in case of error + */ +int +xmlTextReaderRead(xmlTextReaderPtr reader) { + int val, olddepth = 0; + xmlTextReaderState oldstate = XML_TEXTREADER_START; + xmlNodePtr oldnode = NULL; + + + if (reader == NULL) + return(-1); + reader->curnode = NULL; + if (reader->doc != NULL) + return(xmlTextReaderReadTree(reader)); + if (reader->ctxt == NULL) + return(-1); + if (reader->ctxt->wellFormed != 1) + return(-1); + +#ifdef DEBUG_READER + fprintf(stderr, "\nREAD "); + DUMP_READER +#endif + if (reader->mode == XML_TEXTREADER_MODE_INITIAL) { + reader->mode = XML_TEXTREADER_MODE_INTERACTIVE; + /* + * Initial state + */ + do { + val = xmlTextReaderPushData(reader); + 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))); + if (reader->ctxt->node == NULL) { + 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; + return(-1); + } + reader->state = XML_TEXTREADER_ELEMENT; + } else { + if (reader->ctxt->myDoc != NULL) { + reader->node = reader->ctxt->myDoc->children; + } + if (reader->node == NULL) + reader->node = reader->ctxt->nodeTab[0]; + reader->state = XML_TEXTREADER_ELEMENT; + } + reader->depth = 0; + reader->ctxt->parseMode = XML_PARSE_READER; + goto node_found; + } + oldstate = reader->state; + olddepth = reader->ctxt->nodeNr; + oldnode = reader->node; + +get_next_node: + if (reader->node == NULL) { + if (reader->mode == XML_TEXTREADER_MODE_EOF) + return(0); + else + return(-1); + } + + /* + * If we are not backtracking on ancestors or examined nodes, + * that the parser didn't finished or that we arent at the end + * of stream, continue processing. + */ + while ((reader->node != NULL) && (reader->node->next == NULL) && + (reader->ctxt->nodeNr == olddepth) && + ((oldstate == XML_TEXTREADER_BACKTRACK) || + (reader->node->children == NULL) || + (reader->node->type == XML_ENTITY_REF_NODE) || + ((reader->node->children != NULL) && + (reader->node->children->type == XML_TEXT_NODE) && + (reader->node->children->next == NULL)) || + (reader->node->type == XML_DTD_NODE) || + (reader->node->type == XML_DOCUMENT_NODE) || + (reader->node->type == XML_HTML_DOCUMENT_NODE)) && + ((reader->ctxt->node == NULL) || + (reader->ctxt->node == reader->node) || + (reader->ctxt->node == reader->node->parent)) && + (reader->ctxt->instate != XML_PARSER_EOF)) { + val = xmlTextReaderPushData(reader); + if (val < 0){ + reader->mode = XML_TEXTREADER_MODE_ERROR; + reader->state = XML_TEXTREADER_ERROR; + return(-1); + } + if (reader->node == NULL) + goto node_end; + } + if (oldstate != XML_TEXTREADER_BACKTRACK) { + if ((reader->node->children != NULL) && + (reader->node->type != XML_ENTITY_REF_NODE) && + (reader->node->type != XML_XINCLUDE_START) && + (reader->node->type != XML_DTD_NODE)) { + reader->node = reader->node->children; + reader->depth++; + reader->state = XML_TEXTREADER_ELEMENT; + goto node_found; + } + } + if (reader->node->next != NULL) { + if ((oldstate == XML_TEXTREADER_ELEMENT) && + (reader->node->type == XML_ELEMENT_NODE) && + (reader->node->children == NULL) && + ((reader->node->extra & NODE_IS_EMPTY) == 0) +#ifdef LIBXML_XINCLUDE_ENABLED + && (reader->in_xinclude <= 0) +#endif + ) { + reader->state = XML_TEXTREADER_END; + goto node_found; + } +#ifdef LIBXML_REGEXP_ENABLED + if ((reader->validate) && + (reader->node->type == XML_ELEMENT_NODE)) + xmlTextReaderValidatePop(reader); +#endif /* LIBXML_REGEXP_ENABLED */ + if ((reader->preserves > 0) && + (reader->node->extra & NODE_IS_SPRESERVED)) + reader->preserves--; + reader->node = reader->node->next; + reader->state = XML_TEXTREADER_ELEMENT; + + /* + * Cleanup of the old node + */ + if ((reader->preserves == 0) && +#ifdef LIBXML_XINCLUDE_ENABLED + (reader->in_xinclude == 0) && +#endif + (reader->entNr == 0) && + (reader->node->prev != NULL) && + (reader->node->prev->type != XML_DTD_NODE) && + (reader->entNr == 0)) { + xmlNodePtr tmp = reader->node->prev; + if ((tmp->extra & NODE_IS_PRESERVED) == 0) { + xmlUnlinkNode(tmp); + xmlTextReaderFreeNode(reader, tmp); + } + } + + goto node_found; + } + if ((oldstate == XML_TEXTREADER_ELEMENT) && + (reader->node->type == XML_ELEMENT_NODE) && + (reader->node->children == NULL) && + ((reader->node->extra & NODE_IS_EMPTY) == 0)) {; + reader->state = XML_TEXTREADER_END; + goto node_found; + } +#ifdef LIBXML_REGEXP_ENABLED + if ((reader->validate) && (reader->node->type == XML_ELEMENT_NODE)) + xmlTextReaderValidatePop(reader); +#endif /* LIBXML_REGEXP_ENABLED */ + if ((reader->preserves > 0) && + (reader->node->extra & NODE_IS_SPRESERVED)) + reader->preserves--; + reader->node = reader->node->parent; + if ((reader->node == NULL) || + (reader->node->type == XML_DOCUMENT_NODE) || +#ifdef LIBXML_DOCB_ENABLED + (reader->node->type == XML_DOCB_DOCUMENT_NODE) || +#endif + (reader->node->type == XML_HTML_DOCUMENT_NODE)) { + if (reader->mode != XML_TEXTREADER_MODE_EOF) { + val = xmlParseChunk(reader->ctxt, "", 0, 1); + reader->state = XML_TEXTREADER_DONE; + if (val != 0) + return(-1); + } + reader->node = NULL; + reader->depth = -1; + + /* + * Cleanup of the old node + */ + if ((oldnode != NULL) && (reader->preserves == 0) && +#ifdef LIBXML_XINCLUDE_ENABLED + (reader->in_xinclude == 0) && +#endif + (reader->entNr == 0) && + (oldnode->type != XML_DTD_NODE) && + ((oldnode->extra & NODE_IS_PRESERVED) == 0) && + (reader->entNr == 0)) { + xmlUnlinkNode(oldnode); + xmlTextReaderFreeNode(reader, oldnode); + } + + goto node_end; + } + if ((reader->preserves == 0) && +#ifdef LIBXML_XINCLUDE_ENABLED + (reader->in_xinclude == 0) && +#endif + (reader->entNr == 0) && + (reader->node->last != NULL) && + ((reader->node->last->extra & NODE_IS_PRESERVED) == 0)) { + xmlNodePtr tmp = reader->node->last; + xmlUnlinkNode(tmp); + xmlTextReaderFreeNode(reader, tmp); + } + reader->depth--; + reader->state = XML_TEXTREADER_BACKTRACK; + +node_found: + DUMP_READER + + /* + * If we are in the middle of a piece of CDATA make sure it's finished + */ + if ((reader->node != NULL) && + (reader->node->next == NULL) && + ((reader->node->type == XML_TEXT_NODE) || + (reader->node->type == XML_CDATA_SECTION_NODE))) { + if (xmlTextReaderExpand(reader) == NULL) + return -1; + } + +#ifdef LIBXML_XINCLUDE_ENABLED + /* + * Handle XInclude if asked for + */ + if ((reader->xinclude) && (reader->node != NULL) && + (reader->node->type == XML_ELEMENT_NODE) && + (reader->node->ns != NULL) && + ((xmlStrEqual(reader->node->ns->href, XINCLUDE_NS)) || + (xmlStrEqual(reader->node->ns->href, XINCLUDE_OLD_NS)))) { + if (reader->xincctxt == NULL) { + reader->xincctxt = xmlXIncludeNewContext(reader->ctxt->myDoc); + xmlXIncludeSetFlags(reader->xincctxt, + reader->parserFlags & (~XML_PARSE_NOXINCNODE)); + } + /* + * expand that node and process it + */ + if (xmlTextReaderExpand(reader) == NULL) + return -1; + xmlXIncludeProcessNode(reader->xincctxt, reader->node); + } + if ((reader->node != NULL) && (reader->node->type == XML_XINCLUDE_START)) { + reader->in_xinclude++; + goto get_next_node; + } + if ((reader->node != NULL) && (reader->node->type == XML_XINCLUDE_END)) { + reader->in_xinclude--; + goto get_next_node; + } +#endif + /* + * Handle entities enter and exit when in entity replacement mode + */ + if ((reader->node != NULL) && + (reader->node->type == XML_ENTITY_REF_NODE) && + (reader->ctxt != NULL) && (reader->ctxt->replaceEntities == 1)) { + /* + * Case where the underlying tree is not availble, lookup the entity + * and walk it. + */ + if ((reader->node->children == NULL) && (reader->ctxt->sax != NULL) && + (reader->ctxt->sax->getEntity != NULL)) { + reader->node->children = (xmlNodePtr) + reader->ctxt->sax->getEntity(reader->ctxt, reader->node->name); + } + + if ((reader->node->children != NULL) && + (reader->node->children->type == XML_ENTITY_DECL) && + (reader->node->children->children != NULL)) { + xmlTextReaderEntPush(reader, reader->node); + reader->node = reader->node->children->children; + } +#ifdef LIBXML_REGEXP_ENABLED + } else if ((reader->node != NULL) && + (reader->node->type == XML_ENTITY_REF_NODE) && + (reader->ctxt != NULL) && (reader->validate)) { + xmlTextReaderValidateEntity(reader); +#endif /* LIBXML_REGEXP_ENABLED */ + } + if ((reader->node != NULL) && + (reader->node->type == XML_ENTITY_DECL) && + (reader->ent != NULL) && (reader->ent->children == reader->node)) { + reader->node = xmlTextReaderEntPop(reader); + reader->depth++; + goto get_next_node; + } +#ifdef LIBXML_REGEXP_ENABLED + if ((reader->validate) && (reader->node != NULL)) { + xmlNodePtr node = reader->node; + + if ((node->type == XML_ELEMENT_NODE) && + ((reader->state != XML_TEXTREADER_END) && + (reader->state != XML_TEXTREADER_BACKTRACK))) { + xmlTextReaderValidatePush(reader); + } else if ((node->type == XML_TEXT_NODE) || + (node->type == XML_CDATA_SECTION_NODE)) { + xmlTextReaderValidateCData(reader, node->content, + xmlStrlen(node->content)); + } + } +#endif /* LIBXML_REGEXP_ENABLED */ +#ifdef LIBXML_PATTERN_ENABLED + if ((reader->patternNr > 0) && (reader->state != XML_TEXTREADER_END) && + (reader->state != XML_TEXTREADER_BACKTRACK)) { + int i; + for (i = 0;i < reader->patternNr;i++) { + if (xmlPatternMatch(reader->patternTab[i], reader->node) == 1) { + xmlTextReaderPreserve(reader); + break; + } + } + } +#endif /* LIBXML_PATTERN_ENABLED */ +#ifdef LIBXML_SCHEMAS_ENABLED + if ((reader->validate == XML_TEXTREADER_VALIDATE_XSD) && + (reader->xsdValidErrors == 0) && + (reader->xsdValidCtxt != NULL)) { + reader->xsdValidErrors = !xmlSchemaIsValid(reader->xsdValidCtxt); + } +#endif /* LIBXML_PATTERN_ENABLED */ + return(1); +node_end: + reader->state = XML_TEXTREADER_DONE; + return(0); +} + +/** + * xmlTextReaderReadState: + * @reader: the xmlTextReaderPtr used + * + * Gets the read state of the reader. + * + * Returns the state value, or -1 in case of error + */ +int +xmlTextReaderReadState(xmlTextReaderPtr reader) { + if (reader == NULL) + return(-1); + return(reader->mode); +} + +/** + * xmlTextReaderExpand: + * @reader: the xmlTextReaderPtr used + * + * Reads the contents of the current node and the full subtree. It then makes + * the subtree available until the next xmlTextReaderRead() call + * + * Returns a node pointer valid until the next xmlTextReaderRead() call + * or NULL in case of error. + */ +xmlNodePtr +xmlTextReaderExpand(xmlTextReaderPtr reader) { + if ((reader == NULL) || (reader->node == NULL)) + return(NULL); + if (reader->doc != NULL) + return(reader->node); + if (reader->ctxt == NULL) + return(NULL); + if (xmlTextReaderDoExpand(reader) < 0) + return(NULL); + return(reader->node); +} + +/** + * xmlTextReaderNext: + * @reader: the xmlTextReaderPtr used + * + * Skip to the node following the current one in document order while + * avoiding the subtree if any. + * + * Returns 1 if the node was read successfully, 0 if there is no more + * nodes to read, or -1 in case of error + */ +int +xmlTextReaderNext(xmlTextReaderPtr reader) { + int ret; + xmlNodePtr cur; + + if (reader == NULL) + return(-1); + if (reader->doc != NULL) + return(xmlTextReaderNextTree(reader)); + cur = reader->node; + if ((cur == NULL) || (cur->type != XML_ELEMENT_NODE)) + return(xmlTextReaderRead(reader)); + if (reader->state == XML_TEXTREADER_END || reader->state == XML_TEXTREADER_BACKTRACK) + return(xmlTextReaderRead(reader)); + if (cur->extra & NODE_IS_EMPTY) + return(xmlTextReaderRead(reader)); + do { + ret = xmlTextReaderRead(reader); + if (ret != 1) + return(ret); + } while (reader->node != cur); + return(xmlTextReaderRead(reader)); +} + +#ifdef LIBXML_WRITER_ENABLED +/** + * xmlTextReaderReadInnerXml: + * @reader: the xmlTextReaderPtr used + * + * Reads the contents of the current node, including child nodes and markup. + * + * Returns a string containing the XML content, or NULL if the current node + * is neither an element nor attribute, or has no child nodes. The + * string must be deallocated by the caller. + */ +xmlChar * +xmlTextReaderReadInnerXml(xmlTextReaderPtr reader ATTRIBUTE_UNUSED) +{ + xmlChar *resbuf; + xmlNodePtr node, cur_node; + xmlBufferPtr buff, buff2; + xmlDocPtr doc; + + if (xmlTextReaderExpand(reader) == NULL) { + return NULL; + } + doc = reader->doc; + buff = xmlBufferCreate(); + for (cur_node = reader->node->children; cur_node != NULL; + cur_node = cur_node->next) { + node = xmlDocCopyNode(cur_node, doc, 1); + buff2 = xmlBufferCreate(); + if (xmlNodeDump(buff2, doc, node, 0, 0) == -1) { + xmlFreeNode(node); + xmlBufferFree(buff2); + xmlBufferFree(buff); + return NULL; + } + xmlBufferCat(buff, buff2->content); + xmlFreeNode(node); + xmlBufferFree(buff2); + } + resbuf = buff->content; + buff->content = NULL; + + xmlBufferFree(buff); + return resbuf; +} +#endif + +#ifdef LIBXML_WRITER_ENABLED +/** + * xmlTextReaderReadOuterXml: + * @reader: the xmlTextReaderPtr used + * + * Reads the contents of the current node, including child nodes and markup. + * + * Returns a string containing the node and any XML content, or NULL if the + * current node cannot be serialized. The string must be deallocated + * by the caller. + */ +xmlChar * +xmlTextReaderReadOuterXml(xmlTextReaderPtr reader ATTRIBUTE_UNUSED) +{ + xmlChar *resbuf; + xmlNodePtr node; + xmlBufferPtr buff; + xmlDocPtr doc; + + node = reader->node; + doc = reader->doc; + if (xmlTextReaderExpand(reader) == NULL) { + return NULL; + } + if (node->type == XML_DTD_NODE) { + node = (xmlNodePtr) xmlCopyDtd((xmlDtdPtr) node); + } else { + node = xmlDocCopyNode(node, doc, 1); + } + buff = xmlBufferCreate(); + if (xmlNodeDump(buff, doc, node, 0, 0) == -1) { + xmlFreeNode(node); + xmlBufferFree(buff); + return NULL; + } + + resbuf = buff->content; + buff->content = NULL; + + xmlFreeNode(node); + xmlBufferFree(buff); + return resbuf; +} +#endif + +/** + * xmlTextReaderReadString: + * @reader: the xmlTextReaderPtr used + * + * 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. + * The string must be deallocated by the caller. + */ +xmlChar * +xmlTextReaderReadString(xmlTextReaderPtr reader) +{ + xmlNodePtr node; + + 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); + } + case XML_ATTRIBUTE_NODE: + TODO + break; + default: + break; + } + return(NULL); +} + +#if 0 +/** + * xmlTextReaderReadBase64: + * @reader: the xmlTextReaderPtr used + * @array: a byte array to store the content. + * @offset: the zero-based index into array where the method should + * begin to write. + * @len: the number of bytes to write. + * + * Reads and decodes the Base64 encoded contents of an element and + * stores the result in a byte buffer. + * + * Returns the number of bytes written to array, or zero if the current + * instance is not positioned on an element or -1 in case of error. + */ +int +xmlTextReaderReadBase64(xmlTextReaderPtr reader, + unsigned char *array ATTRIBUTE_UNUSED, + int offset ATTRIBUTE_UNUSED, + int len ATTRIBUTE_UNUSED) { + if ((reader == NULL) || (reader->ctxt == NULL)) + return(-1); + if (reader->ctxt->wellFormed != 1) + return(-1); + + if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE)) + return(0); + TODO + return(0); +} + +/** + * xmlTextReaderReadBinHex: + * @reader: the xmlTextReaderPtr used + * @array: a byte array to store the content. + * @offset: the zero-based index into array where the method should + * begin to write. + * @len: the number of bytes to write. + * + * Reads and decodes the BinHex encoded contents of an element and + * stores the result in a byte buffer. + * + * Returns the number of bytes written to array, or zero if the current + * instance is not positioned on an element or -1 in case of error. + */ +int +xmlTextReaderReadBinHex(xmlTextReaderPtr reader, + unsigned char *array ATTRIBUTE_UNUSED, + int offset ATTRIBUTE_UNUSED, + int len ATTRIBUTE_UNUSED) { + if ((reader == NULL) || (reader->ctxt == NULL)) + return(-1); + if (reader->ctxt->wellFormed != 1) + return(-1); + + if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE)) + return(0); + TODO + return(0); +} +#endif + +/************************************************************************ + * * + * Operating on a preparsed tree * + * * + ************************************************************************/ +static int +xmlTextReaderNextTree(xmlTextReaderPtr reader) +{ + if (reader == NULL) + return(-1); + + if (reader->state == XML_TEXTREADER_END) + return(0); + + if (reader->node == NULL) { + if (reader->doc->children == NULL) { + reader->state = XML_TEXTREADER_END; + return(0); + } + + reader->node = reader->doc->children; + reader->state = XML_TEXTREADER_START; + return(1); + } + + if (reader->state != XML_TEXTREADER_BACKTRACK) { + /* Here removed traversal to child, because we want to skip the subtree, + replace with traversal to sibling to skip subtree */ + if (reader->node->next != 0) { + /* Move to sibling if present,skipping sub-tree */ + reader->node = reader->node->next; + reader->state = XML_TEXTREADER_START; + return(1); + } + + /* if reader->node->next is NULL mean no subtree for current node, + so need to move to sibling of parent node if present */ + if ((reader->node->type == XML_ELEMENT_NODE) || + (reader->node->type == XML_ATTRIBUTE_NODE)) { + reader->state = XML_TEXTREADER_BACKTRACK; + /* This will move to parent if present */ + xmlTextReaderRead(reader); + } + } + + if (reader->node->next != 0) { + reader->node = reader->node->next; + reader->state = XML_TEXTREADER_START; + return(1); + } + + if (reader->node->parent != 0) { + if (reader->node->parent->type == XML_DOCUMENT_NODE) { + reader->state = XML_TEXTREADER_END; + return(0); + } + + reader->node = reader->node->parent; + reader->depth--; + reader->state = XML_TEXTREADER_BACKTRACK; + /* Repeat process to move to sibling of parent node if present */ + xmlTextReaderNextTree(reader); + } + + reader->state = XML_TEXTREADER_END; + + return(1); +} + +/** + * xmlTextReaderReadTree: + * @reader: the xmlTextReaderPtr used + * + * Moves the position of the current instance to the next node in + * the stream, exposing its properties. + * + * Returns 1 if the node was read successfully, 0 if there is no more + * nodes to read, or -1 in case of error + */ +static int +xmlTextReaderReadTree(xmlTextReaderPtr reader) { + if (reader->state == XML_TEXTREADER_END) + return(0); + +next_node: + if (reader->node == NULL) { + if (reader->doc->children == NULL) { + reader->state = XML_TEXTREADER_END; + return(0); + } + + reader->node = reader->doc->children; + reader->state = XML_TEXTREADER_START; + goto found_node; + } + + if ((reader->state != XML_TEXTREADER_BACKTRACK) && + (reader->node->type != XML_DTD_NODE) && + (reader->node->type != XML_XINCLUDE_START) && + (reader->node->type != XML_ENTITY_REF_NODE)) { + if (reader->node->children != NULL) { + reader->node = reader->node->children; + reader->depth++; + reader->state = XML_TEXTREADER_START; + goto found_node; + } + + if (reader->node->type == XML_ATTRIBUTE_NODE) { + reader->state = XML_TEXTREADER_BACKTRACK; + goto found_node; + } + } + + if (reader->node->next != NULL) { + reader->node = reader->node->next; + reader->state = XML_TEXTREADER_START; + goto found_node; + } + + if (reader->node->parent != NULL) { + if ((reader->node->parent->type == XML_DOCUMENT_NODE) || + (reader->node->parent->type == XML_HTML_DOCUMENT_NODE)) { + reader->state = XML_TEXTREADER_END; + return(0); + } + + reader->node = reader->node->parent; + reader->depth--; + reader->state = XML_TEXTREADER_BACKTRACK; + goto found_node; + } + + reader->state = XML_TEXTREADER_END; + +found_node: + if ((reader->node->type == XML_XINCLUDE_START) || + (reader->node->type == XML_XINCLUDE_END)) + goto next_node; + + return(1); +} + +/** + * xmlTextReaderNextSibling: + * @reader: the xmlTextReaderPtr used + * + * Skip to the node following the current one in document order while + * avoiding the subtree if any. + * Currently implemented only for Readers built on a document + * + * Returns 1 if the node was read successfully, 0 if there is no more + * nodes to read, or -1 in case of error + */ +int +xmlTextReaderNextSibling(xmlTextReaderPtr reader) { + if (reader == NULL) + return(-1); + if (reader->doc == NULL) { + /* TODO */ + return(-1); + } + + if (reader->state == XML_TEXTREADER_END) + return(0); + + if (reader->node == NULL) + return(xmlTextReaderNextTree(reader)); + + if (reader->node->next != NULL) { + reader->node = reader->node->next; + reader->state = XML_TEXTREADER_START; + return(1); + } + + return(0); +} + +/************************************************************************ + * * + * Constructor and destructors * + * * + ************************************************************************/ +/** + * xmlNewTextReader: + * @input: the xmlParserInputBufferPtr used to read data + * @URI: the URI information for the source if available + * + * Create an xmlTextReader structure fed with @input + * + * Returns the new xmlTextReaderPtr or NULL in case of error + */ +xmlTextReaderPtr +xmlNewTextReader(xmlParserInputBufferPtr input, const char *URI) { + xmlTextReaderPtr ret; + + if (input == NULL) + return(NULL); + ret = xmlMalloc(sizeof(xmlTextReader)); + if (ret == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlNewTextReader : malloc failed\n"); + return(NULL); + } + memset(ret, 0, sizeof(xmlTextReader)); + ret->doc = NULL; + ret->entTab = NULL; + ret->entMax = 0; + ret->entNr = 0; + ret->input = input; + ret->buffer = xmlBufferCreateSize(100); + if (ret->buffer == NULL) { + xmlFree(ret); + xmlGenericError(xmlGenericErrorContext, + "xmlNewTextReader : malloc failed\n"); + return(NULL); + } + ret->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler)); + if (ret->sax == NULL) { + xmlBufferFree(ret->buffer); + xmlFree(ret); + xmlGenericError(xmlGenericErrorContext, + "xmlNewTextReader : malloc failed\n"); + return(NULL); + } + xmlSAXVersion(ret->sax, 2); + ret->startElement = ret->sax->startElement; + ret->sax->startElement = xmlTextReaderStartElement; + ret->endElement = ret->sax->endElement; + ret->sax->endElement = xmlTextReaderEndElement; +#ifdef LIBXML_SAX1_ENABLED + if (ret->sax->initialized == XML_SAX2_MAGIC) { +#endif /* LIBXML_SAX1_ENABLED */ + ret->startElementNs = ret->sax->startElementNs; + ret->sax->startElementNs = xmlTextReaderStartElementNs; + ret->endElementNs = ret->sax->endElementNs; + ret->sax->endElementNs = xmlTextReaderEndElementNs; +#ifdef LIBXML_SAX1_ENABLED + } else { + ret->startElementNs = NULL; + ret->endElementNs = NULL; + } +#endif /* LIBXML_SAX1_ENABLED */ + ret->characters = ret->sax->characters; + ret->sax->characters = xmlTextReaderCharacters; + ret->sax->ignorableWhitespace = xmlTextReaderCharacters; + ret->cdataBlock = ret->sax->cdataBlock; + ret->sax->cdataBlock = xmlTextReaderCDataBlock; + + ret->mode = XML_TEXTREADER_MODE_INITIAL; + ret->node = NULL; + ret->curnode = NULL; + if (ret->input->buffer->use < 4) { + xmlParserInputBufferRead(input, 4); + } + if (ret->input->buffer->use >= 4) { + ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL, + (const char *) ret->input->buffer->content, 4, URI); + ret->base = 0; + ret->cur = 4; + } else { + ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL, NULL, 0, URI); + ret->base = 0; + ret->cur = 0; + } + + if (ret->ctxt == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlNewTextReader : malloc failed\n"); + xmlBufferFree(ret->buffer); + xmlFree(ret->sax); + xmlFree(ret); + return(NULL); + } + ret->ctxt->parseMode = XML_PARSE_READER; + ret->ctxt->_private = ret; + ret->ctxt->linenumbers = 1; + ret->ctxt->dictNames = 1; + ret->allocs = XML_TEXTREADER_CTXT; + /* + * use the parser dictionnary to allocate all elements and attributes names + */ + ret->ctxt->docdict = 1; + ret->dict = ret->ctxt->dict; +#ifdef LIBXML_XINCLUDE_ENABLED + ret->xinclude = 0; +#endif +#ifdef LIBXML_PATTERN_ENABLED + ret->patternMax = 0; + ret->patternTab = NULL; +#endif + return(ret); +} + +/** + * xmlNewTextReaderFilename: + * @URI: the URI of the resource to process + * + * Create an xmlTextReader structure fed with the resource at @URI + * + * Returns the new xmlTextReaderPtr or NULL in case of error + */ +xmlTextReaderPtr +xmlNewTextReaderFilename(const char *URI) { + xmlParserInputBufferPtr input; + xmlTextReaderPtr ret; + char *directory = NULL; + + input = xmlParserInputBufferCreateFilename(URI, XML_CHAR_ENCODING_NONE); + if (input == NULL) + return(NULL); + ret = xmlNewTextReader(input, URI); + if (ret == NULL) { + xmlFreeParserInputBuffer(input); + 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); +} + +/** + * xmlFreeTextReader: + * @reader: the xmlTextReaderPtr + * + * Deallocate all the resources associated to the reader + */ +void +xmlFreeTextReader(xmlTextReaderPtr reader) { + if (reader == NULL) + return; +#ifdef LIBXML_SCHEMAS_ENABLED + if (reader->rngSchemas != NULL) { + xmlRelaxNGFree(reader->rngSchemas); + reader->rngSchemas = NULL; + } + if (reader->rngValidCtxt != NULL) { + xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt); + reader->rngValidCtxt = NULL; + } + if (reader->xsdPlug != NULL) { + xmlSchemaSAXUnplug(reader->xsdPlug); + reader->xsdPlug = NULL; + } + if (reader->xsdValidCtxt != NULL) { + if (! reader->xsdPreserveCtxt) + xmlSchemaFreeValidCtxt(reader->xsdValidCtxt); + reader->xsdValidCtxt = NULL; + } + if (reader->xsdSchemas != NULL) { + xmlSchemaFree(reader->xsdSchemas); + reader->xsdSchemas = NULL; + } +#endif +#ifdef LIBXML_XINCLUDE_ENABLED + if (reader->xincctxt != NULL) + xmlXIncludeFreeContext(reader->xincctxt); +#endif +#ifdef LIBXML_PATTERN_ENABLED + if (reader->patternTab != NULL) { + int i; + for (i = 0;i < reader->patternNr;i++) { + if (reader->patternTab[i] != NULL) + xmlFreePattern(reader->patternTab[i]); + } + xmlFree(reader->patternTab); + } +#endif + if (reader->faketext != NULL) { + xmlFreeNode(reader->faketext); + } + if (reader->ctxt != NULL) { + if (reader->dict == reader->ctxt->dict) + reader->dict = NULL; + if (reader->ctxt->myDoc != NULL) { + if (reader->preserve == 0) + xmlTextReaderFreeDoc(reader, reader->ctxt->myDoc); + reader->ctxt->myDoc = NULL; + } + if ((reader->ctxt->vctxt.vstateTab != NULL) && + (reader->ctxt->vctxt.vstateMax > 0)){ + xmlFree(reader->ctxt->vctxt.vstateTab); + reader->ctxt->vctxt.vstateTab = NULL; + reader->ctxt->vctxt.vstateMax = 0; + } + if (reader->allocs & XML_TEXTREADER_CTXT) + xmlFreeParserCtxt(reader->ctxt); + } + if (reader->sax != NULL) + xmlFree(reader->sax); + if ((reader->input != NULL) && (reader->allocs & XML_TEXTREADER_INPUT)) + xmlFreeParserInputBuffer(reader->input); + if (reader->buffer != NULL) + xmlBufferFree(reader->buffer); + if (reader->entTab != NULL) + xmlFree(reader->entTab); + if (reader->dict != NULL) + xmlDictFree(reader->dict); + xmlFree(reader); +} + +/************************************************************************ + * * + * Methods for XmlTextReader * + * * + ************************************************************************/ +/** + * xmlTextReaderClose: + * @reader: the xmlTextReaderPtr used + * + * This method releases any resources allocated by the current instance + * changes the state to Closed and close any underlying input. + * + * Returns 0 or -1 in case of error + */ +int +xmlTextReaderClose(xmlTextReaderPtr reader) { + if (reader == NULL) + return(-1); + reader->node = NULL; + reader->curnode = NULL; + reader->mode = XML_TEXTREADER_MODE_CLOSED; + if (reader->ctxt != NULL) { + xmlStopParser(reader->ctxt); + if (reader->ctxt->myDoc != NULL) { + if (reader->preserve == 0) + xmlTextReaderFreeDoc(reader, reader->ctxt->myDoc); + reader->ctxt->myDoc = NULL; + } + } + if ((reader->input != NULL) && (reader->allocs & XML_TEXTREADER_INPUT)) { + xmlFreeParserInputBuffer(reader->input); + reader->allocs -= XML_TEXTREADER_INPUT; + } + return(0); +} + +/** + * xmlTextReaderGetAttributeNo: + * @reader: the xmlTextReaderPtr used + * @no: the zero-based index of the attribute relative to the containing element + * + * Provides the value of the attribute with the specified index relative + * to the containing element. + * + * Returns a string containing the value of the specified attribute, or NULL + * in case of error. The string must be deallocated by the caller. + */ +xmlChar * +xmlTextReaderGetAttributeNo(xmlTextReaderPtr reader, int no) { + xmlChar *ret; + int i; + xmlAttrPtr cur; + xmlNsPtr ns; + + if (reader == NULL) + return(NULL); + if (reader->node == NULL) + return(NULL); + if (reader->curnode != NULL) + return(NULL); + /* TODO: handle the xmlDecl */ + if (reader->node->type != XML_ELEMENT_NODE) + return(NULL); + + ns = reader->node->nsDef; + for (i = 0;(i < no) && (ns != NULL);i++) { + ns = ns->next; + } + if (ns != NULL) + return(xmlStrdup(ns->href)); + + cur = reader->node->properties; + if (cur == NULL) + return(NULL); + for (;i < no;i++) { + cur = cur->next; + if (cur == NULL) + return(NULL); + } + /* TODO walk the DTD if present */ + + ret = xmlNodeListGetString(reader->node->doc, cur->children, 1); + if (ret == NULL) return(xmlStrdup((xmlChar *)"")); + return(ret); +} + +/** + * xmlTextReaderGetAttribute: + * @reader: the xmlTextReaderPtr used + * @name: the qualified name of the attribute. + * + * Provides the value of the attribute with the specified qualified name. + * + * Returns a string containing the value of the specified attribute, or NULL + * in case of error. The string must be deallocated by the caller. + */ +xmlChar * +xmlTextReaderGetAttribute(xmlTextReaderPtr reader, const xmlChar *name) { + xmlChar *prefix = NULL; + xmlChar *localname; + xmlNsPtr ns; + xmlChar *ret = NULL; + + if ((reader == NULL) || (name == NULL)) + return(NULL); + if (reader->node == NULL) + return(NULL); + if (reader->curnode != NULL) + return(NULL); + + /* TODO: handle the xmlDecl */ + if (reader->node->type != XML_ELEMENT_NODE) + return(NULL); + + localname = xmlSplitQName2(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)); + } + + /* + * 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; + } + } else { + ns = xmlSearchNs(reader->node->doc, reader->node, prefix); + if (ns != NULL) + ret = xmlGetNsProp(reader->node, localname, ns->href); + } + + xmlFree(localname); + if (prefix != NULL) + xmlFree(prefix); + return(ret); +} + + +/** + * xmlTextReaderGetAttributeNs: + * @reader: the xmlTextReaderPtr used + * @localName: the local name of the attribute. + * @namespaceURI: the namespace URI of the attribute. + * + * Provides the value of the specified attribute + * + * Returns a string containing the value of the specified attribute, or NULL + * in case of error. The string must be deallocated by the caller. + */ +xmlChar * +xmlTextReaderGetAttributeNs(xmlTextReaderPtr reader, const xmlChar *localName, + const xmlChar *namespaceURI) { + xmlChar *prefix = NULL; + xmlNsPtr ns; + + if ((reader == NULL) || (localName == NULL)) + return(NULL); + if (reader->node == NULL) + return(NULL); + if (reader->curnode != NULL) + return(NULL); + + /* TODO: handle the xmlDecl */ + if (reader->node->type != XML_ELEMENT_NODE) + 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; + } + + return(xmlGetNsProp(reader->node, localName, namespaceURI)); +} + +/** + * xmlTextReaderGetRemainder: + * @reader: the xmlTextReaderPtr used + * + * Method to get the remainder of the buffered XML. this method stops the + * parser, set its state to End Of File and return the input stream with + * what is left that the parser did not use. + * + * The implementation is not good, the parser certainly procgressed past + * what's left in reader->input, and there is an allocation problem. Best + * would be to rewrite it differently. + * + * Returns the xmlParserInputBufferPtr attached to the XML or NULL + * in case of error. + */ +xmlParserInputBufferPtr +xmlTextReaderGetRemainder(xmlTextReaderPtr reader) { + xmlParserInputBufferPtr ret = NULL; + + if (reader == NULL) + return(NULL); + if (reader->node == NULL) + return(NULL); + + reader->node = NULL; + reader->curnode = NULL; + reader->mode = XML_TEXTREADER_MODE_EOF; + if (reader->ctxt != NULL) { + xmlStopParser(reader->ctxt); + if (reader->ctxt->myDoc != NULL) { + if (reader->preserve == 0) + xmlTextReaderFreeDoc(reader, reader->ctxt->myDoc); + reader->ctxt->myDoc = NULL; + } + } + if (reader->allocs & XML_TEXTREADER_INPUT) { + ret = reader->input; + reader->input = NULL; + reader->allocs -= XML_TEXTREADER_INPUT; + } else { + /* + * Hum, one may need to duplicate the data structure because + * without reference counting the input may be freed twice: + * - by the layer which allocated it. + * - by the layer to which would have been returned to. + */ + TODO + return(NULL); + } + return(ret); +} + +/** + * xmlTextReaderLookupNamespace: + * @reader: the xmlTextReaderPtr used + * @prefix: the prefix whose namespace URI is to be resolved. To return + * the default namespace, specify NULL + * + * Resolves a namespace prefix in the scope of the current element. + * + * Returns a string containing the namespace URI to which the prefix maps + * or NULL in case of error. The string must be deallocated by the caller. + */ +xmlChar * +xmlTextReaderLookupNamespace(xmlTextReaderPtr reader, const xmlChar *prefix) { + xmlNsPtr ns; + + if (reader == NULL) + return(NULL); + if (reader->node == NULL) + return(NULL); + + ns = xmlSearchNs(reader->node->doc, reader->node, prefix); + if (ns == NULL) + return(NULL); + return(xmlStrdup(ns->href)); +} + +/** + * xmlTextReaderMoveToAttributeNo: + * @reader: the xmlTextReaderPtr used + * @no: the zero-based index of the attribute relative to the containing + * element. + * + * Moves the position of the current instance to the attribute with + * the specified index relative to the containing element. + * + * Returns 1 in case of success, -1 in case of error, 0 if not found + */ +int +xmlTextReaderMoveToAttributeNo(xmlTextReaderPtr reader, int no) { + int i; + xmlAttrPtr cur; + xmlNsPtr ns; + + if (reader == NULL) + return(-1); + if (reader->node == NULL) + return(-1); + /* TODO: handle the xmlDecl */ + if (reader->node->type != XML_ELEMENT_NODE) + return(-1); + + reader->curnode = NULL; + + ns = reader->node->nsDef; + for (i = 0;(i < no) && (ns != NULL);i++) { + ns = ns->next; + } + if (ns != NULL) { + reader->curnode = (xmlNodePtr) ns; + return(1); + } + + cur = reader->node->properties; + if (cur == NULL) + return(0); + for (;i < no;i++) { + cur = cur->next; + if (cur == NULL) + return(0); + } + /* TODO walk the DTD if present */ + + reader->curnode = (xmlNodePtr) cur; + return(1); +} + +/** + * xmlTextReaderMoveToAttribute: + * @reader: the xmlTextReaderPtr used + * @name: the qualified name of the attribute. + * + * Moves the position of the current instance to the attribute with + * the specified qualified name. + * + * Returns 1 in case of success, -1 in case of error, 0 if not found + */ +int +xmlTextReaderMoveToAttribute(xmlTextReaderPtr reader, const xmlChar *name) { + xmlChar *prefix = NULL; + xmlChar *localname; + xmlNsPtr ns; + xmlAttrPtr prop; + + if ((reader == NULL) || (name == NULL)) + return(-1); + if (reader->node == NULL) + return(-1); + + /* TODO: handle the xmlDecl */ + if (reader->node->type != XML_ELEMENT_NODE) + return(0); + + localname = xmlSplitQName2(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) { + reader->curnode = (xmlNodePtr) ns; + return(1); + } + ns = ns->next; + } + return(0); + } + + prop = reader->node->properties; + while (prop != NULL) { + /* + * One need to have + * - same attribute names + * - and the attribute carrying that namespace + */ + if ((xmlStrEqual(prop->name, name)) && + ((prop->ns == NULL) || (prop->ns->prefix == NULL))) { + reader->curnode = (xmlNodePtr) prop; + return(1); + } + prop = prop->next; + } + return(0); + } + + /* + * Namespace default decl + */ + if (xmlStrEqual(prefix, BAD_CAST "xmlns")) { + ns = reader->node->nsDef; + while (ns != NULL) { + if ((ns->prefix != NULL) && (xmlStrEqual(ns->prefix, localname))) { + reader->curnode = (xmlNodePtr) ns; + goto found; + } + ns = ns->next; + } + goto not_found; + } + prop = reader->node->properties; + while (prop != NULL) { + /* + * One need to have + * - same attribute names + * - and the attribute carrying that namespace + */ + if ((xmlStrEqual(prop->name, localname)) && + (prop->ns != NULL) && (xmlStrEqual(prop->ns->prefix, prefix))) { + reader->curnode = (xmlNodePtr) prop; + goto found; + } + 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); +} + +/** + * xmlTextReaderMoveToAttributeNs: + * @reader: the xmlTextReaderPtr used + * @localName: the local name of the attribute. + * @namespaceURI: the namespace URI of the attribute. + * + * Moves the position of the current instance to the attribute with the + * specified local name and namespace URI. + * + * Returns 1 in case of success, -1 in case of error, 0 if not found + */ +int +xmlTextReaderMoveToAttributeNs(xmlTextReaderPtr reader, + const xmlChar *localName, const xmlChar *namespaceURI) { + xmlAttrPtr prop; + xmlNodePtr node; + xmlNsPtr ns; + xmlChar *prefix = NULL; + + if ((reader == NULL) || (localName == NULL) || (namespaceURI == NULL)) + return(-1); + if (reader->node == NULL) + return(-1); + if (reader->node->type != XML_ELEMENT_NODE) + return(0); + node = reader->node; + + 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)))) { + reader->curnode = (xmlNodePtr) ns; + return(1); + } + ns = ns->next; + } + return(0); + } + + prop = node->properties; + while (prop != NULL) { + /* + * One need to have + * - same attribute names + * - and the attribute carrying that namespace + */ + if (xmlStrEqual(prop->name, localName) && + ((prop->ns != NULL) && + (xmlStrEqual(prop->ns->href, namespaceURI)))) { + reader->curnode = (xmlNodePtr) prop; + return(1); + } + prop = prop->next; + } + return(0); +} + +/** + * xmlTextReaderMoveToFirstAttribute: + * @reader: the xmlTextReaderPtr used + * + * Moves the position of the current instance to the first attribute + * associated with the current node. + * + * Returns 1 in case of success, -1 in case of error, 0 if not found + */ +int +xmlTextReaderMoveToFirstAttribute(xmlTextReaderPtr reader) { + if (reader == NULL) + return(-1); + if (reader->node == NULL) + return(-1); + if (reader->node->type != XML_ELEMENT_NODE) + return(0); + + if (reader->node->nsDef != NULL) { + reader->curnode = (xmlNodePtr) reader->node->nsDef; + return(1); + } + if (reader->node->properties != NULL) { + reader->curnode = (xmlNodePtr) reader->node->properties; + return(1); + } + return(0); +} + +/** + * xmlTextReaderMoveToNextAttribute: + * @reader: the xmlTextReaderPtr used + * + * Moves the position of the current instance to the next attribute + * associated with the current node. + * + * Returns 1 in case of success, -1 in case of error, 0 if not found + */ +int +xmlTextReaderMoveToNextAttribute(xmlTextReaderPtr reader) { + if (reader == NULL) + return(-1); + if (reader->node == NULL) + return(-1); + if (reader->node->type != XML_ELEMENT_NODE) + return(0); + if (reader->curnode == NULL) + return(xmlTextReaderMoveToFirstAttribute(reader)); + + if (reader->curnode->type == XML_NAMESPACE_DECL) { + xmlNsPtr ns = (xmlNsPtr) reader->curnode; + if (ns->next != NULL) { + reader->curnode = (xmlNodePtr) ns->next; + return(1); + } + if (reader->node->properties != NULL) { + reader->curnode = (xmlNodePtr) reader->node->properties; + return(1); + } + return(0); + } else if ((reader->curnode->type == XML_ATTRIBUTE_NODE) && + (reader->curnode->next != NULL)) { + reader->curnode = reader->curnode->next; + return(1); + } + return(0); +} + +/** + * xmlTextReaderMoveToElement: + * @reader: the xmlTextReaderPtr used + * + * Moves the position of the current instance to the node that + * contains the current Attribute node. + * + * Returns 1 in case of success, -1 in case of error, 0 if not moved + */ +int +xmlTextReaderMoveToElement(xmlTextReaderPtr reader) { + if (reader == NULL) + return(-1); + if (reader->node == NULL) + return(-1); + if (reader->node->type != XML_ELEMENT_NODE) + return(0); + if (reader->curnode != NULL) { + reader->curnode = NULL; + return(1); + } + return(0); +} + +/** + * xmlTextReaderReadAttributeValue: + * @reader: the xmlTextReaderPtr used + * + * Parses an attribute value into one or more Text and EntityReference nodes. + * + * Returns 1 in case of success, 0 if the reader was not positionned on an + * ttribute node or all the attribute values have been read, or -1 + * in case of error. + */ +int +xmlTextReaderReadAttributeValue(xmlTextReaderPtr reader) { + if (reader == NULL) + return(-1); + if (reader->node == NULL) + return(-1); + if (reader->curnode == NULL) + return(0); + if (reader->curnode->type == XML_ATTRIBUTE_NODE) { + if (reader->curnode->children == NULL) + return(0); + reader->curnode = reader->curnode->children; + } else if (reader->curnode->type == XML_NAMESPACE_DECL) { + xmlNsPtr ns = (xmlNsPtr) reader->curnode; + + if (reader->faketext == NULL) { + reader->faketext = xmlNewDocText(reader->node->doc, + ns->href); + } else { + if ((reader->faketext->content != NULL) && + (reader->faketext->content != + (xmlChar *) &(reader->faketext->properties))) + xmlFree(reader->faketext->content); + reader->faketext->content = xmlStrdup(ns->href); + } + reader->curnode = reader->faketext; + } else { + if (reader->curnode->next == NULL) + return(0); + reader->curnode = reader->curnode->next; + } + return(1); +} + +/** + * xmlTextReaderConstEncoding: + * @reader: the xmlTextReaderPtr used + * + * Determine the encoding of the document being read. + * + * Returns a string containing the encoding of the document or NULL in + * case of error. The string is deallocated with the reader. + */ +const xmlChar * +xmlTextReaderConstEncoding(xmlTextReaderPtr reader) { + xmlDocPtr doc = NULL; + if (reader == NULL) + return(NULL); + if (reader->doc != NULL) + doc = reader->doc; + else if (reader->ctxt != NULL) + doc = reader->ctxt->myDoc; + if (doc == NULL) + return(NULL); + + if (doc->encoding == NULL) + return(NULL); + else + return(CONSTSTR(doc->encoding)); +} + + +/************************************************************************ + * * + * Acces API to the current node * + * * + ************************************************************************/ +/** + * xmlTextReaderAttributeCount: + * @reader: the xmlTextReaderPtr used + * + * Provides the number of attributes of the current node + * + * Returns 0 i no attributes, -1 in case of error or the attribute count + */ +int +xmlTextReaderAttributeCount(xmlTextReaderPtr reader) { + int ret; + xmlAttrPtr attr; + xmlNsPtr ns; + xmlNodePtr node; + + if (reader == NULL) + return(-1); + if (reader->node == NULL) + return(0); + + if (reader->curnode != NULL) + node = reader->curnode; + else + node = reader->node; + + if (node->type != XML_ELEMENT_NODE) + return(0); + if ((reader->state == XML_TEXTREADER_END) || + (reader->state == XML_TEXTREADER_BACKTRACK)) + return(0); + ret = 0; + attr = node->properties; + while (attr != NULL) { + ret++; + attr = attr->next; + } + ns = node->nsDef; + while (ns != NULL) { + ret++; + ns = ns->next; + } + return(ret); +} + +/** + * xmlTextReaderNodeType: + * @reader: the xmlTextReaderPtr used + * + * Get the node type of the current node + * Reference: + * http://www.gnu.org/software/dotgnu/pnetlib-doc/System/Xml/XmlNodeType.html + * + * Returns the xmlNodeType of the current node or -1 in case of error + */ +int +xmlTextReaderNodeType(xmlTextReaderPtr reader) { + xmlNodePtr node; + + if (reader == NULL) + return(-1); + if (reader->node == NULL) + return(XML_READER_TYPE_NONE); + if (reader->curnode != NULL) + node = reader->curnode; + else + node = reader->node; + switch (node->type) { + case XML_ELEMENT_NODE: + if ((reader->state == XML_TEXTREADER_END) || + (reader->state == XML_TEXTREADER_BACKTRACK)) + return(XML_READER_TYPE_END_ELEMENT); + return(XML_READER_TYPE_ELEMENT); + case XML_NAMESPACE_DECL: + case XML_ATTRIBUTE_NODE: + return(XML_READER_TYPE_ATTRIBUTE); + case XML_TEXT_NODE: + if (xmlIsBlankNode(reader->node)) { + if (xmlNodeGetSpacePreserve(reader->node)) + return(XML_READER_TYPE_SIGNIFICANT_WHITESPACE); + else + return(XML_READER_TYPE_WHITESPACE); + } else { + return(XML_READER_TYPE_TEXT); + } + case XML_CDATA_SECTION_NODE: + return(XML_READER_TYPE_CDATA); + case XML_ENTITY_REF_NODE: + return(XML_READER_TYPE_ENTITY_REFERENCE); + case XML_ENTITY_NODE: + return(XML_READER_TYPE_ENTITY); + case XML_PI_NODE: + return(XML_READER_TYPE_PROCESSING_INSTRUCTION); + case XML_COMMENT_NODE: + return(XML_READER_TYPE_COMMENT); + case XML_DOCUMENT_NODE: + case XML_HTML_DOCUMENT_NODE: +#ifdef LIBXML_DOCB_ENABLED + case XML_DOCB_DOCUMENT_NODE: +#endif + return(XML_READER_TYPE_DOCUMENT); + case XML_DOCUMENT_FRAG_NODE: + return(XML_READER_TYPE_DOCUMENT_FRAGMENT); + case XML_NOTATION_NODE: + return(XML_READER_TYPE_NOTATION); + case XML_DOCUMENT_TYPE_NODE: + case XML_DTD_NODE: + return(XML_READER_TYPE_DOCUMENT_TYPE); + + case XML_ELEMENT_DECL: + case XML_ATTRIBUTE_DECL: + case XML_ENTITY_DECL: + case XML_XINCLUDE_START: + case XML_XINCLUDE_END: + return(XML_READER_TYPE_NONE); + } + return(-1); +} + +/** + * xmlTextReaderIsEmptyElement: + * @reader: the xmlTextReaderPtr used + * + * Check if the current node is empty + * + * Returns 1 if empty, 0 if not and -1 in case of error + */ +int +xmlTextReaderIsEmptyElement(xmlTextReaderPtr reader) { + if ((reader == NULL) || (reader->node == NULL)) + return(-1); + if (reader->node->type != XML_ELEMENT_NODE) + return(0); + if (reader->curnode != NULL) + return(0); + if (reader->node->children != NULL) + return(0); + if (reader->state == XML_TEXTREADER_END) + return(0); + if (reader->doc != NULL) + return(1); +#ifdef LIBXML_XINCLUDE_ENABLED + if (reader->in_xinclude > 0) + return(1); +#endif + return((reader->node->extra & NODE_IS_EMPTY) != 0); +} + +/** + * xmlTextReaderLocalName: + * @reader: the xmlTextReaderPtr used + * + * The local name of the node. + * + * Returns the local name or NULL if not available, + * if non NULL it need to be freed by the caller. + */ +xmlChar * +xmlTextReaderLocalName(xmlTextReaderPtr reader) { + xmlNodePtr node; + if ((reader == NULL) || (reader->node == NULL)) + return(NULL); + if (reader->curnode != NULL) + node = reader->curnode; + else + node = reader->node; + if (node->type == XML_NAMESPACE_DECL) { + xmlNsPtr ns = (xmlNsPtr) node; + if (ns->prefix == NULL) + return(xmlStrdup(BAD_CAST "xmlns")); + else + return(xmlStrdup(ns->prefix)); + } + if ((node->type != XML_ELEMENT_NODE) && + (node->type != XML_ATTRIBUTE_NODE)) + return(xmlTextReaderName(reader)); + return(xmlStrdup(node->name)); +} + +/** + * xmlTextReaderConstLocalName: + * @reader: the xmlTextReaderPtr used + * + * The local name of the node. + * + * Returns the local name or NULL if not available, the + * string will be deallocated with the reader. + */ +const xmlChar * +xmlTextReaderConstLocalName(xmlTextReaderPtr reader) { + xmlNodePtr node; + if ((reader == NULL) || (reader->node == NULL)) + return(NULL); + if (reader->curnode != NULL) + node = reader->curnode; + else + node = reader->node; + if (node->type == XML_NAMESPACE_DECL) { + xmlNsPtr ns = (xmlNsPtr) node; + if (ns->prefix == NULL) + return(CONSTSTR(BAD_CAST "xmlns")); + else + return(ns->prefix); + } + if ((node->type != XML_ELEMENT_NODE) && + (node->type != XML_ATTRIBUTE_NODE)) + return(xmlTextReaderConstName(reader)); + return(node->name); +} + +/** + * xmlTextReaderName: + * @reader: the xmlTextReaderPtr used + * + * The qualified name of the node, equal to Prefix :LocalName. + * + * Returns the local name or NULL if not available, + * if non NULL it need to be freed by the caller. + */ +xmlChar * +xmlTextReaderName(xmlTextReaderPtr reader) { + xmlNodePtr node; + xmlChar *ret; + + if ((reader == NULL) || (reader->node == NULL)) + return(NULL); + if (reader->curnode != NULL) + node = reader->curnode; + else + node = reader->node; + switch (node->type) { + case XML_ELEMENT_NODE: + case XML_ATTRIBUTE_NODE: + if ((node->ns == NULL) || + (node->ns->prefix == NULL)) + return(xmlStrdup(node->name)); + + ret = xmlStrdup(node->ns->prefix); + ret = xmlStrcat(ret, BAD_CAST ":"); + ret = xmlStrcat(ret, node->name); + return(ret); + case XML_TEXT_NODE: + return(xmlStrdup(BAD_CAST "#text")); + case XML_CDATA_SECTION_NODE: + return(xmlStrdup(BAD_CAST "#cdata-section")); + case XML_ENTITY_NODE: + case XML_ENTITY_REF_NODE: + return(xmlStrdup(node->name)); + case XML_PI_NODE: + return(xmlStrdup(node->name)); + case XML_COMMENT_NODE: + return(xmlStrdup(BAD_CAST "#comment")); + case XML_DOCUMENT_NODE: + case XML_HTML_DOCUMENT_NODE: +#ifdef LIBXML_DOCB_ENABLED + case XML_DOCB_DOCUMENT_NODE: +#endif + return(xmlStrdup(BAD_CAST "#document")); + case XML_DOCUMENT_FRAG_NODE: + return(xmlStrdup(BAD_CAST "#document-fragment")); + case XML_NOTATION_NODE: + return(xmlStrdup(node->name)); + case XML_DOCUMENT_TYPE_NODE: + case XML_DTD_NODE: + return(xmlStrdup(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(ret); + } + + case XML_ELEMENT_DECL: + case XML_ATTRIBUTE_DECL: + case XML_ENTITY_DECL: + case XML_XINCLUDE_START: + case XML_XINCLUDE_END: + return(NULL); + } + return(NULL); +} + +/** + * xmlTextReaderConstName: + * @reader: the xmlTextReaderPtr used + * + * The qualified name of the node, equal to Prefix :LocalName. + * + * Returns the local name or NULL if not available, the string is + * deallocated with the reader. + */ +const xmlChar * +xmlTextReaderConstName(xmlTextReaderPtr reader) { + xmlNodePtr node; + + if ((reader == NULL) || (reader->node == NULL)) + return(NULL); + if (reader->curnode != NULL) + node = reader->curnode; + else + node = reader->node; + switch (node->type) { + case XML_ELEMENT_NODE: + case XML_ATTRIBUTE_NODE: + if ((node->ns == NULL) || + (node->ns->prefix == NULL)) + return(node->name); + return(CONSTQSTR(node->ns->prefix, node->name)); + case XML_TEXT_NODE: + return(CONSTSTR(BAD_CAST "#text")); + case XML_CDATA_SECTION_NODE: + return(CONSTSTR(BAD_CAST "#cdata-section")); + case XML_ENTITY_NODE: + case XML_ENTITY_REF_NODE: + return(CONSTSTR(node->name)); + case XML_PI_NODE: + return(CONSTSTR(node->name)); + case XML_COMMENT_NODE: + return(CONSTSTR(BAD_CAST "#comment")); + case XML_DOCUMENT_NODE: + case XML_HTML_DOCUMENT_NODE: +#ifdef LIBXML_DOCB_ENABLED + case XML_DOCB_DOCUMENT_NODE: +#endif + return(CONSTSTR(BAD_CAST "#document")); + case XML_DOCUMENT_FRAG_NODE: + return(CONSTSTR(BAD_CAST "#document-fragment")); + case XML_NOTATION_NODE: + return(CONSTSTR(node->name)); + case XML_DOCUMENT_TYPE_NODE: + case XML_DTD_NODE: + return(CONSTSTR(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)); + } + + case XML_ELEMENT_DECL: + case XML_ATTRIBUTE_DECL: + case XML_ENTITY_DECL: + case XML_XINCLUDE_START: + case XML_XINCLUDE_END: + return(NULL); + } + return(NULL); +} + +/** + * xmlTextReaderPrefix: + * @reader: the xmlTextReaderPtr used + * + * A shorthand reference to the namespace associated with the node. + * + * Returns the prefix or NULL if not available, + * if non NULL it need to be freed by the caller. + */ +xmlChar * +xmlTextReaderPrefix(xmlTextReaderPtr reader) { + xmlNodePtr node; + if ((reader == NULL) || (reader->node == NULL)) + return(NULL); + if (reader->curnode != NULL) + node = reader->curnode; + else + node = reader->node; + if (node->type == XML_NAMESPACE_DECL) { + xmlNsPtr ns = (xmlNsPtr) node; + if (ns->prefix == NULL) + return(NULL); + return(xmlStrdup(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(NULL); +} + +/** + * xmlTextReaderConstPrefix: + * @reader: the xmlTextReaderPtr used + * + * A shorthand reference to the namespace associated with the node. + * + * Returns the prefix or NULL if not available, the string is deallocated + * with the reader. + */ +const xmlChar * +xmlTextReaderConstPrefix(xmlTextReaderPtr reader) { + xmlNodePtr node; + if ((reader == NULL) || (reader->node == NULL)) + return(NULL); + if (reader->curnode != NULL) + node = reader->curnode; + else + node = reader->node; + if (node->type == XML_NAMESPACE_DECL) { + xmlNsPtr ns = (xmlNsPtr) node; + if (ns->prefix == NULL) + return(NULL); + return(CONSTSTR(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(NULL); +} + +/** + * xmlTextReaderNamespaceUri: + * @reader: the xmlTextReaderPtr used + * + * The URI defining the namespace associated with the node. + * + * Returns the namespace URI or NULL if not available, + * if non NULL it need to be freed by the caller. + */ +xmlChar * +xmlTextReaderNamespaceUri(xmlTextReaderPtr reader) { + xmlNodePtr node; + if ((reader == NULL) || (reader->node == NULL)) + return(NULL); + if (reader->curnode != NULL) + node = reader->curnode; + else + node = reader->node; + if (node->type == XML_NAMESPACE_DECL) + return(xmlStrdup(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(NULL); +} + +/** + * xmlTextReaderConstNamespaceUri: + * @reader: the xmlTextReaderPtr used + * + * The URI defining the namespace associated with the node. + * + * Returns the namespace URI or NULL if not available, the string + * will be deallocated with the reader + */ +const xmlChar * +xmlTextReaderConstNamespaceUri(xmlTextReaderPtr reader) { + xmlNodePtr node; + if ((reader == NULL) || (reader->node == NULL)) + return(NULL); + if (reader->curnode != NULL) + node = reader->curnode; + else + node = reader->node; + if (node->type == XML_NAMESPACE_DECL) + return(CONSTSTR(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(NULL); +} + +/** + * xmlTextReaderBaseUri: + * @reader: the xmlTextReaderPtr used + * + * The base URI of the node. + * + * Returns the base URI or NULL if not available, + * if non NULL it need to be freed by the caller. + */ +xmlChar * +xmlTextReaderBaseUri(xmlTextReaderPtr reader) { + if ((reader == NULL) || (reader->node == NULL)) + return(NULL); + return(xmlNodeGetBase(NULL, reader->node)); +} + +/** + * xmlTextReaderConstBaseUri: + * @reader: the xmlTextReaderPtr used + * + * The base URI of the node. + * + * Returns the base URI or NULL if not available, the string + * will be deallocated with the reader + */ +const xmlChar * +xmlTextReaderConstBaseUri(xmlTextReaderPtr reader) { + xmlChar *tmp; + const xmlChar *ret; + + if ((reader == NULL) || (reader->node == NULL)) + return(NULL); + tmp = xmlNodeGetBase(NULL, reader->node); + if (tmp == NULL) + return(NULL); + ret = CONSTSTR(tmp); + xmlFree(tmp); + return(ret); +} + +/** + * xmlTextReaderDepth: + * @reader: the xmlTextReaderPtr used + * + * The depth of the node in the tree. + * + * Returns the depth or -1 in case of error + */ +int +xmlTextReaderDepth(xmlTextReaderPtr reader) { + if (reader == NULL) + return(-1); + if (reader->node == NULL) + return(0); + + if (reader->curnode != NULL) { + if ((reader->curnode->type == XML_ATTRIBUTE_NODE) || + (reader->curnode->type == XML_NAMESPACE_DECL)) + return(reader->depth + 1); + return(reader->depth + 2); + } + return(reader->depth); +} + +/** + * xmlTextReaderHasAttributes: + * @reader: the xmlTextReaderPtr used + * + * Whether the node has attributes. + * + * Returns 1 if true, 0 if false, and -1 in case or error + */ +int +xmlTextReaderHasAttributes(xmlTextReaderPtr reader) { + xmlNodePtr node; + if (reader == NULL) + return(-1); + if (reader->node == NULL) + return(0); + if (reader->curnode != NULL) + node = reader->curnode; + else + node = reader->node; + + if ((node->type == XML_ELEMENT_NODE) && + ((node->properties != NULL) || (node->nsDef != NULL))) + return(1); + /* TODO: handle the xmlDecl */ + return(0); +} + +/** + * xmlTextReaderHasValue: + * @reader: the xmlTextReaderPtr used + * + * Whether the node can have a text value. + * + * Returns 1 if true, 0 if false, and -1 in case or error + */ +int +xmlTextReaderHasValue(xmlTextReaderPtr reader) { + xmlNodePtr node; + if (reader == NULL) + return(-1); + if (reader->node == NULL) + return(0); + if (reader->curnode != NULL) + node = reader->curnode; + else + node = reader->node; + + switch (node->type) { + case XML_ATTRIBUTE_NODE: + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: + case XML_PI_NODE: + case XML_COMMENT_NODE: + case XML_NAMESPACE_DECL: + return(1); + default: + break; + } + return(0); +} + +/** + * xmlTextReaderValue: + * @reader: the xmlTextReaderPtr used + * + * Provides the text value of the node if present + * + * Returns the string or NULL if not available. The result must be deallocated + * with xmlFree() + */ +xmlChar * +xmlTextReaderValue(xmlTextReaderPtr reader) { + xmlNodePtr node; + if (reader == NULL) + return(NULL); + if (reader->node == NULL) + return(NULL); + if (reader->curnode != NULL) + node = reader->curnode; + else + node = reader->node; + + switch (node->type) { + case XML_NAMESPACE_DECL: + return(xmlStrdup(((xmlNsPtr) node)->href)); + case XML_ATTRIBUTE_NODE:{ + xmlAttrPtr attr = (xmlAttrPtr) node; + + if (attr->parent != NULL) + return (xmlNodeListGetString + (attr->parent->doc, attr->children, 1)); + else + return (xmlNodeListGetString(NULL, attr->children, 1)); + break; + } + 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)); + default: + break; + } + return(NULL); +} + +/** + * xmlTextReaderConstValue: + * @reader: the xmlTextReaderPtr used + * + * Provides the text value of the node if present + * + * Returns the string or NULL if not available. The result will be + * deallocated on the next Read() operation. + */ +const xmlChar * +xmlTextReaderConstValue(xmlTextReaderPtr reader) { + xmlNodePtr node; + if (reader == NULL) + return(NULL); + if (reader->node == NULL) + return(NULL); + if (reader->curnode != NULL) + node = reader->curnode; + else + node = reader->node; + + switch (node->type) { + case XML_NAMESPACE_DECL: + return(((xmlNsPtr) node)->href); + case XML_ATTRIBUTE_NODE:{ + xmlAttrPtr attr = (xmlAttrPtr) node; + + if ((attr->children != NULL) && + (attr->children->type == XML_TEXT_NODE) && + (attr->children->next == NULL)) + return(attr->children->content); + else { + if (reader->buffer == NULL) + reader->buffer = xmlBufferCreateSize(100); + if (reader->buffer == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlTextReaderSetup : malloc failed\n"); + return (NULL); + } + reader->buffer->use = 0; + xmlNodeBufGetContent(reader->buffer, node); + return(reader->buffer->content); + } + break; + } + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: + case XML_PI_NODE: + case XML_COMMENT_NODE: + return(node->content); + default: + break; + } + return(NULL); +} + +/** + * xmlTextReaderIsDefault: + * @reader: the xmlTextReaderPtr used + * + * Whether an Attribute node was generated from the default value + * defined in the DTD or schema. + * + * Returns 0 if not defaulted, 1 if defaulted, and -1 in case of error + */ +int +xmlTextReaderIsDefault(xmlTextReaderPtr reader) { + if (reader == NULL) + return(-1); + return(0); +} + +/** + * xmlTextReaderQuoteChar: + * @reader: the xmlTextReaderPtr used + * + * The quotation mark character used to enclose the value of an attribute. + * + * Returns " or ' and -1 in case of error + */ +int +xmlTextReaderQuoteChar(xmlTextReaderPtr reader) { + if (reader == NULL) + return(-1); + /* TODO maybe lookup the attribute value for " first */ + return((int) '"'); +} + +/** + * xmlTextReaderXmlLang: + * @reader: the xmlTextReaderPtr used + * + * The xml:lang scope within which the node resides. + * + * Returns the xml:lang value or NULL if none exists., + * if non NULL it need to be freed by the caller. + */ +xmlChar * +xmlTextReaderXmlLang(xmlTextReaderPtr reader) { + if (reader == NULL) + return(NULL); + if (reader->node == NULL) + return(NULL); + return(xmlNodeGetLang(reader->node)); +} + +/** + * xmlTextReaderConstXmlLang: + * @reader: the xmlTextReaderPtr used + * + * The xml:lang scope within which the node resides. + * + * Returns the xml:lang value or NULL if none exists. + */ +const xmlChar * +xmlTextReaderConstXmlLang(xmlTextReaderPtr reader) { + xmlChar *tmp; + const xmlChar *ret; + + if (reader == NULL) + return(NULL); + if (reader->node == NULL) + return(NULL); + tmp = xmlNodeGetLang(reader->node); + if (tmp == NULL) + return(NULL); + ret = CONSTSTR(tmp); + xmlFree(tmp); + return(ret); +} + +/** + * xmlTextReaderConstString: + * @reader: the xmlTextReaderPtr used + * @str: the string to intern. + * + * Get an interned string from the reader, allows for example to + * speedup string name comparisons + * + * Returns an interned copy of the string or NULL in case of error. The + * string will be deallocated with the reader. + */ +const xmlChar * +xmlTextReaderConstString(xmlTextReaderPtr reader, const xmlChar *str) { + if (reader == NULL) + return(NULL); + return(CONSTSTR(str)); +} + +/** + * xmlTextReaderNormalization: + * @reader: the xmlTextReaderPtr used + * + * The value indicating whether to normalize white space and attribute values. + * Since attribute value and end of line normalizations are a MUST in the XML + * specification only the value true is accepted. The broken bahaviour of + * accepting out of range character entities like � is of course not + * supported either. + * + * Returns 1 or -1 in case of error. + */ +int +xmlTextReaderNormalization(xmlTextReaderPtr reader) { + if (reader == NULL) + return(-1); + return(1); +} + +/************************************************************************ + * * + * Extensions to the base APIs * + * * + ************************************************************************/ + +/** + * xmlTextReaderSetParserProp: + * @reader: the xmlTextReaderPtr used + * @prop: the xmlParserProperties to set + * @value: usually 0 or 1 to (de)activate it + * + * Change the parser processing behaviour by changing some of its internal + * properties. Note that some properties can only be changed before any + * read has been done. + * + * Returns 0 if the call was successful, or -1 in case of error + */ +int +xmlTextReaderSetParserProp(xmlTextReaderPtr reader, int prop, int value) { + xmlParserProperties p = (xmlParserProperties) prop; + xmlParserCtxtPtr ctxt; + + if ((reader == NULL) || (reader->ctxt == NULL)) + return(-1); + ctxt = reader->ctxt; + + switch (p) { + case XML_PARSER_LOADDTD: + if (value != 0) { + if (ctxt->loadsubset == 0) { + if (reader->mode != XML_TEXTREADER_MODE_INITIAL) + return(-1); + ctxt->loadsubset = XML_DETECT_IDS; + } + } else { + ctxt->loadsubset = 0; + } + return(0); + case XML_PARSER_DEFAULTATTRS: + if (value != 0) { + ctxt->loadsubset |= XML_COMPLETE_ATTRS; + } else { + if (ctxt->loadsubset & XML_COMPLETE_ATTRS) + ctxt->loadsubset -= XML_COMPLETE_ATTRS; + } + return(0); + case XML_PARSER_VALIDATE: + if (value != 0) { + ctxt->validate = 1; + reader->validate = XML_TEXTREADER_VALIDATE_DTD; + } else { + ctxt->validate = 0; + } + return(0); + case XML_PARSER_SUBST_ENTITIES: + if (value != 0) { + ctxt->replaceEntities = 1; + } else { + ctxt->replaceEntities = 0; + } + return(0); + } + return(-1); +} + +/** + * xmlTextReaderGetParserProp: + * @reader: the xmlTextReaderPtr used + * @prop: the xmlParserProperties to get + * + * Read the parser internal property. + * + * Returns the value, usually 0 or 1, or -1 in case of error. + */ +int +xmlTextReaderGetParserProp(xmlTextReaderPtr reader, int prop) { + xmlParserProperties p = (xmlParserProperties) prop; + xmlParserCtxtPtr ctxt; + + if ((reader == NULL) || (reader->ctxt == NULL)) + return(-1); + ctxt = reader->ctxt; + + switch (p) { + case XML_PARSER_LOADDTD: + if ((ctxt->loadsubset != 0) || (ctxt->validate != 0)) + return(1); + return(0); + case XML_PARSER_DEFAULTATTRS: + if (ctxt->loadsubset & XML_COMPLETE_ATTRS) + return(1); + return(0); + case XML_PARSER_VALIDATE: + return(reader->validate); + case XML_PARSER_SUBST_ENTITIES: + return(ctxt->replaceEntities); + } + return(-1); +} + + +/** + * xmlTextReaderGetParserLineNumber: + * @reader: the user data (XML reader context) + * + * Provide the line number of the current parsing point. + * + * Returns an int or 0 if not available + */ +int +xmlTextReaderGetParserLineNumber(xmlTextReaderPtr reader) +{ + if ((reader == NULL) || (reader->ctxt == NULL) || + (reader->ctxt->input == NULL)) { + return (0); + } + return (reader->ctxt->input->line); +} + +/** + * xmlTextReaderGetParserColumnNumber: + * @reader: the user data (XML reader context) + * + * Provide the column number of the current parsing point. + * + * Returns an int or 0 if not available + */ +int +xmlTextReaderGetParserColumnNumber(xmlTextReaderPtr reader) +{ + if ((reader == NULL) || (reader->ctxt == NULL) || + (reader->ctxt->input == NULL)) { + return (0); + } + return (reader->ctxt->input->col); +} + +/** + * xmlTextReaderCurrentNode: + * @reader: the xmlTextReaderPtr used + * + * Hacking interface allowing to get the xmlNodePtr correponding to the + * current node being accessed by the xmlTextReader. This is dangerous + * because the underlying node may be destroyed on the next Reads. + * + * Returns the xmlNodePtr or NULL in case of error. + */ +xmlNodePtr +xmlTextReaderCurrentNode(xmlTextReaderPtr reader) { + if (reader == NULL) + return(NULL); + + if (reader->curnode != NULL) + return(reader->curnode); + return(reader->node); +} + +/** + * xmlTextReaderPreserve: + * @reader: the xmlTextReaderPtr used + * + * This tells the XML Reader to preserve the current node. + * The caller must also use xmlTextReaderCurrentDoc() to + * keep an handle on the resulting document once parsing has finished + * + * Returns the xmlNodePtr or NULL in case of error. + */ +xmlNodePtr +xmlTextReaderPreserve(xmlTextReaderPtr reader) { + xmlNodePtr cur, parent; + + if (reader == NULL) + return(NULL); + + if (reader->curnode != NULL) + cur = reader->curnode; + else + cur = reader->node; + if (cur == NULL) + return(NULL); + + if ((cur->type != XML_DOCUMENT_NODE) && (cur->type != XML_DTD_NODE)) { + cur->extra |= NODE_IS_PRESERVED; + cur->extra |= NODE_IS_SPRESERVED; + } + reader->preserves++; + + parent = cur->parent;; + while (parent != NULL) { + if (parent->type == XML_ELEMENT_NODE) + parent->extra |= NODE_IS_PRESERVED; + parent = parent->parent; + } + return(cur); +} + +#ifdef LIBXML_PATTERN_ENABLED +/** + * xmlTextReaderPreservePattern: + * @reader: the xmlTextReaderPtr used + * @pattern: an XPath subset pattern + * @namespaces: the prefix definitions, array of [URI, prefix] or NULL + * + * This tells the XML Reader to preserve all nodes matched by the + * pattern. The caller must also use xmlTextReaderCurrentDoc() to + * keep an handle on the resulting document once parsing has finished + * + * Returns a positive number in case of success and -1 in case of error + */ +int +xmlTextReaderPreservePattern(xmlTextReaderPtr reader, const xmlChar *pattern, + const xmlChar **namespaces) +{ + xmlPatternPtr comp; + + if ((reader == NULL) || (pattern == NULL)) + return(-1); + + comp = xmlPatterncompile(pattern, reader->dict, 0, namespaces); + if (comp == NULL) + return(-1); + + if (reader->patternMax <= 0) { + reader->patternMax = 4; + reader->patternTab = (xmlPatternPtr *) xmlMalloc(reader->patternMax * + sizeof(reader->patternTab[0])); + if (reader->patternTab == NULL) { + xmlGenericError(xmlGenericErrorContext, "xmlMalloc failed !\n"); + return (-1); + } + } + if (reader->patternNr >= reader->patternMax) { + xmlPatternPtr *tmp; + reader->patternMax *= 2; + tmp = (xmlPatternPtr *) xmlRealloc(reader->patternTab, + reader->patternMax * + sizeof(reader->patternTab[0])); + if (tmp == NULL) { + xmlGenericError(xmlGenericErrorContext, "xmlRealloc failed !\n"); + reader->patternMax /= 2; + return (-1); + } + reader->patternTab = tmp; + } + reader->patternTab[reader->patternNr] = comp; + return(reader->patternNr++); +} +#endif + +/** + * xmlTextReaderCurrentDoc: + * @reader: the xmlTextReaderPtr used + * + * Hacking interface allowing to get the xmlDocPtr correponding to the + * current document being accessed by the xmlTextReader. + * NOTE: as a result of this call, the reader will not destroy the + * associated XML document and calling xmlFreeDoc() on the result + * is needed once the reader parsing has finished. + * + * Returns the xmlDocPtr or NULL in case of error. + */ +xmlDocPtr +xmlTextReaderCurrentDoc(xmlTextReaderPtr reader) { + if (reader == NULL) + return(NULL); + if (reader->doc != NULL) + return(reader->doc); + if ((reader->ctxt == NULL) || (reader->ctxt->myDoc == NULL)) + return(NULL); + + reader->preserve = 1; + return(reader->ctxt->myDoc); +} + +#ifdef LIBXML_SCHEMAS_ENABLED +static char *xmlTextReaderBuildMessage(const char *msg, va_list ap); + +static void XMLCDECL +xmlTextReaderValidityError(void *ctxt, const char *msg, ...); + +static void XMLCDECL +xmlTextReaderValidityWarning(void *ctxt, const char *msg, ...); + +static void XMLCDECL +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 XMLCDECL +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, xmlErrorPtr error); + +static void +xmlTextReaderValidityStructuredRelay(void *userData, xmlErrorPtr error) +{ + xmlTextReaderPtr reader = (xmlTextReaderPtr) userData; + + if (reader->sErrorFunc) { + reader->sErrorFunc(reader->errorFuncArg, error); + } else { + xmlTextReaderStructuredError(reader, error); + } +} +/** + * xmlTextReaderRelaxNGSetSchema: + * @reader: the xmlTextReaderPtr used + * @schema: a precompiled RelaxNG schema + * + * Use RelaxNG to validate the document as it is processed. + * Activation is only possible before the first Read(). + * if @schema is NULL, then RelaxNG validation is desactivated. + @ The @schema should not be freed until the reader is deallocated + * or its use has been deactivated. + * + * Returns 0 in case the RelaxNG validation could be (des)activated and + * -1 in case of error. + */ +int +xmlTextReaderRelaxNGSetSchema(xmlTextReaderPtr reader, xmlRelaxNGPtr schema) { + if (reader == NULL) + return(-1); + if (schema == NULL) { + if (reader->rngSchemas != NULL) { + xmlRelaxNGFree(reader->rngSchemas); + reader->rngSchemas = NULL; + } + if (reader->rngValidCtxt != NULL) { + xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt); + reader->rngValidCtxt = NULL; + } + return(0); + } + if (reader->mode != XML_TEXTREADER_MODE_INITIAL) + return(-1); + if (reader->rngSchemas != NULL) { + xmlRelaxNGFree(reader->rngSchemas); + reader->rngSchemas = NULL; + } + if (reader->rngValidCtxt != NULL) { + xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt); + reader->rngValidCtxt = NULL; + } + 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); + } + reader->rngValidErrors = 0; + reader->rngFullNode = NULL; + reader->validate = XML_TEXTREADER_VALIDATE_RNG; + return(0); +} + +/** + * xmlTextReaderSetSchema: + * @reader: the xmlTextReaderPtr used + * @schema: a precompiled Schema schema + * + * Use XSD Schema to validate the document as it is processed. + * Activation is only possible before the first Read(). + * if @schema is NULL, then Schema validation is desactivated. + @ The @schema should not be freed until the reader is deallocated + * or its use has been deactivated. + * + * Returns 0 in case the Schema validation could be (des)activated and + * -1 in case of error. + */ +int +xmlTextReaderSetSchema(xmlTextReaderPtr reader, xmlSchemaPtr schema) { + if (reader == NULL) + return(-1); + if (schema == NULL) { + if (reader->xsdPlug != NULL) { + xmlSchemaSAXUnplug(reader->xsdPlug); + reader->xsdPlug = NULL; + } + if (reader->xsdValidCtxt != NULL) { + if (! reader->xsdPreserveCtxt) + xmlSchemaFreeValidCtxt(reader->xsdValidCtxt); + reader->xsdValidCtxt = NULL; + } + reader->xsdPreserveCtxt = 0; + if (reader->xsdSchemas != NULL) { + xmlSchemaFree(reader->xsdSchemas); + reader->xsdSchemas = NULL; + } + return(0); + } + if (reader->mode != XML_TEXTREADER_MODE_INITIAL) + return(-1); + if (reader->xsdPlug != NULL) { + xmlSchemaSAXUnplug(reader->xsdPlug); + reader->xsdPlug = NULL; + } + if (reader->xsdValidCtxt != NULL) { + if (! reader->xsdPreserveCtxt) + xmlSchemaFreeValidCtxt(reader->xsdValidCtxt); + reader->xsdValidCtxt = NULL; + } + reader->xsdPreserveCtxt = 0; + if (reader->xsdSchemas != NULL) { + xmlSchemaFree(reader->xsdSchemas); + reader->xsdSchemas = NULL; + } + reader->xsdValidCtxt = xmlSchemaNewValidCtxt(schema); + if (reader->xsdValidCtxt == NULL) { + xmlSchemaFree(reader->xsdSchemas); + reader->xsdSchemas = NULL; + return(-1); + } + reader->xsdPlug = xmlSchemaSAXPlug(reader->xsdValidCtxt, + &(reader->ctxt->sax), + &(reader->ctxt->userData)); + if (reader->xsdPlug == NULL) { + xmlSchemaFree(reader->xsdSchemas); + reader->xsdSchemas = NULL; + xmlSchemaFreeValidCtxt(reader->xsdValidCtxt); + reader->xsdValidCtxt = NULL; + return(-1); + } + if (reader->errorFunc != NULL) { + xmlSchemaSetValidErrors(reader->xsdValidCtxt, + xmlTextReaderValidityErrorRelay, + xmlTextReaderValidityWarningRelay, + reader); + } + if (reader->sErrorFunc != NULL) { + xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt, + xmlTextReaderValidityStructuredRelay, + reader); + } + reader->xsdValidErrors = 0; + reader->validate = XML_TEXTREADER_VALIDATE_XSD; + return(0); +} + +/** + * xmlTextReaderRelaxNGValidate: + * @reader: the xmlTextReaderPtr used + * @rng: the path to a RelaxNG schema or NULL + * + * Use RelaxNG to validate the document as it is processed. + * Activation is only possible before the first Read(). + * if @rng is NULL, then RelaxNG validation is deactivated. + * + * Returns 0 in case the RelaxNG validation could be (de)activated and + * -1 in case of error. + */ +int +xmlTextReaderRelaxNGValidate(xmlTextReaderPtr reader, const char *rng) { + xmlRelaxNGParserCtxtPtr ctxt; + + if (reader == NULL) + return(-1); + + if (rng == NULL) { + if (reader->rngValidCtxt != NULL) { + xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt); + reader->rngValidCtxt = NULL; + } + if (reader->rngSchemas != NULL) { + xmlRelaxNGFree(reader->rngSchemas); + reader->rngSchemas = NULL; + } + return(0); + } + if (reader->mode != XML_TEXTREADER_MODE_INITIAL) + return(-1); + if (reader->rngSchemas != NULL) { + xmlRelaxNGFree(reader->rngSchemas); + reader->rngSchemas = NULL; + } + if (reader->rngValidCtxt != NULL) { + xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt); + reader->rngValidCtxt = NULL; + } + ctxt = xmlRelaxNGNewParserCtxt(rng); + if (reader->errorFunc != NULL) { + xmlRelaxNGSetParserErrors(ctxt, + xmlTextReaderValidityErrorRelay, + xmlTextReaderValidityWarningRelay, + reader); + } + if (reader->sErrorFunc != NULL) { + xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, + xmlTextReaderValidityStructuredRelay, + reader); + } + reader->rngSchemas = xmlRelaxNGParse(ctxt); + xmlRelaxNGFreeParserCtxt(ctxt); + if (reader->rngSchemas == NULL) + return(-1); + reader->rngValidCtxt = xmlRelaxNGNewValidCtxt(reader->rngSchemas); + if (reader->rngValidCtxt == NULL) { + xmlRelaxNGFree(reader->rngSchemas); + reader->rngSchemas = NULL; + return(-1); + } + if (reader->errorFunc != NULL) { + xmlRelaxNGSetValidErrors(reader->rngValidCtxt, + xmlTextReaderValidityErrorRelay, + xmlTextReaderValidityWarningRelay, + reader); + } + if (reader->sErrorFunc != NULL) { + xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, + xmlTextReaderValidityStructuredRelay, + reader); + } + reader->rngValidErrors = 0; + reader->rngFullNode = NULL; + reader->validate = XML_TEXTREADER_VALIDATE_RNG; + return(0); +} + +/** + * xmlTextReaderSchemaValidateInternal: + * @reader: the xmlTextReaderPtr used + * @xsd: the path to a W3C XSD schema or NULL + * @ctxt: the XML Schema validation context or NULL + * @options: options (not used yet) + * + * Validate the document as it is processed using XML Schema. + * Activation is only possible before the first Read(). + * If both @xsd and @ctxt are NULL then XML Schema validation is deactivated. + * + * Returns 0 in case the schemas validation could be (de)activated and + * -1 in case of error. + */ +static int +xmlTextReaderSchemaValidateInternal(xmlTextReaderPtr reader, + const char *xsd, + xmlSchemaValidCtxtPtr ctxt, + int options ATTRIBUTE_UNUSED) +{ + if (reader == NULL) + return(-1); + + if ((xsd != NULL) && (ctxt != NULL)) + return(-1); + + if (((xsd != NULL) || (ctxt != NULL)) && + ((reader->mode != XML_TEXTREADER_MODE_INITIAL) || + (reader->ctxt == NULL))) + return(-1); + + /* Cleanup previous validation stuff. */ + if (reader->xsdPlug != NULL) { + xmlSchemaSAXUnplug(reader->xsdPlug); + reader->xsdPlug = NULL; + } + if (reader->xsdValidCtxt != NULL) { + if (! reader->xsdPreserveCtxt) + xmlSchemaFreeValidCtxt(reader->xsdValidCtxt); + reader->xsdValidCtxt = NULL; + } + reader->xsdPreserveCtxt = 0; + if (reader->xsdSchemas != NULL) { + xmlSchemaFree(reader->xsdSchemas); + reader->xsdSchemas = NULL; + } + + if ((xsd == NULL) && (ctxt == NULL)) { + /* We just want to deactivate the validation, so get out. */ + return(0); + } + + if (xsd != NULL) { + xmlSchemaParserCtxtPtr pctxt; + /* Parse the schema and create validation environment. */ + pctxt = xmlSchemaNewParserCtxt(xsd); + if (reader->errorFunc != NULL) { + xmlSchemaSetParserErrors(pctxt, + xmlTextReaderValidityErrorRelay, + xmlTextReaderValidityWarningRelay, + reader); + } + reader->xsdSchemas = xmlSchemaParse(pctxt); + xmlSchemaFreeParserCtxt(pctxt); + if (reader->xsdSchemas == NULL) + return(-1); + reader->xsdValidCtxt = xmlSchemaNewValidCtxt(reader->xsdSchemas); + if (reader->xsdValidCtxt == NULL) { + xmlSchemaFree(reader->xsdSchemas); + reader->xsdSchemas = NULL; + return(-1); + } + reader->xsdPlug = xmlSchemaSAXPlug(reader->xsdValidCtxt, + &(reader->ctxt->sax), + &(reader->ctxt->userData)); + if (reader->xsdPlug == NULL) { + xmlSchemaFree(reader->xsdSchemas); + reader->xsdSchemas = NULL; + xmlSchemaFreeValidCtxt(reader->xsdValidCtxt); + reader->xsdValidCtxt = NULL; + return(-1); + } + } else { + /* Use the given validation context. */ + reader->xsdValidCtxt = ctxt; + reader->xsdPreserveCtxt = 1; + reader->xsdPlug = xmlSchemaSAXPlug(reader->xsdValidCtxt, + &(reader->ctxt->sax), + &(reader->ctxt->userData)); + if (reader->xsdPlug == NULL) { + reader->xsdValidCtxt = NULL; + reader->xsdPreserveCtxt = 0; + return(-1); + } + } + /* + * Redirect the validation context's error channels to use + * the reader channels. + * 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); + } + reader->xsdValidErrors = 0; + reader->validate = XML_TEXTREADER_VALIDATE_XSD; + return(0); +} + +/** + * xmlTextReaderSchemaValidateCtxt: + * @reader: the xmlTextReaderPtr used + * @ctxt: the XML Schema validation context or NULL + * @options: options (not used yet) + * + * Use W3C XSD schema context to validate the document as it is processed. + * Activation is only possible before the first Read(). + * If @ctxt is NULL, then XML Schema validation is deactivated. + * + * Returns 0 in case the schemas validation could be (de)activated and + * -1 in case of error. + */ +int +xmlTextReaderSchemaValidateCtxt(xmlTextReaderPtr reader, + xmlSchemaValidCtxtPtr ctxt, + int options) +{ + return(xmlTextReaderSchemaValidateInternal(reader, NULL, ctxt, options)); +} + +/** + * xmlTextReaderSchemaValidate: + * @reader: the xmlTextReaderPtr used + * @xsd: the path to a W3C XSD schema or NULL + * + * Use W3C XSD schema to validate the document as it is processed. + * Activation is only possible before the first Read(). + * If @xsd is NULL, then XML Schema validation is deactivated. + * + * Returns 0 in case the schemas validation could be (de)activated and + * -1 in case of error. + */ +int +xmlTextReaderSchemaValidate(xmlTextReaderPtr reader, const char *xsd) +{ + return(xmlTextReaderSchemaValidateInternal(reader, xsd, NULL, 0)); +} +#endif + +/** + * xmlTextReaderIsNamespaceDecl: + * @reader: the xmlTextReaderPtr used + * + * Determine whether the current node is a namespace declaration + * rather than a regular attribute. + * + * Returns 1 if the current node is a namespace declaration, 0 if it + * is a regular attribute or other type of node, or -1 in case of + * error. + */ +int +xmlTextReaderIsNamespaceDecl(xmlTextReaderPtr reader) { + xmlNodePtr node; + if (reader == NULL) + return(-1); + if (reader->node == NULL) + return(-1); + if (reader->curnode != NULL) + node = reader->curnode; + else + node = reader->node; + + if (XML_NAMESPACE_DECL == node->type) + return(1); + else + return(0); +} + +/** + * xmlTextReaderConstXmlVersion: + * @reader: the xmlTextReaderPtr used + * + * Determine the XML version of the document being read. + * + * Returns a string containing the XML version of the document or NULL + * in case of error. The string is deallocated with the reader. + */ +const xmlChar * +xmlTextReaderConstXmlVersion(xmlTextReaderPtr reader) { + xmlDocPtr doc = NULL; + if (reader == NULL) + return(NULL); + if (reader->doc != NULL) + doc = reader->doc; + else if (reader->ctxt != NULL) + doc = reader->ctxt->myDoc; + if (doc == NULL) + return(NULL); + + if (doc->version == NULL) + return(NULL); + else + return(CONSTSTR(doc->version)); +} + +/** + * xmlTextReaderStandalone: + * @reader: the xmlTextReaderPtr used + * + * Determine the standalone status of the document being read. + * + * Returns 1 if the document was declared to be standalone, 0 if it + * was declared to be not standalone, or -1 if the document did not + * specify its standalone status or in case of error. + */ +int +xmlTextReaderStandalone(xmlTextReaderPtr reader) { + xmlDocPtr doc = NULL; + if (reader == NULL) + return(-1); + if (reader->doc != NULL) + doc = reader->doc; + else if (reader->ctxt != NULL) + doc = reader->ctxt->myDoc; + if (doc == NULL) + return(-1); + + return(doc->standalone); +} + +/************************************************************************ + * * + * Error Handling Extensions * + * * + ************************************************************************/ + +/* 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 + * + * Obtain the line number for the given locator. + * + * Returns the line number or -1 in case of error. + */ +int +xmlTextReaderLocatorLineNumber(xmlTextReaderLocatorPtr locator) { + /* we know that locator is a xmlParserCtxtPtr */ + xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)locator; + int ret = -1; + + if (locator == NULL) + return(-1); + if (ctx->node != NULL) { + ret = xmlGetLineNo(ctx->node); + } + else { + /* inspired from error.c */ + xmlParserInputPtr input; + input = ctx->input; + if ((input->filename == NULL) && (ctx->inputNr > 1)) + input = ctx->inputTab[ctx->inputNr - 2]; + if (input != NULL) { + ret = input->line; + } + else { + ret = -1; + } + } + + return ret; +} + +/** + * xmlTextReaderLocatorBaseURI: + * @locator: the xmlTextReaderLocatorPtr used + * + * Obtain the base URI for the given locator. + * + * Returns the base URI or NULL in case of error, + * if non NULL it need to be freed by the caller. + */ +xmlChar * +xmlTextReaderLocatorBaseURI(xmlTextReaderLocatorPtr locator) { + /* we know that locator is a xmlParserCtxtPtr */ + xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)locator; + xmlChar *ret = NULL; + + if (locator == NULL) + return(NULL); + if (ctx->node != NULL) { + ret = xmlNodeGetBase(NULL,ctx->node); + } + else { + /* inspired from error.c */ + xmlParserInputPtr input; + input = ctx->input; + if ((input->filename == NULL) && (ctx->inputNr > 1)) + input = ctx->inputTab[ctx->inputNr - 2]; + if (input != NULL) { + ret = xmlStrdup(BAD_CAST input->filename); + } + else { + ret = NULL; + } + } + + 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, xmlErrorPtr error) +{ + xmlParserCtxtPtr ctx = (xmlParserCtxtPtr) ctxt; + + xmlTextReaderPtr reader = (xmlTextReaderPtr) ctx->_private; + + if (error && reader->sErrorFunc) { + reader->sErrorFunc(reader->errorFuncArg, (xmlErrorPtr) error); + } +} + +static void XMLCDECL +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 XMLCDECL +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 XMLCDECL +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 XMLCDECL +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 + * + * Register a callback function that will be called on error and warnings. + * + * If @f is NULL, the default error and warning handlers are restored. + */ +void +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; +#ifdef LIBXML_SCHEMAS_ENABLED + if (reader->rngValidCtxt) { + xmlRelaxNGSetValidErrors(reader->rngValidCtxt, + xmlTextReaderValidityErrorRelay, + xmlTextReaderValidityWarningRelay, + reader); + xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, NULL, + reader); + } + if (reader->xsdValidCtxt) { + xmlSchemaSetValidErrors(reader->xsdValidCtxt, + xmlTextReaderValidityErrorRelay, + xmlTextReaderValidityWarningRelay, + reader); + xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt, NULL, + 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; +#ifdef LIBXML_SCHEMAS_ENABLED + if (reader->rngValidCtxt) { + xmlRelaxNGSetValidErrors(reader->rngValidCtxt, NULL, NULL, + reader); + xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, NULL, + reader); + } + if (reader->xsdValidCtxt) { + xmlSchemaSetValidErrors(reader->xsdValidCtxt, NULL, NULL, + reader); + xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt, NULL, + reader); + } +#endif + } +} + +/** +* xmlTextReaderSetStructuredErrorHandler: + * @reader: the xmlTextReaderPtr used + * @f: the callback function to call on error and warnings + * @arg: a user argument to pass to the callback function + * + * Register a callback function that will be called on error and warnings. + * + * If @f is NULL, the default error and warning handlers are restored. + */ +void +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; +#ifdef LIBXML_SCHEMAS_ENABLED + if (reader->rngValidCtxt) { + xmlRelaxNGSetValidErrors(reader->rngValidCtxt, NULL, NULL, + reader); + xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, + xmlTextReaderValidityStructuredRelay, + reader); + } + if (reader->xsdValidCtxt) { + xmlSchemaSetValidErrors(reader->xsdValidCtxt, NULL, NULL, + reader); + xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt, + xmlTextReaderValidityStructuredRelay, + 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; +#ifdef LIBXML_SCHEMAS_ENABLED + if (reader->rngValidCtxt) { + xmlRelaxNGSetValidErrors(reader->rngValidCtxt, NULL, NULL, + reader); + xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, NULL, + reader); + } + if (reader->xsdValidCtxt) { + xmlSchemaSetValidErrors(reader->xsdValidCtxt, NULL, NULL, + reader); + xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt, NULL, + reader); + } +#endif + } +} + +/** + * xmlTextReaderIsValid: + * @reader: the xmlTextReaderPtr used + * + * Retrieve the validity status from the parser context + * + * Returns the flag value 1 if valid, 0 if no, and -1 in case of error + */ +int +xmlTextReaderIsValid(xmlTextReaderPtr reader) +{ + if (reader == NULL) + return (-1); +#ifdef LIBXML_SCHEMAS_ENABLED + if (reader->validate == XML_TEXTREADER_VALIDATE_RNG) + return (reader->rngValidErrors == 0); + if (reader->validate == XML_TEXTREADER_VALIDATE_XSD) + return (reader->xsdValidErrors == 0); +#endif + if ((reader->ctxt != NULL) && (reader->ctxt->validate == 1)) + return (reader->ctxt->valid); + return (0); +} + +/** + * xmlTextReaderGetErrorHandler: + * @reader: the xmlTextReaderPtr used + * @f: the callback function or NULL is no callback has been registered + * @arg: a user argument + * + * Retrieve the error callback function and user argument. + */ +void +xmlTextReaderGetErrorHandler(xmlTextReaderPtr reader, + xmlTextReaderErrorFunc * f, void **arg) +{ + if (f != NULL) + *f = reader->errorFunc; + if (arg != NULL) + *arg = reader->errorFuncArg; +} +/************************************************************************ + * * + * New set (2.6.0) of simpler and more flexible APIs * + * * + ************************************************************************/ + +/** + * xmlTextReaderSetup: + * @reader: an XML reader + * @input: xmlParserInputBufferPtr used to feed the reader, will + * be destroyed with it. + * @URL: the base URL to use for the document + * @encoding: the document encoding, or NULL + * @options: a combination of xmlParserOption + * + * Setup an XML reader with new options + * + * Returns 0 in case of success and -1 in case of error. + */ +int +xmlTextReaderSetup(xmlTextReaderPtr reader, + xmlParserInputBufferPtr input, const char *URL, + const char *encoding, int options) +{ + if (reader == NULL) { + if (input != NULL) + xmlFreeParserInputBuffer(input); + return (-1); + } + + /* + * we force the generation of compact text nodes on the reader + * since usr applications should never modify the tree + */ + options |= XML_PARSE_COMPACT; + + reader->doc = NULL; + reader->entNr = 0; + reader->parserFlags = options; + reader->validate = XML_TEXTREADER_NOT_VALIDATE; + if ((input != NULL) && (reader->input != NULL) && + (reader->allocs & XML_TEXTREADER_INPUT)) { + xmlFreeParserInputBuffer(reader->input); + reader->input = NULL; + reader->allocs -= XML_TEXTREADER_INPUT; + } + if (input != NULL) { + reader->input = input; + reader->allocs |= XML_TEXTREADER_INPUT; + } + if (reader->buffer == NULL) + reader->buffer = xmlBufferCreateSize(100); + if (reader->buffer == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlTextReaderSetup : malloc failed\n"); + return (-1); + } + 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); + reader->startElement = reader->sax->startElement; + reader->sax->startElement = xmlTextReaderStartElement; + reader->endElement = reader->sax->endElement; + reader->sax->endElement = xmlTextReaderEndElement; +#ifdef LIBXML_SAX1_ENABLED + if (reader->sax->initialized == XML_SAX2_MAGIC) { +#endif /* LIBXML_SAX1_ENABLED */ + reader->startElementNs = reader->sax->startElementNs; + reader->sax->startElementNs = xmlTextReaderStartElementNs; + reader->endElementNs = reader->sax->endElementNs; + reader->sax->endElementNs = xmlTextReaderEndElementNs; +#ifdef LIBXML_SAX1_ENABLED + } else { + reader->startElementNs = NULL; + reader->endElementNs = NULL; + } +#endif /* LIBXML_SAX1_ENABLED */ + reader->characters = reader->sax->characters; + reader->sax->characters = xmlTextReaderCharacters; + reader->sax->ignorableWhitespace = xmlTextReaderCharacters; + reader->cdataBlock = reader->sax->cdataBlock; + reader->sax->cdataBlock = xmlTextReaderCDataBlock; + + reader->mode = XML_TEXTREADER_MODE_INITIAL; + reader->node = NULL; + reader->curnode = NULL; + if (input != NULL) { + if (reader->input->buffer->use < 4) { + xmlParserInputBufferRead(input, 4); + } + if (reader->ctxt == NULL) { + if (reader->input->buffer->use >= 4) { + reader->ctxt = xmlCreatePushParserCtxt(reader->sax, NULL, + (const char *) reader->input->buffer->content, 4, URL); + reader->base = 0; + reader->cur = 4; + } else { + reader->ctxt = + xmlCreatePushParserCtxt(reader->sax, NULL, NULL, 0, URL); + reader->base = 0; + reader->cur = 0; + } + } else { + xmlParserInputPtr inputStream; + xmlParserInputBufferPtr buf; + xmlCharEncoding enc = XML_CHAR_ENCODING_NONE; + + xmlCtxtReset(reader->ctxt); + buf = xmlAllocParserInputBuffer(enc); + if (buf == NULL) return(-1); + inputStream = xmlNewInputStream(reader->ctxt); + if (inputStream == NULL) { + xmlFreeParserInputBuffer(buf); + return(-1); + } + + if (URL == NULL) + inputStream->filename = NULL; + else + inputStream->filename = (char *) + xmlCanonicPath((const xmlChar *) URL); + inputStream->buf = buf; + inputStream->base = inputStream->buf->buffer->content; + inputStream->cur = inputStream->buf->buffer->content; + inputStream->end = + &inputStream->buf->buffer->content[inputStream->buf->buffer->use]; + + inputPush(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) { + if (reader->dict != reader->ctxt->dict) { + xmlDictFree(reader->dict); + reader->dict = reader->ctxt->dict; + } + } else { + reader->ctxt->dict = reader->dict; + } + } else { + if (reader->ctxt->dict == NULL) + reader->ctxt->dict = xmlDictCreate(); + reader->dict = reader->ctxt->dict; + } + reader->ctxt->_private = reader; + reader->ctxt->linenumbers = 1; + reader->ctxt->dictNames = 1; + /* + * use the parser dictionnary to allocate all elements and attributes names + */ + reader->ctxt->docdict = 1; + reader->ctxt->parseMode = XML_PARSE_READER; + +#ifdef LIBXML_XINCLUDE_ENABLED + if (reader->xincctxt != NULL) { + xmlXIncludeFreeContext(reader->xincctxt); + reader->xincctxt = NULL; + } + if (options & XML_PARSE_XINCLUDE) { + reader->xinclude = 1; + reader->xinclude_name = xmlDictLookup(reader->dict, XINCLUDE_NODE, -1); + options -= XML_PARSE_XINCLUDE; + } else + reader->xinclude = 0; + reader->in_xinclude = 0; +#endif +#ifdef LIBXML_PATTERN_ENABLED + if (reader->patternTab == NULL) { + reader->patternNr = 0; + reader->patternMax = 0; + } + while (reader->patternNr > 0) { + reader->patternNr--; + if (reader->patternTab[reader->patternNr] != NULL) { + xmlFreePattern(reader->patternTab[reader->patternNr]); + reader->patternTab[reader->patternNr] = NULL; + } + } +#endif + + if (options & XML_PARSE_DTDVALID) + 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 ((URL != NULL) && (reader->ctxt->input != NULL) && + (reader->ctxt->input->filename == NULL)) + reader->ctxt->input->filename = (char *) + xmlStrdup((const xmlChar *) URL); + + reader->doc = NULL; + + return (0); +} + +/** + * xmlTextReaderByteConsumed: + * @reader: an XML reader + * + * This function provides the current index of the parser used + * by the reader, relative to the start of the current entity. + * This function actually just wraps a call to xmlBytesConsumed() + * for the parser context associated with the reader. + * See xmlBytesConsumed() for more information. + * + * Returns the index in bytes from the beginning of the entity or -1 + * in case the index could not be computed. + */ +long +xmlTextReaderByteConsumed(xmlTextReaderPtr reader) { + if ((reader == NULL) || (reader->ctxt == NULL)) + return(-1); + return(xmlByteConsumed(reader->ctxt)); +} + + +/** + * xmlReaderWalker: + * @doc: a preparsed document + * + * Create an xmltextReader for a preparsed document. + * + * Returns the new reader or NULL in case of error. + */ +xmlTextReaderPtr +xmlReaderWalker(xmlDocPtr doc) +{ + xmlTextReaderPtr ret; + + if (doc == NULL) + return(NULL); + + ret = xmlMalloc(sizeof(xmlTextReader)); + if (ret == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlNewTextReader : malloc failed\n"); + return(NULL); + } + memset(ret, 0, sizeof(xmlTextReader)); + ret->entNr = 0; + ret->input = NULL; + ret->mode = XML_TEXTREADER_MODE_INITIAL; + ret->node = NULL; + ret->curnode = NULL; + ret->base = 0; + ret->cur = 0; + ret->allocs = XML_TEXTREADER_CTXT; + ret->doc = doc; + ret->state = XML_TEXTREADER_START; + ret->dict = xmlDictCreate(); + return(ret); +} + +/** + * xmlReaderForDoc: + * @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 xmlParserOption + * + * Create an xmltextReader for an XML in-memory document. + * The parsing flags @options are a combination of xmlParserOption. + * + * Returns the new reader or NULL in case of error. + */ +xmlTextReaderPtr +xmlReaderForDoc(const xmlChar * cur, const char *URL, const char *encoding, + int options) +{ + int len; + + if (cur == NULL) + return (NULL); + len = xmlStrlen(cur); + + return (xmlReaderForMemory + ((const char *) cur, len, URL, encoding, options)); +} + +/** + * xmlReaderForFile: + * @filename: a file or URL + * @encoding: the document encoding, or NULL + * @options: a combination of xmlParserOption + * + * parse an XML file from the filesystem or the network. + * The parsing flags @options are a combination of xmlParserOption. + * + * Returns the new reader or NULL in case of error. + */ +xmlTextReaderPtr +xmlReaderForFile(const char *filename, const char *encoding, int options) +{ + xmlTextReaderPtr reader; + + reader = xmlNewTextReaderFilename(filename); + if (reader == NULL) + return (NULL); + xmlTextReaderSetup(reader, NULL, NULL, encoding, options); + return (reader); +} + +/** + * xmlReaderForMemory: + * @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 xmlParserOption + * + * Create an xmltextReader for an XML in-memory document. + * The parsing flags @options are a combination of xmlParserOption. + * + * Returns the new reader or NULL in case of error. + */ +xmlTextReaderPtr +xmlReaderForMemory(const char *buffer, int size, const char *URL, + const char *encoding, int options) +{ + xmlTextReaderPtr reader; + xmlParserInputBufferPtr buf; + + buf = xmlParserInputBufferCreateStatic(buffer, size, + XML_CHAR_ENCODING_NONE); + if (buf == NULL) { + return (NULL); + } + reader = xmlNewTextReader(buf, URL); + if (reader == NULL) { + xmlFreeParserInputBuffer(buf); + return (NULL); + } + reader->allocs |= XML_TEXTREADER_INPUT; + xmlTextReaderSetup(reader, NULL, URL, encoding, options); + return (reader); +} + +/** + * xmlReaderForFd: + * @fd: an open file descriptor + * @URL: the base URL to use for the document + * @encoding: the document encoding, or NULL + * @options: a combination of xmlParserOption + * + * Create an xmltextReader for an XML from a file descriptor. + * The parsing flags @options are a combination of xmlParserOption. + * NOTE that the file descriptor will not be closed when the + * reader is closed or reset. + * + * Returns the new reader or NULL in case of error. + */ +xmlTextReaderPtr +xmlReaderForFd(int fd, const char *URL, const char *encoding, int options) +{ + xmlTextReaderPtr reader; + xmlParserInputBufferPtr input; + + if (fd < 0) + return (NULL); + + input = xmlParserInputBufferCreateFd(fd, XML_CHAR_ENCODING_NONE); + if (input == NULL) + return (NULL); + input->closecallback = NULL; + reader = xmlNewTextReader(input, URL); + if (reader == NULL) { + xmlFreeParserInputBuffer(input); + return (NULL); + } + reader->allocs |= XML_TEXTREADER_INPUT; + xmlTextReaderSetup(reader, NULL, URL, encoding, options); + return (reader); +} + +/** + * xmlReaderForIO: + * @ioread: an I/O read function + * @ioclose: an I/O close function + * @ioctx: an I/O handler + * @URL: the base URL to use for the document + * @encoding: the document encoding, or NULL + * @options: a combination of xmlParserOption + * + * Create an xmltextReader for an XML document from I/O functions and source. + * The parsing flags @options are a combination of xmlParserOption. + * + * Returns the new reader or NULL in case of error. + */ +xmlTextReaderPtr +xmlReaderForIO(xmlInputReadCallback ioread, xmlInputCloseCallback ioclose, + void *ioctx, const char *URL, const char *encoding, + int options) +{ + xmlTextReaderPtr reader; + xmlParserInputBufferPtr input; + + if (ioread == NULL) + return (NULL); + + input = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx, + XML_CHAR_ENCODING_NONE); + if (input == NULL) + return (NULL); + reader = xmlNewTextReader(input, URL); + if (reader == NULL) { + xmlFreeParserInputBuffer(input); + return (NULL); + } + reader->allocs |= XML_TEXTREADER_INPUT; + xmlTextReaderSetup(reader, NULL, URL, encoding, options); + return (reader); +} + +/** + * xmlReaderNewWalker: + * @reader: an XML reader + * @doc: a preparsed document + * + * Setup an xmltextReader to parse a preparsed XML document. + * This reuses the existing @reader xmlTextReader. + * + * Returns 0 in case of success and -1 in case of error + */ +int +xmlReaderNewWalker(xmlTextReaderPtr reader, xmlDocPtr doc) +{ + if (doc == NULL) + return (-1); + if (reader == NULL) + return (-1); + + if (reader->input != NULL) { + xmlFreeParserInputBuffer(reader->input); + } + if (reader->ctxt != NULL) { + xmlCtxtReset(reader->ctxt); + } + + reader->entNr = 0; + reader->input = NULL; + reader->mode = XML_TEXTREADER_MODE_INITIAL; + reader->node = NULL; + reader->curnode = NULL; + reader->base = 0; + reader->cur = 0; + reader->allocs = XML_TEXTREADER_CTXT; + reader->doc = doc; + reader->state = XML_TEXTREADER_START; + if (reader->dict == NULL) { + if ((reader->ctxt != NULL) && (reader->ctxt->dict != NULL)) + reader->dict = reader->ctxt->dict; + else + reader->dict = xmlDictCreate(); + } + return(0); +} + +/** + * xmlReaderNewDoc: + * @reader: an XML reader + * @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 xmlParserOption + * + * Setup an xmltextReader to parse an XML in-memory document. + * The parsing flags @options are a combination of xmlParserOption. + * This reuses the existing @reader xmlTextReader. + * + * Returns 0 in case of success and -1 in case of error + */ +int +xmlReaderNewDoc(xmlTextReaderPtr reader, const xmlChar * cur, + const char *URL, const char *encoding, int options) +{ + + int len; + + if (cur == NULL) + return (-1); + if (reader == NULL) + return (-1); + + len = xmlStrlen(cur); + return (xmlReaderNewMemory(reader, (const char *)cur, len, + URL, encoding, options)); +} + +/** + * xmlReaderNewFile: + * @reader: an XML reader + * @filename: a file or URL + * @encoding: the document encoding, or NULL + * @options: a combination of xmlParserOption + * + * parse an XML file from the filesystem or the network. + * The parsing flags @options are a combination of xmlParserOption. + * This reuses the existing @reader xmlTextReader. + * + * Returns 0 in case of success and -1 in case of error + */ +int +xmlReaderNewFile(xmlTextReaderPtr reader, const char *filename, + const char *encoding, int options) +{ + xmlParserInputBufferPtr input; + + if (filename == NULL) + return (-1); + if (reader == NULL) + return (-1); + + input = + xmlParserInputBufferCreateFilename(filename, + XML_CHAR_ENCODING_NONE); + if (input == NULL) + return (-1); + return (xmlTextReaderSetup(reader, input, filename, encoding, options)); +} + +/** + * xmlReaderNewMemory: + * @reader: an XML reader + * @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 xmlParserOption + * + * Setup an xmltextReader to parse an XML in-memory document. + * The parsing flags @options are a combination of xmlParserOption. + * This reuses the existing @reader xmlTextReader. + * + * Returns 0 in case of success and -1 in case of error + */ +int +xmlReaderNewMemory(xmlTextReaderPtr reader, const char *buffer, int size, + const char *URL, const char *encoding, int options) +{ + xmlParserInputBufferPtr input; + + if (reader == NULL) + return (-1); + if (buffer == NULL) + return (-1); + + input = xmlParserInputBufferCreateStatic(buffer, size, + XML_CHAR_ENCODING_NONE); + if (input == NULL) { + return (-1); + } + return (xmlTextReaderSetup(reader, input, URL, encoding, options)); +} + +/** + * xmlReaderNewFd: + * @reader: an XML reader + * @fd: an open file descriptor + * @URL: the base URL to use for the document + * @encoding: the document encoding, or NULL + * @options: a combination of xmlParserOption + * + * Setup an xmltextReader to parse an XML from a file descriptor. + * NOTE that the file descriptor will not be closed when the + * reader is closed or reset. + * The parsing flags @options are a combination of xmlParserOption. + * This reuses the existing @reader xmlTextReader. + * + * Returns 0 in case of success and -1 in case of error + */ +int +xmlReaderNewFd(xmlTextReaderPtr reader, int fd, + const char *URL, const char *encoding, int options) +{ + xmlParserInputBufferPtr input; + + if (fd < 0) + return (-1); + if (reader == NULL) + return (-1); + + input = xmlParserInputBufferCreateFd(fd, XML_CHAR_ENCODING_NONE); + if (input == NULL) + return (-1); + input->closecallback = NULL; + return (xmlTextReaderSetup(reader, input, URL, encoding, options)); +} + +/** + * xmlReaderNewIO: + * @reader: an XML reader + * @ioread: an I/O read function + * @ioclose: an I/O close function + * @ioctx: an I/O handler + * @URL: the base URL to use for the document + * @encoding: the document encoding, or NULL + * @options: a combination of xmlParserOption + * + * Setup an xmltextReader to parse an XML document from I/O functions + * and source. + * The parsing flags @options are a combination of xmlParserOption. + * This reuses the existing @reader xmlTextReader. + * + * Returns 0 in case of success and -1 in case of error + */ +int +xmlReaderNewIO(xmlTextReaderPtr reader, xmlInputReadCallback ioread, + xmlInputCloseCallback ioclose, void *ioctx, + const char *URL, const char *encoding, int options) +{ + xmlParserInputBufferPtr input; + + if (ioread == NULL) + return (-1); + if (reader == NULL) + return (-1); + + input = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx, + XML_CHAR_ENCODING_NONE); + if (input == NULL) + return (-1); + return (xmlTextReaderSetup(reader, input, URL, encoding, options)); +} +/************************************************************************ + * * + * Utilities * + * * + ************************************************************************/ +#ifdef NOT_USED_YET + +/** + * xmlBase64Decode: + * @in: the input buffer + * @inlen: the size of the input (in), the size read from it (out) + * @to: the output buffer + * @tolen: the size of the output (in), the size written to (out) + * + * Base64 decoder, reads from @in and save in @to + * TODO: tell jody when this is actually exported + * + * Returns 0 if all the input was consumer, 1 if the Base64 end was reached, + * 2 if there wasn't enough space on the output or -1 in case of error. + */ +static int +xmlBase64Decode(const unsigned char *in, unsigned long *inlen, + unsigned char *to, unsigned long *tolen) +{ + unsigned long incur; /* current index in in[] */ + + unsigned long inblk; /* last block index in in[] */ + + unsigned long outcur; /* current index in out[] */ + + unsigned long inmax; /* size of in[] */ + + unsigned long outmax; /* size of out[] */ + + unsigned char cur; /* the current value read from in[] */ + + unsigned char intmp[4], outtmp[4]; /* temporary buffers for the convert */ + + int nbintmp; /* number of byte in intmp[] */ + + int is_ignore; /* cur should be ignored */ + + int is_end = 0; /* the end of the base64 was found */ + + int retval = 1; + + int i; + + if ((in == NULL) || (inlen == NULL) || (to == NULL) || (tolen == NULL)) + return (-1); + + incur = 0; + inblk = 0; + outcur = 0; + inmax = *inlen; + outmax = *tolen; + nbintmp = 0; + + while (1) { + if (incur >= inmax) + break; + cur = in[incur++]; + is_ignore = 0; + if ((cur >= 'A') && (cur <= 'Z')) + cur = cur - 'A'; + else if ((cur >= 'a') && (cur <= 'z')) + cur = cur - 'a' + 26; + else if ((cur >= '0') && (cur <= '9')) + cur = cur - '0' + 52; + else if (cur == '+') + cur = 62; + else if (cur == '/') + cur = 63; + else if (cur == '.') + cur = 0; + else if (cur == '=') /*no op , end of the base64 stream */ + is_end = 1; + else { + is_ignore = 1; + if (nbintmp == 0) + inblk = incur; + } + + if (!is_ignore) { + int nbouttmp = 3; + + int is_break = 0; + + if (is_end) { + if (nbintmp == 0) + break; + if ((nbintmp == 1) || (nbintmp == 2)) + nbouttmp = 1; + else + nbouttmp = 2; + nbintmp = 3; + is_break = 1; + } + intmp[nbintmp++] = cur; + /* + * if intmp is full, push the 4byte sequence as a 3 byte + * sequence out + */ + if (nbintmp == 4) { + nbintmp = 0; + outtmp[0] = (intmp[0] << 2) | ((intmp[1] & 0x30) >> 4); + outtmp[1] = + ((intmp[1] & 0x0F) << 4) | ((intmp[2] & 0x3C) >> 2); + outtmp[2] = ((intmp[2] & 0x03) << 6) | (intmp[3] & 0x3F); + if (outcur + 3 >= outmax) { + retval = 2; + break; + } + + for (i = 0; i < nbouttmp; i++) + to[outcur++] = outtmp[i]; + inblk = incur; + } + + if (is_break) { + retval = 0; + break; + } + } + } + + *tolen = outcur; + *inlen = inblk; + return (retval); +} + +/* + * Test routine for the xmlBase64Decode function + */ +#if 0 +int +main(int argc, char **argv) +{ + char *input = " VW4 gcGV0 \n aXQgdGVzdCAuCg== "; + + char output[100]; + + char output2[100]; + + char output3[100]; + + unsigned long inlen = strlen(input); + + unsigned long outlen = 100; + + int ret; + + unsigned long cons, tmp, tmp2, prod; + + /* + * Direct + */ + ret = xmlBase64Decode(input, &inlen, output, &outlen); + + output[outlen] = 0; + printf("ret: %d, inlen: %ld , outlen: %ld, output: '%s'\n", ret, inlen, + outlen, output)indent: Standard input:179: Error:Unmatched #endif +; + + /* + * output chunking + */ + cons = 0; + prod = 0; + while (cons < inlen) { + tmp = 5; + tmp2 = inlen - cons; + + printf("%ld %ld\n", cons, prod); + ret = xmlBase64Decode(&input[cons], &tmp2, &output2[prod], &tmp); + cons += tmp2; + prod += tmp; + printf("%ld %ld\n", cons, prod); + } + output2[outlen] = 0; + printf("ret: %d, cons: %ld , prod: %ld, output: '%s'\n", ret, cons, + prod, output2); + + /* + * input chunking + */ + cons = 0; + prod = 0; + while (cons < inlen) { + tmp = 100 - prod; + tmp2 = inlen - cons; + if (tmp2 > 5) + tmp2 = 5; + + printf("%ld %ld\n", cons, prod); + ret = xmlBase64Decode(&input[cons], &tmp2, &output3[prod], &tmp); + cons += tmp2; + prod += tmp; + printf("%ld %ld\n", cons, prod); + } + output3[outlen] = 0; + printf("ret: %d, cons: %ld , prod: %ld, output: '%s'\n", ret, cons, + prod, output3); + return (0); + +} +#endif +#endif /* NOT_USED_YET */ +#define bottom_xmlreader +#include "elfgcchack.h" +#endif /* LIBXML_READER_ENABLED */ diff --git a/android/native/libxml2/xmlregexp.c b/android/native/libxml2/xmlregexp.c new file mode 100644 index 0000000000..aaff33e78b --- /dev/null +++ b/android/native/libxml2/xmlregexp.c @@ -0,0 +1,8153 @@ +/* + * regexp.c: generic and extensible Regular Expression engine + * + * Basically designed with the purpose of compiling regexps for + * the variety of validation/shemas mechanisms now available in + * XML related specifications these include: + * - XML-1.0 DTD validation + * - XML Schemas structure part 1 + * - XML Schemas Datatypes part 2 especially Appendix F + * - RELAX-NG/TREX i.e. the counter proposal + * + * See Copyright for the status of this software. + * + * Daniel Veillard + */ + +#define IN_LIBXML +#include "libxml.h" + +#ifdef LIBXML_REGEXP_ENABLED + +/* #define DEBUG_ERR */ + +#include +#include +#ifdef HAVE_LIMITS_H +#include +#endif + +#include +#include +#include +#include +#include + +#ifndef INT_MAX +#define INT_MAX 123456789 /* easy to flag and big enough for our needs */ +#endif + +/* #define DEBUG_REGEXP_GRAPH */ +/* #define DEBUG_REGEXP_EXEC */ +/* #define DEBUG_PUSH */ +/* #define DEBUG_COMPACTION */ + +#define MAX_PUSH 10000000 + +#define ERROR(str) \ + ctxt->error = XML_REGEXP_COMPILE_ERROR; \ + xmlRegexpErrCompile(ctxt, str); +#define NEXT ctxt->cur++ +#define CUR (*(ctxt->cur)) +#define NXT(index) (ctxt->cur[index]) + +#define CUR_SCHAR(s, l) xmlStringCurrentChar(NULL, s, &l) +#define NEXTL(l) ctxt->cur += l; +#define XML_REG_STRING_SEPARATOR '|' +/* + * Need PREV to check on a '-' within a Character Group. May only be used + * when it's guaranteed that cur is not at the beginning of ctxt->string! + */ +#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 * + * * + ************************************************************************/ + +/* + * Note: the order of the enums below is significant, do not shuffle + */ +typedef enum { + XML_REGEXP_EPSILON = 1, + XML_REGEXP_CHARVAL, + XML_REGEXP_RANGES, + XML_REGEXP_SUBREG, /* used for () sub regexps */ + XML_REGEXP_STRING, + XML_REGEXP_ANYCHAR, /* . */ + XML_REGEXP_ANYSPACE, /* \s */ + XML_REGEXP_NOTSPACE, /* \S */ + XML_REGEXP_INITNAME, /* \l */ + XML_REGEXP_NOTINITNAME, /* \L */ + XML_REGEXP_NAMECHAR, /* \c */ + XML_REGEXP_NOTNAMECHAR, /* \C */ + XML_REGEXP_DECIMAL, /* \d */ + XML_REGEXP_NOTDECIMAL, /* \D */ + XML_REGEXP_REALCHAR, /* \w */ + XML_REGEXP_NOTREALCHAR, /* \W */ + XML_REGEXP_LETTER = 100, + XML_REGEXP_LETTER_UPPERCASE, + XML_REGEXP_LETTER_LOWERCASE, + XML_REGEXP_LETTER_TITLECASE, + XML_REGEXP_LETTER_MODIFIER, + XML_REGEXP_LETTER_OTHERS, + XML_REGEXP_MARK, + XML_REGEXP_MARK_NONSPACING, + XML_REGEXP_MARK_SPACECOMBINING, + XML_REGEXP_MARK_ENCLOSING, + XML_REGEXP_NUMBER, + XML_REGEXP_NUMBER_DECIMAL, + XML_REGEXP_NUMBER_LETTER, + XML_REGEXP_NUMBER_OTHERS, + XML_REGEXP_PUNCT, + XML_REGEXP_PUNCT_CONNECTOR, + XML_REGEXP_PUNCT_DASH, + XML_REGEXP_PUNCT_OPEN, + XML_REGEXP_PUNCT_CLOSE, + XML_REGEXP_PUNCT_INITQUOTE, + XML_REGEXP_PUNCT_FINQUOTE, + XML_REGEXP_PUNCT_OTHERS, + XML_REGEXP_SEPAR, + XML_REGEXP_SEPAR_SPACE, + XML_REGEXP_SEPAR_LINE, + XML_REGEXP_SEPAR_PARA, + XML_REGEXP_SYMBOL, + XML_REGEXP_SYMBOL_MATH, + XML_REGEXP_SYMBOL_CURRENCY, + XML_REGEXP_SYMBOL_MODIFIER, + XML_REGEXP_SYMBOL_OTHERS, + XML_REGEXP_OTHER, + XML_REGEXP_OTHER_CONTROL, + XML_REGEXP_OTHER_FORMAT, + XML_REGEXP_OTHER_PRIVATE, + XML_REGEXP_OTHER_NA, + XML_REGEXP_BLOCK_NAME +} xmlRegAtomType; + +typedef enum { + XML_REGEXP_QUANT_EPSILON = 1, + XML_REGEXP_QUANT_ONCE, + XML_REGEXP_QUANT_OPT, + XML_REGEXP_QUANT_MULT, + XML_REGEXP_QUANT_PLUS, + XML_REGEXP_QUANT_ONCEONLY, + XML_REGEXP_QUANT_ALL, + XML_REGEXP_QUANT_RANGE +} xmlRegQuantType; + +typedef enum { + XML_REGEXP_START_STATE = 1, + XML_REGEXP_FINAL_STATE, + XML_REGEXP_TRANS_STATE, + XML_REGEXP_SINK_STATE, + XML_REGEXP_UNREACH_STATE +} xmlRegStateType; + +typedef enum { + XML_REGEXP_MARK_NORMAL = 0, + XML_REGEXP_MARK_START, + XML_REGEXP_MARK_VISITED +} xmlRegMarkedType; + +typedef struct _xmlRegRange xmlRegRange; +typedef xmlRegRange *xmlRegRangePtr; + +struct _xmlRegRange { + int neg; /* 0 normal, 1 not, 2 exclude */ + xmlRegAtomType type; + int start; + int end; + xmlChar *blockName; +}; + +typedef struct _xmlRegAtom xmlRegAtom; +typedef xmlRegAtom *xmlRegAtomPtr; + +typedef struct _xmlAutomataState xmlRegState; +typedef xmlRegState *xmlRegStatePtr; + +struct _xmlRegAtom { + int no; + xmlRegAtomType type; + xmlRegQuantType quant; + int min; + int max; + + void *valuep; + void *valuep2; + int neg; + int codepoint; + xmlRegStatePtr start; + xmlRegStatePtr start0; + xmlRegStatePtr stop; + int maxRanges; + int nbRanges; + xmlRegRangePtr *ranges; + void *data; +}; + +typedef struct _xmlRegCounter xmlRegCounter; +typedef xmlRegCounter *xmlRegCounterPtr; + +struct _xmlRegCounter { + int min; + int max; +}; + +typedef struct _xmlRegTrans xmlRegTrans; +typedef xmlRegTrans *xmlRegTransPtr; + +struct _xmlRegTrans { + xmlRegAtomPtr atom; + int to; + int counter; + int count; + int nd; +}; + +struct _xmlAutomataState { + xmlRegStateType type; + xmlRegMarkedType mark; + xmlRegMarkedType reached; + int no; + int maxTrans; + int nbTrans; + xmlRegTrans *trans; + /* knowing states ponting to us can speed things up */ + int maxTransTo; + int nbTransTo; + int *transTo; +}; + +typedef struct _xmlAutomata xmlRegParserCtxt; +typedef xmlRegParserCtxt *xmlRegParserCtxtPtr; + +#define AM_AUTOMATA_RNG 1 + +struct _xmlAutomata { + xmlChar *string; + xmlChar *cur; + + int error; + int neg; + + xmlRegStatePtr start; + xmlRegStatePtr end; + xmlRegStatePtr state; + + xmlRegAtomPtr atom; + + int maxAtoms; + int nbAtoms; + xmlRegAtomPtr *atoms; + + int maxStates; + int nbStates; + xmlRegStatePtr *states; + + int maxCounters; + int nbCounters; + xmlRegCounter *counters; + + int determinist; + int negs; + int flags; +}; + +struct _xmlRegexp { + xmlChar *string; + int nbStates; + xmlRegStatePtr *states; + int nbAtoms; + xmlRegAtomPtr *atoms; + int nbCounters; + xmlRegCounter *counters; + int determinist; + int flags; + /* + * That's the compact form for determinists automatas + */ + int nbstates; + int *compact; + void **transdata; + int nbstrings; + xmlChar **stringMap; +}; + +typedef struct _xmlRegExecRollback xmlRegExecRollback; +typedef xmlRegExecRollback *xmlRegExecRollbackPtr; + +struct _xmlRegExecRollback { + xmlRegStatePtr state;/* the current state */ + int index; /* the index in the input stack */ + int nextbranch; /* the next transition to explore in that state */ + int *counts; /* save the automata state if it has some */ +}; + +typedef struct _xmlRegInputToken xmlRegInputToken; +typedef xmlRegInputToken *xmlRegInputTokenPtr; + +struct _xmlRegInputToken { + xmlChar *value; + void *data; +}; + +struct _xmlRegExecCtxt { + int status; /* execution status != 0 indicate an error */ + int determinist; /* did we find an indeterministic behaviour */ + xmlRegexpPtr comp; /* the compiled regexp */ + xmlRegExecCallbacks callback; + void *data; + + xmlRegStatePtr state;/* the current state */ + int transno; /* the current transition on that state */ + int transcount; /* the number of chars in char counted transitions */ + + /* + * A stack of rollback states + */ + int maxRollbacks; + int nbRollbacks; + xmlRegExecRollback *rollbacks; + + /* + * The state of the automata if any + */ + int *counts; + + /* + * The input stack + */ + int inputStackMax; + int inputStackNr; + int index; + int *charStack; + const xmlChar *inputString; /* when operating on characters */ + xmlRegInputTokenPtr inputStack;/* when operating on strings */ + + /* + * error handling + */ + int errStateNo; /* the error state number */ + xmlRegStatePtr errState; /* the error state */ + xmlChar *errString; /* the string raising the error */ + int *errCounts; /* counters at the error state */ + int nbPush; +}; + +#define REGEXP_ALL_COUNTER 0x123456 +#define REGEXP_ALL_LAX_COUNTER 0x123457 + +static void xmlFAParseRegExp(xmlRegParserCtxtPtr ctxt, int top); +static void xmlRegFreeState(xmlRegStatePtr state); +static void xmlRegFreeAtom(xmlRegAtomPtr atom); +static int xmlRegStrEqualWildcard(const xmlChar *expStr, const xmlChar *valStr); +static int xmlRegCheckCharacter(xmlRegAtomPtr atom, int codepoint); +static int xmlRegCheckCharacterRange(xmlRegAtomType type, int codepoint, + int neg, int start, int end, const xmlChar *blockName); + +void xmlAutomataSetFlags(xmlAutomataPtr am, int flags); + +/************************************************************************ + * * + * Regexp memory error handler * + * * + ************************************************************************/ +/** + * xmlRegexpErrMemory: + * @extra: extra information + * + * Handle an out of memory condition + */ +static void +xmlRegexpErrMemory(xmlRegParserCtxtPtr ctxt, const char *extra) +{ + 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); +} + +/** + * xmlRegexpErrCompile: + * @extra: extra information + * + * Handle a compilation failure + */ +static void +xmlRegexpErrCompile(xmlRegParserCtxtPtr ctxt, const char *extra) +{ + const char *regexp = NULL; + int idx = 0; + + 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); +} + +/************************************************************************ + * * + * Allocation/Deallocation * + * * + ************************************************************************/ + +static int xmlFAComputesDeterminism(xmlRegParserCtxtPtr ctxt); +/** + * xmlRegEpxFromParse: + * @ctxt: the parser context used to build it + * + * Allocate a new regexp and fill it with the result from the parser + * + * Returns the new regexp or NULL in case of error + */ +static xmlRegexpPtr +xmlRegEpxFromParse(xmlRegParserCtxtPtr ctxt) { + xmlRegexpPtr ret; + + ret = (xmlRegexpPtr) xmlMalloc(sizeof(xmlRegexp)); + if (ret == NULL) { + xmlRegexpErrMemory(ctxt, "compiling regexp"); + return(NULL); + } + memset(ret, 0, sizeof(xmlRegexp)); + ret->string = ctxt->string; + ret->nbStates = ctxt->nbStates; + ret->states = ctxt->states; + ret->nbAtoms = ctxt->nbAtoms; + ret->atoms = ctxt->atoms; + ret->nbCounters = ctxt->nbCounters; + ret->counters = ctxt->counters; + ret->determinist = ctxt->determinist; + ret->flags = ctxt->flags; + if (ret->determinist == -1) { + xmlRegexpIsDeterminist(ret); + } + + if ((ret->determinist != 0) && + (ret->nbCounters == 0) && + (ctxt->negs == 0) && + (ret->atoms != NULL) && + (ret->atoms[0] != NULL) && + (ret->atoms[0]->type == XML_REGEXP_STRING)) { + int i, j, nbstates = 0, nbatoms = 0; + int *stateRemap; + int *stringRemap; + int *transitions; + void **transdata; + xmlChar **stringMap; + xmlChar *value; + + /* + * Switch to a compact representation + * 1/ counting the effective number of states left + * 2/ counting the unique number of atoms, and check that + * they are all of the string type + * 3/ build a table state x atom for the transitions + */ + + stateRemap = xmlMalloc(ret->nbStates * sizeof(int)); + if (stateRemap == NULL) { + xmlRegexpErrMemory(ctxt, "compiling regexp"); + xmlFree(ret); + return(NULL); + } + for (i = 0;i < ret->nbStates;i++) { + if (ret->states[i] != NULL) { + stateRemap[i] = nbstates; + nbstates++; + } else { + stateRemap[i] = -1; + } + } +#ifdef DEBUG_COMPACTION + printf("Final: %d states\n", nbstates); +#endif + stringMap = xmlMalloc(ret->nbAtoms * sizeof(char *)); + if (stringMap == NULL) { + xmlRegexpErrMemory(ctxt, "compiling regexp"); + xmlFree(stateRemap); + xmlFree(ret); + return(NULL); + } + stringRemap = xmlMalloc(ret->nbAtoms * sizeof(int)); + if (stringRemap == NULL) { + xmlRegexpErrMemory(ctxt, "compiling regexp"); + xmlFree(stringMap); + xmlFree(stateRemap); + xmlFree(ret); + return(NULL); + } + for (i = 0;i < ret->nbAtoms;i++) { + if ((ret->atoms[i]->type == XML_REGEXP_STRING) && + (ret->atoms[i]->quant == XML_REGEXP_QUANT_ONCE)) { + value = ret->atoms[i]->valuep; + for (j = 0;j < nbatoms;j++) { + if (xmlStrEqual(stringMap[j], value)) { + stringRemap[i] = j; + break; + } + } + if (j >= nbatoms) { + stringRemap[i] = nbatoms; + stringMap[nbatoms] = xmlStrdup(value); + if (stringMap[nbatoms] == NULL) { + for (i = 0;i < nbatoms;i++) + xmlFree(stringMap[i]); + xmlFree(stringRemap); + xmlFree(stringMap); + xmlFree(stateRemap); + xmlFree(ret); + return(NULL); + } + nbatoms++; + } + } else { + xmlFree(stateRemap); + xmlFree(stringRemap); + for (i = 0;i < nbatoms;i++) + xmlFree(stringMap[i]); + xmlFree(stringMap); + xmlFree(ret); + return(NULL); + } + } +#ifdef DEBUG_COMPACTION + printf("Final: %d atoms\n", nbatoms); +#endif + transitions = (int *) xmlMalloc((nbstates + 1) * + (nbatoms + 1) * sizeof(int)); + if (transitions == NULL) { + xmlFree(stateRemap); + xmlFree(stringRemap); + xmlFree(stringMap); + xmlFree(ret); + return(NULL); + } + memset(transitions, 0, (nbstates + 1) * (nbatoms + 1) * sizeof(int)); + + /* + * Allocate the transition table. The first entry for each + * state corresponds to the state type. + */ + transdata = NULL; + + for (i = 0;i < ret->nbStates;i++) { + int stateno, atomno, targetno, prev; + xmlRegStatePtr state; + xmlRegTransPtr trans; + + stateno = stateRemap[i]; + if (stateno == -1) + continue; + state = ret->states[i]; + + transitions[stateno * (nbatoms + 1)] = state->type; + + for (j = 0;j < state->nbTrans;j++) { + trans = &(state->trans[j]); + if ((trans->to == -1) || (trans->atom == NULL)) + continue; + atomno = stringRemap[trans->atom->no]; + if ((trans->atom->data != NULL) && (transdata == NULL)) { + transdata = (void **) xmlMalloc(nbstates * nbatoms * + sizeof(void *)); + if (transdata != NULL) + memset(transdata, 0, + nbstates * nbatoms * sizeof(void *)); + else { + xmlRegexpErrMemory(ctxt, "compiling regexp"); + break; + } + } + targetno = stateRemap[trans->to]; + /* + * if the same atom can generate transitions to 2 different + * states then it means the automata is not determinist and + * the compact form can't be used ! + */ + prev = transitions[stateno * (nbatoms + 1) + atomno + 1]; + if (prev != 0) { + if (prev != targetno + 1) { + ret->determinist = 0; +#ifdef DEBUG_COMPACTION + printf("Indet: state %d trans %d, atom %d to %d : %d to %d\n", + i, j, trans->atom->no, trans->to, atomno, targetno); + printf(" previous to is %d\n", prev); +#endif + if (transdata != NULL) + xmlFree(transdata); + xmlFree(transitions); + xmlFree(stateRemap); + xmlFree(stringRemap); + for (i = 0;i < nbatoms;i++) + xmlFree(stringMap[i]); + xmlFree(stringMap); + goto not_determ; + } + } else { +#if 0 + printf("State %d trans %d: atom %d to %d : %d to %d\n", + i, j, trans->atom->no, trans->to, atomno, targetno); +#endif + transitions[stateno * (nbatoms + 1) + atomno + 1] = + targetno + 1; /* to avoid 0 */ + if (transdata != NULL) + transdata[stateno * nbatoms + atomno] = + trans->atom->data; + } + } + } + ret->determinist = 1; +#ifdef DEBUG_COMPACTION + /* + * Debug + */ + for (i = 0;i < nbstates;i++) { + for (j = 0;j < nbatoms + 1;j++) { + printf("%02d ", transitions[i * (nbatoms + 1) + j]); + } + printf("\n"); + } + printf("\n"); +#endif + /* + * Cleanup of the old data + */ + if (ret->states != NULL) { + for (i = 0;i < ret->nbStates;i++) + xmlRegFreeState(ret->states[i]); + xmlFree(ret->states); + } + ret->states = NULL; + ret->nbStates = 0; + if (ret->atoms != NULL) { + for (i = 0;i < ret->nbAtoms;i++) + xmlRegFreeAtom(ret->atoms[i]); + xmlFree(ret->atoms); + } + ret->atoms = NULL; + ret->nbAtoms = 0; + + ret->compact = transitions; + ret->transdata = transdata; + ret->stringMap = stringMap; + ret->nbstrings = nbatoms; + ret->nbstates = nbstates; + xmlFree(stateRemap); + xmlFree(stringRemap); + } +not_determ: + ctxt->string = NULL; + ctxt->nbStates = 0; + ctxt->states = NULL; + ctxt->nbAtoms = 0; + ctxt->atoms = NULL; + ctxt->nbCounters = 0; + ctxt->counters = NULL; + return(ret); +} + +/** + * xmlRegNewParserCtxt: + * @string: the string to parse + * + * Allocate a new regexp parser context + * + * Returns the new context or NULL in case of error + */ +static xmlRegParserCtxtPtr +xmlRegNewParserCtxt(const xmlChar *string) { + xmlRegParserCtxtPtr ret; + + ret = (xmlRegParserCtxtPtr) xmlMalloc(sizeof(xmlRegParserCtxt)); + if (ret == NULL) + return(NULL); + memset(ret, 0, sizeof(xmlRegParserCtxt)); + if (string != NULL) + ret->string = xmlStrdup(string); + ret->cur = ret->string; + ret->neg = 0; + ret->negs = 0; + ret->error = 0; + ret->determinist = -1; + return(ret); +} + +/** + * xmlRegNewRange: + * @ctxt: the regexp parser context + * @neg: is that negative + * @type: the type of range + * @start: the start codepoint + * @end: the end codepoint + * + * Allocate a new regexp range + * + * Returns the new range or NULL in case of error + */ +static xmlRegRangePtr +xmlRegNewRange(xmlRegParserCtxtPtr ctxt, + int neg, xmlRegAtomType type, int start, int end) { + xmlRegRangePtr ret; + + ret = (xmlRegRangePtr) xmlMalloc(sizeof(xmlRegRange)); + if (ret == NULL) { + xmlRegexpErrMemory(ctxt, "allocating range"); + return(NULL); + } + ret->neg = neg; + ret->type = type; + ret->start = start; + ret->end = end; + return(ret); +} + +/** + * xmlRegFreeRange: + * @range: the regexp range + * + * Free a regexp range + */ +static void +xmlRegFreeRange(xmlRegRangePtr range) { + if (range == NULL) + return; + + if (range->blockName != NULL) + xmlFree(range->blockName); + xmlFree(range); +} + +/** + * xmlRegCopyRange: + * @range: the regexp range + * + * Copy a regexp range + * + * Returns the new copy or NULL in case of error. + */ +static xmlRegRangePtr +xmlRegCopyRange(xmlRegParserCtxtPtr ctxt, xmlRegRangePtr range) { + xmlRegRangePtr ret; + + if (range == NULL) + return(NULL); + + ret = xmlRegNewRange(ctxt, range->neg, range->type, range->start, + range->end); + if (ret == NULL) + return(NULL); + if (range->blockName != NULL) { + ret->blockName = xmlStrdup(range->blockName); + if (ret->blockName == NULL) { + xmlRegexpErrMemory(ctxt, "allocating range"); + xmlRegFreeRange(ret); + return(NULL); + } + } + return(ret); +} + +/** + * xmlRegNewAtom: + * @ctxt: the regexp parser context + * @type: the type of atom + * + * Allocate a new atom + * + * Returns the new atom or NULL in case of error + */ +static xmlRegAtomPtr +xmlRegNewAtom(xmlRegParserCtxtPtr ctxt, xmlRegAtomType type) { + xmlRegAtomPtr ret; + + ret = (xmlRegAtomPtr) xmlMalloc(sizeof(xmlRegAtom)); + if (ret == NULL) { + xmlRegexpErrMemory(ctxt, "allocating atom"); + return(NULL); + } + memset(ret, 0, sizeof(xmlRegAtom)); + ret->type = type; + ret->quant = XML_REGEXP_QUANT_ONCE; + ret->min = 0; + ret->max = 0; + return(ret); +} + +/** + * xmlRegFreeAtom: + * @atom: the regexp atom + * + * Free a regexp atom + */ +static void +xmlRegFreeAtom(xmlRegAtomPtr atom) { + int i; + + if (atom == NULL) + return; + + for (i = 0;i < atom->nbRanges;i++) + xmlRegFreeRange(atom->ranges[i]); + if (atom->ranges != NULL) + xmlFree(atom->ranges); + if ((atom->type == XML_REGEXP_STRING) && (atom->valuep != NULL)) + xmlFree(atom->valuep); + if ((atom->type == XML_REGEXP_STRING) && (atom->valuep2 != NULL)) + xmlFree(atom->valuep2); + if ((atom->type == XML_REGEXP_BLOCK_NAME) && (atom->valuep != NULL)) + xmlFree(atom->valuep); + xmlFree(atom); +} + +/** + * xmlRegCopyAtom: + * @ctxt: the regexp parser context + * @atom: the oiginal atom + * + * Allocate a new regexp range + * + * Returns the new atom or NULL in case of error + */ +static xmlRegAtomPtr +xmlRegCopyAtom(xmlRegParserCtxtPtr ctxt, xmlRegAtomPtr atom) { + xmlRegAtomPtr ret; + + ret = (xmlRegAtomPtr) xmlMalloc(sizeof(xmlRegAtom)); + if (ret == NULL) { + xmlRegexpErrMemory(ctxt, "copying atom"); + return(NULL); + } + memset(ret, 0, sizeof(xmlRegAtom)); + ret->type = atom->type; + ret->quant = atom->quant; + ret->min = atom->min; + ret->max = atom->max; + if (atom->nbRanges > 0) { + int i; + + ret->ranges = (xmlRegRangePtr *) xmlMalloc(sizeof(xmlRegRangePtr) * + atom->nbRanges); + if (ret->ranges == NULL) { + xmlRegexpErrMemory(ctxt, "copying atom"); + goto error; + } + for (i = 0;i < atom->nbRanges;i++) { + ret->ranges[i] = xmlRegCopyRange(ctxt, atom->ranges[i]); + if (ret->ranges[i] == NULL) + goto error; + ret->nbRanges = i + 1; + } + } + return(ret); + +error: + xmlRegFreeAtom(ret); + return(NULL); +} + +static xmlRegStatePtr +xmlRegNewState(xmlRegParserCtxtPtr ctxt) { + xmlRegStatePtr ret; + + ret = (xmlRegStatePtr) xmlMalloc(sizeof(xmlRegState)); + if (ret == NULL) { + xmlRegexpErrMemory(ctxt, "allocating state"); + return(NULL); + } + memset(ret, 0, sizeof(xmlRegState)); + ret->type = XML_REGEXP_TRANS_STATE; + ret->mark = XML_REGEXP_MARK_NORMAL; + return(ret); +} + +/** + * xmlRegFreeState: + * @state: the regexp state + * + * Free a regexp state + */ +static void +xmlRegFreeState(xmlRegStatePtr state) { + if (state == NULL) + return; + + if (state->trans != NULL) + xmlFree(state->trans); + if (state->transTo != NULL) + xmlFree(state->transTo); + xmlFree(state); +} + +/** + * xmlRegFreeParserCtxt: + * @ctxt: the regexp parser context + * + * Free a regexp parser context + */ +static void +xmlRegFreeParserCtxt(xmlRegParserCtxtPtr ctxt) { + int i; + if (ctxt == NULL) + return; + + if (ctxt->string != NULL) + xmlFree(ctxt->string); + if (ctxt->states != NULL) { + for (i = 0;i < ctxt->nbStates;i++) + xmlRegFreeState(ctxt->states[i]); + xmlFree(ctxt->states); + } + if (ctxt->atoms != NULL) { + for (i = 0;i < ctxt->nbAtoms;i++) + xmlRegFreeAtom(ctxt->atoms[i]); + xmlFree(ctxt->atoms); + } + if (ctxt->counters != NULL) + xmlFree(ctxt->counters); + xmlFree(ctxt); +} + +/************************************************************************ + * * + * Display of Data structures * + * * + ************************************************************************/ + +static void +xmlRegPrintAtomType(FILE *output, xmlRegAtomType type) { + switch (type) { + case XML_REGEXP_EPSILON: + fprintf(output, "epsilon "); break; + case XML_REGEXP_CHARVAL: + fprintf(output, "charval "); break; + case XML_REGEXP_RANGES: + fprintf(output, "ranges "); break; + case XML_REGEXP_SUBREG: + fprintf(output, "subexpr "); break; + case XML_REGEXP_STRING: + fprintf(output, "string "); break; + case XML_REGEXP_ANYCHAR: + fprintf(output, "anychar "); break; + case XML_REGEXP_ANYSPACE: + fprintf(output, "anyspace "); break; + case XML_REGEXP_NOTSPACE: + fprintf(output, "notspace "); break; + case XML_REGEXP_INITNAME: + fprintf(output, "initname "); break; + case XML_REGEXP_NOTINITNAME: + fprintf(output, "notinitname "); break; + case XML_REGEXP_NAMECHAR: + fprintf(output, "namechar "); break; + case XML_REGEXP_NOTNAMECHAR: + fprintf(output, "notnamechar "); break; + case XML_REGEXP_DECIMAL: + fprintf(output, "decimal "); break; + case XML_REGEXP_NOTDECIMAL: + fprintf(output, "notdecimal "); break; + case XML_REGEXP_REALCHAR: + fprintf(output, "realchar "); break; + case XML_REGEXP_NOTREALCHAR: + fprintf(output, "notrealchar "); break; + case XML_REGEXP_LETTER: + fprintf(output, "LETTER "); break; + case XML_REGEXP_LETTER_UPPERCASE: + fprintf(output, "LETTER_UPPERCASE "); break; + case XML_REGEXP_LETTER_LOWERCASE: + fprintf(output, "LETTER_LOWERCASE "); break; + case XML_REGEXP_LETTER_TITLECASE: + fprintf(output, "LETTER_TITLECASE "); break; + case XML_REGEXP_LETTER_MODIFIER: + fprintf(output, "LETTER_MODIFIER "); break; + case XML_REGEXP_LETTER_OTHERS: + fprintf(output, "LETTER_OTHERS "); break; + case XML_REGEXP_MARK: + fprintf(output, "MARK "); break; + case XML_REGEXP_MARK_NONSPACING: + fprintf(output, "MARK_NONSPACING "); break; + case XML_REGEXP_MARK_SPACECOMBINING: + fprintf(output, "MARK_SPACECOMBINING "); break; + case XML_REGEXP_MARK_ENCLOSING: + fprintf(output, "MARK_ENCLOSING "); break; + case XML_REGEXP_NUMBER: + fprintf(output, "NUMBER "); break; + case XML_REGEXP_NUMBER_DECIMAL: + fprintf(output, "NUMBER_DECIMAL "); break; + case XML_REGEXP_NUMBER_LETTER: + fprintf(output, "NUMBER_LETTER "); break; + case XML_REGEXP_NUMBER_OTHERS: + fprintf(output, "NUMBER_OTHERS "); break; + case XML_REGEXP_PUNCT: + fprintf(output, "PUNCT "); break; + case XML_REGEXP_PUNCT_CONNECTOR: + fprintf(output, "PUNCT_CONNECTOR "); break; + case XML_REGEXP_PUNCT_DASH: + fprintf(output, "PUNCT_DASH "); break; + case XML_REGEXP_PUNCT_OPEN: + fprintf(output, "PUNCT_OPEN "); break; + case XML_REGEXP_PUNCT_CLOSE: + fprintf(output, "PUNCT_CLOSE "); break; + case XML_REGEXP_PUNCT_INITQUOTE: + fprintf(output, "PUNCT_INITQUOTE "); break; + case XML_REGEXP_PUNCT_FINQUOTE: + fprintf(output, "PUNCT_FINQUOTE "); break; + case XML_REGEXP_PUNCT_OTHERS: + fprintf(output, "PUNCT_OTHERS "); break; + case XML_REGEXP_SEPAR: + fprintf(output, "SEPAR "); break; + case XML_REGEXP_SEPAR_SPACE: + fprintf(output, "SEPAR_SPACE "); break; + case XML_REGEXP_SEPAR_LINE: + fprintf(output, "SEPAR_LINE "); break; + case XML_REGEXP_SEPAR_PARA: + fprintf(output, "SEPAR_PARA "); break; + case XML_REGEXP_SYMBOL: + fprintf(output, "SYMBOL "); break; + case XML_REGEXP_SYMBOL_MATH: + fprintf(output, "SYMBOL_MATH "); break; + case XML_REGEXP_SYMBOL_CURRENCY: + fprintf(output, "SYMBOL_CURRENCY "); break; + case XML_REGEXP_SYMBOL_MODIFIER: + fprintf(output, "SYMBOL_MODIFIER "); break; + case XML_REGEXP_SYMBOL_OTHERS: + fprintf(output, "SYMBOL_OTHERS "); break; + case XML_REGEXP_OTHER: + fprintf(output, "OTHER "); break; + case XML_REGEXP_OTHER_CONTROL: + fprintf(output, "OTHER_CONTROL "); break; + case XML_REGEXP_OTHER_FORMAT: + fprintf(output, "OTHER_FORMAT "); break; + case XML_REGEXP_OTHER_PRIVATE: + fprintf(output, "OTHER_PRIVATE "); break; + case XML_REGEXP_OTHER_NA: + fprintf(output, "OTHER_NA "); break; + case XML_REGEXP_BLOCK_NAME: + fprintf(output, "BLOCK "); break; + } +} + +static void +xmlRegPrintQuantType(FILE *output, xmlRegQuantType type) { + switch (type) { + case XML_REGEXP_QUANT_EPSILON: + fprintf(output, "epsilon "); break; + case XML_REGEXP_QUANT_ONCE: + fprintf(output, "once "); break; + case XML_REGEXP_QUANT_OPT: + fprintf(output, "? "); break; + case XML_REGEXP_QUANT_MULT: + fprintf(output, "* "); break; + case XML_REGEXP_QUANT_PLUS: + fprintf(output, "+ "); break; + case XML_REGEXP_QUANT_RANGE: + fprintf(output, "range "); break; + case XML_REGEXP_QUANT_ONCEONLY: + fprintf(output, "onceonly "); break; + case XML_REGEXP_QUANT_ALL: + fprintf(output, "all "); break; + } +} +static void +xmlRegPrintRange(FILE *output, xmlRegRangePtr range) { + fprintf(output, " range: "); + if (range->neg) + fprintf(output, "negative "); + xmlRegPrintAtomType(output, range->type); + fprintf(output, "%c - %c\n", range->start, range->end); +} + +static void +xmlRegPrintAtom(FILE *output, xmlRegAtomPtr atom) { + fprintf(output, " atom: "); + if (atom == NULL) { + fprintf(output, "NULL\n"); + return; + } + if (atom->neg) + fprintf(output, "not "); + xmlRegPrintAtomType(output, atom->type); + xmlRegPrintQuantType(output, atom->quant); + if (atom->quant == XML_REGEXP_QUANT_RANGE) + fprintf(output, "%d-%d ", atom->min, atom->max); + if (atom->type == XML_REGEXP_STRING) + fprintf(output, "'%s' ", (char *) atom->valuep); + if (atom->type == XML_REGEXP_CHARVAL) + fprintf(output, "char %c\n", atom->codepoint); + else if (atom->type == XML_REGEXP_RANGES) { + int i; + fprintf(output, "%d entries\n", atom->nbRanges); + for (i = 0; i < atom->nbRanges;i++) + xmlRegPrintRange(output, atom->ranges[i]); + } else if (atom->type == XML_REGEXP_SUBREG) { + fprintf(output, "start %d end %d\n", atom->start->no, atom->stop->no); + } else { + fprintf(output, "\n"); + } +} + +static void +xmlRegPrintTrans(FILE *output, xmlRegTransPtr trans) { + fprintf(output, " trans: "); + if (trans == NULL) { + fprintf(output, "NULL\n"); + return; + } + if (trans->to < 0) { + fprintf(output, "removed\n"); + return; + } + if (trans->nd != 0) { + if (trans->nd == 2) + fprintf(output, "last not determinist, "); + else + fprintf(output, "not determinist, "); + } + if (trans->counter >= 0) { + fprintf(output, "counted %d, ", trans->counter); + } + if (trans->count == REGEXP_ALL_COUNTER) { + fprintf(output, "all transition, "); + } else if (trans->count >= 0) { + fprintf(output, "count based %d, ", trans->count); + } + if (trans->atom == NULL) { + fprintf(output, "epsilon to %d\n", trans->to); + return; + } + if (trans->atom->type == XML_REGEXP_CHARVAL) + fprintf(output, "char %c ", trans->atom->codepoint); + fprintf(output, "atom %d, to %d\n", trans->atom->no, trans->to); +} + +static void +xmlRegPrintState(FILE *output, xmlRegStatePtr state) { + int i; + + fprintf(output, " state: "); + if (state == NULL) { + fprintf(output, "NULL\n"); + return; + } + if (state->type == XML_REGEXP_START_STATE) + fprintf(output, "START "); + if (state->type == XML_REGEXP_FINAL_STATE) + fprintf(output, "FINAL "); + + fprintf(output, "%d, %d transitions:\n", state->no, state->nbTrans); + for (i = 0;i < state->nbTrans; i++) { + xmlRegPrintTrans(output, &(state->trans[i])); + } +} + +#ifdef DEBUG_REGEXP_GRAPH +static void +xmlRegPrintCtxt(FILE *output, xmlRegParserCtxtPtr ctxt) { + int i; + + fprintf(output, " ctxt: "); + if (ctxt == NULL) { + fprintf(output, "NULL\n"); + return; + } + fprintf(output, "'%s' ", ctxt->string); + if (ctxt->error) + fprintf(output, "error "); + if (ctxt->neg) + fprintf(output, "neg "); + fprintf(output, "\n"); + fprintf(output, "%d atoms:\n", ctxt->nbAtoms); + for (i = 0;i < ctxt->nbAtoms; i++) { + fprintf(output, " %02d ", i); + xmlRegPrintAtom(output, ctxt->atoms[i]); + } + if (ctxt->atom != NULL) { + fprintf(output, "current atom:\n"); + xmlRegPrintAtom(output, ctxt->atom); + } + fprintf(output, "%d states:", ctxt->nbStates); + if (ctxt->start != NULL) + fprintf(output, " start: %d", ctxt->start->no); + if (ctxt->end != NULL) + fprintf(output, " end: %d", ctxt->end->no); + fprintf(output, "\n"); + for (i = 0;i < ctxt->nbStates; i++) { + xmlRegPrintState(output, ctxt->states[i]); + } + fprintf(output, "%d counters:\n", ctxt->nbCounters); + for (i = 0;i < ctxt->nbCounters; i++) { + fprintf(output, " %d: min %d max %d\n", i, ctxt->counters[i].min, + ctxt->counters[i].max); + } +} +#endif + +/************************************************************************ + * * + * Finite Automata structures manipulations * + * * + ************************************************************************/ + +static void +xmlRegAtomAddRange(xmlRegParserCtxtPtr ctxt, xmlRegAtomPtr atom, + int neg, xmlRegAtomType type, int start, int end, + xmlChar *blockName) { + xmlRegRangePtr range; + + if (atom == NULL) { + ERROR("add range: atom is NULL"); + return; + } + if (atom->type != XML_REGEXP_RANGES) { + ERROR("add range: atom is not ranges"); + return; + } + if (atom->maxRanges == 0) { + atom->maxRanges = 4; + atom->ranges = (xmlRegRangePtr *) xmlMalloc(atom->maxRanges * + sizeof(xmlRegRangePtr)); + if (atom->ranges == NULL) { + xmlRegexpErrMemory(ctxt, "adding ranges"); + atom->maxRanges = 0; + return; + } + } else if (atom->nbRanges >= atom->maxRanges) { + xmlRegRangePtr *tmp; + atom->maxRanges *= 2; + tmp = (xmlRegRangePtr *) xmlRealloc(atom->ranges, atom->maxRanges * + sizeof(xmlRegRangePtr)); + if (tmp == NULL) { + xmlRegexpErrMemory(ctxt, "adding ranges"); + atom->maxRanges /= 2; + return; + } + atom->ranges = tmp; + } + range = xmlRegNewRange(ctxt, neg, type, start, end); + if (range == NULL) + return; + range->blockName = blockName; + atom->ranges[atom->nbRanges++] = range; + +} + +static int +xmlRegGetCounter(xmlRegParserCtxtPtr ctxt) { + if (ctxt->maxCounters == 0) { + ctxt->maxCounters = 4; + ctxt->counters = (xmlRegCounter *) xmlMalloc(ctxt->maxCounters * + sizeof(xmlRegCounter)); + if (ctxt->counters == NULL) { + xmlRegexpErrMemory(ctxt, "allocating counter"); + ctxt->maxCounters = 0; + return(-1); + } + } else if (ctxt->nbCounters >= ctxt->maxCounters) { + xmlRegCounter *tmp; + ctxt->maxCounters *= 2; + tmp = (xmlRegCounter *) xmlRealloc(ctxt->counters, ctxt->maxCounters * + sizeof(xmlRegCounter)); + if (tmp == NULL) { + xmlRegexpErrMemory(ctxt, "allocating counter"); + ctxt->maxCounters /= 2; + return(-1); + } + ctxt->counters = tmp; + } + ctxt->counters[ctxt->nbCounters].min = -1; + ctxt->counters[ctxt->nbCounters].max = -1; + return(ctxt->nbCounters++); +} + +static int +xmlRegAtomPush(xmlRegParserCtxtPtr ctxt, xmlRegAtomPtr atom) { + if (atom == NULL) { + ERROR("atom push: atom is NULL"); + return(-1); + } + if (ctxt->maxAtoms == 0) { + ctxt->maxAtoms = 4; + ctxt->atoms = (xmlRegAtomPtr *) xmlMalloc(ctxt->maxAtoms * + sizeof(xmlRegAtomPtr)); + if (ctxt->atoms == NULL) { + xmlRegexpErrMemory(ctxt, "pushing atom"); + ctxt->maxAtoms = 0; + return(-1); + } + } else if (ctxt->nbAtoms >= ctxt->maxAtoms) { + xmlRegAtomPtr *tmp; + ctxt->maxAtoms *= 2; + tmp = (xmlRegAtomPtr *) xmlRealloc(ctxt->atoms, ctxt->maxAtoms * + sizeof(xmlRegAtomPtr)); + if (tmp == NULL) { + xmlRegexpErrMemory(ctxt, "allocating counter"); + ctxt->maxAtoms /= 2; + return(-1); + } + ctxt->atoms = tmp; + } + atom->no = ctxt->nbAtoms; + ctxt->atoms[ctxt->nbAtoms++] = atom; + return(0); +} + +static void +xmlRegStateAddTransTo(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr target, + int from) { + if (target->maxTransTo == 0) { + target->maxTransTo = 8; + target->transTo = (int *) xmlMalloc(target->maxTransTo * + sizeof(int)); + if (target->transTo == NULL) { + xmlRegexpErrMemory(ctxt, "adding transition"); + target->maxTransTo = 0; + return; + } + } else if (target->nbTransTo >= target->maxTransTo) { + int *tmp; + target->maxTransTo *= 2; + tmp = (int *) xmlRealloc(target->transTo, target->maxTransTo * + sizeof(int)); + if (tmp == NULL) { + xmlRegexpErrMemory(ctxt, "adding transition"); + target->maxTransTo /= 2; + return; + } + target->transTo = tmp; + } + target->transTo[target->nbTransTo] = from; + target->nbTransTo++; +} + +static void +xmlRegStateAddTrans(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr state, + xmlRegAtomPtr atom, xmlRegStatePtr target, + int counter, int count) { + + int nrtrans; + + if (state == NULL) { + ERROR("add state: state is NULL"); + return; + } + if (target == NULL) { + ERROR("add state: target is NULL"); + return; + } + /* + * Other routines follow the philosophy 'When in doubt, add a transition' + * so we check here whether such a transition is already present and, if + * so, silently ignore this request. + */ + + for (nrtrans = state->nbTrans - 1; nrtrans >= 0; nrtrans--) { + xmlRegTransPtr trans = &(state->trans[nrtrans]); + if ((trans->atom == atom) && + (trans->to == target->no) && + (trans->counter == counter) && + (trans->count == count)) { +#ifdef DEBUG_REGEXP_GRAPH + printf("Ignoring duplicate transition from %d to %d\n", + state->no, target->no); +#endif + return; + } + } + + if (state->maxTrans == 0) { + state->maxTrans = 8; + state->trans = (xmlRegTrans *) xmlMalloc(state->maxTrans * + sizeof(xmlRegTrans)); + if (state->trans == NULL) { + xmlRegexpErrMemory(ctxt, "adding transition"); + state->maxTrans = 0; + return; + } + } else if (state->nbTrans >= state->maxTrans) { + xmlRegTrans *tmp; + state->maxTrans *= 2; + tmp = (xmlRegTrans *) xmlRealloc(state->trans, state->maxTrans * + sizeof(xmlRegTrans)); + if (tmp == NULL) { + xmlRegexpErrMemory(ctxt, "adding transition"); + state->maxTrans /= 2; + return; + } + state->trans = tmp; + } +#ifdef DEBUG_REGEXP_GRAPH + printf("Add trans from %d to %d ", state->no, target->no); + if (count == REGEXP_ALL_COUNTER) + printf("all transition\n"); + else if (count >= 0) + printf("count based %d\n", count); + else if (counter >= 0) + printf("counted %d\n", counter); + else if (atom == NULL) + printf("epsilon transition\n"); + else if (atom != NULL) + xmlRegPrintAtom(stdout, atom); +#endif + + state->trans[state->nbTrans].atom = atom; + state->trans[state->nbTrans].to = target->no; + state->trans[state->nbTrans].counter = counter; + state->trans[state->nbTrans].count = count; + state->trans[state->nbTrans].nd = 0; + state->nbTrans++; + xmlRegStateAddTransTo(ctxt, target, state->no); +} + +static int +xmlRegStatePush(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr state) { + if (state == NULL) return(-1); + if (ctxt->maxStates == 0) { + ctxt->maxStates = 4; + ctxt->states = (xmlRegStatePtr *) xmlMalloc(ctxt->maxStates * + sizeof(xmlRegStatePtr)); + if (ctxt->states == NULL) { + xmlRegexpErrMemory(ctxt, "adding state"); + ctxt->maxStates = 0; + return(-1); + } + } else if (ctxt->nbStates >= ctxt->maxStates) { + xmlRegStatePtr *tmp; + ctxt->maxStates *= 2; + tmp = (xmlRegStatePtr *) xmlRealloc(ctxt->states, ctxt->maxStates * + sizeof(xmlRegStatePtr)); + if (tmp == NULL) { + xmlRegexpErrMemory(ctxt, "adding state"); + ctxt->maxStates /= 2; + return(-1); + } + ctxt->states = tmp; + } + state->no = ctxt->nbStates; + ctxt->states[ctxt->nbStates++] = state; + return(0); +} + +/** + * xmlFAGenerateAllTransition: + * @ctxt: a regexp parser context + * @from: the from state + * @to: the target state or NULL for building a new one + * @lax: + * + */ +static void +xmlFAGenerateAllTransition(xmlRegParserCtxtPtr ctxt, + xmlRegStatePtr from, xmlRegStatePtr to, + int lax) { + if (to == NULL) { + to = xmlRegNewState(ctxt); + xmlRegStatePush(ctxt, to); + ctxt->state = to; + } + if (lax) + xmlRegStateAddTrans(ctxt, from, NULL, to, -1, REGEXP_ALL_LAX_COUNTER); + else + xmlRegStateAddTrans(ctxt, from, NULL, to, -1, REGEXP_ALL_COUNTER); +} + +/** + * xmlFAGenerateEpsilonTransition: + * @ctxt: a regexp parser context + * @from: the from state + * @to: the target state or NULL for building a new one + * + */ +static void +xmlFAGenerateEpsilonTransition(xmlRegParserCtxtPtr ctxt, + xmlRegStatePtr from, xmlRegStatePtr to) { + if (to == NULL) { + to = xmlRegNewState(ctxt); + xmlRegStatePush(ctxt, to); + ctxt->state = to; + } + xmlRegStateAddTrans(ctxt, from, NULL, to, -1, -1); +} + +/** + * xmlFAGenerateCountedEpsilonTransition: + * @ctxt: a regexp parser context + * @from: the from state + * @to: the target state or NULL for building a new one + * counter: the counter for that transition + * + */ +static void +xmlFAGenerateCountedEpsilonTransition(xmlRegParserCtxtPtr ctxt, + xmlRegStatePtr from, xmlRegStatePtr to, int counter) { + if (to == NULL) { + to = xmlRegNewState(ctxt); + xmlRegStatePush(ctxt, to); + ctxt->state = to; + } + xmlRegStateAddTrans(ctxt, from, NULL, to, counter, -1); +} + +/** + * xmlFAGenerateCountedTransition: + * @ctxt: a regexp parser context + * @from: the from state + * @to: the target state or NULL for building a new one + * counter: the counter for that transition + * + */ +static void +xmlFAGenerateCountedTransition(xmlRegParserCtxtPtr ctxt, + xmlRegStatePtr from, xmlRegStatePtr to, int counter) { + if (to == NULL) { + to = xmlRegNewState(ctxt); + xmlRegStatePush(ctxt, to); + ctxt->state = to; + } + xmlRegStateAddTrans(ctxt, from, NULL, to, -1, counter); +} + +/** + * xmlFAGenerateTransitions: + * @ctxt: a regexp parser context + * @from: the from state + * @to: the target state or NULL for building a new one + * @atom: the atom generating the transition + * + * Returns 0 if success and -1 in case of error. + */ +static int +xmlFAGenerateTransitions(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr from, + xmlRegStatePtr to, xmlRegAtomPtr atom) { + xmlRegStatePtr end; + + if (atom == NULL) { + ERROR("genrate transition: atom == NULL"); + return(-1); + } + if (atom->type == XML_REGEXP_SUBREG) { + /* + * this is a subexpression handling one should not need to + * create a new node except for XML_REGEXP_QUANT_RANGE. + */ + if (xmlRegAtomPush(ctxt, atom) < 0) { + return(-1); + } + if ((to != NULL) && (atom->stop != to) && + (atom->quant != XML_REGEXP_QUANT_RANGE)) { + /* + * Generate an epsilon transition to link to the target + */ + xmlFAGenerateEpsilonTransition(ctxt, atom->stop, to); +#ifdef DV + } else if ((to == NULL) && (atom->quant != XML_REGEXP_QUANT_RANGE) && + (atom->quant != XML_REGEXP_QUANT_ONCE)) { + to = xmlRegNewState(ctxt); + xmlRegStatePush(ctxt, to); + ctxt->state = to; + xmlFAGenerateEpsilonTransition(ctxt, atom->stop, to); +#endif + } + switch (atom->quant) { + case XML_REGEXP_QUANT_OPT: + atom->quant = XML_REGEXP_QUANT_ONCE; + /* + * transition done to the state after end of atom. + * 1. set transition from atom start to new state + * 2. set transition from atom end to this state. + */ + if (to == NULL) { + xmlFAGenerateEpsilonTransition(ctxt, atom->start, 0); + xmlFAGenerateEpsilonTransition(ctxt, atom->stop, + ctxt->state); + } else { + xmlFAGenerateEpsilonTransition(ctxt, atom->start, to); + } + break; + case XML_REGEXP_QUANT_MULT: + atom->quant = XML_REGEXP_QUANT_ONCE; + xmlFAGenerateEpsilonTransition(ctxt, atom->start, atom->stop); + xmlFAGenerateEpsilonTransition(ctxt, atom->stop, atom->start); + break; + case XML_REGEXP_QUANT_PLUS: + atom->quant = XML_REGEXP_QUANT_ONCE; + xmlFAGenerateEpsilonTransition(ctxt, atom->stop, atom->start); + break; + case XML_REGEXP_QUANT_RANGE: { + int counter; + xmlRegStatePtr inter, newstate; + + /* + * create the final state now if needed + */ + if (to != NULL) { + newstate = to; + } else { + newstate = xmlRegNewState(ctxt); + xmlRegStatePush(ctxt, newstate); + } + + /* + * The principle here is to use counted transition + * to avoid explosion in the number of states in the + * graph. This is clearly more complex but should not + * be exploitable at runtime. + */ + if ((atom->min == 0) && (atom->start0 == NULL)) { + xmlRegAtomPtr copy; + /* + * duplicate a transition based on atom to count next + * occurences after 1. We cannot loop to atom->start + * directly because we need an epsilon transition to + * newstate. + */ + /* ???? For some reason it seems we never reach that + case, I suppose this got optimized out before when + building the automata */ + copy = xmlRegCopyAtom(ctxt, atom); + if (copy == NULL) + return(-1); + copy->quant = XML_REGEXP_QUANT_ONCE; + copy->min = 0; + copy->max = 0; + + if (xmlFAGenerateTransitions(ctxt, atom->start, NULL, copy) + < 0) + return(-1); + inter = ctxt->state; + counter = xmlRegGetCounter(ctxt); + ctxt->counters[counter].min = atom->min - 1; + ctxt->counters[counter].max = atom->max - 1; + /* count the number of times we see it again */ + xmlFAGenerateCountedEpsilonTransition(ctxt, inter, + atom->stop, counter); + /* allow a way out based on the count */ + xmlFAGenerateCountedTransition(ctxt, inter, + newstate, counter); + /* and also allow a direct exit for 0 */ + xmlFAGenerateEpsilonTransition(ctxt, atom->start, + newstate); + } else { + /* + * either we need the atom at least once or there + * is an atom->start0 allowing to easilly plug the + * epsilon transition. + */ + counter = xmlRegGetCounter(ctxt); + ctxt->counters[counter].min = atom->min - 1; + ctxt->counters[counter].max = atom->max - 1; + /* count the number of times we see it again */ + xmlFAGenerateCountedEpsilonTransition(ctxt, atom->stop, + atom->start, counter); + /* allow a way out based on the count */ + xmlFAGenerateCountedTransition(ctxt, atom->stop, + newstate, counter); + /* and if needed allow a direct exit for 0 */ + if (atom->min == 0) + xmlFAGenerateEpsilonTransition(ctxt, atom->start0, + newstate); + + } + atom->min = 0; + atom->max = 0; + atom->quant = XML_REGEXP_QUANT_ONCE; + ctxt->state = newstate; + } + default: + break; + } + return(0); + } + if ((atom->min == 0) && (atom->max == 0) && + (atom->quant == XML_REGEXP_QUANT_RANGE)) { + /* + * we can discard the atom and generate an epsilon transition instead + */ + if (to == NULL) { + to = xmlRegNewState(ctxt); + if (to != NULL) + xmlRegStatePush(ctxt, to); + else { + return(-1); + } + } + xmlFAGenerateEpsilonTransition(ctxt, from, to); + ctxt->state = to; + xmlRegFreeAtom(atom); + return(0); + } + if (to == NULL) { + to = xmlRegNewState(ctxt); + if (to != NULL) + xmlRegStatePush(ctxt, to); + else { + return(-1); + } + } + end = to; + if ((atom->quant == XML_REGEXP_QUANT_MULT) || + (atom->quant == XML_REGEXP_QUANT_PLUS)) { + /* + * Do not pollute the target state by adding transitions from + * it as it is likely to be the shared target of multiple branches. + * So isolate with an epsilon transition. + */ + xmlRegStatePtr tmp; + + tmp = xmlRegNewState(ctxt); + if (tmp != NULL) + xmlRegStatePush(ctxt, tmp); + else { + return(-1); + } + xmlFAGenerateEpsilonTransition(ctxt, tmp, to); + to = tmp; + } + if (xmlRegAtomPush(ctxt, atom) < 0) { + return(-1); + } + xmlRegStateAddTrans(ctxt, from, atom, to, -1, -1); + ctxt->state = end; + switch (atom->quant) { + case XML_REGEXP_QUANT_OPT: + atom->quant = XML_REGEXP_QUANT_ONCE; + xmlFAGenerateEpsilonTransition(ctxt, from, to); + break; + case XML_REGEXP_QUANT_MULT: + atom->quant = XML_REGEXP_QUANT_ONCE; + xmlFAGenerateEpsilonTransition(ctxt, from, to); + xmlRegStateAddTrans(ctxt, to, atom, to, -1, -1); + break; + case XML_REGEXP_QUANT_PLUS: + atom->quant = XML_REGEXP_QUANT_ONCE; + xmlRegStateAddTrans(ctxt, to, atom, to, -1, -1); + break; + case XML_REGEXP_QUANT_RANGE: +#if DV_test + if (atom->min == 0) { + xmlFAGenerateEpsilonTransition(ctxt, from, to); + } +#endif + break; + default: + break; + } + return(0); +} + +/** + * xmlFAReduceEpsilonTransitions: + * @ctxt: a regexp parser context + * @fromnr: the from state + * @tonr: the to state + * @counter: should that transition be associated to a counted + * + */ +static void +xmlFAReduceEpsilonTransitions(xmlRegParserCtxtPtr ctxt, int fromnr, + int tonr, int counter) { + int transnr; + xmlRegStatePtr from; + xmlRegStatePtr to; + +#ifdef DEBUG_REGEXP_GRAPH + printf("xmlFAReduceEpsilonTransitions(%d, %d)\n", fromnr, tonr); +#endif + from = ctxt->states[fromnr]; + if (from == NULL) + return; + to = ctxt->states[tonr]; + if (to == NULL) + return; + if ((to->mark == XML_REGEXP_MARK_START) || + (to->mark == XML_REGEXP_MARK_VISITED)) + return; + + to->mark = XML_REGEXP_MARK_VISITED; + if (to->type == XML_REGEXP_FINAL_STATE) { +#ifdef DEBUG_REGEXP_GRAPH + printf("State %d is final, so %d becomes final\n", tonr, fromnr); +#endif + from->type = XML_REGEXP_FINAL_STATE; + } + for (transnr = 0;transnr < to->nbTrans;transnr++) { + if (to->trans[transnr].to < 0) + continue; + if (to->trans[transnr].atom == NULL) { + /* + * Don't remove counted transitions + * Don't loop either + */ + if (to->trans[transnr].to != fromnr) { + if (to->trans[transnr].count >= 0) { + int newto = to->trans[transnr].to; + + xmlRegStateAddTrans(ctxt, from, NULL, + ctxt->states[newto], + -1, to->trans[transnr].count); + } else { +#ifdef DEBUG_REGEXP_GRAPH + printf("Found epsilon trans %d from %d to %d\n", + transnr, tonr, to->trans[transnr].to); +#endif + if (to->trans[transnr].counter >= 0) { + xmlFAReduceEpsilonTransitions(ctxt, fromnr, + to->trans[transnr].to, + to->trans[transnr].counter); + } else { + xmlFAReduceEpsilonTransitions(ctxt, fromnr, + to->trans[transnr].to, + counter); + } + } + } + } else { + int newto = to->trans[transnr].to; + + if (to->trans[transnr].counter >= 0) { + xmlRegStateAddTrans(ctxt, from, to->trans[transnr].atom, + ctxt->states[newto], + to->trans[transnr].counter, -1); + } else { + xmlRegStateAddTrans(ctxt, from, to->trans[transnr].atom, + ctxt->states[newto], counter, -1); + } + } + } + to->mark = XML_REGEXP_MARK_NORMAL; +} + +/** + * xmlFAEliminateSimpleEpsilonTransitions: + * @ctxt: a regexp parser context + * + * Eliminating general epsilon transitions can get costly in the general + * algorithm due to the large amount of generated new transitions and + * associated comparisons. However for simple epsilon transition used just + * to separate building blocks when generating the automata this can be + * reduced to state elimination: + * - if there exists an epsilon from X to Y + * - if there is no other transition from X + * then X and Y are semantically equivalent and X can be eliminated + * If X is the start state then make Y the start state, else replace the + * target of all transitions to X by transitions to Y. + */ +static void +xmlFAEliminateSimpleEpsilonTransitions(xmlRegParserCtxtPtr ctxt) { + int statenr, i, j, newto; + xmlRegStatePtr state, tmp; + + for (statenr = 0;statenr < ctxt->nbStates;statenr++) { + state = ctxt->states[statenr]; + if (state == NULL) + continue; + if (state->nbTrans != 1) + continue; + if (state->type == XML_REGEXP_UNREACH_STATE) + continue; + /* is the only transition out a basic transition */ + if ((state->trans[0].atom == NULL) && + (state->trans[0].to >= 0) && + (state->trans[0].to != statenr) && + (state->trans[0].counter < 0) && + (state->trans[0].count < 0)) { + newto = state->trans[0].to; + + if (state->type == XML_REGEXP_START_STATE) { +#ifdef DEBUG_REGEXP_GRAPH + printf("Found simple epsilon trans from start %d to %d\n", + statenr, newto); +#endif + } else { +#ifdef DEBUG_REGEXP_GRAPH + printf("Found simple epsilon trans from %d to %d\n", + statenr, newto); +#endif + for (i = 0;i < state->nbTransTo;i++) { + tmp = ctxt->states[state->transTo[i]]; + for (j = 0;j < tmp->nbTrans;j++) { + if (tmp->trans[j].to == statenr) { +#ifdef DEBUG_REGEXP_GRAPH + printf("Changed transition %d on %d to go to %d\n", + j, tmp->no, newto); +#endif + tmp->trans[j].to = -1; + xmlRegStateAddTrans(ctxt, tmp, tmp->trans[j].atom, + ctxt->states[newto], + tmp->trans[j].counter, + tmp->trans[j].count); + } + } + } + if (state->type == XML_REGEXP_FINAL_STATE) + ctxt->states[newto]->type = XML_REGEXP_FINAL_STATE; + /* eliminate the transition completely */ + state->nbTrans = 0; + + state->type = XML_REGEXP_UNREACH_STATE; + + } + + } + } +} +/** + * xmlFAEliminateEpsilonTransitions: + * @ctxt: a regexp parser context + * + */ +static void +xmlFAEliminateEpsilonTransitions(xmlRegParserCtxtPtr ctxt) { + int statenr, transnr; + xmlRegStatePtr state; + int has_epsilon; + + if (ctxt->states == NULL) return; + + /* + * Eliminate simple epsilon transition and the associated unreachable + * states. + */ + xmlFAEliminateSimpleEpsilonTransitions(ctxt); + for (statenr = 0;statenr < ctxt->nbStates;statenr++) { + state = ctxt->states[statenr]; + if ((state != NULL) && (state->type == XML_REGEXP_UNREACH_STATE)) { +#ifdef DEBUG_REGEXP_GRAPH + printf("Removed unreachable state %d\n", statenr); +#endif + xmlRegFreeState(state); + ctxt->states[statenr] = NULL; + } + } + + has_epsilon = 0; + + /* + * Build the completed transitions bypassing the epsilons + * Use a marking algorithm to avoid loops + * Mark sink states too. + * Process from the latests states backward to the start when + * there is long cascading epsilon chains this minimize the + * recursions and transition compares when adding the new ones + */ + for (statenr = ctxt->nbStates - 1;statenr >= 0;statenr--) { + state = ctxt->states[statenr]; + if (state == NULL) + continue; + if ((state->nbTrans == 0) && + (state->type != XML_REGEXP_FINAL_STATE)) { + state->type = XML_REGEXP_SINK_STATE; + } + for (transnr = 0;transnr < state->nbTrans;transnr++) { + if ((state->trans[transnr].atom == NULL) && + (state->trans[transnr].to >= 0)) { + if (state->trans[transnr].to == statenr) { + state->trans[transnr].to = -1; +#ifdef DEBUG_REGEXP_GRAPH + printf("Removed loopback epsilon trans %d on %d\n", + transnr, statenr); +#endif + } else if (state->trans[transnr].count < 0) { + int newto = state->trans[transnr].to; + +#ifdef DEBUG_REGEXP_GRAPH + printf("Found epsilon trans %d from %d to %d\n", + transnr, statenr, newto); +#endif + has_epsilon = 1; + state->trans[transnr].to = -2; + state->mark = XML_REGEXP_MARK_START; + xmlFAReduceEpsilonTransitions(ctxt, statenr, + newto, state->trans[transnr].counter); + state->mark = XML_REGEXP_MARK_NORMAL; +#ifdef DEBUG_REGEXP_GRAPH + } else { + printf("Found counted transition %d on %d\n", + transnr, statenr); +#endif + } + } + } + } + /* + * Eliminate the epsilon transitions + */ + if (has_epsilon) { + for (statenr = 0;statenr < ctxt->nbStates;statenr++) { + state = ctxt->states[statenr]; + if (state == NULL) + continue; + for (transnr = 0;transnr < state->nbTrans;transnr++) { + xmlRegTransPtr trans = &(state->trans[transnr]); + if ((trans->atom == NULL) && + (trans->count < 0) && + (trans->to >= 0)) { + trans->to = -1; + } + } + } + } + + /* + * Use this pass to detect unreachable states too + */ + for (statenr = 0;statenr < ctxt->nbStates;statenr++) { + state = ctxt->states[statenr]; + if (state != NULL) + state->reached = XML_REGEXP_MARK_NORMAL; + } + state = ctxt->states[0]; + if (state != NULL) + state->reached = XML_REGEXP_MARK_START; + while (state != NULL) { + xmlRegStatePtr target = NULL; + state->reached = XML_REGEXP_MARK_VISITED; + /* + * Mark all states reachable from the current reachable state + */ + for (transnr = 0;transnr < state->nbTrans;transnr++) { + if ((state->trans[transnr].to >= 0) && + ((state->trans[transnr].atom != NULL) || + (state->trans[transnr].count >= 0))) { + int newto = state->trans[transnr].to; + + if (ctxt->states[newto] == NULL) + continue; + if (ctxt->states[newto]->reached == XML_REGEXP_MARK_NORMAL) { + ctxt->states[newto]->reached = XML_REGEXP_MARK_START; + target = ctxt->states[newto]; + } + } + } + + /* + * find the next accessible state not explored + */ + if (target == NULL) { + for (statenr = 1;statenr < ctxt->nbStates;statenr++) { + state = ctxt->states[statenr]; + if ((state != NULL) && (state->reached == + XML_REGEXP_MARK_START)) { + target = state; + break; + } + } + } + state = target; + } + for (statenr = 0;statenr < ctxt->nbStates;statenr++) { + state = ctxt->states[statenr]; + if ((state != NULL) && (state->reached == XML_REGEXP_MARK_NORMAL)) { +#ifdef DEBUG_REGEXP_GRAPH + printf("Removed unreachable state %d\n", statenr); +#endif + xmlRegFreeState(state); + ctxt->states[statenr] = NULL; + } + } + +} + +static int +xmlFACompareRanges(xmlRegRangePtr range1, xmlRegRangePtr range2) { + int ret = 0; + + if ((range1->type == XML_REGEXP_RANGES) || + (range2->type == XML_REGEXP_RANGES) || + (range2->type == XML_REGEXP_SUBREG) || + (range1->type == XML_REGEXP_SUBREG) || + (range1->type == XML_REGEXP_STRING) || + (range2->type == XML_REGEXP_STRING)) + return(-1); + + /* put them in order */ + if (range1->type > range2->type) { + xmlRegRangePtr tmp; + + tmp = range1; + range1 = range2; + range2 = tmp; + } + if ((range1->type == XML_REGEXP_ANYCHAR) || + (range2->type == XML_REGEXP_ANYCHAR)) { + ret = 1; + } else if ((range1->type == XML_REGEXP_EPSILON) || + (range2->type == XML_REGEXP_EPSILON)) { + return(0); + } else if (range1->type == range2->type) { + if (range1->type != XML_REGEXP_CHARVAL) + ret = 1; + else if ((range1->end < range2->start) || + (range2->end < range1->start)) + ret = 0; + else + ret = 1; + } else if (range1->type == XML_REGEXP_CHARVAL) { + int codepoint; + int neg = 0; + + /* + * just check all codepoints in the range for acceptance, + * this is usually way cheaper since done only once at + * compilation than testing over and over at runtime or + * pushing too many states when evaluating. + */ + if (((range1->neg == 0) && (range2->neg != 0)) || + ((range1->neg != 0) && (range2->neg == 0))) + neg = 1; + + for (codepoint = range1->start;codepoint <= range1->end ;codepoint++) { + ret = xmlRegCheckCharacterRange(range2->type, codepoint, + 0, range2->start, range2->end, + range2->blockName); + if (ret < 0) + return(-1); + if (((neg == 1) && (ret == 0)) || + ((neg == 0) && (ret == 1))) + return(1); + } + return(0); + } else if ((range1->type == XML_REGEXP_BLOCK_NAME) || + (range2->type == XML_REGEXP_BLOCK_NAME)) { + if (range1->type == range2->type) { + ret = xmlStrEqual(range1->blockName, range2->blockName); + } else { + /* + * comparing a block range with anything else is way + * too costly, and maintining the table is like too much + * memory too, so let's force the automata to save state + * here. + */ + return(1); + } + } else if ((range1->type < XML_REGEXP_LETTER) || + (range2->type < XML_REGEXP_LETTER)) { + if ((range1->type == XML_REGEXP_ANYSPACE) && + (range2->type == XML_REGEXP_NOTSPACE)) + ret = 0; + else if ((range1->type == XML_REGEXP_INITNAME) && + (range2->type == XML_REGEXP_NOTINITNAME)) + ret = 0; + else if ((range1->type == XML_REGEXP_NAMECHAR) && + (range2->type == XML_REGEXP_NOTNAMECHAR)) + ret = 0; + else if ((range1->type == XML_REGEXP_DECIMAL) && + (range2->type == XML_REGEXP_NOTDECIMAL)) + ret = 0; + else if ((range1->type == XML_REGEXP_REALCHAR) && + (range2->type == XML_REGEXP_NOTREALCHAR)) + ret = 0; + else { + /* same thing to limit complexity */ + return(1); + } + } else { + ret = 0; + /* range1->type < range2->type here */ + switch (range1->type) { + case XML_REGEXP_LETTER: + /* all disjoint except in the subgroups */ + if ((range2->type == XML_REGEXP_LETTER_UPPERCASE) || + (range2->type == XML_REGEXP_LETTER_LOWERCASE) || + (range2->type == XML_REGEXP_LETTER_TITLECASE) || + (range2->type == XML_REGEXP_LETTER_MODIFIER) || + (range2->type == XML_REGEXP_LETTER_OTHERS)) + ret = 1; + break; + case XML_REGEXP_MARK: + if ((range2->type == XML_REGEXP_MARK_NONSPACING) || + (range2->type == XML_REGEXP_MARK_SPACECOMBINING) || + (range2->type == XML_REGEXP_MARK_ENCLOSING)) + ret = 1; + break; + case XML_REGEXP_NUMBER: + if ((range2->type == XML_REGEXP_NUMBER_DECIMAL) || + (range2->type == XML_REGEXP_NUMBER_LETTER) || + (range2->type == XML_REGEXP_NUMBER_OTHERS)) + ret = 1; + break; + case XML_REGEXP_PUNCT: + if ((range2->type == XML_REGEXP_PUNCT_CONNECTOR) || + (range2->type == XML_REGEXP_PUNCT_DASH) || + (range2->type == XML_REGEXP_PUNCT_OPEN) || + (range2->type == XML_REGEXP_PUNCT_CLOSE) || + (range2->type == XML_REGEXP_PUNCT_INITQUOTE) || + (range2->type == XML_REGEXP_PUNCT_FINQUOTE) || + (range2->type == XML_REGEXP_PUNCT_OTHERS)) + ret = 1; + break; + case XML_REGEXP_SEPAR: + if ((range2->type == XML_REGEXP_SEPAR_SPACE) || + (range2->type == XML_REGEXP_SEPAR_LINE) || + (range2->type == XML_REGEXP_SEPAR_PARA)) + ret = 1; + break; + case XML_REGEXP_SYMBOL: + if ((range2->type == XML_REGEXP_SYMBOL_MATH) || + (range2->type == XML_REGEXP_SYMBOL_CURRENCY) || + (range2->type == XML_REGEXP_SYMBOL_MODIFIER) || + (range2->type == XML_REGEXP_SYMBOL_OTHERS)) + ret = 1; + break; + case XML_REGEXP_OTHER: + if ((range2->type == XML_REGEXP_OTHER_CONTROL) || + (range2->type == XML_REGEXP_OTHER_FORMAT) || + (range2->type == XML_REGEXP_OTHER_PRIVATE)) + ret = 1; + break; + default: + if ((range2->type >= XML_REGEXP_LETTER) && + (range2->type < XML_REGEXP_BLOCK_NAME)) + ret = 0; + else { + /* safety net ! */ + return(1); + } + } + } + if (((range1->neg == 0) && (range2->neg != 0)) || + ((range1->neg != 0) && (range2->neg == 0))) + ret = !ret; + return(ret); +} + +/** + * xmlFACompareAtomTypes: + * @type1: an atom type + * @type2: an atom type + * + * Compares two atoms type to check whether they intersect in some ways, + * this is used by xmlFACompareAtoms only + * + * Returns 1 if they may intersect and 0 otherwise + */ +static int +xmlFACompareAtomTypes(xmlRegAtomType type1, xmlRegAtomType type2) { + if ((type1 == XML_REGEXP_EPSILON) || + (type1 == XML_REGEXP_CHARVAL) || + (type1 == XML_REGEXP_RANGES) || + (type1 == XML_REGEXP_SUBREG) || + (type1 == XML_REGEXP_STRING) || + (type1 == XML_REGEXP_ANYCHAR)) + return(1); + if ((type2 == XML_REGEXP_EPSILON) || + (type2 == XML_REGEXP_CHARVAL) || + (type2 == XML_REGEXP_RANGES) || + (type2 == XML_REGEXP_SUBREG) || + (type2 == XML_REGEXP_STRING) || + (type2 == XML_REGEXP_ANYCHAR)) + return(1); + + if (type1 == type2) return(1); + + /* simplify subsequent compares by making sure type1 < type2 */ + if (type1 > type2) { + xmlRegAtomType tmp = type1; + type1 = type2; + type2 = tmp; + } + switch (type1) { + case XML_REGEXP_ANYSPACE: /* \s */ + /* can't be a letter, number, mark, pontuation, symbol */ + if ((type2 == XML_REGEXP_NOTSPACE) || + ((type2 >= XML_REGEXP_LETTER) && + (type2 <= XML_REGEXP_LETTER_OTHERS)) || + ((type2 >= XML_REGEXP_NUMBER) && + (type2 <= XML_REGEXP_NUMBER_OTHERS)) || + ((type2 >= XML_REGEXP_MARK) && + (type2 <= XML_REGEXP_MARK_ENCLOSING)) || + ((type2 >= XML_REGEXP_PUNCT) && + (type2 <= XML_REGEXP_PUNCT_OTHERS)) || + ((type2 >= XML_REGEXP_SYMBOL) && + (type2 <= XML_REGEXP_SYMBOL_OTHERS)) + ) return(0); + break; + case XML_REGEXP_NOTSPACE: /* \S */ + break; + case XML_REGEXP_INITNAME: /* \l */ + /* can't be a number, mark, separator, pontuation, symbol or other */ + if ((type2 == XML_REGEXP_NOTINITNAME) || + ((type2 >= XML_REGEXP_NUMBER) && + (type2 <= XML_REGEXP_NUMBER_OTHERS)) || + ((type2 >= XML_REGEXP_MARK) && + (type2 <= XML_REGEXP_MARK_ENCLOSING)) || + ((type2 >= XML_REGEXP_SEPAR) && + (type2 <= XML_REGEXP_SEPAR_PARA)) || + ((type2 >= XML_REGEXP_PUNCT) && + (type2 <= XML_REGEXP_PUNCT_OTHERS)) || + ((type2 >= XML_REGEXP_SYMBOL) && + (type2 <= XML_REGEXP_SYMBOL_OTHERS)) || + ((type2 >= XML_REGEXP_OTHER) && + (type2 <= XML_REGEXP_OTHER_NA)) + ) return(0); + break; + case XML_REGEXP_NOTINITNAME: /* \L */ + break; + case XML_REGEXP_NAMECHAR: /* \c */ + /* can't be a mark, separator, pontuation, symbol or other */ + if ((type2 == XML_REGEXP_NOTNAMECHAR) || + ((type2 >= XML_REGEXP_MARK) && + (type2 <= XML_REGEXP_MARK_ENCLOSING)) || + ((type2 >= XML_REGEXP_PUNCT) && + (type2 <= XML_REGEXP_PUNCT_OTHERS)) || + ((type2 >= XML_REGEXP_SEPAR) && + (type2 <= XML_REGEXP_SEPAR_PARA)) || + ((type2 >= XML_REGEXP_SYMBOL) && + (type2 <= XML_REGEXP_SYMBOL_OTHERS)) || + ((type2 >= XML_REGEXP_OTHER) && + (type2 <= XML_REGEXP_OTHER_NA)) + ) return(0); + break; + case XML_REGEXP_NOTNAMECHAR: /* \C */ + break; + case XML_REGEXP_DECIMAL: /* \d */ + /* can't be a letter, mark, separator, pontuation, symbol or other */ + if ((type2 == XML_REGEXP_NOTDECIMAL) || + (type2 == XML_REGEXP_REALCHAR) || + ((type2 >= XML_REGEXP_LETTER) && + (type2 <= XML_REGEXP_LETTER_OTHERS)) || + ((type2 >= XML_REGEXP_MARK) && + (type2 <= XML_REGEXP_MARK_ENCLOSING)) || + ((type2 >= XML_REGEXP_PUNCT) && + (type2 <= XML_REGEXP_PUNCT_OTHERS)) || + ((type2 >= XML_REGEXP_SEPAR) && + (type2 <= XML_REGEXP_SEPAR_PARA)) || + ((type2 >= XML_REGEXP_SYMBOL) && + (type2 <= XML_REGEXP_SYMBOL_OTHERS)) || + ((type2 >= XML_REGEXP_OTHER) && + (type2 <= XML_REGEXP_OTHER_NA)) + )return(0); + break; + case XML_REGEXP_NOTDECIMAL: /* \D */ + break; + case XML_REGEXP_REALCHAR: /* \w */ + /* can't be a mark, separator, pontuation, symbol or other */ + if ((type2 == XML_REGEXP_NOTDECIMAL) || + ((type2 >= XML_REGEXP_MARK) && + (type2 <= XML_REGEXP_MARK_ENCLOSING)) || + ((type2 >= XML_REGEXP_PUNCT) && + (type2 <= XML_REGEXP_PUNCT_OTHERS)) || + ((type2 >= XML_REGEXP_SEPAR) && + (type2 <= XML_REGEXP_SEPAR_PARA)) || + ((type2 >= XML_REGEXP_SYMBOL) && + (type2 <= XML_REGEXP_SYMBOL_OTHERS)) || + ((type2 >= XML_REGEXP_OTHER) && + (type2 <= XML_REGEXP_OTHER_NA)) + )return(0); + break; + case XML_REGEXP_NOTREALCHAR: /* \W */ + break; + /* + * at that point we know both type 1 and type2 are from + * character categories are ordered and are different, + * it becomes simple because this is a partition + */ + case XML_REGEXP_LETTER: + if (type2 <= XML_REGEXP_LETTER_OTHERS) + return(1); + return(0); + case XML_REGEXP_LETTER_UPPERCASE: + case XML_REGEXP_LETTER_LOWERCASE: + case XML_REGEXP_LETTER_TITLECASE: + case XML_REGEXP_LETTER_MODIFIER: + case XML_REGEXP_LETTER_OTHERS: + return(0); + case XML_REGEXP_MARK: + if (type2 <= XML_REGEXP_MARK_ENCLOSING) + return(1); + return(0); + case XML_REGEXP_MARK_NONSPACING: + case XML_REGEXP_MARK_SPACECOMBINING: + case XML_REGEXP_MARK_ENCLOSING: + return(0); + case XML_REGEXP_NUMBER: + if (type2 <= XML_REGEXP_NUMBER_OTHERS) + return(1); + return(0); + case XML_REGEXP_NUMBER_DECIMAL: + case XML_REGEXP_NUMBER_LETTER: + case XML_REGEXP_NUMBER_OTHERS: + return(0); + case XML_REGEXP_PUNCT: + if (type2 <= XML_REGEXP_PUNCT_OTHERS) + return(1); + return(0); + case XML_REGEXP_PUNCT_CONNECTOR: + case XML_REGEXP_PUNCT_DASH: + case XML_REGEXP_PUNCT_OPEN: + case XML_REGEXP_PUNCT_CLOSE: + case XML_REGEXP_PUNCT_INITQUOTE: + case XML_REGEXP_PUNCT_FINQUOTE: + case XML_REGEXP_PUNCT_OTHERS: + return(0); + case XML_REGEXP_SEPAR: + if (type2 <= XML_REGEXP_SEPAR_PARA) + return(1); + return(0); + case XML_REGEXP_SEPAR_SPACE: + case XML_REGEXP_SEPAR_LINE: + case XML_REGEXP_SEPAR_PARA: + return(0); + case XML_REGEXP_SYMBOL: + if (type2 <= XML_REGEXP_SYMBOL_OTHERS) + return(1); + return(0); + case XML_REGEXP_SYMBOL_MATH: + case XML_REGEXP_SYMBOL_CURRENCY: + case XML_REGEXP_SYMBOL_MODIFIER: + case XML_REGEXP_SYMBOL_OTHERS: + return(0); + case XML_REGEXP_OTHER: + if (type2 <= XML_REGEXP_OTHER_NA) + return(1); + return(0); + case XML_REGEXP_OTHER_CONTROL: + case XML_REGEXP_OTHER_FORMAT: + case XML_REGEXP_OTHER_PRIVATE: + case XML_REGEXP_OTHER_NA: + return(0); + default: + break; + } + return(1); +} + +/** + * xmlFAEqualAtoms: + * @atom1: an atom + * @atom2: an atom + * @deep: if not set only compare string pointers + * + * Compares two atoms to check whether they are the same exactly + * this is used to remove equivalent transitions + * + * Returns 1 if same and 0 otherwise + */ +static int +xmlFAEqualAtoms(xmlRegAtomPtr atom1, xmlRegAtomPtr atom2, int deep) { + int ret = 0; + + if (atom1 == atom2) + return(1); + if ((atom1 == NULL) || (atom2 == NULL)) + return(0); + + if (atom1->type != atom2->type) + return(0); + switch (atom1->type) { + case XML_REGEXP_EPSILON: + ret = 0; + break; + case XML_REGEXP_STRING: + if (!deep) + ret = (atom1->valuep == atom2->valuep); + else + ret = xmlStrEqual((xmlChar *)atom1->valuep, + (xmlChar *)atom2->valuep); + break; + case XML_REGEXP_CHARVAL: + ret = (atom1->codepoint == atom2->codepoint); + break; + case XML_REGEXP_RANGES: + /* too hard to do in the general case */ + ret = 0; + default: + break; + } + return(ret); +} + +/** + * xmlFACompareAtoms: + * @atom1: an atom + * @atom2: an atom + * @deep: if not set only compare string pointers + * + * Compares two atoms to check whether they intersect in some ways, + * this is used by xmlFAComputesDeterminism and xmlFARecurseDeterminism only + * + * Returns 1 if yes and 0 otherwise + */ +static int +xmlFACompareAtoms(xmlRegAtomPtr atom1, xmlRegAtomPtr atom2, int deep) { + int ret = 1; + + if (atom1 == atom2) + return(1); + if ((atom1 == NULL) || (atom2 == NULL)) + return(0); + + if ((atom1->type == XML_REGEXP_ANYCHAR) || + (atom2->type == XML_REGEXP_ANYCHAR)) + return(1); + + if (atom1->type > atom2->type) { + xmlRegAtomPtr tmp; + tmp = atom1; + atom1 = atom2; + atom2 = tmp; + } + if (atom1->type != atom2->type) { + ret = xmlFACompareAtomTypes(atom1->type, atom2->type); + /* if they can't intersect at the type level break now */ + if (ret == 0) + return(0); + } + switch (atom1->type) { + case XML_REGEXP_STRING: + if (!deep) + ret = (atom1->valuep != atom2->valuep); + else + ret = xmlRegStrEqualWildcard((xmlChar *)atom1->valuep, + (xmlChar *)atom2->valuep); + break; + case XML_REGEXP_EPSILON: + goto not_determinist; + case XML_REGEXP_CHARVAL: + if (atom2->type == XML_REGEXP_CHARVAL) { + ret = (atom1->codepoint == atom2->codepoint); + } else { + ret = xmlRegCheckCharacter(atom2, atom1->codepoint); + if (ret < 0) + ret = 1; + } + break; + case XML_REGEXP_RANGES: + if (atom2->type == XML_REGEXP_RANGES) { + int i, j, res; + xmlRegRangePtr r1, r2; + + /* + * need to check that none of the ranges eventually matches + */ + for (i = 0;i < atom1->nbRanges;i++) { + for (j = 0;j < atom2->nbRanges;j++) { + r1 = atom1->ranges[i]; + r2 = atom2->ranges[j]; + res = xmlFACompareRanges(r1, r2); + if (res == 1) { + ret = 1; + goto done; + } + } + } + ret = 0; + } + break; + default: + goto not_determinist; + } +done: + if (atom1->neg != atom2->neg) { + ret = !ret; + } + if (ret == 0) + return(0); +not_determinist: + return(1); +} + +/** + * xmlFARecurseDeterminism: + * @ctxt: a regexp parser context + * + * Check whether the associated regexp is determinist, + * should be called after xmlFAEliminateEpsilonTransitions() + * + */ +static int +xmlFARecurseDeterminism(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr state, + int to, xmlRegAtomPtr atom) { + int ret = 1; + int res; + int transnr, nbTrans; + xmlRegTransPtr t1; + int deep = 1; + + if (state == NULL) + return(ret); + + if (ctxt->flags & AM_AUTOMATA_RNG) + deep = 0; + + /* + * don't recurse on transitions potentially added in the course of + * the elimination. + */ + nbTrans = state->nbTrans; + for (transnr = 0;transnr < nbTrans;transnr++) { + t1 = &(state->trans[transnr]); + /* + * check transitions conflicting with the one looked at + */ + if (t1->atom == NULL) { + if (t1->to < 0) + continue; + res = xmlFARecurseDeterminism(ctxt, ctxt->states[t1->to], + to, atom); + if (res == 0) { + ret = 0; + /* t1->nd = 1; */ + } + continue; + } + if (t1->to != to) + continue; + if (xmlFACompareAtoms(t1->atom, atom, deep)) { + ret = 0; + /* mark the transition as non-deterministic */ + t1->nd = 1; + } + } + return(ret); +} + +/** + * xmlFAComputesDeterminism: + * @ctxt: a regexp parser context + * + * Check whether the associated regexp is determinist, + * should be called after xmlFAEliminateEpsilonTransitions() + * + */ +static int +xmlFAComputesDeterminism(xmlRegParserCtxtPtr ctxt) { + int statenr, transnr; + xmlRegStatePtr state; + xmlRegTransPtr t1, t2, last; + int i; + int ret = 1; + int deep = 1; + +#ifdef DEBUG_REGEXP_GRAPH + printf("xmlFAComputesDeterminism\n"); + xmlRegPrintCtxt(stdout, ctxt); +#endif + if (ctxt->determinist != -1) + return(ctxt->determinist); + + if (ctxt->flags & AM_AUTOMATA_RNG) + deep = 0; + + /* + * First cleanup the automata removing cancelled transitions + */ + for (statenr = 0;statenr < ctxt->nbStates;statenr++) { + state = ctxt->states[statenr]; + if (state == NULL) + continue; + if (state->nbTrans < 2) + continue; + for (transnr = 0;transnr < state->nbTrans;transnr++) { + t1 = &(state->trans[transnr]); + /* + * Determinism checks in case of counted or all transitions + * will have to be handled separately + */ + if (t1->atom == NULL) { + /* t1->nd = 1; */ + continue; + } + if (t1->to == -1) /* eliminated */ + continue; + for (i = 0;i < transnr;i++) { + t2 = &(state->trans[i]); + if (t2->to == -1) /* eliminated */ + continue; + if (t2->atom != NULL) { + if (t1->to == t2->to) { + /* + * Here we use deep because we want to keep the + * transitions which indicate a conflict + */ + if (xmlFAEqualAtoms(t1->atom, t2->atom, deep) && + (t1->counter == t2->counter) && + (t1->count == t2->count)) + t2->to = -1; /* eliminated */ + } + } + } + } + } + + /* + * Check for all states that there aren't 2 transitions + * with the same atom and a different target. + */ + for (statenr = 0;statenr < ctxt->nbStates;statenr++) { + state = ctxt->states[statenr]; + if (state == NULL) + continue; + if (state->nbTrans < 2) + continue; + last = NULL; + for (transnr = 0;transnr < state->nbTrans;transnr++) { + t1 = &(state->trans[transnr]); + /* + * Determinism checks in case of counted or all transitions + * will have to be handled separately + */ + if (t1->atom == NULL) { + continue; + } + if (t1->to == -1) /* eliminated */ + continue; + for (i = 0;i < transnr;i++) { + t2 = &(state->trans[i]); + if (t2->to == -1) /* eliminated */ + continue; + if (t2->atom != NULL) { + /* + * But here we don't use deep because we want to + * find transitions which indicate a conflict + */ + if (xmlFACompareAtoms(t1->atom, t2->atom, 1)) { + ret = 0; + /* mark the transitions as non-deterministic ones */ + t1->nd = 1; + t2->nd = 1; + last = t1; + } + } else if (t1->to != -1) { + /* + * do the closure in case of remaining specific + * epsilon transitions like choices or all + */ + ret = xmlFARecurseDeterminism(ctxt, ctxt->states[t1->to], + t2->to, t2->atom); + /* don't shortcut the computation so all non deterministic + transition get marked down + if (ret == 0) + return(0); + */ + if (ret == 0) { + t1->nd = 1; + /* t2->nd = 1; */ + last = t1; + } + } + } + /* don't shortcut the computation so all non deterministic + transition get marked down + if (ret == 0) + break; */ + } + + /* + * mark specifically the last non-deterministic transition + * from a state since there is no need to set-up rollback + * from it + */ + if (last != NULL) { + last->nd = 2; + } + + /* don't shortcut the computation so all non deterministic + transition get marked down + if (ret == 0) + break; */ + } + + ctxt->determinist = ret; + return(ret); +} + +/************************************************************************ + * * + * Routines to check input against transition atoms * + * * + ************************************************************************/ + +static int +xmlRegCheckCharacterRange(xmlRegAtomType type, int codepoint, int neg, + int start, int end, const xmlChar *blockName) { + int ret = 0; + + switch (type) { + case XML_REGEXP_STRING: + case XML_REGEXP_SUBREG: + case XML_REGEXP_RANGES: + case XML_REGEXP_EPSILON: + return(-1); + case XML_REGEXP_ANYCHAR: + ret = ((codepoint != '\n') && (codepoint != '\r')); + break; + case XML_REGEXP_CHARVAL: + ret = ((codepoint >= start) && (codepoint <= end)); + break; + case XML_REGEXP_NOTSPACE: + neg = !neg; + case XML_REGEXP_ANYSPACE: + ret = ((codepoint == '\n') || (codepoint == '\r') || + (codepoint == '\t') || (codepoint == ' ')); + break; + case XML_REGEXP_NOTINITNAME: + neg = !neg; + case XML_REGEXP_INITNAME: + ret = (IS_LETTER(codepoint) || + (codepoint == '_') || (codepoint == ':')); + break; + case XML_REGEXP_NOTNAMECHAR: + neg = !neg; + case XML_REGEXP_NAMECHAR: + ret = (IS_LETTER(codepoint) || IS_DIGIT(codepoint) || + (codepoint == '.') || (codepoint == '-') || + (codepoint == '_') || (codepoint == ':') || + IS_COMBINING(codepoint) || IS_EXTENDER(codepoint)); + break; + case XML_REGEXP_NOTDECIMAL: + neg = !neg; + case XML_REGEXP_DECIMAL: + ret = xmlUCSIsCatNd(codepoint); + break; + case XML_REGEXP_REALCHAR: + neg = !neg; + case XML_REGEXP_NOTREALCHAR: + ret = xmlUCSIsCatP(codepoint); + if (ret == 0) + ret = xmlUCSIsCatZ(codepoint); + if (ret == 0) + ret = xmlUCSIsCatC(codepoint); + break; + case XML_REGEXP_LETTER: + ret = xmlUCSIsCatL(codepoint); + break; + case XML_REGEXP_LETTER_UPPERCASE: + ret = xmlUCSIsCatLu(codepoint); + break; + case XML_REGEXP_LETTER_LOWERCASE: + ret = xmlUCSIsCatLl(codepoint); + break; + case XML_REGEXP_LETTER_TITLECASE: + ret = xmlUCSIsCatLt(codepoint); + break; + case XML_REGEXP_LETTER_MODIFIER: + ret = xmlUCSIsCatLm(codepoint); + break; + case XML_REGEXP_LETTER_OTHERS: + ret = xmlUCSIsCatLo(codepoint); + break; + case XML_REGEXP_MARK: + ret = xmlUCSIsCatM(codepoint); + break; + case XML_REGEXP_MARK_NONSPACING: + ret = xmlUCSIsCatMn(codepoint); + break; + case XML_REGEXP_MARK_SPACECOMBINING: + ret = xmlUCSIsCatMc(codepoint); + break; + case XML_REGEXP_MARK_ENCLOSING: + ret = xmlUCSIsCatMe(codepoint); + break; + case XML_REGEXP_NUMBER: + ret = xmlUCSIsCatN(codepoint); + break; + case XML_REGEXP_NUMBER_DECIMAL: + ret = xmlUCSIsCatNd(codepoint); + break; + case XML_REGEXP_NUMBER_LETTER: + ret = xmlUCSIsCatNl(codepoint); + break; + case XML_REGEXP_NUMBER_OTHERS: + ret = xmlUCSIsCatNo(codepoint); + break; + case XML_REGEXP_PUNCT: + ret = xmlUCSIsCatP(codepoint); + break; + case XML_REGEXP_PUNCT_CONNECTOR: + ret = xmlUCSIsCatPc(codepoint); + break; + case XML_REGEXP_PUNCT_DASH: + ret = xmlUCSIsCatPd(codepoint); + break; + case XML_REGEXP_PUNCT_OPEN: + ret = xmlUCSIsCatPs(codepoint); + break; + case XML_REGEXP_PUNCT_CLOSE: + ret = xmlUCSIsCatPe(codepoint); + break; + case XML_REGEXP_PUNCT_INITQUOTE: + ret = xmlUCSIsCatPi(codepoint); + break; + case XML_REGEXP_PUNCT_FINQUOTE: + ret = xmlUCSIsCatPf(codepoint); + break; + case XML_REGEXP_PUNCT_OTHERS: + ret = xmlUCSIsCatPo(codepoint); + break; + case XML_REGEXP_SEPAR: + ret = xmlUCSIsCatZ(codepoint); + break; + case XML_REGEXP_SEPAR_SPACE: + ret = xmlUCSIsCatZs(codepoint); + break; + case XML_REGEXP_SEPAR_LINE: + ret = xmlUCSIsCatZl(codepoint); + break; + case XML_REGEXP_SEPAR_PARA: + ret = xmlUCSIsCatZp(codepoint); + break; + case XML_REGEXP_SYMBOL: + ret = xmlUCSIsCatS(codepoint); + break; + case XML_REGEXP_SYMBOL_MATH: + ret = xmlUCSIsCatSm(codepoint); + break; + case XML_REGEXP_SYMBOL_CURRENCY: + ret = xmlUCSIsCatSc(codepoint); + break; + case XML_REGEXP_SYMBOL_MODIFIER: + ret = xmlUCSIsCatSk(codepoint); + break; + case XML_REGEXP_SYMBOL_OTHERS: + ret = xmlUCSIsCatSo(codepoint); + break; + case XML_REGEXP_OTHER: + ret = xmlUCSIsCatC(codepoint); + break; + case XML_REGEXP_OTHER_CONTROL: + ret = xmlUCSIsCatCc(codepoint); + break; + case XML_REGEXP_OTHER_FORMAT: + ret = xmlUCSIsCatCf(codepoint); + break; + case XML_REGEXP_OTHER_PRIVATE: + ret = xmlUCSIsCatCo(codepoint); + break; + case XML_REGEXP_OTHER_NA: + /* ret = xmlUCSIsCatCn(codepoint); */ + /* Seems it doesn't exist anymore in recent Unicode releases */ + ret = 0; + break; + case XML_REGEXP_BLOCK_NAME: + ret = xmlUCSIsBlock(codepoint, (const char *) blockName); + break; + } + if (neg) + return(!ret); + return(ret); +} + +static int +xmlRegCheckCharacter(xmlRegAtomPtr atom, int codepoint) { + int i, ret = 0; + xmlRegRangePtr range; + + if ((atom == NULL) || (!IS_CHAR(codepoint))) + return(-1); + + switch (atom->type) { + case XML_REGEXP_SUBREG: + case XML_REGEXP_EPSILON: + return(-1); + case XML_REGEXP_CHARVAL: + return(codepoint == atom->codepoint); + case XML_REGEXP_RANGES: { + int accept = 0; + + for (i = 0;i < atom->nbRanges;i++) { + range = atom->ranges[i]; + if (range->neg == 2) { + ret = xmlRegCheckCharacterRange(range->type, codepoint, + 0, range->start, range->end, + range->blockName); + if (ret != 0) + return(0); /* excluded char */ + } else if (range->neg) { + ret = xmlRegCheckCharacterRange(range->type, codepoint, + 0, range->start, range->end, + range->blockName); + if (ret == 0) + accept = 1; + else + return(0); + } else { + ret = xmlRegCheckCharacterRange(range->type, codepoint, + 0, range->start, range->end, + range->blockName); + if (ret != 0) + accept = 1; /* might still be excluded */ + } + } + return(accept); + } + case XML_REGEXP_STRING: + printf("TODO: XML_REGEXP_STRING\n"); + return(-1); + case XML_REGEXP_ANYCHAR: + case XML_REGEXP_ANYSPACE: + case XML_REGEXP_NOTSPACE: + case XML_REGEXP_INITNAME: + case XML_REGEXP_NOTINITNAME: + case XML_REGEXP_NAMECHAR: + case XML_REGEXP_NOTNAMECHAR: + case XML_REGEXP_DECIMAL: + case XML_REGEXP_NOTDECIMAL: + case XML_REGEXP_REALCHAR: + case XML_REGEXP_NOTREALCHAR: + case XML_REGEXP_LETTER: + case XML_REGEXP_LETTER_UPPERCASE: + case XML_REGEXP_LETTER_LOWERCASE: + case XML_REGEXP_LETTER_TITLECASE: + case XML_REGEXP_LETTER_MODIFIER: + case XML_REGEXP_LETTER_OTHERS: + case XML_REGEXP_MARK: + case XML_REGEXP_MARK_NONSPACING: + case XML_REGEXP_MARK_SPACECOMBINING: + case XML_REGEXP_MARK_ENCLOSING: + case XML_REGEXP_NUMBER: + case XML_REGEXP_NUMBER_DECIMAL: + case XML_REGEXP_NUMBER_LETTER: + case XML_REGEXP_NUMBER_OTHERS: + case XML_REGEXP_PUNCT: + case XML_REGEXP_PUNCT_CONNECTOR: + case XML_REGEXP_PUNCT_DASH: + case XML_REGEXP_PUNCT_OPEN: + case XML_REGEXP_PUNCT_CLOSE: + case XML_REGEXP_PUNCT_INITQUOTE: + case XML_REGEXP_PUNCT_FINQUOTE: + case XML_REGEXP_PUNCT_OTHERS: + case XML_REGEXP_SEPAR: + case XML_REGEXP_SEPAR_SPACE: + case XML_REGEXP_SEPAR_LINE: + case XML_REGEXP_SEPAR_PARA: + case XML_REGEXP_SYMBOL: + case XML_REGEXP_SYMBOL_MATH: + case XML_REGEXP_SYMBOL_CURRENCY: + case XML_REGEXP_SYMBOL_MODIFIER: + case XML_REGEXP_SYMBOL_OTHERS: + case XML_REGEXP_OTHER: + case XML_REGEXP_OTHER_CONTROL: + case XML_REGEXP_OTHER_FORMAT: + case XML_REGEXP_OTHER_PRIVATE: + case XML_REGEXP_OTHER_NA: + case XML_REGEXP_BLOCK_NAME: + ret = xmlRegCheckCharacterRange(atom->type, codepoint, 0, 0, 0, + (const xmlChar *)atom->valuep); + if (atom->neg) + ret = !ret; + break; + } + return(ret); +} + +/************************************************************************ + * * + * Saving and restoring state of an execution context * + * * + ************************************************************************/ + +#ifdef DEBUG_REGEXP_EXEC +static void +xmlFARegDebugExec(xmlRegExecCtxtPtr exec) { + printf("state: %d:%d:idx %d", exec->state->no, exec->transno, exec->index); + if (exec->inputStack != NULL) { + int i; + printf(": "); + for (i = 0;(i < 3) && (i < exec->inputStackNr);i++) + printf("%s ", (const char *) + exec->inputStack[exec->inputStackNr - (i + 1)].value); + } else { + printf(": %s", &(exec->inputString[exec->index])); + } + printf("\n"); +} +#endif + +static void +xmlFARegExecSave(xmlRegExecCtxtPtr exec) { +#ifdef DEBUG_REGEXP_EXEC + printf("saving "); + exec->transno++; + xmlFARegDebugExec(exec); + exec->transno--; +#endif +#ifdef MAX_PUSH + if (exec->nbPush > MAX_PUSH) { + return; + } + exec->nbPush++; +#endif + + if (exec->maxRollbacks == 0) { + exec->maxRollbacks = 4; + exec->rollbacks = (xmlRegExecRollback *) xmlMalloc(exec->maxRollbacks * + sizeof(xmlRegExecRollback)); + if (exec->rollbacks == NULL) { + xmlRegexpErrMemory(NULL, "saving regexp"); + exec->maxRollbacks = 0; + return; + } + memset(exec->rollbacks, 0, + exec->maxRollbacks * sizeof(xmlRegExecRollback)); + } else if (exec->nbRollbacks >= exec->maxRollbacks) { + xmlRegExecRollback *tmp; + int len = exec->maxRollbacks; + + exec->maxRollbacks *= 2; + tmp = (xmlRegExecRollback *) xmlRealloc(exec->rollbacks, + exec->maxRollbacks * sizeof(xmlRegExecRollback)); + if (tmp == NULL) { + xmlRegexpErrMemory(NULL, "saving regexp"); + exec->maxRollbacks /= 2; + return; + } + exec->rollbacks = tmp; + tmp = &exec->rollbacks[len]; + memset(tmp, 0, (exec->maxRollbacks - len) * sizeof(xmlRegExecRollback)); + } + exec->rollbacks[exec->nbRollbacks].state = exec->state; + exec->rollbacks[exec->nbRollbacks].index = exec->index; + exec->rollbacks[exec->nbRollbacks].nextbranch = exec->transno + 1; + if (exec->comp->nbCounters > 0) { + if (exec->rollbacks[exec->nbRollbacks].counts == NULL) { + 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 = -5; + return; + } + } + memcpy(exec->rollbacks[exec->nbRollbacks].counts, exec->counts, + exec->comp->nbCounters * sizeof(int)); + } + exec->nbRollbacks++; +} + +static void +xmlFARegExecRollBack(xmlRegExecCtxtPtr exec) { + if (exec->nbRollbacks <= 0) { + exec->status = -1; +#ifdef DEBUG_REGEXP_EXEC + printf("rollback failed on empty stack\n"); +#endif + return; + } + exec->nbRollbacks--; + exec->state = exec->rollbacks[exec->nbRollbacks].state; + exec->index = exec->rollbacks[exec->nbRollbacks].index; + exec->transno = exec->rollbacks[exec->nbRollbacks].nextbranch; + if (exec->comp->nbCounters > 0) { + if (exec->rollbacks[exec->nbRollbacks].counts == NULL) { + fprintf(stderr, "exec save: allocation failed"); + exec->status = -6; + return; + } + memcpy(exec->counts, exec->rollbacks[exec->nbRollbacks].counts, + exec->comp->nbCounters * sizeof(int)); + } + +#ifdef DEBUG_REGEXP_EXEC + printf("restored "); + xmlFARegDebugExec(exec); +#endif +} + +/************************************************************************ + * * + * Verifier, running an input against a compiled regexp * + * * + ************************************************************************/ + +static int +xmlFARegExec(xmlRegexpPtr comp, const xmlChar *content) { + xmlRegExecCtxt execval; + xmlRegExecCtxtPtr exec = &execval; + int ret, codepoint = 0, len, deter; + + exec->inputString = content; + exec->index = 0; + exec->nbPush = 0; + exec->determinist = 1; + exec->maxRollbacks = 0; + exec->nbRollbacks = 0; + exec->rollbacks = NULL; + exec->status = 0; + exec->comp = comp; + exec->state = comp->states[0]; + exec->transno = 0; + exec->transcount = 0; + exec->inputStack = NULL; + exec->inputStackMax = 0; + if (comp->nbCounters > 0) { + exec->counts = (int *) xmlMalloc(comp->nbCounters * sizeof(int)); + if (exec->counts == NULL) { + xmlRegexpErrMemory(NULL, "running regexp"); + return(-1); + } + memset(exec->counts, 0, comp->nbCounters * sizeof(int)); + } else + exec->counts = NULL; + while ((exec->status == 0) && + ((exec->inputString[exec->index] != 0) || + ((exec->state != NULL) && + (exec->state->type != XML_REGEXP_FINAL_STATE)))) { + xmlRegTransPtr trans; + xmlRegAtomPtr atom; + + /* + * If end of input on non-terminal state, rollback, however we may + * still have epsilon like transition for counted transitions + * on counters, in that case don't break too early. Additionally, + * if we are working on a range like "AB{0,2}", where B is not present, + * we don't want to break. + */ + len = 1; + if ((exec->inputString[exec->index] == 0) && (exec->counts == NULL)) { + /* + * if there is a transition, we must check if + * atom allows minOccurs of 0 + */ + if (exec->transno < exec->state->nbTrans) { + trans = &exec->state->trans[exec->transno]; + if (trans->to >=0) { + atom = trans->atom; + if (!((atom->min == 0) && (atom->max > 0))) + goto rollback; + } + } else + goto rollback; + } + + exec->transcount = 0; + for (;exec->transno < exec->state->nbTrans;exec->transno++) { + trans = &exec->state->trans[exec->transno]; + if (trans->to < 0) + continue; + atom = trans->atom; + ret = 0; + deter = 1; + if (trans->count >= 0) { + int count; + xmlRegCounterPtr counter; + + if (exec->counts == NULL) { + exec->status = -1; + goto error; + } + /* + * A counted transition. + */ + + count = exec->counts[trans->count]; + counter = &exec->comp->counters[trans->count]; +#ifdef DEBUG_REGEXP_EXEC + printf("testing count %d: val %d, min %d, max %d\n", + trans->count, count, counter->min, counter->max); +#endif + ret = ((count >= counter->min) && (count <= counter->max)); + if ((ret) && (counter->min != counter->max)) + deter = 0; + } else if (atom == NULL) { + fprintf(stderr, "epsilon transition left at runtime\n"); + exec->status = -2; + break; + } else if (exec->inputString[exec->index] != 0) { + codepoint = CUR_SCHAR(&(exec->inputString[exec->index]), len); + ret = xmlRegCheckCharacter(atom, codepoint); + if ((ret == 1) && (atom->min >= 0) && (atom->max > 0)) { + xmlRegStatePtr to = comp->states[trans->to]; + + /* + * this is a multiple input sequence + * If there is a counter associated increment it now. + * before potentially saving and rollback + * do not increment if the counter is already over the + * maximum limit in which case get to next transition + */ + if (trans->counter >= 0) { + xmlRegCounterPtr counter; + + if ((exec->counts == NULL) || + (exec->comp == NULL) || + (exec->comp->counters == NULL)) { + exec->status = -1; + goto error; + } + counter = &exec->comp->counters[trans->counter]; + if (exec->counts[trans->counter] >= counter->max) + continue; /* for loop on transitions */ + +#ifdef DEBUG_REGEXP_EXEC + printf("Increasing count %d\n", trans->counter); +#endif + exec->counts[trans->counter]++; + } + if (exec->state->nbTrans > exec->transno + 1) { + xmlFARegExecSave(exec); + } + exec->transcount = 1; + do { + /* + * Try to progress as much as possible on the input + */ + if (exec->transcount == atom->max) { + break; + } + exec->index += len; + /* + * End of input: stop here + */ + if (exec->inputString[exec->index] == 0) { + exec->index -= len; + break; + } + if (exec->transcount >= atom->min) { + int transno = exec->transno; + xmlRegStatePtr state = exec->state; + + /* + * The transition is acceptable save it + */ + exec->transno = -1; /* trick */ + exec->state = to; + xmlFARegExecSave(exec); + exec->transno = transno; + exec->state = state; + } + codepoint = CUR_SCHAR(&(exec->inputString[exec->index]), + len); + ret = xmlRegCheckCharacter(atom, codepoint); + exec->transcount++; + } while (ret == 1); + if (exec->transcount < atom->min) + ret = 0; + + /* + * If the last check failed but one transition was found + * possible, rollback + */ + if (ret < 0) + ret = 0; + if (ret == 0) { + goto rollback; + } + if (trans->counter >= 0) { + if (exec->counts == NULL) { + exec->status = -1; + goto error; + } +#ifdef DEBUG_REGEXP_EXEC + printf("Decreasing count %d\n", trans->counter); +#endif + exec->counts[trans->counter]--; + } + } else if ((ret == 0) && (atom->min == 0) && (atom->max > 0)) { + /* + * we don't match on the codepoint, but minOccurs of 0 + * says that's ok. Setting len to 0 inhibits stepping + * over the codepoint. + */ + exec->transcount = 1; + len = 0; + ret = 1; + } + } else if ((atom->min == 0) && (atom->max > 0)) { + /* another spot to match when minOccurs is 0 */ + exec->transcount = 1; + len = 0; + ret = 1; + } + if (ret == 1) { + if ((trans->nd == 1) || + ((trans->count >= 0) && (deter == 0) && + (exec->state->nbTrans > exec->transno + 1))) { +#ifdef DEBUG_REGEXP_EXEC + if (trans->nd == 1) + printf("Saving on nd transition atom %d for %c at %d\n", + trans->atom->no, codepoint, exec->index); + else + printf("Saving on counted transition count %d for %c at %d\n", + trans->count, codepoint, exec->index); +#endif + xmlFARegExecSave(exec); + } + if (trans->counter >= 0) { + xmlRegCounterPtr counter; + + /* make sure we don't go over the counter maximum value */ + if ((exec->counts == NULL) || + (exec->comp == NULL) || + (exec->comp->counters == NULL)) { + exec->status = -1; + goto error; + } + counter = &exec->comp->counters[trans->counter]; + if (exec->counts[trans->counter] >= counter->max) + continue; /* for loop on transitions */ +#ifdef DEBUG_REGEXP_EXEC + printf("Increasing count %d\n", trans->counter); +#endif + exec->counts[trans->counter]++; + } + if ((trans->count >= 0) && + (trans->count < REGEXP_ALL_COUNTER)) { + if (exec->counts == NULL) { + exec->status = -1; + goto error; + } +#ifdef DEBUG_REGEXP_EXEC + printf("resetting count %d on transition\n", + trans->count); +#endif + exec->counts[trans->count] = 0; + } +#ifdef DEBUG_REGEXP_EXEC + printf("entering state %d\n", trans->to); +#endif + exec->state = comp->states[trans->to]; + exec->transno = 0; + if (trans->atom != NULL) { + exec->index += len; + } + goto progress; + } else if (ret < 0) { + exec->status = -4; + break; + } + } + if ((exec->transno != 0) || (exec->state->nbTrans == 0)) { +rollback: + /* + * Failed to find a way out + */ + exec->determinist = 0; +#ifdef DEBUG_REGEXP_EXEC + printf("rollback from state %d on %d:%c\n", exec->state->no, + codepoint,codepoint); +#endif + xmlFARegExecRollBack(exec); + } +progress: + continue; + } +error: + if (exec->rollbacks != NULL) { + if (exec->counts != NULL) { + int i; + + for (i = 0;i < exec->maxRollbacks;i++) + if (exec->rollbacks[i].counts != NULL) + xmlFree(exec->rollbacks[i].counts); + } + xmlFree(exec->rollbacks); + } + if (exec->counts != NULL) + xmlFree(exec->counts); + if (exec->status == 0) + return(1); + if (exec->status == -1) { + if (exec->nbPush > MAX_PUSH) + return(-1); + return(0); + } + return(exec->status); +} + +/************************************************************************ + * * + * Progressive interface to the verifier one atom at a time * + * * + ************************************************************************/ +#ifdef DEBUG_ERR +static void testerr(xmlRegExecCtxtPtr exec); +#endif + +/** + * xmlRegNewExecCtxt: + * @comp: a precompiled regular expression + * @callback: a callback function used for handling progresses in the + * automata matching phase + * @data: the context data associated to the callback in this context + * + * Build a context used for progressive evaluation of a regexp. + * + * Returns the new context + */ +xmlRegExecCtxtPtr +xmlRegNewExecCtxt(xmlRegexpPtr comp, xmlRegExecCallbacks callback, void *data) { + xmlRegExecCtxtPtr exec; + + if (comp == NULL) + return(NULL); + if ((comp->compact == NULL) && (comp->states == NULL)) + return(NULL); + exec = (xmlRegExecCtxtPtr) xmlMalloc(sizeof(xmlRegExecCtxt)); + if (exec == NULL) { + xmlRegexpErrMemory(NULL, "creating execution context"); + return(NULL); + } + memset(exec, 0, sizeof(xmlRegExecCtxt)); + exec->inputString = NULL; + exec->index = 0; + exec->determinist = 1; + exec->maxRollbacks = 0; + exec->nbRollbacks = 0; + exec->rollbacks = NULL; + exec->status = 0; + exec->comp = comp; + if (comp->compact == NULL) + exec->state = comp->states[0]; + exec->transno = 0; + exec->transcount = 0; + exec->callback = callback; + exec->data = data; + if (comp->nbCounters > 0) { + /* + * For error handling, exec->counts is allocated twice the size + * the second half is used to store the data in case of rollback + */ + exec->counts = (int *) xmlMalloc(comp->nbCounters * sizeof(int) + * 2); + if (exec->counts == NULL) { + xmlRegexpErrMemory(NULL, "creating execution context"); + xmlFree(exec); + return(NULL); + } + memset(exec->counts, 0, comp->nbCounters * sizeof(int) * 2); + exec->errCounts = &exec->counts[comp->nbCounters]; + } else { + exec->counts = NULL; + exec->errCounts = NULL; + } + exec->inputStackMax = 0; + exec->inputStackNr = 0; + exec->inputStack = NULL; + exec->errStateNo = -1; + exec->errString = NULL; + exec->nbPush = 0; + return(exec); +} + +/** + * xmlRegFreeExecCtxt: + * @exec: a regular expression evaulation context + * + * Free the structures associated to a regular expression evaulation context. + */ +void +xmlRegFreeExecCtxt(xmlRegExecCtxtPtr exec) { + if (exec == NULL) + return; + + if (exec->rollbacks != NULL) { + if (exec->counts != NULL) { + int i; + + for (i = 0;i < exec->maxRollbacks;i++) + if (exec->rollbacks[i].counts != NULL) + xmlFree(exec->rollbacks[i].counts); + } + xmlFree(exec->rollbacks); + } + if (exec->counts != NULL) + xmlFree(exec->counts); + if (exec->inputStack != NULL) { + int i; + + for (i = 0;i < exec->inputStackNr;i++) { + if (exec->inputStack[i].value != NULL) + xmlFree(exec->inputStack[i].value); + } + xmlFree(exec->inputStack); + } + if (exec->errString != NULL) + xmlFree(exec->errString); + xmlFree(exec); +} + +static void +xmlFARegExecSaveInputString(xmlRegExecCtxtPtr exec, const xmlChar *value, + void *data) { +#ifdef DEBUG_PUSH + printf("saving value: %d:%s\n", exec->inputStackNr, value); +#endif + if (exec->inputStackMax == 0) { + exec->inputStackMax = 4; + exec->inputStack = (xmlRegInputTokenPtr) + xmlMalloc(exec->inputStackMax * sizeof(xmlRegInputToken)); + if (exec->inputStack == NULL) { + xmlRegexpErrMemory(NULL, "pushing input string"); + exec->inputStackMax = 0; + return; + } + } else if (exec->inputStackNr + 1 >= exec->inputStackMax) { + xmlRegInputTokenPtr tmp; + + exec->inputStackMax *= 2; + tmp = (xmlRegInputTokenPtr) xmlRealloc(exec->inputStack, + exec->inputStackMax * sizeof(xmlRegInputToken)); + if (tmp == NULL) { + xmlRegexpErrMemory(NULL, "pushing input string"); + exec->inputStackMax /= 2; + return; + } + exec->inputStack = tmp; + } + exec->inputStack[exec->inputStackNr].value = xmlStrdup(value); + exec->inputStack[exec->inputStackNr].data = data; + exec->inputStackNr++; + exec->inputStack[exec->inputStackNr].value = NULL; + exec->inputStack[exec->inputStackNr].data = NULL; +} + +/** + * xmlRegStrEqualWildcard: + * @expStr: the string to be evaluated + * @valStr: the validation string + * + * Checks if both strings are equal or have the same content. "*" + * can be used as a wildcard in @valStr; "|" is used as a seperator of + * substrings in both @expStr and @valStr. + * + * Returns 1 if the comparison is satisfied and the number of substrings + * is equal, 0 otherwise. + */ + +static int +xmlRegStrEqualWildcard(const xmlChar *expStr, const xmlChar *valStr) { + if (expStr == valStr) return(1); + if (expStr == NULL) return(0); + if (valStr == NULL) return(0); + do { + /* + * Eval if we have a wildcard for the current item. + */ + if (*expStr != *valStr) { + /* if one of them starts with a wildcard make valStr be it */ + if (*valStr == '*') { + const xmlChar *tmp; + + tmp = valStr; + valStr = expStr; + expStr = tmp; + } + if ((*valStr != 0) && (*expStr != 0) && (*expStr++ == '*')) { + do { + if (*valStr == XML_REG_STRING_SEPARATOR) + break; + valStr++; + } while (*valStr != 0); + continue; + } else + return(0); + } + expStr++; + valStr++; + } while (*valStr != 0); + if (*expStr != 0) + return (0); + else + return (1); +} + +/** + * xmlRegCompactPushString: + * @exec: a regexp execution context + * @comp: the precompiled exec with a compact table + * @value: a string token input + * @data: data associated to the token to reuse in callbacks + * + * Push one input token in the execution context + * + * Returns: 1 if the regexp reached a final state, 0 if non-final, and + * a negative value in case of error. + */ +static int +xmlRegCompactPushString(xmlRegExecCtxtPtr exec, + xmlRegexpPtr comp, + const xmlChar *value, + void *data) { + int state = exec->index; + int i, target; + + if ((comp == NULL) || (comp->compact == NULL) || (comp->stringMap == NULL)) + return(-1); + + if (value == NULL) { + /* + * are we at a final state ? + */ + if (comp->compact[state * (comp->nbstrings + 1)] == + XML_REGEXP_FINAL_STATE) + return(1); + return(0); + } + +#ifdef DEBUG_PUSH + printf("value pushed: %s\n", value); +#endif + + /* + * Examine all outside transitions from current state + */ + for (i = 0;i < comp->nbstrings;i++) { + target = comp->compact[state * (comp->nbstrings + 1) + i + 1]; + if ((target > 0) && (target <= comp->nbstates)) { + target--; /* to avoid 0 */ + if (xmlRegStrEqualWildcard(comp->stringMap[i], value)) { + exec->index = target; + if ((exec->callback != NULL) && (comp->transdata != NULL)) { + exec->callback(exec->data, value, + comp->transdata[state * comp->nbstrings + i], data); + } +#ifdef DEBUG_PUSH + printf("entering state %d\n", target); +#endif + if (comp->compact[target * (comp->nbstrings + 1)] == + XML_REGEXP_SINK_STATE) + goto error; + + if (comp->compact[target * (comp->nbstrings + 1)] == + XML_REGEXP_FINAL_STATE) + return(1); + return(0); + } + } + } + /* + * Failed to find an exit transition out from current state for the + * current token + */ +#ifdef DEBUG_PUSH + printf("failed to find a transition for %s on state %d\n", value, state); +#endif +error: + if (exec->errString != NULL) + xmlFree(exec->errString); + exec->errString = xmlStrdup(value); + exec->errStateNo = state; + exec->status = -1; +#ifdef DEBUG_ERR + testerr(exec); +#endif + return(-1); +} + +/** + * xmlRegExecPushStringInternal: + * @exec: a regexp execution context or NULL to indicate the end + * @value: a string token input + * @data: data associated to the token to reuse in callbacks + * @compound: value was assembled from 2 strings + * + * Push one input token in the execution context + * + * Returns: 1 if the regexp reached a final state, 0 if non-final, and + * a negative value in case of error. + */ +static int +xmlRegExecPushStringInternal(xmlRegExecCtxtPtr exec, const xmlChar *value, + void *data, int compound) { + xmlRegTransPtr trans; + xmlRegAtomPtr atom; + int ret; + int final = 0; + int progress = 1; + + if (exec == NULL) + return(-1); + if (exec->comp == NULL) + return(-1); + if (exec->status != 0) + return(exec->status); + + if (exec->comp->compact != NULL) + return(xmlRegCompactPushString(exec, exec->comp, value, data)); + + if (value == NULL) { + if (exec->state->type == XML_REGEXP_FINAL_STATE) + return(1); + final = 1; + } + +#ifdef DEBUG_PUSH + printf("value pushed: %s\n", value); +#endif + /* + * If we have an active rollback stack push the new value there + * and get back to where we were left + */ + if ((value != NULL) && (exec->inputStackNr > 0)) { + xmlFARegExecSaveInputString(exec, value, data); + value = exec->inputStack[exec->index].value; + data = exec->inputStack[exec->index].data; +#ifdef DEBUG_PUSH + printf("value loaded: %s\n", value); +#endif + } + + while ((exec->status == 0) && + ((value != NULL) || + ((final == 1) && + (exec->state->type != XML_REGEXP_FINAL_STATE)))) { + + /* + * End of input on non-terminal state, rollback, however we may + * still have epsilon like transition for counted transitions + * on counters, in that case don't break too early. + */ + if ((value == NULL) && (exec->counts == NULL)) + goto rollback; + + exec->transcount = 0; + for (;exec->transno < exec->state->nbTrans;exec->transno++) { + trans = &exec->state->trans[exec->transno]; + if (trans->to < 0) + continue; + atom = trans->atom; + ret = 0; + if (trans->count == REGEXP_ALL_LAX_COUNTER) { + int i; + int count; + xmlRegTransPtr t; + xmlRegCounterPtr counter; + + ret = 0; + +#ifdef DEBUG_PUSH + printf("testing all lax %d\n", trans->count); +#endif + /* + * Check all counted transitions from the current state + */ + if ((value == NULL) && (final)) { + ret = 1; + } else if (value != NULL) { + for (i = 0;i < exec->state->nbTrans;i++) { + t = &exec->state->trans[i]; + if ((t->counter < 0) || (t == trans)) + continue; + counter = &exec->comp->counters[t->counter]; + count = exec->counts[t->counter]; + if ((count < counter->max) && + (t->atom != NULL) && + (xmlStrEqual(value, t->atom->valuep))) { + ret = 0; + break; + } + if ((count >= counter->min) && + (count < counter->max) && + (t->atom != NULL) && + (xmlStrEqual(value, t->atom->valuep))) { + ret = 1; + break; + } + } + } + } else if (trans->count == REGEXP_ALL_COUNTER) { + int i; + int count; + xmlRegTransPtr t; + xmlRegCounterPtr counter; + + ret = 1; + +#ifdef DEBUG_PUSH + printf("testing all %d\n", trans->count); +#endif + /* + * Check all counted transitions from the current state + */ + for (i = 0;i < exec->state->nbTrans;i++) { + t = &exec->state->trans[i]; + if ((t->counter < 0) || (t == trans)) + continue; + counter = &exec->comp->counters[t->counter]; + count = exec->counts[t->counter]; + if ((count < counter->min) || (count > counter->max)) { + ret = 0; + break; + } + } + } else if (trans->count >= 0) { + int count; + xmlRegCounterPtr counter; + + /* + * A counted transition. + */ + + count = exec->counts[trans->count]; + counter = &exec->comp->counters[trans->count]; +#ifdef DEBUG_PUSH + printf("testing count %d: val %d, min %d, max %d\n", + trans->count, count, counter->min, counter->max); +#endif + ret = ((count >= counter->min) && (count <= counter->max)); + } else if (atom == NULL) { + fprintf(stderr, "epsilon transition left at runtime\n"); + exec->status = -2; + break; + } else if (value != NULL) { + ret = xmlRegStrEqualWildcard(atom->valuep, value); + if (atom->neg) { + ret = !ret; + if (!compound) + ret = 0; + } + if ((ret == 1) && (trans->counter >= 0)) { + xmlRegCounterPtr counter; + int count; + + count = exec->counts[trans->counter]; + counter = &exec->comp->counters[trans->counter]; + if (count >= counter->max) + ret = 0; + } + + if ((ret == 1) && (atom->min > 0) && (atom->max > 0)) { + xmlRegStatePtr to = exec->comp->states[trans->to]; + + /* + * this is a multiple input sequence + */ + if (exec->state->nbTrans > exec->transno + 1) { + if (exec->inputStackNr <= 0) { + xmlFARegExecSaveInputString(exec, value, data); + } + xmlFARegExecSave(exec); + } + exec->transcount = 1; + do { + /* + * Try to progress as much as possible on the input + */ + if (exec->transcount == atom->max) { + break; + } + exec->index++; + value = exec->inputStack[exec->index].value; + data = exec->inputStack[exec->index].data; +#ifdef DEBUG_PUSH + printf("value loaded: %s\n", value); +#endif + + /* + * End of input: stop here + */ + if (value == NULL) { + exec->index --; + break; + } + if (exec->transcount >= atom->min) { + int transno = exec->transno; + xmlRegStatePtr state = exec->state; + + /* + * The transition is acceptable save it + */ + exec->transno = -1; /* trick */ + exec->state = to; + if (exec->inputStackNr <= 0) { + xmlFARegExecSaveInputString(exec, value, data); + } + xmlFARegExecSave(exec); + exec->transno = transno; + exec->state = state; + } + ret = xmlStrEqual(value, atom->valuep); + exec->transcount++; + } while (ret == 1); + if (exec->transcount < atom->min) + ret = 0; + + /* + * If the last check failed but one transition was found + * possible, rollback + */ + if (ret < 0) + ret = 0; + if (ret == 0) { + goto rollback; + } + } + } + if (ret == 1) { + if ((exec->callback != NULL) && (atom != NULL) && + (data != NULL)) { + exec->callback(exec->data, atom->valuep, + atom->data, data); + } + if (exec->state->nbTrans > exec->transno + 1) { + if (exec->inputStackNr <= 0) { + xmlFARegExecSaveInputString(exec, value, data); + } + xmlFARegExecSave(exec); + } + if (trans->counter >= 0) { +#ifdef DEBUG_PUSH + printf("Increasing count %d\n", trans->counter); +#endif + exec->counts[trans->counter]++; + } + if ((trans->count >= 0) && + (trans->count < REGEXP_ALL_COUNTER)) { +#ifdef DEBUG_REGEXP_EXEC + printf("resetting count %d on transition\n", + trans->count); +#endif + exec->counts[trans->count] = 0; + } +#ifdef DEBUG_PUSH + printf("entering state %d\n", trans->to); +#endif + if ((exec->comp->states[trans->to] != NULL) && + (exec->comp->states[trans->to]->type == + XML_REGEXP_SINK_STATE)) { + /* + * entering a sink state, save the current state as error + * state. + */ + if (exec->errString != NULL) + xmlFree(exec->errString); + exec->errString = xmlStrdup(value); + exec->errState = exec->state; + memcpy(exec->errCounts, exec->counts, + exec->comp->nbCounters * sizeof(int)); + } + exec->state = exec->comp->states[trans->to]; + exec->transno = 0; + if (trans->atom != NULL) { + if (exec->inputStack != NULL) { + exec->index++; + if (exec->index < exec->inputStackNr) { + value = exec->inputStack[exec->index].value; + data = exec->inputStack[exec->index].data; +#ifdef DEBUG_PUSH + printf("value loaded: %s\n", value); +#endif + } else { + value = NULL; + data = NULL; +#ifdef DEBUG_PUSH + printf("end of input\n"); +#endif + } + } else { + value = NULL; + data = NULL; +#ifdef DEBUG_PUSH + printf("end of input\n"); +#endif + } + } + goto progress; + } else if (ret < 0) { + exec->status = -4; + break; + } + } + if ((exec->transno != 0) || (exec->state->nbTrans == 0)) { +rollback: + /* + * if we didn't yet rollback on the current input + * store the current state as the error state. + */ + 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); + exec->errState = exec->state; + memcpy(exec->errCounts, exec->counts, + exec->comp->nbCounters * sizeof(int)); + } + + /* + * Failed to find a way out + */ + exec->determinist = 0; + xmlFARegExecRollBack(exec); + if (exec->status == 0) { + value = exec->inputStack[exec->index].value; + data = exec->inputStack[exec->index].data; +#ifdef DEBUG_PUSH + printf("value loaded: %s\n", value); +#endif + } + } + continue; +progress: + progress = 1; + continue; + } + if (exec->status == 0) { + return(exec->state->type == XML_REGEXP_FINAL_STATE); + } +#ifdef DEBUG_ERR + if (exec->status < 0) { + testerr(exec); + } +#endif + return(exec->status); +} + +/** + * xmlRegExecPushString: + * @exec: a regexp execution context or NULL to indicate the end + * @value: a string token input + * @data: data associated to the token to reuse in callbacks + * + * Push one input token in the execution context + * + * Returns: 1 if the regexp reached a final state, 0 if non-final, and + * a negative value in case of error. + */ +int +xmlRegExecPushString(xmlRegExecCtxtPtr exec, const xmlChar *value, + void *data) { + return(xmlRegExecPushStringInternal(exec, value, data, 0)); +} + +/** + * xmlRegExecPushString2: + * @exec: a regexp execution context or NULL to indicate the end + * @value: the first string token input + * @value2: the second string token input + * @data: data associated to the token to reuse in callbacks + * + * Push one input token in the execution context + * + * Returns: 1 if the regexp reached a final state, 0 if non-final, and + * a negative value in case of error. + */ +int +xmlRegExecPushString2(xmlRegExecCtxtPtr exec, const xmlChar *value, + const xmlChar *value2, void *data) { + xmlChar buf[150]; + int lenn, lenp, ret; + xmlChar *str; + + if (exec == NULL) + return(-1); + if (exec->comp == NULL) + return(-1); + if (exec->status != 0) + return(exec->status); + + if (value2 == NULL) + return(xmlRegExecPushString(exec, value, data)); + + lenn = strlen((char *) value2); + lenp = strlen((char *) value); + + if (150 < lenn + lenp + 2) { + str = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2); + if (str == NULL) { + exec->status = -1; + return(-1); + } + } else { + str = buf; + } + memcpy(&str[0], value, lenp); + str[lenp] = XML_REG_STRING_SEPARATOR; + memcpy(&str[lenp + 1], value2, lenn); + str[lenn + lenp + 1] = 0; + + if (exec->comp->compact != NULL) + ret = xmlRegCompactPushString(exec, exec->comp, str, data); + else + ret = xmlRegExecPushStringInternal(exec, str, data, 1); + + if (str != buf) + xmlFree(str); + return(ret); +} + +/** + * xmlRegExecGetValues: + * @exec: a regexp execution context + * @err: error extraction or normal one + * @nbval: pointer to the number of accepted values IN/OUT + * @nbneg: return number of negative transitions + * @values: pointer to the array of acceptable values + * @terminal: return value if this was a terminal state + * + * Extract informations from the regexp execution, internal routine to + * implement xmlRegExecNextValues() and xmlRegExecErrInfo() + * + * Returns: 0 in case of success or -1 in case of error. + */ +static int +xmlRegExecGetValues(xmlRegExecCtxtPtr exec, int err, + int *nbval, int *nbneg, + xmlChar **values, int *terminal) { + int maxval; + int nb = 0; + + if ((exec == NULL) || (nbval == NULL) || (nbneg == NULL) || + (values == NULL) || (*nbval <= 0)) + return(-1); + + maxval = *nbval; + *nbval = 0; + *nbneg = 0; + if ((exec->comp != NULL) && (exec->comp->compact != NULL)) { + xmlRegexpPtr comp; + int target, i, state; + + comp = exec->comp; + + if (err) { + if (exec->errStateNo == -1) return(-1); + state = exec->errStateNo; + } else { + state = exec->index; + } + if (terminal != NULL) { + if (comp->compact[state * (comp->nbstrings + 1)] == + XML_REGEXP_FINAL_STATE) + *terminal = 1; + else + *terminal = 0; + } + for (i = 0;(i < comp->nbstrings) && (nb < maxval);i++) { + target = comp->compact[state * (comp->nbstrings + 1) + i + 1]; + if ((target > 0) && (target <= comp->nbstates) && + (comp->compact[(target - 1) * (comp->nbstrings + 1)] != + XML_REGEXP_SINK_STATE)) { + values[nb++] = comp->stringMap[i]; + (*nbval)++; + } + } + for (i = 0;(i < comp->nbstrings) && (nb < maxval);i++) { + target = comp->compact[state * (comp->nbstrings + 1) + i + 1]; + if ((target > 0) && (target <= comp->nbstates) && + (comp->compact[(target - 1) * (comp->nbstrings + 1)] == + XML_REGEXP_SINK_STATE)) { + values[nb++] = comp->stringMap[i]; + (*nbneg)++; + } + } + } else { + int transno; + xmlRegTransPtr trans; + xmlRegAtomPtr atom; + xmlRegStatePtr state; + + if (terminal != NULL) { + if (exec->state->type == XML_REGEXP_FINAL_STATE) + *terminal = 1; + else + *terminal = 0; + } + + if (err) { + if (exec->errState == NULL) return(-1); + state = exec->errState; + } else { + if (exec->state == NULL) return(-1); + state = exec->state; + } + for (transno = 0; + (transno < state->nbTrans) && (nb < maxval); + transno++) { + trans = &state->trans[transno]; + if (trans->to < 0) + continue; + atom = trans->atom; + if ((atom == NULL) || (atom->valuep == NULL)) + 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; + + if (err) + count = exec->errCounts[trans->counter]; + else + count = exec->counts[trans->counter]; + if (exec->comp != NULL) + counter = &exec->comp->counters[trans->counter]; + if ((counter == NULL) || (count < counter->max)) { + if (atom->neg) + values[nb++] = (xmlChar *) atom->valuep2; + else + values[nb++] = (xmlChar *) atom->valuep; + (*nbval)++; + } + } else { + if ((exec->comp->states[trans->to] != NULL) && + (exec->comp->states[trans->to]->type != + XML_REGEXP_SINK_STATE)) { + if (atom->neg) + values[nb++] = (xmlChar *) atom->valuep2; + else + values[nb++] = (xmlChar *) atom->valuep; + (*nbval)++; + } + } + } + for (transno = 0; + (transno < state->nbTrans) && (nb < maxval); + transno++) { + trans = &state->trans[transno]; + if (trans->to < 0) + continue; + atom = trans->atom; + if ((atom == NULL) || (atom->valuep == NULL)) + continue; + if (trans->count == REGEXP_ALL_LAX_COUNTER) { + continue; + } else if (trans->count == REGEXP_ALL_COUNTER) { + continue; + } else if (trans->counter >= 0) { + continue; + } else { + if ((exec->comp->states[trans->to] != NULL) && + (exec->comp->states[trans->to]->type == + XML_REGEXP_SINK_STATE)) { + if (atom->neg) + values[nb++] = (xmlChar *) atom->valuep2; + else + values[nb++] = (xmlChar *) atom->valuep; + (*nbneg)++; + } + } + } + } + return(0); +} + +/** + * xmlRegExecNextValues: + * @exec: a regexp execution context + * @nbval: pointer to the number of accepted values IN/OUT + * @nbneg: return number of negative transitions + * @values: pointer to the array of acceptable values + * @terminal: return value if this was a terminal state + * + * Extract informations from the regexp execution, + * the parameter @values must point to an array of @nbval string pointers + * on return nbval will contain the number of possible strings in that + * state and the @values array will be updated with them. The string values + * returned will be freed with the @exec context and don't need to be + * deallocated. + * + * Returns: 0 in case of success or -1 in case of error. + */ +int +xmlRegExecNextValues(xmlRegExecCtxtPtr exec, int *nbval, int *nbneg, + xmlChar **values, int *terminal) { + return(xmlRegExecGetValues(exec, 0, nbval, nbneg, values, terminal)); +} + +/** + * xmlRegExecErrInfo: + * @exec: a regexp execution context generating an error + * @string: return value for the error string + * @nbval: pointer to the number of accepted values IN/OUT + * @nbneg: return number of negative transitions + * @values: pointer to the array of acceptable values + * @terminal: return value if this was a terminal state + * + * Extract error informations from the regexp execution, the parameter + * @string will be updated with the value pushed and not accepted, + * the parameter @values must point to an array of @nbval string pointers + * on return nbval will contain the number of possible strings in that + * state and the @values array will be updated with them. The string values + * returned will be freed with the @exec context and don't need to be + * deallocated. + * + * Returns: 0 in case of success or -1 in case of error. + */ +int +xmlRegExecErrInfo(xmlRegExecCtxtPtr exec, const xmlChar **string, + int *nbval, int *nbneg, xmlChar **values, int *terminal) { + if (exec == NULL) + return(-1); + if (string != NULL) { + if (exec->status != 0) + *string = exec->errString; + else + *string = NULL; + } + return(xmlRegExecGetValues(exec, 1, nbval, nbneg, values, terminal)); +} + +#ifdef DEBUG_ERR +static void testerr(xmlRegExecCtxtPtr exec) { + const xmlChar *string; + xmlChar *values[5]; + int nb = 5; + int nbneg; + int terminal; + xmlRegExecErrInfo(exec, &string, &nb, &nbneg, &values[0], &terminal); +} +#endif + +#if 0 +static int +xmlRegExecPushChar(xmlRegExecCtxtPtr exec, int UCS) { + xmlRegTransPtr trans; + xmlRegAtomPtr atom; + int ret; + int codepoint, len; + + if (exec == NULL) + return(-1); + if (exec->status != 0) + return(exec->status); + + while ((exec->status == 0) && + ((exec->inputString[exec->index] != 0) || + (exec->state->type != XML_REGEXP_FINAL_STATE))) { + + /* + * End of input on non-terminal state, rollback, however we may + * still have epsilon like transition for counted transitions + * on counters, in that case don't break too early. + */ + if ((exec->inputString[exec->index] == 0) && (exec->counts == NULL)) + goto rollback; + + exec->transcount = 0; + for (;exec->transno < exec->state->nbTrans;exec->transno++) { + trans = &exec->state->trans[exec->transno]; + if (trans->to < 0) + continue; + atom = trans->atom; + ret = 0; + if (trans->count >= 0) { + int count; + xmlRegCounterPtr counter; + + /* + * A counted transition. + */ + + count = exec->counts[trans->count]; + counter = &exec->comp->counters[trans->count]; +#ifdef DEBUG_REGEXP_EXEC + printf("testing count %d: val %d, min %d, max %d\n", + trans->count, count, counter->min, counter->max); +#endif + ret = ((count >= counter->min) && (count <= counter->max)); + } else if (atom == NULL) { + fprintf(stderr, "epsilon transition left at runtime\n"); + exec->status = -2; + break; + } else if (exec->inputString[exec->index] != 0) { + codepoint = CUR_SCHAR(&(exec->inputString[exec->index]), len); + ret = xmlRegCheckCharacter(atom, codepoint); + if ((ret == 1) && (atom->min > 0) && (atom->max > 0)) { + xmlRegStatePtr to = exec->comp->states[trans->to]; + + /* + * this is a multiple input sequence + */ + if (exec->state->nbTrans > exec->transno + 1) { + xmlFARegExecSave(exec); + } + exec->transcount = 1; + do { + /* + * Try to progress as much as possible on the input + */ + if (exec->transcount == atom->max) { + break; + } + exec->index += len; + /* + * End of input: stop here + */ + if (exec->inputString[exec->index] == 0) { + exec->index -= len; + break; + } + if (exec->transcount >= atom->min) { + int transno = exec->transno; + xmlRegStatePtr state = exec->state; + + /* + * The transition is acceptable save it + */ + exec->transno = -1; /* trick */ + exec->state = to; + xmlFARegExecSave(exec); + exec->transno = transno; + exec->state = state; + } + codepoint = CUR_SCHAR(&(exec->inputString[exec->index]), + len); + ret = xmlRegCheckCharacter(atom, codepoint); + exec->transcount++; + } while (ret == 1); + if (exec->transcount < atom->min) + ret = 0; + + /* + * If the last check failed but one transition was found + * possible, rollback + */ + if (ret < 0) + ret = 0; + if (ret == 0) { + goto rollback; + } + } + } + if (ret == 1) { + if (exec->state->nbTrans > exec->transno + 1) { + xmlFARegExecSave(exec); + } + /* + * restart count for expressions like this ((abc){2})* + */ + if (trans->count >= 0) { +#ifdef DEBUG_REGEXP_EXEC + printf("Reset count %d\n", trans->count); +#endif + exec->counts[trans->count] = 0; + } + if (trans->counter >= 0) { +#ifdef DEBUG_REGEXP_EXEC + printf("Increasing count %d\n", trans->counter); +#endif + exec->counts[trans->counter]++; + } +#ifdef DEBUG_REGEXP_EXEC + printf("entering state %d\n", trans->to); +#endif + exec->state = exec->comp->states[trans->to]; + exec->transno = 0; + if (trans->atom != NULL) { + exec->index += len; + } + goto progress; + } else if (ret < 0) { + exec->status = -4; + break; + } + } + if ((exec->transno != 0) || (exec->state->nbTrans == 0)) { +rollback: + /* + * Failed to find a way out + */ + exec->determinist = 0; + xmlFARegExecRollBack(exec); + } +progress: + continue; + } +} +#endif +/************************************************************************ + * * + * Parser for the Schemas Datatype Regular Expressions * + * http://www.w3.org/TR/2001/REC-xmlschema-2-20010502/#regexs * + * * + ************************************************************************/ + +/** + * xmlFAIsChar: + * @ctxt: a regexp parser context + * + * [10] Char ::= [^.\?*+()|#x5B#x5D] + */ +static int +xmlFAIsChar(xmlRegParserCtxtPtr ctxt) { + int cur; + int len; + + cur = CUR_SCHAR(ctxt->cur, len); + if ((cur == '.') || (cur == '\\') || (cur == '?') || + (cur == '*') || (cur == '+') || (cur == '(') || + (cur == ')') || (cur == '|') || (cur == 0x5B) || + (cur == 0x5D) || (cur == 0)) + return(-1); + return(cur); +} + +/** + * xmlFAParseCharProp: + * @ctxt: a regexp parser context + * + * [27] charProp ::= IsCategory | IsBlock + * [28] IsCategory ::= Letters | Marks | Numbers | Punctuation | + * Separators | Symbols | Others + * [29] Letters ::= 'L' [ultmo]? + * [30] Marks ::= 'M' [nce]? + * [31] Numbers ::= 'N' [dlo]? + * [32] Punctuation ::= 'P' [cdseifo]? + * [33] Separators ::= 'Z' [slp]? + * [34] Symbols ::= 'S' [mcko]? + * [35] Others ::= 'C' [cfon]? + * [36] IsBlock ::= 'Is' [a-zA-Z0-9#x2D]+ + */ +static void +xmlFAParseCharProp(xmlRegParserCtxtPtr ctxt) { + int cur; + xmlRegAtomType type = (xmlRegAtomType) 0; + xmlChar *blockName = NULL; + + cur = CUR; + if (cur == 'L') { + NEXT; + cur = CUR; + if (cur == 'u') { + NEXT; + type = XML_REGEXP_LETTER_UPPERCASE; + } else if (cur == 'l') { + NEXT; + type = XML_REGEXP_LETTER_LOWERCASE; + } else if (cur == 't') { + NEXT; + type = XML_REGEXP_LETTER_TITLECASE; + } else if (cur == 'm') { + NEXT; + type = XML_REGEXP_LETTER_MODIFIER; + } else if (cur == 'o') { + NEXT; + type = XML_REGEXP_LETTER_OTHERS; + } else { + type = XML_REGEXP_LETTER; + } + } else if (cur == 'M') { + NEXT; + cur = CUR; + if (cur == 'n') { + NEXT; + /* nonspacing */ + type = XML_REGEXP_MARK_NONSPACING; + } else if (cur == 'c') { + NEXT; + /* spacing combining */ + type = XML_REGEXP_MARK_SPACECOMBINING; + } else if (cur == 'e') { + NEXT; + /* enclosing */ + type = XML_REGEXP_MARK_ENCLOSING; + } else { + /* all marks */ + type = XML_REGEXP_MARK; + } + } else if (cur == 'N') { + NEXT; + cur = CUR; + if (cur == 'd') { + NEXT; + /* digital */ + type = XML_REGEXP_NUMBER_DECIMAL; + } else if (cur == 'l') { + NEXT; + /* letter */ + type = XML_REGEXP_NUMBER_LETTER; + } else if (cur == 'o') { + NEXT; + /* other */ + type = XML_REGEXP_NUMBER_OTHERS; + } else { + /* all numbers */ + type = XML_REGEXP_NUMBER; + } + } else if (cur == 'P') { + NEXT; + cur = CUR; + if (cur == 'c') { + NEXT; + /* connector */ + type = XML_REGEXP_PUNCT_CONNECTOR; + } else if (cur == 'd') { + NEXT; + /* dash */ + type = XML_REGEXP_PUNCT_DASH; + } else if (cur == 's') { + NEXT; + /* open */ + type = XML_REGEXP_PUNCT_OPEN; + } else if (cur == 'e') { + NEXT; + /* close */ + type = XML_REGEXP_PUNCT_CLOSE; + } else if (cur == 'i') { + NEXT; + /* initial quote */ + type = XML_REGEXP_PUNCT_INITQUOTE; + } else if (cur == 'f') { + NEXT; + /* final quote */ + type = XML_REGEXP_PUNCT_FINQUOTE; + } else if (cur == 'o') { + NEXT; + /* other */ + type = XML_REGEXP_PUNCT_OTHERS; + } else { + /* all punctuation */ + type = XML_REGEXP_PUNCT; + } + } else if (cur == 'Z') { + NEXT; + cur = CUR; + if (cur == 's') { + NEXT; + /* space */ + type = XML_REGEXP_SEPAR_SPACE; + } else if (cur == 'l') { + NEXT; + /* line */ + type = XML_REGEXP_SEPAR_LINE; + } else if (cur == 'p') { + NEXT; + /* paragraph */ + type = XML_REGEXP_SEPAR_PARA; + } else { + /* all separators */ + type = XML_REGEXP_SEPAR; + } + } else if (cur == 'S') { + NEXT; + cur = CUR; + if (cur == 'm') { + NEXT; + type = XML_REGEXP_SYMBOL_MATH; + /* math */ + } else if (cur == 'c') { + NEXT; + type = XML_REGEXP_SYMBOL_CURRENCY; + /* currency */ + } else if (cur == 'k') { + NEXT; + type = XML_REGEXP_SYMBOL_MODIFIER; + /* modifiers */ + } else if (cur == 'o') { + NEXT; + type = XML_REGEXP_SYMBOL_OTHERS; + /* other */ + } else { + /* all symbols */ + type = XML_REGEXP_SYMBOL; + } + } else if (cur == 'C') { + NEXT; + cur = CUR; + if (cur == 'c') { + NEXT; + /* control */ + type = XML_REGEXP_OTHER_CONTROL; + } else if (cur == 'f') { + NEXT; + /* format */ + type = XML_REGEXP_OTHER_FORMAT; + } else if (cur == 'o') { + NEXT; + /* private use */ + type = XML_REGEXP_OTHER_PRIVATE; + } else if (cur == 'n') { + NEXT; + /* not assigned */ + type = XML_REGEXP_OTHER_NA; + } else { + /* all others */ + type = XML_REGEXP_OTHER; + } + } else if (cur == 'I') { + const xmlChar *start; + NEXT; + cur = CUR; + if (cur != 's') { + ERROR("IsXXXX expected"); + return; + } + NEXT; + start = ctxt->cur; + cur = CUR; + if (((cur >= 'a') && (cur <= 'z')) || + ((cur >= 'A') && (cur <= 'Z')) || + ((cur >= '0') && (cur <= '9')) || + (cur == 0x2D)) { + NEXT; + cur = CUR; + while (((cur >= 'a') && (cur <= 'z')) || + ((cur >= 'A') && (cur <= 'Z')) || + ((cur >= '0') && (cur <= '9')) || + (cur == 0x2D)) { + NEXT; + cur = CUR; + } + } + type = XML_REGEXP_BLOCK_NAME; + blockName = xmlStrndup(start, ctxt->cur - start); + } else { + ERROR("Unknown char property"); + return; + } + if (ctxt->atom == NULL) { + ctxt->atom = xmlRegNewAtom(ctxt, type); + if (ctxt->atom != NULL) + ctxt->atom->valuep = blockName; + } else if (ctxt->atom->type == XML_REGEXP_RANGES) { + xmlRegAtomAddRange(ctxt, ctxt->atom, ctxt->neg, + type, 0, 0, blockName); + } +} + +/** + * xmlFAParseCharClassEsc: + * @ctxt: a regexp parser context + * + * [23] charClassEsc ::= ( SingleCharEsc | MultiCharEsc | catEsc | complEsc ) + * [24] SingleCharEsc ::= '\' [nrt\|.?*+(){}#x2D#x5B#x5D#x5E] + * [25] catEsc ::= '\p{' charProp '}' + * [26] complEsc ::= '\P{' charProp '}' + * [37] MultiCharEsc ::= '.' | ('\' [sSiIcCdDwW]) + */ +static void +xmlFAParseCharClassEsc(xmlRegParserCtxtPtr ctxt) { + int cur; + + if (CUR == '.') { + if (ctxt->atom == NULL) { + ctxt->atom = xmlRegNewAtom(ctxt, XML_REGEXP_ANYCHAR); + } else if (ctxt->atom->type == XML_REGEXP_RANGES) { + xmlRegAtomAddRange(ctxt, ctxt->atom, ctxt->neg, + XML_REGEXP_ANYCHAR, 0, 0, NULL); + } + NEXT; + return; + } + if (CUR != '\\') { + ERROR("Escaped sequence: expecting \\"); + return; + } + NEXT; + cur = CUR; + if (cur == 'p') { + NEXT; + if (CUR != '{') { + ERROR("Expecting '{'"); + return; + } + NEXT; + xmlFAParseCharProp(ctxt); + if (CUR != '}') { + ERROR("Expecting '}'"); + return; + } + NEXT; + } else if (cur == 'P') { + NEXT; + if (CUR != '{') { + ERROR("Expecting '{'"); + return; + } + NEXT; + xmlFAParseCharProp(ctxt); + ctxt->atom->neg = 1; + if (CUR != '}') { + ERROR("Expecting '}'"); + return; + } + NEXT; + } else if ((cur == 'n') || (cur == 'r') || (cur == 't') || (cur == '\\') || + (cur == '|') || (cur == '.') || (cur == '?') || (cur == '*') || + (cur == '+') || (cur == '(') || (cur == ')') || (cur == '{') || + (cur == '}') || (cur == 0x2D) || (cur == 0x5B) || (cur == 0x5D) || + (cur == 0x5E)) { + if (ctxt->atom == NULL) { + ctxt->atom = xmlRegNewAtom(ctxt, XML_REGEXP_CHARVAL); + if (ctxt->atom != NULL) { + switch (cur) { + case 'n': + ctxt->atom->codepoint = '\n'; + break; + case 'r': + ctxt->atom->codepoint = '\r'; + break; + case 't': + ctxt->atom->codepoint = '\t'; + break; + default: + ctxt->atom->codepoint = cur; + } + } + } else if (ctxt->atom->type == XML_REGEXP_RANGES) { + switch (cur) { + case 'n': + cur = '\n'; + break; + case 'r': + cur = '\r'; + break; + case 't': + cur = '\t'; + break; + } + xmlRegAtomAddRange(ctxt, ctxt->atom, ctxt->neg, + XML_REGEXP_CHARVAL, cur, cur, NULL); + } + NEXT; + } else if ((cur == 's') || (cur == 'S') || (cur == 'i') || (cur == 'I') || + (cur == 'c') || (cur == 'C') || (cur == 'd') || (cur == 'D') || + (cur == 'w') || (cur == 'W')) { + xmlRegAtomType type = XML_REGEXP_ANYSPACE; + + switch (cur) { + case 's': + type = XML_REGEXP_ANYSPACE; + break; + case 'S': + type = XML_REGEXP_NOTSPACE; + break; + case 'i': + type = XML_REGEXP_INITNAME; + break; + case 'I': + type = XML_REGEXP_NOTINITNAME; + break; + case 'c': + type = XML_REGEXP_NAMECHAR; + break; + case 'C': + type = XML_REGEXP_NOTNAMECHAR; + break; + case 'd': + type = XML_REGEXP_DECIMAL; + break; + case 'D': + type = XML_REGEXP_NOTDECIMAL; + break; + case 'w': + type = XML_REGEXP_REALCHAR; + break; + case 'W': + type = XML_REGEXP_NOTREALCHAR; + break; + } + NEXT; + if (ctxt->atom == NULL) { + ctxt->atom = xmlRegNewAtom(ctxt, type); + } else if (ctxt->atom->type == XML_REGEXP_RANGES) { + xmlRegAtomAddRange(ctxt, ctxt->atom, ctxt->neg, + type, 0, 0, NULL); + } + } else { + ERROR("Wrong escape sequence, misuse of character '\\'"); + } +} + +/** + * xmlFAParseCharRange: + * @ctxt: a regexp parser context + * + * [17] charRange ::= seRange | XmlCharRef | XmlCharIncDash + * [18] seRange ::= charOrEsc '-' charOrEsc + * [20] charOrEsc ::= XmlChar | SingleCharEsc + * [21] XmlChar ::= [^\#x2D#x5B#x5D] + * [22] XmlCharIncDash ::= [^\#x5B#x5D] + */ +static void +xmlFAParseCharRange(xmlRegParserCtxtPtr ctxt) { + int cur, len; + int start = -1; + int end = -1; + + if (CUR == '\0') { + ERROR("Expecting ']'"); + return; + } + + cur = CUR; + if (cur == '\\') { + NEXT; + cur = CUR; + switch (cur) { + case 'n': start = 0xA; break; + case 'r': start = 0xD; break; + case 't': start = 0x9; break; + case '\\': case '|': case '.': case '-': case '^': case '?': + case '*': case '+': case '{': case '}': case '(': case ')': + case '[': case ']': + start = cur; break; + default: + ERROR("Invalid escape value"); + return; + } + end = start; + len = 1; + } else if ((cur != 0x5B) && (cur != 0x5D)) { + end = start = CUR_SCHAR(ctxt->cur, len); + } else { + ERROR("Expecting a char range"); + return; + } + /* + * Since we are "inside" a range, we can assume ctxt->cur is past + * the start of ctxt->string, and PREV should be safe + */ + if ((start == '-') && (NXT(1) != ']') && (PREV != '[') && (PREV != '^')) { + NEXTL(len); + return; + } + NEXTL(len); + cur = CUR; + if ((cur != '-') || (NXT(1) == ']')) { + xmlRegAtomAddRange(ctxt, ctxt->atom, ctxt->neg, + XML_REGEXP_CHARVAL, start, end, NULL); + return; + } + NEXT; + cur = CUR; + if (cur == '\\') { + NEXT; + cur = CUR; + switch (cur) { + case 'n': end = 0xA; break; + case 'r': end = 0xD; break; + case 't': end = 0x9; break; + case '\\': case '|': case '.': case '-': case '^': case '?': + case '*': case '+': case '{': case '}': case '(': case ')': + case '[': case ']': + end = cur; break; + default: + ERROR("Invalid escape value"); + return; + } + len = 1; + } else if ((cur != 0x5B) && (cur != 0x5D)) { + end = CUR_SCHAR(ctxt->cur, len); + } else { + ERROR("Expecting the end of a char range"); + return; + } + NEXTL(len); + /* TODO check that the values are acceptable character ranges for XML */ + if (end < start) { + ERROR("End of range is before start of range"); + } else { + xmlRegAtomAddRange(ctxt, ctxt->atom, ctxt->neg, + XML_REGEXP_CHARVAL, start, end, NULL); + } + return; +} + +/** + * xmlFAParsePosCharGroup: + * @ctxt: a regexp parser context + * + * [14] posCharGroup ::= ( charRange | charClassEsc )+ + */ +static void +xmlFAParsePosCharGroup(xmlRegParserCtxtPtr ctxt) { + do { + if (CUR == '\\') { + xmlFAParseCharClassEsc(ctxt); + } else { + xmlFAParseCharRange(ctxt); + } + } while ((CUR != ']') && (CUR != '^') && (CUR != '-') && + (CUR != 0) && (ctxt->error == 0)); +} + +/** + * xmlFAParseCharGroup: + * @ctxt: a regexp parser context + * + * [13] charGroup ::= posCharGroup | negCharGroup | charClassSub + * [15] negCharGroup ::= '^' posCharGroup + * [16] charClassSub ::= ( posCharGroup | negCharGroup ) '-' charClassExpr + * [12] charClassExpr ::= '[' charGroup ']' + */ +static void +xmlFAParseCharGroup(xmlRegParserCtxtPtr ctxt) { + int n = ctxt->neg; + while ((CUR != ']') && (ctxt->error == 0)) { + if (CUR == '^') { + int neg = ctxt->neg; + + NEXT; + ctxt->neg = !ctxt->neg; + xmlFAParsePosCharGroup(ctxt); + ctxt->neg = neg; + } else if ((CUR == '-') && (NXT(1) == '[')) { + int neg = ctxt->neg; + ctxt->neg = 2; + NEXT; /* eat the '-' */ + NEXT; /* eat the '[' */ + xmlFAParseCharGroup(ctxt); + if (CUR == ']') { + NEXT; + } else { + ERROR("charClassExpr: ']' expected"); + break; + } + ctxt->neg = neg; + break; + } else if (CUR != ']') { + xmlFAParsePosCharGroup(ctxt); + } + } + ctxt->neg = n; +} + +/** + * xmlFAParseCharClass: + * @ctxt: a regexp parser context + * + * [11] charClass ::= charClassEsc | charClassExpr + * [12] charClassExpr ::= '[' charGroup ']' + */ +static void +xmlFAParseCharClass(xmlRegParserCtxtPtr ctxt) { + if (CUR == '[') { + NEXT; + ctxt->atom = xmlRegNewAtom(ctxt, XML_REGEXP_RANGES); + if (ctxt->atom == NULL) + return; + xmlFAParseCharGroup(ctxt); + if (CUR == ']') { + NEXT; + } else { + ERROR("xmlFAParseCharClass: ']' expected"); + } + } else { + xmlFAParseCharClassEsc(ctxt); + } +} + +/** + * xmlFAParseQuantExact: + * @ctxt: a regexp parser context + * + * [8] QuantExact ::= [0-9]+ + * + * Returns 0 if success or -1 in case of error + */ +static int +xmlFAParseQuantExact(xmlRegParserCtxtPtr ctxt) { + int ret = 0; + int ok = 0; + + while ((CUR >= '0') && (CUR <= '9')) { + ret = ret * 10 + (CUR - '0'); + ok = 1; + NEXT; + } + if (ok != 1) { + return(-1); + } + return(ret); +} + +/** + * xmlFAParseQuantifier: + * @ctxt: a regexp parser context + * + * [4] quantifier ::= [?*+] | ( '{' quantity '}' ) + * [5] quantity ::= quantRange | quantMin | QuantExact + * [6] quantRange ::= QuantExact ',' QuantExact + * [7] quantMin ::= QuantExact ',' + * [8] QuantExact ::= [0-9]+ + */ +static int +xmlFAParseQuantifier(xmlRegParserCtxtPtr ctxt) { + int cur; + + cur = CUR; + if ((cur == '?') || (cur == '*') || (cur == '+')) { + if (ctxt->atom != NULL) { + if (cur == '?') + ctxt->atom->quant = XML_REGEXP_QUANT_OPT; + else if (cur == '*') + ctxt->atom->quant = XML_REGEXP_QUANT_MULT; + else if (cur == '+') + ctxt->atom->quant = XML_REGEXP_QUANT_PLUS; + } + NEXT; + return(1); + } + if (cur == '{') { + int min = 0, max = 0; + + NEXT; + cur = xmlFAParseQuantExact(ctxt); + if (cur >= 0) + min = cur; + if (CUR == ',') { + NEXT; + if (CUR == '}') + max = INT_MAX; + else { + cur = xmlFAParseQuantExact(ctxt); + if (cur >= 0) + max = cur; + else { + ERROR("Improper quantifier"); + } + } + } + if (CUR == '}') { + NEXT; + } else { + ERROR("Unterminated quantifier"); + } + if (max == 0) + max = min; + if (ctxt->atom != NULL) { + ctxt->atom->quant = XML_REGEXP_QUANT_RANGE; + ctxt->atom->min = min; + ctxt->atom->max = max; + } + return(1); + } + return(0); +} + +/** + * xmlFAParseAtom: + * @ctxt: a regexp parser context + * + * [9] atom ::= Char | charClass | ( '(' regExp ')' ) + */ +static int +xmlFAParseAtom(xmlRegParserCtxtPtr ctxt) { + int codepoint, len; + + codepoint = xmlFAIsChar(ctxt); + if (codepoint > 0) { + ctxt->atom = xmlRegNewAtom(ctxt, XML_REGEXP_CHARVAL); + if (ctxt->atom == NULL) + return(-1); + codepoint = CUR_SCHAR(ctxt->cur, len); + ctxt->atom->codepoint = codepoint; + NEXTL(len); + return(1); + } else if (CUR == '|') { + return(0); + } else if (CUR == 0) { + return(0); + } else if (CUR == ')') { + return(0); + } else if (CUR == '(') { + xmlRegStatePtr start, oldend, start0; + + NEXT; + /* + * this extra Epsilon transition is needed if we count with 0 allowed + * unfortunately this can't be known at that point + */ + xmlFAGenerateEpsilonTransition(ctxt, ctxt->state, NULL); + start0 = ctxt->state; + xmlFAGenerateEpsilonTransition(ctxt, ctxt->state, NULL); + start = ctxt->state; + oldend = ctxt->end; + ctxt->end = NULL; + ctxt->atom = NULL; + xmlFAParseRegExp(ctxt, 0); + if (CUR == ')') { + NEXT; + } else { + ERROR("xmlFAParseAtom: expecting ')'"); + } + ctxt->atom = xmlRegNewAtom(ctxt, XML_REGEXP_SUBREG); + if (ctxt->atom == NULL) + return(-1); + ctxt->atom->start = start; + ctxt->atom->start0 = start0; + ctxt->atom->stop = ctxt->state; + ctxt->end = oldend; + return(1); + } else if ((CUR == '[') || (CUR == '\\') || (CUR == '.')) { + xmlFAParseCharClass(ctxt); + return(1); + } + return(0); +} + +/** + * xmlFAParsePiece: + * @ctxt: a regexp parser context + * + * [3] piece ::= atom quantifier? + */ +static int +xmlFAParsePiece(xmlRegParserCtxtPtr ctxt) { + int ret; + + ctxt->atom = NULL; + ret = xmlFAParseAtom(ctxt); + if (ret == 0) + return(0); + if (ctxt->atom == NULL) { + ERROR("internal: no atom generated"); + } + xmlFAParseQuantifier(ctxt); + return(1); +} + +/** + * xmlFAParseBranch: + * @ctxt: a regexp parser context + * @to: optional target to the end of the branch + * + * @to is used to optimize by removing duplicate path in automata + * in expressions like (a|b)(c|d) + * + * [2] branch ::= piece* + */ +static int +xmlFAParseBranch(xmlRegParserCtxtPtr ctxt, xmlRegStatePtr to) { + xmlRegStatePtr previous; + int ret; + + previous = ctxt->state; + ret = xmlFAParsePiece(ctxt); + if (ret != 0) { + if (xmlFAGenerateTransitions(ctxt, previous, + (CUR=='|' || CUR==')') ? to : NULL, ctxt->atom) < 0) + return(-1); + previous = ctxt->state; + ctxt->atom = NULL; + } + while ((ret != 0) && (ctxt->error == 0)) { + ret = xmlFAParsePiece(ctxt); + if (ret != 0) { + if (xmlFAGenerateTransitions(ctxt, previous, + (CUR=='|' || CUR==')') ? to : NULL, ctxt->atom) < 0) + return(-1); + previous = ctxt->state; + ctxt->atom = NULL; + } + } + return(0); +} + +/** + * xmlFAParseRegExp: + * @ctxt: a regexp parser context + * @top: is this the top-level expression ? + * + * [1] regExp ::= branch ( '|' branch )* + */ +static void +xmlFAParseRegExp(xmlRegParserCtxtPtr ctxt, int top) { + xmlRegStatePtr start, end; + + /* if not top start should have been generated by an epsilon trans */ + start = ctxt->state; + ctxt->end = NULL; + xmlFAParseBranch(ctxt, NULL); + if (top) { +#ifdef DEBUG_REGEXP_GRAPH + printf("State %d is final\n", ctxt->state->no); +#endif + ctxt->state->type = XML_REGEXP_FINAL_STATE; + } + if (CUR != '|') { + ctxt->end = ctxt->state; + return; + } + end = ctxt->state; + while ((CUR == '|') && (ctxt->error == 0)) { + NEXT; + ctxt->state = start; + ctxt->end = NULL; + xmlFAParseBranch(ctxt, end); + } + if (!top) { + ctxt->state = end; + ctxt->end = end; + } +} + +/************************************************************************ + * * + * The basic API * + * * + ************************************************************************/ + +/** + * xmlRegexpPrint: + * @output: the file for the output debug + * @regexp: the compiled regexp + * + * Print the content of the compiled regular expression + */ +void +xmlRegexpPrint(FILE *output, xmlRegexpPtr regexp) { + int i; + + if (output == NULL) + return; + fprintf(output, " regexp: "); + if (regexp == NULL) { + fprintf(output, "NULL\n"); + return; + } + fprintf(output, "'%s' ", regexp->string); + fprintf(output, "\n"); + fprintf(output, "%d atoms:\n", regexp->nbAtoms); + for (i = 0;i < regexp->nbAtoms; i++) { + fprintf(output, " %02d ", i); + xmlRegPrintAtom(output, regexp->atoms[i]); + } + fprintf(output, "%d states:", regexp->nbStates); + fprintf(output, "\n"); + for (i = 0;i < regexp->nbStates; i++) { + xmlRegPrintState(output, regexp->states[i]); + } + fprintf(output, "%d counters:\n", regexp->nbCounters); + for (i = 0;i < regexp->nbCounters; i++) { + fprintf(output, " %d: min %d max %d\n", i, regexp->counters[i].min, + regexp->counters[i].max); + } +} + +/** + * xmlRegexpCompile: + * @regexp: a regular expression string + * + * Parses a regular expression conforming to XML Schemas Part 2 Datatype + * Appendix F and builds an automata suitable for testing strings against + * that regular expression + * + * Returns the compiled expression or NULL in case of error + */ +xmlRegexpPtr +xmlRegexpCompile(const xmlChar *regexp) { + xmlRegexpPtr ret; + xmlRegParserCtxtPtr ctxt; + + ctxt = xmlRegNewParserCtxt(regexp); + if (ctxt == NULL) + return(NULL); + + /* initialize the parser */ + ctxt->end = NULL; + ctxt->start = ctxt->state = xmlRegNewState(ctxt); + xmlRegStatePush(ctxt, ctxt->start); + + /* parse the expression building an automata */ + xmlFAParseRegExp(ctxt, 1); + if (CUR != 0) { + ERROR("xmlFAParseRegExp: extra characters"); + } + if (ctxt->error != 0) { + xmlRegFreeParserCtxt(ctxt); + return(NULL); + } + ctxt->end = ctxt->state; + ctxt->start->type = XML_REGEXP_START_STATE; + ctxt->end->type = XML_REGEXP_FINAL_STATE; + + /* remove the Epsilon except for counted transitions */ + xmlFAEliminateEpsilonTransitions(ctxt); + + + if (ctxt->error != 0) { + xmlRegFreeParserCtxt(ctxt); + return(NULL); + } + ret = xmlRegEpxFromParse(ctxt); + xmlRegFreeParserCtxt(ctxt); + return(ret); +} + +/** + * xmlRegexpExec: + * @comp: the compiled regular expression + * @content: the value to check against the regular expression + * + * Check if the regular expression generates the value + * + * Returns 1 if it matches, 0 if not and a negative value in case of error + */ +int +xmlRegexpExec(xmlRegexpPtr comp, const xmlChar *content) { + if ((comp == NULL) || (content == NULL)) + return(-1); + return(xmlFARegExec(comp, content)); +} + +/** + * xmlRegexpIsDeterminist: + * @comp: the compiled regular expression + * + * Check if the regular expression is determinist + * + * Returns 1 if it yes, 0 if not and a negative value in case of error + */ +int +xmlRegexpIsDeterminist(xmlRegexpPtr comp) { + xmlAutomataPtr am; + int ret; + + if (comp == NULL) + return(-1); + if (comp->determinist != -1) + return(comp->determinist); + + am = xmlNewAutomata(); + if (am->states != NULL) { + int i; + + for (i = 0;i < am->nbStates;i++) + xmlRegFreeState(am->states[i]); + xmlFree(am->states); + } + am->nbAtoms = comp->nbAtoms; + am->atoms = comp->atoms; + am->nbStates = comp->nbStates; + am->states = comp->states; + am->determinist = -1; + am->flags = comp->flags; + ret = xmlFAComputesDeterminism(am); + am->atoms = NULL; + am->states = NULL; + xmlFreeAutomata(am); + comp->determinist = ret; + return(ret); +} + +/** + * xmlRegFreeRegexp: + * @regexp: the regexp + * + * Free a regexp + */ +void +xmlRegFreeRegexp(xmlRegexpPtr regexp) { + int i; + if (regexp == NULL) + return; + + if (regexp->string != NULL) + xmlFree(regexp->string); + if (regexp->states != NULL) { + for (i = 0;i < regexp->nbStates;i++) + xmlRegFreeState(regexp->states[i]); + xmlFree(regexp->states); + } + if (regexp->atoms != NULL) { + for (i = 0;i < regexp->nbAtoms;i++) + xmlRegFreeAtom(regexp->atoms[i]); + xmlFree(regexp->atoms); + } + if (regexp->counters != NULL) + xmlFree(regexp->counters); + if (regexp->compact != NULL) + xmlFree(regexp->compact); + if (regexp->transdata != NULL) + xmlFree(regexp->transdata); + if (regexp->stringMap != NULL) { + for (i = 0; i < regexp->nbstrings;i++) + xmlFree(regexp->stringMap[i]); + xmlFree(regexp->stringMap); + } + + xmlFree(regexp); +} + +#ifdef LIBXML_AUTOMATA_ENABLED +/************************************************************************ + * * + * The Automata interface * + * * + ************************************************************************/ + +/** + * xmlNewAutomata: + * + * Create a new automata + * + * Returns the new object or NULL in case of failure + */ +xmlAutomataPtr +xmlNewAutomata(void) { + xmlAutomataPtr ctxt; + + ctxt = xmlRegNewParserCtxt(NULL); + if (ctxt == NULL) + return(NULL); + + /* initialize the parser */ + ctxt->end = NULL; + ctxt->start = ctxt->state = xmlRegNewState(ctxt); + if (ctxt->start == NULL) { + xmlFreeAutomata(ctxt); + return(NULL); + } + ctxt->start->type = XML_REGEXP_START_STATE; + if (xmlRegStatePush(ctxt, ctxt->start) < 0) { + xmlRegFreeState(ctxt->start); + xmlFreeAutomata(ctxt); + return(NULL); + } + ctxt->flags = 0; + + return(ctxt); +} + +/** + * xmlFreeAutomata: + * @am: an automata + * + * Free an automata + */ +void +xmlFreeAutomata(xmlAutomataPtr am) { + if (am == NULL) + return; + xmlRegFreeParserCtxt(am); +} + +/** + * xmlAutomataSetFlags: + * @am: an automata + * @flags: a set of internal flags + * + * Set some flags on the automata + */ +void +xmlAutomataSetFlags(xmlAutomataPtr am, int flags) { + if (am == NULL) + return; + am->flags |= flags; +} + +/** + * xmlAutomataGetInitState: + * @am: an automata + * + * Initial state lookup + * + * Returns the initial state of the automata + */ +xmlAutomataStatePtr +xmlAutomataGetInitState(xmlAutomataPtr am) { + if (am == NULL) + return(NULL); + return(am->start); +} + +/** + * xmlAutomataSetFinalState: + * @am: an automata + * @state: a state in this automata + * + * Makes that state a final state + * + * Returns 0 or -1 in case of error + */ +int +xmlAutomataSetFinalState(xmlAutomataPtr am, xmlAutomataStatePtr state) { + if ((am == NULL) || (state == NULL)) + return(-1); + state->type = XML_REGEXP_FINAL_STATE; + return(0); +} + +/** + * xmlAutomataNewTransition: + * @am: an automata + * @from: the starting point of the transition + * @to: the target point of the transition or NULL + * @token: the input string associated to that transition + * @data: data passed to the callback function if the transition is activated + * + * If @to is NULL, this creates first a new target state in the automata + * and then adds a transition from the @from state to the target state + * activated by the value of @token + * + * Returns the target state or NULL in case of error + */ +xmlAutomataStatePtr +xmlAutomataNewTransition(xmlAutomataPtr am, xmlAutomataStatePtr from, + xmlAutomataStatePtr to, const xmlChar *token, + void *data) { + xmlRegAtomPtr atom; + + if ((am == NULL) || (from == NULL) || (token == NULL)) + return(NULL); + atom = xmlRegNewAtom(am, XML_REGEXP_STRING); + if (atom == NULL) + return(NULL); + atom->data = data; + if (atom == NULL) + return(NULL); + atom->valuep = xmlStrdup(token); + + if (xmlFAGenerateTransitions(am, from, to, atom) < 0) { + xmlRegFreeAtom(atom); + return(NULL); + } + if (to == NULL) + return(am->state); + return(to); +} + +/** + * xmlAutomataNewTransition2: + * @am: an automata + * @from: the starting point of the transition + * @to: the target point of the transition or NULL + * @token: the first input string associated to that transition + * @token2: the second input string associated to that transition + * @data: data passed to the callback function if the transition is activated + * + * If @to is NULL, this creates first a new target state in the automata + * and then adds a transition from the @from state to the target state + * activated by the value of @token + * + * Returns the target state or NULL in case of error + */ +xmlAutomataStatePtr +xmlAutomataNewTransition2(xmlAutomataPtr am, xmlAutomataStatePtr from, + xmlAutomataStatePtr to, const xmlChar *token, + const xmlChar *token2, void *data) { + xmlRegAtomPtr atom; + + if ((am == NULL) || (from == NULL) || (token == NULL)) + return(NULL); + atom = xmlRegNewAtom(am, XML_REGEXP_STRING); + if (atom == NULL) + return(NULL); + atom->data = data; + if ((token2 == NULL) || (*token2 == 0)) { + atom->valuep = xmlStrdup(token); + } else { + int lenn, lenp; + xmlChar *str; + + lenn = strlen((char *) token2); + lenp = strlen((char *) token); + + str = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2); + if (str == NULL) { + xmlRegFreeAtom(atom); + return(NULL); + } + memcpy(&str[0], token, lenp); + str[lenp] = '|'; + memcpy(&str[lenp + 1], token2, lenn); + str[lenn + lenp + 1] = 0; + + atom->valuep = str; + } + + if (xmlFAGenerateTransitions(am, from, to, atom) < 0) { + xmlRegFreeAtom(atom); + return(NULL); + } + if (to == NULL) + return(am->state); + return(to); +} + +/** + * xmlAutomataNewNegTrans: + * @am: an automata + * @from: the starting point of the transition + * @to: the target point of the transition or NULL + * @token: the first input string associated to that transition + * @token2: the second input string associated to that transition + * @data: data passed to the callback function if the transition is activated + * + * If @to is NULL, this creates first a new target state in the automata + * and then adds a transition from the @from state to the target state + * activated by any value except (@token,@token2) + * Note that if @token2 is not NULL, then (X, NULL) won't match to follow + # the semantic of XSD ##other + * + * Returns the target state or NULL in case of error + */ +xmlAutomataStatePtr +xmlAutomataNewNegTrans(xmlAutomataPtr am, xmlAutomataStatePtr from, + xmlAutomataStatePtr to, const xmlChar *token, + const xmlChar *token2, void *data) { + xmlRegAtomPtr atom; + xmlChar err_msg[200]; + + if ((am == NULL) || (from == NULL) || (token == NULL)) + return(NULL); + atom = xmlRegNewAtom(am, XML_REGEXP_STRING); + if (atom == NULL) + return(NULL); + atom->data = data; + atom->neg = 1; + if ((token2 == NULL) || (*token2 == 0)) { + atom->valuep = xmlStrdup(token); + } else { + int lenn, lenp; + xmlChar *str; + + lenn = strlen((char *) token2); + lenp = strlen((char *) token); + + str = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2); + if (str == NULL) { + xmlRegFreeAtom(atom); + return(NULL); + } + memcpy(&str[0], token, lenp); + str[lenp] = '|'; + memcpy(&str[lenp + 1], token2, lenn); + str[lenn + lenp + 1] = 0; + + atom->valuep = str; + } + snprintf((char *) err_msg, 199, "not %s", (const char *) atom->valuep); + err_msg[199] = 0; + atom->valuep2 = xmlStrdup(err_msg); + + if (xmlFAGenerateTransitions(am, from, to, atom) < 0) { + xmlRegFreeAtom(atom); + return(NULL); + } + am->negs++; + if (to == NULL) + return(am->state); + return(to); +} + +/** + * xmlAutomataNewCountTrans2: + * @am: an automata + * @from: the starting point of the transition + * @to: the target point of the transition or NULL + * @token: the input string associated to that transition + * @token2: the second input string associated to that transition + * @min: the minimum successive occurences of token + * @max: the maximum successive occurences of token + * @data: data associated to the transition + * + * If @to is NULL, this creates first a new target state in the automata + * and then adds a transition from the @from state to the target state + * activated by a succession of input of value @token and @token2 and + * whose number is between @min and @max + * + * Returns the target state or NULL in case of error + */ +xmlAutomataStatePtr +xmlAutomataNewCountTrans2(xmlAutomataPtr am, xmlAutomataStatePtr from, + xmlAutomataStatePtr to, const xmlChar *token, + const xmlChar *token2, + int min, int max, void *data) { + xmlRegAtomPtr atom; + int counter; + + if ((am == NULL) || (from == NULL) || (token == NULL)) + return(NULL); + if (min < 0) + return(NULL); + if ((max < min) || (max < 1)) + return(NULL); + atom = xmlRegNewAtom(am, XML_REGEXP_STRING); + if (atom == NULL) + return(NULL); + if ((token2 == NULL) || (*token2 == 0)) { + atom->valuep = xmlStrdup(token); + } else { + int lenn, lenp; + xmlChar *str; + + lenn = strlen((char *) token2); + lenp = strlen((char *) token); + + str = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2); + if (str == NULL) { + xmlRegFreeAtom(atom); + return(NULL); + } + memcpy(&str[0], token, lenp); + str[lenp] = '|'; + memcpy(&str[lenp + 1], token2, lenn); + str[lenn + lenp + 1] = 0; + + atom->valuep = str; + } + atom->data = data; + if (min == 0) + atom->min = 1; + else + atom->min = min; + atom->max = max; + + /* + * associate a counter to the transition. + */ + counter = xmlRegGetCounter(am); + am->counters[counter].min = min; + am->counters[counter].max = max; + + /* xmlFAGenerateTransitions(am, from, to, atom); */ + if (to == NULL) { + to = xmlRegNewState(am); + xmlRegStatePush(am, to); + } + xmlRegStateAddTrans(am, from, atom, to, counter, -1); + xmlRegAtomPush(am, atom); + am->state = to; + + if (to == NULL) + to = am->state; + if (to == NULL) + return(NULL); + if (min == 0) + xmlFAGenerateEpsilonTransition(am, from, to); + return(to); +} + +/** + * xmlAutomataNewCountTrans: + * @am: an automata + * @from: the starting point of the transition + * @to: the target point of the transition or NULL + * @token: the input string associated to that transition + * @min: the minimum successive occurences of token + * @max: the maximum successive occurences of token + * @data: data associated to the transition + * + * If @to is NULL, this creates first a new target state in the automata + * and then adds a transition from the @from state to the target state + * activated by a succession of input of value @token and whose number + * is between @min and @max + * + * Returns the target state or NULL in case of error + */ +xmlAutomataStatePtr +xmlAutomataNewCountTrans(xmlAutomataPtr am, xmlAutomataStatePtr from, + xmlAutomataStatePtr to, const xmlChar *token, + int min, int max, void *data) { + xmlRegAtomPtr atom; + int counter; + + if ((am == NULL) || (from == NULL) || (token == NULL)) + return(NULL); + if (min < 0) + return(NULL); + if ((max < min) || (max < 1)) + return(NULL); + atom = xmlRegNewAtom(am, XML_REGEXP_STRING); + if (atom == NULL) + return(NULL); + atom->valuep = xmlStrdup(token); + atom->data = data; + if (min == 0) + atom->min = 1; + else + atom->min = min; + atom->max = max; + + /* + * associate a counter to the transition. + */ + counter = xmlRegGetCounter(am); + am->counters[counter].min = min; + am->counters[counter].max = max; + + /* xmlFAGenerateTransitions(am, from, to, atom); */ + if (to == NULL) { + to = xmlRegNewState(am); + xmlRegStatePush(am, to); + } + xmlRegStateAddTrans(am, from, atom, to, counter, -1); + xmlRegAtomPush(am, atom); + am->state = to; + + if (to == NULL) + to = am->state; + if (to == NULL) + return(NULL); + if (min == 0) + xmlFAGenerateEpsilonTransition(am, from, to); + return(to); +} + +/** + * xmlAutomataNewOnceTrans2: + * @am: an automata + * @from: the starting point of the transition + * @to: the target point of the transition or NULL + * @token: the input string associated to that transition + * @token2: the second input string associated to that transition + * @min: the minimum successive occurences of token + * @max: the maximum successive occurences of token + * @data: data associated to the transition + * + * If @to is NULL, this creates first a new target state in the automata + * and then adds a transition from the @from state to the target state + * activated by a succession of input of value @token and @token2 and whose + * number is between @min and @max, moreover that transition can only be + * crossed once. + * + * Returns the target state or NULL in case of error + */ +xmlAutomataStatePtr +xmlAutomataNewOnceTrans2(xmlAutomataPtr am, xmlAutomataStatePtr from, + xmlAutomataStatePtr to, const xmlChar *token, + const xmlChar *token2, + int min, int max, void *data) { + xmlRegAtomPtr atom; + int counter; + + if ((am == NULL) || (from == NULL) || (token == NULL)) + return(NULL); + if (min < 1) + return(NULL); + if ((max < min) || (max < 1)) + return(NULL); + atom = xmlRegNewAtom(am, XML_REGEXP_STRING); + if (atom == NULL) + return(NULL); + if ((token2 == NULL) || (*token2 == 0)) { + atom->valuep = xmlStrdup(token); + } else { + int lenn, lenp; + xmlChar *str; + + lenn = strlen((char *) token2); + lenp = strlen((char *) token); + + str = (xmlChar *) xmlMallocAtomic(lenn + lenp + 2); + if (str == NULL) { + xmlRegFreeAtom(atom); + return(NULL); + } + memcpy(&str[0], token, lenp); + str[lenp] = '|'; + memcpy(&str[lenp + 1], token2, lenn); + str[lenn + lenp + 1] = 0; + + atom->valuep = str; + } + atom->data = data; + atom->quant = XML_REGEXP_QUANT_ONCEONLY; + atom->min = min; + atom->max = max; + /* + * associate a counter to the transition. + */ + counter = xmlRegGetCounter(am); + am->counters[counter].min = 1; + am->counters[counter].max = 1; + + /* xmlFAGenerateTransitions(am, from, to, atom); */ + if (to == NULL) { + to = xmlRegNewState(am); + xmlRegStatePush(am, to); + } + xmlRegStateAddTrans(am, from, atom, to, counter, -1); + xmlRegAtomPush(am, atom); + am->state = to; + return(to); +} + + + +/** + * xmlAutomataNewOnceTrans: + * @am: an automata + * @from: the starting point of the transition + * @to: the target point of the transition or NULL + * @token: the input string associated to that transition + * @min: the minimum successive occurences of token + * @max: the maximum successive occurences of token + * @data: data associated to the transition + * + * If @to is NULL, this creates first a new target state in the automata + * and then adds a transition from the @from state to the target state + * activated by a succession of input of value @token and whose number + * is between @min and @max, moreover that transition can only be crossed + * once. + * + * Returns the target state or NULL in case of error + */ +xmlAutomataStatePtr +xmlAutomataNewOnceTrans(xmlAutomataPtr am, xmlAutomataStatePtr from, + xmlAutomataStatePtr to, const xmlChar *token, + int min, int max, void *data) { + xmlRegAtomPtr atom; + int counter; + + if ((am == NULL) || (from == NULL) || (token == NULL)) + return(NULL); + if (min < 1) + return(NULL); + if ((max < min) || (max < 1)) + return(NULL); + atom = xmlRegNewAtom(am, XML_REGEXP_STRING); + if (atom == NULL) + return(NULL); + atom->valuep = xmlStrdup(token); + atom->data = data; + atom->quant = XML_REGEXP_QUANT_ONCEONLY; + atom->min = min; + atom->max = max; + /* + * associate a counter to the transition. + */ + counter = xmlRegGetCounter(am); + am->counters[counter].min = 1; + am->counters[counter].max = 1; + + /* xmlFAGenerateTransitions(am, from, to, atom); */ + if (to == NULL) { + to = xmlRegNewState(am); + xmlRegStatePush(am, to); + } + xmlRegStateAddTrans(am, from, atom, to, counter, -1); + xmlRegAtomPush(am, atom); + am->state = to; + return(to); +} + +/** + * xmlAutomataNewState: + * @am: an automata + * + * Create a new disconnected state in the automata + * + * Returns the new state or NULL in case of error + */ +xmlAutomataStatePtr +xmlAutomataNewState(xmlAutomataPtr am) { + xmlAutomataStatePtr to; + + if (am == NULL) + return(NULL); + to = xmlRegNewState(am); + xmlRegStatePush(am, to); + return(to); +} + +/** + * xmlAutomataNewEpsilon: + * @am: an automata + * @from: the starting point of the transition + * @to: the target point of the transition or NULL + * + * If @to is NULL, this creates first a new target state in the automata + * and then adds an epsilon transition from the @from state to the + * target state + * + * Returns the target state or NULL in case of error + */ +xmlAutomataStatePtr +xmlAutomataNewEpsilon(xmlAutomataPtr am, xmlAutomataStatePtr from, + xmlAutomataStatePtr to) { + if ((am == NULL) || (from == NULL)) + return(NULL); + xmlFAGenerateEpsilonTransition(am, from, to); + if (to == NULL) + return(am->state); + return(to); +} + +/** + * xmlAutomataNewAllTrans: + * @am: an automata + * @from: the starting point of the transition + * @to: the target point of the transition or NULL + * @lax: allow to transition if not all all transitions have been activated + * + * If @to is NULL, this creates first a new target state in the automata + * and then adds a an ALL transition from the @from state to the + * target state. That transition is an epsilon transition allowed only when + * all transitions from the @from node have been activated. + * + * Returns the target state or NULL in case of error + */ +xmlAutomataStatePtr +xmlAutomataNewAllTrans(xmlAutomataPtr am, xmlAutomataStatePtr from, + xmlAutomataStatePtr to, int lax) { + if ((am == NULL) || (from == NULL)) + return(NULL); + xmlFAGenerateAllTransition(am, from, to, lax); + if (to == NULL) + return(am->state); + return(to); +} + +/** + * xmlAutomataNewCounter: + * @am: an automata + * @min: the minimal value on the counter + * @max: the maximal value on the counter + * + * Create a new counter + * + * Returns the counter number or -1 in case of error + */ +int +xmlAutomataNewCounter(xmlAutomataPtr am, int min, int max) { + int ret; + + if (am == NULL) + return(-1); + + ret = xmlRegGetCounter(am); + if (ret < 0) + return(-1); + am->counters[ret].min = min; + am->counters[ret].max = max; + return(ret); +} + +/** + * xmlAutomataNewCountedTrans: + * @am: an automata + * @from: the starting point of the transition + * @to: the target point of the transition or NULL + * @counter: the counter associated to that transition + * + * If @to is NULL, this creates first a new target state in the automata + * and then adds an epsilon transition from the @from state to the target state + * which will increment the counter provided + * + * Returns the target state or NULL in case of error + */ +xmlAutomataStatePtr +xmlAutomataNewCountedTrans(xmlAutomataPtr am, xmlAutomataStatePtr from, + xmlAutomataStatePtr to, int counter) { + if ((am == NULL) || (from == NULL) || (counter < 0)) + return(NULL); + xmlFAGenerateCountedEpsilonTransition(am, from, to, counter); + if (to == NULL) + return(am->state); + return(to); +} + +/** + * xmlAutomataNewCounterTrans: + * @am: an automata + * @from: the starting point of the transition + * @to: the target point of the transition or NULL + * @counter: the counter associated to that transition + * + * If @to is NULL, this creates first a new target state in the automata + * and then adds an epsilon transition from the @from state to the target state + * which will be allowed only if the counter is within the right range. + * + * Returns the target state or NULL in case of error + */ +xmlAutomataStatePtr +xmlAutomataNewCounterTrans(xmlAutomataPtr am, xmlAutomataStatePtr from, + xmlAutomataStatePtr to, int counter) { + if ((am == NULL) || (from == NULL) || (counter < 0)) + return(NULL); + xmlFAGenerateCountedTransition(am, from, to, counter); + if (to == NULL) + return(am->state); + return(to); +} + +/** + * xmlAutomataCompile: + * @am: an automata + * + * Compile the automata into a Reg Exp ready for being executed. + * The automata should be free after this point. + * + * Returns the compiled regexp or NULL in case of error + */ +xmlRegexpPtr +xmlAutomataCompile(xmlAutomataPtr am) { + xmlRegexpPtr ret; + + if ((am == NULL) || (am->error != 0)) return(NULL); + xmlFAEliminateEpsilonTransitions(am); + /* xmlFAComputesDeterminism(am); */ + ret = xmlRegEpxFromParse(am); + + return(ret); +} + +/** + * xmlAutomataIsDeterminist: + * @am: an automata + * + * Checks if an automata is determinist. + * + * Returns 1 if true, 0 if not, and -1 in case of error + */ +int +xmlAutomataIsDeterminist(xmlAutomataPtr am) { + int ret; + + if (am == NULL) + return(-1); + + ret = xmlFAComputesDeterminism(am); + return(ret); +} +#endif /* LIBXML_AUTOMATA_ENABLED */ + +#ifdef LIBXML_EXPR_ENABLED +/************************************************************************ + * * + * Formal Expression handling code * + * * + ************************************************************************/ +/************************************************************************ + * * + * Expression handling context * + * * + ************************************************************************/ + +struct _xmlExpCtxt { + xmlDictPtr dict; + xmlExpNodePtr *table; + int size; + int nbElems; + int nb_nodes; + int maxNodes; + const char *expr; + const char *cur; + int nb_cons; + int tabSize; +}; + +/** + * xmlExpNewCtxt: + * @maxNodes: the maximum number of nodes + * @dict: optional dictionnary to use internally + * + * Creates a new context for manipulating expressions + * + * Returns the context or NULL in case of error + */ +xmlExpCtxtPtr +xmlExpNewCtxt(int maxNodes, xmlDictPtr dict) { + xmlExpCtxtPtr ret; + int size = 256; + + if (maxNodes <= 4096) + maxNodes = 4096; + + ret = (xmlExpCtxtPtr) xmlMalloc(sizeof(xmlExpCtxt)); + if (ret == NULL) + return(NULL); + memset(ret, 0, sizeof(xmlExpCtxt)); + ret->size = size; + ret->nbElems = 0; + ret->maxNodes = maxNodes; + ret->table = xmlMalloc(size * sizeof(xmlExpNodePtr)); + if (ret->table == NULL) { + xmlFree(ret); + return(NULL); + } + memset(ret->table, 0, size * sizeof(xmlExpNodePtr)); + if (dict == NULL) { + ret->dict = xmlDictCreate(); + if (ret->dict == NULL) { + xmlFree(ret->table); + xmlFree(ret); + return(NULL); + } + } else { + ret->dict = dict; + xmlDictReference(ret->dict); + } + return(ret); +} + +/** + * xmlExpFreeCtxt: + * @ctxt: an expression context + * + * Free an expression context + */ +void +xmlExpFreeCtxt(xmlExpCtxtPtr ctxt) { + if (ctxt == NULL) + return; + xmlDictFree(ctxt->dict); + if (ctxt->table != NULL) + xmlFree(ctxt->table); + xmlFree(ctxt); +} + +/************************************************************************ + * * + * Structure associated to an expression node * + * * + ************************************************************************/ +#define MAX_NODES 10000 + +/* #define DEBUG_DERIV */ + +/* + * TODO: + * - Wildcards + * - public API for creation + * + * Started + * - regression testing + * + * Done + * - split into module and test tool + * - memleaks + */ + +typedef enum { + XML_EXP_NILABLE = (1 << 0) +} xmlExpNodeInfo; + +#define IS_NILLABLE(node) ((node)->info & XML_EXP_NILABLE) + +struct _xmlExpNode { + unsigned char type;/* xmlExpNodeType */ + unsigned char info;/* OR of xmlExpNodeInfo */ + unsigned short key; /* the hash key */ + unsigned int ref; /* The number of references */ + int c_max; /* the maximum length it can consume */ + xmlExpNodePtr exp_left; + xmlExpNodePtr next;/* the next node in the hash table or free list */ + union { + struct { + int f_min; + int f_max; + } count; + struct { + xmlExpNodePtr f_right; + } children; + const xmlChar *f_str; + } field; +}; + +#define exp_min field.count.f_min +#define exp_max field.count.f_max +/* #define exp_left field.children.f_left */ +#define exp_right field.children.f_right +#define exp_str field.f_str + +static xmlExpNodePtr xmlExpNewNode(xmlExpCtxtPtr ctxt, xmlExpNodeType type); +static xmlExpNode forbiddenExpNode = { + XML_EXP_FORBID, 0, 0, 0, 0, NULL, NULL, {{ 0, 0}} +}; +xmlExpNodePtr forbiddenExp = &forbiddenExpNode; +static xmlExpNode emptyExpNode = { + XML_EXP_EMPTY, 1, 0, 0, 0, NULL, NULL, {{ 0, 0}} +}; +xmlExpNodePtr emptyExp = &emptyExpNode; + +/************************************************************************ + * * + * The custom hash table for unicity and canonicalization * + * of sub-expressions pointers * + * * + ************************************************************************/ +/* + * xmlExpHashNameComputeKey: + * Calculate the hash key for a token + */ +static unsigned short +xmlExpHashNameComputeKey(const xmlChar *name) { + unsigned short value = 0L; + char ch; + + if (name != NULL) { + value += 30 * (*name); + while ((ch = *name++) != 0) { + value = value ^ ((value << 5) + (value >> 3) + (unsigned long)ch); + } + } + return (value); +} + +/* + * xmlExpHashComputeKey: + * Calculate the hash key for a compound expression + */ +static unsigned short +xmlExpHashComputeKey(xmlExpNodeType type, xmlExpNodePtr left, + xmlExpNodePtr right) { + unsigned long value; + unsigned short ret; + + switch (type) { + case XML_EXP_SEQ: + value = left->key; + value += right->key; + value *= 3; + ret = (unsigned short) value; + break; + case XML_EXP_OR: + value = left->key; + value += right->key; + value *= 7; + ret = (unsigned short) value; + break; + case XML_EXP_COUNT: + value = left->key; + value += right->key; + ret = (unsigned short) value; + break; + default: + ret = 0; + } + return(ret); +} + + +static xmlExpNodePtr +xmlExpNewNode(xmlExpCtxtPtr ctxt, xmlExpNodeType type) { + xmlExpNodePtr ret; + + if (ctxt->nb_nodes >= MAX_NODES) + return(NULL); + ret = (xmlExpNodePtr) xmlMalloc(sizeof(xmlExpNode)); + if (ret == NULL) + return(NULL); + memset(ret, 0, sizeof(xmlExpNode)); + ret->type = type; + ret->next = NULL; + ctxt->nb_nodes++; + ctxt->nb_cons++; + return(ret); +} + +/** + * xmlExpHashGetEntry: + * @table: the hash table + * + * Get the unique entry from the hash table. The entry is created if + * needed. @left and @right are consumed, i.e. their ref count will + * be decremented by the operation. + * + * Returns the pointer or NULL in case of error + */ +static xmlExpNodePtr +xmlExpHashGetEntry(xmlExpCtxtPtr ctxt, xmlExpNodeType type, + xmlExpNodePtr left, xmlExpNodePtr right, + const xmlChar *name, int min, int max) { + unsigned short kbase, key; + xmlExpNodePtr entry; + xmlExpNodePtr insert; + + if (ctxt == NULL) + return(NULL); + + /* + * Check for duplicate and insertion location. + */ + if (type == XML_EXP_ATOM) { + kbase = xmlExpHashNameComputeKey(name); + } else if (type == XML_EXP_COUNT) { + /* COUNT reduction rule 1 */ + /* a{1} -> a */ + if (min == max) { + if (min == 1) { + return(left); + } + if (min == 0) { + xmlExpFree(ctxt, left); + return(emptyExp); + } + } + if (min < 0) { + xmlExpFree(ctxt, left); + return(forbiddenExp); + } + if (max == -1) + kbase = min + 79; + else + kbase = max - min; + kbase += left->key; + } else if (type == XML_EXP_OR) { + /* Forbid reduction rules */ + if (left->type == XML_EXP_FORBID) { + xmlExpFree(ctxt, left); + return(right); + } + if (right->type == XML_EXP_FORBID) { + xmlExpFree(ctxt, right); + return(left); + } + + /* OR reduction rule 1 */ + /* a | a reduced to a */ + if (left == right) { + left->ref--; + return(left); + } + /* OR canonicalization rule 1 */ + /* linearize (a | b) | c into a | (b | c) */ + if ((left->type == XML_EXP_OR) && (right->type != XML_EXP_OR)) { + xmlExpNodePtr tmp = left; + left = right; + right = tmp; + } + /* OR reduction rule 2 */ + /* a | (a | b) and b | (a | b) are reduced to a | b */ + if (right->type == XML_EXP_OR) { + if ((left == right->exp_left) || + (left == right->exp_right)) { + xmlExpFree(ctxt, left); + return(right); + } + } + /* OR canonicalization rule 2 */ + /* linearize (a | b) | c into a | (b | c) */ + if (left->type == XML_EXP_OR) { + xmlExpNodePtr tmp; + + /* OR canonicalization rule 2 */ + if ((left->exp_right->type != XML_EXP_OR) && + (left->exp_right->key < left->exp_left->key)) { + tmp = left->exp_right; + left->exp_right = left->exp_left; + left->exp_left = tmp; + } + left->exp_right->ref++; + tmp = xmlExpHashGetEntry(ctxt, XML_EXP_OR, left->exp_right, right, + NULL, 0, 0); + left->exp_left->ref++; + tmp = xmlExpHashGetEntry(ctxt, XML_EXP_OR, left->exp_left, tmp, + NULL, 0, 0); + + xmlExpFree(ctxt, left); + return(tmp); + } + if (right->type == XML_EXP_OR) { + /* Ordering in the tree */ + /* C | (A | B) -> A | (B | C) */ + if (left->key > right->exp_right->key) { + xmlExpNodePtr tmp; + right->exp_right->ref++; + tmp = xmlExpHashGetEntry(ctxt, XML_EXP_OR, right->exp_right, + left, NULL, 0, 0); + right->exp_left->ref++; + tmp = xmlExpHashGetEntry(ctxt, XML_EXP_OR, right->exp_left, + tmp, NULL, 0, 0); + xmlExpFree(ctxt, right); + return(tmp); + } + /* Ordering in the tree */ + /* B | (A | C) -> A | (B | C) */ + if (left->key > right->exp_left->key) { + xmlExpNodePtr tmp; + right->exp_right->ref++; + tmp = xmlExpHashGetEntry(ctxt, XML_EXP_OR, left, + right->exp_right, NULL, 0, 0); + right->exp_left->ref++; + tmp = xmlExpHashGetEntry(ctxt, XML_EXP_OR, right->exp_left, + tmp, NULL, 0, 0); + xmlExpFree(ctxt, right); + return(tmp); + } + } + /* we know both types are != XML_EXP_OR here */ + else if (left->key > right->key) { + xmlExpNodePtr tmp = left; + left = right; + right = tmp; + } + kbase = xmlExpHashComputeKey(type, left, right); + } else if (type == XML_EXP_SEQ) { + /* Forbid reduction rules */ + if (left->type == XML_EXP_FORBID) { + xmlExpFree(ctxt, right); + return(left); + } + if (right->type == XML_EXP_FORBID) { + xmlExpFree(ctxt, left); + return(right); + } + /* Empty reduction rules */ + if (right->type == XML_EXP_EMPTY) { + return(left); + } + if (left->type == XML_EXP_EMPTY) { + return(right); + } + kbase = xmlExpHashComputeKey(type, left, right); + } else + return(NULL); + + key = kbase % ctxt->size; + if (ctxt->table[key] != NULL) { + for (insert = ctxt->table[key]; insert != NULL; + insert = insert->next) { + if ((insert->key == kbase) && + (insert->type == type)) { + if (type == XML_EXP_ATOM) { + if (name == insert->exp_str) { + insert->ref++; + return(insert); + } + } else if (type == XML_EXP_COUNT) { + if ((insert->exp_min == min) && (insert->exp_max == max) && + (insert->exp_left == left)) { + insert->ref++; + left->ref--; + return(insert); + } + } else if ((insert->exp_left == left) && + (insert->exp_right == right)) { + insert->ref++; + left->ref--; + right->ref--; + return(insert); + } + } + } + } + + entry = xmlExpNewNode(ctxt, type); + if (entry == NULL) + return(NULL); + entry->key = kbase; + if (type == XML_EXP_ATOM) { + entry->exp_str = name; + entry->c_max = 1; + } else if (type == XML_EXP_COUNT) { + entry->exp_min = min; + entry->exp_max = max; + entry->exp_left = left; + if ((min == 0) || (IS_NILLABLE(left))) + entry->info |= XML_EXP_NILABLE; + if (max < 0) + entry->c_max = -1; + else + entry->c_max = max * entry->exp_left->c_max; + } else { + entry->exp_left = left; + entry->exp_right = right; + if (type == XML_EXP_OR) { + if ((IS_NILLABLE(left)) || (IS_NILLABLE(right))) + entry->info |= XML_EXP_NILABLE; + if ((entry->exp_left->c_max == -1) || + (entry->exp_right->c_max == -1)) + entry->c_max = -1; + else if (entry->exp_left->c_max > entry->exp_right->c_max) + entry->c_max = entry->exp_left->c_max; + else + entry->c_max = entry->exp_right->c_max; + } else { + if ((IS_NILLABLE(left)) && (IS_NILLABLE(right))) + entry->info |= XML_EXP_NILABLE; + if ((entry->exp_left->c_max == -1) || + (entry->exp_right->c_max == -1)) + entry->c_max = -1; + else + entry->c_max = entry->exp_left->c_max + entry->exp_right->c_max; + } + } + entry->ref = 1; + if (ctxt->table[key] != NULL) + entry->next = ctxt->table[key]; + + ctxt->table[key] = entry; + ctxt->nbElems++; + + return(entry); +} + +/** + * xmlExpFree: + * @ctxt: the expression context + * @exp: the expression + * + * Dereference the expression + */ +void +xmlExpFree(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp) { + if ((exp == NULL) || (exp == forbiddenExp) || (exp == emptyExp)) + return; + exp->ref--; + if (exp->ref == 0) { + unsigned short key; + + /* Unlink it first from the hash table */ + key = exp->key % ctxt->size; + if (ctxt->table[key] == exp) { + ctxt->table[key] = exp->next; + } else { + xmlExpNodePtr tmp; + + tmp = ctxt->table[key]; + while (tmp != NULL) { + if (tmp->next == exp) { + tmp->next = exp->next; + break; + } + tmp = tmp->next; + } + } + + if ((exp->type == XML_EXP_SEQ) || (exp->type == XML_EXP_OR)) { + xmlExpFree(ctxt, exp->exp_left); + xmlExpFree(ctxt, exp->exp_right); + } else if (exp->type == XML_EXP_COUNT) { + xmlExpFree(ctxt, exp->exp_left); + } + xmlFree(exp); + ctxt->nb_nodes--; + } +} + +/** + * xmlExpRef: + * @exp: the expression + * + * Increase the reference count of the expression + */ +void +xmlExpRef(xmlExpNodePtr exp) { + if (exp != NULL) + exp->ref++; +} + +/** + * xmlExpNewAtom: + * @ctxt: the expression context + * @name: the atom name + * @len: the atom name lenght in byte (or -1); + * + * Get the atom associated to this name from that context + * + * Returns the node or NULL in case of error + */ +xmlExpNodePtr +xmlExpNewAtom(xmlExpCtxtPtr ctxt, const xmlChar *name, int len) { + if ((ctxt == NULL) || (name == NULL)) + return(NULL); + name = xmlDictLookup(ctxt->dict, name, len); + if (name == NULL) + return(NULL); + return(xmlExpHashGetEntry(ctxt, XML_EXP_ATOM, NULL, NULL, name, 0, 0)); +} + +/** + * xmlExpNewOr: + * @ctxt: the expression context + * @left: left expression + * @right: right expression + * + * Get the atom associated to the choice @left | @right + * Note that @left and @right are consumed in the operation, to keep + * an handle on them use xmlExpRef() and use xmlExpFree() to release them, + * this is true even in case of failure (unless ctxt == NULL). + * + * Returns the node or NULL in case of error + */ +xmlExpNodePtr +xmlExpNewOr(xmlExpCtxtPtr ctxt, xmlExpNodePtr left, xmlExpNodePtr right) { + if (ctxt == NULL) + return(NULL); + if ((left == NULL) || (right == NULL)) { + xmlExpFree(ctxt, left); + xmlExpFree(ctxt, right); + return(NULL); + } + return(xmlExpHashGetEntry(ctxt, XML_EXP_OR, left, right, NULL, 0, 0)); +} + +/** + * xmlExpNewSeq: + * @ctxt: the expression context + * @left: left expression + * @right: right expression + * + * Get the atom associated to the sequence @left , @right + * Note that @left and @right are consumed in the operation, to keep + * an handle on them use xmlExpRef() and use xmlExpFree() to release them, + * this is true even in case of failure (unless ctxt == NULL). + * + * Returns the node or NULL in case of error + */ +xmlExpNodePtr +xmlExpNewSeq(xmlExpCtxtPtr ctxt, xmlExpNodePtr left, xmlExpNodePtr right) { + if (ctxt == NULL) + return(NULL); + if ((left == NULL) || (right == NULL)) { + xmlExpFree(ctxt, left); + xmlExpFree(ctxt, right); + return(NULL); + } + return(xmlExpHashGetEntry(ctxt, XML_EXP_SEQ, left, right, NULL, 0, 0)); +} + +/** + * xmlExpNewRange: + * @ctxt: the expression context + * @subset: the expression to be repeated + * @min: the lower bound for the repetition + * @max: the upper bound for the repetition, -1 means infinite + * + * Get the atom associated to the range (@subset){@min, @max} + * Note that @subset is consumed in the operation, to keep + * an handle on it use xmlExpRef() and use xmlExpFree() to release it, + * this is true even in case of failure (unless ctxt == NULL). + * + * Returns the node or NULL in case of error + */ +xmlExpNodePtr +xmlExpNewRange(xmlExpCtxtPtr ctxt, xmlExpNodePtr subset, int min, int max) { + if (ctxt == NULL) + return(NULL); + if ((subset == NULL) || (min < 0) || (max < -1) || + ((max >= 0) && (min > max))) { + xmlExpFree(ctxt, subset); + return(NULL); + } + return(xmlExpHashGetEntry(ctxt, XML_EXP_COUNT, subset, + NULL, NULL, min, max)); +} + +/************************************************************************ + * * + * Public API for operations on expressions * + * * + ************************************************************************/ + +static int +xmlExpGetLanguageInt(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, + const xmlChar**list, int len, int nb) { + int tmp, tmp2; +tail: + switch (exp->type) { + case XML_EXP_EMPTY: + return(0); + case XML_EXP_ATOM: + for (tmp = 0;tmp < nb;tmp++) + if (list[tmp] == exp->exp_str) + return(0); + if (nb >= len) + return(-2); + list[nb] = exp->exp_str; + return(1); + case XML_EXP_COUNT: + exp = exp->exp_left; + goto tail; + case XML_EXP_SEQ: + case XML_EXP_OR: + tmp = xmlExpGetLanguageInt(ctxt, exp->exp_left, list, len, nb); + if (tmp < 0) + return(tmp); + tmp2 = xmlExpGetLanguageInt(ctxt, exp->exp_right, list, len, + nb + tmp); + if (tmp2 < 0) + return(tmp2); + return(tmp + tmp2); + } + return(-1); +} + +/** + * xmlExpGetLanguage: + * @ctxt: the expression context + * @exp: the expression + * @langList: where to store the tokens + * @len: the allocated lenght of @list + * + * Find all the strings used in @exp and store them in @list + * + * Returns the number of unique strings found, -1 in case of errors and + * -2 if there is more than @len strings + */ +int +xmlExpGetLanguage(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, + const xmlChar**langList, int len) { + if ((ctxt == NULL) || (exp == NULL) || (langList == NULL) || (len <= 0)) + return(-1); + return(xmlExpGetLanguageInt(ctxt, exp, langList, len, 0)); +} + +static int +xmlExpGetStartInt(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, + const xmlChar**list, int len, int nb) { + int tmp, tmp2; +tail: + switch (exp->type) { + case XML_EXP_FORBID: + return(0); + case XML_EXP_EMPTY: + return(0); + case XML_EXP_ATOM: + for (tmp = 0;tmp < nb;tmp++) + if (list[tmp] == exp->exp_str) + return(0); + if (nb >= len) + return(-2); + list[nb] = exp->exp_str; + return(1); + case XML_EXP_COUNT: + exp = exp->exp_left; + goto tail; + case XML_EXP_SEQ: + tmp = xmlExpGetStartInt(ctxt, exp->exp_left, list, len, nb); + if (tmp < 0) + return(tmp); + if (IS_NILLABLE(exp->exp_left)) { + tmp2 = xmlExpGetStartInt(ctxt, exp->exp_right, list, len, + nb + tmp); + if (tmp2 < 0) + return(tmp2); + tmp += tmp2; + } + return(tmp); + case XML_EXP_OR: + tmp = xmlExpGetStartInt(ctxt, exp->exp_left, list, len, nb); + if (tmp < 0) + return(tmp); + tmp2 = xmlExpGetStartInt(ctxt, exp->exp_right, list, len, + nb + tmp); + if (tmp2 < 0) + return(tmp2); + return(tmp + tmp2); + } + return(-1); +} + +/** + * xmlExpGetStart: + * @ctxt: the expression context + * @exp: the expression + * @tokList: where to store the tokens + * @len: the allocated lenght of @list + * + * Find all the strings that appears at the start of the languages + * accepted by @exp and store them in @list. E.g. for (a, b) | c + * it will return the list [a, c] + * + * Returns the number of unique strings found, -1 in case of errors and + * -2 if there is more than @len strings + */ +int +xmlExpGetStart(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, + const xmlChar**tokList, int len) { + if ((ctxt == NULL) || (exp == NULL) || (tokList == NULL) || (len <= 0)) + return(-1); + return(xmlExpGetStartInt(ctxt, exp, tokList, len, 0)); +} + +/** + * xmlExpIsNillable: + * @exp: the expression + * + * Finds if the expression is nillable, i.e. if it accepts the empty sequqnce + * + * Returns 1 if nillable, 0 if not and -1 in case of error + */ +int +xmlExpIsNillable(xmlExpNodePtr exp) { + if (exp == NULL) + return(-1); + return(IS_NILLABLE(exp) != 0); +} + +static xmlExpNodePtr +xmlExpStringDeriveInt(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, const xmlChar *str) +{ + xmlExpNodePtr ret; + + switch (exp->type) { + case XML_EXP_EMPTY: + return(forbiddenExp); + case XML_EXP_FORBID: + return(forbiddenExp); + case XML_EXP_ATOM: + if (exp->exp_str == str) { +#ifdef DEBUG_DERIV + printf("deriv atom: equal => Empty\n"); +#endif + ret = emptyExp; + } else { +#ifdef DEBUG_DERIV + printf("deriv atom: mismatch => forbid\n"); +#endif + /* TODO wildcards here */ + ret = forbiddenExp; + } + return(ret); + case XML_EXP_OR: { + xmlExpNodePtr tmp; + +#ifdef DEBUG_DERIV + printf("deriv or: => or(derivs)\n"); +#endif + tmp = xmlExpStringDeriveInt(ctxt, exp->exp_left, str); + if (tmp == NULL) { + return(NULL); + } + ret = xmlExpStringDeriveInt(ctxt, exp->exp_right, str); + if (ret == NULL) { + xmlExpFree(ctxt, tmp); + return(NULL); + } + ret = xmlExpHashGetEntry(ctxt, XML_EXP_OR, tmp, ret, + NULL, 0, 0); + return(ret); + } + case XML_EXP_SEQ: +#ifdef DEBUG_DERIV + printf("deriv seq: starting with left\n"); +#endif + ret = xmlExpStringDeriveInt(ctxt, exp->exp_left, str); + if (ret == NULL) { + return(NULL); + } else if (ret == forbiddenExp) { + if (IS_NILLABLE(exp->exp_left)) { +#ifdef DEBUG_DERIV + printf("deriv seq: left failed but nillable\n"); +#endif + ret = xmlExpStringDeriveInt(ctxt, exp->exp_right, str); + } + } else { +#ifdef DEBUG_DERIV + printf("deriv seq: left match => sequence\n"); +#endif + exp->exp_right->ref++; + ret = xmlExpHashGetEntry(ctxt, XML_EXP_SEQ, ret, exp->exp_right, + NULL, 0, 0); + } + return(ret); + case XML_EXP_COUNT: { + int min, max; + xmlExpNodePtr tmp; + + if (exp->exp_max == 0) + return(forbiddenExp); + ret = xmlExpStringDeriveInt(ctxt, exp->exp_left, str); + if (ret == NULL) + return(NULL); + if (ret == forbiddenExp) { +#ifdef DEBUG_DERIV + printf("deriv count: pattern mismatch => forbid\n"); +#endif + return(ret); + } + if (exp->exp_max == 1) + return(ret); + if (exp->exp_max < 0) /* unbounded */ + max = -1; + else + max = exp->exp_max - 1; + if (exp->exp_min > 0) + min = exp->exp_min - 1; + else + min = 0; + exp->exp_left->ref++; + tmp = xmlExpHashGetEntry(ctxt, XML_EXP_COUNT, exp->exp_left, NULL, + NULL, min, max); + if (ret == emptyExp) { +#ifdef DEBUG_DERIV + printf("deriv count: match to empty => new count\n"); +#endif + return(tmp); + } +#ifdef DEBUG_DERIV + printf("deriv count: match => sequence with new count\n"); +#endif + return(xmlExpHashGetEntry(ctxt, XML_EXP_SEQ, ret, tmp, + NULL, 0, 0)); + } + } + return(NULL); +} + +/** + * xmlExpStringDerive: + * @ctxt: the expression context + * @exp: the expression + * @str: the string + * @len: the string len in bytes if available + * + * Do one step of Brzozowski derivation of the expression @exp with + * respect to the input string + * + * Returns the resulting expression or NULL in case of internal error + */ +xmlExpNodePtr +xmlExpStringDerive(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, + const xmlChar *str, int len) { + const xmlChar *input; + + if ((exp == NULL) || (ctxt == NULL) || (str == NULL)) { + return(NULL); + } + /* + * check the string is in the dictionnary, if yes use an interned + * copy, otherwise we know it's not an acceptable input + */ + input = xmlDictExists(ctxt->dict, str, len); + if (input == NULL) { + return(forbiddenExp); + } + return(xmlExpStringDeriveInt(ctxt, exp, input)); +} + +static int +xmlExpCheckCard(xmlExpNodePtr exp, xmlExpNodePtr sub) { + int ret = 1; + + if (sub->c_max == -1) { + if (exp->c_max != -1) + ret = 0; + } else if ((exp->c_max >= 0) && (exp->c_max < sub->c_max)) { + ret = 0; + } +#if 0 + if ((IS_NILLABLE(sub)) && (!IS_NILLABLE(exp))) + ret = 0; +#endif + return(ret); +} + +static xmlExpNodePtr xmlExpExpDeriveInt(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, + xmlExpNodePtr sub); +/** + * xmlExpDivide: + * @ctxt: the expressions context + * @exp: the englobing expression + * @sub: the subexpression + * @mult: the multiple expression + * @remain: the remain from the derivation of the multiple + * + * Check if exp is a multiple of sub, i.e. if there is a finite number n + * so that sub{n} subsume exp + * + * Returns the multiple value if successful, 0 if it is not a multiple + * and -1 in case of internel error. + */ + +static int +xmlExpDivide(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, xmlExpNodePtr sub, + xmlExpNodePtr *mult, xmlExpNodePtr *remain) { + int i; + xmlExpNodePtr tmp, tmp2; + + if (mult != NULL) *mult = NULL; + if (remain != NULL) *remain = NULL; + if (exp->c_max == -1) return(0); + if (IS_NILLABLE(exp) && (!IS_NILLABLE(sub))) return(0); + + for (i = 1;i <= exp->c_max;i++) { + sub->ref++; + tmp = xmlExpHashGetEntry(ctxt, XML_EXP_COUNT, + sub, NULL, NULL, i, i); + if (tmp == NULL) { + return(-1); + } + if (!xmlExpCheckCard(tmp, exp)) { + xmlExpFree(ctxt, tmp); + continue; + } + tmp2 = xmlExpExpDeriveInt(ctxt, tmp, exp); + if (tmp2 == NULL) { + xmlExpFree(ctxt, tmp); + return(-1); + } + if ((tmp2 != forbiddenExp) && (IS_NILLABLE(tmp2))) { + if (remain != NULL) + *remain = tmp2; + else + xmlExpFree(ctxt, tmp2); + if (mult != NULL) + *mult = tmp; + else + xmlExpFree(ctxt, tmp); +#ifdef DEBUG_DERIV + printf("Divide succeeded %d\n", i); +#endif + return(i); + } + xmlExpFree(ctxt, tmp); + xmlExpFree(ctxt, tmp2); + } +#ifdef DEBUG_DERIV + printf("Divide failed\n"); +#endif + return(0); +} + +/** + * xmlExpExpDeriveInt: + * @ctxt: the expressions context + * @exp: the englobing expression + * @sub: the subexpression + * + * Try to do a step of Brzozowski derivation but at a higher level + * the input being a subexpression. + * + * Returns the resulting expression or NULL in case of internal error + */ +static xmlExpNodePtr +xmlExpExpDeriveInt(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, xmlExpNodePtr sub) { + xmlExpNodePtr ret, tmp, tmp2, tmp3; + const xmlChar **tab; + int len, i; + + /* + * In case of equality and if the expression can only consume a finite + * amount, then the derivation is empty + */ + if ((exp == sub) && (exp->c_max >= 0)) { +#ifdef DEBUG_DERIV + printf("Equal(exp, sub) and finite -> Empty\n"); +#endif + return(emptyExp); + } + /* + * decompose sub sequence first + */ + if (sub->type == XML_EXP_EMPTY) { +#ifdef DEBUG_DERIV + printf("Empty(sub) -> Empty\n"); +#endif + exp->ref++; + return(exp); + } + if (sub->type == XML_EXP_SEQ) { +#ifdef DEBUG_DERIV + printf("Seq(sub) -> decompose\n"); +#endif + tmp = xmlExpExpDeriveInt(ctxt, exp, sub->exp_left); + if (tmp == NULL) + return(NULL); + if (tmp == forbiddenExp) + return(tmp); + ret = xmlExpExpDeriveInt(ctxt, tmp, sub->exp_right); + xmlExpFree(ctxt, tmp); + return(ret); + } + if (sub->type == XML_EXP_OR) { +#ifdef DEBUG_DERIV + printf("Or(sub) -> decompose\n"); +#endif + tmp = xmlExpExpDeriveInt(ctxt, exp, sub->exp_left); + if (tmp == forbiddenExp) + return(tmp); + if (tmp == NULL) + return(NULL); + ret = xmlExpExpDeriveInt(ctxt, exp, sub->exp_right); + if ((ret == NULL) || (ret == forbiddenExp)) { + xmlExpFree(ctxt, tmp); + return(ret); + } + return(xmlExpHashGetEntry(ctxt, XML_EXP_OR, tmp, ret, NULL, 0, 0)); + } + if (!xmlExpCheckCard(exp, sub)) { +#ifdef DEBUG_DERIV + printf("CheckCard(exp, sub) failed -> Forbid\n"); +#endif + return(forbiddenExp); + } + switch (exp->type) { + case XML_EXP_EMPTY: + if (sub == emptyExp) + return(emptyExp); +#ifdef DEBUG_DERIV + printf("Empty(exp) -> Forbid\n"); +#endif + return(forbiddenExp); + case XML_EXP_FORBID: +#ifdef DEBUG_DERIV + printf("Forbid(exp) -> Forbid\n"); +#endif + return(forbiddenExp); + case XML_EXP_ATOM: + if (sub->type == XML_EXP_ATOM) { + /* TODO: handle wildcards */ + if (exp->exp_str == sub->exp_str) { +#ifdef DEBUG_DERIV + printf("Atom match -> Empty\n"); +#endif + return(emptyExp); + } +#ifdef DEBUG_DERIV + printf("Atom mismatch -> Forbid\n"); +#endif + return(forbiddenExp); + } + if ((sub->type == XML_EXP_COUNT) && + (sub->exp_max == 1) && + (sub->exp_left->type == XML_EXP_ATOM)) { + /* TODO: handle wildcards */ + if (exp->exp_str == sub->exp_left->exp_str) { +#ifdef DEBUG_DERIV + printf("Atom match -> Empty\n"); +#endif + return(emptyExp); + } +#ifdef DEBUG_DERIV + printf("Atom mismatch -> Forbid\n"); +#endif + return(forbiddenExp); + } +#ifdef DEBUG_DERIV + printf("Compex exp vs Atom -> Forbid\n"); +#endif + return(forbiddenExp); + case XML_EXP_SEQ: + /* try to get the sequence consumed only if possible */ + if (xmlExpCheckCard(exp->exp_left, sub)) { + /* See if the sequence can be consumed directly */ +#ifdef DEBUG_DERIV + printf("Seq trying left only\n"); +#endif + ret = xmlExpExpDeriveInt(ctxt, exp->exp_left, sub); + if ((ret != forbiddenExp) && (ret != NULL)) { +#ifdef DEBUG_DERIV + printf("Seq trying left only worked\n"); +#endif + /* + * TODO: assumption here that we are determinist + * i.e. we won't get to a nillable exp left + * subset which could be matched by the right + * part too. + * e.g.: (a | b)+,(a | c) and 'a+,a' + */ + exp->exp_right->ref++; + return(xmlExpHashGetEntry(ctxt, XML_EXP_SEQ, ret, + exp->exp_right, NULL, 0, 0)); + } +#ifdef DEBUG_DERIV + } else { + printf("Seq: left too short\n"); +#endif + } + /* Try instead to decompose */ + if (sub->type == XML_EXP_COUNT) { + int min, max; + +#ifdef DEBUG_DERIV + printf("Seq: sub is a count\n"); +#endif + ret = xmlExpExpDeriveInt(ctxt, exp->exp_left, sub->exp_left); + if (ret == NULL) + return(NULL); + if (ret != forbiddenExp) { +#ifdef DEBUG_DERIV + printf("Seq , Count match on left\n"); +#endif + if (sub->exp_max < 0) + max = -1; + else + max = sub->exp_max -1; + if (sub->exp_min > 0) + min = sub->exp_min -1; + else + min = 0; + exp->exp_right->ref++; + tmp = xmlExpHashGetEntry(ctxt, XML_EXP_SEQ, ret, + exp->exp_right, NULL, 0, 0); + if (tmp == NULL) + return(NULL); + + sub->exp_left->ref++; + tmp2 = xmlExpHashGetEntry(ctxt, XML_EXP_COUNT, + sub->exp_left, NULL, NULL, min, max); + if (tmp2 == NULL) { + xmlExpFree(ctxt, tmp); + return(NULL); + } + ret = xmlExpExpDeriveInt(ctxt, tmp, tmp2); + xmlExpFree(ctxt, tmp); + xmlExpFree(ctxt, tmp2); + return(ret); + } + } + /* we made no progress on structured operations */ + break; + case XML_EXP_OR: +#ifdef DEBUG_DERIV + printf("Or , trying both side\n"); +#endif + ret = xmlExpExpDeriveInt(ctxt, exp->exp_left, sub); + if (ret == NULL) + return(NULL); + tmp = xmlExpExpDeriveInt(ctxt, exp->exp_right, sub); + if (tmp == NULL) { + xmlExpFree(ctxt, ret); + return(NULL); + } + return(xmlExpHashGetEntry(ctxt, XML_EXP_OR, ret, tmp, NULL, 0, 0)); + case XML_EXP_COUNT: { + int min, max; + + if (sub->type == XML_EXP_COUNT) { + /* + * Try to see if the loop is completely subsumed + */ + tmp = xmlExpExpDeriveInt(ctxt, exp->exp_left, sub->exp_left); + if (tmp == NULL) + return(NULL); + if (tmp == forbiddenExp) { + int mult; + +#ifdef DEBUG_DERIV + printf("Count, Count inner don't subsume\n"); +#endif + mult = xmlExpDivide(ctxt, sub->exp_left, exp->exp_left, + NULL, &tmp); + if (mult <= 0) { +#ifdef DEBUG_DERIV + printf("Count, Count not multiple => forbidden\n"); +#endif + return(forbiddenExp); + } + if (sub->exp_max == -1) { + max = -1; + if (exp->exp_max == -1) { + if (exp->exp_min <= sub->exp_min * mult) + min = 0; + else + min = exp->exp_min - sub->exp_min * mult; + } else { +#ifdef DEBUG_DERIV + printf("Count, Count finite can't subsume infinite\n"); +#endif + xmlExpFree(ctxt, tmp); + return(forbiddenExp); + } + } else { + if (exp->exp_max == -1) { +#ifdef DEBUG_DERIV + printf("Infinite loop consume mult finite loop\n"); +#endif + if (exp->exp_min > sub->exp_min * mult) { + max = -1; + min = exp->exp_min - sub->exp_min * mult; + } else { + max = -1; + min = 0; + } + } else { + if (exp->exp_max < sub->exp_max * mult) { +#ifdef DEBUG_DERIV + printf("loops max mult mismatch => forbidden\n"); +#endif + xmlExpFree(ctxt, tmp); + return(forbiddenExp); + } + if (sub->exp_max * mult > exp->exp_min) + min = 0; + else + min = exp->exp_min - sub->exp_max * mult; + max = exp->exp_max - sub->exp_max * mult; + } + } + } else if (!IS_NILLABLE(tmp)) { + /* + * TODO: loop here to try to grow if working on finite + * blocks. + */ +#ifdef DEBUG_DERIV + printf("Count, Count remain not nillable => forbidden\n"); +#endif + xmlExpFree(ctxt, tmp); + return(forbiddenExp); + } else if (sub->exp_max == -1) { + if (exp->exp_max == -1) { + if (exp->exp_min <= sub->exp_min) { +#ifdef DEBUG_DERIV + printf("Infinite loops Okay => COUNT(0,Inf)\n"); +#endif + max = -1; + min = 0; + } else { +#ifdef DEBUG_DERIV + printf("Infinite loops min => Count(X,Inf)\n"); +#endif + max = -1; + min = exp->exp_min - sub->exp_min; + } + } else if (exp->exp_min > sub->exp_min) { +#ifdef DEBUG_DERIV + printf("loops min mismatch 1 => forbidden ???\n"); +#endif + xmlExpFree(ctxt, tmp); + return(forbiddenExp); + } else { + max = -1; + min = 0; + } + } else { + if (exp->exp_max == -1) { +#ifdef DEBUG_DERIV + printf("Infinite loop consume finite loop\n"); +#endif + if (exp->exp_min > sub->exp_min) { + max = -1; + min = exp->exp_min - sub->exp_min; + } else { + max = -1; + min = 0; + } + } else { + if (exp->exp_max < sub->exp_max) { +#ifdef DEBUG_DERIV + printf("loops max mismatch => forbidden\n"); +#endif + xmlExpFree(ctxt, tmp); + return(forbiddenExp); + } + if (sub->exp_max > exp->exp_min) + min = 0; + else + min = exp->exp_min - sub->exp_max; + max = exp->exp_max - sub->exp_max; + } + } +#ifdef DEBUG_DERIV + printf("loops match => SEQ(COUNT())\n"); +#endif + exp->exp_left->ref++; + tmp2 = xmlExpHashGetEntry(ctxt, XML_EXP_COUNT, exp->exp_left, + NULL, NULL, min, max); + if (tmp2 == NULL) { + return(NULL); + } + ret = xmlExpHashGetEntry(ctxt, XML_EXP_SEQ, tmp, tmp2, + NULL, 0, 0); + return(ret); + } + tmp = xmlExpExpDeriveInt(ctxt, exp->exp_left, sub); + if (tmp == NULL) + return(NULL); + if (tmp == forbiddenExp) { +#ifdef DEBUG_DERIV + printf("loop mismatch => forbidden\n"); +#endif + return(forbiddenExp); + } + if (exp->exp_min > 0) + min = exp->exp_min - 1; + else + min = 0; + if (exp->exp_max < 0) + max = -1; + else + max = exp->exp_max - 1; + +#ifdef DEBUG_DERIV + printf("loop match => SEQ(COUNT())\n"); +#endif + exp->exp_left->ref++; + tmp2 = xmlExpHashGetEntry(ctxt, XML_EXP_COUNT, exp->exp_left, + NULL, NULL, min, max); + if (tmp2 == NULL) + return(NULL); + ret = xmlExpHashGetEntry(ctxt, XML_EXP_SEQ, tmp, tmp2, + NULL, 0, 0); + return(ret); + } + } + +#ifdef DEBUG_DERIV + printf("Fallback to derivative\n"); +#endif + if (IS_NILLABLE(sub)) { + if (!(IS_NILLABLE(exp))) + return(forbiddenExp); + else + ret = emptyExp; + } else + ret = NULL; + /* + * here the structured derivation made no progress so + * we use the default token based derivation to force one more step + */ + if (ctxt->tabSize == 0) + ctxt->tabSize = 40; + + tab = (const xmlChar **) xmlMalloc(ctxt->tabSize * + sizeof(const xmlChar *)); + if (tab == NULL) { + return(NULL); + } + + /* + * collect all the strings accepted by the subexpression on input + */ + len = xmlExpGetStartInt(ctxt, sub, tab, ctxt->tabSize, 0); + while (len < 0) { + const xmlChar **temp; + temp = (const xmlChar **) xmlRealloc((xmlChar **) tab, ctxt->tabSize * 2 * + sizeof(const xmlChar *)); + if (temp == NULL) { + xmlFree((xmlChar **) tab); + return(NULL); + } + tab = temp; + ctxt->tabSize *= 2; + len = xmlExpGetStartInt(ctxt, sub, tab, ctxt->tabSize, 0); + } + for (i = 0;i < len;i++) { + tmp = xmlExpStringDeriveInt(ctxt, exp, tab[i]); + if ((tmp == NULL) || (tmp == forbiddenExp)) { + xmlExpFree(ctxt, ret); + xmlFree((xmlChar **) tab); + return(tmp); + } + tmp2 = xmlExpStringDeriveInt(ctxt, sub, tab[i]); + if ((tmp2 == NULL) || (tmp2 == forbiddenExp)) { + xmlExpFree(ctxt, tmp); + xmlExpFree(ctxt, ret); + xmlFree((xmlChar **) tab); + return(tmp); + } + tmp3 = xmlExpExpDeriveInt(ctxt, tmp, tmp2); + xmlExpFree(ctxt, tmp); + xmlExpFree(ctxt, tmp2); + + if ((tmp3 == NULL) || (tmp3 == forbiddenExp)) { + xmlExpFree(ctxt, ret); + xmlFree((xmlChar **) tab); + return(tmp3); + } + + if (ret == NULL) + ret = tmp3; + else { + ret = xmlExpHashGetEntry(ctxt, XML_EXP_OR, ret, tmp3, NULL, 0, 0); + if (ret == NULL) { + xmlFree((xmlChar **) tab); + return(NULL); + } + } + } + xmlFree((xmlChar **) tab); + return(ret); +} + +/** + * xmlExpExpDerive: + * @ctxt: the expressions context + * @exp: the englobing expression + * @sub: the subexpression + * + * Evaluates the expression resulting from @exp consuming a sub expression @sub + * Based on algebraic derivation and sometimes direct Brzozowski derivation + * it usually tatkes less than linear time and can handle expressions generating + * infinite languages. + * + * Returns the resulting expression or NULL in case of internal error, the + * result must be freed + */ +xmlExpNodePtr +xmlExpExpDerive(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, xmlExpNodePtr sub) { + if ((exp == NULL) || (ctxt == NULL) || (sub == NULL)) + return(NULL); + + /* + * O(1) speedups + */ + if (IS_NILLABLE(sub) && (!IS_NILLABLE(exp))) { +#ifdef DEBUG_DERIV + printf("Sub nillable and not exp : can't subsume\n"); +#endif + return(forbiddenExp); + } + if (xmlExpCheckCard(exp, sub) == 0) { +#ifdef DEBUG_DERIV + printf("sub generate longuer sequances than exp : can't subsume\n"); +#endif + return(forbiddenExp); + } + return(xmlExpExpDeriveInt(ctxt, exp, sub)); +} + +/** + * xmlExpSubsume: + * @ctxt: the expressions context + * @exp: the englobing expression + * @sub: the subexpression + * + * Check whether @exp accepts all the languages accexpted by @sub + * the input being a subexpression. + * + * Returns 1 if true 0 if false and -1 in case of failure. + */ +int +xmlExpSubsume(xmlExpCtxtPtr ctxt, xmlExpNodePtr exp, xmlExpNodePtr sub) { + xmlExpNodePtr tmp; + + if ((exp == NULL) || (ctxt == NULL) || (sub == NULL)) + return(-1); + + /* + * TODO: speedup by checking the language of sub is a subset of the + * language of exp + */ + /* + * O(1) speedups + */ + if (IS_NILLABLE(sub) && (!IS_NILLABLE(exp))) { +#ifdef DEBUG_DERIV + printf("Sub nillable and not exp : can't subsume\n"); +#endif + return(0); + } + if (xmlExpCheckCard(exp, sub) == 0) { +#ifdef DEBUG_DERIV + printf("sub generate longuer sequances than exp : can't subsume\n"); +#endif + return(0); + } + tmp = xmlExpExpDeriveInt(ctxt, exp, sub); +#ifdef DEBUG_DERIV + printf("Result derivation :\n"); + PRINT_EXP(tmp); +#endif + if (tmp == NULL) + return(-1); + if (tmp == forbiddenExp) + return(0); + if (tmp == emptyExp) + return(1); + if ((tmp != NULL) && (IS_NILLABLE(tmp))) { + xmlExpFree(ctxt, tmp); + return(1); + } + xmlExpFree(ctxt, tmp); + return(0); +} + +/************************************************************************ + * * + * Parsing expression * + * * + ************************************************************************/ + +static xmlExpNodePtr xmlExpParseExpr(xmlExpCtxtPtr ctxt); + +#undef CUR +#define CUR (*ctxt->cur) +#undef NEXT +#define NEXT ctxt->cur++; +#undef IS_BLANK +#define IS_BLANK(c) ((c == ' ') || (c == '\n') || (c == '\r') || (c == '\t')) +#define SKIP_BLANKS while (IS_BLANK(*ctxt->cur)) ctxt->cur++; + +static int +xmlExpParseNumber(xmlExpCtxtPtr ctxt) { + int ret = 0; + + SKIP_BLANKS + if (CUR == '*') { + NEXT + return(-1); + } + if ((CUR < '0') || (CUR > '9')) + return(-1); + while ((CUR >= '0') && (CUR <= '9')) { + ret = ret * 10 + (CUR - '0'); + NEXT + } + return(ret); +} + +static xmlExpNodePtr +xmlExpParseOr(xmlExpCtxtPtr ctxt) { + const char *base; + xmlExpNodePtr ret; + const xmlChar *val; + + SKIP_BLANKS + base = ctxt->cur; + if (*ctxt->cur == '(') { + NEXT + ret = xmlExpParseExpr(ctxt); + SKIP_BLANKS + if (*ctxt->cur != ')') { + fprintf(stderr, "unbalanced '(' : %s\n", base); + xmlExpFree(ctxt, ret); + return(NULL); + } + NEXT; + SKIP_BLANKS + goto parse_quantifier; + } + while ((CUR != 0) && (!(IS_BLANK(CUR))) && (CUR != '(') && + (CUR != ')') && (CUR != '|') && (CUR != ',') && (CUR != '{') && + (CUR != '*') && (CUR != '+') && (CUR != '?') && (CUR != '}')) + NEXT; + val = xmlDictLookup(ctxt->dict, BAD_CAST base, ctxt->cur - base); + if (val == NULL) + return(NULL); + ret = xmlExpHashGetEntry(ctxt, XML_EXP_ATOM, NULL, NULL, val, 0, 0); + if (ret == NULL) + return(NULL); + SKIP_BLANKS +parse_quantifier: + if (CUR == '{') { + int min, max; + + NEXT + min = xmlExpParseNumber(ctxt); + if (min < 0) { + xmlExpFree(ctxt, ret); + return(NULL); + } + SKIP_BLANKS + if (CUR == ',') { + NEXT + max = xmlExpParseNumber(ctxt); + SKIP_BLANKS + } else + max = min; + if (CUR != '}') { + xmlExpFree(ctxt, ret); + return(NULL); + } + NEXT + ret = xmlExpHashGetEntry(ctxt, XML_EXP_COUNT, ret, NULL, NULL, + min, max); + SKIP_BLANKS + } else if (CUR == '?') { + NEXT + ret = xmlExpHashGetEntry(ctxt, XML_EXP_COUNT, ret, NULL, NULL, + 0, 1); + SKIP_BLANKS + } else if (CUR == '+') { + NEXT + ret = xmlExpHashGetEntry(ctxt, XML_EXP_COUNT, ret, NULL, NULL, + 1, -1); + SKIP_BLANKS + } else if (CUR == '*') { + NEXT + ret = xmlExpHashGetEntry(ctxt, XML_EXP_COUNT, ret, NULL, NULL, + 0, -1); + SKIP_BLANKS + } + return(ret); +} + + +static xmlExpNodePtr +xmlExpParseSeq(xmlExpCtxtPtr ctxt) { + xmlExpNodePtr ret, right; + + ret = xmlExpParseOr(ctxt); + SKIP_BLANKS + while (CUR == '|') { + NEXT + right = xmlExpParseOr(ctxt); + if (right == NULL) { + xmlExpFree(ctxt, ret); + return(NULL); + } + ret = xmlExpHashGetEntry(ctxt, XML_EXP_OR, ret, right, NULL, 0, 0); + if (ret == NULL) + return(NULL); + } + return(ret); +} + +static xmlExpNodePtr +xmlExpParseExpr(xmlExpCtxtPtr ctxt) { + xmlExpNodePtr ret, right; + + ret = xmlExpParseSeq(ctxt); + SKIP_BLANKS + while (CUR == ',') { + NEXT + right = xmlExpParseSeq(ctxt); + if (right == NULL) { + xmlExpFree(ctxt, ret); + return(NULL); + } + ret = xmlExpHashGetEntry(ctxt, XML_EXP_SEQ, ret, right, NULL, 0, 0); + if (ret == NULL) + return(NULL); + } + return(ret); +} + +/** + * xmlExpParse: + * @ctxt: the expressions context + * @expr: the 0 terminated string + * + * Minimal parser for regexps, it understand the following constructs + * - string terminals + * - choice operator | + * - sequence operator , + * - subexpressions (...) + * - usual cardinality operators + * and ? + * - finite sequences { min, max } + * - infinite sequences { min, * } + * There is minimal checkings made especially no checking on strings values + * + * Returns a new expression or NULL in case of failure + */ +xmlExpNodePtr +xmlExpParse(xmlExpCtxtPtr ctxt, const char *expr) { + xmlExpNodePtr ret; + + ctxt->expr = expr; + ctxt->cur = expr; + + ret = xmlExpParseExpr(ctxt); + SKIP_BLANKS + if (*ctxt->cur != 0) { + xmlExpFree(ctxt, ret); + return(NULL); + } + return(ret); +} + +static void +xmlExpDumpInt(xmlBufferPtr buf, xmlExpNodePtr expr, int glob) { + xmlExpNodePtr c; + + if (expr == NULL) return; + if (glob) xmlBufferWriteChar(buf, "("); + switch (expr->type) { + case XML_EXP_EMPTY: + xmlBufferWriteChar(buf, "empty"); + break; + case XML_EXP_FORBID: + xmlBufferWriteChar(buf, "forbidden"); + break; + case XML_EXP_ATOM: + xmlBufferWriteCHAR(buf, expr->exp_str); + break; + case XML_EXP_SEQ: + c = expr->exp_left; + if ((c->type == XML_EXP_SEQ) || (c->type == XML_EXP_OR)) + xmlExpDumpInt(buf, c, 1); + else + xmlExpDumpInt(buf, c, 0); + xmlBufferWriteChar(buf, " , "); + c = expr->exp_right; + if ((c->type == XML_EXP_SEQ) || (c->type == XML_EXP_OR)) + xmlExpDumpInt(buf, c, 1); + else + xmlExpDumpInt(buf, c, 0); + break; + case XML_EXP_OR: + c = expr->exp_left; + if ((c->type == XML_EXP_SEQ) || (c->type == XML_EXP_OR)) + xmlExpDumpInt(buf, c, 1); + else + xmlExpDumpInt(buf, c, 0); + xmlBufferWriteChar(buf, " | "); + c = expr->exp_right; + if ((c->type == XML_EXP_SEQ) || (c->type == XML_EXP_OR)) + xmlExpDumpInt(buf, c, 1); + else + xmlExpDumpInt(buf, c, 0); + break; + case XML_EXP_COUNT: { + char rep[40]; + + c = expr->exp_left; + if ((c->type == XML_EXP_SEQ) || (c->type == XML_EXP_OR)) + xmlExpDumpInt(buf, c, 1); + else + xmlExpDumpInt(buf, c, 0); + if ((expr->exp_min == 0) && (expr->exp_max == 1)) { + rep[0] = '?'; + rep[1] = 0; + } else if ((expr->exp_min == 0) && (expr->exp_max == -1)) { + rep[0] = '*'; + rep[1] = 0; + } else if ((expr->exp_min == 1) && (expr->exp_max == -1)) { + rep[0] = '+'; + rep[1] = 0; + } else if (expr->exp_max == expr->exp_min) { + snprintf(rep, 39, "{%d}", expr->exp_min); + } else if (expr->exp_max < 0) { + snprintf(rep, 39, "{%d,inf}", expr->exp_min); + } else { + snprintf(rep, 39, "{%d,%d}", expr->exp_min, expr->exp_max); + } + rep[39] = 0; + xmlBufferWriteChar(buf, rep); + break; + } + default: + fprintf(stderr, "Error in tree\n"); + } + if (glob) + xmlBufferWriteChar(buf, ")"); +} +/** + * xmlExpDump: + * @buf: a buffer to receive the output + * @expr: the compiled expression + * + * Serialize the expression as compiled to the buffer + */ +void +xmlExpDump(xmlBufferPtr buf, xmlExpNodePtr expr) { + if ((buf == NULL) || (expr == NULL)) + return; + xmlExpDumpInt(buf, expr, 0); +} + +/** + * xmlExpMaxToken: + * @expr: a compiled expression + * + * Indicate the maximum number of input a expression can accept + * + * Returns the maximum length or -1 in case of error + */ +int +xmlExpMaxToken(xmlExpNodePtr expr) { + if (expr == NULL) + return(-1); + return(expr->c_max); +} + +/** + * xmlExpCtxtNbNodes: + * @ctxt: an expression context + * + * Debugging facility provides the number of allocated nodes at a that point + * + * Returns the number of nodes in use or -1 in case of error + */ +int +xmlExpCtxtNbNodes(xmlExpCtxtPtr ctxt) { + if (ctxt == NULL) + return(-1); + return(ctxt->nb_nodes); +} + +/** + * xmlExpCtxtNbCons: + * @ctxt: an expression context + * + * Debugging facility provides the number of allocated nodes over lifetime + * + * Returns the number of nodes ever allocated or -1 in case of error + */ +int +xmlExpCtxtNbCons(xmlExpCtxtPtr ctxt) { + if (ctxt == NULL) + return(-1); + return(ctxt->nb_cons); +} + +#endif /* LIBXML_EXPR_ENABLED */ +#define bottom_xmlregexp +#include "elfgcchack.h" +#endif /* LIBXML_REGEXP_ENABLED */ diff --git a/android/native/libxml2/xmlsave.c b/android/native/libxml2/xmlsave.c new file mode 100644 index 0000000000..7d500a0ed4 --- /dev/null +++ b/android/native/libxml2/xmlsave.c @@ -0,0 +1,1951 @@ +/* + * xmlsave.c: Implemetation of the document serializer + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + */ + +#define IN_LIBXML +#include "libxml.h" + +#include +#include +#include +#include +#include + +#define MAX_INDENT 60 + +#include + +/************************************************************************ + * * + * XHTML detection * + * * + ************************************************************************/ +#define XHTML_STRICT_PUBLIC_ID BAD_CAST \ + "-//W3C//DTD XHTML 1.0 Strict//EN" +#define XHTML_STRICT_SYSTEM_ID BAD_CAST \ + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" +#define XHTML_FRAME_PUBLIC_ID BAD_CAST \ + "-//W3C//DTD XHTML 1.0 Frameset//EN" +#define XHTML_FRAME_SYSTEM_ID BAD_CAST \ + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd" +#define XHTML_TRANS_PUBLIC_ID BAD_CAST \ + "-//W3C//DTD XHTML 1.0 Transitional//EN" +#define XHTML_TRANS_SYSTEM_ID BAD_CAST \ + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" + +#define XHTML_NS_NAME BAD_CAST "http://www.w3.org/1999/xhtml" +/** + * xmlIsXHTML: + * @systemID: the system identifier + * @publicID: the public identifier + * + * Try to find if the document correspond to an XHTML DTD + * + * Returns 1 if true, 0 if not and -1 in case of error + */ +int +xmlIsXHTML(const xmlChar *systemID, const xmlChar *publicID) { + if ((systemID == NULL) && (publicID == NULL)) + return(-1); + if (publicID != NULL) { + if (xmlStrEqual(publicID, XHTML_STRICT_PUBLIC_ID)) return(1); + if (xmlStrEqual(publicID, XHTML_FRAME_PUBLIC_ID)) return(1); + if (xmlStrEqual(publicID, XHTML_TRANS_PUBLIC_ID)) return(1); + } + if (systemID != NULL) { + if (xmlStrEqual(systemID, XHTML_STRICT_SYSTEM_ID)) return(1); + if (xmlStrEqual(systemID, XHTML_FRAME_SYSTEM_ID)) return(1); + if (xmlStrEqual(systemID, XHTML_TRANS_SYSTEM_ID)) return(1); + } + return(0); +} + +#ifdef LIBXML_OUTPUT_ENABLED + +#define TODO \ + xmlGenericError(xmlGenericErrorContext, \ + "Unimplemented block at %s:%d\n", \ + __FILE__, __LINE__); + +struct _xmlSaveCtxt { + void *_private; + int type; + int fd; + const xmlChar *filename; + const xmlChar *encoding; + xmlCharEncodingHandlerPtr handler; + xmlOutputBufferPtr buf; + xmlDocPtr doc; + int options; + int level; + int format; + char indent[MAX_INDENT + 1]; /* array for indenting output */ + int indent_nr; + int indent_size; + xmlCharEncodingOutputFunc escape; /* used for element content */ + xmlCharEncodingOutputFunc escapeAttr;/* used for attribute content */ +}; + +/************************************************************************ + * * + * Output error handlers * + * * + ************************************************************************/ +/** + * xmlSaveErrMemory: + * @extra: extra informations + * + * Handle an out of memory condition + */ +static void +xmlSaveErrMemory(const char *extra) +{ + __xmlSimpleError(XML_FROM_OUTPUT, XML_ERR_NO_MEMORY, NULL, NULL, extra); +} + +/** + * xmlSaveErr: + * @code: the error number + * @node: the location of the error. + * @extra: extra informations + * + * Handle an out of memory condition + */ +static void +xmlSaveErr(int code, xmlNodePtr node, const char *extra) +{ + const char *msg = NULL; + + switch(code) { + case XML_SAVE_NOT_UTF8: + msg = "string is not in UTF-8\n"; + break; + case XML_SAVE_CHAR_INVALID: + msg = "invalid character value\n"; + break; + case XML_SAVE_UNKNOWN_ENCODING: + msg = "unknown encoding %s\n"; + break; + case XML_SAVE_NO_DOCTYPE: + msg = "document has no DOCTYPE\n"; + break; + default: + msg = "unexpected error number\n"; + } + __xmlSimpleError(XML_FROM_OUTPUT, code, node, msg, extra); +} + +/************************************************************************ + * * + * Special escaping routines * + * * + ************************************************************************/ +static unsigned char * +xmlSerializeHexCharRef(unsigned char *out, int val) { + unsigned char *ptr; + + *out++ = '&'; + *out++ = '#'; + *out++ = 'x'; + if (val < 0x10) ptr = out; + else if (val < 0x100) ptr = out + 1; + else if (val < 0x1000) ptr = out + 2; + else if (val < 0x10000) ptr = out + 3; + else if (val < 0x100000) ptr = out + 4; + else ptr = out + 5; + out = ptr + 1; + while (val > 0) { + switch (val & 0xF) { + case 0: *ptr-- = '0'; break; + case 1: *ptr-- = '1'; break; + case 2: *ptr-- = '2'; break; + case 3: *ptr-- = '3'; break; + case 4: *ptr-- = '4'; break; + case 5: *ptr-- = '5'; break; + case 6: *ptr-- = '6'; break; + case 7: *ptr-- = '7'; break; + case 8: *ptr-- = '8'; break; + case 9: *ptr-- = '9'; break; + case 0xA: *ptr-- = 'A'; break; + case 0xB: *ptr-- = 'B'; break; + case 0xC: *ptr-- = 'C'; break; + case 0xD: *ptr-- = 'D'; break; + case 0xE: *ptr-- = 'E'; break; + case 0xF: *ptr-- = 'F'; break; + default: *ptr-- = '0'; break; + } + val >>= 4; + } + *out++ = ';'; + *out = 0; + return(out); +} + +/** + * xmlEscapeEntities: + * @out: a pointer to an array of bytes to store the result + * @outlen: the length of @out + * @in: a pointer to an array of unescaped UTF-8 bytes + * @inlen: the length of @in + * + * Take a block of UTF-8 chars in and escape them. Used when there is no + * encoding specified. + * + * Returns 0 if success, or -1 otherwise + * The value of @inlen after return is the number of octets consumed + * if the return value is positive, else unpredictable. + * The value of @outlen after return is the number of octets consumed. + */ +static int +xmlEscapeEntities(unsigned char* out, int *outlen, + const xmlChar* in, int *inlen) { + unsigned char* outstart = out; + const unsigned char* base = in; + unsigned char* outend = out + *outlen; + const unsigned char* inend; + int val; + + inend = in + (*inlen); + + while ((in < inend) && (out < outend)) { + if (*in == '<') { + if (outend - out < 4) break; + *out++ = '&'; + *out++ = 'l'; + *out++ = 't'; + *out++ = ';'; + in++; + continue; + } else if (*in == '>') { + if (outend - out < 4) break; + *out++ = '&'; + *out++ = 'g'; + *out++ = 't'; + *out++ = ';'; + in++; + continue; + } else if (*in == '&') { + if (outend - out < 5) break; + *out++ = '&'; + *out++ = 'a'; + *out++ = 'm'; + *out++ = 'p'; + *out++ = ';'; + in++; + continue; + } else if (((*in >= 0x20) && (*in < 0x80)) || + (*in == '\n') || (*in == '\t')) { + /* + * default case, just copy ! + */ + *out++ = *in++; + continue; + } else if (*in >= 0x80) { + /* + * We assume we have UTF-8 input. + */ + 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; + } + + /* + * 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); +} + +/************************************************************************ + * * + * Allocation and deallocation * + * * + ************************************************************************/ +/** + * xmlSaveCtxtInit: + * @ctxt: the saving context + * + * Initialize a saving context + */ +static void +xmlSaveCtxtInit(xmlSaveCtxtPtr ctxt) +{ + int i; + int len; + + if (ctxt == NULL) return; + if ((ctxt->encoding == NULL) && (ctxt->escape == NULL)) + ctxt->escape = xmlEscapeEntities; + len = xmlStrlen((xmlChar *)xmlTreeIndentString); + if ((xmlTreeIndentString == NULL) || (len == 0)) { + memset(&ctxt->indent[0], 0, MAX_INDENT + 1); + } else { + ctxt->indent_size = len; + ctxt->indent_nr = MAX_INDENT / ctxt->indent_size; + for (i = 0;i < ctxt->indent_nr;i++) + memcpy(&ctxt->indent[i * ctxt->indent_size], xmlTreeIndentString, + ctxt->indent_size); + ctxt->indent[ctxt->indent_nr * ctxt->indent_size] = 0; + } + + if (xmlSaveNoEmptyTags) { + ctxt->options |= XML_SAVE_NO_EMPTY; + } +} + +/** + * xmlFreeSaveCtxt: + * + * Free a saving context, destroying the ouptut in any remaining buffer + */ +static void +xmlFreeSaveCtxt(xmlSaveCtxtPtr ctxt) +{ + if (ctxt == NULL) return; + if (ctxt->encoding != NULL) + xmlFree((char *) ctxt->encoding); + if (ctxt->buf != NULL) + xmlOutputBufferClose(ctxt->buf); + xmlFree(ctxt); +} + +/** + * xmlNewSaveCtxt: + * + * Create a new saving context + * + * Returns the new structure or NULL in case of error + */ +static xmlSaveCtxtPtr +xmlNewSaveCtxt(const char *encoding, int options) +{ + xmlSaveCtxtPtr ret; + + ret = (xmlSaveCtxtPtr) xmlMalloc(sizeof(xmlSaveCtxt)); + if (ret == NULL) { + xmlSaveErrMemory("creating saving context"); + 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); + xmlFreeSaveCtxt(ret); + return(NULL); + } + ret->encoding = xmlStrdup((const xmlChar *)encoding); + ret->escape = NULL; + } + xmlSaveCtxtInit(ret); + + /* + * Use the options + */ + + /* Re-check this option as it may already have been set */ + if ((ret->options & XML_SAVE_NO_EMPTY) && ! (options & XML_SAVE_NO_EMPTY)) { + options |= XML_SAVE_NO_EMPTY; + } + + ret->options = options; + if (options & XML_SAVE_FORMAT) + ret->format = 1; + else if (options & XML_SAVE_WSNONSIG) + ret->format = 2; + + return(ret); +} + +/************************************************************************ + * * + * Dumping XML tree content to a simple buffer * + * * + ************************************************************************/ +/** + * xmlAttrSerializeContent: + * @buf: the XML buffer output + * @doc: the document + * @attr: the attribute pointer + * + * Serialize the attribute in the buffer + */ +static void +xmlAttrSerializeContent(xmlOutputBufferPtr buf, xmlAttrPtr attr) +{ + xmlNodePtr children; + + children = attr->children; + while (children != NULL) { + switch (children->type) { + case XML_TEXT_NODE: + xmlAttrSerializeTxtContent(buf->buffer, attr->doc, + attr, children->content); + break; + case XML_ENTITY_REF_NODE: + xmlBufferAdd(buf->buffer, BAD_CAST "&", 1); + xmlBufferAdd(buf->buffer, children->name, + xmlStrlen(children->name)); + xmlBufferAdd(buf->buffer, BAD_CAST ";", 1); + break; + default: + /* should not happen unless we have a badly built tree */ + break; + } + children = children->next; + } +} + +/************************************************************************ + * * + * Dumping XML tree content to an I/O output buffer * + * * + ************************************************************************/ + +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); + } + buf->conv = xmlBufferCreate(); + if (buf->conv == NULL) { + xmlCharEncCloseFunc(buf->encoder); + xmlSaveErrMemory("creating encoding buffer"); + return(-1); + } + /* + * initialize the state, e.g. if outputting a BOM + */ + xmlCharEncOutFunc(buf->encoder, buf->conv, NULL); + } + return(0); +} + +static int xmlSaveClearEncoding(xmlSaveCtxtPtr ctxt) { + xmlOutputBufferPtr buf = ctxt->buf; + xmlOutputBufferFlush(buf); + xmlCharEncCloseFunc(buf->encoder); + xmlBufferFree(buf->conv); + buf->encoder = NULL; + buf->conv = NULL; + return(0); +} + +static void xmlNodeListDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur); +static void xmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur); +void xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur); +static int xmlDocContentDumpOutput(xmlSaveCtxtPtr ctxt, xmlDocPtr cur); + +/** + * xmlOutputBufferWriteWSNonSig: + * @ctxt: The save context + * @extra: Number of extra indents to apply to ctxt->level + * + * Write out formatting for non-significant whitespace output. + */ +static void +xmlOutputBufferWriteWSNonSig(xmlSaveCtxtPtr ctxt, int extra) +{ + int i; + if ((ctxt == NULL) || (ctxt->buf == NULL)) + return; + xmlOutputBufferWrite(ctxt->buf, 1, "\n"); + for (i = 0; i < (ctxt->level + extra); i += ctxt->indent_nr) { + xmlOutputBufferWrite(ctxt->buf, ctxt->indent_size * + ((ctxt->level + extra - i) > ctxt->indent_nr ? + ctxt->indent_nr : (ctxt->level + extra - i)), + ctxt->indent); + } +} + +/** + * xmlNsDumpOutput: + * @buf: the XML buffer output + * @cur: a namespace + * @ctxt: the output save context. Optional. + * + * Dump a local Namespace definition. + * Should be called in the context of attributes dumps. + * If @ctxt is supplied, @buf should be its buffer. + */ +static void +xmlNsDumpOutput(xmlOutputBufferPtr buf, 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")) + return; + + if (ctxt != NULL && ctxt->format == 2) + xmlOutputBufferWriteWSNonSig(ctxt, 2); + else + xmlOutputBufferWrite(buf, 1, " "); + + /* Within the context of an element attributes */ + if (cur->prefix != NULL) { + xmlOutputBufferWrite(buf, 6, "xmlns:"); + xmlOutputBufferWriteString(buf, (const char *)cur->prefix); + } else + xmlOutputBufferWrite(buf, 5, "xmlns"); + xmlOutputBufferWrite(buf, 1, "="); + xmlBufferWriteQuotedString(buf->buffer, cur->href); + } +} + +/** + * 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 + * @cur: the first namespace + * + * Dump a list of local namespace definitions to a save context. + * Should be called in the context of attribute dumps. + */ +static void +xmlNsListDumpOutputCtxt(xmlSaveCtxtPtr ctxt, xmlNsPtr cur) { + while (cur != NULL) { + xmlNsDumpOutput(ctxt->buf, cur, ctxt); + cur = cur->next; + } +} + +/** + * xmlNsListDumpOutput: + * @buf: the XML buffer output + * @cur: the first namespace + * + * Dump a list of local Namespace definitions. + * Should be called in the context of attributes dumps. + */ +void +xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) { + while (cur != NULL) { + xmlNsDumpOutput(buf, cur, NULL); + cur = cur->next; + } +} + +/** + * xmlDtdDumpOutput: + * @buf: the XML buffer output + * @dtd: the pointer to the DTD + * + * Dump the XML document DTD, if any. + */ +static void +xmlDtdDumpOutput(xmlSaveCtxtPtr ctxt, xmlDtdPtr dtd) { + xmlOutputBufferPtr buf; + int format, level; + xmlDocPtr doc; + + if (dtd == NULL) return; + if ((ctxt == NULL) || (ctxt->buf == NULL)) + return; + buf = ctxt->buf; + xmlOutputBufferWrite(buf, 10, "name); + if (dtd->ExternalID != NULL) { + xmlOutputBufferWrite(buf, 8, " PUBLIC "); + xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID); + xmlOutputBufferWrite(buf, 1, " "); + xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID); + } else if (dtd->SystemID != NULL) { + xmlOutputBufferWrite(buf, 8, " SYSTEM "); + xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID); + } + if ((dtd->entities == NULL) && (dtd->elements == NULL) && + (dtd->attributes == NULL) && (dtd->notations == NULL) && + (dtd->pentities == NULL)) { + xmlOutputBufferWrite(buf, 1, ">"); + return; + } + xmlOutputBufferWrite(buf, 3, " [\n"); + /* + * Dump the notations first they are not in the DTD children list + * Do this only on a standalone DTD or on the internal subset though. + */ + if ((dtd->notations != NULL) && ((dtd->doc == NULL) || + (dtd->doc->intSubset == dtd))) { + xmlDumpNotationTable(buf->buffer, (xmlNotationTablePtr) dtd->notations); + } + format = ctxt->format; + level = ctxt->level; + doc = ctxt->doc; + ctxt->format = 0; + ctxt->level = -1; + ctxt->doc = dtd->doc; + xmlNodeListDumpOutput(ctxt, dtd->children); + ctxt->format = format; + ctxt->level = level; + ctxt->doc = doc; + xmlOutputBufferWrite(buf, 2, "]>"); +} + +/** + * xmlAttrDumpOutput: + * @buf: the XML buffer output + * @cur: the attribute pointer + * + * Dump an XML attribute + */ +static void +xmlAttrDumpOutput(xmlSaveCtxtPtr ctxt, xmlAttrPtr cur) { + xmlOutputBufferPtr buf; + + if (cur == NULL) return; + buf = ctxt->buf; + if (buf == NULL) return; + if (ctxt->format == 2) + xmlOutputBufferWriteWSNonSig(ctxt, 2); + else + xmlOutputBufferWrite(buf, 1, " "); + if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) { + xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix); + xmlOutputBufferWrite(buf, 1, ":"); + } + xmlOutputBufferWriteString(buf, (const char *)cur->name); + xmlOutputBufferWrite(buf, 2, "=\""); + xmlAttrSerializeContent(buf, cur); + xmlOutputBufferWrite(buf, 1, "\""); +} + +/** + * xmlAttrListDumpOutput: + * @buf: the XML buffer output + * @doc: the document + * @cur: the first attribute pointer + * @encoding: an optional encoding string + * + * Dump a list of XML attributes + */ +static void +xmlAttrListDumpOutput(xmlSaveCtxtPtr ctxt, xmlAttrPtr cur) { + if (cur == NULL) return; + while (cur != NULL) { + xmlAttrDumpOutput(ctxt, cur); + cur = cur->next; + } +} + + + +/** + * xmlNodeListDumpOutput: + * @cur: the first node + * + * Dump an XML node list, recursive behaviour, children are printed too. + */ +static void +xmlNodeListDumpOutput(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) { + xmlOutputBufferPtr buf; + + if (cur == NULL) return; + buf = ctxt->buf; + while (cur != NULL) { + if ((ctxt->format == 1) && (xmlIndentTreeOutput) && + ((cur->type == XML_ELEMENT_NODE) || + (cur->type == XML_COMMENT_NODE) || + (cur->type == XML_PI_NODE))) + xmlOutputBufferWrite(buf, ctxt->indent_size * + (ctxt->level > ctxt->indent_nr ? + ctxt->indent_nr : ctxt->level), + ctxt->indent); + xmlNodeDumpOutputInternal(ctxt, cur); + if (ctxt->format == 1) { + xmlOutputBufferWrite(buf, 1, "\n"); + } + cur = cur->next; + } +} + +/** + * xmlNodeDumpOutputInternal: + * @cur: the current node + * + * Dump an XML node, recursive behaviour, children are printed too. + */ +static void +xmlNodeDumpOutputInternal(xmlSaveCtxtPtr ctxt, xmlNodePtr cur) { + int format; + xmlNodePtr tmp; + xmlChar *start, *end; + xmlOutputBufferPtr buf; + + if (cur == NULL) return; + buf = ctxt->buf; + if (cur->type == XML_XINCLUDE_START) + return; + if (cur->type == XML_XINCLUDE_END) + return; + if ((cur->type == XML_DOCUMENT_NODE) || + (cur->type == XML_HTML_DOCUMENT_NODE)) { + xmlDocContentDumpOutput(ctxt, (xmlDocPtr) cur); + return; + } + if (cur->type == XML_DTD_NODE) { + xmlDtdDumpOutput(ctxt, (xmlDtdPtr) cur); + return; + } + if (cur->type == XML_DOCUMENT_FRAG_NODE) { + xmlNodeListDumpOutput(ctxt, cur->children); + return; + } + if (cur->type == XML_ELEMENT_DECL) { + xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur); + return; + } + if (cur->type == XML_ATTRIBUTE_DECL) { + xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur); + return; + } + if (cur->type == XML_ENTITY_DECL) { + xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur); + return; + } + if (cur->type == XML_TEXT_NODE) { + if (cur->content != NULL) { + if (cur->name != xmlStringTextNoenc) { + xmlOutputBufferWriteEscape(buf, cur->content, ctxt->escape); + } else { + /* + * Disable escaping, needed for XSLT + */ + xmlOutputBufferWriteString(buf, (const char *) cur->content); + } + } + + return; + } + if (cur->type == XML_PI_NODE) { + if (cur->content != NULL) { + xmlOutputBufferWrite(buf, 2, "name); + if (cur->content != NULL) { + if (ctxt->format == 2) + xmlOutputBufferWriteWSNonSig(ctxt, 0); + else + xmlOutputBufferWrite(buf, 1, " "); + xmlOutputBufferWriteString(buf, (const char *)cur->content); + } + xmlOutputBufferWrite(buf, 2, "?>"); + } else { + xmlOutputBufferWrite(buf, 2, "name); + if (ctxt->format == 2) + xmlOutputBufferWriteWSNonSig(ctxt, 0); + xmlOutputBufferWrite(buf, 2, "?>"); + } + return; + } + if (cur->type == XML_COMMENT_NODE) { + if (cur->content != NULL) { + xmlOutputBufferWrite(buf, 4, ""); + } + return; + } + if (cur->type == XML_ENTITY_REF_NODE) { + xmlOutputBufferWrite(buf, 1, "&"); + xmlOutputBufferWriteString(buf, (const char *)cur->name); + xmlOutputBufferWrite(buf, 1, ";"); + return; + } + if (cur->type == XML_CDATA_SECTION_NODE) { + if (cur->content == NULL || *cur->content == '\0') { + xmlOutputBufferWrite(buf, 12, ""); + } else { + start = end = cur->content; + while (*end != '\0') { + if ((*end == ']') && (*(end + 1) == ']') && + (*(end + 2) == '>')) { + end = end + 2; + xmlOutputBufferWrite(buf, 9, ""); + start = end; + } + end++; + } + if (start != end) { + xmlOutputBufferWrite(buf, 9, ""); + } + } + return; + } + if (cur->type == XML_ATTRIBUTE_NODE) { + xmlAttrDumpOutput(ctxt, (xmlAttrPtr) cur); + return; + } + if (cur->type == XML_NAMESPACE_DECL) { + xmlNsDumpOutputCtxt(ctxt, (xmlNsPtr) cur); + return; + } + + format = ctxt->format; + if (format == 1) { + tmp = cur->children; + while (tmp != NULL) { + if ((tmp->type == XML_TEXT_NODE) || + (tmp->type == XML_CDATA_SECTION_NODE) || + (tmp->type == XML_ENTITY_REF_NODE)) { + ctxt->format = 0; + break; + } + tmp = tmp->next; + } + } + xmlOutputBufferWrite(buf, 1, "<"); + if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) { + xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix); + xmlOutputBufferWrite(buf, 1, ":"); + } + + xmlOutputBufferWriteString(buf, (const char *)cur->name); + if (cur->nsDef) + xmlNsListDumpOutputCtxt(ctxt, cur->nsDef); + if (cur->properties != NULL) + xmlAttrListDumpOutput(ctxt, cur->properties); + + if (((cur->type == XML_ELEMENT_NODE) || (cur->content == NULL)) && + (cur->children == NULL) && ((ctxt->options & XML_SAVE_NO_EMPTY) == 0)) { + if (ctxt->format == 2) + xmlOutputBufferWriteWSNonSig(ctxt, 0); + xmlOutputBufferWrite(buf, 2, "/>"); + ctxt->format = format; + return; + } + if (ctxt->format == 2) + xmlOutputBufferWriteWSNonSig(ctxt, 1); + xmlOutputBufferWrite(buf, 1, ">"); + if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) { + xmlOutputBufferWriteEscape(buf, cur->content, ctxt->escape); + } + if (cur->children != NULL) { + if (ctxt->format == 1) xmlOutputBufferWrite(buf, 1, "\n"); + if (ctxt->level >= 0) ctxt->level++; + xmlNodeListDumpOutput(ctxt, cur->children); + if (ctxt->level > 0) ctxt->level--; + if ((xmlIndentTreeOutput) && (ctxt->format == 1)) + xmlOutputBufferWrite(buf, ctxt->indent_size * + (ctxt->level > ctxt->indent_nr ? + ctxt->indent_nr : ctxt->level), + ctxt->indent); + } + xmlOutputBufferWrite(buf, 2, "ns != NULL) && (cur->ns->prefix != NULL)) { + xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix); + xmlOutputBufferWrite(buf, 1, ":"); + } + + xmlOutputBufferWriteString(buf, (const char *)cur->name); + if (ctxt->format == 2) + xmlOutputBufferWriteWSNonSig(ctxt, 0); + xmlOutputBufferWrite(buf, 1, ">"); + ctxt->format = format; +} + +/** + * xmlDocContentDumpOutput: + * @cur: the document + * + * Dump an XML document. + */ +static int +xmlDocContentDumpOutput(xmlSaveCtxtPtr ctxt, xmlDocPtr cur) { + const xmlChar *oldenc = cur->encoding; + const xmlChar *oldctxtenc = ctxt->encoding; + const xmlChar *encoding = ctxt->encoding; + xmlCharEncodingOutputFunc oldescape = ctxt->escape; + xmlCharEncodingOutputFunc oldescapeAttr = ctxt->escapeAttr; + xmlOutputBufferPtr buf = ctxt->buf; + xmlCharEncoding enc; + int switched_encoding = 0; + + xmlInitParser(); + + if ((cur->type != XML_HTML_DOCUMENT_NODE) && + (cur->type != XML_DOCUMENT_NODE)) + return(-1); + + if (ctxt->encoding != NULL) { + cur->encoding = BAD_CAST ctxt->encoding; + } else if (cur->encoding != NULL) { + encoding = cur->encoding; + } else if (cur->charset != XML_CHAR_ENCODING_UTF8) { + encoding = (const xmlChar *) + xmlGetCharEncodingName((xmlCharEncoding) cur->charset); + } + + if (((cur->type == XML_HTML_DOCUMENT_NODE) && + ((ctxt->options & XML_SAVE_AS_XML) == 0) && + ((ctxt->options & XML_SAVE_XHTML) == 0)) || + (ctxt->options & XML_SAVE_AS_HTML)) { + return(-1); + } else if ((cur->type == XML_DOCUMENT_NODE) || + (ctxt->options & XML_SAVE_AS_XML) || + (ctxt->options & XML_SAVE_XHTML)) { + enc = xmlParseCharEncoding((const char*) encoding); + if ((encoding != NULL) && (oldctxtenc == NULL) && + (buf->encoder == NULL) && (buf->conv == NULL) && + ((ctxt->options & XML_SAVE_NO_DECL) == 0)) { + if ((enc != XML_CHAR_ENCODING_UTF8) && + (enc != XML_CHAR_ENCODING_NONE) && + (enc != XML_CHAR_ENCODING_ASCII)) { + /* + * we need to switch to this encoding but just for this + * document since we output the XMLDecl the conversion + * must be done to not generate not well formed documents. + */ + if (xmlSaveSwitchEncoding(ctxt, (const char*) encoding) < 0) { + cur->encoding = oldenc; + return(-1); + } + switched_encoding = 1; + } + if (ctxt->escape == xmlEscapeEntities) + ctxt->escape = NULL; + if (ctxt->escapeAttr == xmlEscapeEntities) + ctxt->escapeAttr = NULL; + } + + + /* + * Save the XML declaration + */ + if ((ctxt->options & XML_SAVE_NO_DECL) == 0) { + xmlOutputBufferWrite(buf, 14, "version != NULL) + xmlBufferWriteQuotedString(buf->buffer, cur->version); + else + xmlOutputBufferWrite(buf, 5, "\"1.0\""); + if (encoding != NULL) { + xmlOutputBufferWrite(buf, 10, " encoding="); + xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding); + } + switch (cur->standalone) { + case 0: + xmlOutputBufferWrite(buf, 16, " standalone=\"no\""); + break; + case 1: + xmlOutputBufferWrite(buf, 17, " standalone=\"yes\""); + break; + } + xmlOutputBufferWrite(buf, 3, "?>\n"); + } + + if (cur->children != NULL) { + xmlNodePtr child = cur->children; + + while (child != NULL) { + ctxt->level = 0; + xmlNodeDumpOutputInternal(ctxt, child); + xmlOutputBufferWrite(buf, 1, "\n"); + child = child->next; + } + } + } + + /* + * Restore the state of the saving context at the end of the document + */ + if ((switched_encoding) && (oldctxtenc == NULL)) { + xmlSaveClearEncoding(ctxt); + ctxt->escape = oldescape; + ctxt->escapeAttr = oldescapeAttr; + } + cur->encoding = oldenc; + return(0); +} + +/************************************************************************ + * * + * Public entry points * + * * + ************************************************************************/ + +/** + * xmlSaveToFd: + * @fd: a file descriptor number + * @encoding: the encoding name to use or NULL + * @options: a set of xmlSaveOptions + * + * Create a document saving context serializing to a file descriptor + * with the encoding and the options given. + * + * Returns a new serialization context or NULL in case of error. + */ +xmlSaveCtxtPtr +xmlSaveToFd(int fd, const char *encoding, int options) +{ + xmlSaveCtxtPtr ret; + + ret = xmlNewSaveCtxt(encoding, options); + if (ret == NULL) return(NULL); + ret->buf = xmlOutputBufferCreateFd(fd, ret->handler); + if (ret->buf == NULL) { + xmlFreeSaveCtxt(ret); + return(NULL); + } + return(ret); +} + +/** + * xmlSaveToFilename: + * @filename: a file name or an URL + * @encoding: the encoding name to use or NULL + * @options: a set of xmlSaveOptions + * + * Create a document saving context serializing to a filename or possibly + * to an URL (but this is less reliable) with the encoding and the options + * given. + * + * Returns a new serialization context or NULL in case of error. + */ +xmlSaveCtxtPtr +xmlSaveToFilename(const char *filename, const char *encoding, int options) +{ + xmlSaveCtxtPtr ret; + int compression = 0; /* TODO handle compression option */ + + ret = xmlNewSaveCtxt(encoding, options); + if (ret == NULL) return(NULL); + ret->buf = xmlOutputBufferCreateFilename(filename, ret->handler, + compression); + if (ret->buf == NULL) { + xmlFreeSaveCtxt(ret); + return(NULL); + } + return(ret); +} + +/** + * xmlSaveToBuffer: + * @buffer: a buffer + * @encoding: the encoding name to use or NULL + * @options: a set of xmlSaveOptions + * + * Create a document saving context serializing to a buffer + * with the encoding and the options given + * + * Returns a new serialization context or NULL in case of error. + */ + +xmlSaveCtxtPtr +xmlSaveToBuffer(xmlBufferPtr buffer, const char *encoding, int options) +{ + xmlSaveCtxtPtr ret; + xmlOutputBufferPtr out_buff; + xmlCharEncodingHandlerPtr handler; + + ret = xmlNewSaveCtxt(encoding, options); + if (ret == NULL) return(NULL); + + if (encoding != NULL) { + handler = xmlFindCharEncodingHandler(encoding); + if (handler == NULL) { + xmlFree(ret); + return(NULL); + } + } else + handler = NULL; + out_buff = xmlOutputBufferCreateBuffer(buffer, handler); + if (out_buff == NULL) { + xmlFree(ret); + if (handler) xmlCharEncCloseFunc(handler); + return(NULL); + } + + ret->buf = out_buff; + return(ret); +} + +/** + * xmlSaveToIO: + * @iowrite: an I/O write function + * @ioclose: an I/O close function + * @ioctx: an I/O handler + * @encoding: the encoding name to use or NULL + * @options: a set of xmlSaveOptions + * + * Create a document saving context serializing to a file descriptor + * with the encoding and the options given + * + * Returns a new serialization context or NULL in case of error. + */ +xmlSaveCtxtPtr +xmlSaveToIO(xmlOutputWriteCallback iowrite, + xmlOutputCloseCallback ioclose, + void *ioctx, const char *encoding, int options) +{ + xmlSaveCtxtPtr ret; + + ret = xmlNewSaveCtxt(encoding, options); + if (ret == NULL) return(NULL); + ret->buf = xmlOutputBufferCreateIO(iowrite, ioclose, ioctx, ret->handler); + if (ret->buf == NULL) { + xmlFreeSaveCtxt(ret); + return(NULL); + } + return(ret); +} + +/** + * xmlSaveDoc: + * @ctxt: a document saving context + * @doc: a document + * + * Save a full document to a saving context + * TODO: The function is not fully implemented yet as it does not return the + * byte count but 0 instead + * + * Returns the number of byte written or -1 in case of error + */ +long +xmlSaveDoc(xmlSaveCtxtPtr ctxt, xmlDocPtr doc) +{ + long ret = 0; + + if ((ctxt == NULL) || (doc == NULL)) return(-1); + if (xmlDocContentDumpOutput(ctxt, doc) < 0) + return(-1); + return(ret); +} + +/** + * xmlSaveTree: + * @ctxt: a document saving context + * @node: the top node of the subtree to save + * + * Save a subtree starting at the node parameter to a saving context + * TODO: The function is not fully implemented yet as it does not return the + * byte count but 0 instead + * + * Returns the number of byte written or -1 in case of error + */ +long +xmlSaveTree(xmlSaveCtxtPtr ctxt, xmlNodePtr node) +{ + long ret = 0; + + if ((ctxt == NULL) || (node == NULL)) return(-1); + xmlNodeDumpOutputInternal(ctxt, node); + return(ret); +} + +/** + * xmlSaveFlush: + * @ctxt: a document saving context + * + * Flush a document saving context, i.e. make sure that all bytes have + * been output. + * + * Returns the number of byte written or -1 in case of error. + */ +int +xmlSaveFlush(xmlSaveCtxtPtr ctxt) +{ + if (ctxt == NULL) return(-1); + if (ctxt->buf == NULL) return(-1); + return(xmlOutputBufferFlush(ctxt->buf)); +} + +/** + * xmlSaveClose: + * @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. + * + * Returns the number of byte written or -1 in case of error. + */ +int +xmlSaveClose(xmlSaveCtxtPtr ctxt) +{ + int ret; + + if (ctxt == NULL) return(-1); + ret = xmlSaveFlush(ctxt); + xmlFreeSaveCtxt(ctxt); + return(ret); +} + +/** + * xmlSaveSetEscape: + * @ctxt: a document saving context + * @escape: the escaping function + * + * Set a custom escaping function to be used for text in element content + * + * Returns 0 if successful or -1 in case of error. + */ +int +xmlSaveSetEscape(xmlSaveCtxtPtr ctxt, xmlCharEncodingOutputFunc escape) +{ + if (ctxt == NULL) return(-1); + ctxt->escape = escape; + return(0); +} + +/** + * xmlSaveSetAttrEscape: + * @ctxt: a document saving context + * @escape: the escaping function + * + * Set a custom escaping function to be used for text in attribute content + * + * Returns 0 if successful or -1 in case of error. + */ +int +xmlSaveSetAttrEscape(xmlSaveCtxtPtr ctxt, xmlCharEncodingOutputFunc escape) +{ + if (ctxt == NULL) return(-1); + ctxt->escapeAttr = escape; + return(0); +} + +/************************************************************************ + * * + * Public entry points based on buffers * + * * + ************************************************************************/ +/** + * xmlAttrSerializeTxtContent: + * @buf: the XML buffer output + * @doc: the document + * @attr: the attribute node + * @string: the text content + * + * Serialize text attribute values to an xml simple buffer + */ +void +xmlAttrSerializeTxtContent(xmlBufferPtr buf, xmlDocPtr doc, + xmlAttrPtr attr, const xmlChar * string) +{ + xmlChar *base, *cur; + + if (string == NULL) + return; + base = cur = (xmlChar *) string; + while (*cur != 0) { + if (*cur == '\n') { + if (base != cur) + xmlBufferAdd(buf, base, cur - base); + xmlBufferAdd(buf, BAD_CAST " ", 5); + cur++; + base = cur; + } else if (*cur == '\r') { + if (base != cur) + xmlBufferAdd(buf, base, cur - base); + xmlBufferAdd(buf, BAD_CAST " ", 5); + cur++; + base = cur; + } else if (*cur == '\t') { + if (base != cur) + xmlBufferAdd(buf, base, cur - base); + xmlBufferAdd(buf, BAD_CAST " ", 4); + cur++; + base = cur; + } else 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 "<", 4); + cur++; + base = cur; + } else if (*cur == '>') { + if (base != cur) + xmlBufferAdd(buf, base, cur - base); + xmlBufferAdd(buf, BAD_CAST ">", 4); + cur++; + base = cur; + } else if (*cur == '&') { + if (base != cur) + xmlBufferAdd(buf, base, cur - base); + xmlBufferAdd(buf, BAD_CAST "&", 5); + cur++; + base = cur; + } else if ((*cur >= 0x80) && ((doc == NULL) || + (doc->encoding == NULL))) { + /* + * We assume we have UTF-8 content. + */ + unsigned char tmp[12]; + int val = 0, l = 1; + + if (base != cur) + xmlBufferAdd(buf, base, cur - base); + if (*cur < 0xC0) { + xmlSaveErr(XML_SAVE_NOT_UTF8, (xmlNodePtr) attr, NULL); + if (doc != NULL) + doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1"); + xmlSerializeHexCharRef(tmp, *cur); + xmlBufferAdd(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) { + 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))) { + xmlSaveErr(XML_SAVE_CHAR_INVALID, (xmlNodePtr) attr, NULL); + if (doc != NULL) + doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1"); + + xmlSerializeHexCharRef(tmp, *cur); + xmlBufferAdd(buf, (xmlChar *) tmp, -1); + cur++; + base = cur; + continue; + } + /* + * We could do multiple things here. Just save + * as a char ref + */ + xmlSerializeHexCharRef(tmp, val); + xmlBufferAdd(buf, (xmlChar *) tmp, -1); + cur += l; + base = cur; + } else { + cur++; + } + } + if (base != cur) + xmlBufferAdd(buf, base, cur - base); +} + +/** + * xmlNodeDump: + * @buf: the XML buffer output + * @doc: the document + * @cur: the current node + * @level: the imbrication level for indenting + * @format: is formatting allowed + * + * Dump an XML node, recursive behaviour,children are printed too. + * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 + * or xmlKeepBlanksDefault(0) was called + * + * Returns the number of bytes written to the buffer or -1 in case of error + */ +int +xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level, + int format) +{ + unsigned int use; + int ret; + xmlOutputBufferPtr outbuf; + + xmlInitParser(); + + if (cur == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlNodeDump : node == NULL\n"); +#endif + return (-1); + } + if (buf == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlNodeDump : buf == NULL\n"); +#endif + return (-1); + } + outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer)); + if (outbuf == NULL) { + xmlSaveErrMemory("creating buffer"); + return (-1); + } + memset(outbuf, 0, (size_t) sizeof(xmlOutputBuffer)); + outbuf->buffer = buf; + outbuf->encoder = NULL; + outbuf->writecallback = NULL; + outbuf->closecallback = NULL; + outbuf->context = NULL; + outbuf->written = 0; + + use = buf->use; + xmlNodeDumpOutput(outbuf, doc, cur, level, format, NULL); + xmlFree(outbuf); + ret = buf->use - use; + return (ret); +} + +/** + * xmlElemDump: + * @f: the FILE * for the output + * @doc: the document + * @cur: the current node + * + * Dump an XML/HTML node, recursive behaviour, children are printed too. + */ +void +xmlElemDump(FILE * f, xmlDocPtr doc, xmlNodePtr cur) +{ + xmlOutputBufferPtr outbuf; + + xmlInitParser(); + + if (cur == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlElemDump : cur == NULL\n"); +#endif + return; + } +#ifdef DEBUG_TREE + if (doc == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlElemDump : doc == NULL\n"); + } +#endif + + outbuf = xmlOutputBufferCreateFile(f, NULL); + if (outbuf == NULL) + return; + if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) { + xmlSaveErr(XML_ERR_INTERNAL_ERROR, cur, "HTML support not compiled in\n"); + } else + xmlNodeDumpOutput(outbuf, doc, cur, 0, 1, NULL); + xmlOutputBufferClose(outbuf); +} + +/************************************************************************ + * * + * Saving functions front-ends * + * * + ************************************************************************/ + +/** + * xmlNodeDumpOutput: + * @buf: the XML buffer output + * @doc: the document + * @cur: the current node + * @level: the imbrication level for indenting + * @format: is formatting allowed + * @encoding: an optional encoding string + * + * Dump an XML node, recursive behaviour, children are printed too. + * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 + * or xmlKeepBlanksDefault(0) was called + */ +void +xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, + int level, int format, const char *encoding) +{ + xmlSaveCtxt ctxt; + + xmlInitParser(); + + if ((buf == NULL) || (cur == NULL)) return; + + if (encoding == NULL) + encoding = "UTF-8"; + + memset(&ctxt, 0, sizeof(ctxt)); + ctxt.doc = doc; + ctxt.buf = buf; + ctxt.level = level; + ctxt.format = format ? 1 : 0; + ctxt.encoding = (const xmlChar *) encoding; + xmlSaveCtxtInit(&ctxt); + ctxt.options |= XML_SAVE_AS_XML; + + xmlNodeDumpOutputInternal(&ctxt, cur); +} + +/** + * xmlDocDumpFormatMemoryEnc: + * @out_doc: Document to generate XML text from + * @doc_txt_ptr: Memory pointer for allocated XML text + * @doc_txt_len: Length of the generated XML text + * @txt_encoding: Character encoding to use when generating XML text + * @format: should formatting spaces been added + * + * Dump the current DOM tree into memory using the character encoding specified + * by the caller. Note it is up to the caller of this function to free the + * allocated memory with xmlFree(). + * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 + * or xmlKeepBlanksDefault(0) was called + */ + +void +xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr, + int * doc_txt_len, const char * txt_encoding, + int format) { + xmlSaveCtxt ctxt; + int dummy = 0; + xmlOutputBufferPtr out_buff = NULL; + xmlCharEncodingHandlerPtr conv_hdlr = NULL; + + if (doc_txt_len == NULL) { + doc_txt_len = &dummy; /* Continue, caller just won't get length */ + } + + if (doc_txt_ptr == NULL) { + *doc_txt_len = 0; + return; + } + + *doc_txt_ptr = NULL; + *doc_txt_len = 0; + + if (out_doc == NULL) { + /* No document, no output */ + return; + } + + /* + * Validate the encoding value, if provided. + * This logic is copied from xmlSaveFileEnc. + */ + + 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); + return; + } + } + + if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) { + xmlSaveErrMemory("creating buffer"); + return; + } + + memset(&ctxt, 0, sizeof(ctxt)); + ctxt.doc = out_doc; + ctxt.buf = out_buff; + ctxt.level = 0; + ctxt.format = format ? 1 : 0; + ctxt.encoding = (const xmlChar *) txt_encoding; + xmlSaveCtxtInit(&ctxt); + ctxt.options |= XML_SAVE_AS_XML; + xmlDocContentDumpOutput(&ctxt, out_doc); + xmlOutputBufferFlush(out_buff); + if (out_buff->conv != NULL) { + *doc_txt_len = out_buff->conv->use; + *doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len); + } else { + *doc_txt_len = out_buff->buffer->use; + *doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len); + } + (void)xmlOutputBufferClose(out_buff); + + if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) { + *doc_txt_len = 0; + xmlSaveErrMemory("creating output"); + } + + return; +} + +/** + * xmlDocDumpMemory: + * @cur: the document + * @mem: OUT: the memory pointer + * @size: OUT: the memory length + * + * Dump an XML document in memory and return the #xmlChar * and it's size + * in bytes. It's up to the caller to free the memory with xmlFree(). + * The resulting byte array is zero terminated, though the last 0 is not + * included in the returned size. + */ +void +xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) { + xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0); +} + +/** + * xmlDocDumpFormatMemory: + * @cur: the document + * @mem: OUT: the memory pointer + * @size: OUT: the memory length + * @format: should formatting spaces been added + * + * + * Dump an XML document in memory and return the #xmlChar * and it's size. + * It's up to the caller to free the memory with xmlFree(). + * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 + * or xmlKeepBlanksDefault(0) was called + */ +void +xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) { + xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format); +} + +/** + * xmlDocDumpMemoryEnc: + * @out_doc: Document to generate XML text from + * @doc_txt_ptr: Memory pointer for allocated XML text + * @doc_txt_len: Length of the generated XML text + * @txt_encoding: Character encoding to use when generating XML text + * + * Dump the current DOM tree into memory using the character encoding specified + * by the caller. Note it is up to the caller of this function to free the + * allocated memory with xmlFree(). + */ + +void +xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr, + int * doc_txt_len, const char * txt_encoding) { + xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len, + txt_encoding, 0); +} + +/** + * xmlDocFormatDump: + * @f: the FILE* + * @cur: the document + * @format: should formatting spaces been added + * + * Dump an XML document to an open FILE. + * + * returns: the number of bytes written or -1 in case of failure. + * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 + * or xmlKeepBlanksDefault(0) was called + */ +int +xmlDocFormatDump(FILE *f, xmlDocPtr cur, int format) { + xmlSaveCtxt ctxt; + xmlOutputBufferPtr buf; + const char * encoding; + xmlCharEncodingHandlerPtr handler = NULL; + int ret; + + if (cur == NULL) { +#ifdef DEBUG_TREE + xmlGenericError(xmlGenericErrorContext, + "xmlDocDump : document == NULL\n"); +#endif + return(-1); + } + encoding = (const char *) cur->encoding; + + if (encoding != NULL) { + handler = xmlFindCharEncodingHandler(encoding); + if (handler == NULL) { + xmlFree((char *) cur->encoding); + cur->encoding = NULL; + encoding = NULL; + } + } + buf = xmlOutputBufferCreateFile(f, handler); + if (buf == NULL) return(-1); + memset(&ctxt, 0, sizeof(ctxt)); + ctxt.doc = cur; + ctxt.buf = buf; + ctxt.level = 0; + ctxt.format = format ? 1 : 0; + ctxt.encoding = (const xmlChar *) encoding; + xmlSaveCtxtInit(&ctxt); + ctxt.options |= XML_SAVE_AS_XML; + xmlDocContentDumpOutput(&ctxt, cur); + + ret = xmlOutputBufferClose(buf); + return(ret); +} + +/** + * xmlDocDump: + * @f: the FILE* + * @cur: the document + * + * Dump an XML document to an open FILE. + * + * returns: the number of bytes written or -1 in case of failure. + */ +int +xmlDocDump(FILE *f, xmlDocPtr cur) { + return(xmlDocFormatDump (f, cur, 0)); +} + +/** + * xmlSaveFileTo: + * @buf: an output I/O buffer + * @cur: the document + * @encoding: the encoding if any assuming the I/O layer handles the trancoding + * + * Dump an XML document to an I/O buffer. + * Warning ! This call xmlOutputBufferClose() on buf which is not available + * after this call. + * + * returns: the number of bytes written or -1 in case of failure. + */ +int +xmlSaveFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) { + xmlSaveCtxt ctxt; + int ret; + + if (buf == NULL) return(-1); + if (cur == NULL) { + xmlOutputBufferClose(buf); + return(-1); + } + memset(&ctxt, 0, sizeof(ctxt)); + ctxt.doc = cur; + ctxt.buf = buf; + ctxt.level = 0; + ctxt.format = 0; + ctxt.encoding = (const xmlChar *) encoding; + xmlSaveCtxtInit(&ctxt); + ctxt.options |= XML_SAVE_AS_XML; + xmlDocContentDumpOutput(&ctxt, cur); + ret = xmlOutputBufferClose(buf); + return(ret); +} + +/** + * xmlSaveFormatFileTo: + * @buf: an output I/O buffer + * @cur: the document + * @encoding: the encoding if any assuming the I/O layer handles the trancoding + * @format: should formatting spaces been added + * + * Dump an XML document to an I/O buffer. + * Warning ! This call xmlOutputBufferClose() on buf which is not available + * after this call. + * + * returns: the number of bytes written or -1 in case of failure. + */ +int +xmlSaveFormatFileTo(xmlOutputBufferPtr buf, xmlDocPtr cur, + const char *encoding, int format) +{ + xmlSaveCtxt ctxt; + int ret; + + if (buf == NULL) return(-1); + if ((cur == NULL) || + ((cur->type != XML_DOCUMENT_NODE) && + (cur->type != XML_HTML_DOCUMENT_NODE))) { + xmlOutputBufferClose(buf); + return(-1); + } + memset(&ctxt, 0, sizeof(ctxt)); + ctxt.doc = cur; + ctxt.buf = buf; + ctxt.level = 0; + ctxt.format = format ? 1 : 0; + ctxt.encoding = (const xmlChar *) encoding; + xmlSaveCtxtInit(&ctxt); + ctxt.options |= XML_SAVE_AS_XML; + xmlDocContentDumpOutput(&ctxt, cur); + ret = xmlOutputBufferClose(buf); + return (ret); +} + +/** + * xmlSaveFormatFileEnc: + * @filename: the filename or URL to output + * @cur: the document being saved + * @encoding: the name of the encoding to use or NULL. + * @format: should formatting spaces be added. + * + * Dump an XML document to a file or an URL. + * + * Returns the number of bytes written or -1 in case of error. + * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 + * or xmlKeepBlanksDefault(0) was called + */ +int +xmlSaveFormatFileEnc( const char * filename, xmlDocPtr cur, + const char * encoding, int format ) { + xmlSaveCtxt ctxt; + xmlOutputBufferPtr buf; + xmlCharEncodingHandlerPtr handler = NULL; + int ret; + + if (cur == NULL) + return(-1); + + if (encoding == NULL) + encoding = (const char *) cur->encoding; + + if (encoding != NULL) { + + handler = xmlFindCharEncodingHandler(encoding); + if (handler == NULL) + return(-1); + } + +#ifdef HAVE_ZLIB_H + if (cur->compression < 0) cur->compression = xmlGetCompressMode(); +#endif + /* + * save the content to a temp buffer. + */ + buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression); + if (buf == NULL) return(-1); + memset(&ctxt, 0, sizeof(ctxt)); + ctxt.doc = cur; + ctxt.buf = buf; + ctxt.level = 0; + ctxt.format = format ? 1 : 0; + ctxt.encoding = (const xmlChar *) encoding; + xmlSaveCtxtInit(&ctxt); + ctxt.options |= XML_SAVE_AS_XML; + + xmlDocContentDumpOutput(&ctxt, cur); + + ret = xmlOutputBufferClose(buf); + return(ret); +} + + +/** + * xmlSaveFileEnc: + * @filename: the filename (or URL) + * @cur: the document + * @encoding: the name of an encoding (or NULL) + * + * Dump an XML document, converting it to the given encoding + * + * returns: the number of bytes written or -1 in case of failure. + */ +int +xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) { + return ( xmlSaveFormatFileEnc( filename, cur, encoding, 0 ) ); +} + +/** + * xmlSaveFormatFile: + * @filename: the filename (or URL) + * @cur: the document + * @format: should formatting spaces been added + * + * Dump an XML document to a file. Will use compression if + * compiled in and enabled. If @filename is "-" the stdout file is + * used. If @format is set then the document will be indented on output. + * Note that @format = 1 provide node indenting only if xmlIndentTreeOutput = 1 + * or xmlKeepBlanksDefault(0) was called + * + * returns: the number of bytes written or -1 in case of failure. + */ +int +xmlSaveFormatFile(const char *filename, xmlDocPtr cur, int format) { + return ( xmlSaveFormatFileEnc( filename, cur, NULL, format ) ); +} + +/** + * xmlSaveFile: + * @filename: the filename (or URL) + * @cur: the document + * + * Dump an XML document to a file. Will use compression if + * compiled in and enabled. If @filename is "-" the stdout file is + * used. + * returns: the number of bytes written or -1 in case of failure. + */ +int +xmlSaveFile(const char *filename, xmlDocPtr cur) { + return(xmlSaveFormatFileEnc(filename, cur, NULL, 0)); +} + +#endif /* LIBXML_OUTPUT_ENABLED */ + +#define bottom_xmlsave +#include "elfgcchack.h" diff --git a/android/native/libxml2/xmlschemas.c b/android/native/libxml2/xmlschemas.c new file mode 100644 index 0000000000..ddb31d6782 --- /dev/null +++ b/android/native/libxml2/xmlschemas.c @@ -0,0 +1,28772 @@ +/* + * schemas.c : implementation of the XML Schema handling and + * schema validity checking + * + * See Copyright for the status of this software. + * + * Daniel Veillard + */ + +/* + * TODO: + * - when types are redefined in includes, check that all + * types in the redef list are equal + * -> need a type equality operation. + * - if we don't intend to use the schema for schemas, we + * need to validate all schema attributes (ref, type, name) + * against their types. + * - Eliminate item creation for: ?? + * + * URGENT TODO: + * - For xsi-driven schema acquisition, augment the IDCs after every + * acquisition episode (xmlSchemaAugmentIDC). + * + * NOTES: + * - Elimated item creation for: , , + * , , , + * + * PROBLEMS: + * - http://lists.w3.org/Archives/Public/www-xml-schema-comments/2005JulSep/0337.html + * IDC XPath expression and chameleon includes: the targetNamespace is changed, so + * XPath will have trouble to resolve to this namespace, since not known. + * + * + * CONSTRAINTS: + * + * Schema Component Constraint: + * All Group Limited (cos-all-limited) + * Status: complete + * (1.2) + * In xmlSchemaGroupDefReferenceTermFixup() and + * (2) + * In xmlSchemaParseModelGroup() + * TODO: Actually this should go to component-level checks, + * but is done here due to performance. Move it to an other layer + * is schema construction via an API is implemented. + */ +#define IN_LIBXML +#include "libxml.h" + +#ifdef LIBXML_SCHEMAS_ENABLED + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef LIBXML_PATTERN_ENABLED +#include +#endif +#ifdef LIBXML_READER_ENABLED +#include +#endif + +/* #define DEBUG 1 */ + +/* #define DEBUG_CONTENT 1 */ + +/* #define DEBUG_TYPE 1 */ + +/* #define DEBUG_CONTENT_REGEXP 1 */ + +/* #define DEBUG_AUTOMATA 1 */ + +/* #define DEBUG_IDC */ + +/* #define DEBUG_IDC_NODE_TABLE */ + +/* #define WXS_ELEM_DECL_CONS_ENABLED */ + +#ifdef DEBUG_IDC + #ifndef DEBUG_IDC_NODE_TABLE + #define DEBUG_IDC_NODE_TABLE + #endif +#endif + +/* #define ENABLE_PARTICLE_RESTRICTION 1 */ + +#define ENABLE_REDEFINE + +/* #define ENABLE_NAMED_LOCALS */ + +/* #define ENABLE_IDC_NODE_TABLES_TEST */ + +#define DUMP_CONTENT_MODEL + +#ifdef LIBXML_READER_ENABLED +/* #define XML_SCHEMA_READER_ENABLED */ +#endif + +#define UNBOUNDED (1 << 30) +#define TODO \ + xmlGenericError(xmlGenericErrorContext, \ + "Unimplemented block at %s:%d\n", \ + __FILE__, __LINE__); + +#define XML_SCHEMAS_NO_NAMESPACE (const xmlChar *) "##" + +/* + * The XML Schemas namespaces + */ +static const xmlChar *xmlSchemaNs = (const xmlChar *) + "http://www.w3.org/2001/XMLSchema"; + +static const xmlChar *xmlSchemaInstanceNs = (const xmlChar *) + "http://www.w3.org/2001/XMLSchema-instance"; + +static const xmlChar *xmlNamespaceNs = (const xmlChar *) + "http://www.w3.org/2000/xmlns/"; + +/* +* Come casting macros. +*/ +#define ACTXT_CAST (xmlSchemaAbstractCtxtPtr) +#define PCTXT_CAST (xmlSchemaParserCtxtPtr) +#define VCTXT_CAST (xmlSchemaValidCtxtPtr) +#define WXS_BASIC_CAST (xmlSchemaBasicItemPtr) +#define WXS_TREE_CAST (xmlSchemaTreeItemPtr) +#define WXS_PTC_CAST (xmlSchemaParticlePtr) +#define WXS_TYPE_CAST (xmlSchemaTypePtr) +#define WXS_ELEM_CAST (xmlSchemaElementPtr) +#define WXS_ATTR_GROUP_CAST (xmlSchemaAttributeGroupPtr) +#define WXS_ATTR_CAST (xmlSchemaAttributePtr) +#define WXS_ATTR_USE_CAST (xmlSchemaAttributeUsePtr) +#define WXS_ATTR_PROHIB_CAST (xmlSchemaAttributeUseProhibPtr) +#define WXS_MODEL_GROUPDEF_CAST (xmlSchemaModelGroupDefPtr) +#define WXS_MODEL_GROUP_CAST (xmlSchemaModelGroupPtr) +#define WXS_IDC_CAST (xmlSchemaIDCPtr) +#define WXS_QNAME_CAST (xmlSchemaQNameRefPtr) +#define WXS_LIST_CAST (xmlSchemaItemListPtr) + +/* +* Macros to query common properties of components. +*/ +#define WXS_ITEM_NODE(i) xmlSchemaGetComponentNode(WXS_BASIC_CAST (i)) + +#define WXS_ITEM_TYPE_NAME(i) xmlSchemaGetComponentTypeStr(WXS_BASIC_CAST (i)) +/* +* Macros for element declarations. +*/ +#define WXS_ELEM_TYPEDEF(e) (e)->subtypes + +#define WXS_SUBST_HEAD(item) (item)->refDecl +/* +* Macros for attribute declarations. +*/ +#define WXS_ATTR_TYPEDEF(a) (a)->subtypes +/* +* Macros for attribute uses. +*/ +#define WXS_ATTRUSE_DECL(au) WXS_ATTR_CAST (WXS_ATTR_USE_CAST (au))->attrDecl + +#define WXS_ATTRUSE_TYPEDEF(au) WXS_ATTR_TYPEDEF(WXS_ATTRUSE_DECL( WXS_ATTR_USE_CAST au)) + +#define WXS_ATTRUSE_DECL_NAME(au) (WXS_ATTRUSE_DECL(au))->name + +#define WXS_ATTRUSE_DECL_TNS(au) (WXS_ATTRUSE_DECL(au))->targetNamespace +/* +* Macros for attribute groups. +*/ +#define WXS_ATTR_GROUP_HAS_REFS(ag) ((WXS_ATTR_GROUP_CAST (ag))->flags & XML_SCHEMAS_ATTRGROUP_HAS_REFS) +#define WXS_ATTR_GROUP_EXPANDED(ag) ((WXS_ATTR_GROUP_CAST (ag))->flags & XML_SCHEMAS_ATTRGROUP_WILDCARD_BUILDED) +/* +* Macros for particles. +*/ +#define WXS_PARTICLE(p) WXS_PTC_CAST (p) + +#define WXS_PARTICLE_TERM(p) (WXS_PARTICLE(p))->children + +#define WXS_PARTICLE_TERM_AS_ELEM(p) (WXS_ELEM_CAST WXS_PARTICLE_TERM(p)) + +#define WXS_PARTICLE_MODEL(p) WXS_MODEL_GROUP_CAST WXS_PARTICLE(p)->children +/* +* Macros for model groups definitions. +*/ +#define WXS_MODELGROUPDEF_MODEL(mgd) (WXS_MODEL_GROUP_CAST (mgd))->children +/* +* Macros for model groups. +*/ +#define WXS_IS_MODEL_GROUP(i) \ + (((i)->type == XML_SCHEMA_TYPE_SEQUENCE) || \ + ((i)->type == XML_SCHEMA_TYPE_CHOICE) || \ + ((i)->type == XML_SCHEMA_TYPE_ALL)) + +#define WXS_MODELGROUP_PARTICLE(mg) WXS_PTC_CAST (mg)->children +/* +* Macros for schema buckets. +*/ +#define WXS_IS_BUCKET_INCREDEF(t) (((t) == XML_SCHEMA_SCHEMA_INCLUDE) || \ + ((t) == XML_SCHEMA_SCHEMA_REDEFINE)) + +#define WXS_IS_BUCKET_IMPMAIN(t) (((t) == XML_SCHEMA_SCHEMA_MAIN) || \ + ((t) == XML_SCHEMA_SCHEMA_IMPORT)) + +#define WXS_IMPBUCKET(b) ((xmlSchemaImportPtr) (b)) + +#define WXS_INCBUCKET(b) ((xmlSchemaIncludePtr) (b)) +/* +* Macros for complex/simple types. +*/ +#define WXS_IS_ANYTYPE(i) \ + (( (i)->type == XML_SCHEMA_TYPE_BASIC) && \ + ( (WXS_TYPE_CAST (i))->builtInType == XML_SCHEMAS_ANYTYPE)) + +#define WXS_IS_COMPLEX(i) \ + (((i)->type == XML_SCHEMA_TYPE_COMPLEX) || \ + ((i)->builtInType == XML_SCHEMAS_ANYTYPE)) + +#define WXS_IS_SIMPLE(item) \ + ((item->type == XML_SCHEMA_TYPE_SIMPLE) || \ + ((item->type == XML_SCHEMA_TYPE_BASIC) && \ + (item->builtInType != XML_SCHEMAS_ANYTYPE))) + +#define WXS_IS_ANY_SIMPLE_TYPE(i) \ + (((i)->type == XML_SCHEMA_TYPE_BASIC) && \ + ((i)->builtInType == XML_SCHEMAS_ANYSIMPLETYPE)) + +#define WXS_IS_RESTRICTION(t) \ + ((t)->flags & XML_SCHEMAS_TYPE_DERIVATION_METHOD_RESTRICTION) + +#define WXS_IS_EXTENSION(t) \ + ((t)->flags & XML_SCHEMAS_TYPE_DERIVATION_METHOD_EXTENSION) + +#define WXS_IS_TYPE_NOT_FIXED(i) \ + (((i)->type != XML_SCHEMA_TYPE_BASIC) && \ + (((i)->flags & XML_SCHEMAS_TYPE_INTERNAL_RESOLVED) == 0)) + +#define WXS_IS_TYPE_NOT_FIXED_1(item) \ + (((item)->type != XML_SCHEMA_TYPE_BASIC) && \ + (((item)->flags & XML_SCHEMAS_TYPE_FIXUP_1) == 0)) + +#define WXS_TYPE_IS_GLOBAL(t) ((t)->flags & XML_SCHEMAS_TYPE_GLOBAL) + +#define WXS_TYPE_IS_LOCAL(t) (((t)->flags & XML_SCHEMAS_TYPE_GLOBAL) == 0) +/* +* Macros for exclusively for complex types. +*/ +#define WXS_HAS_COMPLEX_CONTENT(item) \ + ((item->contentType == XML_SCHEMA_CONTENT_MIXED) || \ + (item->contentType == XML_SCHEMA_CONTENT_EMPTY) || \ + (item->contentType == XML_SCHEMA_CONTENT_ELEMENTS)) + +#define WXS_HAS_SIMPLE_CONTENT(item) \ + ((item->contentType == XML_SCHEMA_CONTENT_SIMPLE) || \ + (item->contentType == XML_SCHEMA_CONTENT_BASIC)) + +#define WXS_HAS_MIXED_CONTENT(item) \ + (item->contentType == XML_SCHEMA_CONTENT_MIXED) + +#define WXS_EMPTIABLE(t) \ + (xmlSchemaIsParticleEmptiable(WXS_PTC_CAST (t)->subtypes)) + +#define WXS_TYPE_CONTENTTYPE(t) (t)->subtypes + +#define WXS_TYPE_PARTICLE(t) WXS_PTC_CAST (t)->subtypes + +#define WXS_TYPE_PARTICLE_TERM(t) WXS_PARTICLE_TERM(WXS_TYPE_PARTICLE(t)) +/* +* Macros for exclusively for simple types. +*/ +#define WXS_LIST_ITEMTYPE(t) (t)->subtypes + +#define WXS_IS_ATOMIC(t) (t->flags & XML_SCHEMAS_TYPE_VARIETY_ATOMIC) + +#define WXS_IS_LIST(t) (t->flags & XML_SCHEMAS_TYPE_VARIETY_LIST) + +#define WXS_IS_UNION(t) (t->flags & XML_SCHEMAS_TYPE_VARIETY_UNION) +/* +* Misc parser context macros. +*/ +#define WXS_CONSTRUCTOR(ctx) (ctx)->constructor + +#define WXS_HAS_BUCKETS(ctx) \ +( (WXS_CONSTRUCTOR((ctx))->buckets != NULL) && \ +(WXS_CONSTRUCTOR((ctx))->buckets->nbItems > 0) ) + +#define WXS_SUBST_GROUPS(ctx) WXS_CONSTRUCTOR((ctx))->substGroups + +#define WXS_BUCKET(ctx) WXS_CONSTRUCTOR((ctx))->bucket + +#define WXS_SCHEMA(ctx) (ctx)->schema + +#define WXS_ADD_LOCAL(ctx, item) \ + xmlSchemaAddItemSize(&(WXS_BUCKET(ctx)->locals), 10, item) + +#define WXS_ADD_GLOBAL(ctx, item) \ + xmlSchemaAddItemSize(&(WXS_BUCKET(ctx)->globals), 5, item) + +#define WXS_ADD_PENDING(ctx, item) \ + xmlSchemaAddItemSize(&((ctx)->constructor->pending), 10, item) +/* +* xmlSchemaItemList macros. +*/ +#define WXS_ILIST_IS_EMPTY(l) ((l == NULL) || ((l)->nbItems == 0)) +/* +* Misc macros. +*/ +#define IS_SCHEMA(node, type) \ + ((node != NULL) && (node->ns != NULL) && \ + (xmlStrEqual(node->name, (const xmlChar *) type)) && \ + (xmlStrEqual(node->ns->href, xmlSchemaNs))) + +#define FREE_AND_NULL(str) if ((str) != NULL) { xmlFree((xmlChar *) (str)); str = NULL; } + +/* +* Since we put the default/fixed values into the dict, we can +* use pointer comparison for those values. +* REMOVED: (xmlStrEqual((v1), (v2))) +*/ +#define WXS_ARE_DEFAULT_STR_EQUAL(v1, v2) ((v1) == (v2)) + +#define INODE_NILLED(item) (item->flags & XML_SCHEMA_ELEM_INFO_NILLED) + +#define CAN_PARSE_SCHEMA(b) (((b)->doc != NULL) && ((b)->parsed == 0)) + +#define HFAILURE if (res == -1) goto exit_failure; + +#define HERROR if (res != 0) goto exit_error; + +#define HSTOP(ctx) if ((ctx)->stop) goto exit; +/* +* Some flags used for various schema constraints. +*/ +#define SUBSET_RESTRICTION 1<<0 +#define SUBSET_EXTENSION 1<<1 +#define SUBSET_SUBSTITUTION 1<<2 +#define SUBSET_LIST 1<<3 +#define SUBSET_UNION 1<<4 + +typedef struct _xmlSchemaNodeInfo xmlSchemaNodeInfo; +typedef xmlSchemaNodeInfo *xmlSchemaNodeInfoPtr; + +typedef struct _xmlSchemaItemList xmlSchemaItemList; +typedef xmlSchemaItemList *xmlSchemaItemListPtr; +struct _xmlSchemaItemList { + void **items; /* used for dynamic addition of schemata */ + int nbItems; /* used for dynamic addition of schemata */ + int sizeItems; /* used for dynamic addition of schemata */ +}; + +#define XML_SCHEMA_CTXT_PARSER 1 +#define XML_SCHEMA_CTXT_VALIDATOR 2 + +typedef struct _xmlSchemaAbstractCtxt xmlSchemaAbstractCtxt; +typedef xmlSchemaAbstractCtxt *xmlSchemaAbstractCtxtPtr; +struct _xmlSchemaAbstractCtxt { + int type; /* E.g. XML_SCHEMA_CTXT_VALIDATOR */ +}; + +typedef struct _xmlSchemaBucket xmlSchemaBucket; +typedef xmlSchemaBucket *xmlSchemaBucketPtr; + +#define XML_SCHEMA_SCHEMA_MAIN 0 +#define XML_SCHEMA_SCHEMA_IMPORT 1 +#define XML_SCHEMA_SCHEMA_INCLUDE 2 +#define XML_SCHEMA_SCHEMA_REDEFINE 3 + +/** + * xmlSchemaSchemaRelation: + * + * Used to create a graph of schema relationships. + */ +typedef struct _xmlSchemaSchemaRelation xmlSchemaSchemaRelation; +typedef xmlSchemaSchemaRelation *xmlSchemaSchemaRelationPtr; +struct _xmlSchemaSchemaRelation { + xmlSchemaSchemaRelationPtr next; + int type; /* E.g. XML_SCHEMA_SCHEMA_IMPORT */ + const xmlChar *importNamespace; + xmlSchemaBucketPtr bucket; +}; + +#define XML_SCHEMA_BUCKET_MARKED 1<<0 +#define XML_SCHEMA_BUCKET_COMPS_ADDED 1<<1 + +struct _xmlSchemaBucket { + int type; + int flags; + const xmlChar *schemaLocation; + const xmlChar *origTargetNamespace; + const xmlChar *targetNamespace; + xmlDocPtr doc; + xmlSchemaSchemaRelationPtr relations; + int located; + int parsed; + int imported; + int preserveDoc; + xmlSchemaItemListPtr globals; /* Global components. */ + xmlSchemaItemListPtr locals; /* Local components. */ +}; + +/** + * xmlSchemaImport: + * (extends xmlSchemaBucket) + * + * Reflects a schema. Holds some information + * about the schema and its toplevel components. Duplicate + * toplevel components are not checked at this level. + */ +typedef struct _xmlSchemaImport xmlSchemaImport; +typedef xmlSchemaImport *xmlSchemaImportPtr; +struct _xmlSchemaImport { + int type; /* Main OR import OR include. */ + int flags; + const xmlChar *schemaLocation; /* The URI of the schema document. */ + /* For chameleon includes, @origTargetNamespace will be NULL */ + const xmlChar *origTargetNamespace; + /* + * For chameleon includes, @targetNamespace will be the + * targetNamespace of the including schema. + */ + const xmlChar *targetNamespace; + xmlDocPtr doc; /* The schema node-tree. */ + /* @relations will hold any included/imported/redefined schemas. */ + xmlSchemaSchemaRelationPtr relations; + int located; + int parsed; + int imported; + int preserveDoc; + xmlSchemaItemListPtr globals; + xmlSchemaItemListPtr locals; + /* The imported schema. */ + xmlSchemaPtr schema; +}; + +/* +* (extends xmlSchemaBucket) +*/ +typedef struct _xmlSchemaInclude xmlSchemaInclude; +typedef xmlSchemaInclude *xmlSchemaIncludePtr; +struct _xmlSchemaInclude { + int type; + int flags; + const xmlChar *schemaLocation; + const xmlChar *origTargetNamespace; + const xmlChar *targetNamespace; + xmlDocPtr doc; + xmlSchemaSchemaRelationPtr relations; + int located; + int parsed; + int imported; + int preserveDoc; + xmlSchemaItemListPtr globals; /* Global components. */ + xmlSchemaItemListPtr locals; /* Local components. */ + + /* The owning main or import schema bucket. */ + xmlSchemaImportPtr ownerImport; +}; + +/** + * xmlSchemaBasicItem: + * + * The abstract base type for schema components. + */ +typedef struct _xmlSchemaBasicItem xmlSchemaBasicItem; +typedef xmlSchemaBasicItem *xmlSchemaBasicItemPtr; +struct _xmlSchemaBasicItem { + xmlSchemaTypeType type; +}; + +/** + * xmlSchemaAnnotItem: + * + * The abstract base type for annotated schema components. + * (Extends xmlSchemaBasicItem) + */ +typedef struct _xmlSchemaAnnotItem xmlSchemaAnnotItem; +typedef xmlSchemaAnnotItem *xmlSchemaAnnotItemPtr; +struct _xmlSchemaAnnotItem { + xmlSchemaTypeType type; + xmlSchemaAnnotPtr annot; +}; + +/** + * xmlSchemaTreeItem: + * + * The abstract base type for tree-like structured schema components. + * (Extends xmlSchemaAnnotItem) + */ +typedef struct _xmlSchemaTreeItem xmlSchemaTreeItem; +typedef xmlSchemaTreeItem *xmlSchemaTreeItemPtr; +struct _xmlSchemaTreeItem { + xmlSchemaTypeType type; + xmlSchemaAnnotPtr annot; + xmlSchemaTreeItemPtr next; + xmlSchemaTreeItemPtr children; +}; + + +#define XML_SCHEMA_ATTR_USE_FIXED 1<<0 +/** + * xmlSchemaAttributeUsePtr: + * + * The abstract base type for tree-like structured schema components. + * (Extends xmlSchemaTreeItem) + */ +typedef struct _xmlSchemaAttributeUse xmlSchemaAttributeUse; +typedef xmlSchemaAttributeUse *xmlSchemaAttributeUsePtr; +struct _xmlSchemaAttributeUse { + xmlSchemaTypeType type; + xmlSchemaAnnotPtr annot; + xmlSchemaAttributeUsePtr next; /* The next attr. use. */ + /* + * The attr. decl. OR a QName-ref. to an attr. decl. OR + * a QName-ref. to an attribute group definition. + */ + xmlSchemaAttributePtr attrDecl; + + int flags; + xmlNodePtr node; + int occurs; /* required, optional */ + const xmlChar * defValue; + xmlSchemaValPtr defVal; +}; + +/** + * xmlSchemaAttributeUseProhibPtr: + * + * A helper component to reflect attribute prohibitions. + * (Extends xmlSchemaBasicItem) + */ +typedef struct _xmlSchemaAttributeUseProhib xmlSchemaAttributeUseProhib; +typedef xmlSchemaAttributeUseProhib *xmlSchemaAttributeUseProhibPtr; +struct _xmlSchemaAttributeUseProhib { + xmlSchemaTypeType type; /* == XML_SCHEMA_EXTRA_ATTR_USE_PROHIB */ + xmlNodePtr node; + const xmlChar *name; + const xmlChar *targetNamespace; + int isRef; +}; + +/** + * xmlSchemaRedef: + */ +typedef struct _xmlSchemaRedef xmlSchemaRedef; +typedef xmlSchemaRedef *xmlSchemaRedefPtr; +struct _xmlSchemaRedef { + xmlSchemaRedefPtr next; + xmlSchemaBasicItemPtr item; /* The redefining component. */ + xmlSchemaBasicItemPtr reference; /* The referencing component. */ + xmlSchemaBasicItemPtr target; /* The to-be-redefined component. */ + const xmlChar *refName; /* The name of the to-be-redefined component. */ + const xmlChar *refTargetNs; /* The target namespace of the + to-be-redefined comp. */ + xmlSchemaBucketPtr targetBucket; /* The redefined schema. */ +}; + +/** + * xmlSchemaConstructionCtxt: + */ +typedef struct _xmlSchemaConstructionCtxt xmlSchemaConstructionCtxt; +typedef xmlSchemaConstructionCtxt *xmlSchemaConstructionCtxtPtr; +struct _xmlSchemaConstructionCtxt { + xmlSchemaPtr mainSchema; /* The main schema. */ + xmlSchemaBucketPtr mainBucket; /* The main schema bucket */ + xmlDictPtr dict; + xmlSchemaItemListPtr buckets; /* List of schema buckets. */ + /* xmlSchemaItemListPtr relations; */ /* List of schema relations. */ + xmlSchemaBucketPtr bucket; /* The current schema bucket */ + xmlSchemaItemListPtr pending; /* All Components of all schemas that + need to be fixed. */ + xmlHashTablePtr substGroups; + xmlSchemaRedefPtr redefs; + xmlSchemaRedefPtr lastRedef; +}; + +#define XML_SCHEMAS_PARSE_ERROR 1 +#define SCHEMAS_PARSE_OPTIONS XML_PARSE_NOENT + +struct _xmlSchemaParserCtxt { + int type; + void *errCtxt; /* user specific error context */ + xmlSchemaValidityErrorFunc error; /* the callback in case of errors */ + xmlSchemaValidityWarningFunc warning; /* the callback in case of warning */ + int err; + int nberrors; + xmlStructuredErrorFunc serror; + + xmlSchemaConstructionCtxtPtr constructor; + int ownsConstructor; /* TODO: Move this to parser *flags*. */ + + /* xmlSchemaPtr topschema; */ + /* xmlHashTablePtr namespaces; */ + + xmlSchemaPtr schema; /* The main schema in use */ + int counter; + + const xmlChar *URL; + xmlDocPtr doc; + int preserve; /* Whether the doc should be freed */ + + const char *buffer; + int size; + + /* + * Used to build complex element content models + */ + xmlAutomataPtr am; + xmlAutomataStatePtr start; + xmlAutomataStatePtr end; + xmlAutomataStatePtr state; + + xmlDictPtr dict; /* dictionnary for interned string names */ + xmlSchemaTypePtr ctxtType; /* The current context simple/complex type */ + int options; + xmlSchemaValidCtxtPtr vctxt; + int isS4S; + int isRedefine; + int xsiAssemble; + int stop; /* If the parser should stop; i.e. a critical error. */ + const xmlChar *targetNamespace; + xmlSchemaBucketPtr redefined; /* The schema to be redefined. */ + + xmlSchemaRedefPtr redef; /* Used for redefinitions. */ + int redefCounter; /* Used for redefinitions. */ + xmlSchemaItemListPtr attrProhibs; +}; + +/** + * xmlSchemaQNameRef: + * + * A component reference item (not a schema component) + * (Extends xmlSchemaBasicItem) + */ +typedef struct _xmlSchemaQNameRef xmlSchemaQNameRef; +typedef xmlSchemaQNameRef *xmlSchemaQNameRefPtr; +struct _xmlSchemaQNameRef { + xmlSchemaTypeType type; + xmlSchemaBasicItemPtr item; /* The resolved referenced item. */ + xmlSchemaTypeType itemType; + const xmlChar *name; + const xmlChar *targetNamespace; + xmlNodePtr node; +}; + +/** + * xmlSchemaParticle: + * + * A particle component. + * (Extends xmlSchemaTreeItem) + */ +typedef struct _xmlSchemaParticle xmlSchemaParticle; +typedef xmlSchemaParticle *xmlSchemaParticlePtr; +struct _xmlSchemaParticle { + xmlSchemaTypeType type; + xmlSchemaAnnotPtr annot; + xmlSchemaTreeItemPtr next; /* next particle */ + xmlSchemaTreeItemPtr children; /* the "term" (e.g. a model group, + a group definition, a XML_SCHEMA_EXTRA_QNAMEREF (if a reference), + etc.) */ + int minOccurs; + int maxOccurs; + xmlNodePtr node; +}; + +/** + * xmlSchemaModelGroup: + * + * A model group component. + * (Extends xmlSchemaTreeItem) + */ +typedef struct _xmlSchemaModelGroup xmlSchemaModelGroup; +typedef xmlSchemaModelGroup *xmlSchemaModelGroupPtr; +struct _xmlSchemaModelGroup { + xmlSchemaTypeType type; /* XML_SCHEMA_TYPE_SEQUENCE, XML_SCHEMA_TYPE_CHOICE, XML_SCHEMA_TYPE_ALL */ + xmlSchemaAnnotPtr annot; + xmlSchemaTreeItemPtr next; /* not used */ + xmlSchemaTreeItemPtr children; /* first particle (OR "element decl" OR "wildcard") */ + xmlNodePtr node; +}; + +#define XML_SCHEMA_MODEL_GROUP_DEF_MARKED 1<<0 +#define XML_SCHEMA_MODEL_GROUP_DEF_REDEFINED 1<<1 +/** + * xmlSchemaModelGroupDef: + * + * A model group definition component. + * (Extends xmlSchemaTreeItem) + */ +typedef struct _xmlSchemaModelGroupDef xmlSchemaModelGroupDef; +typedef xmlSchemaModelGroupDef *xmlSchemaModelGroupDefPtr; +struct _xmlSchemaModelGroupDef { + xmlSchemaTypeType type; /* XML_SCHEMA_TYPE_GROUP */ + xmlSchemaAnnotPtr annot; + xmlSchemaTreeItemPtr next; /* not used */ + xmlSchemaTreeItemPtr children; /* the "model group" */ + const xmlChar *name; + const xmlChar *targetNamespace; + xmlNodePtr node; + int flags; +}; + +typedef struct _xmlSchemaIDC xmlSchemaIDC; +typedef xmlSchemaIDC *xmlSchemaIDCPtr; + +/** + * xmlSchemaIDCSelect: + * + * The identity-constraint "field" and "selector" item, holding the + * XPath expression. + */ +typedef struct _xmlSchemaIDCSelect xmlSchemaIDCSelect; +typedef xmlSchemaIDCSelect *xmlSchemaIDCSelectPtr; +struct _xmlSchemaIDCSelect { + xmlSchemaIDCSelectPtr next; + xmlSchemaIDCPtr idc; + int index; /* an index position if significant for IDC key-sequences */ + const xmlChar *xpath; /* the XPath expression */ + void *xpathComp; /* the compiled XPath expression */ +}; + +/** + * xmlSchemaIDC: + * + * The identity-constraint definition component. + * (Extends xmlSchemaAnnotItem) + */ + +struct _xmlSchemaIDC { + xmlSchemaTypeType type; + xmlSchemaAnnotPtr annot; + xmlSchemaIDCPtr next; + xmlNodePtr node; + const xmlChar *name; + const xmlChar *targetNamespace; + xmlSchemaIDCSelectPtr selector; + xmlSchemaIDCSelectPtr fields; + int nbFields; + xmlSchemaQNameRefPtr ref; +}; + +/** + * xmlSchemaIDCAug: + * + * The augmented IDC information used for validation. + */ +typedef struct _xmlSchemaIDCAug xmlSchemaIDCAug; +typedef xmlSchemaIDCAug *xmlSchemaIDCAugPtr; +struct _xmlSchemaIDCAug { + xmlSchemaIDCAugPtr next; /* next in a list */ + xmlSchemaIDCPtr def; /* the IDC definition */ + int keyrefDepth; /* the lowest tree level to which IDC + tables need to be bubbled upwards */ +}; + +/** + * xmlSchemaPSVIIDCKeySequence: + * + * The key sequence of a node table item. + */ +typedef struct _xmlSchemaPSVIIDCKey xmlSchemaPSVIIDCKey; +typedef xmlSchemaPSVIIDCKey *xmlSchemaPSVIIDCKeyPtr; +struct _xmlSchemaPSVIIDCKey { + xmlSchemaTypePtr type; + xmlSchemaValPtr val; +}; + +/** + * xmlSchemaPSVIIDCNode: + * + * The node table item of a node table. + */ +typedef struct _xmlSchemaPSVIIDCNode xmlSchemaPSVIIDCNode; +typedef xmlSchemaPSVIIDCNode *xmlSchemaPSVIIDCNodePtr; +struct _xmlSchemaPSVIIDCNode { + xmlNodePtr node; + xmlSchemaPSVIIDCKeyPtr *keys; + int nodeLine; + int nodeQNameID; + +}; + +/** + * xmlSchemaPSVIIDCBinding: + * + * The identity-constraint binding item of the [identity-constraint table]. + */ +typedef struct _xmlSchemaPSVIIDCBinding xmlSchemaPSVIIDCBinding; +typedef xmlSchemaPSVIIDCBinding *xmlSchemaPSVIIDCBindingPtr; +struct _xmlSchemaPSVIIDCBinding { + xmlSchemaPSVIIDCBindingPtr next; /* next binding of a specific node */ + xmlSchemaIDCPtr definition; /* the IDC definition */ + xmlSchemaPSVIIDCNodePtr *nodeTable; /* array of key-sequences */ + int nbNodes; /* number of entries in the node table */ + int sizeNodes; /* size of the node table */ + xmlSchemaItemListPtr dupls; +}; + + +#define XPATH_STATE_OBJ_TYPE_IDC_SELECTOR 1 +#define XPATH_STATE_OBJ_TYPE_IDC_FIELD 2 + +#define XPATH_STATE_OBJ_MATCHES -2 +#define XPATH_STATE_OBJ_BLOCKED -3 + +typedef struct _xmlSchemaIDCMatcher xmlSchemaIDCMatcher; +typedef xmlSchemaIDCMatcher *xmlSchemaIDCMatcherPtr; + +/** + * xmlSchemaIDCStateObj: + * + * The state object used to evaluate XPath expressions. + */ +typedef struct _xmlSchemaIDCStateObj xmlSchemaIDCStateObj; +typedef xmlSchemaIDCStateObj *xmlSchemaIDCStateObjPtr; +struct _xmlSchemaIDCStateObj { + int type; + xmlSchemaIDCStateObjPtr next; /* next if in a list */ + int depth; /* depth of creation */ + int *history; /* list of (depth, state-id) tuples */ + int nbHistory; + int sizeHistory; + xmlSchemaIDCMatcherPtr matcher; /* the correspondent field/selector + matcher */ + xmlSchemaIDCSelectPtr sel; + void *xpathCtxt; +}; + +#define IDC_MATCHER 0 + +/** + * xmlSchemaIDCMatcher: + * + * Used to evaluate IDC selectors (and fields). + */ +struct _xmlSchemaIDCMatcher { + int type; + int depth; /* the tree depth at creation time */ + xmlSchemaIDCMatcherPtr next; /* next in the list */ + xmlSchemaIDCMatcherPtr nextCached; /* next in the cache list */ + xmlSchemaIDCAugPtr aidc; /* the augmented IDC item */ + int idcType; + xmlSchemaPSVIIDCKeyPtr **keySeqs; /* the key-sequences of the target + elements */ + int sizeKeySeqs; + xmlSchemaItemListPtr targets; /* list of target-node + (xmlSchemaPSVIIDCNodePtr) entries */ +}; + +/* +* Element info flags. +*/ +#define XML_SCHEMA_NODE_INFO_FLAG_OWNED_NAMES 1<<0 +#define XML_SCHEMA_NODE_INFO_FLAG_OWNED_VALUES 1<<1 +#define XML_SCHEMA_ELEM_INFO_NILLED 1<<2 +#define XML_SCHEMA_ELEM_INFO_LOCAL_TYPE 1<<3 + +#define XML_SCHEMA_NODE_INFO_VALUE_NEEDED 1<<4 +#define XML_SCHEMA_ELEM_INFO_EMPTY 1<<5 +#define XML_SCHEMA_ELEM_INFO_HAS_CONTENT 1<<6 + +#define XML_SCHEMA_ELEM_INFO_HAS_ELEM_CONTENT 1<<7 +#define XML_SCHEMA_ELEM_INFO_ERR_BAD_CONTENT 1<<8 +#define XML_SCHEMA_NODE_INFO_ERR_NOT_EXPECTED 1<<9 +#define XML_SCHEMA_NODE_INFO_ERR_BAD_TYPE 1<<10 + +/** + * xmlSchemaNodeInfo: + * + * Holds information of an element node. + */ +struct _xmlSchemaNodeInfo { + int nodeType; + xmlNodePtr node; + int nodeLine; + const xmlChar *localName; + const xmlChar *nsName; + const xmlChar *value; + xmlSchemaValPtr val; /* the pre-computed value if any */ + xmlSchemaTypePtr typeDef; /* the complex/simple type definition if any */ + + int flags; /* combination of node info flags */ + + int valNeeded; + int normVal; + + xmlSchemaElementPtr decl; /* the element/attribute declaration */ + int depth; + xmlSchemaPSVIIDCBindingPtr idcTable; /* the table of PSVI IDC bindings + for the scope element*/ + xmlSchemaIDCMatcherPtr idcMatchers; /* the IDC matchers for the scope + element */ + xmlRegExecCtxtPtr regexCtxt; + + const xmlChar **nsBindings; /* Namespace bindings on this element */ + int nbNsBindings; + int sizeNsBindings; + + int hasKeyrefs; + int appliedXPath; /* Indicates that an XPath has been applied. */ +}; + +#define XML_SCHEMAS_ATTR_UNKNOWN 1 +#define XML_SCHEMAS_ATTR_ASSESSED 2 +#define XML_SCHEMAS_ATTR_PROHIBITED 3 +#define XML_SCHEMAS_ATTR_ERR_MISSING 4 +#define XML_SCHEMAS_ATTR_INVALID_VALUE 5 +#define XML_SCHEMAS_ATTR_ERR_NO_TYPE 6 +#define XML_SCHEMAS_ATTR_ERR_FIXED_VALUE 7 +#define XML_SCHEMAS_ATTR_DEFAULT 8 +#define XML_SCHEMAS_ATTR_VALIDATE_VALUE 9 +#define XML_SCHEMAS_ATTR_ERR_WILD_STRICT_NO_DECL 10 +#define XML_SCHEMAS_ATTR_HAS_ATTR_USE 11 +#define XML_SCHEMAS_ATTR_HAS_ATTR_DECL 12 +#define XML_SCHEMAS_ATTR_WILD_SKIP 13 +#define XML_SCHEMAS_ATTR_WILD_LAX_NO_DECL 14 +#define XML_SCHEMAS_ATTR_ERR_WILD_DUPLICATE_ID 15 +#define XML_SCHEMAS_ATTR_ERR_WILD_AND_USE_ID 16 +#define XML_SCHEMAS_ATTR_META 17 +/* +* @metaType values of xmlSchemaAttrInfo. +*/ +#define XML_SCHEMA_ATTR_INFO_META_XSI_TYPE 1 +#define XML_SCHEMA_ATTR_INFO_META_XSI_NIL 2 +#define XML_SCHEMA_ATTR_INFO_META_XSI_SCHEMA_LOC 3 +#define XML_SCHEMA_ATTR_INFO_META_XSI_NO_NS_SCHEMA_LOC 4 +#define XML_SCHEMA_ATTR_INFO_META_XMLNS 5 + +typedef struct _xmlSchemaAttrInfo xmlSchemaAttrInfo; +typedef xmlSchemaAttrInfo *xmlSchemaAttrInfoPtr; +struct _xmlSchemaAttrInfo { + int nodeType; + xmlNodePtr node; + int nodeLine; + const xmlChar *localName; + const xmlChar *nsName; + const xmlChar *value; + xmlSchemaValPtr val; /* the pre-computed value if any */ + xmlSchemaTypePtr typeDef; /* the complex/simple type definition if any */ + int flags; /* combination of node info flags */ + + xmlSchemaAttributePtr decl; /* the attribute declaration */ + xmlSchemaAttributeUsePtr use; /* the attribute use */ + int state; + int metaType; + const xmlChar *vcValue; /* the value constraint value */ + xmlSchemaNodeInfoPtr parent; +}; + + +#define XML_SCHEMA_VALID_CTXT_FLAG_STREAM 1 +/** + * xmlSchemaValidCtxt: + * + * A Schemas validation context + */ +struct _xmlSchemaValidCtxt { + int type; + void *errCtxt; /* user specific data block */ + xmlSchemaValidityErrorFunc error; /* the callback in case of errors */ + xmlSchemaValidityWarningFunc warning; /* the callback in case of warning */ + xmlStructuredErrorFunc serror; + + xmlSchemaPtr schema; /* The schema in use */ + xmlDocPtr doc; + xmlParserInputBufferPtr input; + xmlCharEncoding enc; + xmlSAXHandlerPtr sax; + xmlParserCtxtPtr parserCtxt; + void *user_data; /* TODO: What is this for? */ + + int err; + int nberrors; + + xmlNodePtr node; + xmlNodePtr cur; + /* xmlSchemaTypePtr type; */ + + xmlRegExecCtxtPtr regexp; + xmlSchemaValPtr value; + + int valueWS; + int options; + xmlNodePtr validationRoot; + xmlSchemaParserCtxtPtr pctxt; + int xsiAssemble; + + int depth; + xmlSchemaNodeInfoPtr *elemInfos; /* array of element informations */ + int sizeElemInfos; + xmlSchemaNodeInfoPtr inode; /* the current element information */ + + xmlSchemaIDCAugPtr aidcs; /* a list of augmented IDC informations */ + + xmlSchemaIDCStateObjPtr xpathStates; /* first active state object. */ + xmlSchemaIDCStateObjPtr xpathStatePool; /* first stored state object. */ + xmlSchemaIDCMatcherPtr idcMatcherCache; /* Cache for IDC matcher objects. */ + + xmlSchemaPSVIIDCNodePtr *idcNodes; /* list of all IDC node-table entries*/ + int nbIdcNodes; + int sizeIdcNodes; + + xmlSchemaPSVIIDCKeyPtr *idcKeys; /* list of all IDC node-table entries */ + int nbIdcKeys; + int sizeIdcKeys; + + int flags; + + xmlDictPtr dict; + +#ifdef LIBXML_READER_ENABLED + xmlTextReaderPtr reader; +#endif + + xmlSchemaAttrInfoPtr *attrInfos; + int nbAttrInfos; + int sizeAttrInfos; + + int skipDepth; + xmlSchemaItemListPtr nodeQNames; + int hasKeyrefs; + int createIDCNodeTables; + int psviExposeIDCNodeTables; +}; + +/** + * xmlSchemaSubstGroup: + * + * + */ +typedef struct _xmlSchemaSubstGroup xmlSchemaSubstGroup; +typedef xmlSchemaSubstGroup *xmlSchemaSubstGroupPtr; +struct _xmlSchemaSubstGroup { + xmlSchemaElementPtr head; + xmlSchemaItemListPtr members; +}; + +/************************************************************************ + * * + * Some predeclarations * + * * + ************************************************************************/ + +static int xmlSchemaParseInclude(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaPtr schema, + xmlNodePtr node); +static int xmlSchemaParseRedefine(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaPtr schema, + xmlNodePtr node); +static int +xmlSchemaTypeFixup(xmlSchemaTypePtr type, + xmlSchemaAbstractCtxtPtr ctxt); +static const xmlChar * +xmlSchemaFacetTypeToString(xmlSchemaTypeType type); +static int +xmlSchemaParseImport(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, + xmlNodePtr node); +static int +xmlSchemaCheckFacetValues(xmlSchemaTypePtr typeDecl, + xmlSchemaParserCtxtPtr ctxt); +static void +xmlSchemaClearValidCtxt(xmlSchemaValidCtxtPtr vctxt); +static xmlSchemaWhitespaceValueType +xmlSchemaGetWhiteSpaceFacetValue(xmlSchemaTypePtr type); +static xmlSchemaTreeItemPtr +xmlSchemaParseModelGroup(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, + xmlNodePtr node, xmlSchemaTypeType type, + int withParticle); +static const xmlChar * +xmlSchemaGetComponentTypeStr(xmlSchemaBasicItemPtr item); +static xmlSchemaTypeLinkPtr +xmlSchemaGetUnionSimpleTypeMemberTypes(xmlSchemaTypePtr type); +static void +xmlSchemaInternalErr(xmlSchemaAbstractCtxtPtr actxt, + const char *funcName, + const char *message); +static int +xmlSchemaCheckCOSSTDerivedOK(xmlSchemaAbstractCtxtPtr ctxt, + xmlSchemaTypePtr type, + xmlSchemaTypePtr baseType, + int subset); +static void +xmlSchemaCheckElementDeclComponent(xmlSchemaElementPtr elemDecl, + xmlSchemaParserCtxtPtr ctxt); +static void +xmlSchemaComponentListFree(xmlSchemaItemListPtr list); +static xmlSchemaQNameRefPtr +xmlSchemaParseAttributeGroupRef(xmlSchemaParserCtxtPtr pctxt, + xmlSchemaPtr schema, + xmlNodePtr node); + +/************************************************************************ + * * + * Helper functions * + * * + ************************************************************************/ + +/** + * xmlSchemaItemTypeToStr: + * @type: the type of the schema item + * + * Returns the component name of a schema item. + */ +static const xmlChar * +xmlSchemaItemTypeToStr(xmlSchemaTypeType type) +{ + switch (type) { + case XML_SCHEMA_TYPE_BASIC: + return(BAD_CAST "simple type definition"); + case XML_SCHEMA_TYPE_SIMPLE: + return(BAD_CAST "simple type definition"); + case XML_SCHEMA_TYPE_COMPLEX: + return(BAD_CAST "complex type definition"); + case XML_SCHEMA_TYPE_ELEMENT: + return(BAD_CAST "element declaration"); + case XML_SCHEMA_TYPE_ATTRIBUTE_USE: + return(BAD_CAST "attribute use"); + case XML_SCHEMA_TYPE_ATTRIBUTE: + return(BAD_CAST "attribute declaration"); + case XML_SCHEMA_TYPE_GROUP: + return(BAD_CAST "model group definition"); + case XML_SCHEMA_TYPE_ATTRIBUTEGROUP: + return(BAD_CAST "attribute group definition"); + case XML_SCHEMA_TYPE_NOTATION: + return(BAD_CAST "notation declaration"); + case XML_SCHEMA_TYPE_SEQUENCE: + return(BAD_CAST "model group (sequence)"); + case XML_SCHEMA_TYPE_CHOICE: + return(BAD_CAST "model group (choice)"); + case XML_SCHEMA_TYPE_ALL: + return(BAD_CAST "model group (all)"); + case XML_SCHEMA_TYPE_PARTICLE: + return(BAD_CAST "particle"); + case XML_SCHEMA_TYPE_IDC_UNIQUE: + return(BAD_CAST "unique identity-constraint"); + /* return(BAD_CAST "IDC (unique)"); */ + case XML_SCHEMA_TYPE_IDC_KEY: + return(BAD_CAST "key identity-constraint"); + /* return(BAD_CAST "IDC (key)"); */ + case XML_SCHEMA_TYPE_IDC_KEYREF: + return(BAD_CAST "keyref identity-constraint"); + /* return(BAD_CAST "IDC (keyref)"); */ + case XML_SCHEMA_TYPE_ANY: + return(BAD_CAST "wildcard (any)"); + case XML_SCHEMA_EXTRA_QNAMEREF: + return(BAD_CAST "[helper component] QName reference"); + case XML_SCHEMA_EXTRA_ATTR_USE_PROHIB: + return(BAD_CAST "[helper component] attribute use prohibition"); + default: + return(BAD_CAST "Not a schema component"); + } +} + +/** + * xmlSchemaGetComponentTypeStr: + * @type: the type of the schema item + * + * Returns the component name of a schema item. + */ +static const xmlChar * +xmlSchemaGetComponentTypeStr(xmlSchemaBasicItemPtr item) +{ + switch (item->type) { + case XML_SCHEMA_TYPE_BASIC: + if (WXS_IS_COMPLEX(WXS_TYPE_CAST item)) + return(BAD_CAST "complex type definition"); + else + return(BAD_CAST "simple type definition"); + default: + return(xmlSchemaItemTypeToStr(item->type)); + } +} + +/** + * xmlSchemaGetComponentNode: + * @item: a schema component + * + * Returns node associated with the schema component. + * NOTE that such a node need not be available; plus, a component's + * node need not to reflect the component directly, since there is no + * one-to-one relationship between the XML Schema representation and + * the component representation. + */ +static xmlNodePtr +xmlSchemaGetComponentNode(xmlSchemaBasicItemPtr item) +{ + switch (item->type) { + case XML_SCHEMA_TYPE_ELEMENT: + return (((xmlSchemaElementPtr) item)->node); + case XML_SCHEMA_TYPE_ATTRIBUTE: + return (((xmlSchemaAttributePtr) item)->node); + case XML_SCHEMA_TYPE_COMPLEX: + case XML_SCHEMA_TYPE_SIMPLE: + return (((xmlSchemaTypePtr) item)->node); + case XML_SCHEMA_TYPE_ANY: + case XML_SCHEMA_TYPE_ANY_ATTRIBUTE: + return (((xmlSchemaWildcardPtr) item)->node); + case XML_SCHEMA_TYPE_PARTICLE: + return (((xmlSchemaParticlePtr) item)->node); + case XML_SCHEMA_TYPE_SEQUENCE: + case XML_SCHEMA_TYPE_CHOICE: + case XML_SCHEMA_TYPE_ALL: + return (((xmlSchemaModelGroupPtr) item)->node); + case XML_SCHEMA_TYPE_GROUP: + return (((xmlSchemaModelGroupDefPtr) item)->node); + case XML_SCHEMA_TYPE_ATTRIBUTEGROUP: + return (((xmlSchemaAttributeGroupPtr) item)->node); + case XML_SCHEMA_TYPE_IDC_UNIQUE: + case XML_SCHEMA_TYPE_IDC_KEY: + case XML_SCHEMA_TYPE_IDC_KEYREF: + return (((xmlSchemaIDCPtr) item)->node); + case XML_SCHEMA_EXTRA_QNAMEREF: + return(((xmlSchemaQNameRefPtr) item)->node); + /* TODO: What to do with NOTATIONs? + case XML_SCHEMA_TYPE_NOTATION: + return (((xmlSchemaNotationPtr) item)->node); + */ + case XML_SCHEMA_TYPE_ATTRIBUTE_USE: + return (((xmlSchemaAttributeUsePtr) item)->node); + default: + return (NULL); + } +} + +#if 0 +/** + * xmlSchemaGetNextComponent: + * @item: a schema component + * + * Returns the next sibling of the schema component. + */ +static xmlSchemaBasicItemPtr +xmlSchemaGetNextComponent(xmlSchemaBasicItemPtr item) +{ + switch (item->type) { + case XML_SCHEMA_TYPE_ELEMENT: + return ((xmlSchemaBasicItemPtr) ((xmlSchemaElementPtr) item)->next); + case XML_SCHEMA_TYPE_ATTRIBUTE: + return ((xmlSchemaBasicItemPtr) ((xmlSchemaAttributePtr) item)->next); + case XML_SCHEMA_TYPE_COMPLEX: + case XML_SCHEMA_TYPE_SIMPLE: + return ((xmlSchemaBasicItemPtr) ((xmlSchemaTypePtr) item)->next); + case XML_SCHEMA_TYPE_ANY: + case XML_SCHEMA_TYPE_ANY_ATTRIBUTE: + return (NULL); + case XML_SCHEMA_TYPE_PARTICLE: + return ((xmlSchemaBasicItemPtr) ((xmlSchemaParticlePtr) item)->next); + case XML_SCHEMA_TYPE_SEQUENCE: + case XML_SCHEMA_TYPE_CHOICE: + case XML_SCHEMA_TYPE_ALL: + return (NULL); + case XML_SCHEMA_TYPE_GROUP: + return (NULL); + case XML_SCHEMA_TYPE_ATTRIBUTEGROUP: + return ((xmlSchemaBasicItemPtr) ((xmlSchemaAttributeGroupPtr) item)->next); + case XML_SCHEMA_TYPE_IDC_UNIQUE: + case XML_SCHEMA_TYPE_IDC_KEY: + case XML_SCHEMA_TYPE_IDC_KEYREF: + return ((xmlSchemaBasicItemPtr) ((xmlSchemaIDCPtr) item)->next); + default: + return (NULL); + } +} +#endif + + +/** + * xmlSchemaFormatQName: + * @buf: the string buffer + * @namespaceName: the namespace name + * @localName: the local name + * + * Returns the given QName in the format "{namespaceName}localName" or + * just "localName" if @namespaceName is NULL. + * + * Returns the localName if @namespaceName is NULL, a formatted + * string otherwise. + */ +static const xmlChar* +xmlSchemaFormatQName(xmlChar **buf, + const xmlChar *namespaceName, + const xmlChar *localName) +{ + FREE_AND_NULL(*buf) + if (namespaceName != NULL) { + *buf = xmlStrdup(BAD_CAST "{"); + *buf = xmlStrcat(*buf, namespaceName); + *buf = xmlStrcat(*buf, BAD_CAST "}"); + } + if (localName != NULL) { + if (namespaceName == NULL) + return(localName); + *buf = xmlStrcat(*buf, localName); + } else { + *buf = xmlStrcat(*buf, BAD_CAST "(NULL)"); + } + return ((const xmlChar *) *buf); +} + +static const xmlChar* +xmlSchemaFormatQNameNs(xmlChar **buf, xmlNsPtr ns, const xmlChar *localName) +{ + if (ns != NULL) + return (xmlSchemaFormatQName(buf, ns->href, localName)); + else + return (xmlSchemaFormatQName(buf, NULL, localName)); +} + +static const xmlChar * +xmlSchemaGetComponentName(xmlSchemaBasicItemPtr item) +{ + switch (item->type) { + case XML_SCHEMA_TYPE_ELEMENT: + return (((xmlSchemaElementPtr) item)->name); + case XML_SCHEMA_TYPE_ATTRIBUTE: + return (((xmlSchemaAttributePtr) item)->name); + case XML_SCHEMA_TYPE_ATTRIBUTEGROUP: + return (((xmlSchemaAttributeGroupPtr) item)->name); + case XML_SCHEMA_TYPE_BASIC: + case XML_SCHEMA_TYPE_SIMPLE: + case XML_SCHEMA_TYPE_COMPLEX: + return (((xmlSchemaTypePtr) item)->name); + case XML_SCHEMA_TYPE_GROUP: + return (((xmlSchemaModelGroupDefPtr) item)->name); + case XML_SCHEMA_TYPE_IDC_KEY: + case XML_SCHEMA_TYPE_IDC_UNIQUE: + case XML_SCHEMA_TYPE_IDC_KEYREF: + return (((xmlSchemaIDCPtr) item)->name); + case XML_SCHEMA_TYPE_ATTRIBUTE_USE: + if (WXS_ATTRUSE_DECL(item) != NULL) { + return(xmlSchemaGetComponentName( + WXS_BASIC_CAST WXS_ATTRUSE_DECL(item))); + } else + return(NULL); + case XML_SCHEMA_EXTRA_QNAMEREF: + return (((xmlSchemaQNameRefPtr) item)->name); + case XML_SCHEMA_TYPE_NOTATION: + return (((xmlSchemaNotationPtr) item)->name); + default: + /* + * Other components cannot have names. + */ + break; + } + return (NULL); +} + +#define xmlSchemaGetQNameRefName(r) (WXS_QNAME_CAST (r))->name +#define xmlSchemaGetQNameRefTargetNs(r) (WXS_QNAME_CAST (r))->targetNamespace +/* +static const xmlChar * +xmlSchemaGetQNameRefName(void *ref) +{ + return(((xmlSchemaQNameRefPtr) ref)->name); +} + +static const xmlChar * +xmlSchemaGetQNameRefTargetNs(void *ref) +{ + return(((xmlSchemaQNameRefPtr) ref)->targetNamespace); +} +*/ + +static const xmlChar * +xmlSchemaGetComponentTargetNs(xmlSchemaBasicItemPtr item) +{ + switch (item->type) { + case XML_SCHEMA_TYPE_ELEMENT: + return (((xmlSchemaElementPtr) item)->targetNamespace); + case XML_SCHEMA_TYPE_ATTRIBUTE: + return (((xmlSchemaAttributePtr) item)->targetNamespace); + case XML_SCHEMA_TYPE_ATTRIBUTEGROUP: + return (((xmlSchemaAttributeGroupPtr) item)->targetNamespace); + case XML_SCHEMA_TYPE_BASIC: + return (BAD_CAST "http://www.w3.org/2001/XMLSchema"); + case XML_SCHEMA_TYPE_SIMPLE: + case XML_SCHEMA_TYPE_COMPLEX: + return (((xmlSchemaTypePtr) item)->targetNamespace); + case XML_SCHEMA_TYPE_GROUP: + return (((xmlSchemaModelGroupDefPtr) item)->targetNamespace); + case XML_SCHEMA_TYPE_IDC_KEY: + case XML_SCHEMA_TYPE_IDC_UNIQUE: + case XML_SCHEMA_TYPE_IDC_KEYREF: + return (((xmlSchemaIDCPtr) item)->targetNamespace); + case XML_SCHEMA_TYPE_ATTRIBUTE_USE: + if (WXS_ATTRUSE_DECL(item) != NULL) { + return(xmlSchemaGetComponentTargetNs( + WXS_BASIC_CAST WXS_ATTRUSE_DECL(item))); + } + /* TODO: Will returning NULL break something? */ + break; + case XML_SCHEMA_EXTRA_QNAMEREF: + return (((xmlSchemaQNameRefPtr) item)->targetNamespace); + case XML_SCHEMA_TYPE_NOTATION: + return (((xmlSchemaNotationPtr) item)->targetNamespace); + default: + /* + * Other components cannot have names. + */ + break; + } + return (NULL); +} + +static const xmlChar* +xmlSchemaGetComponentQName(xmlChar **buf, + void *item) +{ + return (xmlSchemaFormatQName(buf, + xmlSchemaGetComponentTargetNs((xmlSchemaBasicItemPtr) item), + xmlSchemaGetComponentName((xmlSchemaBasicItemPtr) item))); +} + +static const xmlChar* +xmlSchemaGetComponentDesignation(xmlChar **buf, void *item) +{ + xmlChar *str = NULL; + + *buf = xmlStrcat(*buf, WXS_ITEM_TYPE_NAME(item)); + *buf = xmlStrcat(*buf, BAD_CAST " '"); + *buf = xmlStrcat(*buf, xmlSchemaGetComponentQName(&str, + (xmlSchemaBasicItemPtr) item)); + *buf = xmlStrcat(*buf, BAD_CAST "'"); + FREE_AND_NULL(str); + return(*buf); +} + +static const xmlChar* +xmlSchemaGetIDCDesignation(xmlChar **buf, xmlSchemaIDCPtr idc) +{ + return(xmlSchemaGetComponentDesignation(buf, idc)); +} + +/** + * xmlSchemaWildcardPCToString: + * @pc: the type of processContents + * + * Returns a string representation of the type of + * processContents. + */ +static const xmlChar * +xmlSchemaWildcardPCToString(int pc) +{ + switch (pc) { + case XML_SCHEMAS_ANY_SKIP: + return (BAD_CAST "skip"); + case XML_SCHEMAS_ANY_LAX: + return (BAD_CAST "lax"); + case XML_SCHEMAS_ANY_STRICT: + return (BAD_CAST "strict"); + default: + return (BAD_CAST "invalid process contents"); + } +} + +/** + * xmlSchemaGetCanonValueWhtspExt: + * @val: the precomputed value + * @retValue: the returned value + * @ws: the whitespace type of the value + * + * Get a the cononical representation of the value. + * The caller has to free the returned retValue. + * + * Returns 0 if the value could be built and -1 in case of + * API errors or if the value type is not supported yet. + */ +static int +xmlSchemaGetCanonValueWhtspExt(xmlSchemaValPtr val, + xmlSchemaWhitespaceValueType ws, + xmlChar **retValue) +{ + int list; + xmlSchemaValType valType; + const xmlChar *value, *value2 = NULL; + + + if ((retValue == NULL) || (val == NULL)) + return (-1); + list = xmlSchemaValueGetNext(val) ? 1 : 0; + *retValue = NULL; + do { + value = NULL; + valType = xmlSchemaGetValType(val); + switch (valType) { + case XML_SCHEMAS_STRING: + case XML_SCHEMAS_NORMSTRING: + case XML_SCHEMAS_ANYSIMPLETYPE: + value = xmlSchemaValueGetAsString(val); + if (value != NULL) { + if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE) + value2 = xmlSchemaCollapseString(value); + else if (ws == XML_SCHEMA_WHITESPACE_REPLACE) + value2 = xmlSchemaWhiteSpaceReplace(value); + if (value2 != NULL) + value = value2; + } + break; + default: + if (xmlSchemaGetCanonValue(val, &value2) == -1) { + if (value2 != NULL) + xmlFree((xmlChar *) value2); + goto internal_error; + } + value = value2; + } + if (*retValue == NULL) + if (value == NULL) { + if (! list) + *retValue = xmlStrdup(BAD_CAST ""); + } else + *retValue = xmlStrdup(value); + else if (value != NULL) { + /* List. */ + *retValue = xmlStrcat((xmlChar *) *retValue, BAD_CAST " "); + *retValue = xmlStrcat((xmlChar *) *retValue, value); + } + FREE_AND_NULL(value2) + val = xmlSchemaValueGetNext(val); + } while (val != NULL); + + return (0); +internal_error: + if (*retValue != NULL) + xmlFree((xmlChar *) (*retValue)); + if (value2 != NULL) + xmlFree((xmlChar *) value2); + return (-1); +} + +/** + * xmlSchemaFormatItemForReport: + * @buf: the string buffer + * @itemDes: the designation of the item + * @itemName: the name of the item + * @item: the item as an object + * @itemNode: the node of the item + * @local: the local name + * @parsing: if the function is used during the parse + * + * Returns a representation of the given item used + * for error reports. + * + * The following order is used to build the resulting + * designation if the arguments are not NULL: + * 1a. If itemDes not NULL -> itemDes + * 1b. If (itemDes not NULL) and (itemName not NULL) + * -> itemDes + itemName + * 2. If the preceding was NULL and (item not NULL) -> item + * 3. If the preceding was NULL and (itemNode not NULL) -> itemNode + * + * If the itemNode is an attribute node, the name of the attribute + * will be appended to the result. + * + * Returns the formatted string and sets @buf to the resulting value. + */ +static xmlChar* +xmlSchemaFormatItemForReport(xmlChar **buf, + const xmlChar *itemDes, + xmlSchemaBasicItemPtr item, + xmlNodePtr itemNode) +{ + xmlChar *str = NULL; + int named = 1; + + if (*buf != NULL) { + xmlFree(*buf); + *buf = NULL; + } + + if (itemDes != NULL) { + *buf = xmlStrdup(itemDes); + } else if (item != NULL) { + switch (item->type) { + case XML_SCHEMA_TYPE_BASIC: { + xmlSchemaTypePtr type = WXS_TYPE_CAST item; + + if (WXS_IS_ATOMIC(type)) + *buf = xmlStrdup(BAD_CAST "atomic type 'xs:"); + else if (WXS_IS_LIST(type)) + *buf = xmlStrdup(BAD_CAST "list type 'xs:"); + else if (WXS_IS_UNION(type)) + *buf = xmlStrdup(BAD_CAST "union type 'xs:"); + else + *buf = xmlStrdup(BAD_CAST "simple type 'xs:"); + *buf = xmlStrcat(*buf, type->name); + *buf = xmlStrcat(*buf, BAD_CAST "'"); + } + break; + case XML_SCHEMA_TYPE_SIMPLE: { + xmlSchemaTypePtr type = WXS_TYPE_CAST item; + + if (type->flags & XML_SCHEMAS_TYPE_GLOBAL) { + *buf = xmlStrdup(BAD_CAST""); + } else { + *buf = xmlStrdup(BAD_CAST "local "); + } + if (WXS_IS_ATOMIC(type)) + *buf = xmlStrcat(*buf, BAD_CAST "atomic type"); + else if (WXS_IS_LIST(type)) + *buf = xmlStrcat(*buf, BAD_CAST "list type"); + else if (WXS_IS_UNION(type)) + *buf = xmlStrcat(*buf, BAD_CAST "union type"); + else + *buf = xmlStrcat(*buf, BAD_CAST "simple type"); + if (type->flags & XML_SCHEMAS_TYPE_GLOBAL) { + *buf = xmlStrcat(*buf, BAD_CAST " '"); + *buf = xmlStrcat(*buf, type->name); + *buf = xmlStrcat(*buf, BAD_CAST "'"); + } + } + break; + case XML_SCHEMA_TYPE_COMPLEX: { + xmlSchemaTypePtr type = WXS_TYPE_CAST item; + + if (type->flags & XML_SCHEMAS_TYPE_GLOBAL) + *buf = xmlStrdup(BAD_CAST ""); + else + *buf = xmlStrdup(BAD_CAST "local "); + *buf = xmlStrcat(*buf, BAD_CAST "complex type"); + if (type->flags & XML_SCHEMAS_TYPE_GLOBAL) { + *buf = xmlStrcat(*buf, BAD_CAST " '"); + *buf = xmlStrcat(*buf, type->name); + *buf = xmlStrcat(*buf, BAD_CAST "'"); + } + } + break; + case XML_SCHEMA_TYPE_ATTRIBUTE_USE: { + xmlSchemaAttributeUsePtr ause; + + ause = WXS_ATTR_USE_CAST item; + *buf = xmlStrdup(BAD_CAST "attribute use "); + if (WXS_ATTRUSE_DECL(ause) != NULL) { + *buf = xmlStrcat(*buf, BAD_CAST "'"); + *buf = xmlStrcat(*buf, + xmlSchemaGetComponentQName(&str, WXS_ATTRUSE_DECL(ause))); + FREE_AND_NULL(str) + *buf = xmlStrcat(*buf, BAD_CAST "'"); + } else { + *buf = xmlStrcat(*buf, BAD_CAST "(unknown)"); + } + } + break; + case XML_SCHEMA_TYPE_ATTRIBUTE: { + xmlSchemaAttributePtr attr; + + attr = (xmlSchemaAttributePtr) item; + *buf = xmlStrdup(BAD_CAST "attribute decl."); + *buf = xmlStrcat(*buf, BAD_CAST " '"); + *buf = xmlStrcat(*buf, xmlSchemaFormatQName(&str, + attr->targetNamespace, attr->name)); + FREE_AND_NULL(str) + *buf = xmlStrcat(*buf, BAD_CAST "'"); + } + break; + case XML_SCHEMA_TYPE_ATTRIBUTEGROUP: + xmlSchemaGetComponentDesignation(buf, item); + break; + case XML_SCHEMA_TYPE_ELEMENT: { + xmlSchemaElementPtr elem; + + elem = (xmlSchemaElementPtr) item; + *buf = xmlStrdup(BAD_CAST "element decl."); + *buf = xmlStrcat(*buf, BAD_CAST " '"); + *buf = xmlStrcat(*buf, xmlSchemaFormatQName(&str, + elem->targetNamespace, elem->name)); + *buf = xmlStrcat(*buf, BAD_CAST "'"); + } + break; + case XML_SCHEMA_TYPE_IDC_UNIQUE: + case XML_SCHEMA_TYPE_IDC_KEY: + case XML_SCHEMA_TYPE_IDC_KEYREF: + if (item->type == XML_SCHEMA_TYPE_IDC_UNIQUE) + *buf = xmlStrdup(BAD_CAST "unique '"); + else if (item->type == XML_SCHEMA_TYPE_IDC_KEY) + *buf = xmlStrdup(BAD_CAST "key '"); + else + *buf = xmlStrdup(BAD_CAST "keyRef '"); + *buf = xmlStrcat(*buf, ((xmlSchemaIDCPtr) item)->name); + *buf = xmlStrcat(*buf, BAD_CAST "'"); + break; + case XML_SCHEMA_TYPE_ANY: + case XML_SCHEMA_TYPE_ANY_ATTRIBUTE: + *buf = xmlStrdup(xmlSchemaWildcardPCToString( + ((xmlSchemaWildcardPtr) item)->processContents)); + *buf = xmlStrcat(*buf, BAD_CAST " wildcard"); + break; + case XML_SCHEMA_FACET_MININCLUSIVE: + case XML_SCHEMA_FACET_MINEXCLUSIVE: + case XML_SCHEMA_FACET_MAXINCLUSIVE: + case XML_SCHEMA_FACET_MAXEXCLUSIVE: + case XML_SCHEMA_FACET_TOTALDIGITS: + case XML_SCHEMA_FACET_FRACTIONDIGITS: + case XML_SCHEMA_FACET_PATTERN: + case XML_SCHEMA_FACET_ENUMERATION: + case XML_SCHEMA_FACET_WHITESPACE: + case XML_SCHEMA_FACET_LENGTH: + case XML_SCHEMA_FACET_MAXLENGTH: + case XML_SCHEMA_FACET_MINLENGTH: + *buf = xmlStrdup(BAD_CAST "facet '"); + *buf = xmlStrcat(*buf, xmlSchemaFacetTypeToString(item->type)); + *buf = xmlStrcat(*buf, BAD_CAST "'"); + break; + case XML_SCHEMA_TYPE_GROUP: { + *buf = xmlStrdup(BAD_CAST "model group def."); + *buf = xmlStrcat(*buf, BAD_CAST " '"); + *buf = xmlStrcat(*buf, xmlSchemaGetComponentQName(&str, item)); + *buf = xmlStrcat(*buf, BAD_CAST "'"); + FREE_AND_NULL(str) + } + break; + case XML_SCHEMA_TYPE_SEQUENCE: + case XML_SCHEMA_TYPE_CHOICE: + case XML_SCHEMA_TYPE_ALL: + case XML_SCHEMA_TYPE_PARTICLE: + *buf = xmlStrdup(WXS_ITEM_TYPE_NAME(item)); + break; + case XML_SCHEMA_TYPE_NOTATION: { + *buf = xmlStrdup(WXS_ITEM_TYPE_NAME(item)); + *buf = xmlStrcat(*buf, BAD_CAST " '"); + *buf = xmlStrcat(*buf, xmlSchemaGetComponentQName(&str, item)); + *buf = xmlStrcat(*buf, BAD_CAST "'"); + FREE_AND_NULL(str); + } + default: + named = 0; + } + } else + named = 0; + + if ((named == 0) && (itemNode != NULL)) { + xmlNodePtr elem; + + if (itemNode->type == XML_ATTRIBUTE_NODE) + elem = itemNode->parent; + else + elem = itemNode; + *buf = xmlStrdup(BAD_CAST "Element '"); + if (elem->ns != NULL) { + *buf = xmlStrcat(*buf, + xmlSchemaFormatQName(&str, elem->ns->href, elem->name)); + FREE_AND_NULL(str) + } else + *buf = xmlStrcat(*buf, elem->name); + *buf = xmlStrcat(*buf, BAD_CAST "'"); + + } + if ((itemNode != NULL) && (itemNode->type == XML_ATTRIBUTE_NODE)) { + *buf = xmlStrcat(*buf, BAD_CAST ", attribute '"); + if (itemNode->ns != NULL) { + *buf = xmlStrcat(*buf, xmlSchemaFormatQName(&str, + itemNode->ns->href, itemNode->name)); + FREE_AND_NULL(str) + } else + *buf = xmlStrcat(*buf, itemNode->name); + *buf = xmlStrcat(*buf, BAD_CAST "'"); + } + FREE_AND_NULL(str) + + return (*buf); +} + +/** + * xmlSchemaFormatFacetEnumSet: + * @buf: the string buffer + * @type: the type holding the enumeration facets + * + * Builds a string consisting of all enumeration elements. + * + * Returns a string of all enumeration elements. + */ +static const xmlChar * +xmlSchemaFormatFacetEnumSet(xmlSchemaAbstractCtxtPtr actxt, + xmlChar **buf, xmlSchemaTypePtr type) +{ + xmlSchemaFacetPtr facet; + xmlSchemaWhitespaceValueType ws; + xmlChar *value = NULL; + int res, found = 0; + + if (*buf != NULL) + xmlFree(*buf); + *buf = NULL; + + do { + /* + * Use the whitespace type of the base type. + */ + ws = xmlSchemaGetWhiteSpaceFacetValue(type->baseType); + for (facet = type->facets; facet != NULL; facet = facet->next) { + if (facet->type != XML_SCHEMA_FACET_ENUMERATION) + continue; + found = 1; + res = xmlSchemaGetCanonValueWhtspExt(facet->val, + ws, &value); + if (res == -1) { + xmlSchemaInternalErr(actxt, + "xmlSchemaFormatFacetEnumSet", + "compute the canonical lexical representation"); + if (*buf != NULL) + xmlFree(*buf); + *buf = NULL; + return (NULL); + } + if (*buf == NULL) + *buf = xmlStrdup(BAD_CAST "'"); + else + *buf = xmlStrcat(*buf, BAD_CAST ", '"); + *buf = xmlStrcat(*buf, BAD_CAST value); + *buf = xmlStrcat(*buf, BAD_CAST "'"); + if (value != NULL) { + xmlFree((xmlChar *)value); + value = NULL; + } + } + /* + * The enumeration facet of a type restricts the enumeration + * facet of the ancestor type; i.e., such restricted enumerations + * do not belong to the set of the given type. Thus we break + * on the first found enumeration. + */ + if (found) + break; + type = type->baseType; + } while ((type != NULL) && (type->type != XML_SCHEMA_TYPE_BASIC)); + + return ((const xmlChar *) *buf); +} + +/************************************************************************ + * * + * Error functions * + * * + ************************************************************************/ + +#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 + * @extra: extra informations + * + * Handle an out of memory condition + */ +static void +xmlSchemaPErrMemory(xmlSchemaParserCtxtPtr ctxt, + const char *extra, xmlNodePtr node) +{ + if (ctxt != NULL) + ctxt->nberrors++; + __xmlSimpleError(XML_FROM_SCHEMASP, XML_ERR_NO_MEMORY, node, NULL, + extra); +} + +/** + * xmlSchemaPErr: + * @ctxt: the parsing context + * @node: the context node + * @error: the error code + * @msg: the error message + * @str1: extra data + * @str2: extra data + * + * Handle a parser error + */ +static void +xmlSchemaPErr(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node, int error, + 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); +} + +/** + * xmlSchemaPErr2: + * @ctxt: the parsing context + * @node: the context node + * @node: the current child + * @error: the error code + * @msg: the error message + * @str1: extra data + * @str2: extra data + * + * Handle a parser error + */ +static void +xmlSchemaPErr2(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node, + xmlNodePtr child, int error, + const char *msg, const xmlChar * str1, const xmlChar * str2) +{ + if (child != NULL) + xmlSchemaPErr(ctxt, child, error, msg, str1, str2); + else + xmlSchemaPErr(ctxt, node, error, msg, str1, str2); +} + + +/** + * xmlSchemaPErrExt: + * @ctxt: the parsing context + * @node: the context node + * @error: the error code + * @strData1: extra data + * @strData2: extra data + * @strData3: extra data + * @msg: the message + * @str1: extra parameter for the message display + * @str2: extra parameter for the message display + * @str3: extra parameter for the message display + * @str4: extra parameter for the message display + * @str5: extra parameter for the message display + * + * Handle a parser error + */ +static void +xmlSchemaPErrExt(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node, int error, + 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); +} + +/************************************************************************ + * * + * Allround error functions * + * * + ************************************************************************/ + +/** + * xmlSchemaVTypeErrMemory: + * @node: a context node + * @extra: extra informations + * + * Handle an out of memory condition + */ +static void +xmlSchemaVErrMemory(xmlSchemaValidCtxtPtr ctxt, + const char *extra, xmlNodePtr node) +{ + if (ctxt != NULL) { + ctxt->nberrors++; + ctxt->err = XML_SCHEMAV_INTERNAL; + } + __xmlSimpleError(XML_FROM_SCHEMASV, XML_ERR_NO_MEMORY, node, NULL, + extra); +} + +static void +xmlSchemaPSimpleInternalErr(xmlNodePtr node, + const char *msg, const xmlChar *str) +{ + __xmlSimpleError(XML_FROM_SCHEMASP, XML_SCHEMAP_INTERNAL, node, + msg, (const char *) str); +} + +#define WXS_ERROR_TYPE_ERROR 1 +#define WXS_ERROR_TYPE_WARNING 2 +/** + * xmlSchemaErr3: + * @ctxt: the validation context + * @node: the context node + * @error: the error code + * @msg: the error message + * @str1: extra data + * @str2: extra data + * @str3: extra data + * + * Handle a validation error + */ +static void +xmlSchemaErr4Line(xmlSchemaAbstractCtxtPtr ctxt, + xmlErrorLevel errorLevel, + int error, 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; + 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 + * do not channel any node to the error function. + */ + if (line == 0) { + if ((node == NULL) && + (vctxt->depth >= 0) && + (vctxt->inode != NULL)) { + node = vctxt->inode->node; + } + /* + * Get filename and line if no node-tree. + */ + if ((node == NULL) && + (vctxt->parserCtxt != NULL) && + (vctxt->parserCtxt->input != NULL)) { + file = vctxt->parserCtxt->input->filename; + line = vctxt->parserCtxt->input->line; + } + } else { + /* + * Override the given node's (if any) position + * and channel only the given line number. + */ + node = NULL; + /* + * Get filename. + */ + if (vctxt->doc != NULL) + file = (const char *) vctxt->doc->URL; + else if ((vctxt->parserCtxt != NULL) && + (vctxt->parserCtxt->input != NULL)) + file = vctxt->parserCtxt->input->filename; + } + __xmlRaiseError(schannel, channel, data, ctxt, + node, XML_FROM_SCHEMASV, + error, errorLevel, file, line, + (const char *) str1, (const char *) str2, + (const char *) str3, 0, 0, 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 + } + } +} + +/** + * xmlSchemaErr3: + * @ctxt: the validation context + * @node: the context node + * @error: the error code + * @msg: the error message + * @str1: extra data + * @str2: extra data + * @str3: extra data + * + * Handle a validation error + */ +static void +xmlSchemaErr3(xmlSchemaAbstractCtxtPtr actxt, + int error, xmlNodePtr node, const char *msg, + const xmlChar *str1, const xmlChar *str2, const xmlChar *str3) +{ + xmlSchemaErr4Line(actxt, XML_ERR_ERROR, error, node, 0, + msg, str1, str2, str3, NULL); +} + +static void +xmlSchemaErr4(xmlSchemaAbstractCtxtPtr actxt, + int error, xmlNodePtr node, const char *msg, + const xmlChar *str1, const xmlChar *str2, + const xmlChar *str3, const xmlChar *str4) +{ + xmlSchemaErr4Line(actxt, XML_ERR_ERROR, error, node, 0, + msg, str1, str2, str3, str4); +} + +static void +xmlSchemaErr(xmlSchemaAbstractCtxtPtr actxt, + int error, xmlNodePtr node, const char *msg, + const xmlChar *str1, const xmlChar *str2) +{ + xmlSchemaErr4(actxt, error, node, msg, str1, str2, NULL, NULL); +} + +static xmlChar * +xmlSchemaFormatNodeForError(xmlChar ** msg, + xmlSchemaAbstractCtxtPtr actxt, + xmlNodePtr node) +{ + xmlChar *str = NULL; + + *msg = NULL; + if ((node != NULL) && + (node->type != XML_ELEMENT_NODE) && + (node->type != XML_ATTRIBUTE_NODE)) + { + /* + * Don't try to format other nodes than element and + * attribute nodes. + * Play save and return an empty string. + */ + *msg = xmlStrdup(BAD_CAST ""); + return(*msg); + } + if (node != NULL) { + /* + * Work on tree nodes. + */ + if (node->type == XML_ATTRIBUTE_NODE) { + xmlNodePtr elem = node->parent; + + *msg = xmlStrdup(BAD_CAST "Element '"); + if (elem->ns != NULL) + *msg = xmlStrcat(*msg, xmlSchemaFormatQName(&str, + elem->ns->href, elem->name)); + else + *msg = xmlStrcat(*msg, xmlSchemaFormatQName(&str, + NULL, elem->name)); + FREE_AND_NULL(str); + *msg = xmlStrcat(*msg, BAD_CAST "', "); + *msg = xmlStrcat(*msg, BAD_CAST "attribute '"); + } else { + *msg = xmlStrdup(BAD_CAST "Element '"); + } + if (node->ns != NULL) + *msg = xmlStrcat(*msg, xmlSchemaFormatQName(&str, + node->ns->href, node->name)); + else + *msg = xmlStrcat(*msg, xmlSchemaFormatQName(&str, + NULL, node->name)); + FREE_AND_NULL(str); + *msg = xmlStrcat(*msg, BAD_CAST "': "); + } else if (actxt->type == XML_SCHEMA_CTXT_VALIDATOR) { + xmlSchemaValidCtxtPtr vctxt = (xmlSchemaValidCtxtPtr) actxt; + /* + * Work on node infos. + */ + if (vctxt->inode->nodeType == XML_ATTRIBUTE_NODE) { + xmlSchemaNodeInfoPtr ielem = + vctxt->elemInfos[vctxt->depth]; + + *msg = xmlStrdup(BAD_CAST "Element '"); + *msg = xmlStrcat(*msg, xmlSchemaFormatQName(&str, + ielem->nsName, ielem->localName)); + FREE_AND_NULL(str); + *msg = xmlStrcat(*msg, BAD_CAST "', "); + *msg = xmlStrcat(*msg, BAD_CAST "attribute '"); + } else { + *msg = xmlStrdup(BAD_CAST "Element '"); + } + *msg = xmlStrcat(*msg, xmlSchemaFormatQName(&str, + vctxt->inode->nsName, vctxt->inode->localName)); + FREE_AND_NULL(str); + *msg = xmlStrcat(*msg, BAD_CAST "': "); + } else if (actxt->type == XML_SCHEMA_CTXT_PARSER) { + /* + * Hmm, no node while parsing? + * Return an empty string, in case NULL will break something. + */ + *msg = xmlStrdup(BAD_CAST ""); + } else { + TODO + return (NULL); + } + /* + * VAL TODO: The output of the given schema component is currently + * disabled. + */ +#if 0 + if ((type != NULL) && (xmlSchemaIsGlobalItem(type))) { + *msg = xmlStrcat(*msg, BAD_CAST " ["); + *msg = xmlStrcat(*msg, xmlSchemaFormatItemForReport(&str, + NULL, type, NULL, 0)); + FREE_AND_NULL(str) + *msg = xmlStrcat(*msg, BAD_CAST "]"); + } +#endif + return (*msg); +} + +static void +xmlSchemaInternalErr2(xmlSchemaAbstractCtxtPtr actxt, + const char *funcName, + const char *message, + const xmlChar *str1, + const xmlChar *str2) +{ + xmlChar *msg = NULL; + + if (actxt == NULL) + return; + msg = xmlStrdup(BAD_CAST "Internal error: "); + msg = xmlStrcat(msg, BAD_CAST funcName); + msg = xmlStrcat(msg, BAD_CAST ", "); + msg = xmlStrcat(msg, BAD_CAST message); + msg = xmlStrcat(msg, BAD_CAST ".\n"); + + if (actxt->type == XML_SCHEMA_CTXT_VALIDATOR) + xmlSchemaErr(actxt, XML_SCHEMAV_INTERNAL, NULL, + (const char *) msg, str1, str2); + + else if (actxt->type == XML_SCHEMA_CTXT_PARSER) + xmlSchemaErr(actxt, XML_SCHEMAP_INTERNAL, NULL, + (const char *) msg, str1, str2); + + FREE_AND_NULL(msg) +} + +static void +xmlSchemaInternalErr(xmlSchemaAbstractCtxtPtr actxt, + const char *funcName, + const char *message) +{ + xmlSchemaInternalErr2(actxt, funcName, message, NULL, NULL); +} + +#if 0 +static void +xmlSchemaPInternalErr(xmlSchemaParserCtxtPtr pctxt, + const char *funcName, + const char *message, + const xmlChar *str1, + const xmlChar *str2) +{ + xmlSchemaInternalErr2(ACTXT_CAST pctxt, funcName, message, + str1, str2); +} +#endif + +static void +xmlSchemaCustomErr4(xmlSchemaAbstractCtxtPtr actxt, + xmlParserErrors error, + xmlNodePtr node, + xmlSchemaBasicItemPtr item, + const char *message, + const xmlChar *str1, const xmlChar *str2, + const xmlChar *str3, const xmlChar *str4) +{ + xmlChar *msg = NULL; + + if ((node == NULL) && (item != NULL) && + (actxt->type == XML_SCHEMA_CTXT_PARSER)) { + node = WXS_ITEM_NODE(item); + xmlSchemaFormatItemForReport(&msg, NULL, item, NULL); + msg = xmlStrcat(msg, BAD_CAST ": "); + } else + xmlSchemaFormatNodeForError(&msg, actxt, node); + msg = xmlStrcat(msg, (const xmlChar *) message); + msg = xmlStrcat(msg, BAD_CAST ".\n"); + xmlSchemaErr4(actxt, error, node, + (const char *) msg, str1, str2, str3, str4); + FREE_AND_NULL(msg) +} + +static void +xmlSchemaCustomErr(xmlSchemaAbstractCtxtPtr actxt, + xmlParserErrors error, + xmlNodePtr node, + xmlSchemaBasicItemPtr item, + const char *message, + const xmlChar *str1, + const xmlChar *str2) +{ + xmlSchemaCustomErr4(actxt, error, node, item, + message, str1, str2, NULL, NULL); +} + + + +static void +xmlSchemaCustomWarning(xmlSchemaAbstractCtxtPtr actxt, + xmlParserErrors error, + xmlNodePtr node, + xmlSchemaTypePtr type ATTRIBUTE_UNUSED, + const char *message, + const xmlChar *str1, + const xmlChar *str2, + const xmlChar *str3) +{ + xmlChar *msg = NULL; + + xmlSchemaFormatNodeForError(&msg, actxt, node); + msg = xmlStrcat(msg, (const xmlChar *) message); + msg = xmlStrcat(msg, BAD_CAST ".\n"); + + /* URGENT TODO: Set the error code to something sane. */ + xmlSchemaErr4Line(actxt, XML_ERR_WARNING, error, node, 0, + (const char *) msg, str1, str2, str3, NULL); + + FREE_AND_NULL(msg) +} + + + +static void +xmlSchemaKeyrefErr(xmlSchemaValidCtxtPtr vctxt, + xmlParserErrors error, + xmlSchemaPSVIIDCNodePtr idcNode, + xmlSchemaTypePtr type ATTRIBUTE_UNUSED, + const char *message, + const xmlChar *str1, + const xmlChar *str2) +{ + xmlChar *msg = NULL, *qname = NULL; + + msg = xmlStrdup(BAD_CAST "Element '%s': "); + msg = xmlStrcat(msg, (const xmlChar *) message); + msg = xmlStrcat(msg, BAD_CAST ".\n"); + xmlSchemaErr4Line(ACTXT_CAST vctxt, XML_ERR_ERROR, + error, NULL, idcNode->nodeLine, (const char *) msg, + xmlSchemaFormatQName(&qname, + vctxt->nodeQNames->items[idcNode->nodeQNameID +1], + vctxt->nodeQNames->items[idcNode->nodeQNameID]), + str1, str2, NULL); + FREE_AND_NULL(qname); + FREE_AND_NULL(msg); +} + +static int +xmlSchemaEvalErrorNodeType(xmlSchemaAbstractCtxtPtr actxt, + xmlNodePtr node) +{ + if (node != NULL) + return (node->type); + if ((actxt->type == XML_SCHEMA_CTXT_VALIDATOR) && + (((xmlSchemaValidCtxtPtr) actxt)->inode != NULL)) + return ( ((xmlSchemaValidCtxtPtr) actxt)->inode->nodeType); + return (-1); +} + +static int +xmlSchemaIsGlobalItem(xmlSchemaTypePtr item) +{ + switch (item->type) { + case XML_SCHEMA_TYPE_COMPLEX: + case XML_SCHEMA_TYPE_SIMPLE: + if (item->flags & XML_SCHEMAS_TYPE_GLOBAL) + return(1); + break; + case XML_SCHEMA_TYPE_GROUP: + return (1); + case XML_SCHEMA_TYPE_ELEMENT: + if ( ((xmlSchemaElementPtr) item)->flags & + XML_SCHEMAS_ELEM_GLOBAL) + return(1); + break; + case XML_SCHEMA_TYPE_ATTRIBUTE: + if ( ((xmlSchemaAttributePtr) item)->flags & + XML_SCHEMAS_ATTR_GLOBAL) + return(1); + break; + /* Note that attribute groups are always global. */ + default: + return(1); + } + return (0); +} + +static void +xmlSchemaSimpleTypeErr(xmlSchemaAbstractCtxtPtr actxt, + xmlParserErrors error, + xmlNodePtr node, + const xmlChar *value, + xmlSchemaTypePtr type, + int displayValue) +{ + xmlChar *msg = NULL; + + xmlSchemaFormatNodeForError(&msg, actxt, node); + + if (displayValue || (xmlSchemaEvalErrorNodeType(actxt, node) == + XML_ATTRIBUTE_NODE)) + msg = xmlStrcat(msg, BAD_CAST "'%s' is not a valid value of "); + else + msg = xmlStrcat(msg, BAD_CAST "The character content is not a valid " + "value of "); + + if (! xmlSchemaIsGlobalItem(type)) + msg = xmlStrcat(msg, BAD_CAST "the local "); + else + msg = xmlStrcat(msg, BAD_CAST "the "); + + if (WXS_IS_ATOMIC(type)) + msg = xmlStrcat(msg, BAD_CAST "atomic type"); + else if (WXS_IS_LIST(type)) + msg = xmlStrcat(msg, BAD_CAST "list type"); + else if (WXS_IS_UNION(type)) + msg = xmlStrcat(msg, BAD_CAST "union type"); + + if (xmlSchemaIsGlobalItem(type)) { + xmlChar *str = NULL; + msg = xmlStrcat(msg, BAD_CAST " '"); + if (type->builtInType != 0) { + msg = xmlStrcat(msg, BAD_CAST "xs:"); + msg = xmlStrcat(msg, type->name); + } else + msg = xmlStrcat(msg, + xmlSchemaFormatQName(&str, + type->targetNamespace, type->name)); + msg = xmlStrcat(msg, BAD_CAST "'"); + FREE_AND_NULL(str); + } + msg = xmlStrcat(msg, BAD_CAST ".\n"); + if (displayValue || (xmlSchemaEvalErrorNodeType(actxt, node) == + XML_ATTRIBUTE_NODE)) + xmlSchemaErr(actxt, error, node, (const char *) msg, value, NULL); + else + xmlSchemaErr(actxt, error, node, (const char *) msg, NULL, NULL); + FREE_AND_NULL(msg) +} + +static const xmlChar * +xmlSchemaFormatErrorNodeQName(xmlChar ** str, + xmlSchemaNodeInfoPtr ni, + xmlNodePtr node) +{ + if (node != NULL) { + if (node->ns != NULL) + return (xmlSchemaFormatQName(str, node->ns->href, node->name)); + else + return (xmlSchemaFormatQName(str, NULL, node->name)); + } else if (ni != NULL) + return (xmlSchemaFormatQName(str, ni->nsName, ni->localName)); + return (NULL); +} + +static void +xmlSchemaIllegalAttrErr(xmlSchemaAbstractCtxtPtr actxt, + xmlParserErrors error, + xmlSchemaAttrInfoPtr ni, + xmlNodePtr node) +{ + xmlChar *msg = NULL, *str = NULL; + + xmlSchemaFormatNodeForError(&msg, actxt, node); + msg = xmlStrcat(msg, BAD_CAST "The attribute '%s' is not allowed.\n"); + xmlSchemaErr(actxt, error, node, (const char *) msg, + xmlSchemaFormatErrorNodeQName(&str, (xmlSchemaNodeInfoPtr) ni, node), + NULL); + FREE_AND_NULL(str) + FREE_AND_NULL(msg) +} + +static void +xmlSchemaComplexTypeErr(xmlSchemaAbstractCtxtPtr actxt, + xmlParserErrors error, + xmlNodePtr node, + xmlSchemaTypePtr type ATTRIBUTE_UNUSED, + const char *message, + int nbval, + int nbneg, + xmlChar **values) +{ + xmlChar *str = NULL, *msg = NULL; + xmlChar *localName, *nsName; + const xmlChar *cur, *end; + int i; + + xmlSchemaFormatNodeForError(&msg, actxt, node); + msg = xmlStrcat(msg, (const xmlChar *) message); + msg = xmlStrcat(msg, BAD_CAST "."); + /* + * Note that is does not make sense to report that we have a + * wildcard here, since the wildcard might be unfolded into + * multiple transitions. + */ + if (nbval + nbneg > 0) { + if (nbval + nbneg > 1) { + str = xmlStrdup(BAD_CAST " Expected is one of ( "); + } else + str = xmlStrdup(BAD_CAST " Expected is ( "); + nsName = NULL; + + for (i = 0; i < nbval + nbneg; i++) { + cur = values[i]; + if (cur == NULL) + continue; + if ((cur[0] == 'n') && (cur[1] == 'o') && (cur[2] == 't') && + (cur[3] == ' ')) { + cur += 4; + str = xmlStrcat(str, BAD_CAST "##other"); + } + /* + * Get the local name. + */ + localName = NULL; + + end = cur; + if (*end == '*') { + localName = xmlStrdup(BAD_CAST "*"); + end++; + } else { + while ((*end != 0) && (*end != '|')) + end++; + localName = xmlStrncat(localName, BAD_CAST cur, end - cur); + } + if (*end != 0) { + end++; + /* + * Skip "*|*" if they come with negated expressions, since + * they represent the same negated wildcard. + */ + if ((nbneg == 0) || (*end != '*') || (*localName != '*')) { + /* + * Get the namespace name. + */ + cur = end; + if (*end == '*') { + nsName = xmlStrdup(BAD_CAST "{*}"); + } else { + while (*end != 0) + end++; + + if (i >= nbval) + nsName = xmlStrdup(BAD_CAST "{##other:"); + else + nsName = xmlStrdup(BAD_CAST "{"); + + nsName = xmlStrncat(nsName, BAD_CAST cur, end - cur); + nsName = xmlStrcat(nsName, BAD_CAST "}"); + } + str = xmlStrcat(str, BAD_CAST nsName); + FREE_AND_NULL(nsName) + } else { + FREE_AND_NULL(localName); + continue; + } + } + str = xmlStrcat(str, BAD_CAST localName); + FREE_AND_NULL(localName); + + if (i < nbval + nbneg -1) + str = xmlStrcat(str, BAD_CAST ", "); + } + str = xmlStrcat(str, BAD_CAST " ).\n"); + msg = xmlStrcat(msg, BAD_CAST str); + FREE_AND_NULL(str) + } else + msg = xmlStrcat(msg, BAD_CAST "\n"); + xmlSchemaErr(actxt, error, node, (const char *) msg, NULL, NULL); + xmlFree(msg); +} + +static void +xmlSchemaFacetErr(xmlSchemaAbstractCtxtPtr actxt, + xmlParserErrors error, + xmlNodePtr node, + const xmlChar *value, + unsigned long length, + xmlSchemaTypePtr type, + xmlSchemaFacetPtr facet, + const char *message, + const xmlChar *str1, + const xmlChar *str2) +{ + xmlChar *str = NULL, *msg = NULL; + xmlSchemaTypeType facetType; + int nodeType = xmlSchemaEvalErrorNodeType(actxt, node); + + xmlSchemaFormatNodeForError(&msg, actxt, node); + if (error == XML_SCHEMAV_CVC_ENUMERATION_VALID) { + facetType = XML_SCHEMA_FACET_ENUMERATION; + /* + * If enumerations are validated, one must not expect the + * facet to be given. + */ + } else + facetType = facet->type; + msg = xmlStrcat(msg, BAD_CAST "["); + msg = xmlStrcat(msg, BAD_CAST "facet '"); + msg = xmlStrcat(msg, xmlSchemaFacetTypeToString(facetType)); + msg = xmlStrcat(msg, BAD_CAST "'] "); + if (message == NULL) { + /* + * Use a default message. + */ + if ((facetType == XML_SCHEMA_FACET_LENGTH) || + (facetType == XML_SCHEMA_FACET_MINLENGTH) || + (facetType == XML_SCHEMA_FACET_MAXLENGTH)) { + + char len[25], actLen[25]; + + /* FIXME, TODO: What is the max expected string length of the + * this value? + */ + if (nodeType == XML_ATTRIBUTE_NODE) + msg = xmlStrcat(msg, BAD_CAST "The value '%s' has a length of '%s'; "); + else + msg = xmlStrcat(msg, BAD_CAST "The value has a length of '%s'; "); + + snprintf(len, 24, "%lu", xmlSchemaGetFacetValueAsULong(facet)); + snprintf(actLen, 24, "%lu", length); + + if (facetType == XML_SCHEMA_FACET_LENGTH) + msg = xmlStrcat(msg, + BAD_CAST "this differs from the allowed length of '%s'.\n"); + else if (facetType == XML_SCHEMA_FACET_MAXLENGTH) + msg = xmlStrcat(msg, + BAD_CAST "this exceeds the allowed maximum length of '%s'.\n"); + else if (facetType == XML_SCHEMA_FACET_MINLENGTH) + msg = xmlStrcat(msg, + BAD_CAST "this underruns the allowed minimum length of '%s'.\n"); + + if (nodeType == XML_ATTRIBUTE_NODE) + xmlSchemaErr3(actxt, error, node, (const char *) msg, + value, (const xmlChar *) actLen, (const xmlChar *) len); + else + xmlSchemaErr(actxt, error, node, (const char *) msg, + (const xmlChar *) actLen, (const xmlChar *) len); + + } else if (facetType == XML_SCHEMA_FACET_ENUMERATION) { + msg = xmlStrcat(msg, BAD_CAST "The value '%s' is not an element " + "of the set {%s}.\n"); + xmlSchemaErr(actxt, error, node, (const char *) msg, value, + xmlSchemaFormatFacetEnumSet(actxt, &str, type)); + } else if (facetType == XML_SCHEMA_FACET_PATTERN) { + msg = xmlStrcat(msg, BAD_CAST "The value '%s' is not accepted " + "by the pattern '%s'.\n"); + xmlSchemaErr(actxt, error, node, (const char *) msg, value, + facet->value); + } else if (facetType == XML_SCHEMA_FACET_MININCLUSIVE) { + msg = xmlStrcat(msg, BAD_CAST "The value '%s' is less than the " + "minimum value allowed ('%s').\n"); + xmlSchemaErr(actxt, error, node, (const char *) msg, value, + facet->value); + } else if (facetType == XML_SCHEMA_FACET_MAXINCLUSIVE) { + msg = xmlStrcat(msg, BAD_CAST "The value '%s' is greater than the " + "maximum value allowed ('%s').\n"); + xmlSchemaErr(actxt, error, node, (const char *) msg, value, + facet->value); + } else if (facetType == XML_SCHEMA_FACET_MINEXCLUSIVE) { + msg = xmlStrcat(msg, BAD_CAST "The value '%s' must be greater than " + "'%s'.\n"); + xmlSchemaErr(actxt, error, node, (const char *) msg, value, + facet->value); + } else if (facetType == XML_SCHEMA_FACET_MAXEXCLUSIVE) { + msg = xmlStrcat(msg, BAD_CAST "The value '%s' must be less than " + "'%s'.\n"); + xmlSchemaErr(actxt, error, node, (const char *) msg, value, + facet->value); + } else if (facetType == XML_SCHEMA_FACET_TOTALDIGITS) { + msg = xmlStrcat(msg, BAD_CAST "The value '%s' has more " + "digits than are allowed ('%s').\n"); + xmlSchemaErr(actxt, error, node, (const char*) msg, value, + facet->value); + } else if (facetType == XML_SCHEMA_FACET_FRACTIONDIGITS) { + msg = xmlStrcat(msg, BAD_CAST "The value '%s' has more fractional " + "digits than are allowed ('%s').\n"); + xmlSchemaErr(actxt, error, node, (const char*) msg, value, + facet->value); + } else if (nodeType == XML_ATTRIBUTE_NODE) { + msg = xmlStrcat(msg, BAD_CAST "The value '%s' is not facet-valid.\n"); + xmlSchemaErr(actxt, error, node, (const char *) msg, value, NULL); + } else { + msg = xmlStrcat(msg, BAD_CAST "The value is not facet-valid.\n"); + xmlSchemaErr(actxt, error, node, (const char *) msg, NULL, NULL); + } + } else { + msg = xmlStrcat(msg, (const xmlChar *) message); + msg = xmlStrcat(msg, BAD_CAST ".\n"); + xmlSchemaErr(actxt, error, node, (const char *) msg, str1, str2); + } + FREE_AND_NULL(str) + xmlFree(msg); +} + +#define VERROR(err, type, msg) \ + xmlSchemaCustomErr(ACTXT_CAST vctxt, err, NULL, type, msg, NULL, NULL); + +#define VERROR_INT(func, msg) xmlSchemaInternalErr(ACTXT_CAST vctxt, func, msg); + +#define PERROR_INT(func, msg) xmlSchemaInternalErr(ACTXT_CAST pctxt, func, msg); +#define PERROR_INT2(func, msg) xmlSchemaInternalErr(ACTXT_CAST ctxt, func, msg); + +#define AERROR_INT(func, msg) xmlSchemaInternalErr(actxt, func, msg); + + +/** + * xmlSchemaPMissingAttrErr: + * @ctxt: the schema validation context + * @ownerDes: the designation of the owner + * @ownerName: the name of the owner + * @ownerItem: the owner as a schema object + * @ownerElem: the owner as an element node + * @node: the parent element node of the missing attribute node + * @type: the corresponding type of the attribute node + * + * Reports an illegal attribute. + */ +static void +xmlSchemaPMissingAttrErr(xmlSchemaParserCtxtPtr ctxt, + xmlParserErrors error, + xmlSchemaBasicItemPtr ownerItem, + xmlNodePtr ownerElem, + const char *name, + const char *message) +{ + xmlChar *des = NULL; + + xmlSchemaFormatItemForReport(&des, NULL, ownerItem, ownerElem); + + if (message != NULL) + xmlSchemaPErr(ctxt, ownerElem, error, "%s: %s.\n", BAD_CAST des, BAD_CAST message); + else + xmlSchemaPErr(ctxt, ownerElem, error, + "%s: The attribute '%s' is required but missing.\n", + BAD_CAST des, BAD_CAST name); + FREE_AND_NULL(des); +} + + +/** + * xmlSchemaPResCompAttrErr: + * @ctxt: the schema validation context + * @error: the error code + * @ownerDes: the designation of the owner + * @ownerItem: the owner as a schema object + * @ownerElem: the owner as an element node + * @name: the name of the attribute holding the QName + * @refName: the referenced local name + * @refURI: the referenced namespace URI + * @message: optional message + * + * Used to report QName attribute values that failed to resolve + * to schema components. + */ +static void +xmlSchemaPResCompAttrErr(xmlSchemaParserCtxtPtr ctxt, + xmlParserErrors error, + xmlSchemaBasicItemPtr ownerItem, + xmlNodePtr ownerElem, + const char *name, + const xmlChar *refName, + const xmlChar *refURI, + xmlSchemaTypeType refType, + const char *refTypeStr) +{ + xmlChar *des = NULL, *strA = NULL; + + xmlSchemaFormatItemForReport(&des, NULL, ownerItem, ownerElem); + if (refTypeStr == NULL) + refTypeStr = (const char *) xmlSchemaItemTypeToStr(refType); + xmlSchemaPErrExt(ctxt, ownerElem, error, + NULL, NULL, NULL, + "%s, attribute '%s': The QName value '%s' does not resolve to a(n) " + "%s.\n", BAD_CAST des, BAD_CAST name, + xmlSchemaFormatQName(&strA, refURI, refName), + BAD_CAST refTypeStr, NULL); + FREE_AND_NULL(des) + FREE_AND_NULL(strA) +} + +/** + * xmlSchemaPCustomAttrErr: + * @ctxt: the schema parser context + * @error: the error code + * @ownerDes: the designation of the owner + * @ownerItem: the owner as a schema object + * @attr: the illegal attribute node + * + * Reports an illegal attribute during the parse. + */ +static void +xmlSchemaPCustomAttrErr(xmlSchemaParserCtxtPtr ctxt, + xmlParserErrors error, + xmlChar **ownerDes, + xmlSchemaBasicItemPtr ownerItem, + xmlAttrPtr attr, + const char *msg) +{ + xmlChar *des = NULL; + + if (ownerDes == NULL) + xmlSchemaFormatItemForReport(&des, NULL, ownerItem, attr->parent); + else if (*ownerDes == NULL) { + xmlSchemaFormatItemForReport(ownerDes, NULL, ownerItem, attr->parent); + des = *ownerDes; + } else + des = *ownerDes; + if (attr == NULL) { + xmlSchemaPErrExt(ctxt, NULL, error, NULL, NULL, NULL, + "%s, attribute '%s': %s.\n", + BAD_CAST des, (const xmlChar *) "Unknown", + (const xmlChar *) msg, NULL, NULL); + } else { + xmlSchemaPErrExt(ctxt, (xmlNodePtr) attr, error, NULL, NULL, NULL, + "%s, attribute '%s': %s.\n", + BAD_CAST des, attr->name, (const xmlChar *) msg, NULL, NULL); + } + if (ownerDes == NULL) + FREE_AND_NULL(des); +} + +/** + * xmlSchemaPIllegalAttrErr: + * @ctxt: the schema parser context + * @error: the error code + * @ownerDes: the designation of the attribute's owner + * @ownerItem: the attribute's owner item + * @attr: the illegal attribute node + * + * Reports an illegal attribute during the parse. + */ +static void +xmlSchemaPIllegalAttrErr(xmlSchemaParserCtxtPtr ctxt, + xmlParserErrors error, + xmlSchemaBasicItemPtr ownerComp ATTRIBUTE_UNUSED, + xmlAttrPtr attr) +{ + xmlChar *strA = NULL, *strB = NULL; + + xmlSchemaFormatNodeForError(&strA, ACTXT_CAST ctxt, attr->parent); + xmlSchemaErr4(ACTXT_CAST ctxt, error, (xmlNodePtr) attr, + "%sThe attribute '%s' is not allowed.\n", BAD_CAST strA, + xmlSchemaFormatQNameNs(&strB, attr->ns, attr->name), + NULL, NULL); + FREE_AND_NULL(strA); + FREE_AND_NULL(strB); +} + +/** + * xmlSchemaPCustomErr: + * @ctxt: the schema parser context + * @error: the error code + * @itemDes: the designation of the schema item + * @item: the schema item + * @itemElem: the node of the schema item + * @message: the error message + * @str1: an optional param for the error message + * @str2: an optional param for the error message + * @str3: an optional param for the error message + * + * Reports an error during parsing. + */ +static void +xmlSchemaPCustomErrExt(xmlSchemaParserCtxtPtr ctxt, + xmlParserErrors error, + xmlSchemaBasicItemPtr item, + xmlNodePtr itemElem, + const char *message, + const xmlChar *str1, + const xmlChar *str2, + const xmlChar *str3) +{ + xmlChar *des = NULL, *msg = NULL; + + xmlSchemaFormatItemForReport(&des, NULL, item, itemElem); + msg = xmlStrdup(BAD_CAST "%s: "); + msg = xmlStrcat(msg, (const xmlChar *) message); + msg = xmlStrcat(msg, BAD_CAST ".\n"); + if ((itemElem == NULL) && (item != NULL)) + itemElem = WXS_ITEM_NODE(item); + xmlSchemaPErrExt(ctxt, itemElem, error, NULL, NULL, NULL, + (const char *) msg, BAD_CAST des, str1, str2, str3, NULL); + FREE_AND_NULL(des); + FREE_AND_NULL(msg); +} + +/** + * xmlSchemaPCustomErr: + * @ctxt: the schema parser context + * @error: the error code + * @itemDes: the designation of the schema item + * @item: the schema item + * @itemElem: the node of the schema item + * @message: the error message + * @str1: the optional param for the error message + * + * Reports an error during parsing. + */ +static void +xmlSchemaPCustomErr(xmlSchemaParserCtxtPtr ctxt, + xmlParserErrors error, + xmlSchemaBasicItemPtr item, + xmlNodePtr itemElem, + const char *message, + const xmlChar *str1) +{ + xmlSchemaPCustomErrExt(ctxt, error, item, itemElem, message, + str1, NULL, NULL); +} + +/** + * xmlSchemaPAttrUseErr: + * @ctxt: the schema parser context + * @error: the error code + * @itemDes: the designation of the schema type + * @item: the schema type + * @itemElem: the node of the schema type + * @attr: the invalid schema attribute + * @message: the error message + * @str1: the optional param for the error message + * + * Reports an attribute use error during parsing. + */ +static void +xmlSchemaPAttrUseErr4(xmlSchemaParserCtxtPtr ctxt, + xmlParserErrors error, + xmlNodePtr node, + xmlSchemaBasicItemPtr ownerItem, + const xmlSchemaAttributeUsePtr attruse, + const char *message, + const xmlChar *str1, const xmlChar *str2, + const xmlChar *str3,const xmlChar *str4) +{ + xmlChar *str = NULL, *msg = NULL; + + xmlSchemaFormatItemForReport(&msg, NULL, ownerItem, NULL); + msg = xmlStrcat(msg, BAD_CAST ", "); + msg = xmlStrcat(msg, + BAD_CAST xmlSchemaFormatItemForReport(&str, NULL, + WXS_BASIC_CAST attruse, NULL)); + FREE_AND_NULL(str); + msg = xmlStrcat(msg, BAD_CAST ": "); + msg = xmlStrcat(msg, (const xmlChar *) message); + msg = xmlStrcat(msg, BAD_CAST ".\n"); + xmlSchemaErr4(ACTXT_CAST ctxt, error, node, + (const char *) msg, str1, str2, str3, str4); + xmlFree(msg); +} + +/** + * xmlSchemaPIllegalFacetAtomicErr: + * @ctxt: the schema parser context + * @error: the error code + * @type: the schema type + * @baseType: the base type of type + * @facet: the illegal facet + * + * Reports an illegal facet for atomic simple types. + */ +static void +xmlSchemaPIllegalFacetAtomicErr(xmlSchemaParserCtxtPtr ctxt, + xmlParserErrors error, + xmlSchemaTypePtr type, + xmlSchemaTypePtr baseType, + xmlSchemaFacetPtr facet) +{ + xmlChar *des = NULL, *strT = NULL; + + xmlSchemaFormatItemForReport(&des, NULL, WXS_BASIC_CAST type, type->node); + xmlSchemaPErrExt(ctxt, type->node, error, NULL, NULL, NULL, + "%s: The facet '%s' is not allowed on types derived from the " + "type %s.\n", + BAD_CAST des, xmlSchemaFacetTypeToString(facet->type), + xmlSchemaFormatItemForReport(&strT, NULL, WXS_BASIC_CAST baseType, NULL), + NULL, NULL); + FREE_AND_NULL(des); + FREE_AND_NULL(strT); +} + +/** + * xmlSchemaPIllegalFacetListUnionErr: + * @ctxt: the schema parser context + * @error: the error code + * @itemDes: the designation of the schema item involved + * @item: the schema item involved + * @facet: the illegal facet + * + * Reports an illegal facet for and . + */ +static void +xmlSchemaPIllegalFacetListUnionErr(xmlSchemaParserCtxtPtr ctxt, + xmlParserErrors error, + xmlSchemaTypePtr type, + xmlSchemaFacetPtr facet) +{ + xmlChar *des = NULL; + + xmlSchemaFormatItemForReport(&des, NULL, WXS_BASIC_CAST type, + type->node); + xmlSchemaPErr(ctxt, type->node, error, + "%s: The facet '%s' is not allowed.\n", + BAD_CAST des, xmlSchemaFacetTypeToString(facet->type)); + FREE_AND_NULL(des); +} + +/** + * xmlSchemaPMutualExclAttrErr: + * @ctxt: the schema validation context + * @error: the error code + * @elemDes: the designation of the parent element node + * @attr: the bad attribute node + * @type: the corresponding type of the attribute node + * + * Reports an illegal attribute. + */ +static void +xmlSchemaPMutualExclAttrErr(xmlSchemaParserCtxtPtr ctxt, + xmlParserErrors error, + xmlSchemaBasicItemPtr ownerItem, + xmlAttrPtr attr, + const char *name1, + const char *name2) +{ + xmlChar *des = NULL; + + xmlSchemaFormatItemForReport(&des, NULL, WXS_BASIC_CAST ownerItem, attr->parent); + xmlSchemaPErrExt(ctxt, (xmlNodePtr) attr, error, NULL, NULL, NULL, + "%s: The attributes '%s' and '%s' are mutually exclusive.\n", + BAD_CAST des, BAD_CAST name1, BAD_CAST name2, NULL, NULL); + FREE_AND_NULL(des); +} + +/** + * xmlSchemaPSimpleTypeErr: + * @ctxt: the schema validation context + * @error: the error code + * @type: the type specifier + * @ownerDes: the designation of the owner + * @ownerItem: the schema object if existent + * @node: the validated node + * @value: the validated value + * + * Reports a simple type validation error. + * TODO: Should this report the value of an element as well? + */ +static void +xmlSchemaPSimpleTypeErr(xmlSchemaParserCtxtPtr ctxt, + xmlParserErrors error, + xmlSchemaBasicItemPtr ownerItem ATTRIBUTE_UNUSED, + xmlNodePtr node, + xmlSchemaTypePtr type, + const char *expected, + const xmlChar *value, + const char *message, + const xmlChar *str1, + const xmlChar *str2) +{ + xmlChar *msg = NULL; + + xmlSchemaFormatNodeForError(&msg, ACTXT_CAST ctxt, node); + if (message == NULL) { + /* + * Use default messages. + */ + if (type != NULL) { + if (node->type == XML_ATTRIBUTE_NODE) + msg = xmlStrcat(msg, BAD_CAST "'%s' is not a valid value of "); + else + msg = xmlStrcat(msg, BAD_CAST "The character content is not a " + "valid value of "); + if (! xmlSchemaIsGlobalItem(type)) + msg = xmlStrcat(msg, BAD_CAST "the local "); + else + msg = xmlStrcat(msg, BAD_CAST "the "); + + if (WXS_IS_ATOMIC(type)) + msg = xmlStrcat(msg, BAD_CAST "atomic type"); + else if (WXS_IS_LIST(type)) + msg = xmlStrcat(msg, BAD_CAST "list type"); + else if (WXS_IS_UNION(type)) + msg = xmlStrcat(msg, BAD_CAST "union type"); + + if (xmlSchemaIsGlobalItem(type)) { + xmlChar *str = NULL; + msg = xmlStrcat(msg, BAD_CAST " '"); + if (type->builtInType != 0) { + msg = xmlStrcat(msg, BAD_CAST "xs:"); + msg = xmlStrcat(msg, type->name); + } else + msg = xmlStrcat(msg, + xmlSchemaFormatQName(&str, + type->targetNamespace, type->name)); + msg = xmlStrcat(msg, BAD_CAST "'."); + FREE_AND_NULL(str); + } + } else { + if (node->type == XML_ATTRIBUTE_NODE) + msg = xmlStrcat(msg, BAD_CAST "The value '%s' is not valid."); + else + msg = xmlStrcat(msg, BAD_CAST "The character content is not " + "valid."); + } + if (expected) { + msg = xmlStrcat(msg, BAD_CAST " Expected is '"); + msg = xmlStrcat(msg, BAD_CAST expected); + msg = xmlStrcat(msg, BAD_CAST "'.\n"); + } else + msg = xmlStrcat(msg, BAD_CAST "\n"); + if (node->type == XML_ATTRIBUTE_NODE) + xmlSchemaPErr(ctxt, node, error, (const char *) msg, value, NULL); + else + xmlSchemaPErr(ctxt, node, error, (const char *) msg, NULL, NULL); + } else { + msg = xmlStrcat(msg, BAD_CAST message); + msg = xmlStrcat(msg, BAD_CAST ".\n"); + xmlSchemaPErrExt(ctxt, node, error, NULL, NULL, NULL, + (const char*) msg, str1, str2, NULL, NULL, NULL); + } + /* Cleanup. */ + FREE_AND_NULL(msg) +} + +/** + * xmlSchemaPContentErr: + * @ctxt: the schema parser context + * @error: the error code + * @onwerDes: the designation of the holder of the content + * @ownerItem: the owner item of the holder of the content + * @ownerElem: the node of the holder of the content + * @child: the invalid child node + * @message: the optional error message + * @content: the optional string describing the correct content + * + * Reports an error concerning the content of a schema element. + */ +static void +xmlSchemaPContentErr(xmlSchemaParserCtxtPtr ctxt, + xmlParserErrors error, + xmlSchemaBasicItemPtr ownerItem, + xmlNodePtr ownerElem, + xmlNodePtr child, + const char *message, + const char *content) +{ + xmlChar *des = NULL; + + xmlSchemaFormatItemForReport(&des, NULL, ownerItem, ownerElem); + if (message != NULL) + xmlSchemaPErr2(ctxt, ownerElem, child, error, + "%s: %s.\n", + BAD_CAST des, BAD_CAST message); + else { + if (content != NULL) { + xmlSchemaPErr2(ctxt, ownerElem, child, error, + "%s: The content is not valid. Expected is %s.\n", + BAD_CAST des, BAD_CAST content); + } else { + xmlSchemaPErr2(ctxt, ownerElem, child, error, + "%s: The content is not valid.\n", + BAD_CAST des, NULL); + } + } + FREE_AND_NULL(des) +} + +/************************************************************************ + * * + * Streamable error functions * + * * + ************************************************************************/ + + + + +/************************************************************************ + * * + * Validation helper functions * + * * + ************************************************************************/ + + +/************************************************************************ + * * + * Allocation functions * + * * + ************************************************************************/ + +/** + * xmlSchemaNewSchemaForParserCtxt: + * @ctxt: a schema validation context + * + * Allocate a new Schema structure. + * + * Returns the newly allocated structure or NULL in case or error + */ +static xmlSchemaPtr +xmlSchemaNewSchema(xmlSchemaParserCtxtPtr ctxt) +{ + xmlSchemaPtr ret; + + ret = (xmlSchemaPtr) xmlMalloc(sizeof(xmlSchema)); + if (ret == NULL) { + xmlSchemaPErrMemory(ctxt, "allocating schema", NULL); + return (NULL); + } + memset(ret, 0, sizeof(xmlSchema)); + ret->dict = ctxt->dict; + xmlDictReference(ret->dict); + + return (ret); +} + +/** + * xmlSchemaNewFacet: + * + * Allocate a new Facet structure. + * + * Returns the newly allocated structure or NULL in case or error + */ +xmlSchemaFacetPtr +xmlSchemaNewFacet(void) +{ + xmlSchemaFacetPtr ret; + + ret = (xmlSchemaFacetPtr) xmlMalloc(sizeof(xmlSchemaFacet)); + if (ret == NULL) { + return (NULL); + } + memset(ret, 0, sizeof(xmlSchemaFacet)); + + return (ret); +} + +/** + * xmlSchemaNewAnnot: + * @ctxt: a schema validation context + * @node: a node + * + * Allocate a new annotation structure. + * + * Returns the newly allocated structure or NULL in case or error + */ +static xmlSchemaAnnotPtr +xmlSchemaNewAnnot(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node) +{ + xmlSchemaAnnotPtr ret; + + ret = (xmlSchemaAnnotPtr) xmlMalloc(sizeof(xmlSchemaAnnot)); + if (ret == NULL) { + xmlSchemaPErrMemory(ctxt, "allocating annotation", node); + return (NULL); + } + memset(ret, 0, sizeof(xmlSchemaAnnot)); + ret->content = node; + return (ret); +} + +static xmlSchemaItemListPtr +xmlSchemaItemListCreate(void) +{ + xmlSchemaItemListPtr ret; + + ret = xmlMalloc(sizeof(xmlSchemaItemList)); + if (ret == NULL) { + xmlSchemaPErrMemory(NULL, + "allocating an item list structure", NULL); + return (NULL); + } + memset(ret, 0, sizeof(xmlSchemaItemList)); + return (ret); +} + +static void +xmlSchemaItemListClear(xmlSchemaItemListPtr list) +{ + if (list->items != NULL) { + xmlFree(list->items); + list->items = NULL; + } + list->nbItems = 0; + list->sizeItems = 0; +} + +static int +xmlSchemaItemListAdd(xmlSchemaItemListPtr list, void *item) +{ + if (list->items == NULL) { + list->items = (void **) xmlMalloc( + 20 * sizeof(void *)); + if (list->items == NULL) { + xmlSchemaPErrMemory(NULL, "allocating new item list", NULL); + return(-1); + } + list->sizeItems = 20; + } else if (list->sizeItems <= list->nbItems) { + list->sizeItems *= 2; + list->items = (void **) xmlRealloc(list->items, + list->sizeItems * sizeof(void *)); + if (list->items == NULL) { + xmlSchemaPErrMemory(NULL, "growing item list", NULL); + list->sizeItems = 0; + return(-1); + } + } + list->items[list->nbItems++] = item; + return(0); +} + +static int +xmlSchemaItemListAddSize(xmlSchemaItemListPtr list, + int initialSize, + void *item) +{ + if (list->items == NULL) { + if (initialSize <= 0) + initialSize = 1; + list->items = (void **) xmlMalloc( + initialSize * sizeof(void *)); + if (list->items == NULL) { + xmlSchemaPErrMemory(NULL, "allocating new item list", NULL); + return(-1); + } + list->sizeItems = initialSize; + } else if (list->sizeItems <= list->nbItems) { + list->sizeItems *= 2; + list->items = (void **) xmlRealloc(list->items, + list->sizeItems * sizeof(void *)); + if (list->items == NULL) { + xmlSchemaPErrMemory(NULL, "growing item list", NULL); + list->sizeItems = 0; + return(-1); + } + } + list->items[list->nbItems++] = item; + return(0); +} + +static int +xmlSchemaItemListInsert(xmlSchemaItemListPtr list, void *item, int idx) +{ + if (list->items == NULL) { + list->items = (void **) xmlMalloc( + 20 * sizeof(void *)); + if (list->items == NULL) { + xmlSchemaPErrMemory(NULL, "allocating new item list", NULL); + return(-1); + } + list->sizeItems = 20; + } else if (list->sizeItems <= list->nbItems) { + list->sizeItems *= 2; + list->items = (void **) xmlRealloc(list->items, + list->sizeItems * sizeof(void *)); + if (list->items == NULL) { + xmlSchemaPErrMemory(NULL, "growing item list", NULL); + list->sizeItems = 0; + return(-1); + } + } + /* + * Just append if the index is greater/equal than the item count. + */ + if (idx >= list->nbItems) { + list->items[list->nbItems++] = item; + } else { + int i; + for (i = list->nbItems; i > idx; i--) + list->items[i] = list->items[i-1]; + list->items[idx] = item; + list->nbItems++; + } + return(0); +} + +#if 0 /* enable if ever needed */ +static int +xmlSchemaItemListInsertSize(xmlSchemaItemListPtr list, + int initialSize, + void *item, + int idx) +{ + if (list->items == NULL) { + if (initialSize <= 0) + initialSize = 1; + list->items = (void **) xmlMalloc( + initialSize * sizeof(void *)); + if (list->items == NULL) { + xmlSchemaPErrMemory(NULL, "allocating new item list", NULL); + return(-1); + } + list->sizeItems = initialSize; + } else if (list->sizeItems <= list->nbItems) { + list->sizeItems *= 2; + list->items = (void **) xmlRealloc(list->items, + list->sizeItems * sizeof(void *)); + if (list->items == NULL) { + xmlSchemaPErrMemory(NULL, "growing item list", NULL); + list->sizeItems = 0; + return(-1); + } + } + /* + * Just append if the index is greater/equal than the item count. + */ + if (idx >= list->nbItems) { + list->items[list->nbItems++] = item; + } else { + int i; + for (i = list->nbItems; i > idx; i--) + list->items[i] = list->items[i-1]; + list->items[idx] = item; + list->nbItems++; + } + return(0); +} +#endif + +static int +xmlSchemaItemListRemove(xmlSchemaItemListPtr list, int idx) +{ + int i; + if ((list->items == NULL) || (idx >= list->nbItems)) { + xmlSchemaPSimpleErr("Internal error: xmlSchemaItemListRemove, " + "index error.\n"); + return(-1); + } + + if (list->nbItems == 1) { + /* TODO: Really free the list? */ + xmlFree(list->items); + list->items = NULL; + list->nbItems = 0; + list->sizeItems = 0; + } else if (list->nbItems -1 == idx) { + list->nbItems--; + } else { + for (i = idx; i < list->nbItems -1; i++) + list->items[i] = list->items[i+1]; + list->nbItems--; + } + return(0); +} + +/** + * xmlSchemaItemListFree: + * @annot: a schema type structure + * + * Deallocate a annotation structure + */ +static void +xmlSchemaItemListFree(xmlSchemaItemListPtr list) +{ + if (list == NULL) + return; + if (list->items != NULL) + xmlFree(list->items); + xmlFree(list); +} + +static void +xmlSchemaBucketFree(xmlSchemaBucketPtr bucket) +{ + if (bucket == NULL) + return; + if (bucket->globals != NULL) { + xmlSchemaComponentListFree(bucket->globals); + xmlSchemaItemListFree(bucket->globals); + } + if (bucket->locals != NULL) { + xmlSchemaComponentListFree(bucket->locals); + xmlSchemaItemListFree(bucket->locals); + } + if (bucket->relations != NULL) { + xmlSchemaSchemaRelationPtr prev, cur = bucket->relations; + do { + prev = cur; + cur = cur->next; + xmlFree(prev); + } while (cur != NULL); + } + if ((! bucket->preserveDoc) && (bucket->doc != NULL)) { + xmlFreeDoc(bucket->doc); + } + if (bucket->type == XML_SCHEMA_SCHEMA_IMPORT) { + if (WXS_IMPBUCKET(bucket)->schema != NULL) + xmlSchemaFree(WXS_IMPBUCKET(bucket)->schema); + } + xmlFree(bucket); +} + +static xmlSchemaBucketPtr +xmlSchemaBucketCreate(xmlSchemaParserCtxtPtr pctxt, + int type, const xmlChar *targetNamespace) +{ + xmlSchemaBucketPtr ret; + int size; + xmlSchemaPtr mainSchema; + + if (WXS_CONSTRUCTOR(pctxt)->mainSchema == NULL) { + PERROR_INT("xmlSchemaBucketCreate", + "no main schema on constructor"); + return(NULL); + } + mainSchema = WXS_CONSTRUCTOR(pctxt)->mainSchema; + /* Create the schema bucket. */ + if (WXS_IS_BUCKET_INCREDEF(type)) + size = sizeof(xmlSchemaInclude); + else + size = sizeof(xmlSchemaImport); + ret = (xmlSchemaBucketPtr) xmlMalloc(size); + if (ret == NULL) { + xmlSchemaPErrMemory(NULL, "allocating schema bucket", NULL); + return(NULL); + } + memset(ret, 0, size); + ret->targetNamespace = targetNamespace; + ret->type = type; + ret->globals = xmlSchemaItemListCreate(); + if (ret->globals == NULL) { + xmlFree(ret); + return(NULL); + } + ret->locals = xmlSchemaItemListCreate(); + if (ret->locals == NULL) { + xmlFree(ret); + return(NULL); + } + /* + * The following will assure that only the first bucket is marked as + * XML_SCHEMA_SCHEMA_MAIN and it points to the *main* schema. + * For each following import buckets an xmlSchema will be created. + * An xmlSchema will be created for every distinct targetNamespace. + * We assign the targetNamespace to the schemata here. + */ + if (! WXS_HAS_BUCKETS(pctxt)) { + if (WXS_IS_BUCKET_INCREDEF(type)) { + PERROR_INT("xmlSchemaBucketCreate", + "first bucket but it's an include or redefine"); + xmlSchemaBucketFree(ret); + return(NULL); + } + /* Force the type to be XML_SCHEMA_SCHEMA_MAIN. */ + ret->type = XML_SCHEMA_SCHEMA_MAIN; + /* Point to the *main* schema. */ + WXS_CONSTRUCTOR(pctxt)->mainBucket = ret; + WXS_IMPBUCKET(ret)->schema = mainSchema; + /* + * Ensure that the main schema gets a targetNamespace. + */ + mainSchema->targetNamespace = targetNamespace; + } else { + if (type == XML_SCHEMA_SCHEMA_MAIN) { + PERROR_INT("xmlSchemaBucketCreate", + "main bucket but it's not the first one"); + xmlSchemaBucketFree(ret); + return(NULL); + } else if (type == XML_SCHEMA_SCHEMA_IMPORT) { + /* + * Create a schema for imports and assign the + * targetNamespace. + */ + WXS_IMPBUCKET(ret)->schema = xmlSchemaNewSchema(pctxt); + if (WXS_IMPBUCKET(ret)->schema == NULL) { + xmlSchemaBucketFree(ret); + return(NULL); + } + WXS_IMPBUCKET(ret)->schema->targetNamespace = targetNamespace; + } + } + if (WXS_IS_BUCKET_IMPMAIN(type)) { + int res; + /* + * Imports go into the "schemasImports" slot of the main *schema*. + * Note that we create an import entry for the main schema as well; i.e., + * even if there's only one schema, we'll get an import. + */ + if (mainSchema->schemasImports == NULL) { + mainSchema->schemasImports = xmlHashCreateDict(5, + WXS_CONSTRUCTOR(pctxt)->dict); + if (mainSchema->schemasImports == NULL) { + xmlSchemaBucketFree(ret); + return(NULL); + } + } + if (targetNamespace == NULL) + res = xmlHashAddEntry(mainSchema->schemasImports, + XML_SCHEMAS_NO_NAMESPACE, ret); + else + res = xmlHashAddEntry(mainSchema->schemasImports, + targetNamespace, ret); + if (res != 0) { + PERROR_INT("xmlSchemaBucketCreate", + "failed to add the schema bucket to the hash"); + xmlSchemaBucketFree(ret); + return(NULL); + } + } else { + /* Set the @ownerImport of an include bucket. */ + if (WXS_IS_BUCKET_IMPMAIN(WXS_CONSTRUCTOR(pctxt)->bucket->type)) + WXS_INCBUCKET(ret)->ownerImport = + WXS_IMPBUCKET(WXS_CONSTRUCTOR(pctxt)->bucket); + else + WXS_INCBUCKET(ret)->ownerImport = + WXS_INCBUCKET(WXS_CONSTRUCTOR(pctxt)->bucket)->ownerImport; + + /* Includes got into the "includes" slot of the *main* schema. */ + if (mainSchema->includes == NULL) { + mainSchema->includes = xmlSchemaItemListCreate(); + if (mainSchema->includes == NULL) { + xmlSchemaBucketFree(ret); + return(NULL); + } + } + xmlSchemaItemListAdd(mainSchema->includes, ret); + } + /* + * Add to list of all buckets; this is used for lookup + * during schema construction time only. + */ + if (xmlSchemaItemListAdd(WXS_CONSTRUCTOR(pctxt)->buckets, ret) == -1) + return(NULL); + return(ret); +} + +static int +xmlSchemaAddItemSize(xmlSchemaItemListPtr *list, int initialSize, void *item) +{ + if (*list == NULL) { + *list = xmlSchemaItemListCreate(); + if (*list == NULL) + return(-1); + } + xmlSchemaItemListAddSize(*list, initialSize, item); + return(0); +} + +/** + * xmlSchemaFreeAnnot: + * @annot: a schema type structure + * + * Deallocate a annotation structure + */ +static void +xmlSchemaFreeAnnot(xmlSchemaAnnotPtr annot) +{ + if (annot == NULL) + return; + if (annot->next == NULL) { + xmlFree(annot); + } else { + xmlSchemaAnnotPtr prev; + + do { + prev = annot; + annot = annot->next; + xmlFree(prev); + } while (annot != NULL); + } +} + +/** + * xmlSchemaFreeNotation: + * @schema: a schema notation structure + * + * Deallocate a Schema Notation structure. + */ +static void +xmlSchemaFreeNotation(xmlSchemaNotationPtr nota) +{ + if (nota == NULL) + return; + xmlFree(nota); +} + +/** + * xmlSchemaFreeAttribute: + * @attr: an attribute declaration + * + * Deallocates an attribute declaration structure. + */ +static void +xmlSchemaFreeAttribute(xmlSchemaAttributePtr attr) +{ + if (attr == NULL) + return; + if (attr->annot != NULL) + xmlSchemaFreeAnnot(attr->annot); + if (attr->defVal != NULL) + xmlSchemaFreeValue(attr->defVal); + xmlFree(attr); +} + +/** + * xmlSchemaFreeAttributeUse: + * @use: an attribute use + * + * Deallocates an attribute use structure. + */ +static void +xmlSchemaFreeAttributeUse(xmlSchemaAttributeUsePtr use) +{ + if (use == NULL) + return; + if (use->annot != NULL) + xmlSchemaFreeAnnot(use->annot); + if (use->defVal != NULL) + xmlSchemaFreeValue(use->defVal); + xmlFree(use); +} + +/** + * xmlSchemaFreeAttributeUseProhib: + * @prohib: an attribute use prohibition + * + * Deallocates an attribute use structure. + */ +static void +xmlSchemaFreeAttributeUseProhib(xmlSchemaAttributeUseProhibPtr prohib) +{ + if (prohib == NULL) + return; + xmlFree(prohib); +} + +/** + * xmlSchemaFreeWildcardNsSet: + * set: a schema wildcard namespace + * + * Deallocates a list of wildcard constraint structures. + */ +static void +xmlSchemaFreeWildcardNsSet(xmlSchemaWildcardNsPtr set) +{ + xmlSchemaWildcardNsPtr next; + + while (set != NULL) { + next = set->next; + xmlFree(set); + set = next; + } +} + +/** + * xmlSchemaFreeWildcard: + * @wildcard: a wildcard structure + * + * Deallocates a wildcard structure. + */ +void +xmlSchemaFreeWildcard(xmlSchemaWildcardPtr wildcard) +{ + if (wildcard == NULL) + return; + if (wildcard->annot != NULL) + xmlSchemaFreeAnnot(wildcard->annot); + if (wildcard->nsSet != NULL) + xmlSchemaFreeWildcardNsSet(wildcard->nsSet); + if (wildcard->negNsSet != NULL) + xmlFree(wildcard->negNsSet); + xmlFree(wildcard); +} + +/** + * xmlSchemaFreeAttributeGroup: + * @schema: a schema attribute group structure + * + * Deallocate a Schema Attribute Group structure. + */ +static void +xmlSchemaFreeAttributeGroup(xmlSchemaAttributeGroupPtr attrGr) +{ + if (attrGr == NULL) + return; + if (attrGr->annot != NULL) + xmlSchemaFreeAnnot(attrGr->annot); + if (attrGr->attrUses != NULL) + xmlSchemaItemListFree(WXS_LIST_CAST attrGr->attrUses); + xmlFree(attrGr); +} + +/** + * xmlSchemaFreeQNameRef: + * @item: a QName reference structure + * + * Deallocatea a QName reference structure. + */ +static void +xmlSchemaFreeQNameRef(xmlSchemaQNameRefPtr item) +{ + xmlFree(item); +} + +/** + * xmlSchemaFreeTypeLinkList: + * @alink: a type link + * + * Deallocate a list of types. + */ +static void +xmlSchemaFreeTypeLinkList(xmlSchemaTypeLinkPtr link) +{ + xmlSchemaTypeLinkPtr next; + + while (link != NULL) { + next = link->next; + xmlFree(link); + link = next; + } +} + +static void +xmlSchemaFreeIDCStateObjList(xmlSchemaIDCStateObjPtr sto) +{ + xmlSchemaIDCStateObjPtr next; + while (sto != NULL) { + next = sto->next; + if (sto->history != NULL) + xmlFree(sto->history); + if (sto->xpathCtxt != NULL) + xmlFreeStreamCtxt((xmlStreamCtxtPtr) sto->xpathCtxt); + xmlFree(sto); + sto = next; + } +} + +/** + * xmlSchemaFreeIDC: + * @idc: a identity-constraint definition + * + * Deallocates an identity-constraint definition. + */ +static void +xmlSchemaFreeIDC(xmlSchemaIDCPtr idcDef) +{ + xmlSchemaIDCSelectPtr cur, prev; + + if (idcDef == NULL) + return; + if (idcDef->annot != NULL) + xmlSchemaFreeAnnot(idcDef->annot); + /* Selector */ + if (idcDef->selector != NULL) { + if (idcDef->selector->xpathComp != NULL) + xmlFreePattern((xmlPatternPtr) idcDef->selector->xpathComp); + xmlFree(idcDef->selector); + } + /* Fields */ + if (idcDef->fields != NULL) { + cur = idcDef->fields; + do { + prev = cur; + cur = cur->next; + if (prev->xpathComp != NULL) + xmlFreePattern((xmlPatternPtr) prev->xpathComp); + xmlFree(prev); + } while (cur != NULL); + } + xmlFree(idcDef); +} + +/** + * xmlSchemaFreeElement: + * @schema: a schema element structure + * + * Deallocate a Schema Element structure. + */ +static void +xmlSchemaFreeElement(xmlSchemaElementPtr elem) +{ + if (elem == NULL) + return; + if (elem->annot != NULL) + xmlSchemaFreeAnnot(elem->annot); + if (elem->contModel != NULL) + xmlRegFreeRegexp(elem->contModel); + if (elem->defVal != NULL) + xmlSchemaFreeValue(elem->defVal); + xmlFree(elem); +} + +/** + * xmlSchemaFreeFacet: + * @facet: a schema facet structure + * + * Deallocate a Schema Facet structure. + */ +void +xmlSchemaFreeFacet(xmlSchemaFacetPtr facet) +{ + if (facet == NULL) + return; + if (facet->val != NULL) + xmlSchemaFreeValue(facet->val); + if (facet->regexp != NULL) + xmlRegFreeRegexp(facet->regexp); + if (facet->annot != NULL) + xmlSchemaFreeAnnot(facet->annot); + xmlFree(facet); +} + +/** + * xmlSchemaFreeType: + * @type: a schema type structure + * + * Deallocate a Schema Type structure. + */ +void +xmlSchemaFreeType(xmlSchemaTypePtr type) +{ + if (type == NULL) + return; + if (type->annot != NULL) + xmlSchemaFreeAnnot(type->annot); + if (type->facets != NULL) { + xmlSchemaFacetPtr facet, next; + + facet = type->facets; + while (facet != NULL) { + next = facet->next; + xmlSchemaFreeFacet(facet); + facet = next; + } + } + if (type->attrUses != NULL) + xmlSchemaItemListFree((xmlSchemaItemListPtr) type->attrUses); + if (type->memberTypes != NULL) + xmlSchemaFreeTypeLinkList(type->memberTypes); + if (type->facetSet != NULL) { + xmlSchemaFacetLinkPtr next, link; + + link = type->facetSet; + do { + next = link->next; + xmlFree(link); + link = next; + } while (link != NULL); + } + if (type->contModel != NULL) + xmlRegFreeRegexp(type->contModel); + xmlFree(type); +} + +/** + * xmlSchemaFreeModelGroupDef: + * @item: a schema model group definition + * + * Deallocates a schema model group definition. + */ +static void +xmlSchemaFreeModelGroupDef(xmlSchemaModelGroupDefPtr item) +{ + if (item->annot != NULL) + xmlSchemaFreeAnnot(item->annot); + xmlFree(item); +} + +/** + * xmlSchemaFreeModelGroup: + * @item: a schema model group + * + * Deallocates a schema model group structure. + */ +static void +xmlSchemaFreeModelGroup(xmlSchemaModelGroupPtr item) +{ + if (item->annot != NULL) + xmlSchemaFreeAnnot(item->annot); + xmlFree(item); +} + +static void +xmlSchemaComponentListFree(xmlSchemaItemListPtr list) +{ + if ((list == NULL) || (list->nbItems == 0)) + return; + { + xmlSchemaTreeItemPtr item; + xmlSchemaTreeItemPtr *items = (xmlSchemaTreeItemPtr *) list->items; + int i; + + for (i = 0; i < list->nbItems; i++) { + item = items[i]; + if (item == NULL) + continue; + switch (item->type) { + case XML_SCHEMA_TYPE_SIMPLE: + case XML_SCHEMA_TYPE_COMPLEX: + xmlSchemaFreeType((xmlSchemaTypePtr) item); + break; + case XML_SCHEMA_TYPE_ATTRIBUTE: + xmlSchemaFreeAttribute((xmlSchemaAttributePtr) item); + break; + case XML_SCHEMA_TYPE_ATTRIBUTE_USE: + xmlSchemaFreeAttributeUse((xmlSchemaAttributeUsePtr) item); + break; + case XML_SCHEMA_EXTRA_ATTR_USE_PROHIB: + xmlSchemaFreeAttributeUseProhib( + (xmlSchemaAttributeUseProhibPtr) item); + break; + case XML_SCHEMA_TYPE_ELEMENT: + xmlSchemaFreeElement((xmlSchemaElementPtr) item); + break; + case XML_SCHEMA_TYPE_PARTICLE: + if (item->annot != NULL) + xmlSchemaFreeAnnot(item->annot); + xmlFree(item); + break; + case XML_SCHEMA_TYPE_SEQUENCE: + case XML_SCHEMA_TYPE_CHOICE: + case XML_SCHEMA_TYPE_ALL: + xmlSchemaFreeModelGroup((xmlSchemaModelGroupPtr) item); + break; + case XML_SCHEMA_TYPE_ATTRIBUTEGROUP: + xmlSchemaFreeAttributeGroup( + (xmlSchemaAttributeGroupPtr) item); + break; + case XML_SCHEMA_TYPE_GROUP: + xmlSchemaFreeModelGroupDef( + (xmlSchemaModelGroupDefPtr) item); + break; + case XML_SCHEMA_TYPE_ANY: + case XML_SCHEMA_TYPE_ANY_ATTRIBUTE: + xmlSchemaFreeWildcard((xmlSchemaWildcardPtr) item); + break; + case XML_SCHEMA_TYPE_IDC_KEY: + case XML_SCHEMA_TYPE_IDC_UNIQUE: + case XML_SCHEMA_TYPE_IDC_KEYREF: + xmlSchemaFreeIDC((xmlSchemaIDCPtr) item); + break; + case XML_SCHEMA_TYPE_NOTATION: + xmlSchemaFreeNotation((xmlSchemaNotationPtr) item); + break; + case XML_SCHEMA_EXTRA_QNAMEREF: + xmlSchemaFreeQNameRef((xmlSchemaQNameRefPtr) item); + break; + 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; + } + } + list->nbItems = 0; + } +} + +/** + * xmlSchemaFree: + * @schema: a schema structure + * + * Deallocate a Schema structure. + */ +void +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 + * the schema buckets. + */ + if (schema->notaDecl != NULL) + xmlHashFree(schema->notaDecl, NULL); + if (schema->attrDecl != NULL) + xmlHashFree(schema->attrDecl, NULL); + if (schema->attrgrpDecl != NULL) + xmlHashFree(schema->attrgrpDecl, NULL); + if (schema->elemDecl != NULL) + xmlHashFree(schema->elemDecl, NULL); + if (schema->typeDecl != NULL) + xmlHashFree(schema->typeDecl, NULL); + if (schema->groupDecl != NULL) + xmlHashFree(schema->groupDecl, NULL); + if (schema->idcDef != NULL) + xmlHashFree(schema->idcDef, NULL); + + if (schema->schemasImports != NULL) + xmlHashFree(schema->schemasImports, + (xmlHashDeallocator) xmlSchemaBucketFree); + if (schema->includes != NULL) { + xmlSchemaItemListPtr list = (xmlSchemaItemListPtr) schema->includes; + int i; + for (i = 0; i < list->nbItems; i++) { + xmlSchemaBucketFree((xmlSchemaBucketPtr) list->items[i]); + } + xmlSchemaItemListFree(list); + } + if (schema->annot != NULL) + xmlSchemaFreeAnnot(schema->annot); + /* Never free the doc here, since this will be done by the buckets. */ + + xmlDictFree(schema->dict); + xmlFree(schema); +} + +/************************************************************************ + * * + * Debug functions * + * * + ************************************************************************/ + +#ifdef LIBXML_OUTPUT_ENABLED + +static void +xmlSchemaTypeDump(xmlSchemaTypePtr type, FILE * output); /* forward */ + +/** + * xmlSchemaElementDump: + * @elem: an element + * @output: the file output + * + * Dump the element + */ +static void +xmlSchemaElementDump(xmlSchemaElementPtr elem, FILE * output, + const xmlChar * name ATTRIBUTE_UNUSED, + const xmlChar * namespace ATTRIBUTE_UNUSED, + const xmlChar * context ATTRIBUTE_UNUSED) +{ + if (elem == NULL) + return; + + + fprintf(output, "Element"); + if (elem->flags & XML_SCHEMAS_ELEM_GLOBAL) + fprintf(output, " (global)"); + fprintf(output, ": '%s' ", elem->name); + if (namespace != NULL) + fprintf(output, "ns '%s'", namespace); + fprintf(output, "\n"); +#if 0 + if ((elem->minOccurs != 1) || (elem->maxOccurs != 1)) { + fprintf(output, " min %d ", elem->minOccurs); + if (elem->maxOccurs >= UNBOUNDED) + fprintf(output, "max: unbounded\n"); + else if (elem->maxOccurs != 1) + fprintf(output, "max: %d\n", elem->maxOccurs); + else + fprintf(output, "\n"); + } +#endif + /* + * Misc other properties. + */ + if ((elem->flags & XML_SCHEMAS_ELEM_NILLABLE) || + (elem->flags & XML_SCHEMAS_ELEM_ABSTRACT) || + (elem->flags & XML_SCHEMAS_ELEM_FIXED) || + (elem->flags & XML_SCHEMAS_ELEM_DEFAULT)) { + fprintf(output, " props: "); + if (elem->flags & XML_SCHEMAS_ELEM_FIXED) + fprintf(output, "[fixed] "); + if (elem->flags & XML_SCHEMAS_ELEM_DEFAULT) + fprintf(output, "[default] "); + if (elem->flags & XML_SCHEMAS_ELEM_ABSTRACT) + fprintf(output, "[abstract] "); + if (elem->flags & XML_SCHEMAS_ELEM_NILLABLE) + fprintf(output, "[nillable] "); + fprintf(output, "\n"); + } + /* + * Default/fixed value. + */ + if (elem->value != NULL) + fprintf(output, " value: '%s'\n", elem->value); + /* + * Type. + */ + if (elem->namedType != NULL) { + fprintf(output, " type: '%s' ", elem->namedType); + if (elem->namedTypeNs != NULL) + fprintf(output, "ns '%s'\n", elem->namedTypeNs); + else + fprintf(output, "\n"); + } else if (elem->subtypes != NULL) { + /* + * Dump local types. + */ + xmlSchemaTypeDump(elem->subtypes, output); + } + /* + * Substitution group. + */ + if (elem->substGroup != NULL) { + fprintf(output, " substitutionGroup: '%s' ", elem->substGroup); + if (elem->substGroupNs != NULL) + fprintf(output, "ns '%s'\n", elem->substGroupNs); + else + fprintf(output, "\n"); + } +} + +/** + * xmlSchemaAnnotDump: + * @output: the file output + * @annot: a annotation + * + * Dump the annotation + */ +static void +xmlSchemaAnnotDump(FILE * output, xmlSchemaAnnotPtr annot) +{ + xmlChar *content; + + if (annot == NULL) + return; + + content = xmlNodeGetContent(annot->content); + if (content != NULL) { + fprintf(output, " Annot: %s\n", content); + xmlFree(content); + } else + fprintf(output, " Annot: empty\n"); +} + +/** + * xmlSchemaContentModelDump: + * @particle: the schema particle + * @output: the file output + * @depth: the depth used for intentation + * + * Dump a SchemaType structure + */ +static void +xmlSchemaContentModelDump(xmlSchemaParticlePtr particle, FILE * output, int depth) +{ + xmlChar *str = NULL; + xmlSchemaTreeItemPtr term; + char shift[100]; + int i; + + if (particle == NULL) + return; + for (i = 0;((i < depth) && (i < 25));i++) + shift[2 * i] = shift[2 * i + 1] = ' '; + shift[2 * i] = shift[2 * i + 1] = 0; + fprintf(output, "%s", shift); + if (particle->children == NULL) { + fprintf(output, "MISSING particle term\n"); + return; + } + term = particle->children; + if (term == NULL) { + fprintf(output, "(NULL)"); + } else { + switch (term->type) { + case XML_SCHEMA_TYPE_ELEMENT: + fprintf(output, "ELEM '%s'", xmlSchemaFormatQName(&str, + ((xmlSchemaElementPtr)term)->targetNamespace, + ((xmlSchemaElementPtr)term)->name)); + FREE_AND_NULL(str); + break; + case XML_SCHEMA_TYPE_SEQUENCE: + fprintf(output, "SEQUENCE"); + break; + case XML_SCHEMA_TYPE_CHOICE: + fprintf(output, "CHOICE"); + break; + case XML_SCHEMA_TYPE_ALL: + fprintf(output, "ALL"); + break; + case XML_SCHEMA_TYPE_ANY: + fprintf(output, "ANY"); + break; + default: + fprintf(output, "UNKNOWN\n"); + return; + } + } + if (particle->minOccurs != 1) + fprintf(output, " min: %d", particle->minOccurs); + if (particle->maxOccurs >= UNBOUNDED) + fprintf(output, " max: unbounded"); + else if (particle->maxOccurs != 1) + fprintf(output, " max: %d", particle->maxOccurs); + fprintf(output, "\n"); + if (term && + ((term->type == XML_SCHEMA_TYPE_SEQUENCE) || + (term->type == XML_SCHEMA_TYPE_CHOICE) || + (term->type == XML_SCHEMA_TYPE_ALL)) && + (term->children != NULL)) { + xmlSchemaContentModelDump((xmlSchemaParticlePtr) term->children, + output, depth +1); + } + if (particle->next != NULL) + xmlSchemaContentModelDump((xmlSchemaParticlePtr) particle->next, + output, depth); +} + +/** + * xmlSchemaAttrUsesDump: + * @uses: attribute uses list + * @output: the file output + * + * Dumps a list of attribute use components. + */ +static void +xmlSchemaAttrUsesDump(xmlSchemaItemListPtr uses, FILE * output) +{ + xmlSchemaAttributeUsePtr use; + xmlSchemaAttributeUseProhibPtr prohib; + xmlSchemaQNameRefPtr ref; + const xmlChar *name, *tns; + xmlChar *str = NULL; + int i; + + if ((uses == NULL) || (uses->nbItems == 0)) + return; + + fprintf(output, " attributes:\n"); + for (i = 0; i < uses->nbItems; i++) { + use = uses->items[i]; + if (use->type == XML_SCHEMA_EXTRA_ATTR_USE_PROHIB) { + fprintf(output, " [prohibition] "); + prohib = (xmlSchemaAttributeUseProhibPtr) use; + name = prohib->name; + tns = prohib->targetNamespace; + } else if (use->type == XML_SCHEMA_EXTRA_QNAMEREF) { + fprintf(output, " [reference] "); + ref = (xmlSchemaQNameRefPtr) use; + name = ref->name; + tns = ref->targetNamespace; + } else { + fprintf(output, " [use] "); + name = WXS_ATTRUSE_DECL_NAME(use); + tns = WXS_ATTRUSE_DECL_TNS(use); + } + fprintf(output, "'%s'\n", + (const char *) xmlSchemaFormatQName(&str, tns, name)); + FREE_AND_NULL(str); + } +} + +/** + * xmlSchemaTypeDump: + * @output: the file output + * @type: a type structure + * + * Dump a SchemaType structure + */ +static void +xmlSchemaTypeDump(xmlSchemaTypePtr type, FILE * output) +{ + if (type == NULL) { + fprintf(output, "Type: NULL\n"); + return; + } + fprintf(output, "Type: "); + if (type->name != NULL) + fprintf(output, "'%s' ", type->name); + else + fprintf(output, "(no name) "); + if (type->targetNamespace != NULL) + fprintf(output, "ns '%s' ", type->targetNamespace); + switch (type->type) { + case XML_SCHEMA_TYPE_BASIC: + fprintf(output, "[basic] "); + break; + case XML_SCHEMA_TYPE_SIMPLE: + fprintf(output, "[simple] "); + break; + case XML_SCHEMA_TYPE_COMPLEX: + fprintf(output, "[complex] "); + break; + case XML_SCHEMA_TYPE_SEQUENCE: + fprintf(output, "[sequence] "); + break; + case XML_SCHEMA_TYPE_CHOICE: + fprintf(output, "[choice] "); + break; + case XML_SCHEMA_TYPE_ALL: + fprintf(output, "[all] "); + break; + case XML_SCHEMA_TYPE_UR: + fprintf(output, "[ur] "); + break; + case XML_SCHEMA_TYPE_RESTRICTION: + fprintf(output, "[restriction] "); + break; + case XML_SCHEMA_TYPE_EXTENSION: + fprintf(output, "[extension] "); + break; + default: + fprintf(output, "[unknown type %d] ", type->type); + break; + } + fprintf(output, "content: "); + switch (type->contentType) { + case XML_SCHEMA_CONTENT_UNKNOWN: + fprintf(output, "[unknown] "); + break; + case XML_SCHEMA_CONTENT_EMPTY: + fprintf(output, "[empty] "); + break; + case XML_SCHEMA_CONTENT_ELEMENTS: + fprintf(output, "[element] "); + break; + case XML_SCHEMA_CONTENT_MIXED: + fprintf(output, "[mixed] "); + break; + case XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS: + /* not used. */ + break; + case XML_SCHEMA_CONTENT_BASIC: + fprintf(output, "[basic] "); + break; + case XML_SCHEMA_CONTENT_SIMPLE: + fprintf(output, "[simple] "); + break; + case XML_SCHEMA_CONTENT_ANY: + fprintf(output, "[any] "); + break; + } + fprintf(output, "\n"); + if (type->base != NULL) { + fprintf(output, " base type: '%s'", type->base); + if (type->baseNs != NULL) + fprintf(output, " ns '%s'\n", type->baseNs); + else + fprintf(output, "\n"); + } + if (type->attrUses != NULL) + xmlSchemaAttrUsesDump(type->attrUses, output); + if (type->annot != NULL) + xmlSchemaAnnotDump(output, type->annot); +#ifdef DUMP_CONTENT_MODEL + if ((type->type == XML_SCHEMA_TYPE_COMPLEX) && + (type->subtypes != NULL)) { + xmlSchemaContentModelDump((xmlSchemaParticlePtr) type->subtypes, + output, 1); + } +#endif +} + +/** + * xmlSchemaDump: + * @output: the file output + * @schema: a schema structure + * + * Dump a Schema structure. + */ +void +xmlSchemaDump(FILE * output, xmlSchemaPtr schema) +{ + if (output == NULL) + return; + if (schema == NULL) { + fprintf(output, "Schemas: NULL\n"); + return; + } + fprintf(output, "Schemas: "); + if (schema->name != NULL) + fprintf(output, "%s, ", schema->name); + else + fprintf(output, "no name, "); + if (schema->targetNamespace != NULL) + fprintf(output, "%s", (const char *) schema->targetNamespace); + else + fprintf(output, "no target namespace"); + fprintf(output, "\n"); + if (schema->annot != NULL) + xmlSchemaAnnotDump(output, schema->annot); + xmlHashScan(schema->typeDecl, (xmlHashScanner) xmlSchemaTypeDump, + output); + xmlHashScanFull(schema->elemDecl, + (xmlHashScannerFull) xmlSchemaElementDump, output); +} + +#ifdef DEBUG_IDC_NODE_TABLE +/** + * xmlSchemaDebugDumpIDCTable: + * @vctxt: the WXS validation context + * + * Displays the current IDC table for debug purposes. + */ +static void +xmlSchemaDebugDumpIDCTable(FILE * output, + const xmlChar *namespaceName, + const xmlChar *localName, + xmlSchemaPSVIIDCBindingPtr bind) +{ + xmlChar *str = NULL; + const xmlChar *value; + xmlSchemaPSVIIDCNodePtr tab; + xmlSchemaPSVIIDCKeyPtr key; + int i, j, res; + + fprintf(output, "IDC: TABLES on '%s'\n", + xmlSchemaFormatQName(&str, namespaceName, localName)); + FREE_AND_NULL(str) + + if (bind == NULL) + return; + do { + fprintf(output, "IDC: BINDING '%s' (%d)\n", + xmlSchemaGetComponentQName(&str, + bind->definition), bind->nbNodes); + FREE_AND_NULL(str) + for (i = 0; i < bind->nbNodes; i++) { + tab = bind->nodeTable[i]; + fprintf(output, " ( "); + for (j = 0; j < bind->definition->nbFields; j++) { + key = tab->keys[j]; + if ((key != NULL) && (key->val != NULL)) { + res = xmlSchemaGetCanonValue(key->val, &value); + if (res >= 0) + fprintf(output, "'%s' ", value); + else + fprintf(output, "CANON-VALUE-FAILED "); + if (res == 0) + FREE_AND_NULL(value) + } else if (key != NULL) + fprintf(output, "(no val), "); + else + fprintf(output, "(key missing), "); + } + fprintf(output, ")\n"); + } + if (bind->dupls && bind->dupls->nbItems) { + fprintf(output, "IDC: dupls (%d):\n", bind->dupls->nbItems); + for (i = 0; i < bind->dupls->nbItems; i++) { + tab = bind->dupls->items[i]; + fprintf(output, " ( "); + for (j = 0; j < bind->definition->nbFields; j++) { + key = tab->keys[j]; + if ((key != NULL) && (key->val != NULL)) { + res = xmlSchemaGetCanonValue(key->val, &value); + if (res >= 0) + fprintf(output, "'%s' ", value); + else + fprintf(output, "CANON-VALUE-FAILED "); + if (res == 0) + FREE_AND_NULL(value) + } else if (key != NULL) + fprintf(output, "(no val), "); + else + fprintf(output, "(key missing), "); + } + fprintf(output, ")\n"); + } + } + bind = bind->next; + } while (bind != NULL); +} +#endif /* DEBUG_IDC */ +#endif /* LIBXML_OUTPUT_ENABLED */ + +/************************************************************************ + * * + * Utilities * + * * + ************************************************************************/ + +/** + * xmlSchemaGetPropNode: + * @node: the element node + * @name: the name of the attribute + * + * Seeks an attribute with a name of @name in + * no namespace. + * + * Returns the attribute or NULL if not present. + */ +static xmlAttrPtr +xmlSchemaGetPropNode(xmlNodePtr node, const char *name) +{ + xmlAttrPtr prop; + + if ((node == NULL) || (name == NULL)) + return(NULL); + prop = node->properties; + while (prop != NULL) { + if ((prop->ns == NULL) && xmlStrEqual(prop->name, BAD_CAST name)) + return(prop); + prop = prop->next; + } + return (NULL); +} + +/** + * xmlSchemaGetPropNodeNs: + * @node: the element node + * @uri: the uri + * @name: the name of the attribute + * + * Seeks an attribute with a local name of @name and + * a namespace URI of @uri. + * + * Returns the attribute or NULL if not present. + */ +static xmlAttrPtr +xmlSchemaGetPropNodeNs(xmlNodePtr node, const char *uri, const char *name) +{ + xmlAttrPtr prop; + + if ((node == NULL) || (name == NULL)) + return(NULL); + prop = node->properties; + while (prop != NULL) { + if ((prop->ns != NULL) && + xmlStrEqual(prop->name, BAD_CAST name) && + xmlStrEqual(prop->ns->href, BAD_CAST uri)) + return(prop); + prop = prop->next; + } + return (NULL); +} + +static const xmlChar * +xmlSchemaGetNodeContent(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node) +{ + xmlChar *val; + const xmlChar *ret; + + val = xmlNodeGetContent(node); + if (val == NULL) + val = xmlStrdup((xmlChar *)""); + ret = xmlDictLookup(ctxt->dict, val, -1); + xmlFree(val); + return(ret); +} + +static const xmlChar * +xmlSchemaGetNodeContentNoDict(xmlNodePtr node) +{ + return((const xmlChar*) xmlNodeGetContent(node)); +} + +/** + * xmlSchemaGetProp: + * @ctxt: the parser context + * @node: the node + * @name: the property name + * + * Read a attribute value and internalize the string + * + * Returns the string or NULL if not present. + */ +static const xmlChar * +xmlSchemaGetProp(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node, + const char *name) +{ + xmlChar *val; + const xmlChar *ret; + + val = xmlGetNoNsProp(node, BAD_CAST name); + if (val == NULL) + return(NULL); + ret = xmlDictLookup(ctxt->dict, val, -1); + xmlFree(val); + return(ret); +} + +/************************************************************************ + * * + * Parsing functions * + * * + ************************************************************************/ + +#define WXS_FIND_GLOBAL_ITEM(slot) \ + if (xmlStrEqual(nsName, schema->targetNamespace)) { \ + ret = xmlHashLookup(schema->slot, name); \ + if (ret != NULL) goto exit; \ + } \ + if (xmlHashSize(schema->schemasImports) > 1) { \ + xmlSchemaImportPtr import; \ + if (nsName == NULL) \ + import = xmlHashLookup(schema->schemasImports, \ + XML_SCHEMAS_NO_NAMESPACE); \ + else \ + import = xmlHashLookup(schema->schemasImports, nsName); \ + if (import == NULL) \ + goto exit; \ + ret = xmlHashLookup(import->schema->slot, name); \ + } + +/** + * xmlSchemaGetElem: + * @schema: the schema context + * @name: the element name + * @ns: the element namespace + * + * Lookup a global element declaration in the schema. + * + * Returns the element declaration or NULL if not found. + */ +static xmlSchemaElementPtr +xmlSchemaGetElem(xmlSchemaPtr schema, const xmlChar * name, + const xmlChar * nsName) +{ + xmlSchemaElementPtr ret = NULL; + + if ((name == NULL) || (schema == NULL)) + return(NULL); + if (schema != NULL) { + WXS_FIND_GLOBAL_ITEM(elemDecl) + } +exit: +#ifdef DEBUG + if (ret == NULL) { + if (nsName == NULL) + fprintf(stderr, "Unable to lookup element decl. %s", name); + else + fprintf(stderr, "Unable to lookup element decl. %s:%s", name, + nsName); + } +#endif + return (ret); +} + +/** + * xmlSchemaGetType: + * @schema: the main schema + * @name: the type's name + * nsName: the type's namespace + * + * Lookup a type in the schemas or the predefined types + * + * Returns the group definition or NULL if not found. + */ +static xmlSchemaTypePtr +xmlSchemaGetType(xmlSchemaPtr schema, const xmlChar * name, + const xmlChar * nsName) +{ + xmlSchemaTypePtr ret = NULL; + + if (name == NULL) + return (NULL); + /* First try the built-in types. */ + if ((nsName != NULL) && xmlStrEqual(nsName, xmlSchemaNs)) { + ret = xmlSchemaGetPredefinedType(name, nsName); + if (ret != NULL) + goto exit; + /* + * Note that we try the parsed schemas as well here + * since one might have parsed the S4S, which contain more + * than the built-in types. + * TODO: Can we optimize this? + */ + } + if (schema != NULL) { + WXS_FIND_GLOBAL_ITEM(typeDecl) + } +exit: + +#ifdef DEBUG + if (ret == NULL) { + if (nsName == NULL) + fprintf(stderr, "Unable to lookup type %s", name); + else + fprintf(stderr, "Unable to lookup type %s:%s", name, + nsName); + } +#endif + return (ret); +} + +/** + * xmlSchemaGetAttributeDecl: + * @schema: the context of the schema + * @name: the name of the attribute + * @ns: the target namespace of the attribute + * + * Lookup a an attribute in the schema or imported schemas + * + * Returns the attribute declaration or NULL if not found. + */ +static xmlSchemaAttributePtr +xmlSchemaGetAttributeDecl(xmlSchemaPtr schema, const xmlChar * name, + const xmlChar * nsName) +{ + xmlSchemaAttributePtr ret = NULL; + + if ((name == NULL) || (schema == NULL)) + return (NULL); + if (schema != NULL) { + WXS_FIND_GLOBAL_ITEM(attrDecl) + } +exit: +#ifdef DEBUG + if (ret == NULL) { + if (nsName == NULL) + fprintf(stderr, "Unable to lookup attribute %s", name); + else + fprintf(stderr, "Unable to lookup attribute %s:%s", name, + nsName); + } +#endif + return (ret); +} + +/** + * xmlSchemaGetAttributeGroup: + * @schema: the context of the schema + * @name: the name of the attribute group + * @ns: the target namespace of the attribute group + * + * Lookup a an attribute group in the schema or imported schemas + * + * Returns the attribute group definition or NULL if not found. + */ +static xmlSchemaAttributeGroupPtr +xmlSchemaGetAttributeGroup(xmlSchemaPtr schema, const xmlChar * name, + const xmlChar * nsName) +{ + xmlSchemaAttributeGroupPtr ret = NULL; + + if ((name == NULL) || (schema == NULL)) + return (NULL); + if (schema != NULL) { + WXS_FIND_GLOBAL_ITEM(attrgrpDecl) + } +exit: + /* TODO: + if ((ret != NULL) && (ret->redef != NULL)) { + * Return the last redefinition. * + ret = ret->redef; + } + */ +#ifdef DEBUG + if (ret == NULL) { + if (nsName == NULL) + fprintf(stderr, "Unable to lookup attribute group %s", name); + else + fprintf(stderr, "Unable to lookup attribute group %s:%s", name, + nsName); + } +#endif + return (ret); +} + +/** + * xmlSchemaGetGroup: + * @schema: the context of the schema + * @name: the name of the group + * @ns: the target namespace of the group + * + * Lookup a group in the schema or imported schemas + * + * Returns the group definition or NULL if not found. + */ +static xmlSchemaModelGroupDefPtr +xmlSchemaGetGroup(xmlSchemaPtr schema, const xmlChar * name, + const xmlChar * nsName) +{ + xmlSchemaModelGroupDefPtr ret = NULL; + + if ((name == NULL) || (schema == NULL)) + return (NULL); + if (schema != NULL) { + WXS_FIND_GLOBAL_ITEM(groupDecl) + } +exit: + +#ifdef DEBUG + if (ret == NULL) { + if (nsName == NULL) + fprintf(stderr, "Unable to lookup group %s", name); + else + fprintf(stderr, "Unable to lookup group %s:%s", name, + nsName); + } +#endif + return (ret); +} + +static xmlSchemaNotationPtr +xmlSchemaGetNotation(xmlSchemaPtr schema, + const xmlChar *name, + const xmlChar *nsName) +{ + xmlSchemaNotationPtr ret = NULL; + + if ((name == NULL) || (schema == NULL)) + return (NULL); + if (schema != NULL) { + WXS_FIND_GLOBAL_ITEM(notaDecl) + } +exit: + return (ret); +} + +static xmlSchemaIDCPtr +xmlSchemaGetIDC(xmlSchemaPtr schema, + const xmlChar *name, + const xmlChar *nsName) +{ + xmlSchemaIDCPtr ret = NULL; + + if ((name == NULL) || (schema == NULL)) + return (NULL); + if (schema != NULL) { + WXS_FIND_GLOBAL_ITEM(idcDef) + } +exit: + return (ret); +} + +/** + * xmlSchemaGetNamedComponent: + * @schema: the schema + * @name: the name of the group + * @ns: the target namespace of the group + * + * Lookup a group in the schema or imported schemas + * + * Returns the group definition or NULL if not found. + */ +static xmlSchemaBasicItemPtr +xmlSchemaGetNamedComponent(xmlSchemaPtr schema, + xmlSchemaTypeType itemType, + const xmlChar *name, + const xmlChar *targetNs) +{ + switch (itemType) { + case XML_SCHEMA_TYPE_GROUP: + return ((xmlSchemaBasicItemPtr) xmlSchemaGetGroup(schema, + name, targetNs)); + case XML_SCHEMA_TYPE_ELEMENT: + return ((xmlSchemaBasicItemPtr) xmlSchemaGetElem(schema, + name, targetNs)); + default: + TODO + return (NULL); + } +} + +/************************************************************************ + * * + * Parsing functions * + * * + ************************************************************************/ + +#define IS_BLANK_NODE(n) \ + (((n)->type == XML_TEXT_NODE) && (xmlSchemaIsBlank((n)->content, -1))) + +/** + * xmlSchemaIsBlank: + * @str: a string + * @len: the length of the string or -1 + * + * Check if a string is ignorable + * + * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise + */ +static int +xmlSchemaIsBlank(xmlChar * str, int len) +{ + if (str == NULL) + return (1); + if (len < 0) { + while (*str != 0) { + if (!(IS_BLANK_CH(*str))) + return (0); + str++; + } + } else while ((*str != 0) && (len != 0)) { + if (!(IS_BLANK_CH(*str))) + return (0); + str++; + len--; + } + + return (1); +} + +#define WXS_COMP_NAME(c, t) ((t) (c))->name +#define WXS_COMP_TNS(c, t) ((t) (c))->targetNamespace +/* +* xmlSchemaFindRedefCompInGraph: +* ATTENTION TODO: This uses pointer comp. for strings. +*/ +static xmlSchemaBasicItemPtr +xmlSchemaFindRedefCompInGraph(xmlSchemaBucketPtr bucket, + xmlSchemaTypeType type, + const xmlChar *name, + const xmlChar *nsName) +{ + xmlSchemaBasicItemPtr ret; + int i; + + if ((bucket == NULL) || (name == NULL)) + return(NULL); + if ((bucket->globals == NULL) || + (bucket->globals->nbItems == 0)) + goto subschemas; + /* + * Search in global components. + */ + for (i = 0; i < bucket->globals->nbItems; i++) { + ret = bucket->globals->items[i]; + if (ret->type == type) { + switch (type) { + case XML_SCHEMA_TYPE_COMPLEX: + case XML_SCHEMA_TYPE_SIMPLE: + if ((WXS_COMP_NAME(ret, xmlSchemaTypePtr) == name) && + (WXS_COMP_TNS(ret, xmlSchemaTypePtr) == + nsName)) + { + return(ret); + } + break; + case XML_SCHEMA_TYPE_GROUP: + if ((WXS_COMP_NAME(ret, + xmlSchemaModelGroupDefPtr) == name) && + (WXS_COMP_TNS(ret, + xmlSchemaModelGroupDefPtr) == nsName)) + { + return(ret); + } + break; + case XML_SCHEMA_TYPE_ATTRIBUTEGROUP: + if ((WXS_COMP_NAME(ret, + xmlSchemaAttributeGroupPtr) == name) && + (WXS_COMP_TNS(ret, + xmlSchemaAttributeGroupPtr) == nsName)) + { + return(ret); + } + break; + default: + /* Should not be hit. */ + return(NULL); + } + } + } +subschemas: + /* + * Process imported/included schemas. + */ + if (bucket->relations != NULL) { + xmlSchemaSchemaRelationPtr rel = bucket->relations; + + /* + * TODO: Marking the bucket will not avoid multiple searches + * in the same schema, but avoids at least circularity. + */ + bucket->flags |= XML_SCHEMA_BUCKET_MARKED; + do { + if ((rel->bucket != NULL) && + ((rel->bucket->flags & XML_SCHEMA_BUCKET_MARKED) == 0)) { + ret = xmlSchemaFindRedefCompInGraph(rel->bucket, + type, name, nsName); + if (ret != NULL) + return(ret); + } + rel = rel->next; + } while (rel != NULL); + bucket->flags ^= XML_SCHEMA_BUCKET_MARKED; + } + return(NULL); +} + +/** + * xmlSchemaAddNotation: + * @ctxt: a schema parser context + * @schema: the schema being built + * @name: the item name + * + * Add an XML schema annotation declaration + * *WARNING* this interface is highly subject to change + * + * Returns the new struture or NULL in case of error + */ +static xmlSchemaNotationPtr +xmlSchemaAddNotation(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, + const xmlChar *name, const xmlChar *nsName, + xmlNodePtr node ATTRIBUTE_UNUSED) +{ + xmlSchemaNotationPtr ret = NULL; + + if ((ctxt == NULL) || (schema == NULL) || (name == NULL)) + return (NULL); + + ret = (xmlSchemaNotationPtr) xmlMalloc(sizeof(xmlSchemaNotation)); + if (ret == NULL) { + xmlSchemaPErrMemory(ctxt, "add annotation", NULL); + return (NULL); + } + memset(ret, 0, sizeof(xmlSchemaNotation)); + ret->type = XML_SCHEMA_TYPE_NOTATION; + ret->name = name; + ret->targetNamespace = nsName; + /* TODO: do we need the node to be set? + * ret->node = node;*/ + WXS_ADD_GLOBAL(ctxt, ret); + return (ret); +} + +/** + * xmlSchemaAddAttribute: + * @ctxt: a schema parser context + * @schema: the schema being built + * @name: the item name + * @namespace: the namespace + * + * Add an XML schema Attrribute declaration + * *WARNING* this interface is highly subject to change + * + * Returns the new struture or NULL in case of error + */ +static xmlSchemaAttributePtr +xmlSchemaAddAttribute(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, + const xmlChar * name, const xmlChar * nsName, + xmlNodePtr node, int topLevel) +{ + xmlSchemaAttributePtr ret = NULL; + + if ((ctxt == NULL) || (schema == NULL)) + return (NULL); + + ret = (xmlSchemaAttributePtr) xmlMalloc(sizeof(xmlSchemaAttribute)); + if (ret == NULL) { + xmlSchemaPErrMemory(ctxt, "allocating attribute", NULL); + return (NULL); + } + memset(ret, 0, sizeof(xmlSchemaAttribute)); + ret->type = XML_SCHEMA_TYPE_ATTRIBUTE; + ret->node = node; + ret->name = name; + ret->targetNamespace = nsName; + + if (topLevel) + WXS_ADD_GLOBAL(ctxt, ret); + else + WXS_ADD_LOCAL(ctxt, ret); + WXS_ADD_PENDING(ctxt, ret); + return (ret); +} + +/** + * xmlSchemaAddAttributeUse: + * @ctxt: a schema parser context + * @schema: the schema being built + * @name: the item name + * @namespace: the namespace + * + * Add an XML schema Attrribute declaration + * *WARNING* this interface is highly subject to change + * + * Returns the new struture or NULL in case of error + */ +static xmlSchemaAttributeUsePtr +xmlSchemaAddAttributeUse(xmlSchemaParserCtxtPtr pctxt, + xmlNodePtr node) +{ + xmlSchemaAttributeUsePtr ret = NULL; + + if (pctxt == NULL) + return (NULL); + + ret = (xmlSchemaAttributeUsePtr) xmlMalloc(sizeof(xmlSchemaAttributeUse)); + if (ret == NULL) { + xmlSchemaPErrMemory(pctxt, "allocating attribute", NULL); + return (NULL); + } + memset(ret, 0, sizeof(xmlSchemaAttributeUse)); + ret->type = XML_SCHEMA_TYPE_ATTRIBUTE_USE; + ret->node = node; + + WXS_ADD_LOCAL(pctxt, ret); + return (ret); +} + +/* +* xmlSchemaAddRedef: +* +* Adds a redefinition information. This is used at a later stage to: +* resolve references to the redefined components and to check constraints. +*/ +static xmlSchemaRedefPtr +xmlSchemaAddRedef(xmlSchemaParserCtxtPtr pctxt, + xmlSchemaBucketPtr targetBucket, + void *item, + const xmlChar *refName, + const xmlChar *refTargetNs) +{ + xmlSchemaRedefPtr ret; + + ret = (xmlSchemaRedefPtr) + xmlMalloc(sizeof(xmlSchemaRedef)); + if (ret == NULL) { + xmlSchemaPErrMemory(pctxt, + "allocating redefinition info", NULL); + return (NULL); + } + memset(ret, 0, sizeof(xmlSchemaRedef)); + ret->item = item; + ret->targetBucket = targetBucket; + ret->refName = refName; + ret->refTargetNs = refTargetNs; + if (WXS_CONSTRUCTOR(pctxt)->redefs == NULL) + WXS_CONSTRUCTOR(pctxt)->redefs = ret; + else + WXS_CONSTRUCTOR(pctxt)->lastRedef->next = ret; + WXS_CONSTRUCTOR(pctxt)->lastRedef = ret; + + return (ret); +} + +/** + * xmlSchemaAddAttributeGroupDefinition: + * @ctxt: a schema parser context + * @schema: the schema being built + * @name: the item name + * @nsName: the target namespace + * @node: the corresponding node + * + * Add an XML schema Attrribute Group definition. + * + * Returns the new struture or NULL in case of error + */ +static xmlSchemaAttributeGroupPtr +xmlSchemaAddAttributeGroupDefinition(xmlSchemaParserCtxtPtr pctxt, + xmlSchemaPtr schema ATTRIBUTE_UNUSED, + const xmlChar *name, + const xmlChar *nsName, + xmlNodePtr node) +{ + xmlSchemaAttributeGroupPtr ret = NULL; + + if ((pctxt == NULL) || (name == NULL)) + return (NULL); + + ret = (xmlSchemaAttributeGroupPtr) + xmlMalloc(sizeof(xmlSchemaAttributeGroup)); + if (ret == NULL) { + xmlSchemaPErrMemory(pctxt, "allocating attribute group", NULL); + return (NULL); + } + memset(ret, 0, sizeof(xmlSchemaAttributeGroup)); + ret->type = XML_SCHEMA_TYPE_ATTRIBUTEGROUP; + ret->name = name; + ret->targetNamespace = nsName; + ret->node = node; + + /* TODO: Remove the flag. */ + ret->flags |= XML_SCHEMAS_ATTRGROUP_GLOBAL; + if (pctxt->isRedefine) { + pctxt->redef = xmlSchemaAddRedef(pctxt, pctxt->redefined, + ret, name, nsName); + if (pctxt->redef == NULL) { + xmlFree(ret); + return(NULL); + } + pctxt->redefCounter = 0; + } + WXS_ADD_GLOBAL(pctxt, ret); + WXS_ADD_PENDING(pctxt, ret); + return (ret); +} + +/** + * xmlSchemaAddElement: + * @ctxt: a schema parser context + * @schema: the schema being built + * @name: the type name + * @namespace: the type namespace + * + * Add an XML schema Element declaration + * *WARNING* this interface is highly subject to change + * + * Returns the new struture or NULL in case of error + */ +static xmlSchemaElementPtr +xmlSchemaAddElement(xmlSchemaParserCtxtPtr ctxt, + const xmlChar * name, const xmlChar * nsName, + xmlNodePtr node, int topLevel) +{ + xmlSchemaElementPtr ret = NULL; + + if ((ctxt == NULL) || (name == NULL)) + return (NULL); + + ret = (xmlSchemaElementPtr) xmlMalloc(sizeof(xmlSchemaElement)); + if (ret == NULL) { + xmlSchemaPErrMemory(ctxt, "allocating element", NULL); + return (NULL); + } + memset(ret, 0, sizeof(xmlSchemaElement)); + ret->type = XML_SCHEMA_TYPE_ELEMENT; + ret->name = name; + ret->targetNamespace = nsName; + ret->node = node; + + if (topLevel) + WXS_ADD_GLOBAL(ctxt, ret); + else + WXS_ADD_LOCAL(ctxt, ret); + WXS_ADD_PENDING(ctxt, ret); + return (ret); +} + +/** + * xmlSchemaAddType: + * @ctxt: a schema parser context + * @schema: the schema being built + * @name: the item name + * @namespace: the namespace + * + * Add an XML schema item + * *WARNING* this interface is highly subject to change + * + * Returns the new struture or NULL in case of error + */ +static xmlSchemaTypePtr +xmlSchemaAddType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, + xmlSchemaTypeType type, + const xmlChar * name, const xmlChar * nsName, + xmlNodePtr node, int topLevel) +{ + xmlSchemaTypePtr ret = NULL; + + if ((ctxt == NULL) || (schema == NULL)) + return (NULL); + + ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType)); + if (ret == NULL) { + xmlSchemaPErrMemory(ctxt, "allocating type", NULL); + return (NULL); + } + memset(ret, 0, sizeof(xmlSchemaType)); + ret->type = type; + ret->name = name; + ret->targetNamespace = nsName; + ret->node = node; + if (topLevel) { + if (ctxt->isRedefine) { + ctxt->redef = xmlSchemaAddRedef(ctxt, ctxt->redefined, + ret, name, nsName); + if (ctxt->redef == NULL) { + xmlFree(ret); + return(NULL); + } + ctxt->redefCounter = 0; + } + WXS_ADD_GLOBAL(ctxt, ret); + } else + WXS_ADD_LOCAL(ctxt, ret); + WXS_ADD_PENDING(ctxt, ret); + return (ret); +} + +static xmlSchemaQNameRefPtr +xmlSchemaNewQNameRef(xmlSchemaParserCtxtPtr pctxt, + xmlSchemaTypeType refType, + const xmlChar *refName, + const xmlChar *refNs) +{ + xmlSchemaQNameRefPtr ret; + + ret = (xmlSchemaQNameRefPtr) + xmlMalloc(sizeof(xmlSchemaQNameRef)); + if (ret == NULL) { + xmlSchemaPErrMemory(pctxt, + "allocating QName reference item", NULL); + return (NULL); + } + ret->node = NULL; + ret->type = XML_SCHEMA_EXTRA_QNAMEREF; + ret->name = refName; + ret->targetNamespace = refNs; + ret->item = NULL; + ret->itemType = refType; + /* + * Store the reference item in the schema. + */ + WXS_ADD_LOCAL(pctxt, ret); + return (ret); +} + +static xmlSchemaAttributeUseProhibPtr +xmlSchemaAddAttributeUseProhib(xmlSchemaParserCtxtPtr pctxt) +{ + xmlSchemaAttributeUseProhibPtr ret; + + ret = (xmlSchemaAttributeUseProhibPtr) + xmlMalloc(sizeof(xmlSchemaAttributeUseProhib)); + if (ret == NULL) { + xmlSchemaPErrMemory(pctxt, + "allocating attribute use prohibition", NULL); + return (NULL); + } + memset(ret, 0, sizeof(xmlSchemaAttributeUseProhib)); + ret->type = XML_SCHEMA_EXTRA_ATTR_USE_PROHIB; + WXS_ADD_LOCAL(pctxt, ret); + return (ret); +} + + +/** + * xmlSchemaAddModelGroup: + * @ctxt: a schema parser context + * @schema: the schema being built + * @type: the "compositor" type of the model group + * @node: the node in the schema doc + * + * Adds a schema model group + * *WARNING* this interface is highly subject to change + * + * Returns the new struture or NULL in case of error + */ +static xmlSchemaModelGroupPtr +xmlSchemaAddModelGroup(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaPtr schema, + xmlSchemaTypeType type, + xmlNodePtr node) +{ + xmlSchemaModelGroupPtr ret = NULL; + + if ((ctxt == NULL) || (schema == NULL)) + return (NULL); + + ret = (xmlSchemaModelGroupPtr) + xmlMalloc(sizeof(xmlSchemaModelGroup)); + if (ret == NULL) { + xmlSchemaPErrMemory(ctxt, "allocating model group component", + NULL); + return (NULL); + } + memset(ret, 0, sizeof(xmlSchemaModelGroup)); + ret->type = type; + ret->node = node; + WXS_ADD_LOCAL(ctxt, ret); + if ((type == XML_SCHEMA_TYPE_SEQUENCE) || + (type == XML_SCHEMA_TYPE_CHOICE)) + WXS_ADD_PENDING(ctxt, ret); + return (ret); +} + + +/** + * xmlSchemaAddParticle: + * @ctxt: a schema parser context + * @schema: the schema being built + * @node: the corresponding node in the schema doc + * @min: the minOccurs + * @max: the maxOccurs + * + * Adds an XML schema particle component. + * *WARNING* this interface is highly subject to change + * + * Returns the new struture or NULL in case of error + */ +static xmlSchemaParticlePtr +xmlSchemaAddParticle(xmlSchemaParserCtxtPtr ctxt, + xmlNodePtr node, int min, int max) +{ + xmlSchemaParticlePtr ret = NULL; + if (ctxt == NULL) + return (NULL); + +#ifdef DEBUG + fprintf(stderr, "Adding particle component\n"); +#endif + ret = (xmlSchemaParticlePtr) + xmlMalloc(sizeof(xmlSchemaParticle)); + if (ret == NULL) { + xmlSchemaPErrMemory(ctxt, "allocating particle component", + NULL); + return (NULL); + } + ret->type = XML_SCHEMA_TYPE_PARTICLE; + ret->annot = NULL; + ret->node = node; + ret->minOccurs = min; + ret->maxOccurs = max; + ret->next = NULL; + ret->children = NULL; + + WXS_ADD_LOCAL(ctxt, ret); + /* + * Note that addition to pending components will be done locally + * to the specific parsing function, since the most particles + * need not to be fixed up (i.e. the reference to be resolved). + * REMOVED: WXS_ADD_PENDING(ctxt, ret); + */ + return (ret); +} + +/** + * xmlSchemaAddModelGroupDefinition: + * @ctxt: a schema validation context + * @schema: the schema being built + * @name: the group name + * + * Add an XML schema Group definition + * + * Returns the new struture or NULL in case of error + */ +static xmlSchemaModelGroupDefPtr +xmlSchemaAddModelGroupDefinition(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaPtr schema, + const xmlChar *name, + const xmlChar *nsName, + xmlNodePtr node) +{ + xmlSchemaModelGroupDefPtr ret = NULL; + + if ((ctxt == NULL) || (schema == NULL) || (name == NULL)) + return (NULL); + + ret = (xmlSchemaModelGroupDefPtr) + xmlMalloc(sizeof(xmlSchemaModelGroupDef)); + if (ret == NULL) { + xmlSchemaPErrMemory(ctxt, "adding group", NULL); + return (NULL); + } + memset(ret, 0, sizeof(xmlSchemaModelGroupDef)); + ret->name = name; + ret->type = XML_SCHEMA_TYPE_GROUP; + ret->node = node; + ret->targetNamespace = nsName; + + if (ctxt->isRedefine) { + ctxt->redef = xmlSchemaAddRedef(ctxt, ctxt->redefined, + ret, name, nsName); + if (ctxt->redef == NULL) { + xmlFree(ret); + return(NULL); + } + ctxt->redefCounter = 0; + } + WXS_ADD_GLOBAL(ctxt, ret); + WXS_ADD_PENDING(ctxt, ret); + return (ret); +} + +/** + * xmlSchemaNewWildcardNs: + * @ctxt: a schema validation context + * + * Creates a new wildcard namespace constraint. + * + * Returns the new struture or NULL in case of error + */ +static xmlSchemaWildcardNsPtr +xmlSchemaNewWildcardNsConstraint(xmlSchemaParserCtxtPtr ctxt) +{ + xmlSchemaWildcardNsPtr ret; + + ret = (xmlSchemaWildcardNsPtr) + xmlMalloc(sizeof(xmlSchemaWildcardNs)); + if (ret == NULL) { + xmlSchemaPErrMemory(ctxt, "creating wildcard namespace constraint", NULL); + return (NULL); + } + ret->value = NULL; + ret->next = NULL; + return (ret); +} + +static xmlSchemaIDCPtr +xmlSchemaAddIDC(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, + const xmlChar *name, const xmlChar *nsName, + int category, xmlNodePtr node) +{ + xmlSchemaIDCPtr ret = NULL; + + if ((ctxt == NULL) || (schema == NULL) || (name == NULL)) + return (NULL); + + ret = (xmlSchemaIDCPtr) xmlMalloc(sizeof(xmlSchemaIDC)); + if (ret == NULL) { + xmlSchemaPErrMemory(ctxt, + "allocating an identity-constraint definition", NULL); + return (NULL); + } + memset(ret, 0, sizeof(xmlSchemaIDC)); + /* The target namespace of the parent element declaration. */ + ret->targetNamespace = nsName; + ret->name = name; + ret->type = category; + ret->node = node; + + WXS_ADD_GLOBAL(ctxt, ret); + /* + * Only keyrefs need to be fixup up. + */ + if (category == XML_SCHEMA_TYPE_IDC_KEYREF) + WXS_ADD_PENDING(ctxt, ret); + return (ret); +} + +/** + * xmlSchemaAddWildcard: + * @ctxt: a schema validation context + * @schema: a schema + * + * Adds a wildcard. + * It corresponds to a xsd:anyAttribute and xsd:any. + * + * Returns the new struture or NULL in case of error + */ +static xmlSchemaWildcardPtr +xmlSchemaAddWildcard(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, + xmlSchemaTypeType type, xmlNodePtr node) +{ + xmlSchemaWildcardPtr ret = NULL; + + if ((ctxt == NULL) || (schema == NULL)) + return (NULL); + + ret = (xmlSchemaWildcardPtr) xmlMalloc(sizeof(xmlSchemaWildcard)); + if (ret == NULL) { + xmlSchemaPErrMemory(ctxt, "adding wildcard", NULL); + return (NULL); + } + memset(ret, 0, sizeof(xmlSchemaWildcard)); + ret->type = type; + ret->node = node; + WXS_ADD_LOCAL(ctxt, ret); + return (ret); +} + +static void +xmlSchemaSubstGroupFree(xmlSchemaSubstGroupPtr group) +{ + if (group == NULL) + return; + if (group->members != NULL) + xmlSchemaItemListFree(group->members); + xmlFree(group); +} + +static xmlSchemaSubstGroupPtr +xmlSchemaSubstGroupAdd(xmlSchemaParserCtxtPtr pctxt, + xmlSchemaElementPtr head) +{ + xmlSchemaSubstGroupPtr ret; + + /* Init subst group hash. */ + if (WXS_SUBST_GROUPS(pctxt) == NULL) { + WXS_SUBST_GROUPS(pctxt) = xmlHashCreateDict(10, pctxt->dict); + if (WXS_SUBST_GROUPS(pctxt) == NULL) + return(NULL); + } + /* Create a new substitution group. */ + ret = (xmlSchemaSubstGroupPtr) xmlMalloc(sizeof(xmlSchemaSubstGroup)); + if (ret == NULL) { + xmlSchemaPErrMemory(NULL, + "allocating a substitution group container", NULL); + return(NULL); + } + memset(ret, 0, sizeof(xmlSchemaSubstGroup)); + ret->head = head; + /* Create list of members. */ + ret->members = xmlSchemaItemListCreate(); + if (ret->members == NULL) { + xmlSchemaSubstGroupFree(ret); + return(NULL); + } + /* Add subst group to hash. */ + if (xmlHashAddEntry2(WXS_SUBST_GROUPS(pctxt), + head->name, head->targetNamespace, ret) != 0) { + PERROR_INT("xmlSchemaSubstGroupAdd", + "failed to add a new substitution container"); + xmlSchemaSubstGroupFree(ret); + return(NULL); + } + return(ret); +} + +static xmlSchemaSubstGroupPtr +xmlSchemaSubstGroupGet(xmlSchemaParserCtxtPtr pctxt, + xmlSchemaElementPtr head) +{ + if (WXS_SUBST_GROUPS(pctxt) == NULL) + return(NULL); + return(xmlHashLookup2(WXS_SUBST_GROUPS(pctxt), + head->name, head->targetNamespace)); + +} + +/** + * xmlSchemaAddElementSubstitutionMember: + * @pctxt: a schema parser context + * @head: the head of the substitution group + * @member: the new member of the substitution group + * + * Allocate a new annotation structure. + * + * Returns the newly allocated structure or NULL in case or error + */ +static int +xmlSchemaAddElementSubstitutionMember(xmlSchemaParserCtxtPtr pctxt, + xmlSchemaElementPtr head, + xmlSchemaElementPtr member) +{ + xmlSchemaSubstGroupPtr substGroup = NULL; + + if ((pctxt == NULL) || (head == NULL) || (member == NULL)) + return (-1); + + substGroup = xmlSchemaSubstGroupGet(pctxt, head); + if (substGroup == NULL) + substGroup = xmlSchemaSubstGroupAdd(pctxt, head); + if (substGroup == NULL) + return(-1); + if (xmlSchemaItemListAdd(substGroup->members, member) == -1) + return(-1); + return(0); +} + +/************************************************************************ + * * + * Utilities for parsing * + * * + ************************************************************************/ + +/** + * xmlSchemaPValAttrNodeQNameValue: + * @ctxt: a schema parser context + * @schema: the schema context + * @ownerDes: the designation of the parent element + * @ownerItem: the parent as a schema object + * @value: the QName value + * @local: the resulting local part if found, the attribute value otherwise + * @uri: the resulting namespace URI if found + * + * Extracts the local name and the URI of a QName value and validates it. + * This one is intended to be used on attribute values that + * should resolve to schema components. + * + * Returns 0, in case the QName is valid, a positive error code + * if not valid and -1 if an internal error occurs. + */ +static int +xmlSchemaPValAttrNodeQNameValue(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaPtr schema, + xmlSchemaBasicItemPtr ownerItem, + xmlAttrPtr attr, + const xmlChar *value, + const xmlChar **uri, + const xmlChar **local) +{ + const xmlChar *pref; + xmlNsPtr ns; + int len, ret; + + *uri = NULL; + *local = NULL; + ret = xmlValidateQName(value, 1); + if (ret > 0) { + xmlSchemaPSimpleTypeErr(ctxt, + XML_SCHEMAP_S4S_ATTR_INVALID_VALUE, + ownerItem, (xmlNodePtr) attr, + xmlSchemaGetBuiltInType(XML_SCHEMAS_QNAME), + NULL, value, NULL, NULL, NULL); + *local = value; + return (ctxt->err); + } else if (ret < 0) + return (-1); + + if (!strchr((char *) value, ':')) { + ns = xmlSearchNs(attr->doc, attr->parent, NULL); + if (ns) + *uri = xmlDictLookup(ctxt->dict, ns->href, -1); + else if (schema->flags & XML_SCHEMAS_INCLUDING_CONVERT_NS) { + /* TODO: move XML_SCHEMAS_INCLUDING_CONVERT_NS to the + * parser context. */ + /* + * This one takes care of included schemas with no + * target namespace. + */ + *uri = ctxt->targetNamespace; + } + *local = xmlDictLookup(ctxt->dict, value, -1); + return (0); + } + /* + * At this point xmlSplitQName3 has to return a local name. + */ + *local = xmlSplitQName3(value, &len); + *local = xmlDictLookup(ctxt->dict, *local, -1); + pref = xmlDictLookup(ctxt->dict, value, len); + ns = xmlSearchNs(attr->doc, attr->parent, pref); + if (ns == NULL) { + xmlSchemaPSimpleTypeErr(ctxt, + XML_SCHEMAP_S4S_ATTR_INVALID_VALUE, + ownerItem, (xmlNodePtr) attr, + xmlSchemaGetBuiltInType(XML_SCHEMAS_QNAME), NULL, value, + "The value '%s' of simple type 'xs:QName' has no " + "corresponding namespace declaration in scope", value, NULL); + return (ctxt->err); + } else { + *uri = xmlDictLookup(ctxt->dict, ns->href, -1); + } + return (0); +} + +/** + * xmlSchemaPValAttrNodeQName: + * @ctxt: a schema parser context + * @schema: the schema context + * @ownerDes: the designation of the owner element + * @ownerItem: the owner as a schema object + * @attr: the attribute node + * @local: the resulting local part if found, the attribute value otherwise + * @uri: the resulting namespace URI if found + * + * Extracts and validates the QName of an attribute value. + * This one is intended to be used on attribute values that + * should resolve to schema components. + * + * Returns 0, in case the QName is valid, a positive error code + * if not valid and -1 if an internal error occurs. + */ +static int +xmlSchemaPValAttrNodeQName(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaPtr schema, + xmlSchemaBasicItemPtr ownerItem, + xmlAttrPtr attr, + const xmlChar **uri, + const xmlChar **local) +{ + const xmlChar *value; + + value = xmlSchemaGetNodeContent(ctxt, (xmlNodePtr) attr); + return (xmlSchemaPValAttrNodeQNameValue(ctxt, schema, + ownerItem, attr, value, uri, local)); +} + +/** + * xmlSchemaPValAttrQName: + * @ctxt: a schema parser context + * @schema: the schema context + * @ownerDes: the designation of the parent element + * @ownerItem: the owner as a schema object + * @ownerElem: the parent node of the attribute + * @name: the name of the attribute + * @local: the resulting local part if found, the attribute value otherwise + * @uri: the resulting namespace URI if found + * + * Extracts and validates the QName of an attribute value. + * + * Returns 0, in case the QName is valid, a positive error code + * if not valid and -1 if an internal error occurs. + */ +static int +xmlSchemaPValAttrQName(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaPtr schema, + xmlSchemaBasicItemPtr ownerItem, + xmlNodePtr ownerElem, + const char *name, + const xmlChar **uri, + const xmlChar **local) +{ + xmlAttrPtr attr; + + attr = xmlSchemaGetPropNode(ownerElem, name); + if (attr == NULL) { + *local = NULL; + *uri = NULL; + return (0); + } + return (xmlSchemaPValAttrNodeQName(ctxt, schema, + ownerItem, attr, uri, local)); +} + +/** + * xmlSchemaPValAttrID: + * @ctxt: a schema parser context + * @schema: the schema context + * @ownerDes: the designation of the parent element + * @ownerItem: the owner as a schema object + * @ownerElem: the parent node of the attribute + * @name: the name of the attribute + * + * Extracts and validates the ID of an attribute value. + * + * Returns 0, in case the ID is valid, a positive error code + * if not valid and -1 if an internal error occurs. + */ +static int +xmlSchemaPValAttrNodeID(xmlSchemaParserCtxtPtr ctxt, xmlAttrPtr attr) +{ + int ret; + const xmlChar *value; + + if (attr == NULL) + return(0); + value = xmlSchemaGetNodeContentNoDict((xmlNodePtr) attr); + ret = xmlValidateNCName(value, 1); + if (ret == 0) { + /* + * NOTE: the IDness might have already be declared in the DTD + */ + if (attr->atype != XML_ATTRIBUTE_ID) { + xmlIDPtr res; + xmlChar *strip; + + /* + * TODO: Use xmlSchemaStrip here; it's not exported at this + * moment. + */ + strip = xmlSchemaCollapseString(value); + if (strip != NULL) { + xmlFree((xmlChar *) value); + value = strip; + } + res = xmlAddID(NULL, attr->doc, value, attr); + if (res == NULL) { + ret = XML_SCHEMAP_S4S_ATTR_INVALID_VALUE; + xmlSchemaPSimpleTypeErr(ctxt, + XML_SCHEMAP_S4S_ATTR_INVALID_VALUE, + NULL, (xmlNodePtr) 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; + xmlSchemaPSimpleTypeErr(ctxt, + XML_SCHEMAP_S4S_ATTR_INVALID_VALUE, + NULL, (xmlNodePtr) attr, + xmlSchemaGetBuiltInType(XML_SCHEMAS_ID), + NULL, NULL, "The value '%s' of simple type 'xs:ID' is " + "not a valid 'xs:NCName'", + value, NULL); + } + if (value != NULL) + xmlFree((xmlChar *)value); + + return (ret); +} + +static int +xmlSchemaPValAttrID(xmlSchemaParserCtxtPtr ctxt, + xmlNodePtr ownerElem, + const xmlChar *name) +{ + xmlAttrPtr attr; + + attr = xmlSchemaGetPropNode(ownerElem, (const char *) name); + if (attr == NULL) + return(0); + return(xmlSchemaPValAttrNodeID(ctxt, attr)); + +} + +/** + * xmlGetMaxOccurs: + * @ctxt: a schema validation context + * @node: a subtree containing XML Schema informations + * + * Get the maxOccurs property + * + * Returns the default if not found, or the value + */ +static int +xmlGetMaxOccurs(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node, + int min, int max, int def, const char *expected) +{ + const xmlChar *val, *cur; + int ret = 0; + xmlAttrPtr attr; + + attr = xmlSchemaGetPropNode(node, "maxOccurs"); + if (attr == NULL) + return (def); + val = xmlSchemaGetNodeContent(ctxt, (xmlNodePtr) attr); + + if (xmlStrEqual(val, (const xmlChar *) "unbounded")) { + if (max != UNBOUNDED) { + xmlSchemaPSimpleTypeErr(ctxt, + XML_SCHEMAP_S4S_ATTR_INVALID_VALUE, + /* XML_SCHEMAP_INVALID_MINOCCURS, */ + NULL, (xmlNodePtr) attr, NULL, expected, + val, NULL, NULL, NULL); + return (def); + } else + return (UNBOUNDED); /* encoding it with -1 might be another option */ + } + + cur = val; + while (IS_BLANK_CH(*cur)) + cur++; + if (*cur == 0) { + xmlSchemaPSimpleTypeErr(ctxt, + XML_SCHEMAP_S4S_ATTR_INVALID_VALUE, + /* XML_SCHEMAP_INVALID_MINOCCURS, */ + NULL, (xmlNodePtr) attr, NULL, expected, + val, NULL, NULL, NULL); + return (def); + } + while ((*cur >= '0') && (*cur <= '9')) { + ret = ret * 10 + (*cur - '0'); + cur++; + } + while (IS_BLANK_CH(*cur)) + cur++; + /* + * TODO: Restrict the maximal value to Integer. + */ + if ((*cur != 0) || (ret < min) || ((max != -1) && (ret > max))) { + xmlSchemaPSimpleTypeErr(ctxt, + XML_SCHEMAP_S4S_ATTR_INVALID_VALUE, + /* XML_SCHEMAP_INVALID_MINOCCURS, */ + NULL, (xmlNodePtr) attr, NULL, expected, + val, NULL, NULL, NULL); + return (def); + } + return (ret); +} + +/** + * xmlGetMinOccurs: + * @ctxt: a schema validation context + * @node: a subtree containing XML Schema informations + * + * Get the minOccurs property + * + * Returns the default if not found, or the value + */ +static int +xmlGetMinOccurs(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node, + int min, int max, int def, const char *expected) +{ + const xmlChar *val, *cur; + int ret = 0; + xmlAttrPtr attr; + + attr = xmlSchemaGetPropNode(node, "minOccurs"); + if (attr == NULL) + return (def); + val = xmlSchemaGetNodeContent(ctxt, (xmlNodePtr) attr); + cur = val; + while (IS_BLANK_CH(*cur)) + cur++; + if (*cur == 0) { + xmlSchemaPSimpleTypeErr(ctxt, + XML_SCHEMAP_S4S_ATTR_INVALID_VALUE, + /* XML_SCHEMAP_INVALID_MINOCCURS, */ + NULL, (xmlNodePtr) attr, NULL, expected, + val, NULL, NULL, NULL); + return (def); + } + while ((*cur >= '0') && (*cur <= '9')) { + ret = ret * 10 + (*cur - '0'); + cur++; + } + while (IS_BLANK_CH(*cur)) + cur++; + /* + * TODO: Restrict the maximal value to Integer. + */ + if ((*cur != 0) || (ret < min) || ((max != -1) && (ret > max))) { + xmlSchemaPSimpleTypeErr(ctxt, + XML_SCHEMAP_S4S_ATTR_INVALID_VALUE, + /* XML_SCHEMAP_INVALID_MINOCCURS, */ + NULL, (xmlNodePtr) attr, NULL, expected, + val, NULL, NULL, NULL); + return (def); + } + return (ret); +} + +/** + * xmlSchemaPGetBoolNodeValue: + * @ctxt: a schema validation context + * @ownerDes: owner designation + * @ownerItem: the owner as a schema item + * @node: the node holding the value + * + * Converts a boolean string value into 1 or 0. + * + * Returns 0 or 1. + */ +static int +xmlSchemaPGetBoolNodeValue(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaBasicItemPtr ownerItem, + xmlNodePtr node) +{ + xmlChar *value = NULL; + int res = 0; + + value = xmlNodeGetContent(node); + /* + * 3.2.2.1 Lexical representation + * An instance of a datatype that is defined as �boolean� + * can have the following legal literals {true, false, 1, 0}. + */ + if (xmlStrEqual(BAD_CAST value, BAD_CAST "true")) + res = 1; + else if (xmlStrEqual(BAD_CAST value, BAD_CAST "false")) + res = 0; + else if (xmlStrEqual(BAD_CAST value, BAD_CAST "1")) + res = 1; + else if (xmlStrEqual(BAD_CAST value, BAD_CAST "0")) + res = 0; + else { + xmlSchemaPSimpleTypeErr(ctxt, + XML_SCHEMAP_INVALID_BOOLEAN, + ownerItem, node, + xmlSchemaGetBuiltInType(XML_SCHEMAS_BOOLEAN), + NULL, BAD_CAST value, + NULL, NULL, NULL); + } + if (value != NULL) + xmlFree(value); + return (res); +} + +/** + * xmlGetBooleanProp: + * @ctxt: a schema validation context + * @node: a subtree containing XML Schema informations + * @name: the attribute name + * @def: the default value + * + * Evaluate if a boolean property is set + * + * Returns the default if not found, 0 if found to be false, + * 1 if found to be true + */ +static int +xmlGetBooleanProp(xmlSchemaParserCtxtPtr ctxt, + xmlNodePtr node, + const char *name, int def) +{ + const xmlChar *val; + + val = xmlSchemaGetProp(ctxt, node, name); + if (val == NULL) + return (def); + /* + * 3.2.2.1 Lexical representation + * An instance of a datatype that is defined as �boolean� + * can have the following legal literals {true, false, 1, 0}. + */ + if (xmlStrEqual(val, BAD_CAST "true")) + def = 1; + else if (xmlStrEqual(val, BAD_CAST "false")) + def = 0; + else if (xmlStrEqual(val, BAD_CAST "1")) + def = 1; + else if (xmlStrEqual(val, BAD_CAST "0")) + def = 0; + else { + xmlSchemaPSimpleTypeErr(ctxt, + XML_SCHEMAP_INVALID_BOOLEAN, + NULL, + (xmlNodePtr) xmlSchemaGetPropNode(node, name), + xmlSchemaGetBuiltInType(XML_SCHEMAS_BOOLEAN), + NULL, val, NULL, NULL, NULL); + } + return (def); +} + +/************************************************************************ + * * + * Shema extraction from an Infoset * + * * + ************************************************************************/ +static xmlSchemaTypePtr xmlSchemaParseSimpleType(xmlSchemaParserCtxtPtr + ctxt, xmlSchemaPtr schema, + xmlNodePtr node, + int topLevel); +static xmlSchemaTypePtr xmlSchemaParseComplexType(xmlSchemaParserCtxtPtr + ctxt, + xmlSchemaPtr schema, + xmlNodePtr node, + int topLevel); +static xmlSchemaTypePtr xmlSchemaParseRestriction(xmlSchemaParserCtxtPtr + ctxt, + xmlSchemaPtr schema, + xmlNodePtr node, + xmlSchemaTypeType parentType); +static xmlSchemaBasicItemPtr +xmlSchemaParseLocalAttribute(xmlSchemaParserCtxtPtr pctxt, + xmlSchemaPtr schema, + xmlNodePtr node, + xmlSchemaItemListPtr uses, + int parentType); +static xmlSchemaTypePtr xmlSchemaParseList(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaPtr schema, + xmlNodePtr node); +static xmlSchemaWildcardPtr +xmlSchemaParseAnyAttribute(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaPtr schema, xmlNodePtr node); + +/** + * xmlSchemaPValAttrNodeValue: + * + * @ctxt: a schema parser context + * @ownerDes: the designation of the parent element + * @ownerItem: the schema object owner if existent + * @attr: the schema attribute node being validated + * @value: the value + * @type: the built-in type to be validated against + * + * Validates a value against the given built-in type. + * This one is intended to be used internally for validation + * of schema attribute values during parsing of the schema. + * + * Returns 0 if the value is valid, a positive error code + * number otherwise and -1 in case of an internal or API error. + */ +static int +xmlSchemaPValAttrNodeValue(xmlSchemaParserCtxtPtr pctxt, + xmlSchemaBasicItemPtr ownerItem, + xmlAttrPtr attr, + const xmlChar *value, + xmlSchemaTypePtr type) +{ + + int ret = 0; + + /* + * NOTE: Should we move this to xmlschematypes.c? Hmm, but this + * one is really meant to be used internally, so better not. + */ + if ((pctxt == NULL) || (type == NULL) || (attr == NULL)) + return (-1); + if (type->type != XML_SCHEMA_TYPE_BASIC) { + PERROR_INT("xmlSchemaPValAttrNodeValue", + "the given type is not a built-in type"); + return (-1); + } + switch (type->builtInType) { + case XML_SCHEMAS_NCNAME: + case XML_SCHEMAS_QNAME: + case XML_SCHEMAS_ANYURI: + case XML_SCHEMAS_TOKEN: + case XML_SCHEMAS_LANGUAGE: + ret = xmlSchemaValPredefTypeNode(type, value, NULL, + (xmlNodePtr) attr); + break; + default: { + PERROR_INT("xmlSchemaPValAttrNodeValue", + "validation using the given type is not supported while " + "parsing a schema"); + return (-1); + } + } + /* + * TODO: Should we use the S4S error codes instead? + */ + if (ret < 0) { + PERROR_INT("xmlSchemaPValAttrNodeValue", + "failed to validate a schema attribute value"); + return (-1); + } else if (ret > 0) { + if (WXS_IS_LIST(type)) + ret = XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_2; + else + ret = XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_1; + xmlSchemaPSimpleTypeErr(pctxt, + ret, ownerItem, (xmlNodePtr) attr, + type, NULL, value, NULL, NULL, NULL); + } + return (ret); +} + +/** + * xmlSchemaPValAttrNode: + * + * @ctxt: a schema parser context + * @ownerDes: the designation of the parent element + * @ownerItem: the schema object owner if existent + * @attr: the schema attribute node being validated + * @type: the built-in type to be validated against + * @value: the resulting value if any + * + * Extracts and validates a value against the given built-in type. + * This one is intended to be used internally for validation + * of schema attribute values during parsing of the schema. + * + * Returns 0 if the value is valid, a positive error code + * number otherwise and -1 in case of an internal or API error. + */ +static int +xmlSchemaPValAttrNode(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaBasicItemPtr ownerItem, + xmlAttrPtr attr, + xmlSchemaTypePtr type, + const xmlChar **value) +{ + const xmlChar *val; + + if ((ctxt == NULL) || (type == NULL) || (attr == NULL)) + return (-1); + + val = xmlSchemaGetNodeContent(ctxt, (xmlNodePtr) attr); + if (value != NULL) + *value = val; + + return (xmlSchemaPValAttrNodeValue(ctxt, ownerItem, attr, + val, type)); +} + +/** + * xmlSchemaPValAttr: + * + * @ctxt: a schema parser context + * @node: the element node of the attribute + * @ownerDes: the designation of the parent element + * @ownerItem: the schema object owner if existent + * @ownerElem: the owner element node + * @name: the name of the schema attribute node + * @type: the built-in type to be validated against + * @value: the resulting value if any + * + * Extracts and validates a value against the given built-in type. + * This one is intended to be used internally for validation + * of schema attribute values during parsing of the schema. + * + * Returns 0 if the value is valid, a positive error code + * number otherwise and -1 in case of an internal or API error. + */ +static int +xmlSchemaPValAttr(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaBasicItemPtr ownerItem, + xmlNodePtr ownerElem, + const char *name, + xmlSchemaTypePtr type, + const xmlChar **value) +{ + xmlAttrPtr attr; + + if ((ctxt == NULL) || (type == NULL)) { + if (value != NULL) + *value = NULL; + return (-1); + } + if (type->type != XML_SCHEMA_TYPE_BASIC) { + if (value != NULL) + *value = NULL; + xmlSchemaPErr(ctxt, ownerElem, + XML_SCHEMAP_INTERNAL, + "Internal error: xmlSchemaPValAttr, the given " + "type '%s' is not a built-in type.\n", + type->name, NULL); + return (-1); + } + attr = xmlSchemaGetPropNode(ownerElem, name); + if (attr == NULL) { + if (value != NULL) + *value = NULL; + return (0); + } + return (xmlSchemaPValAttrNode(ctxt, ownerItem, attr, + type, value)); +} + +static int +xmlSchemaCheckReference(xmlSchemaParserCtxtPtr pctxt, + xmlSchemaPtr schema ATTRIBUTE_UNUSED, + xmlNodePtr node, + xmlAttrPtr attr, + const xmlChar *namespaceName) +{ + /* TODO: Pointer comparison instead? */ + if (xmlStrEqual(pctxt->targetNamespace, namespaceName)) + return (0); + if (xmlStrEqual(xmlSchemaNs, namespaceName)) + return (0); + /* + * Check if the referenced namespace was ed. + */ + if (WXS_BUCKET(pctxt)->relations != NULL) { + xmlSchemaSchemaRelationPtr rel; + + rel = WXS_BUCKET(pctxt)->relations; + do { + if (WXS_IS_BUCKET_IMPMAIN(rel->type) && + xmlStrEqual(namespaceName, rel->importNamespace)) + return (0); + rel = rel->next; + } while (rel != NULL); + } + /* + * No matching ed namespace found. + */ + { + xmlNodePtr n = (attr != NULL) ? (xmlNodePtr) attr : node; + + if (namespaceName == NULL) + xmlSchemaCustomErr(ACTXT_CAST pctxt, + XML_SCHEMAP_SRC_RESOLVE, n, NULL, + "References from this schema to components in no " + "namespace are not allowed, since not indicated by an " + "import statement", NULL, NULL); + else + xmlSchemaCustomErr(ACTXT_CAST pctxt, + XML_SCHEMAP_SRC_RESOLVE, n, NULL, + "References from this schema to components in the " + "namespace '%s' are not allowed, since not indicated by an " + "import statement", namespaceName, NULL); + } + return (XML_SCHEMAP_SRC_RESOLVE); +} + +/** + * xmlSchemaParseLocalAttributes: + * @ctxt: a schema validation context + * @schema: the schema being built + * @node: a subtree containing XML Schema informations + * @type: the hosting type where the attributes will be anchored + * + * Parses attribute uses and attribute declarations and + * attribute group references. + */ +static int +xmlSchemaParseLocalAttributes(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, + xmlNodePtr *child, xmlSchemaItemListPtr *list, + int parentType, int *hasRefs) +{ + void *item; + + while ((IS_SCHEMA((*child), "attribute")) || + (IS_SCHEMA((*child), "attributeGroup"))) { + if (IS_SCHEMA((*child), "attribute")) { + item = xmlSchemaParseLocalAttribute(ctxt, schema, *child, + *list, parentType); + } else { + item = xmlSchemaParseAttributeGroupRef(ctxt, schema, *child); + if ((item != NULL) && (hasRefs != NULL)) + *hasRefs = 1; + } + if (item != NULL) { + if (*list == NULL) { + /* TODO: Customize grow factor. */ + *list = xmlSchemaItemListCreate(); + if (*list == NULL) + return(-1); + } + if (xmlSchemaItemListAddSize(*list, 2, item) == -1) + return(-1); + } + *child = (*child)->next; + } + return (0); +} + +/** + * xmlSchemaParseAnnotation: + * @ctxt: a schema validation context + * @schema: the schema being built + * @node: a subtree containing XML Schema informations + * + * parse a XML schema Attrribute declaration + * *WARNING* this interface is highly subject to change + * + * Returns -1 in case of error, 0 if the declaration is improper and + * 1 in case of success. + */ +static xmlSchemaAnnotPtr +xmlSchemaParseAnnotation(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node, int needed) +{ + xmlSchemaAnnotPtr ret; + xmlNodePtr child = NULL; + xmlAttrPtr attr; + int barked = 0; + + /* + * INFO: S4S completed. + */ + /* + * id = ID + * {any attributes with non-schema namespace . . .}> + * Content: (appinfo | documentation)* + */ + if ((ctxt == NULL) || (node == NULL)) + return (NULL); + if (needed) + ret = xmlSchemaNewAnnot(ctxt, node); + else + ret = NULL; + attr = node->properties; + while (attr != NULL) { + if (((attr->ns == NULL) && + (!xmlStrEqual(attr->name, BAD_CAST "id"))) || + ((attr->ns != NULL) && + xmlStrEqual(attr->ns->href, xmlSchemaNs))) { + + xmlSchemaPIllegalAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + attr = attr->next; + } + xmlSchemaPValAttrID(ctxt, node, BAD_CAST "id"); + /* + * And now for the children... + */ + child = node->children; + while (child != NULL) { + if (IS_SCHEMA(child, "appinfo")) { + /* TODO: make available the content of "appinfo". */ + /* + * source = anyURI + * {any attributes with non-schema namespace . . .}> + * Content: ({any})* + */ + attr = child->properties; + while (attr != NULL) { + if (((attr->ns == NULL) && + (!xmlStrEqual(attr->name, BAD_CAST "source"))) || + ((attr->ns != NULL) && + xmlStrEqual(attr->ns->href, xmlSchemaNs))) { + + xmlSchemaPIllegalAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + attr = attr->next; + } + xmlSchemaPValAttr(ctxt, NULL, child, "source", + xmlSchemaGetBuiltInType(XML_SCHEMAS_ANYURI), NULL); + child = child->next; + } else if (IS_SCHEMA(child, "documentation")) { + /* TODO: make available the content of "documentation". */ + /* + * source = anyURI + * {any attributes with non-schema namespace . . .}> + * Content: ({any})* + */ + attr = child->properties; + while (attr != NULL) { + if (attr->ns == NULL) { + if (!xmlStrEqual(attr->name, BAD_CAST "source")) { + xmlSchemaPIllegalAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + } else { + if (xmlStrEqual(attr->ns->href, xmlSchemaNs) || + (xmlStrEqual(attr->name, BAD_CAST "lang") && + (!xmlStrEqual(attr->ns->href, XML_XML_NAMESPACE)))) { + + xmlSchemaPIllegalAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + } + attr = attr->next; + } + /* + * Attribute "xml:lang". + */ + attr = xmlSchemaGetPropNodeNs(child, (const char *) XML_XML_NAMESPACE, "lang"); + if (attr != NULL) + xmlSchemaPValAttrNode(ctxt, NULL, attr, + xmlSchemaGetBuiltInType(XML_SCHEMAS_LANGUAGE), NULL); + child = child->next; + } else { + if (!barked) + xmlSchemaPContentErr(ctxt, + XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED, + NULL, node, child, NULL, "(appinfo | documentation)*"); + barked = 1; + child = child->next; + } + } + + return (ret); +} + +/** + * xmlSchemaParseFacet: + * @ctxt: a schema validation context + * @schema: the schema being built + * @node: a subtree containing XML Schema informations + * + * parse a XML schema Facet declaration + * *WARNING* this interface is highly subject to change + * + * Returns the new type structure or NULL in case of error + */ +static xmlSchemaFacetPtr +xmlSchemaParseFacet(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, + xmlNodePtr node) +{ + xmlSchemaFacetPtr facet; + xmlNodePtr child = NULL; + const xmlChar *value; + + if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) + return (NULL); + + facet = xmlSchemaNewFacet(); + if (facet == NULL) { + xmlSchemaPErrMemory(ctxt, "allocating facet", node); + return (NULL); + } + facet->node = node; + value = xmlSchemaGetProp(ctxt, node, "value"); + if (value == NULL) { + xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_FACET_NO_VALUE, + "Facet %s has no value\n", node->name, NULL); + xmlSchemaFreeFacet(facet); + return (NULL); + } + if (IS_SCHEMA(node, "minInclusive")) { + facet->type = XML_SCHEMA_FACET_MININCLUSIVE; + } else if (IS_SCHEMA(node, "minExclusive")) { + facet->type = XML_SCHEMA_FACET_MINEXCLUSIVE; + } else if (IS_SCHEMA(node, "maxInclusive")) { + facet->type = XML_SCHEMA_FACET_MAXINCLUSIVE; + } else if (IS_SCHEMA(node, "maxExclusive")) { + facet->type = XML_SCHEMA_FACET_MAXEXCLUSIVE; + } else if (IS_SCHEMA(node, "totalDigits")) { + facet->type = XML_SCHEMA_FACET_TOTALDIGITS; + } else if (IS_SCHEMA(node, "fractionDigits")) { + facet->type = XML_SCHEMA_FACET_FRACTIONDIGITS; + } else if (IS_SCHEMA(node, "pattern")) { + facet->type = XML_SCHEMA_FACET_PATTERN; + } else if (IS_SCHEMA(node, "enumeration")) { + facet->type = XML_SCHEMA_FACET_ENUMERATION; + } else if (IS_SCHEMA(node, "whiteSpace")) { + facet->type = XML_SCHEMA_FACET_WHITESPACE; + } else if (IS_SCHEMA(node, "length")) { + facet->type = XML_SCHEMA_FACET_LENGTH; + } else if (IS_SCHEMA(node, "maxLength")) { + facet->type = XML_SCHEMA_FACET_MAXLENGTH; + } else if (IS_SCHEMA(node, "minLength")) { + facet->type = XML_SCHEMA_FACET_MINLENGTH; + } else { + xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_FACET_TYPE, + "Unknown facet type %s\n", node->name, NULL); + xmlSchemaFreeFacet(facet); + return (NULL); + } + xmlSchemaPValAttrID(ctxt, node, BAD_CAST "id"); + facet->value = value; + if ((facet->type != XML_SCHEMA_FACET_PATTERN) && + (facet->type != XML_SCHEMA_FACET_ENUMERATION)) { + const xmlChar *fixed; + + fixed = xmlSchemaGetProp(ctxt, node, "fixed"); + if (fixed != NULL) { + if (xmlStrEqual(fixed, BAD_CAST "true")) + facet->fixed = 1; + } + } + child = node->children; + + if (IS_SCHEMA(child, "annotation")) { + facet->annot = xmlSchemaParseAnnotation(ctxt, child, 1); + child = child->next; + } + if (child != NULL) { + xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_FACET_CHILD, + "Facet %s has unexpected child content\n", + node->name, NULL); + } + return (facet); +} + +/** + * xmlSchemaParseWildcardNs: + * @ctxt: a schema parser context + * @wildc: the wildcard, already created + * @node: a subtree containing XML Schema informations + * + * Parses the attribute "processContents" and "namespace" + * of a xsd:anyAttribute and xsd:any. + * *WARNING* this interface is highly subject to change + * + * Returns 0 if everything goes fine, a positive error code + * if something is not valid and -1 if an internal error occurs. + */ +static int +xmlSchemaParseWildcardNs(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaPtr schema ATTRIBUTE_UNUSED, + xmlSchemaWildcardPtr wildc, + xmlNodePtr node) +{ + const xmlChar *pc, *ns, *dictnsItem; + int ret = 0; + xmlChar *nsItem; + xmlSchemaWildcardNsPtr tmp, lastNs = NULL; + xmlAttrPtr attr; + + pc = xmlSchemaGetProp(ctxt, node, "processContents"); + if ((pc == NULL) + || (xmlStrEqual(pc, (const xmlChar *) "strict"))) { + wildc->processContents = XML_SCHEMAS_ANY_STRICT; + } else if (xmlStrEqual(pc, (const xmlChar *) "skip")) { + wildc->processContents = XML_SCHEMAS_ANY_SKIP; + } else if (xmlStrEqual(pc, (const xmlChar *) "lax")) { + wildc->processContents = XML_SCHEMAS_ANY_LAX; + } else { + xmlSchemaPSimpleTypeErr(ctxt, + XML_SCHEMAP_S4S_ATTR_INVALID_VALUE, + NULL, node, + NULL, "(strict | skip | lax)", pc, + NULL, NULL, NULL); + wildc->processContents = XML_SCHEMAS_ANY_STRICT; + ret = XML_SCHEMAP_S4S_ATTR_INVALID_VALUE; + } + /* + * Build the namespace constraints. + */ + attr = xmlSchemaGetPropNode(node, "namespace"); + ns = xmlSchemaGetNodeContent(ctxt, (xmlNodePtr) attr); + if ((attr == NULL) || (xmlStrEqual(ns, BAD_CAST "##any"))) + wildc->any = 1; + else if (xmlStrEqual(ns, BAD_CAST "##other")) { + wildc->negNsSet = xmlSchemaNewWildcardNsConstraint(ctxt); + if (wildc->negNsSet == NULL) { + return (-1); + } + wildc->negNsSet->value = ctxt->targetNamespace; + } else { + const xmlChar *end, *cur; + + cur = ns; + do { + while (IS_BLANK_CH(*cur)) + cur++; + end = cur; + while ((*end != 0) && (!(IS_BLANK_CH(*end)))) + end++; + if (end == cur) + break; + nsItem = xmlStrndup(cur, end - cur); + if ((xmlStrEqual(nsItem, BAD_CAST "##other")) || + (xmlStrEqual(nsItem, BAD_CAST "##any"))) { + xmlSchemaPSimpleTypeErr(ctxt, + XML_SCHEMAP_WILDCARD_INVALID_NS_MEMBER, + NULL, (xmlNodePtr) attr, + NULL, + "((##any | ##other) | List of (xs:anyURI | " + "(##targetNamespace | ##local)))", + nsItem, NULL, NULL, NULL); + ret = XML_SCHEMAP_WILDCARD_INVALID_NS_MEMBER; + } else { + if (xmlStrEqual(nsItem, BAD_CAST "##targetNamespace")) { + dictnsItem = ctxt->targetNamespace; + } else if (xmlStrEqual(nsItem, BAD_CAST "##local")) { + dictnsItem = NULL; + } else { + /* + * Validate the item (anyURI). + */ + xmlSchemaPValAttrNodeValue(ctxt, NULL, attr, + nsItem, xmlSchemaGetBuiltInType(XML_SCHEMAS_ANYURI)); + dictnsItem = xmlDictLookup(ctxt->dict, nsItem, -1); + } + /* + * Avoid dublicate namespaces. + */ + tmp = wildc->nsSet; + while (tmp != NULL) { + if (dictnsItem == tmp->value) + break; + tmp = tmp->next; + } + if (tmp == NULL) { + tmp = xmlSchemaNewWildcardNsConstraint(ctxt); + if (tmp == NULL) { + xmlFree(nsItem); + return (-1); + } + tmp->value = dictnsItem; + tmp->next = NULL; + if (wildc->nsSet == NULL) + wildc->nsSet = tmp; + else if (lastNs != NULL) + lastNs->next = tmp; + lastNs = tmp; + } + + } + xmlFree(nsItem); + cur = end; + } while (*cur != 0); + } + return (ret); +} + +static int +xmlSchemaPCheckParticleCorrect_2(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaParticlePtr item ATTRIBUTE_UNUSED, + xmlNodePtr node, + int minOccurs, + int maxOccurs) { + + if ((maxOccurs == 0) && ( minOccurs == 0)) + return (0); + if (maxOccurs != UNBOUNDED) { + /* + * TODO: Maybe we should better not create the particle, + * if min/max is invalid, since it could confuse the build of the + * content model. + */ + /* + * 3.9.6 Schema Component Constraint: Particle Correct + * + */ + if (maxOccurs < 1) { + /* + * 2.2 {max occurs} must be greater than or equal to 1. + */ + xmlSchemaPCustomAttrErr(ctxt, + XML_SCHEMAP_P_PROPS_CORRECT_2_2, + NULL, NULL, + xmlSchemaGetPropNode(node, "maxOccurs"), + "The value must be greater than or equal to 1"); + return (XML_SCHEMAP_P_PROPS_CORRECT_2_2); + } else if (minOccurs > maxOccurs) { + /* + * 2.1 {min occurs} must not be greater than {max occurs}. + */ + xmlSchemaPCustomAttrErr(ctxt, + XML_SCHEMAP_P_PROPS_CORRECT_2_1, + NULL, NULL, + xmlSchemaGetPropNode(node, "minOccurs"), + "The value must not be greater than the value of 'maxOccurs'"); + return (XML_SCHEMAP_P_PROPS_CORRECT_2_1); + } + } + return (0); +} + +/** + * xmlSchemaParseAny: + * @ctxt: a schema validation context + * @schema: the schema being built + * @node: a subtree containing XML Schema informations + * + * Parsea a XML schema element. A particle and wildcard + * will be created (except if minOccurs==maxOccurs==0, in this case + * nothing will be created). + * *WARNING* this interface is highly subject to change + * + * Returns the particle or NULL in case of error or if minOccurs==maxOccurs==0 + */ +static xmlSchemaParticlePtr +xmlSchemaParseAny(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, + xmlNodePtr node) +{ + xmlSchemaParticlePtr particle; + xmlNodePtr child = NULL; + xmlSchemaWildcardPtr wild; + int min, max; + xmlAttrPtr attr; + xmlSchemaAnnotPtr annot = NULL; + + if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) + return (NULL); + /* + * Check for illegal attributes. + */ + attr = node->properties; + while (attr != NULL) { + if (attr->ns == NULL) { + if ((!xmlStrEqual(attr->name, BAD_CAST "id")) && + (!xmlStrEqual(attr->name, BAD_CAST "minOccurs")) && + (!xmlStrEqual(attr->name, BAD_CAST "maxOccurs")) && + (!xmlStrEqual(attr->name, BAD_CAST "namespace")) && + (!xmlStrEqual(attr->name, BAD_CAST "processContents"))) { + xmlSchemaPIllegalAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + } else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) { + xmlSchemaPIllegalAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + attr = attr->next; + } + xmlSchemaPValAttrID(ctxt, node, BAD_CAST "id"); + /* + * minOccurs/maxOccurs. + */ + max = xmlGetMaxOccurs(ctxt, node, 0, UNBOUNDED, 1, + "(xs:nonNegativeInteger | unbounded)"); + min = xmlGetMinOccurs(ctxt, node, 0, -1, 1, + "xs:nonNegativeInteger"); + xmlSchemaPCheckParticleCorrect_2(ctxt, NULL, node, min, max); + /* + * Create & parse the wildcard. + */ + wild = xmlSchemaAddWildcard(ctxt, schema, XML_SCHEMA_TYPE_ANY, node); + if (wild == NULL) + return (NULL); + xmlSchemaParseWildcardNs(ctxt, schema, wild, node); + /* + * And now for the children... + */ + child = node->children; + if (IS_SCHEMA(child, "annotation")) { + annot = xmlSchemaParseAnnotation(ctxt, child, 1); + child = child->next; + } + if (child != NULL) { + xmlSchemaPContentErr(ctxt, + XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED, + NULL, node, child, + NULL, "(annotation?)"); + } + /* + * No component if minOccurs==maxOccurs==0. + */ + if ((min == 0) && (max == 0)) { + /* Don't free the wildcard, since it's already on the list. */ + return (NULL); + } + /* + * Create the particle. + */ + particle = xmlSchemaAddParticle(ctxt, node, min, max); + if (particle == NULL) + return (NULL); + particle->annot = annot; + particle->children = (xmlSchemaTreeItemPtr) wild; + + return (particle); +} + +/** + * xmlSchemaParseNotation: + * @ctxt: a schema validation context + * @schema: the schema being built + * @node: a subtree containing XML Schema informations + * + * parse a XML schema Notation declaration + * + * Returns the new structure or NULL in case of error + */ +static xmlSchemaNotationPtr +xmlSchemaParseNotation(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, + xmlNodePtr node) +{ + const xmlChar *name; + xmlSchemaNotationPtr ret; + xmlNodePtr child = NULL; + + if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) + return (NULL); + name = xmlSchemaGetProp(ctxt, node, "name"); + if (name == NULL) { + xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_NOTATION_NO_NAME, + "Notation has no name\n", NULL, NULL); + return (NULL); + } + ret = xmlSchemaAddNotation(ctxt, schema, name, + ctxt->targetNamespace, node); + if (ret == NULL) + return (NULL); + xmlSchemaPValAttrID(ctxt, node, BAD_CAST "id"); + + child = node->children; + if (IS_SCHEMA(child, "annotation")) { + ret->annot = xmlSchemaParseAnnotation(ctxt, child, 1); + child = child->next; + } + if (child != NULL) { + xmlSchemaPContentErr(ctxt, + XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED, + NULL, node, child, + NULL, "(annotation?)"); + } + + return (ret); +} + +/** + * xmlSchemaParseAnyAttribute: + * @ctxt: a schema validation context + * @schema: the schema being built + * @node: a subtree containing XML Schema informations + * + * parse a XML schema AnyAttrribute declaration + * *WARNING* this interface is highly subject to change + * + * Returns a wildcard or NULL. + */ +static xmlSchemaWildcardPtr +xmlSchemaParseAnyAttribute(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaPtr schema, xmlNodePtr node) +{ + xmlSchemaWildcardPtr ret; + xmlNodePtr child = NULL; + xmlAttrPtr attr; + + if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) + return (NULL); + + ret = xmlSchemaAddWildcard(ctxt, schema, XML_SCHEMA_TYPE_ANY_ATTRIBUTE, + node); + if (ret == NULL) { + return (NULL); + } + /* + * Check for illegal attributes. + */ + attr = node->properties; + while (attr != NULL) { + if (attr->ns == NULL) { + if ((!xmlStrEqual(attr->name, BAD_CAST "id")) && + (!xmlStrEqual(attr->name, BAD_CAST "namespace")) && + (!xmlStrEqual(attr->name, BAD_CAST "processContents"))) { + xmlSchemaPIllegalAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + } else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) { + xmlSchemaPIllegalAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + attr = attr->next; + } + xmlSchemaPValAttrID(ctxt, node, BAD_CAST "id"); + /* + * Parse the namespace list. + */ + if (xmlSchemaParseWildcardNs(ctxt, schema, ret, node) != 0) + return (NULL); + /* + * And now for the children... + */ + child = node->children; + if (IS_SCHEMA(child, "annotation")) { + ret->annot = xmlSchemaParseAnnotation(ctxt, child, 1); + child = child->next; + } + if (child != NULL) { + xmlSchemaPContentErr(ctxt, + XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED, + NULL, node, child, + NULL, "(annotation?)"); + } + + return (ret); +} + + +/** + * xmlSchemaParseAttribute: + * @ctxt: a schema validation context + * @schema: the schema being built + * @node: a subtree containing XML Schema informations + * + * parse a XML schema Attrribute declaration + * *WARNING* this interface is highly subject to change + * + * Returns the attribute declaration. + */ +static xmlSchemaBasicItemPtr +xmlSchemaParseLocalAttribute(xmlSchemaParserCtxtPtr pctxt, + xmlSchemaPtr schema, + xmlNodePtr node, + xmlSchemaItemListPtr uses, + int parentType) +{ + const xmlChar *attrValue, *name = NULL, *ns = NULL; + xmlSchemaAttributeUsePtr use = NULL; + xmlNodePtr child = NULL; + xmlAttrPtr attr; + const xmlChar *tmpNs = NULL, *tmpName = NULL, *defValue = NULL; + int isRef = 0, occurs = XML_SCHEMAS_ATTR_USE_OPTIONAL; + int nberrors, hasForm = 0, defValueType = 0; + +#define WXS_ATTR_DEF_VAL_DEFAULT 1 +#define WXS_ATTR_DEF_VAL_FIXED 2 + + /* + * 3.2.3 Constraints on XML Representations of Attribute Declarations + */ + + if ((pctxt == NULL) || (schema == NULL) || (node == NULL)) + return (NULL); + attr = xmlSchemaGetPropNode(node, "ref"); + if (attr != NULL) { + if (xmlSchemaPValAttrNodeQName(pctxt, schema, + NULL, attr, &tmpNs, &tmpName) != 0) { + return (NULL); + } + if (xmlSchemaCheckReference(pctxt, schema, node, attr, tmpNs) != 0) + return(NULL); + isRef = 1; + } + nberrors = pctxt->nberrors; + /* + * Check for illegal attributes. + */ + attr = node->properties; + while (attr != NULL) { + if (attr->ns == NULL) { + if (isRef) { + if (xmlStrEqual(attr->name, BAD_CAST "id")) { + xmlSchemaPValAttrNodeID(pctxt, attr); + goto attr_next; + } else if (xmlStrEqual(attr->name, BAD_CAST "ref")) { + goto attr_next; + } + } else { + if (xmlStrEqual(attr->name, BAD_CAST "name")) { + goto attr_next; + } else if (xmlStrEqual(attr->name, BAD_CAST "id")) { + xmlSchemaPValAttrNodeID(pctxt, attr); + goto attr_next; + } else if (xmlStrEqual(attr->name, BAD_CAST "type")) { + xmlSchemaPValAttrNodeQName(pctxt, schema, NULL, + attr, &tmpNs, &tmpName); + goto attr_next; + } else if (xmlStrEqual(attr->name, BAD_CAST "form")) { + /* + * Evaluate the target namespace + */ + hasForm = 1; + attrValue = xmlSchemaGetNodeContent(pctxt, + (xmlNodePtr) attr); + if (xmlStrEqual(attrValue, BAD_CAST "qualified")) { + ns = pctxt->targetNamespace; + } else if (!xmlStrEqual(attrValue, BAD_CAST "unqualified")) + { + xmlSchemaPSimpleTypeErr(pctxt, + XML_SCHEMAP_S4S_ATTR_INVALID_VALUE, + NULL, (xmlNodePtr) attr, + NULL, "(qualified | unqualified)", + attrValue, NULL, NULL, NULL); + } + goto attr_next; + } + } + if (xmlStrEqual(attr->name, BAD_CAST "use")) { + + attrValue = xmlSchemaGetNodeContent(pctxt, (xmlNodePtr) attr); + /* TODO: Maybe we need to normalize the value beforehand. */ + if (xmlStrEqual(attrValue, BAD_CAST "optional")) + occurs = XML_SCHEMAS_ATTR_USE_OPTIONAL; + else if (xmlStrEqual(attrValue, BAD_CAST "prohibited")) + occurs = XML_SCHEMAS_ATTR_USE_PROHIBITED; + else if (xmlStrEqual(attrValue, BAD_CAST "required")) + occurs = XML_SCHEMAS_ATTR_USE_REQUIRED; + else { + xmlSchemaPSimpleTypeErr(pctxt, + XML_SCHEMAP_INVALID_ATTR_USE, + NULL, (xmlNodePtr) attr, + NULL, "(optional | prohibited | required)", + attrValue, NULL, NULL, NULL); + } + goto attr_next; + } else if (xmlStrEqual(attr->name, BAD_CAST "default")) { + /* + * 3.2.3 : 1 + * default and fixed must not both be present. + */ + if (defValue) { + xmlSchemaPMutualExclAttrErr(pctxt, + XML_SCHEMAP_SRC_ATTRIBUTE_1, + NULL, attr, "default", "fixed"); + } else { + defValue = xmlSchemaGetNodeContent(pctxt, (xmlNodePtr) attr); + defValueType = WXS_ATTR_DEF_VAL_DEFAULT; + } + goto attr_next; + } else if (xmlStrEqual(attr->name, BAD_CAST "fixed")) { + /* + * 3.2.3 : 1 + * default and fixed must not both be present. + */ + if (defValue) { + xmlSchemaPMutualExclAttrErr(pctxt, + XML_SCHEMAP_SRC_ATTRIBUTE_1, + NULL, attr, "default", "fixed"); + } else { + defValue = xmlSchemaGetNodeContent(pctxt, (xmlNodePtr) attr); + defValueType = WXS_ATTR_DEF_VAL_FIXED; + } + goto attr_next; + } + } else if (! xmlStrEqual(attr->ns->href, xmlSchemaNs)) + goto attr_next; + + xmlSchemaPIllegalAttrErr(pctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + +attr_next: + attr = attr->next; + } + /* + * 3.2.3 : 2 + * If default and use are both present, use must have + * the actual value optional. + */ + if ((defValueType == WXS_ATTR_DEF_VAL_DEFAULT) && + (occurs != XML_SCHEMAS_ATTR_USE_OPTIONAL)) { + xmlSchemaPSimpleTypeErr(pctxt, + XML_SCHEMAP_SRC_ATTRIBUTE_2, + NULL, node, NULL, + "(optional | prohibited | required)", NULL, + "The value of the attribute 'use' must be 'optional' " + "if the attribute 'default' is present", + NULL, NULL); + } + /* + * We want correct attributes. + */ + if (nberrors != pctxt->nberrors) + return(NULL); + if (! isRef) { + xmlSchemaAttributePtr attrDecl; + + /* TODO: move XML_SCHEMAS_QUALIF_ATTR to the parser. */ + if ((! hasForm) && (schema->flags & XML_SCHEMAS_QUALIF_ATTR)) + ns = pctxt->targetNamespace; + /* + * 3.2.6 Schema Component Constraint: xsi: Not Allowed + * TODO: Move this to the component layer. + */ + if (xmlStrEqual(ns, xmlSchemaInstanceNs)) { + xmlSchemaCustomErr(ACTXT_CAST pctxt, + XML_SCHEMAP_NO_XSI, + node, NULL, + "The target namespace must not match '%s'", + xmlSchemaInstanceNs, NULL); + } + attr = xmlSchemaGetPropNode(node, "name"); + if (attr == NULL) { + xmlSchemaPMissingAttrErr(pctxt, XML_SCHEMAP_S4S_ATTR_MISSING, + NULL, node, "name", NULL); + return (NULL); + } + if (xmlSchemaPValAttrNode(pctxt, NULL, attr, + xmlSchemaGetBuiltInType(XML_SCHEMAS_NCNAME), &name) != 0) { + return (NULL); + } + /* + * 3.2.6 Schema Component Constraint: xmlns Not Allowed + * TODO: Move this to the component layer. + */ + if (xmlStrEqual(name, BAD_CAST "xmlns")) { + xmlSchemaPSimpleTypeErr(pctxt, + XML_SCHEMAP_NO_XMLNS, + NULL, (xmlNodePtr) attr, + xmlSchemaGetBuiltInType(XML_SCHEMAS_NCNAME), NULL, NULL, + "The value of the attribute must not match 'xmlns'", + NULL, NULL); + return (NULL); + } + if (occurs == XML_SCHEMAS_ATTR_USE_PROHIBITED) + goto check_children; + /* + * Create the attribute use component. + */ + use = xmlSchemaAddAttributeUse(pctxt, node); + if (use == NULL) + return(NULL); + use->occurs = occurs; + /* + * Create the attribute declaration. + */ + attrDecl = xmlSchemaAddAttribute(pctxt, schema, name, ns, node, 0); + if (attrDecl == NULL) + return (NULL); + if (tmpName != NULL) { + attrDecl->typeName = tmpName; + attrDecl->typeNs = tmpNs; + } + use->attrDecl = attrDecl; + /* + * Value constraint. + */ + if (defValue != NULL) { + attrDecl->defValue = defValue; + if (defValueType == WXS_ATTR_DEF_VAL_FIXED) + attrDecl->flags |= XML_SCHEMAS_ATTR_FIXED; + } + } else if (occurs != XML_SCHEMAS_ATTR_USE_PROHIBITED) { + xmlSchemaQNameRefPtr ref; + + /* + * Create the attribute use component. + */ + use = xmlSchemaAddAttributeUse(pctxt, node); + if (use == NULL) + return(NULL); + /* + * We need to resolve the reference at later stage. + */ + WXS_ADD_PENDING(pctxt, use); + use->occurs = occurs; + /* + * Create a QName reference to the attribute declaration. + */ + ref = xmlSchemaNewQNameRef(pctxt, XML_SCHEMA_TYPE_ATTRIBUTE, + tmpName, tmpNs); + if (ref == NULL) + return(NULL); + /* + * Assign the reference. This will be substituted for the + * referenced attribute declaration when the QName is resolved. + */ + use->attrDecl = WXS_ATTR_CAST ref; + /* + * Value constraint. + */ + if (defValue != NULL) + use->defValue = defValue; + if (defValueType == WXS_ATTR_DEF_VAL_FIXED) + use->flags |= XML_SCHEMA_ATTR_USE_FIXED; + } + +check_children: + /* + * And now for the children... + */ + child = node->children; + if (occurs == XML_SCHEMAS_ATTR_USE_PROHIBITED) { + xmlSchemaAttributeUseProhibPtr prohib; + + if (IS_SCHEMA(child, "annotation")) { + xmlSchemaParseAnnotation(pctxt, child, 0); + child = child->next; + } + if (child != NULL) { + xmlSchemaPContentErr(pctxt, + XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED, + NULL, node, child, NULL, + "(annotation?)"); + } + /* + * Check for pointlessness of attribute prohibitions. + */ + if (parentType == XML_SCHEMA_TYPE_ATTRIBUTEGROUP) { + xmlSchemaCustomWarning(ACTXT_CAST pctxt, + XML_SCHEMAP_WARN_ATTR_POINTLESS_PROH, + node, NULL, + "Skipping attribute use prohibition, since it is " + "pointless inside an ", + NULL, NULL, NULL); + return(NULL); + } else if (parentType == XML_SCHEMA_TYPE_EXTENSION) { + xmlSchemaCustomWarning(ACTXT_CAST pctxt, + XML_SCHEMAP_WARN_ATTR_POINTLESS_PROH, + node, NULL, + "Skipping attribute use prohibition, since it is " + "pointless when extending a type", + NULL, NULL, NULL); + return(NULL); + } + if (! isRef) { + tmpName = name; + tmpNs = ns; + } + /* + * Check for duplicate attribute prohibitions. + */ + if (uses) { + int i; + + for (i = 0; i < uses->nbItems; i++) { + use = uses->items[i]; + if ((use->type == XML_SCHEMA_EXTRA_ATTR_USE_PROHIB) && + (tmpName == (WXS_ATTR_PROHIB_CAST use)->name) && + (tmpNs == (WXS_ATTR_PROHIB_CAST use)->targetNamespace)) + { + xmlChar *str = NULL; + + xmlSchemaCustomWarning(ACTXT_CAST pctxt, + XML_SCHEMAP_WARN_ATTR_POINTLESS_PROH, + node, NULL, + "Skipping duplicate attribute use prohibition '%s'", + xmlSchemaFormatQName(&str, tmpNs, tmpName), + NULL, NULL); + FREE_AND_NULL(str) + return(NULL); + } + } + } + /* + * Create the attribute prohibition helper component. + */ + prohib = xmlSchemaAddAttributeUseProhib(pctxt); + if (prohib == NULL) + return(NULL); + prohib->node = node; + prohib->name = tmpName; + prohib->targetNamespace = tmpNs; + if (isRef) { + /* + * We need at least to resolve to the attribute declaration. + */ + WXS_ADD_PENDING(pctxt, prohib); + } + return(WXS_BASIC_CAST prohib); + } else { + if (IS_SCHEMA(child, "annotation")) { + /* + * TODO: Should this go into the attr decl? + */ + use->annot = xmlSchemaParseAnnotation(pctxt, child, 1); + child = child->next; + } + if (isRef) { + if (child != NULL) { + if (IS_SCHEMA(child, "simpleType")) + /* + * 3.2.3 : 3.2 + * If ref is present, then all of , + * form and type must be absent. + */ + xmlSchemaPContentErr(pctxt, + XML_SCHEMAP_SRC_ATTRIBUTE_3_2, + NULL, node, child, NULL, + "(annotation?)"); + else + xmlSchemaPContentErr(pctxt, + XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED, + NULL, node, child, NULL, + "(annotation?)"); + } + } else { + if (IS_SCHEMA(child, "simpleType")) { + if (WXS_ATTRUSE_DECL(use)->typeName != NULL) { + /* + * 3.2.3 : 4 + * type and must not both be present. + */ + xmlSchemaPContentErr(pctxt, XML_SCHEMAP_SRC_ATTRIBUTE_4, + NULL, node, child, + "The attribute 'type' and the child " + "are mutually exclusive", NULL); + } else + WXS_ATTRUSE_TYPEDEF(use) = + xmlSchemaParseSimpleType(pctxt, schema, child, 0); + child = child->next; + } + if (child != NULL) + xmlSchemaPContentErr(pctxt, XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED, + NULL, node, child, NULL, + "(annotation?, simpleType?)"); + } + } + return (WXS_BASIC_CAST use); +} + + +static xmlSchemaAttributePtr +xmlSchemaParseGlobalAttribute(xmlSchemaParserCtxtPtr pctxt, + xmlSchemaPtr schema, + xmlNodePtr node) +{ + const xmlChar *attrValue; + xmlSchemaAttributePtr ret; + xmlNodePtr child = NULL; + xmlAttrPtr attr; + + /* + * Note that the w3c spec assumes the schema to be validated with schema + * for schemas beforehand. + * + * 3.2.3 Constraints on XML Representations of Attribute Declarations + */ + if ((pctxt == NULL) || (schema == NULL) || (node == NULL)) + return (NULL); + /* + * 3.2.3 : 3.1 + * One of ref or name must be present, but not both + */ + attr = xmlSchemaGetPropNode(node, "name"); + if (attr == NULL) { + xmlSchemaPMissingAttrErr(pctxt, XML_SCHEMAP_S4S_ATTR_MISSING, + NULL, node, "name", NULL); + return (NULL); + } + if (xmlSchemaPValAttrNode(pctxt, NULL, attr, + xmlSchemaGetBuiltInType(XML_SCHEMAS_NCNAME), &attrValue) != 0) { + return (NULL); + } + /* + * 3.2.6 Schema Component Constraint: xmlns Not Allowed + * TODO: Move this to the component layer. + */ + if (xmlStrEqual(attrValue, BAD_CAST "xmlns")) { + xmlSchemaPSimpleTypeErr(pctxt, + XML_SCHEMAP_NO_XMLNS, + NULL, (xmlNodePtr) attr, + xmlSchemaGetBuiltInType(XML_SCHEMAS_NCNAME), NULL, NULL, + "The value of the attribute must not match 'xmlns'", + NULL, NULL); + return (NULL); + } + /* + * 3.2.6 Schema Component Constraint: xsi: Not Allowed + * TODO: Move this to the component layer. + * Or better leave it here and add it to the component layer + * if we have a schema construction API. + */ + if (xmlStrEqual(pctxt->targetNamespace, xmlSchemaInstanceNs)) { + xmlSchemaCustomErr(ACTXT_CAST pctxt, + XML_SCHEMAP_NO_XSI, node, NULL, + "The target namespace must not match '%s'", + xmlSchemaInstanceNs, NULL); + } + + ret = xmlSchemaAddAttribute(pctxt, schema, attrValue, + pctxt->targetNamespace, node, 1); + if (ret == NULL) + return (NULL); + ret->flags |= XML_SCHEMAS_ATTR_GLOBAL; + + /* + * Check for illegal attributes. + */ + attr = node->properties; + while (attr != NULL) { + if (attr->ns == NULL) { + if ((!xmlStrEqual(attr->name, BAD_CAST "id")) && + (!xmlStrEqual(attr->name, BAD_CAST "default")) && + (!xmlStrEqual(attr->name, BAD_CAST "fixed")) && + (!xmlStrEqual(attr->name, BAD_CAST "name")) && + (!xmlStrEqual(attr->name, BAD_CAST "type"))) + { + xmlSchemaPIllegalAttrErr(pctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + } else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) { + xmlSchemaPIllegalAttrErr(pctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + attr = attr->next; + } + xmlSchemaPValAttrQName(pctxt, schema, NULL, + node, "type", &ret->typeNs, &ret->typeName); + + xmlSchemaPValAttrID(pctxt, node, BAD_CAST "id"); + /* + * Attribute "fixed". + */ + ret->defValue = xmlSchemaGetProp(pctxt, node, "fixed"); + if (ret->defValue != NULL) + ret->flags |= XML_SCHEMAS_ATTR_FIXED; + /* + * Attribute "default". + */ + attr = xmlSchemaGetPropNode(node, "default"); + if (attr != NULL) { + /* + * 3.2.3 : 1 + * default and fixed must not both be present. + */ + if (ret->flags & XML_SCHEMAS_ATTR_FIXED) { + xmlSchemaPMutualExclAttrErr(pctxt, XML_SCHEMAP_SRC_ATTRIBUTE_1, + WXS_BASIC_CAST ret, attr, "default", "fixed"); + } else + ret->defValue = xmlSchemaGetNodeContent(pctxt, (xmlNodePtr) attr); + } + /* + * And now for the children... + */ + child = node->children; + if (IS_SCHEMA(child, "annotation")) { + ret->annot = xmlSchemaParseAnnotation(pctxt, child, 1); + child = child->next; + } + if (IS_SCHEMA(child, "simpleType")) { + if (ret->typeName != NULL) { + /* + * 3.2.3 : 4 + * type and must not both be present. + */ + xmlSchemaPContentErr(pctxt, XML_SCHEMAP_SRC_ATTRIBUTE_4, + NULL, node, child, + "The attribute 'type' and the child " + "are mutually exclusive", NULL); + } else + ret->subtypes = xmlSchemaParseSimpleType(pctxt, schema, child, 0); + child = child->next; + } + if (child != NULL) + xmlSchemaPContentErr(pctxt, XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED, + NULL, node, child, NULL, + "(annotation?, simpleType?)"); + + return (ret); +} + +/** + * xmlSchemaParseAttributeGroupRef: + * @ctxt: a schema validation context + * @schema: the schema being built + * @node: a subtree containing XML Schema informations + * + * Parse an attribute group definition reference. + * Note that a reference to an attribute group does not + * correspond to any component at all. + * *WARNING* this interface is highly subject to change + * + * Returns the attribute group or NULL in case of error. + */ +static xmlSchemaQNameRefPtr +xmlSchemaParseAttributeGroupRef(xmlSchemaParserCtxtPtr pctxt, + xmlSchemaPtr schema, + xmlNodePtr node) +{ + xmlSchemaQNameRefPtr ret; + xmlNodePtr child = NULL; + xmlAttrPtr attr; + const xmlChar *refNs = NULL, *ref = NULL; + + if ((pctxt == NULL) || (schema == NULL) || (node == NULL)) + return (NULL); + + attr = xmlSchemaGetPropNode(node, "ref"); + if (attr == NULL) { + xmlSchemaPMissingAttrErr(pctxt, + XML_SCHEMAP_S4S_ATTR_MISSING, + NULL, node, "ref", NULL); + return (NULL); + } + xmlSchemaPValAttrNodeQName(pctxt, schema, + NULL, attr, &refNs, &ref); + if (xmlSchemaCheckReference(pctxt, schema, node, attr, refNs) != 0) + return(NULL); + + /* + * Check for illegal attributes. + */ + attr = node->properties; + while (attr != NULL) { + if (attr->ns == NULL) { + if ((!xmlStrEqual(attr->name, BAD_CAST "ref")) && + (!xmlStrEqual(attr->name, BAD_CAST "id"))) + { + xmlSchemaPIllegalAttrErr(pctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + } else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) { + xmlSchemaPIllegalAttrErr(pctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + attr = attr->next; + } + /* Attribute ID */ + xmlSchemaPValAttrID(pctxt, node, BAD_CAST "id"); + + /* + * And now for the children... + */ + child = node->children; + if (IS_SCHEMA(child, "annotation")) { + /* + * TODO: We do not have a place to store the annotation, do we? + */ + xmlSchemaParseAnnotation(pctxt, child, 0); + child = child->next; + } + if (child != NULL) { + xmlSchemaPContentErr(pctxt, + XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED, + NULL, node, child, NULL, + "(annotation?)"); + } + + /* + * Handle attribute group redefinitions. + */ + if (pctxt->isRedefine && pctxt->redef && + (pctxt->redef->item->type == + XML_SCHEMA_TYPE_ATTRIBUTEGROUP) && + (ref == pctxt->redef->refName) && + (refNs == pctxt->redef->refTargetNs)) + { + /* + * SPEC src-redefine: + * (7.1) "If it has an among its contents + * the �actual value� of whose ref [attribute] is the same + * as the �actual value� of its own name attribute plus + * target namespace, then it must have exactly one such group." + */ + if (pctxt->redefCounter != 0) { + xmlChar *str = NULL; + + xmlSchemaCustomErr(ACTXT_CAST pctxt, + XML_SCHEMAP_SRC_REDEFINE, node, NULL, + "The redefining attribute group definition " + "'%s' must not contain more than one " + "reference to the redefined definition", + xmlSchemaFormatQName(&str, refNs, ref), NULL); + FREE_AND_NULL(str); + return(NULL); + } + pctxt->redefCounter++; + /* + * URGENT TODO: How to ensure that the reference will not be + * handled by the normal component resolution mechanism? + */ + ret = xmlSchemaNewQNameRef(pctxt, + XML_SCHEMA_TYPE_ATTRIBUTEGROUP, ref, refNs); + if (ret == NULL) + return(NULL); + ret->node = node; + pctxt->redef->reference = WXS_BASIC_CAST ret; + } else { + /* + * Create a QName-reference helper component. We will substitute this + * component for the attribute uses of the referenced attribute group + * definition. + */ + ret = xmlSchemaNewQNameRef(pctxt, + XML_SCHEMA_TYPE_ATTRIBUTEGROUP, ref, refNs); + if (ret == NULL) + return(NULL); + ret->node = node; + /* Add to pending items, to be able to resolve the reference. */ + WXS_ADD_PENDING(pctxt, ret); + } + return (ret); +} + +/** + * xmlSchemaParseAttributeGroupDefinition: + * @pctxt: a schema validation context + * @schema: the schema being built + * @node: a subtree containing XML Schema informations + * + * parse a XML schema Attribute Group declaration + * *WARNING* this interface is highly subject to change + * + * Returns the attribute group definition or NULL in case of error. + */ +static xmlSchemaAttributeGroupPtr +xmlSchemaParseAttributeGroupDefinition(xmlSchemaParserCtxtPtr pctxt, + xmlSchemaPtr schema, + xmlNodePtr node) +{ + const xmlChar *name; + xmlSchemaAttributeGroupPtr ret; + xmlNodePtr child = NULL; + xmlAttrPtr attr; + int hasRefs = 0; + + if ((pctxt == NULL) || (schema == NULL) || (node == NULL)) + return (NULL); + + attr = xmlSchemaGetPropNode(node, "name"); + if (attr == NULL) { + xmlSchemaPMissingAttrErr(pctxt, + XML_SCHEMAP_S4S_ATTR_MISSING, + NULL, node, "name", NULL); + return (NULL); + } + /* + * The name is crucial, exit if invalid. + */ + if (xmlSchemaPValAttrNode(pctxt, + NULL, attr, + xmlSchemaGetBuiltInType(XML_SCHEMAS_NCNAME), &name) != 0) { + return (NULL); + } + ret = xmlSchemaAddAttributeGroupDefinition(pctxt, schema, + name, pctxt->targetNamespace, node); + if (ret == NULL) + return (NULL); + /* + * Check for illegal attributes. + */ + attr = node->properties; + while (attr != NULL) { + if (attr->ns == NULL) { + if ((!xmlStrEqual(attr->name, BAD_CAST "name")) && + (!xmlStrEqual(attr->name, BAD_CAST "id"))) + { + xmlSchemaPIllegalAttrErr(pctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + } else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) { + xmlSchemaPIllegalAttrErr(pctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + attr = attr->next; + } + /* Attribute ID */ + xmlSchemaPValAttrID(pctxt, node, BAD_CAST "id"); + /* + * And now for the children... + */ + child = node->children; + if (IS_SCHEMA(child, "annotation")) { + ret->annot = xmlSchemaParseAnnotation(pctxt, child, 1); + child = child->next; + } + /* + * Parse contained attribute decls/refs. + */ + if (xmlSchemaParseLocalAttributes(pctxt, schema, &child, + (xmlSchemaItemListPtr *) &(ret->attrUses), + XML_SCHEMA_TYPE_ATTRIBUTEGROUP, &hasRefs) == -1) + return(NULL); + if (hasRefs) + ret->flags |= XML_SCHEMAS_ATTRGROUP_HAS_REFS; + /* + * Parse the attribute wildcard. + */ + if (IS_SCHEMA(child, "anyAttribute")) { + ret->attributeWildcard = xmlSchemaParseAnyAttribute(pctxt, + schema, child); + child = child->next; + } + if (child != NULL) { + xmlSchemaPContentErr(pctxt, + XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED, + NULL, node, child, NULL, + "(annotation?, ((attribute | attributeGroup)*, anyAttribute?))"); + } + return (ret); +} + +/** + * xmlSchemaPValAttrFormDefault: + * @value: the value + * @flags: the flags to be modified + * @flagQualified: the specific flag for "qualified" + * + * Returns 0 if the value is valid, 1 otherwise. + */ +static int +xmlSchemaPValAttrFormDefault(const xmlChar *value, + int *flags, + int flagQualified) +{ + if (xmlStrEqual(value, BAD_CAST "qualified")) { + if ((*flags & flagQualified) == 0) + *flags |= flagQualified; + } else if (!xmlStrEqual(value, BAD_CAST "unqualified")) + return (1); + + return (0); +} + +/** + * xmlSchemaPValAttrBlockFinal: + * @value: the value + * @flags: the flags to be modified + * @flagAll: the specific flag for "#all" + * @flagExtension: the specific flag for "extension" + * @flagRestriction: the specific flag for "restriction" + * @flagSubstitution: the specific flag for "substitution" + * @flagList: the specific flag for "list" + * @flagUnion: the specific flag for "union" + * + * Validates the value of the attribute "final" and "block". The value + * is converted into the specified flag values and returned in @flags. + * + * Returns 0 if the value is valid, 1 otherwise. + */ + +static int +xmlSchemaPValAttrBlockFinal(const xmlChar *value, + int *flags, + int flagAll, + int flagExtension, + int flagRestriction, + int flagSubstitution, + int flagList, + int flagUnion) +{ + int ret = 0; + + /* + * TODO: This does not check for dublicate entries. + */ + if ((flags == NULL) || (value == NULL)) + return (-1); + if (value[0] == 0) + return (0); + if (xmlStrEqual(value, BAD_CAST "#all")) { + if (flagAll != -1) + *flags |= flagAll; + else { + if (flagExtension != -1) + *flags |= flagExtension; + if (flagRestriction != -1) + *flags |= flagRestriction; + if (flagSubstitution != -1) + *flags |= flagSubstitution; + if (flagList != -1) + *flags |= flagList; + if (flagUnion != -1) + *flags |= flagUnion; + } + } else { + const xmlChar *end, *cur = value; + xmlChar *item; + + do { + while (IS_BLANK_CH(*cur)) + cur++; + end = cur; + while ((*end != 0) && (!(IS_BLANK_CH(*end)))) + end++; + if (end == cur) + break; + item = xmlStrndup(cur, end - cur); + if (xmlStrEqual(item, BAD_CAST "extension")) { + if (flagExtension != -1) { + if ((*flags & flagExtension) == 0) + *flags |= flagExtension; + } else + ret = 1; + } else if (xmlStrEqual(item, BAD_CAST "restriction")) { + if (flagRestriction != -1) { + if ((*flags & flagRestriction) == 0) + *flags |= flagRestriction; + } else + ret = 1; + } else if (xmlStrEqual(item, BAD_CAST "substitution")) { + if (flagSubstitution != -1) { + if ((*flags & flagSubstitution) == 0) + *flags |= flagSubstitution; + } else + ret = 1; + } else if (xmlStrEqual(item, BAD_CAST "list")) { + if (flagList != -1) { + if ((*flags & flagList) == 0) + *flags |= flagList; + } else + ret = 1; + } else if (xmlStrEqual(item, BAD_CAST "union")) { + if (flagUnion != -1) { + if ((*flags & flagUnion) == 0) + *flags |= flagUnion; + } else + ret = 1; + } else + ret = 1; + if (item != NULL) + xmlFree(item); + cur = end; + } while ((ret == 0) && (*cur != 0)); + } + + return (ret); +} + +static int +xmlSchemaCheckCSelectorXPath(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaIDCPtr idc, + xmlSchemaIDCSelectPtr selector, + xmlAttrPtr attr, + int isField) +{ + xmlNodePtr node; + + /* + * c-selector-xpath: + * Schema Component Constraint: Selector Value OK + * + * TODO: 1 The {selector} must be a valid XPath expression, as defined + * in [XPath]. + */ + if (selector == NULL) { + xmlSchemaPErr(ctxt, idc->node, + XML_SCHEMAP_INTERNAL, + "Internal error: xmlSchemaCheckCSelectorXPath, " + "the selector is not specified.\n", NULL, NULL); + return (-1); + } + if (attr == NULL) + node = idc->node; + else + node = (xmlNodePtr) attr; + if (selector->xpath == NULL) { + xmlSchemaPCustomErr(ctxt, + /* TODO: Adjust error code. */ + XML_SCHEMAP_S4S_ATTR_INVALID_VALUE, + NULL, node, + "The XPath expression of the selector is not valid", NULL); + return (XML_SCHEMAP_S4S_ATTR_INVALID_VALUE); + } else { + const xmlChar **nsArray = NULL; + xmlNsPtr *nsList = NULL; + /* + * Compile the XPath expression. + */ + /* + * TODO: We need the array of in-scope namespaces for compilation. + * TODO: Call xmlPatterncompile with different options for selector/ + * field. + */ + if (attr == NULL) + nsList = NULL; + else + nsList = xmlGetNsList(attr->doc, attr->parent); + /* + * Build an array of prefixes and namespaces. + */ + if (nsList != NULL) { + int i, count = 0; + + for (i = 0; nsList[i] != NULL; i++) + count++; + + nsArray = (const xmlChar **) xmlMalloc( + (count * 2 + 1) * sizeof(const xmlChar *)); + if (nsArray == NULL) { + xmlSchemaPErrMemory(ctxt, "allocating a namespace array", + NULL); + xmlFree(nsList); + return (-1); + } + for (i = 0; i < count; i++) { + nsArray[2 * i] = nsList[i]->href; + nsArray[2 * i + 1] = nsList[i]->prefix; + } + nsArray[count * 2] = NULL; + xmlFree(nsList); + } + /* + * TODO: Differentiate between "selector" and "field". + */ + if (isField) + selector->xpathComp = (void *) xmlPatterncompile(selector->xpath, + NULL, XML_PATTERN_XSFIELD, nsArray); + else + selector->xpathComp = (void *) xmlPatterncompile(selector->xpath, + NULL, XML_PATTERN_XSSEL, nsArray); + if (nsArray != NULL) + xmlFree((xmlChar **) nsArray); + + if (selector->xpathComp == NULL) { + xmlSchemaPCustomErr(ctxt, + /* TODO: Adjust error code? */ + XML_SCHEMAP_S4S_ATTR_INVALID_VALUE, + NULL, node, + "The XPath expression '%s' could not be " + "compiled", selector->xpath); + return (XML_SCHEMAP_S4S_ATTR_INVALID_VALUE); + } + } + return (0); +} + +#define ADD_ANNOTATION(annot) \ + xmlSchemaAnnotPtr cur = item->annot; \ + if (item->annot == NULL) { \ + item->annot = annot; \ + return (annot); \ + } \ + cur = item->annot; \ + if (cur->next != NULL) { \ + cur = cur->next; \ + } \ + cur->next = annot; + +/** + * xmlSchemaAssignAnnotation: + * @item: the schema component + * @annot: the annotation + * + * Adds the annotation to the given schema component. + * + * Returns the given annotaion. + */ +static xmlSchemaAnnotPtr +xmlSchemaAddAnnotation(xmlSchemaAnnotItemPtr annItem, + xmlSchemaAnnotPtr annot) +{ + if ((annItem == NULL) || (annot == NULL)) + return (NULL); + switch (annItem->type) { + case XML_SCHEMA_TYPE_ELEMENT: { + xmlSchemaElementPtr item = (xmlSchemaElementPtr) annItem; + ADD_ANNOTATION(annot) + } + break; + case XML_SCHEMA_TYPE_ATTRIBUTE: { + xmlSchemaAttributePtr item = (xmlSchemaAttributePtr) annItem; + ADD_ANNOTATION(annot) + } + break; + case XML_SCHEMA_TYPE_ANY_ATTRIBUTE: + case XML_SCHEMA_TYPE_ANY: { + xmlSchemaWildcardPtr item = (xmlSchemaWildcardPtr) annItem; + ADD_ANNOTATION(annot) + } + break; + case XML_SCHEMA_TYPE_PARTICLE: + case XML_SCHEMA_TYPE_IDC_KEY: + case XML_SCHEMA_TYPE_IDC_KEYREF: + case XML_SCHEMA_TYPE_IDC_UNIQUE: { + xmlSchemaAnnotItemPtr item = (xmlSchemaAnnotItemPtr) annItem; + ADD_ANNOTATION(annot) + } + break; + case XML_SCHEMA_TYPE_ATTRIBUTEGROUP: { + xmlSchemaAttributeGroupPtr item = + (xmlSchemaAttributeGroupPtr) annItem; + ADD_ANNOTATION(annot) + } + break; + case XML_SCHEMA_TYPE_NOTATION: { + xmlSchemaNotationPtr item = (xmlSchemaNotationPtr) annItem; + ADD_ANNOTATION(annot) + } + break; + case XML_SCHEMA_FACET_MININCLUSIVE: + case XML_SCHEMA_FACET_MINEXCLUSIVE: + case XML_SCHEMA_FACET_MAXINCLUSIVE: + case XML_SCHEMA_FACET_MAXEXCLUSIVE: + case XML_SCHEMA_FACET_TOTALDIGITS: + case XML_SCHEMA_FACET_FRACTIONDIGITS: + case XML_SCHEMA_FACET_PATTERN: + case XML_SCHEMA_FACET_ENUMERATION: + case XML_SCHEMA_FACET_WHITESPACE: + case XML_SCHEMA_FACET_LENGTH: + case XML_SCHEMA_FACET_MAXLENGTH: + case XML_SCHEMA_FACET_MINLENGTH: { + xmlSchemaFacetPtr item = (xmlSchemaFacetPtr) annItem; + ADD_ANNOTATION(annot) + } + break; + case XML_SCHEMA_TYPE_SIMPLE: + case XML_SCHEMA_TYPE_COMPLEX: { + xmlSchemaTypePtr item = (xmlSchemaTypePtr) annItem; + ADD_ANNOTATION(annot) + } + break; + case XML_SCHEMA_TYPE_GROUP: { + xmlSchemaModelGroupDefPtr item = (xmlSchemaModelGroupDefPtr) annItem; + ADD_ANNOTATION(annot) + } + break; + case XML_SCHEMA_TYPE_SEQUENCE: + case XML_SCHEMA_TYPE_CHOICE: + case XML_SCHEMA_TYPE_ALL: { + xmlSchemaModelGroupPtr item = (xmlSchemaModelGroupPtr) annItem; + ADD_ANNOTATION(annot) + } + break; + default: + xmlSchemaPCustomErr(NULL, + XML_SCHEMAP_INTERNAL, + NULL, NULL, + "Internal error: xmlSchemaAddAnnotation, " + "The item is not a annotated schema component", NULL); + break; + } + return (annot); +} + +/** + * xmlSchemaParseIDCSelectorAndField: + * @ctxt: a schema validation context + * @schema: the schema being built + * @node: a subtree containing XML Schema informations + * + * Parses a XML Schema identity-contraint definition's + * and elements. + * + * Returns the parsed identity-constraint definition. + */ +static xmlSchemaIDCSelectPtr +xmlSchemaParseIDCSelectorAndField(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaIDCPtr idc, + xmlNodePtr node, + int isField) +{ + xmlSchemaIDCSelectPtr item; + xmlNodePtr child = NULL; + xmlAttrPtr attr; + + /* + * Check for illegal attributes. + */ + attr = node->properties; + while (attr != NULL) { + if (attr->ns == NULL) { + if ((!xmlStrEqual(attr->name, BAD_CAST "id")) && + (!xmlStrEqual(attr->name, BAD_CAST "xpath"))) { + xmlSchemaPIllegalAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + } else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) { + xmlSchemaPIllegalAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + attr = attr->next; + } + /* + * Create the item. + */ + item = (xmlSchemaIDCSelectPtr) xmlMalloc(sizeof(xmlSchemaIDCSelect)); + if (item == NULL) { + xmlSchemaPErrMemory(ctxt, + "allocating a 'selector' of an identity-constraint definition", + NULL); + return (NULL); + } + memset(item, 0, sizeof(xmlSchemaIDCSelect)); + /* + * Attribute "xpath" (mandatory). + */ + attr = xmlSchemaGetPropNode(node, "xpath"); + if (attr == NULL) { + xmlSchemaPMissingAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_MISSING, + NULL, node, + "name", NULL); + } else { + item->xpath = xmlSchemaGetNodeContent(ctxt, (xmlNodePtr) attr); + /* + * URGENT TODO: "field"s have an other syntax than "selector"s. + */ + + if (xmlSchemaCheckCSelectorXPath(ctxt, idc, item, attr, + isField) == -1) { + xmlSchemaPErr(ctxt, + (xmlNodePtr) attr, + XML_SCHEMAP_INTERNAL, + "Internal error: xmlSchemaParseIDCSelectorAndField, " + "validating the XPath expression of a IDC selector.\n", + NULL, NULL); + } + + } + xmlSchemaPValAttrID(ctxt, node, BAD_CAST "id"); + /* + * And now for the children... + */ + child = node->children; + if (IS_SCHEMA(child, "annotation")) { + /* + * Add the annotation to the parent IDC. + */ + xmlSchemaAddAnnotation((xmlSchemaAnnotItemPtr) idc, + xmlSchemaParseAnnotation(ctxt, child, 1)); + child = child->next; + } + if (child != NULL) { + xmlSchemaPContentErr(ctxt, + XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED, + NULL, node, child, + NULL, "(annotation?)"); + } + + return (item); +} + +/** + * xmlSchemaParseIDC: + * @ctxt: a schema validation context + * @schema: the schema being built + * @node: a subtree containing XML Schema informations + * + * Parses a XML Schema identity-contraint definition. + * + * Returns the parsed identity-constraint definition. + */ +static xmlSchemaIDCPtr +xmlSchemaParseIDC(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaPtr schema, + xmlNodePtr node, + xmlSchemaTypeType idcCategory, + const xmlChar *targetNamespace) +{ + xmlSchemaIDCPtr item = NULL; + xmlNodePtr child = NULL; + xmlAttrPtr attr; + const xmlChar *name = NULL; + xmlSchemaIDCSelectPtr field = NULL, lastField = NULL; + + /* + * Check for illegal attributes. + */ + attr = node->properties; + while (attr != NULL) { + if (attr->ns == NULL) { + if ((!xmlStrEqual(attr->name, BAD_CAST "id")) && + (!xmlStrEqual(attr->name, BAD_CAST "name")) && + ((idcCategory != XML_SCHEMA_TYPE_IDC_KEYREF) || + (!xmlStrEqual(attr->name, BAD_CAST "refer")))) { + xmlSchemaPIllegalAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + } else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) { + xmlSchemaPIllegalAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + attr = attr->next; + } + /* + * Attribute "name" (mandatory). + */ + attr = xmlSchemaGetPropNode(node, "name"); + if (attr == NULL) { + xmlSchemaPMissingAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_MISSING, + NULL, node, + "name", NULL); + return (NULL); + } else if (xmlSchemaPValAttrNode(ctxt, + NULL, attr, + xmlSchemaGetBuiltInType(XML_SCHEMAS_NCNAME), &name) != 0) { + return (NULL); + } + /* Create the component. */ + item = xmlSchemaAddIDC(ctxt, schema, name, targetNamespace, + idcCategory, node); + if (item == NULL) + return(NULL); + + xmlSchemaPValAttrID(ctxt, node, BAD_CAST "id"); + if (idcCategory == XML_SCHEMA_TYPE_IDC_KEYREF) { + /* + * Attribute "refer" (mandatory). + */ + attr = xmlSchemaGetPropNode(node, "refer"); + if (attr == NULL) { + xmlSchemaPMissingAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_MISSING, + NULL, node, + "refer", NULL); + } else { + /* + * Create a reference item. + */ + item->ref = xmlSchemaNewQNameRef(ctxt, XML_SCHEMA_TYPE_IDC_KEY, + NULL, NULL); + if (item->ref == NULL) + return (NULL); + xmlSchemaPValAttrNodeQName(ctxt, schema, + NULL, attr, + &(item->ref->targetNamespace), + &(item->ref->name)); + xmlSchemaCheckReference(ctxt, schema, node, attr, + item->ref->targetNamespace); + } + } + /* + * And now for the children... + */ + child = node->children; + if (IS_SCHEMA(child, "annotation")) { + item->annot = xmlSchemaParseAnnotation(ctxt, child, 1); + child = child->next; + } + if (child == NULL) { + xmlSchemaPContentErr(ctxt, + XML_SCHEMAP_S4S_ELEM_MISSING, + NULL, node, child, + "A child element is missing", + "(annotation?, (selector, field+))"); + } + /* + * Child element . + */ + if (IS_SCHEMA(child, "selector")) { + item->selector = xmlSchemaParseIDCSelectorAndField(ctxt, + item, child, 0); + child = child->next; + /* + * Child elements . + */ + if (IS_SCHEMA(child, "field")) { + do { + field = xmlSchemaParseIDCSelectorAndField(ctxt, + item, child, 1); + if (field != NULL) { + field->index = item->nbFields; + item->nbFields++; + if (lastField != NULL) + lastField->next = field; + else + item->fields = field; + lastField = field; + } + child = child->next; + } while (IS_SCHEMA(child, "field")); + } else { + xmlSchemaPContentErr(ctxt, + XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED, + NULL, node, child, + NULL, "(annotation?, (selector, field+))"); + } + } + if (child != NULL) { + xmlSchemaPContentErr(ctxt, + XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED, + NULL, node, child, + NULL, "(annotation?, (selector, field+))"); + } + + return (item); +} + +/** + * xmlSchemaParseElement: + * @ctxt: a schema validation context + * @schema: the schema being built + * @node: a subtree containing XML Schema informations + * @topLevel: indicates if this is global declaration + * + * Parses a XML schema element declaration. + * *WARNING* this interface is highly subject to change + * + * Returns the element declaration or a particle; NULL in case + * of an error or if the particle has minOccurs==maxOccurs==0. + */ +static xmlSchemaBasicItemPtr +xmlSchemaParseElement(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, + xmlNodePtr node, int *isElemRef, int topLevel) +{ + xmlSchemaElementPtr decl = NULL; + xmlSchemaParticlePtr particle = NULL; + xmlSchemaAnnotPtr annot = NULL; + xmlNodePtr child = NULL; + xmlAttrPtr attr, nameAttr; + int min, max, isRef = 0; + xmlChar *des = NULL; + + /* 3.3.3 Constraints on XML Representations of Element Declarations */ + /* TODO: Complete implementation of 3.3.6 */ + + if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) + return (NULL); + + if (isElemRef != NULL) + *isElemRef = 0; + /* + * If we get a "ref" attribute on a local we will assume it's + * a reference - even if there's a "name" attribute; this seems to be more + * robust. + */ + nameAttr = xmlSchemaGetPropNode(node, "name"); + attr = xmlSchemaGetPropNode(node, "ref"); + if ((topLevel) || (attr == NULL)) { + if (nameAttr == NULL) { + xmlSchemaPMissingAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_MISSING, + NULL, node, "name", NULL); + return (NULL); + } + } else + isRef = 1; + + xmlSchemaPValAttrID(ctxt, node, BAD_CAST "id"); + child = node->children; + if (IS_SCHEMA(child, "annotation")) { + annot = xmlSchemaParseAnnotation(ctxt, child, 1); + child = child->next; + } + /* + * Skip particle part if a global declaration. + */ + if (topLevel) + goto declaration_part; + /* + * The particle part ================================================== + */ + min = xmlGetMinOccurs(ctxt, node, 0, -1, 1, "xs:nonNegativeInteger"); + max = xmlGetMaxOccurs(ctxt, node, 0, UNBOUNDED, 1, "(xs:nonNegativeInteger | unbounded)"); + xmlSchemaPCheckParticleCorrect_2(ctxt, NULL, node, min, max); + particle = xmlSchemaAddParticle(ctxt, node, min, max); + if (particle == NULL) + goto return_null; + + /* ret->flags |= XML_SCHEMAS_ELEM_REF; */ + + if (isRef) { + const xmlChar *refNs = NULL, *ref = NULL; + xmlSchemaQNameRefPtr refer = NULL; + /* + * The reference part ============================================= + */ + if (isElemRef != NULL) + *isElemRef = 1; + + xmlSchemaPValAttrNodeQName(ctxt, schema, + NULL, attr, &refNs, &ref); + xmlSchemaCheckReference(ctxt, schema, node, attr, refNs); + /* + * SPEC (3.3.3 : 2.1) "One of ref or name must be present, but not both" + */ + if (nameAttr != NULL) { + xmlSchemaPMutualExclAttrErr(ctxt, + XML_SCHEMAP_SRC_ELEMENT_2_1, NULL, nameAttr, "ref", "name"); + } + /* + * Check for illegal attributes. + */ + attr = node->properties; + while (attr != NULL) { + if (attr->ns == NULL) { + if (xmlStrEqual(attr->name, BAD_CAST "ref") || + xmlStrEqual(attr->name, BAD_CAST "name") || + xmlStrEqual(attr->name, BAD_CAST "id") || + xmlStrEqual(attr->name, BAD_CAST "maxOccurs") || + xmlStrEqual(attr->name, BAD_CAST "minOccurs")) + { + attr = attr->next; + continue; + } else { + /* SPEC (3.3.3 : 2.2) */ + xmlSchemaPCustomAttrErr(ctxt, + XML_SCHEMAP_SRC_ELEMENT_2_2, + NULL, NULL, attr, + "Only the attributes 'minOccurs', 'maxOccurs' and " + "'id' are allowed in addition to 'ref'"); + break; + } + } else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) { + xmlSchemaPIllegalAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + attr = attr->next; + } + /* + * No children except expected. + */ + if (child != NULL) { + xmlSchemaPContentErr(ctxt, XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED, + NULL, node, child, NULL, "(annotation?)"); + } + if ((min == 0) && (max == 0)) + goto return_null; + /* + * Create the reference item and attach it to the particle. + */ + refer = xmlSchemaNewQNameRef(ctxt, XML_SCHEMA_TYPE_ELEMENT, + ref, refNs); + if (refer == NULL) + goto return_null; + particle->children = (xmlSchemaTreeItemPtr) refer; + particle->annot = annot; + /* + * Add the particle to pending components, since the reference + * need to be resolved. + */ + WXS_ADD_PENDING(ctxt, particle); + return ((xmlSchemaBasicItemPtr) particle); + } + /* + * The declaration part =============================================== + */ +declaration_part: + { + const xmlChar *ns = NULL, *fixed, *name, *attrValue; + xmlSchemaIDCPtr curIDC = NULL, lastIDC = NULL; + + if (xmlSchemaPValAttrNode(ctxt, NULL, nameAttr, + xmlSchemaGetBuiltInType(XML_SCHEMAS_NCNAME), &name) != 0) + goto return_null; + /* + * Evaluate the target namespace. + */ + if (topLevel) { + ns = ctxt->targetNamespace; + } else { + attr = xmlSchemaGetPropNode(node, "form"); + if (attr != NULL) { + attrValue = xmlSchemaGetNodeContent(ctxt, (xmlNodePtr) attr); + if (xmlStrEqual(attrValue, BAD_CAST "qualified")) { + ns = ctxt->targetNamespace; + } else if (!xmlStrEqual(attrValue, BAD_CAST "unqualified")) { + xmlSchemaPSimpleTypeErr(ctxt, + XML_SCHEMAP_S4S_ATTR_INVALID_VALUE, + NULL, (xmlNodePtr) attr, + NULL, "(qualified | unqualified)", + attrValue, NULL, NULL, NULL); + } + } else if (schema->flags & XML_SCHEMAS_QUALIF_ELEM) + ns = ctxt->targetNamespace; + } + decl = xmlSchemaAddElement(ctxt, name, ns, node, topLevel); + if (decl == NULL) { + goto return_null; + } + /* + * Check for illegal attributes. + */ + attr = node->properties; + while (attr != NULL) { + if (attr->ns == NULL) { + if ((!xmlStrEqual(attr->name, BAD_CAST "name")) && + (!xmlStrEqual(attr->name, BAD_CAST "type")) && + (!xmlStrEqual(attr->name, BAD_CAST "id")) && + (!xmlStrEqual(attr->name, BAD_CAST "default")) && + (!xmlStrEqual(attr->name, BAD_CAST "fixed")) && + (!xmlStrEqual(attr->name, BAD_CAST "block")) && + (!xmlStrEqual(attr->name, BAD_CAST "nillable"))) + { + if (topLevel == 0) { + if ((!xmlStrEqual(attr->name, BAD_CAST "maxOccurs")) && + (!xmlStrEqual(attr->name, BAD_CAST "minOccurs")) && + (!xmlStrEqual(attr->name, BAD_CAST "form"))) + { + xmlSchemaPIllegalAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + } else if ((!xmlStrEqual(attr->name, BAD_CAST "final")) && + (!xmlStrEqual(attr->name, BAD_CAST "abstract")) && + (!xmlStrEqual(attr->name, BAD_CAST "substitutionGroup"))) { + + xmlSchemaPIllegalAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + } + } else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) { + + xmlSchemaPIllegalAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + attr = attr->next; + } + /* + * Extract/validate attributes. + */ + if (topLevel) { + /* + * Process top attributes of global element declarations here. + */ + decl->flags |= XML_SCHEMAS_ELEM_GLOBAL; + decl->flags |= XML_SCHEMAS_ELEM_TOPLEVEL; + xmlSchemaPValAttrQName(ctxt, schema, + NULL, node, "substitutionGroup", + &(decl->substGroupNs), &(decl->substGroup)); + if (xmlGetBooleanProp(ctxt, node, "abstract", 0)) + decl->flags |= XML_SCHEMAS_ELEM_ABSTRACT; + /* + * Attribute "final". + */ + attr = xmlSchemaGetPropNode(node, "final"); + if (attr == NULL) { + if (schema->flags & XML_SCHEMAS_FINAL_DEFAULT_EXTENSION) + decl->flags |= XML_SCHEMAS_ELEM_FINAL_EXTENSION; + if (schema->flags & XML_SCHEMAS_FINAL_DEFAULT_RESTRICTION) + decl->flags |= XML_SCHEMAS_ELEM_FINAL_RESTRICTION; + } else { + attrValue = xmlSchemaGetNodeContent(ctxt, (xmlNodePtr) attr); + if (xmlSchemaPValAttrBlockFinal(attrValue, &(decl->flags), + -1, + XML_SCHEMAS_ELEM_FINAL_EXTENSION, + XML_SCHEMAS_ELEM_FINAL_RESTRICTION, -1, -1, -1) != 0) { + xmlSchemaPSimpleTypeErr(ctxt, + XML_SCHEMAP_S4S_ATTR_INVALID_VALUE, + NULL, (xmlNodePtr) attr, + NULL, "(#all | List of (extension | restriction))", + attrValue, NULL, NULL, NULL); + } + } + } + /* + * Attribute "block". + */ + attr = xmlSchemaGetPropNode(node, "block"); + if (attr == NULL) { + /* + * Apply default "block" values. + */ + if (schema->flags & XML_SCHEMAS_BLOCK_DEFAULT_RESTRICTION) + decl->flags |= XML_SCHEMAS_ELEM_BLOCK_RESTRICTION; + if (schema->flags & XML_SCHEMAS_BLOCK_DEFAULT_EXTENSION) + decl->flags |= XML_SCHEMAS_ELEM_BLOCK_EXTENSION; + if (schema->flags & XML_SCHEMAS_BLOCK_DEFAULT_SUBSTITUTION) + decl->flags |= XML_SCHEMAS_ELEM_BLOCK_SUBSTITUTION; + } else { + attrValue = xmlSchemaGetNodeContent(ctxt, (xmlNodePtr) attr); + if (xmlSchemaPValAttrBlockFinal(attrValue, &(decl->flags), + -1, + XML_SCHEMAS_ELEM_BLOCK_EXTENSION, + XML_SCHEMAS_ELEM_BLOCK_RESTRICTION, + XML_SCHEMAS_ELEM_BLOCK_SUBSTITUTION, -1, -1) != 0) { + xmlSchemaPSimpleTypeErr(ctxt, + XML_SCHEMAP_S4S_ATTR_INVALID_VALUE, + NULL, (xmlNodePtr) attr, + NULL, "(#all | List of (extension | " + "restriction | substitution))", attrValue, + NULL, NULL, NULL); + } + } + if (xmlGetBooleanProp(ctxt, node, "nillable", 0)) + decl->flags |= XML_SCHEMAS_ELEM_NILLABLE; + + attr = xmlSchemaGetPropNode(node, "type"); + if (attr != NULL) { + xmlSchemaPValAttrNodeQName(ctxt, schema, + NULL, attr, + &(decl->namedTypeNs), &(decl->namedType)); + xmlSchemaCheckReference(ctxt, schema, node, + attr, decl->namedTypeNs); + } + decl->value = xmlSchemaGetProp(ctxt, node, "default"); + attr = xmlSchemaGetPropNode(node, "fixed"); + if (attr != NULL) { + fixed = xmlSchemaGetNodeContent(ctxt, (xmlNodePtr) attr); + if (decl->value != NULL) { + /* + * 3.3.3 : 1 + * default and fixed must not both be present. + */ + xmlSchemaPMutualExclAttrErr(ctxt, + XML_SCHEMAP_SRC_ELEMENT_1, + NULL, attr, "default", "fixed"); + } else { + decl->flags |= XML_SCHEMAS_ELEM_FIXED; + decl->value = fixed; + } + } + /* + * And now for the children... + */ + if (IS_SCHEMA(child, "complexType")) { + /* + * 3.3.3 : 3 + * "type" and either or are mutually + * exclusive + */ + if (decl->namedType != NULL) { + xmlSchemaPContentErr(ctxt, + XML_SCHEMAP_SRC_ELEMENT_3, + NULL, node, child, + "The attribute 'type' and the child are " + "mutually exclusive", NULL); + } else + WXS_ELEM_TYPEDEF(decl) = xmlSchemaParseComplexType(ctxt, schema, child, 0); + child = child->next; + } else if (IS_SCHEMA(child, "simpleType")) { + /* + * 3.3.3 : 3 + * "type" and either or are + * mutually exclusive + */ + if (decl->namedType != NULL) { + xmlSchemaPContentErr(ctxt, + XML_SCHEMAP_SRC_ELEMENT_3, + NULL, node, child, + "The attribute 'type' and the child are " + "mutually exclusive", NULL); + } else + WXS_ELEM_TYPEDEF(decl) = xmlSchemaParseSimpleType(ctxt, schema, child, 0); + child = child->next; + } + while ((IS_SCHEMA(child, "unique")) || + (IS_SCHEMA(child, "key")) || (IS_SCHEMA(child, "keyref"))) { + if (IS_SCHEMA(child, "unique")) { + curIDC = xmlSchemaParseIDC(ctxt, schema, child, + XML_SCHEMA_TYPE_IDC_UNIQUE, decl->targetNamespace); + } else if (IS_SCHEMA(child, "key")) { + curIDC = xmlSchemaParseIDC(ctxt, schema, child, + XML_SCHEMA_TYPE_IDC_KEY, decl->targetNamespace); + } else if (IS_SCHEMA(child, "keyref")) { + curIDC = xmlSchemaParseIDC(ctxt, schema, child, + XML_SCHEMA_TYPE_IDC_KEYREF, decl->targetNamespace); + } + if (lastIDC != NULL) + lastIDC->next = curIDC; + else + decl->idcs = (void *) curIDC; + lastIDC = curIDC; + child = child->next; + } + if (child != NULL) { + xmlSchemaPContentErr(ctxt, + XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED, + NULL, node, child, + NULL, "(annotation?, ((simpleType | complexType)?, " + "(unique | key | keyref)*))"); + } + decl->annot = annot; + } + /* + * NOTE: Element Declaration Representation OK 4. will be checked at a + * different layer. + */ + FREE_AND_NULL(des) + if (topLevel) + return ((xmlSchemaBasicItemPtr) decl); + else { + particle->children = (xmlSchemaTreeItemPtr) decl; + return ((xmlSchemaBasicItemPtr) particle); + } + +return_null: + FREE_AND_NULL(des); + if (annot != NULL) { + if (particle != NULL) + particle->annot = NULL; + if (decl != NULL) + decl->annot = NULL; + xmlSchemaFreeAnnot(annot); + } + return (NULL); +} + +/** + * xmlSchemaParseUnion: + * @ctxt: a schema validation context + * @schema: the schema being built + * @node: a subtree containing XML Schema informations + * + * parse a XML schema Union definition + * *WARNING* this interface is highly subject to change + * + * Returns -1 in case of internal error, 0 in case of success and a positive + * error code otherwise. + */ +static int +xmlSchemaParseUnion(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, + xmlNodePtr node) +{ + xmlSchemaTypePtr type; + xmlNodePtr child = NULL; + xmlAttrPtr attr; + const xmlChar *cur = NULL; + + if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) + return (-1); + /* Not a component, don't create it. */ + type = ctxt->ctxtType; + /* + * Mark the simple type as being of variety "union". + */ + type->flags |= XML_SCHEMAS_TYPE_VARIETY_UNION; + /* + * SPEC (Base type) (2) "If the or alternative is chosen, + * then the �simple ur-type definition�." + */ + type->baseType = xmlSchemaGetBuiltInType(XML_SCHEMAS_ANYSIMPLETYPE); + /* + * Check for illegal attributes. + */ + attr = node->properties; + while (attr != NULL) { + if (attr->ns == NULL) { + if ((!xmlStrEqual(attr->name, BAD_CAST "id")) && + (!xmlStrEqual(attr->name, BAD_CAST "memberTypes"))) { + xmlSchemaPIllegalAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + } else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) { + xmlSchemaPIllegalAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + attr = attr->next; + } + xmlSchemaPValAttrID(ctxt, node, BAD_CAST "id"); + /* + * Attribute "memberTypes". This is a list of QNames. + * TODO: Check the value to contain anything. + */ + attr = xmlSchemaGetPropNode(node, "memberTypes"); + if (attr != NULL) { + const xmlChar *end; + xmlChar *tmp; + const xmlChar *localName, *nsName; + xmlSchemaTypeLinkPtr link, lastLink = NULL; + xmlSchemaQNameRefPtr ref; + + cur = xmlSchemaGetNodeContent(ctxt, (xmlNodePtr) attr); + type->base = cur; + do { + while (IS_BLANK_CH(*cur)) + cur++; + end = cur; + while ((*end != 0) && (!(IS_BLANK_CH(*end)))) + end++; + if (end == cur) + break; + tmp = xmlStrndup(cur, end - cur); + if (xmlSchemaPValAttrNodeQNameValue(ctxt, schema, + NULL, attr, BAD_CAST tmp, &nsName, &localName) == 0) { + /* + * Create the member type link. + */ + link = (xmlSchemaTypeLinkPtr) + xmlMalloc(sizeof(xmlSchemaTypeLink)); + if (link == NULL) { + xmlSchemaPErrMemory(ctxt, "xmlSchemaParseUnion, " + "allocating a type link", NULL); + return (-1); + } + link->type = NULL; + link->next = NULL; + if (lastLink == NULL) + type->memberTypes = link; + else + lastLink->next = link; + lastLink = link; + /* + * Create a reference item. + */ + ref = xmlSchemaNewQNameRef(ctxt, XML_SCHEMA_TYPE_SIMPLE, + localName, nsName); + if (ref == NULL) { + FREE_AND_NULL(tmp) + return (-1); + } + /* + * Assign the reference to the link, it will be resolved + * later during fixup of the union simple type. + */ + link->type = (xmlSchemaTypePtr) ref; + } + FREE_AND_NULL(tmp) + cur = end; + } while (*cur != 0); + + } + /* + * And now for the children... + */ + child = node->children; + if (IS_SCHEMA(child, "annotation")) { + /* + * Add the annotation to the simple type ancestor. + */ + xmlSchemaAddAnnotation((xmlSchemaAnnotItemPtr) type, + xmlSchemaParseAnnotation(ctxt, child, 1)); + child = child->next; + } + if (IS_SCHEMA(child, "simpleType")) { + xmlSchemaTypePtr subtype, last = NULL; + + /* + * Anchor the member types in the "subtypes" field of the + * simple type. + */ + while (IS_SCHEMA(child, "simpleType")) { + subtype = (xmlSchemaTypePtr) + xmlSchemaParseSimpleType(ctxt, schema, child, 0); + if (subtype != NULL) { + if (last == NULL) { + type->subtypes = subtype; + last = subtype; + } else { + last->next = subtype; + last = subtype; + } + last->next = NULL; + } + child = child->next; + } + } + if (child != NULL) { + xmlSchemaPContentErr(ctxt, + XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED, + NULL, node, child, NULL, "(annotation?, simpleType*)"); + } + if ((attr == NULL) && (type->subtypes == NULL)) { + /* + * src-union-memberTypes-or-simpleTypes + * Either the memberTypes [attribute] of the element must + * be non-empty or there must be at least one simpleType [child]. + */ + xmlSchemaPCustomErr(ctxt, + XML_SCHEMAP_SRC_UNION_MEMBERTYPES_OR_SIMPLETYPES, + NULL, node, + "Either the attribute 'memberTypes' or " + "at least one child must be present", NULL); + } + return (0); +} + +/** + * xmlSchemaParseList: + * @ctxt: a schema validation context + * @schema: the schema being built + * @node: a subtree containing XML Schema informations + * + * parse a XML schema List definition + * *WARNING* this interface is highly subject to change + * + * Returns -1 in case of error, 0 if the declaration is improper and + * 1 in case of success. + */ +static xmlSchemaTypePtr +xmlSchemaParseList(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, + xmlNodePtr node) +{ + xmlSchemaTypePtr type; + xmlNodePtr child = NULL; + xmlAttrPtr attr; + + if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) + return (NULL); + /* Not a component, don't create it. */ + type = ctxt->ctxtType; + /* + * Mark the type as being of variety "list". + */ + type->flags |= XML_SCHEMAS_TYPE_VARIETY_LIST; + /* + * SPEC (Base type) (2) "If the or alternative is chosen, + * then the �simple ur-type definition�." + */ + type->baseType = xmlSchemaGetBuiltInType(XML_SCHEMAS_ANYSIMPLETYPE); + /* + * Check for illegal attributes. + */ + attr = node->properties; + while (attr != NULL) { + if (attr->ns == NULL) { + if ((!xmlStrEqual(attr->name, BAD_CAST "id")) && + (!xmlStrEqual(attr->name, BAD_CAST "itemType"))) { + xmlSchemaPIllegalAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + } else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) { + xmlSchemaPIllegalAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + attr = attr->next; + } + + xmlSchemaPValAttrID(ctxt, node, BAD_CAST "id"); + + /* + * Attribute "itemType". NOTE that we will use the "ref" and "refNs" + * fields for holding the reference to the itemType. + * + * REVAMP TODO: Use the "base" and "baseNs" fields, since we will remove + * the "ref" fields. + */ + xmlSchemaPValAttrQName(ctxt, schema, NULL, + node, "itemType", &(type->baseNs), &(type->base)); + /* + * And now for the children... + */ + child = node->children; + if (IS_SCHEMA(child, "annotation")) { + xmlSchemaAddAnnotation((xmlSchemaAnnotItemPtr) type, + xmlSchemaParseAnnotation(ctxt, child, 1)); + child = child->next; + } + if (IS_SCHEMA(child, "simpleType")) { + /* + * src-list-itemType-or-simpleType + * Either the itemType [attribute] or the [child] of + * the element must be present, but not both. + */ + if (type->base != NULL) { + xmlSchemaPCustomErr(ctxt, + XML_SCHEMAP_SRC_SIMPLE_TYPE_1, + NULL, node, + "The attribute 'itemType' and the child " + "are mutually exclusive", NULL); + } else { + type->subtypes = xmlSchemaParseSimpleType(ctxt, schema, child, 0); + } + child = child->next; + } else if (type->base == NULL) { + xmlSchemaPCustomErr(ctxt, + XML_SCHEMAP_SRC_SIMPLE_TYPE_1, + NULL, node, + "Either the attribute 'itemType' or the child " + "must be present", NULL); + } + if (child != NULL) { + xmlSchemaPContentErr(ctxt, + XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED, + NULL, node, child, NULL, "(annotation?, simpleType?)"); + } + if ((type->base == NULL) && + (type->subtypes == NULL) && + (xmlSchemaGetPropNode(node, "itemType") == NULL)) { + xmlSchemaPCustomErr(ctxt, + XML_SCHEMAP_SRC_SIMPLE_TYPE_1, + NULL, node, + "Either the attribute 'itemType' or the child " + "must be present", NULL); + } + return (NULL); +} + +/** + * xmlSchemaParseSimpleType: + * @ctxt: a schema validation context + * @schema: the schema being built + * @node: a subtree containing XML Schema informations + * + * parse a XML schema Simple Type definition + * *WARNING* this interface is highly subject to change + * + * Returns -1 in case of error, 0 if the declaration is improper and + * 1 in case of success. + */ +static xmlSchemaTypePtr +xmlSchemaParseSimpleType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, + xmlNodePtr node, int topLevel) +{ + xmlSchemaTypePtr type, oldCtxtType; + xmlNodePtr child = NULL; + const xmlChar *attrValue = NULL; + xmlAttrPtr attr; + int hasRestriction = 0; + + if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) + return (NULL); + + if (topLevel) { + attr = xmlSchemaGetPropNode(node, "name"); + if (attr == NULL) { + xmlSchemaPMissingAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_MISSING, + NULL, node, + "name", NULL); + return (NULL); + } else { + if (xmlSchemaPValAttrNode(ctxt, + NULL, attr, + xmlSchemaGetBuiltInType(XML_SCHEMAS_NCNAME), &attrValue) != 0) + return (NULL); + /* + * Skip built-in types. + */ + if (ctxt->isS4S) { + xmlSchemaTypePtr biType; + + if (ctxt->isRedefine) { + /* + * REDEFINE: Disallow redefinition of built-in-types. + * TODO: It seems that the spec does not say anything + * about this case. + */ + xmlSchemaPCustomErr(ctxt, XML_SCHEMAP_SRC_REDEFINE, + NULL, node, + "Redefinition of built-in simple types is not " + "supported", NULL); + return(NULL); + } + biType = xmlSchemaGetPredefinedType(attrValue, xmlSchemaNs); + if (biType != NULL) + return (biType); + } + } + } + /* + * TargetNamespace: + * SPEC "The �actual value� of the targetNamespace [attribute] + * of the ancestor element information item if present, + * otherwise �absent�. + */ + if (topLevel == 0) { +#ifdef ENABLE_NAMED_LOCALS + char buf[40]; +#endif + /* + * Parse as local simple type definition. + */ +#ifdef ENABLE_NAMED_LOCALS + snprintf(buf, 39, "#ST%d", ctxt->counter++ + 1); + type = xmlSchemaAddType(ctxt, schema, + XML_SCHEMA_TYPE_SIMPLE, + xmlDictLookup(ctxt->dict, (const xmlChar *)buf, -1), + ctxt->targetNamespace, node, 0); +#else + type = xmlSchemaAddType(ctxt, schema, + XML_SCHEMA_TYPE_SIMPLE, + NULL, ctxt->targetNamespace, node, 0); +#endif + if (type == NULL) + return (NULL); + type->type = XML_SCHEMA_TYPE_SIMPLE; + type->contentType = XML_SCHEMA_CONTENT_SIMPLE; + /* + * Check for illegal attributes. + */ + attr = node->properties; + while (attr != NULL) { + if (attr->ns == NULL) { + if (!xmlStrEqual(attr->name, BAD_CAST "id")) { + xmlSchemaPIllegalAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + } else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) { + xmlSchemaPIllegalAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + attr = attr->next; + } + } else { + /* + * Parse as global simple type definition. + * + * Note that attrValue is the value of the attribute "name" here. + */ + type = xmlSchemaAddType(ctxt, schema, XML_SCHEMA_TYPE_SIMPLE, + attrValue, ctxt->targetNamespace, node, 1); + if (type == NULL) + return (NULL); + type->type = XML_SCHEMA_TYPE_SIMPLE; + type->contentType = XML_SCHEMA_CONTENT_SIMPLE; + type->flags |= XML_SCHEMAS_TYPE_GLOBAL; + /* + * Check for illegal attributes. + */ + attr = node->properties; + while (attr != NULL) { + if (attr->ns == NULL) { + if ((!xmlStrEqual(attr->name, BAD_CAST "id")) && + (!xmlStrEqual(attr->name, BAD_CAST "name")) && + (!xmlStrEqual(attr->name, BAD_CAST "final"))) { + xmlSchemaPIllegalAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + } else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) { + xmlSchemaPIllegalAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + attr = attr->next; + } + /* + * Attribute "final". + */ + attr = xmlSchemaGetPropNode(node, "final"); + if (attr == NULL) { + if (schema->flags & XML_SCHEMAS_FINAL_DEFAULT_RESTRICTION) + type->flags |= XML_SCHEMAS_TYPE_FINAL_RESTRICTION; + if (schema->flags & XML_SCHEMAS_FINAL_DEFAULT_LIST) + type->flags |= XML_SCHEMAS_TYPE_FINAL_LIST; + if (schema->flags & XML_SCHEMAS_FINAL_DEFAULT_UNION) + type->flags |= XML_SCHEMAS_TYPE_FINAL_UNION; + } else { + attrValue = xmlSchemaGetProp(ctxt, node, "final"); + if (xmlSchemaPValAttrBlockFinal(attrValue, &(type->flags), + -1, -1, XML_SCHEMAS_TYPE_FINAL_RESTRICTION, -1, + XML_SCHEMAS_TYPE_FINAL_LIST, + XML_SCHEMAS_TYPE_FINAL_UNION) != 0) { + + xmlSchemaPSimpleTypeErr(ctxt, + XML_SCHEMAP_S4S_ATTR_INVALID_VALUE, + WXS_BASIC_CAST type, (xmlNodePtr) attr, + NULL, "(#all | List of (list | union | restriction)", + attrValue, NULL, NULL, NULL); + } + } + } + type->targetNamespace = ctxt->targetNamespace; + xmlSchemaPValAttrID(ctxt, node, BAD_CAST "id"); + /* + * And now for the children... + */ + oldCtxtType = ctxt->ctxtType; + + ctxt->ctxtType = type; + + child = node->children; + if (IS_SCHEMA(child, "annotation")) { + type->annot = xmlSchemaParseAnnotation(ctxt, child, 1); + child = child->next; + } + if (child == NULL) { + xmlSchemaPContentErr(ctxt, XML_SCHEMAP_S4S_ELEM_MISSING, + NULL, node, child, NULL, + "(annotation?, (restriction | list | union))"); + } else if (IS_SCHEMA(child, "restriction")) { + xmlSchemaParseRestriction(ctxt, schema, child, + XML_SCHEMA_TYPE_SIMPLE); + hasRestriction = 1; + child = child->next; + } else if (IS_SCHEMA(child, "list")) { + xmlSchemaParseList(ctxt, schema, child); + child = child->next; + } else if (IS_SCHEMA(child, "union")) { + xmlSchemaParseUnion(ctxt, schema, child); + child = child->next; + } + if (child != NULL) { + xmlSchemaPContentErr(ctxt, XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED, + NULL, node, child, NULL, + "(annotation?, (restriction | list | union))"); + } + /* + * REDEFINE: SPEC src-redefine (5) + * "Within the [children], each must have a + * among its [children] ... the �actual value� of whose + * base [attribute] must be the same as the �actual value� of its own + * name attribute plus target namespace;" + */ + if (topLevel && ctxt->isRedefine && (! hasRestriction)) { + xmlSchemaPCustomErr(ctxt, XML_SCHEMAP_SRC_REDEFINE, + NULL, node, "This is a redefinition, thus the " + " must have a child", NULL); + } + + ctxt->ctxtType = oldCtxtType; + return (type); +} + +/** + * xmlSchemaParseModelGroupDefRef: + * @ctxt: the parser context + * @schema: the schema being built + * @node: the node + * + * Parses a reference to a model group definition. + * + * We will return a particle component with a qname-component or + * NULL in case of an error. + */ +static xmlSchemaTreeItemPtr +xmlSchemaParseModelGroupDefRef(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaPtr schema, + xmlNodePtr node) +{ + xmlSchemaParticlePtr item; + xmlNodePtr child = NULL; + xmlAttrPtr attr; + const xmlChar *ref = NULL, *refNs = NULL; + int min, max; + + if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) + return (NULL); + + attr = xmlSchemaGetPropNode(node, "ref"); + if (attr == NULL) { + xmlSchemaPMissingAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_MISSING, + NULL, node, "ref", NULL); + return (NULL); + } else if (xmlSchemaPValAttrNodeQName(ctxt, schema, NULL, + attr, &refNs, &ref) != 0) { + return (NULL); + } + xmlSchemaCheckReference(ctxt, schema, node, attr, refNs); + min = xmlGetMinOccurs(ctxt, node, 0, -1, 1, "xs:nonNegativeInteger"); + max = xmlGetMaxOccurs(ctxt, node, 0, UNBOUNDED, 1, + "(xs:nonNegativeInteger | unbounded)"); + /* + * Check for illegal attributes. + */ + attr = node->properties; + while (attr != NULL) { + if (attr->ns == NULL) { + if ((!xmlStrEqual(attr->name, BAD_CAST "ref")) && + (!xmlStrEqual(attr->name, BAD_CAST "id")) && + (!xmlStrEqual(attr->name, BAD_CAST "minOccurs")) && + (!xmlStrEqual(attr->name, BAD_CAST "maxOccurs"))) { + xmlSchemaPIllegalAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + } else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) { + xmlSchemaPIllegalAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + attr = attr->next; + } + xmlSchemaPValAttrID(ctxt, node, BAD_CAST "id"); + item = xmlSchemaAddParticle(ctxt, node, min, max); + if (item == NULL) + return (NULL); + /* + * Create a qname-reference and set as the term; it will be substituted + * for the model group after the reference has been resolved. + */ + item->children = (xmlSchemaTreeItemPtr) + xmlSchemaNewQNameRef(ctxt, XML_SCHEMA_TYPE_GROUP, ref, refNs); + xmlSchemaPCheckParticleCorrect_2(ctxt, item, node, min, max); + /* + * And now for the children... + */ + child = node->children; + /* TODO: Is annotation even allowed for a model group reference? */ + if (IS_SCHEMA(child, "annotation")) { + /* + * TODO: What to do exactly with the annotation? + */ + item->annot = xmlSchemaParseAnnotation(ctxt, child, 1); + child = child->next; + } + if (child != NULL) { + xmlSchemaPContentErr(ctxt, + XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED, + NULL, node, child, NULL, + "(annotation?)"); + } + /* + * Corresponds to no component at all if minOccurs==maxOccurs==0. + */ + if ((min == 0) && (max == 0)) + return (NULL); + + return ((xmlSchemaTreeItemPtr) item); +} + +/** + * xmlSchemaParseModelGroupDefinition: + * @ctxt: a schema validation context + * @schema: the schema being built + * @node: a subtree containing XML Schema informations + * + * Parses a XML schema model group definition. + * + * Note that the contraint src-redefine (6.2) can't be applied until + * references have been resolved. So we will do this at the + * component fixup level. + * + * *WARNING* this interface is highly subject to change + * + * Returns -1 in case of error, 0 if the declaration is improper and + * 1 in case of success. + */ +static xmlSchemaModelGroupDefPtr +xmlSchemaParseModelGroupDefinition(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaPtr schema, + xmlNodePtr node) +{ + xmlSchemaModelGroupDefPtr item; + xmlNodePtr child = NULL; + xmlAttrPtr attr; + const xmlChar *name; + + if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) + return (NULL); + + attr = xmlSchemaGetPropNode(node, "name"); + if (attr == NULL) { + xmlSchemaPMissingAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_MISSING, + NULL, node, + "name", NULL); + return (NULL); + } else if (xmlSchemaPValAttrNode(ctxt, NULL, attr, + xmlSchemaGetBuiltInType(XML_SCHEMAS_NCNAME), &name) != 0) { + return (NULL); + } + item = xmlSchemaAddModelGroupDefinition(ctxt, schema, name, + ctxt->targetNamespace, node); + if (item == NULL) + return (NULL); + /* + * Check for illegal attributes. + */ + attr = node->properties; + while (attr != NULL) { + if (attr->ns == NULL) { + if ((!xmlStrEqual(attr->name, BAD_CAST "name")) && + (!xmlStrEqual(attr->name, BAD_CAST "id"))) { + xmlSchemaPIllegalAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + } else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) { + xmlSchemaPIllegalAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + attr = attr->next; + } + xmlSchemaPValAttrID(ctxt, node, BAD_CAST "id"); + /* + * And now for the children... + */ + child = node->children; + if (IS_SCHEMA(child, "annotation")) { + item->annot = xmlSchemaParseAnnotation(ctxt, child, 1); + child = child->next; + } + if (IS_SCHEMA(child, "all")) { + item->children = xmlSchemaParseModelGroup(ctxt, schema, child, + XML_SCHEMA_TYPE_ALL, 0); + child = child->next; + } else if (IS_SCHEMA(child, "choice")) { + item->children = xmlSchemaParseModelGroup(ctxt, schema, child, + XML_SCHEMA_TYPE_CHOICE, 0); + child = child->next; + } else if (IS_SCHEMA(child, "sequence")) { + item->children = xmlSchemaParseModelGroup(ctxt, schema, child, + XML_SCHEMA_TYPE_SEQUENCE, 0); + child = child->next; + } + + + + if (child != NULL) { + xmlSchemaPContentErr(ctxt, + XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED, + NULL, node, child, NULL, + "(annotation?, (all | choice | sequence)?)"); + } + return (item); +} + +/** + * xmlSchemaCleanupDoc: + * @ctxt: a schema validation context + * @node: the root of the document. + * + * removes unwanted nodes in a schemas document tree + */ +static void +xmlSchemaCleanupDoc(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr root) +{ + xmlNodePtr delete, cur; + + if ((ctxt == NULL) || (root == NULL)) return; + + /* + * Remove all the blank text nodes + */ + delete = NULL; + cur = root; + while (cur != NULL) { + if (delete != NULL) { + xmlUnlinkNode(delete); + xmlFreeNode(delete); + delete = NULL; + } + if (cur->type == XML_TEXT_NODE) { + if (IS_BLANK_NODE(cur)) { + if (xmlNodeGetSpacePreserve(cur) != 1) { + delete = cur; + } + } + } else if ((cur->type != XML_ELEMENT_NODE) && + (cur->type != XML_CDATA_SECTION_NODE)) { + delete = cur; + goto skip_children; + } + + /* + * Skip to next node + */ + if (cur->children != NULL) { + if ((cur->children->type != XML_ENTITY_DECL) && + (cur->children->type != XML_ENTITY_REF_NODE) && + (cur->children->type != XML_ENTITY_NODE)) { + cur = cur->children; + continue; + } + } + skip_children: + if (cur->next != NULL) { + cur = cur->next; + continue; + } + + do { + cur = cur->parent; + if (cur == NULL) + break; + if (cur == root) { + cur = NULL; + break; + } + if (cur->next != NULL) { + cur = cur->next; + break; + } + } while (cur != NULL); + } + if (delete != NULL) { + xmlUnlinkNode(delete); + xmlFreeNode(delete); + delete = NULL; + } +} + + +static void +xmlSchemaClearSchemaDefaults(xmlSchemaPtr schema) +{ + if (schema->flags & XML_SCHEMAS_QUALIF_ELEM) + schema->flags ^= XML_SCHEMAS_QUALIF_ELEM; + + if (schema->flags & XML_SCHEMAS_QUALIF_ATTR) + schema->flags ^= XML_SCHEMAS_QUALIF_ATTR; + + if (schema->flags & XML_SCHEMAS_FINAL_DEFAULT_EXTENSION) + schema->flags ^= XML_SCHEMAS_FINAL_DEFAULT_EXTENSION; + if (schema->flags & XML_SCHEMAS_FINAL_DEFAULT_RESTRICTION) + schema->flags ^= XML_SCHEMAS_FINAL_DEFAULT_RESTRICTION; + if (schema->flags & XML_SCHEMAS_FINAL_DEFAULT_LIST) + schema->flags ^= XML_SCHEMAS_FINAL_DEFAULT_LIST; + if (schema->flags & XML_SCHEMAS_FINAL_DEFAULT_UNION) + schema->flags ^= XML_SCHEMAS_FINAL_DEFAULT_UNION; + + if (schema->flags & XML_SCHEMAS_BLOCK_DEFAULT_EXTENSION) + schema->flags ^= XML_SCHEMAS_BLOCK_DEFAULT_EXTENSION; + if (schema->flags & XML_SCHEMAS_BLOCK_DEFAULT_RESTRICTION) + schema->flags ^= XML_SCHEMAS_BLOCK_DEFAULT_RESTRICTION; + if (schema->flags & XML_SCHEMAS_BLOCK_DEFAULT_SUBSTITUTION) + schema->flags ^= XML_SCHEMAS_BLOCK_DEFAULT_SUBSTITUTION; +} + +static int +xmlSchemaParseSchemaElement(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaPtr schema, + xmlNodePtr node) +{ + xmlAttrPtr attr; + const xmlChar *val; + int res = 0, oldErrs = ctxt->nberrors; + + /* + * Those flags should be moved to the parser context flags, + * since they are not visible at the component level. I.e. + * they are used if processing schema *documents* only. + */ + res = xmlSchemaPValAttrID(ctxt, node, BAD_CAST "id"); + HFAILURE; + + /* + * Since the version is of type xs:token, we won't bother to + * check it. + */ + /* REMOVED: + attr = xmlSchemaGetPropNode(node, "version"); + if (attr != NULL) { + res = xmlSchemaPValAttrNode(ctxt, NULL, NULL, attr, + xmlSchemaGetBuiltInType(XML_SCHEMAS_TOKEN), &val); + HFAILURE; + } + */ + attr = xmlSchemaGetPropNode(node, "targetNamespace"); + if (attr != NULL) { + res = xmlSchemaPValAttrNode(ctxt, NULL, attr, + xmlSchemaGetBuiltInType(XML_SCHEMAS_ANYURI), NULL); + HFAILURE; + if (res != 0) { + ctxt->stop = XML_SCHEMAP_S4S_ATTR_INVALID_VALUE; + goto exit; + } + } + attr = xmlSchemaGetPropNode(node, "elementFormDefault"); + if (attr != NULL) { + val = xmlSchemaGetNodeContent(ctxt, (xmlNodePtr) attr); + res = xmlSchemaPValAttrFormDefault(val, &schema->flags, + XML_SCHEMAS_QUALIF_ELEM); + HFAILURE; + if (res != 0) { + xmlSchemaPSimpleTypeErr(ctxt, + XML_SCHEMAP_ELEMFORMDEFAULT_VALUE, + NULL, (xmlNodePtr) attr, NULL, + "(qualified | unqualified)", val, NULL, NULL, NULL); + } + } + attr = xmlSchemaGetPropNode(node, "attributeFormDefault"); + if (attr != NULL) { + val = xmlSchemaGetNodeContent(ctxt, (xmlNodePtr) attr); + res = xmlSchemaPValAttrFormDefault(val, &schema->flags, + XML_SCHEMAS_QUALIF_ATTR); + HFAILURE; + if (res != 0) { + xmlSchemaPSimpleTypeErr(ctxt, + XML_SCHEMAP_ATTRFORMDEFAULT_VALUE, + NULL, (xmlNodePtr) attr, NULL, + "(qualified | unqualified)", val, NULL, NULL, NULL); + } + } + attr = xmlSchemaGetPropNode(node, "finalDefault"); + if (attr != NULL) { + val = xmlSchemaGetNodeContent(ctxt, (xmlNodePtr) attr); + res = xmlSchemaPValAttrBlockFinal(val, &(schema->flags), -1, + XML_SCHEMAS_FINAL_DEFAULT_EXTENSION, + XML_SCHEMAS_FINAL_DEFAULT_RESTRICTION, + -1, + XML_SCHEMAS_FINAL_DEFAULT_LIST, + XML_SCHEMAS_FINAL_DEFAULT_UNION); + HFAILURE; + if (res != 0) { + xmlSchemaPSimpleTypeErr(ctxt, + XML_SCHEMAP_S4S_ATTR_INVALID_VALUE, + NULL, (xmlNodePtr) attr, NULL, + "(#all | List of (extension | restriction | list | union))", + val, NULL, NULL, NULL); + } + } + attr = xmlSchemaGetPropNode(node, "blockDefault"); + if (attr != NULL) { + val = xmlSchemaGetNodeContent(ctxt, (xmlNodePtr) attr); + res = xmlSchemaPValAttrBlockFinal(val, &(schema->flags), -1, + XML_SCHEMAS_BLOCK_DEFAULT_EXTENSION, + XML_SCHEMAS_BLOCK_DEFAULT_RESTRICTION, + XML_SCHEMAS_BLOCK_DEFAULT_SUBSTITUTION, -1, -1); + HFAILURE; + if (res != 0) { + xmlSchemaPSimpleTypeErr(ctxt, + XML_SCHEMAP_S4S_ATTR_INVALID_VALUE, + NULL, (xmlNodePtr) attr, NULL, + "(#all | List of (extension | restriction | substitution))", + val, NULL, NULL, NULL); + } + } + +exit: + if (oldErrs != ctxt->nberrors) + res = ctxt->err; + return(res); +exit_failure: + return(-1); +} + +/** + * xmlSchemaParseSchemaTopLevel: + * @ctxt: a schema validation context + * @schema: the schemas + * @nodes: the list of top level nodes + * + * Returns the internal XML Schema structure built from the resource or + * NULL in case of error + */ +static int +xmlSchemaParseSchemaTopLevel(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaPtr schema, xmlNodePtr nodes) +{ + xmlNodePtr child; + xmlSchemaAnnotPtr annot; + int res = 0, oldErrs, tmpOldErrs; + + if ((ctxt == NULL) || (schema == NULL) || (nodes == NULL)) + return(-1); + + oldErrs = ctxt->nberrors; + child = nodes; + while ((IS_SCHEMA(child, "include")) || + (IS_SCHEMA(child, "import")) || + (IS_SCHEMA(child, "redefine")) || + (IS_SCHEMA(child, "annotation"))) { + if (IS_SCHEMA(child, "annotation")) { + annot = xmlSchemaParseAnnotation(ctxt, child, 1); + if (schema->annot == NULL) + schema->annot = annot; + else + xmlSchemaFreeAnnot(annot); + } else if (IS_SCHEMA(child, "import")) { + tmpOldErrs = ctxt->nberrors; + res = xmlSchemaParseImport(ctxt, schema, child); + HFAILURE; + HSTOP(ctxt); + if (tmpOldErrs != ctxt->nberrors) + goto exit; + } else if (IS_SCHEMA(child, "include")) { + tmpOldErrs = ctxt->nberrors; + res = xmlSchemaParseInclude(ctxt, schema, child); + HFAILURE; + HSTOP(ctxt); + if (tmpOldErrs != ctxt->nberrors) + goto exit; + } else if (IS_SCHEMA(child, "redefine")) { + tmpOldErrs = ctxt->nberrors; + res = xmlSchemaParseRedefine(ctxt, schema, child); + HFAILURE; + HSTOP(ctxt); + if (tmpOldErrs != ctxt->nberrors) + goto exit; + } + child = child->next; + } + /* + * URGENT TODO: Change the functions to return int results. + * We need especially to catch internal errors. + */ + while (child != NULL) { + if (IS_SCHEMA(child, "complexType")) { + xmlSchemaParseComplexType(ctxt, schema, child, 1); + child = child->next; + } else if (IS_SCHEMA(child, "simpleType")) { + xmlSchemaParseSimpleType(ctxt, schema, child, 1); + child = child->next; + } else if (IS_SCHEMA(child, "element")) { + xmlSchemaParseElement(ctxt, schema, child, NULL, 1); + child = child->next; + } else if (IS_SCHEMA(child, "attribute")) { + xmlSchemaParseGlobalAttribute(ctxt, schema, child); + child = child->next; + } else if (IS_SCHEMA(child, "attributeGroup")) { + xmlSchemaParseAttributeGroupDefinition(ctxt, schema, child); + child = child->next; + } else if (IS_SCHEMA(child, "group")) { + xmlSchemaParseModelGroupDefinition(ctxt, schema, child); + child = child->next; + } else if (IS_SCHEMA(child, "notation")) { + xmlSchemaParseNotation(ctxt, schema, child); + child = child->next; + } else { + xmlSchemaPContentErr(ctxt, + XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED, + NULL, child->parent, child, + NULL, "((include | import | redefine | annotation)*, " + "(((simpleType | complexType | group | attributeGroup) " + "| element | attribute | notation), annotation*)*)"); + child = child->next; + } + while (IS_SCHEMA(child, "annotation")) { + /* + * TODO: We should add all annotations. + */ + annot = xmlSchemaParseAnnotation(ctxt, child, 1); + if (schema->annot == NULL) + schema->annot = annot; + else + xmlSchemaFreeAnnot(annot); + child = child->next; + } + } +exit: + ctxt->ctxtType = NULL; + if (oldErrs != ctxt->nberrors) + res = ctxt->err; + return(res); +exit_failure: + return(-1); +} + +static xmlSchemaSchemaRelationPtr +xmlSchemaSchemaRelationCreate(void) +{ + xmlSchemaSchemaRelationPtr ret; + + ret = (xmlSchemaSchemaRelationPtr) + xmlMalloc(sizeof(xmlSchemaSchemaRelation)); + if (ret == NULL) { + xmlSchemaPErrMemory(NULL, "allocating schema relation", NULL); + return(NULL); + } + memset(ret, 0, sizeof(xmlSchemaSchemaRelation)); + return(ret); +} + +#if 0 +static void +xmlSchemaSchemaRelationFree(xmlSchemaSchemaRelationPtr rel) +{ + xmlFree(rel); +} +#endif + +static void +xmlSchemaRedefListFree(xmlSchemaRedefPtr redef) +{ + xmlSchemaRedefPtr prev; + + while (redef != NULL) { + prev = redef; + redef = redef->next; + xmlFree(prev); + } +} + +static void +xmlSchemaConstructionCtxtFree(xmlSchemaConstructionCtxtPtr con) +{ + /* + * After the construction context has been freed, there will be + * no schema graph available any more. Only the schema buckets + * will stay alive, which are put into the "schemasImports" and + * "includes" slots of the xmlSchema. + */ + if (con->buckets != NULL) + xmlSchemaItemListFree(con->buckets); + if (con->pending != NULL) + xmlSchemaItemListFree(con->pending); + if (con->substGroups != NULL) + xmlHashFree(con->substGroups, + (xmlHashDeallocator) xmlSchemaSubstGroupFree); + if (con->redefs != NULL) + xmlSchemaRedefListFree(con->redefs); + if (con->dict != NULL) + xmlDictFree(con->dict); + xmlFree(con); +} + +static xmlSchemaConstructionCtxtPtr +xmlSchemaConstructionCtxtCreate(xmlDictPtr dict) +{ + xmlSchemaConstructionCtxtPtr ret; + + ret = (xmlSchemaConstructionCtxtPtr) + xmlMalloc(sizeof(xmlSchemaConstructionCtxt)); + if (ret == NULL) { + xmlSchemaPErrMemory(NULL, + "allocating schema construction context", NULL); + return (NULL); + } + memset(ret, 0, sizeof(xmlSchemaConstructionCtxt)); + + ret->buckets = xmlSchemaItemListCreate(); + if (ret->buckets == NULL) { + xmlSchemaPErrMemory(NULL, + "allocating list of schema buckets", NULL); + xmlFree(ret); + return (NULL); + } + ret->pending = xmlSchemaItemListCreate(); + if (ret->pending == NULL) { + xmlSchemaPErrMemory(NULL, + "allocating list of pending global components", NULL); + xmlSchemaConstructionCtxtFree(ret); + return (NULL); + } + ret->dict = dict; + xmlDictReference(dict); + return(ret); +} + +static xmlSchemaParserCtxtPtr +xmlSchemaParserCtxtCreate(void) +{ + xmlSchemaParserCtxtPtr ret; + + ret = (xmlSchemaParserCtxtPtr) xmlMalloc(sizeof(xmlSchemaParserCtxt)); + if (ret == NULL) { + xmlSchemaPErrMemory(NULL, "allocating schema parser context", + NULL); + return (NULL); + } + memset(ret, 0, sizeof(xmlSchemaParserCtxt)); + ret->type = XML_SCHEMA_CTXT_PARSER; + ret->attrProhibs = xmlSchemaItemListCreate(); + if (ret->attrProhibs == NULL) { + xmlFree(ret); + return(NULL); + } + return(ret); +} + +/** + * xmlSchemaNewParserCtxtUseDict: + * @URL: the location of the schema + * @dict: the dictionary to be used + * + * Create an XML Schemas parse context for that file/resource expected + * to contain an XML Schemas file. + * + * Returns the parser context or NULL in case of error + */ +static xmlSchemaParserCtxtPtr +xmlSchemaNewParserCtxtUseDict(const char *URL, xmlDictPtr dict) +{ + xmlSchemaParserCtxtPtr ret; + + ret = xmlSchemaParserCtxtCreate(); + if (ret == NULL) + return (NULL); + ret->dict = dict; + xmlDictReference(dict); + if (URL != NULL) + ret->URL = xmlDictLookup(dict, (const xmlChar *) URL, -1); + return (ret); +} + +static int +xmlSchemaCreatePCtxtOnVCtxt(xmlSchemaValidCtxtPtr vctxt) +{ + if (vctxt->pctxt == NULL) { + if (vctxt->schema != NULL) + vctxt->pctxt = + xmlSchemaNewParserCtxtUseDict("*", vctxt->schema->dict); + else + vctxt->pctxt = xmlSchemaNewParserCtxt("*"); + if (vctxt->pctxt == NULL) { + VERROR_INT("xmlSchemaCreatePCtxtOnVCtxt", + "failed to create a temp. parser context"); + return (-1); + } + /* TODO: Pass user data. */ + xmlSchemaSetParserErrors(vctxt->pctxt, vctxt->error, + vctxt->warning, vctxt->errCtxt); + xmlSchemaSetParserStructuredErrors(vctxt->pctxt, vctxt->serror, + vctxt->errCtxt); + } + return (0); +} + +/** + * xmlSchemaGetSchemaBucket: + * @pctxt: the schema parser context + * @schemaLocation: the URI of the schema document + * + * Returns a schema bucket if it was already parsed. + * + * Returns a schema bucket if it was already parsed from + * @schemaLocation, NULL otherwise. + */ +static xmlSchemaBucketPtr +xmlSchemaGetSchemaBucket(xmlSchemaParserCtxtPtr pctxt, + const xmlChar *schemaLocation) +{ + xmlSchemaBucketPtr cur; + xmlSchemaItemListPtr list; + + list = pctxt->constructor->buckets; + if (list->nbItems == 0) + return(NULL); + else { + int i; + for (i = 0; i < list->nbItems; i++) { + cur = (xmlSchemaBucketPtr) list->items[i]; + /* Pointer comparison! */ + if (cur->schemaLocation == schemaLocation) + return(cur); + } + } + return(NULL); +} + +static xmlSchemaBucketPtr +xmlSchemaGetChameleonSchemaBucket(xmlSchemaParserCtxtPtr pctxt, + const xmlChar *schemaLocation, + const xmlChar *targetNamespace) +{ + xmlSchemaBucketPtr cur; + xmlSchemaItemListPtr list; + + list = pctxt->constructor->buckets; + if (list->nbItems == 0) + return(NULL); + else { + int i; + for (i = 0; i < list->nbItems; i++) { + cur = (xmlSchemaBucketPtr) list->items[i]; + /* Pointer comparison! */ + if ((cur->origTargetNamespace == NULL) && + (cur->schemaLocation == schemaLocation) && + (cur->targetNamespace == targetNamespace)) + return(cur); + } + } + return(NULL); +} + + +#define IS_BAD_SCHEMA_DOC(b) \ + (((b)->doc == NULL) && ((b)->schemaLocation != NULL)) + +static xmlSchemaBucketPtr +xmlSchemaGetSchemaBucketByTNS(xmlSchemaParserCtxtPtr pctxt, + const xmlChar *targetNamespace, + int imported) +{ + xmlSchemaBucketPtr cur; + xmlSchemaItemListPtr list; + + list = pctxt->constructor->buckets; + if (list->nbItems == 0) + return(NULL); + else { + int i; + for (i = 0; i < list->nbItems; i++) { + cur = (xmlSchemaBucketPtr) list->items[i]; + if ((! IS_BAD_SCHEMA_DOC(cur)) && + (cur->origTargetNamespace == targetNamespace) && + ((imported && cur->imported) || + ((!imported) && (!cur->imported)))) + return(cur); + } + } + return(NULL); +} + +static int +xmlSchemaParseNewDocWithContext(xmlSchemaParserCtxtPtr pctxt, + xmlSchemaPtr schema, + xmlSchemaBucketPtr bucket) +{ + int oldFlags; + xmlDocPtr oldDoc; + xmlNodePtr node; + int ret, oldErrs; + xmlSchemaBucketPtr oldbucket = pctxt->constructor->bucket; + + /* + * Save old values; reset the *main* schema. + * URGENT TODO: This is not good; move the per-document information + * to the parser. Get rid of passing the main schema to the + * parsing functions. + */ + oldFlags = schema->flags; + oldDoc = schema->doc; + if (schema->flags != 0) + xmlSchemaClearSchemaDefaults(schema); + schema->doc = bucket->doc; + pctxt->schema = schema; + /* + * Keep the current target namespace on the parser *not* on the + * main schema. + */ + pctxt->targetNamespace = bucket->targetNamespace; + WXS_CONSTRUCTOR(pctxt)->bucket = bucket; + + if ((bucket->targetNamespace != NULL) && + xmlStrEqual(bucket->targetNamespace, xmlSchemaNs)) { + /* + * We are parsing the schema for schemas! + */ + pctxt->isS4S = 1; + } + /* Mark it as parsed, even if parsing fails. */ + bucket->parsed++; + /* Compile the schema doc. */ + node = xmlDocGetRootElement(bucket->doc); + ret = xmlSchemaParseSchemaElement(pctxt, schema, node); + if (ret != 0) + goto exit; + /* An empty schema; just get out. */ + if (node->children == NULL) + goto exit; + oldErrs = pctxt->nberrors; + ret = xmlSchemaParseSchemaTopLevel(pctxt, schema, node->children); + if (ret != 0) + goto exit; + /* + * TODO: Not nice, but I'm not 100% sure we will get always an error + * as a result of the obove functions; so better rely on pctxt->err + * as well. + */ + if ((ret == 0) && (oldErrs != pctxt->nberrors)) { + ret = pctxt->err; + goto exit; + } + +exit: + WXS_CONSTRUCTOR(pctxt)->bucket = oldbucket; + /* Restore schema values. */ + schema->doc = oldDoc; + schema->flags = oldFlags; + return(ret); +} + +static int +xmlSchemaParseNewDoc(xmlSchemaParserCtxtPtr pctxt, + xmlSchemaPtr schema, + xmlSchemaBucketPtr bucket) +{ + xmlSchemaParserCtxtPtr newpctxt; + int res = 0; + + if (bucket == NULL) + return(0); + if (bucket->parsed) { + PERROR_INT("xmlSchemaParseNewDoc", + "reparsing a schema doc"); + return(-1); + } + if (bucket->doc == NULL) { + PERROR_INT("xmlSchemaParseNewDoc", + "parsing a schema doc, but there's no doc"); + return(-1); + } + if (pctxt->constructor == NULL) { + PERROR_INT("xmlSchemaParseNewDoc", + "no constructor"); + return(-1); + } + /* Create and init the temporary parser context. */ + newpctxt = xmlSchemaNewParserCtxtUseDict( + (const char *) bucket->schemaLocation, pctxt->dict); + if (newpctxt == NULL) + return(-1); + newpctxt->constructor = pctxt->constructor; + /* + * TODO: Can we avoid that the parser knows about the main schema? + * It would be better if he knows about the current schema bucket + * only. + */ + newpctxt->schema = schema; + xmlSchemaSetParserErrors(newpctxt, pctxt->error, pctxt->warning, + pctxt->errCtxt); + xmlSchemaSetParserStructuredErrors(newpctxt, pctxt->serror, + pctxt->errCtxt); + newpctxt->counter = pctxt->counter; + + + res = xmlSchemaParseNewDocWithContext(newpctxt, schema, bucket); + + /* Channel back errors and cleanup the temporary parser context. */ + if (res != 0) + pctxt->err = res; + pctxt->nberrors += newpctxt->nberrors; + pctxt->counter = newpctxt->counter; + newpctxt->constructor = NULL; + /* Free the parser context. */ + xmlSchemaFreeParserCtxt(newpctxt); + return(res); +} + +static void +xmlSchemaSchemaRelationAddChild(xmlSchemaBucketPtr bucket, + xmlSchemaSchemaRelationPtr rel) +{ + xmlSchemaSchemaRelationPtr cur = bucket->relations; + + if (cur == NULL) { + bucket->relations = rel; + return; + } + while (cur->next != NULL) + cur = cur->next; + cur->next = rel; +} + + +static const xmlChar * +xmlSchemaBuildAbsoluteURI(xmlDictPtr dict, const xmlChar* location, + xmlNodePtr ctxtNode) +{ + /* + * Build an absolue location URI. + */ + if (location != NULL) { + if (ctxtNode == NULL) + return(location); + else { + xmlChar *base, *URI; + const xmlChar *ret = NULL; + + base = xmlNodeGetBase(ctxtNode->doc, ctxtNode); + if (base == NULL) { + URI = xmlBuildURI(location, ctxtNode->doc->URL); + } else { + URI = xmlBuildURI(location, base); + xmlFree(base); + } + if (URI != NULL) { + ret = xmlDictLookup(dict, URI, -1); + xmlFree(URI); + return(ret); + } + } + } + return(NULL); +} + + + +/** + * xmlSchemaAddSchemaDoc: + * @pctxt: a schema validation context + * @schema: the schema being built + * @node: a subtree containing XML Schema informations + * + * Parse an included (and to-be-redefined) XML schema document. + * + * Returns 0 on success, a positive error code on errors and + * -1 in case of an internal or API error. + */ + +static int +xmlSchemaAddSchemaDoc(xmlSchemaParserCtxtPtr pctxt, + int type, /* import or include or redefine */ + const xmlChar *schemaLocation, + xmlDocPtr schemaDoc, + const char *schemaBuffer, + int schemaBufferLen, + xmlNodePtr invokingNode, + const xmlChar *sourceTargetNamespace, + const xmlChar *importNamespace, + xmlSchemaBucketPtr *bucket) +{ + const xmlChar *targetNamespace = NULL; + xmlSchemaSchemaRelationPtr relation = NULL; + xmlDocPtr doc = NULL; + int res = 0, err = 0, located = 0, preserveDoc = 0; + xmlSchemaBucketPtr bkt = NULL; + + if (bucket != NULL) + *bucket = NULL; + + switch (type) { + case XML_SCHEMA_SCHEMA_IMPORT: + case XML_SCHEMA_SCHEMA_MAIN: + err = XML_SCHEMAP_SRC_IMPORT; + break; + case XML_SCHEMA_SCHEMA_INCLUDE: + err = XML_SCHEMAP_SRC_INCLUDE; + break; + case XML_SCHEMA_SCHEMA_REDEFINE: + err = XML_SCHEMAP_SRC_REDEFINE; + break; + } + + + /* Special handling for the main schema: + * skip the location and relation logic and just parse the doc. + * We need just a bucket to be returned in this case. + */ + if ((type == XML_SCHEMA_SCHEMA_MAIN) || (! WXS_HAS_BUCKETS(pctxt))) + goto doc_load; + + /* Note that we expect the location to be an absulute URI. */ + if (schemaLocation != NULL) { + bkt = xmlSchemaGetSchemaBucket(pctxt, schemaLocation); + if ((bkt != NULL) && + (pctxt->constructor->bucket == bkt)) { + /* Report self-imports/inclusions/redefinitions. */ + + xmlSchemaCustomErr(ACTXT_CAST pctxt, err, + invokingNode, NULL, + "The schema must not import/include/redefine itself", + NULL, NULL); + goto exit; + } + } + /* + * Create a relation for the graph of schemas. + */ + relation = xmlSchemaSchemaRelationCreate(); + if (relation == NULL) + return(-1); + xmlSchemaSchemaRelationAddChild(pctxt->constructor->bucket, + relation); + relation->type = type; + + /* + * Save the namespace import information. + */ + if (WXS_IS_BUCKET_IMPMAIN(type)) { + relation->importNamespace = importNamespace; + if (schemaLocation == NULL) { + /* + * No location; this is just an import of the namespace. + * Note that we don't assign a bucket to the relation + * in this case. + */ + goto exit; + } + targetNamespace = importNamespace; + } + + /* Did we already fetch the doc? */ + if (bkt != NULL) { + if ((WXS_IS_BUCKET_IMPMAIN(type)) && (! bkt->imported)) { + /* + * We included/redefined and then try to import a schema, + * but the new location provided for import was different. + */ + if (schemaLocation == NULL) + schemaLocation = BAD_CAST "in_memory_buffer"; + if (!xmlStrEqual(schemaLocation, + bkt->schemaLocation)) { + xmlSchemaCustomErr(ACTXT_CAST pctxt, err, + invokingNode, NULL, + "The schema document '%s' cannot be imported, since " + "it was already included or redefined", + schemaLocation, NULL); + goto exit; + } + } else if ((! WXS_IS_BUCKET_IMPMAIN(type)) && (bkt->imported)) { + /* + * We imported and then try to include/redefine a schema, + * but the new location provided for the include/redefine + * was different. + */ + if (schemaLocation == NULL) + schemaLocation = BAD_CAST "in_memory_buffer"; + if (!xmlStrEqual(schemaLocation, + bkt->schemaLocation)) { + xmlSchemaCustomErr(ACTXT_CAST pctxt, err, + invokingNode, NULL, + "The schema document '%s' cannot be included or " + "redefined, since it was already imported", + schemaLocation, NULL); + goto exit; + } + } + } + + if (WXS_IS_BUCKET_IMPMAIN(type)) { + /* + * Given that the schemaLocation [attribute] is only a hint, it is open + * to applications to ignore all but the first for a given + * namespace, regardless of the �actual value� of schemaLocation, but + * such a strategy risks missing useful information when new + * schemaLocations are offered. + * + * We will use the first that comes with a location. + * Further s *with* a location, will result in an error. + * TODO: Better would be to just report a warning here, but + * we'll try it this way until someone complains. + * + * Schema Document Location Strategy: + * 3 Based on the namespace name, identify an existing schema document, + * either as a resource which is an XML document or a element + * information item, in some local schema repository; + * 5 Attempt to resolve the namespace name to locate such a resource. + * + * NOTE: (3) and (5) are not supported. + */ + if (bkt != NULL) { + relation->bucket = bkt; + goto exit; + } + bkt = xmlSchemaGetSchemaBucketByTNS(pctxt, + importNamespace, 1); + + if (bkt != NULL) { + relation->bucket = bkt; + if (bkt->schemaLocation == NULL) { + /* First given location of the schema; load the doc. */ + bkt->schemaLocation = schemaLocation; + } else { + if (!xmlStrEqual(schemaLocation, + bkt->schemaLocation)) { + /* + * Additional location given; just skip it. + * URGENT TODO: We should report a warning here. + * res = XML_SCHEMAP_SRC_IMPORT; + */ + if (schemaLocation == NULL) + schemaLocation = BAD_CAST "in_memory_buffer"; + + xmlSchemaCustomWarning(ACTXT_CAST pctxt, + XML_SCHEMAP_WARN_SKIP_SCHEMA, + invokingNode, NULL, + "Skipping import of schema located at '%s' for the " + "namespace '%s', since this namespace was already " + "imported with the schema located at '%s'", + schemaLocation, importNamespace, bkt->schemaLocation); + } + goto exit; + } + } + /* + * No bucket + first location: load the doc and create a + * bucket. + */ + } else { + /* and */ + if (bkt != NULL) { + + if ((bkt->origTargetNamespace == NULL) && + (bkt->targetNamespace != sourceTargetNamespace)) { + xmlSchemaBucketPtr chamel; + + /* + * Chameleon include/redefine: skip loading only if it was + * aleady build for the targetNamespace of the including + * schema. + */ + /* + * URGENT TODO: If the schema is a chameleon-include then copy + * the components into the including schema and modify the + * targetNamespace of those components, do nothing otherwise. + * NOTE: This is currently worked-around by compiling the + * chameleon for every destinct including targetNamespace; thus + * not performant at the moment. + * TODO: Check when the namespace in wildcards for chameleons + * needs to be converted: before we built wildcard intersections + * or after. + * Answer: after! + */ + chamel = xmlSchemaGetChameleonSchemaBucket(pctxt, + schemaLocation, sourceTargetNamespace); + if (chamel != NULL) { + /* A fitting chameleon was already parsed; NOP. */ + relation->bucket = chamel; + goto exit; + } + /* + * We need to parse the chameleon again for a different + * targetNamespace. + * CHAMELEON TODO: Optimize this by only parsing the + * chameleon once, and then copying the components to + * the new targetNamespace. + */ + bkt = NULL; + } else { + relation->bucket = bkt; + goto exit; + } + } + } + if ((bkt != NULL) && (bkt->doc != NULL)) { + PERROR_INT("xmlSchemaAddSchemaDoc", + "trying to load a schema doc, but a doc is already " + "assigned to the schema bucket"); + goto exit_failure; + } + +doc_load: + /* + * Load the document. + */ + if (schemaDoc != NULL) { + doc = schemaDoc; + /* Don' free this one, since it was provided by the caller. */ + preserveDoc = 1; + /* TODO: Does the context or the doc hold the location? */ + if (schemaDoc->URL != NULL) + schemaLocation = xmlDictLookup(pctxt->dict, + schemaDoc->URL, -1); + else + schemaLocation = BAD_CAST "in_memory_buffer"; + } else if ((schemaLocation != NULL) || (schemaBuffer != NULL)) { + xmlParserCtxtPtr parserCtxt; + + parserCtxt = xmlNewParserCtxt(); + if (parserCtxt == NULL) { + xmlSchemaPErrMemory(NULL, "xmlSchemaGetDoc, " + "allocating a parser context", NULL); + goto exit_failure; + } + if ((pctxt->dict != NULL) && (parserCtxt->dict != NULL)) { + /* + * TODO: Do we have to burden the schema parser dict with all + * the content of the schema doc? + */ + xmlDictFree(parserCtxt->dict); + parserCtxt->dict = pctxt->dict; + xmlDictReference(parserCtxt->dict); + } + if (schemaLocation != NULL) { + /* Parse from file. */ + doc = xmlCtxtReadFile(parserCtxt, (const char *) schemaLocation, + NULL, SCHEMAS_PARSE_OPTIONS); + } else if (schemaBuffer != NULL) { + /* Parse from memory buffer. */ + doc = xmlCtxtReadMemory(parserCtxt, schemaBuffer, schemaBufferLen, + NULL, NULL, SCHEMAS_PARSE_OPTIONS); + schemaLocation = BAD_CAST "in_memory_buffer"; + if (doc != NULL) + doc->URL = xmlStrdup(schemaLocation); + } + /* + * For : + * 2.1 The referent is (a fragment of) a resource which is an + * XML document (see clause 1.1), which in turn corresponds to + * a element information item in a well-formed information + * set, which in turn corresponds to a valid schema. + * TODO: (2.1) fragments of XML documents are not supported. + * + * 2.2 The referent is a element information item in + * a well-formed information set, which in turn corresponds + * to a valid schema. + * TODO: (2.2) is not supported. + */ + if (doc == NULL) { + xmlErrorPtr lerr; + lerr = xmlGetLastError(); + /* + * Check if this a parser error, or if the document could + * just not be located. + * TODO: Try to find specific error codes to react only on + * localisation failures. + */ + if ((lerr == NULL) || (lerr->domain != XML_FROM_IO)) { + /* + * We assume a parser error here. + */ + located = 1; + /* TODO: Error code ?? */ + res = XML_SCHEMAP_SRC_IMPORT_2_1; + xmlSchemaCustomErr(ACTXT_CAST pctxt, res, + invokingNode, NULL, + "Failed to parse the XML resource '%s'", + schemaLocation, NULL); + } + } + xmlFreeParserCtxt(parserCtxt); + if ((doc == NULL) && located) + goto exit_error; + } else { + xmlSchemaPErr(pctxt, NULL, + XML_SCHEMAP_NOTHING_TO_PARSE, + "No information for parsing was provided with the " + "given schema parser context.\n", + NULL, NULL); + goto exit_failure; + } + /* + * Preprocess the document. + */ + if (doc != NULL) { + xmlNodePtr docElem = NULL; + + located = 1; + docElem = xmlDocGetRootElement(doc); + if (docElem == NULL) { + xmlSchemaCustomErr(ACTXT_CAST pctxt, XML_SCHEMAP_NOROOT, + invokingNode, NULL, + "The document '%s' has no document element", + schemaLocation, NULL); + goto exit_error; + } + /* + * Remove all the blank text nodes. + */ + xmlSchemaCleanupDoc(pctxt, docElem); + /* + * Check the schema's top level element. + */ + if (!IS_SCHEMA(docElem, "schema")) { + xmlSchemaCustomErr(ACTXT_CAST pctxt, XML_SCHEMAP_NOT_SCHEMA, + invokingNode, NULL, + "The XML document '%s' is not a schema document", + schemaLocation, NULL); + goto exit_error; + } + /* + * Note that we don't apply a type check for the + * targetNamespace value here. + */ + targetNamespace = xmlSchemaGetProp(pctxt, docElem, + "targetNamespace"); + } + +/* after_doc_loading: */ + if ((bkt == NULL) && located) { + /* Only create a bucket if the schema was located. */ + bkt = xmlSchemaBucketCreate(pctxt, type, + targetNamespace); + if (bkt == NULL) + goto exit_failure; + } + if (bkt != NULL) { + bkt->schemaLocation = schemaLocation; + bkt->located = located; + if (doc != NULL) { + bkt->doc = doc; + bkt->targetNamespace = targetNamespace; + bkt->origTargetNamespace = targetNamespace; + if (preserveDoc) + bkt->preserveDoc = 1; + } + if (WXS_IS_BUCKET_IMPMAIN(type)) + bkt->imported++; + /* + * Add it to the graph of schemas. + */ + if (relation != NULL) + relation->bucket = bkt; + } + +exit: + /* + * Return the bucket explicitely; this is needed for the + * main schema. + */ + if (bucket != NULL) + *bucket = bkt; + return (0); + +exit_error: + if ((doc != NULL) && (! preserveDoc)) { + xmlFreeDoc(doc); + if (bkt != NULL) + bkt->doc = NULL; + } + return(pctxt->err); + +exit_failure: + if ((doc != NULL) && (! preserveDoc)) { + xmlFreeDoc(doc); + if (bkt != NULL) + bkt->doc = NULL; + } + return (-1); +} + +/** + * xmlSchemaParseImport: + * @ctxt: a schema validation context + * @schema: the schema being built + * @node: a subtree containing XML Schema informations + * + * parse a XML schema Import definition + * *WARNING* this interface is highly subject to change + * + * Returns 0 in case of success, a positive error code if + * not valid and -1 in case of an internal error. + */ +static int +xmlSchemaParseImport(xmlSchemaParserCtxtPtr pctxt, xmlSchemaPtr schema, + xmlNodePtr node) +{ + xmlNodePtr child; + const xmlChar *namespaceName = NULL, *schemaLocation = NULL; + const xmlChar *thisTargetNamespace; + xmlAttrPtr attr; + int ret = 0; + xmlSchemaBucketPtr bucket = NULL; + + if ((pctxt == NULL) || (schema == NULL) || (node == NULL)) + return (-1); + + /* + * Check for illegal attributes. + */ + attr = node->properties; + while (attr != NULL) { + if (attr->ns == NULL) { + if ((!xmlStrEqual(attr->name, BAD_CAST "id")) && + (!xmlStrEqual(attr->name, BAD_CAST "namespace")) && + (!xmlStrEqual(attr->name, BAD_CAST "schemaLocation"))) { + xmlSchemaPIllegalAttrErr(pctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + } else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) { + xmlSchemaPIllegalAttrErr(pctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + attr = attr->next; + } + /* + * Extract and validate attributes. + */ + if (xmlSchemaPValAttr(pctxt, NULL, node, + "namespace", xmlSchemaGetBuiltInType(XML_SCHEMAS_ANYURI), + &namespaceName) != 0) { + xmlSchemaPSimpleTypeErr(pctxt, + XML_SCHEMAP_S4S_ATTR_INVALID_VALUE, + NULL, node, + xmlSchemaGetBuiltInType(XML_SCHEMAS_ANYURI), + NULL, namespaceName, NULL, NULL, NULL); + return (pctxt->err); + } + + if (xmlSchemaPValAttr(pctxt, NULL, node, + "schemaLocation", xmlSchemaGetBuiltInType(XML_SCHEMAS_ANYURI), + &schemaLocation) != 0) { + xmlSchemaPSimpleTypeErr(pctxt, + XML_SCHEMAP_S4S_ATTR_INVALID_VALUE, + NULL, node, + xmlSchemaGetBuiltInType(XML_SCHEMAS_ANYURI), + NULL, namespaceName, NULL, NULL, NULL); + return (pctxt->err); + } + /* + * And now for the children... + */ + child = node->children; + if (IS_SCHEMA(child, "annotation")) { + /* + * the annotation here is simply discarded ... + * TODO: really? + */ + child = child->next; + } + if (child != NULL) { + xmlSchemaPContentErr(pctxt, + XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED, + NULL, node, child, NULL, + "(annotation?)"); + } + /* + * Apply additional constraints. + * + * Note that it is important to use the original @targetNamespace + * (or none at all), to rule out imports of schemas _with_ a + * @targetNamespace if the importing schema is a chameleon schema + * (with no @targetNamespace). + */ + thisTargetNamespace = WXS_BUCKET(pctxt)->origTargetNamespace; + if (namespaceName != NULL) { + /* + * 1.1 If the namespace [attribute] is present, then its �actual value� + * must not match the �actual value� of the enclosing 's + * targetNamespace [attribute]. + */ + if (xmlStrEqual(thisTargetNamespace, namespaceName)) { + xmlSchemaPCustomErr(pctxt, + XML_SCHEMAP_SRC_IMPORT_1_1, + NULL, node, + "The value of the attribute 'namespace' must not match " + "the target namespace '%s' of the importing schema", + thisTargetNamespace); + return (pctxt->err); + } + } else { + /* + * 1.2 If the namespace [attribute] is not present, then the enclosing + * must have a targetNamespace [attribute]. + */ + if (thisTargetNamespace == NULL) { + xmlSchemaPCustomErr(pctxt, + XML_SCHEMAP_SRC_IMPORT_1_2, + NULL, node, + "The attribute 'namespace' must be existent if " + "the importing schema has no target namespace", + NULL); + return (pctxt->err); + } + } + /* + * Locate and acquire the schema document. + */ + if (schemaLocation != NULL) + schemaLocation = xmlSchemaBuildAbsoluteURI(pctxt->dict, + schemaLocation, node); + ret = xmlSchemaAddSchemaDoc(pctxt, XML_SCHEMA_SCHEMA_IMPORT, + schemaLocation, NULL, NULL, 0, node, thisTargetNamespace, + namespaceName, &bucket); + + if (ret != 0) + return(ret); + + /* + * For : "It is *not* an error for the application + * schema reference strategy to fail." + * So just don't parse if no schema document was found. + * Note that we will get no bucket if the schema could not be + * located or if there was no schemaLocation. + */ + if ((bucket == NULL) && (schemaLocation != NULL)) { + xmlSchemaCustomWarning(ACTXT_CAST pctxt, + XML_SCHEMAP_WARN_UNLOCATED_SCHEMA, + node, NULL, + "Failed to locate a schema at location '%s'. " + "Skipping the import", schemaLocation, NULL, NULL); + } + + if ((bucket != NULL) && CAN_PARSE_SCHEMA(bucket)) { + ret = xmlSchemaParseNewDoc(pctxt, schema, bucket); + } + + return (ret); +} + +static int +xmlSchemaParseIncludeOrRedefineAttrs(xmlSchemaParserCtxtPtr pctxt, + xmlSchemaPtr schema, + xmlNodePtr node, + xmlChar **schemaLocation, + int type) +{ + xmlAttrPtr attr; + + if ((pctxt == NULL) || (schema == NULL) || (node == NULL) || + (schemaLocation == NULL)) + return (-1); + + *schemaLocation = NULL; + /* + * Check for illegal attributes. + * Applies for both and . + */ + attr = node->properties; + while (attr != NULL) { + if (attr->ns == NULL) { + if ((!xmlStrEqual(attr->name, BAD_CAST "id")) && + (!xmlStrEqual(attr->name, BAD_CAST "schemaLocation"))) { + xmlSchemaPIllegalAttrErr(pctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + } else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) { + xmlSchemaPIllegalAttrErr(pctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + attr = attr->next; + } + xmlSchemaPValAttrID(pctxt, node, BAD_CAST "id"); + /* + * Preliminary step, extract the URI-Reference and make an URI + * from the base. + */ + /* + * Attribute "schemaLocation" is mandatory. + */ + attr = xmlSchemaGetPropNode(node, "schemaLocation"); + if (attr != NULL) { + xmlChar *base = NULL; + xmlChar *uri = NULL; + + if (xmlSchemaPValAttrNode(pctxt, NULL, attr, + xmlSchemaGetBuiltInType(XML_SCHEMAS_ANYURI), + (const xmlChar **) schemaLocation) != 0) + goto exit_error; + base = xmlNodeGetBase(node->doc, node); + if (base == NULL) { + uri = xmlBuildURI(*schemaLocation, node->doc->URL); + } else { + uri = xmlBuildURI(*schemaLocation, base); + xmlFree(base); + } + if (uri == NULL) { + PERROR_INT("xmlSchemaParseIncludeOrRedefine", + "could not build an URI from the schemaLocation") + goto exit_failure; + } + (*schemaLocation) = (xmlChar *) xmlDictLookup(pctxt->dict, uri, -1); + xmlFree(uri); + } else { + xmlSchemaPMissingAttrErr(pctxt, + XML_SCHEMAP_S4S_ATTR_MISSING, + NULL, node, "schemaLocation", NULL); + goto exit_error; + } + /* + * Report self-inclusion and self-redefinition. + */ + if (xmlStrEqual(*schemaLocation, pctxt->URL)) { + if (type == XML_SCHEMA_SCHEMA_REDEFINE) { + xmlSchemaPCustomErr(pctxt, + XML_SCHEMAP_SRC_REDEFINE, + NULL, node, + "The schema document '%s' cannot redefine itself.", + *schemaLocation); + } else { + xmlSchemaPCustomErr(pctxt, + XML_SCHEMAP_SRC_INCLUDE, + NULL, node, + "The schema document '%s' cannot include itself.", + *schemaLocation); + } + goto exit_error; + } + + return(0); +exit_error: + return(pctxt->err); +exit_failure: + return(-1); +} + +static int +xmlSchemaParseIncludeOrRedefine(xmlSchemaParserCtxtPtr pctxt, + xmlSchemaPtr schema, + xmlNodePtr node, + int type) +{ + xmlNodePtr child = NULL; + const xmlChar *schemaLocation = NULL; + int res = 0; /* hasRedefinitions = 0 */ + int isChameleon = 0, wasChameleon = 0; + xmlSchemaBucketPtr bucket = NULL; + + if ((pctxt == NULL) || (schema == NULL) || (node == NULL)) + return (-1); + + /* + * Parse attributes. Note that the returned schemaLocation will + * be already converted to an absolute URI. + */ + res = xmlSchemaParseIncludeOrRedefineAttrs(pctxt, schema, + node, (xmlChar **) (&schemaLocation), type); + if (res != 0) + return(res); + /* + * Load and add the schema document. + */ + res = xmlSchemaAddSchemaDoc(pctxt, type, schemaLocation, NULL, + NULL, 0, node, pctxt->targetNamespace, NULL, &bucket); + if (res != 0) + return(res); + /* + * If we get no schema bucket back, then this means that the schema + * document could not be located or was broken XML or was not + * a schema document. + */ + if ((bucket == NULL) || (bucket->doc == NULL)) { + if (type == XML_SCHEMA_SCHEMA_INCLUDE) { + /* + * WARNING for : + * We will raise an error if the schema cannot be located + * for inclusions, since the that was the feedback from the + * schema people. I.e. the following spec piece will *not* be + * satisfied: + * SPEC src-include: "It is not an error for the �actual value� of the + * schemaLocation [attribute] to fail to resolve it all, in which + * case no corresponding inclusion is performed. + * So do we need a warning report here?" + */ + res = XML_SCHEMAP_SRC_INCLUDE; + xmlSchemaCustomErr(ACTXT_CAST pctxt, res, + node, NULL, + "Failed to load the document '%s' for inclusion", + schemaLocation, NULL); + } else { + /* + * NOTE: This was changed to raise an error even if no redefinitions + * are specified. + * + * SPEC src-redefine (1) + * "If there are any element information items among the [children] + * other than then the �actual value� of the + * schemaLocation [attribute] must successfully resolve." + * TODO: Ask the WG if a the location has always to resolve + * here as well! + */ + res = XML_SCHEMAP_SRC_REDEFINE; + xmlSchemaCustomErr(ACTXT_CAST pctxt, res, + node, NULL, + "Failed to load the document '%s' for redefinition", + schemaLocation, NULL); + } + } else { + /* + * Check targetNamespace sanity before parsing the new schema. + * TODO: Note that we won't check further content if the + * targetNamespace was bad. + */ + if (bucket->origTargetNamespace != NULL) { + /* + * SPEC src-include (2.1) + * "SII has a targetNamespace [attribute], and its �actual + * value� is identical to the �actual value� of the targetNamespace + * [attribute] of SII� (which must have such an [attribute])." + */ + if (pctxt->targetNamespace == NULL) { + xmlSchemaCustomErr(ACTXT_CAST pctxt, + XML_SCHEMAP_SRC_INCLUDE, + node, NULL, + "The target namespace of the included/redefined schema " + "'%s' has to be absent, since the including/redefining " + "schema has no target namespace", + schemaLocation, NULL); + goto exit_error; + } else if (!xmlStrEqual(bucket->origTargetNamespace, + pctxt->targetNamespace)) { + /* TODO: Change error function. */ + xmlSchemaPCustomErrExt(pctxt, + XML_SCHEMAP_SRC_INCLUDE, + NULL, node, + "The target namespace '%s' of the included/redefined " + "schema '%s' differs from '%s' of the " + "including/redefining schema", + bucket->origTargetNamespace, schemaLocation, + pctxt->targetNamespace); + goto exit_error; + } + } else if (pctxt->targetNamespace != NULL) { + /* + * Chameleons: the original target namespace will + * differ from the resulting namespace. + */ + isChameleon = 1; + if (bucket->parsed && + bucket->origTargetNamespace != NULL) { + xmlSchemaCustomErr(ACTXT_CAST pctxt, + XML_SCHEMAP_SRC_INCLUDE, + node, NULL, + "The target namespace of the included/redefined schema " + "'%s' has to be absent or the same as the " + "including/redefining schema's target namespace", + schemaLocation, NULL); + goto exit_error; + } + bucket->targetNamespace = pctxt->targetNamespace; + } + } + /* + * Parse the schema. + */ + if (bucket && (!bucket->parsed) && (bucket->doc != NULL)) { + if (isChameleon) { + /* TODO: Get rid of this flag on the schema itself. */ + if ((schema->flags & XML_SCHEMAS_INCLUDING_CONVERT_NS) == 0) { + schema->flags |= XML_SCHEMAS_INCLUDING_CONVERT_NS; + } else + wasChameleon = 1; + } + xmlSchemaParseNewDoc(pctxt, schema, bucket); + /* Restore chameleon flag. */ + if (isChameleon && (!wasChameleon)) + schema->flags ^= XML_SCHEMAS_INCLUDING_CONVERT_NS; + } + /* + * And now for the children... + */ + child = node->children; + if (type == XML_SCHEMA_SCHEMA_REDEFINE) { + /* + * Parse (simpleType | complexType | group | attributeGroup))* + */ + pctxt->redefined = bucket; + /* + * How to proceed if the redefined schema was not located? + */ + pctxt->isRedefine = 1; + while (IS_SCHEMA(child, "annotation") || + IS_SCHEMA(child, "simpleType") || + IS_SCHEMA(child, "complexType") || + IS_SCHEMA(child, "group") || + IS_SCHEMA(child, "attributeGroup")) { + if (IS_SCHEMA(child, "annotation")) { + /* + * TODO: discard or not? + */ + } else if (IS_SCHEMA(child, "simpleType")) { + xmlSchemaParseSimpleType(pctxt, schema, child, 1); + } else if (IS_SCHEMA(child, "complexType")) { + xmlSchemaParseComplexType(pctxt, schema, child, 1); + /* hasRedefinitions = 1; */ + } else if (IS_SCHEMA(child, "group")) { + /* hasRedefinitions = 1; */ + xmlSchemaParseModelGroupDefinition(pctxt, + schema, child); + } else if (IS_SCHEMA(child, "attributeGroup")) { + /* hasRedefinitions = 1; */ + xmlSchemaParseAttributeGroupDefinition(pctxt, schema, + child); + } + child = child->next; + } + pctxt->redefined = NULL; + pctxt->isRedefine = 0; + } else { + if (IS_SCHEMA(child, "annotation")) { + /* + * TODO: discard or not? + */ + child = child->next; + } + } + if (child != NULL) { + res = XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED; + if (type == XML_SCHEMA_SCHEMA_REDEFINE) { + xmlSchemaPContentErr(pctxt, res, + NULL, node, child, NULL, + "(annotation | (simpleType | complexType | group | attributeGroup))*"); + } else { + xmlSchemaPContentErr(pctxt, res, + NULL, node, child, NULL, + "(annotation?)"); + } + } + return(res); + +exit_error: + return(pctxt->err); +} + +static int +xmlSchemaParseRedefine(xmlSchemaParserCtxtPtr pctxt, xmlSchemaPtr schema, + xmlNodePtr node) +{ + int res; +#ifndef ENABLE_REDEFINE + TODO + return(0); +#endif + res = xmlSchemaParseIncludeOrRedefine(pctxt, schema, node, + XML_SCHEMA_SCHEMA_REDEFINE); + if (res != 0) + return(res); + return(0); +} + +static int +xmlSchemaParseInclude(xmlSchemaParserCtxtPtr pctxt, xmlSchemaPtr schema, + xmlNodePtr node) +{ + int res; + + res = xmlSchemaParseIncludeOrRedefine(pctxt, schema, node, + XML_SCHEMA_SCHEMA_INCLUDE); + if (res != 0) + return(res); + return(0); +} + +/** + * xmlSchemaParseModelGroup: + * @ctxt: a schema validation context + * @schema: the schema being built + * @node: a subtree containing XML Schema informations + * @type: the "compositor" type + * @particleNeeded: if a a model group with a particle + * + * parse a XML schema Sequence definition. + * Applies parts of: + * Schema Representation Constraint: + * Redefinition Constraints and Semantics (src-redefine) + * (6.1), (6.1.1), (6.1.2) + * + * Schema Component Constraint: + * All Group Limited (cos-all-limited) (2) + * TODO: Actually this should go to component-level checks, + * but is done here due to performance. Move it to an other layer + * is schema construction via an API is implemented. + * + * *WARNING* this interface is highly subject to change + * + * Returns -1 in case of error, 0 if the declaration is improper and + * 1 in case of success. + */ +static xmlSchemaTreeItemPtr +xmlSchemaParseModelGroup(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, + xmlNodePtr node, xmlSchemaTypeType type, + int withParticle) +{ + xmlSchemaModelGroupPtr item; + xmlSchemaParticlePtr particle = NULL; + xmlNodePtr child = NULL; + xmlAttrPtr attr; + int min = 1, max = 1, isElemRef, hasRefs = 0; + + if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) + return (NULL); + /* + * Create a model group with the given compositor. + */ + item = xmlSchemaAddModelGroup(ctxt, schema, type, node); + if (item == NULL) + return (NULL); + + if (withParticle) { + if (type == XML_SCHEMA_TYPE_ALL) { + min = xmlGetMinOccurs(ctxt, node, 0, 1, 1, "(0 | 1)"); + max = xmlGetMaxOccurs(ctxt, node, 1, 1, 1, "1"); + } else { + /* choice + sequence */ + min = xmlGetMinOccurs(ctxt, node, 0, -1, 1, "xs:nonNegativeInteger"); + max = xmlGetMaxOccurs(ctxt, node, 0, UNBOUNDED, 1, + "(xs:nonNegativeInteger | unbounded)"); + } + xmlSchemaPCheckParticleCorrect_2(ctxt, NULL, node, min, max); + /* + * Create a particle + */ + particle = xmlSchemaAddParticle(ctxt, node, min, max); + if (particle == NULL) + return (NULL); + particle->children = (xmlSchemaTreeItemPtr) item; + /* + * Check for illegal attributes. + */ + attr = node->properties; + while (attr != NULL) { + if (attr->ns == NULL) { + if ((!xmlStrEqual(attr->name, BAD_CAST "id")) && + (!xmlStrEqual(attr->name, BAD_CAST "maxOccurs")) && + (!xmlStrEqual(attr->name, BAD_CAST "minOccurs"))) { + xmlSchemaPIllegalAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + } else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) { + xmlSchemaPIllegalAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + attr = attr->next; + } + } else { + /* + * Check for illegal attributes. + */ + attr = node->properties; + while (attr != NULL) { + if (attr->ns == NULL) { + if (!xmlStrEqual(attr->name, BAD_CAST "id")) { + xmlSchemaPIllegalAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + } else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) { + xmlSchemaPIllegalAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + attr = attr->next; + } + } + + /* + * Extract and validate attributes. + */ + xmlSchemaPValAttrID(ctxt, node, BAD_CAST "id"); + /* + * And now for the children... + */ + child = node->children; + if (IS_SCHEMA(child, "annotation")) { + item->annot = xmlSchemaParseAnnotation(ctxt, child, 1); + child = child->next; + } + if (type == XML_SCHEMA_TYPE_ALL) { + xmlSchemaParticlePtr part, last = NULL; + + while (IS_SCHEMA(child, "element")) { + part = (xmlSchemaParticlePtr) xmlSchemaParseElement(ctxt, + schema, child, &isElemRef, 0); + /* + * SPEC cos-all-limited (2) + * "The {max occurs} of all the particles in the {particles} + * of the ('all') group must be 0 or 1. + */ + if (part != NULL) { + if (isElemRef) + hasRefs++; + if (part->minOccurs > 1) { + xmlSchemaPCustomErr(ctxt, + XML_SCHEMAP_COS_ALL_LIMITED, + NULL, child, + "Invalid value for minOccurs (must be 0 or 1)", + NULL); + /* Reset to 1. */ + part->minOccurs = 1; + } + if (part->maxOccurs > 1) { + xmlSchemaPCustomErr(ctxt, + XML_SCHEMAP_COS_ALL_LIMITED, + NULL, child, + "Invalid value for maxOccurs (must be 0 or 1)", + NULL); + /* Reset to 1. */ + part->maxOccurs = 1; + } + if (last == NULL) + item->children = (xmlSchemaTreeItemPtr) part; + else + last->next = (xmlSchemaTreeItemPtr) part; + last = part; + } + child = child->next; + } + if (child != NULL) { + xmlSchemaPContentErr(ctxt, + XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED, + NULL, node, child, NULL, + "(annotation?, (annotation?, element*)"); + } + } else { + /* choice + sequence */ + xmlSchemaTreeItemPtr part = NULL, last = NULL; + + while ((IS_SCHEMA(child, "element")) || + (IS_SCHEMA(child, "group")) || + (IS_SCHEMA(child, "any")) || + (IS_SCHEMA(child, "choice")) || + (IS_SCHEMA(child, "sequence"))) { + + if (IS_SCHEMA(child, "element")) { + part = (xmlSchemaTreeItemPtr) + xmlSchemaParseElement(ctxt, schema, child, &isElemRef, 0); + if (part && isElemRef) + hasRefs++; + } else if (IS_SCHEMA(child, "group")) { + part = + xmlSchemaParseModelGroupDefRef(ctxt, schema, child); + if (part != NULL) + hasRefs++; + /* + * Handle redefinitions. + */ + if (ctxt->isRedefine && ctxt->redef && + (ctxt->redef->item->type == XML_SCHEMA_TYPE_GROUP) && + part && part->children) + { + if ((xmlSchemaGetQNameRefName(part->children) == + ctxt->redef->refName) && + (xmlSchemaGetQNameRefTargetNs(part->children) == + ctxt->redef->refTargetNs)) + { + /* + * SPEC src-redefine: + * (6.1) "If it has a among its contents at + * some level the �actual value� of whose ref + * [attribute] is the same as the �actual value� of + * its own name attribute plus target namespace, then + * all of the following must be true:" + * (6.1.1) "It must have exactly one such group." + */ + if (ctxt->redefCounter != 0) { + xmlChar *str = NULL; + + xmlSchemaCustomErr(ACTXT_CAST ctxt, + XML_SCHEMAP_SRC_REDEFINE, child, NULL, + "The redefining model group definition " + "'%s' must not contain more than one " + "reference to the redefined definition", + xmlSchemaFormatQName(&str, + ctxt->redef->refTargetNs, + ctxt->redef->refName), + NULL); + FREE_AND_NULL(str) + part = NULL; + } else if (((WXS_PARTICLE(part))->minOccurs != 1) || + ((WXS_PARTICLE(part))->maxOccurs != 1)) + { + xmlChar *str = NULL; + /* + * SPEC src-redefine: + * (6.1.2) "The �actual value� of both that + * group's minOccurs and maxOccurs [attribute] + * must be 1 (or �absent�). + */ + xmlSchemaCustomErr(ACTXT_CAST ctxt, + XML_SCHEMAP_SRC_REDEFINE, child, NULL, + "The redefining model group definition " + "'%s' must not contain a reference to the " + "redefined definition with a " + "maxOccurs/minOccurs other than 1", + xmlSchemaFormatQName(&str, + ctxt->redef->refTargetNs, + ctxt->redef->refName), + NULL); + FREE_AND_NULL(str) + part = NULL; + } + ctxt->redef->reference = WXS_BASIC_CAST part; + ctxt->redefCounter++; + } + } + } else if (IS_SCHEMA(child, "any")) { + part = (xmlSchemaTreeItemPtr) + xmlSchemaParseAny(ctxt, schema, child); + } else if (IS_SCHEMA(child, "choice")) { + part = xmlSchemaParseModelGroup(ctxt, schema, child, + XML_SCHEMA_TYPE_CHOICE, 1); + } else if (IS_SCHEMA(child, "sequence")) { + part = xmlSchemaParseModelGroup(ctxt, schema, child, + XML_SCHEMA_TYPE_SEQUENCE, 1); + } + if (part != NULL) { + if (last == NULL) + item->children = part; + else + last->next = part; + last = part; + } + child = child->next; + } + if (child != NULL) { + xmlSchemaPContentErr(ctxt, + XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED, + NULL, node, child, NULL, + "(annotation?, (element | group | choice | sequence | any)*)"); + } + } + if ((max == 0) && (min == 0)) + return (NULL); + if (hasRefs) { + /* + * We need to resolve references. + */ + WXS_ADD_PENDING(ctxt, item); + } + if (withParticle) + return ((xmlSchemaTreeItemPtr) particle); + else + return ((xmlSchemaTreeItemPtr) item); +} + +/** + * xmlSchemaParseRestriction: + * @ctxt: a schema validation context + * @schema: the schema being built + * @node: a subtree containing XML Schema informations + * + * parse a XML schema Restriction definition + * *WARNING* this interface is highly subject to change + * + * Returns the type definition or NULL in case of error + */ +static xmlSchemaTypePtr +xmlSchemaParseRestriction(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, + xmlNodePtr node, xmlSchemaTypeType parentType) +{ + xmlSchemaTypePtr type; + xmlNodePtr child = NULL; + xmlAttrPtr attr; + + if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) + return (NULL); + /* Not a component, don't create it. */ + type = ctxt->ctxtType; + type->flags |= XML_SCHEMAS_TYPE_DERIVATION_METHOD_RESTRICTION; + + /* + * Check for illegal attributes. + */ + attr = node->properties; + while (attr != NULL) { + if (attr->ns == NULL) { + if ((!xmlStrEqual(attr->name, BAD_CAST "id")) && + (!xmlStrEqual(attr->name, BAD_CAST "base"))) { + xmlSchemaPIllegalAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + } else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) { + xmlSchemaPIllegalAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + attr = attr->next; + } + /* + * Extract and validate attributes. + */ + xmlSchemaPValAttrID(ctxt, node, BAD_CAST "id"); + /* + * Attribute + */ + /* + * Extract the base type. The "base" attribute is mandatory if inside + * a complex type or if redefining. + * + * SPEC (1.2) "...otherwise ( has no " + * among its [children]), the simple type definition which is + * the {content type} of the type definition �resolved� to by + * the �actual value� of the base [attribute]" + */ + if (xmlSchemaPValAttrQName(ctxt, schema, NULL, node, "base", + &(type->baseNs), &(type->base)) == 0) + { + if ((type->base == NULL) && (type->type == XML_SCHEMA_TYPE_COMPLEX)) { + xmlSchemaPMissingAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_MISSING, + NULL, node, "base", NULL); + } else if ((ctxt->isRedefine) && + (type->flags & XML_SCHEMAS_TYPE_GLOBAL)) + { + if (type->base == NULL) { + xmlSchemaPMissingAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_MISSING, + NULL, node, "base", NULL); + } else if ((! xmlStrEqual(type->base, type->name)) || + (! xmlStrEqual(type->baseNs, type->targetNamespace))) + { + xmlChar *str1 = NULL, *str2 = NULL; + /* + * REDEFINE: SPEC src-redefine (5) + * "Within the [children], each must have a + * among its [children] ... the �actual value� of + * whose base [attribute] must be the same as the �actual value� + * of its own name attribute plus target namespace;" + */ + xmlSchemaPCustomErrExt(ctxt, XML_SCHEMAP_SRC_REDEFINE, + NULL, node, "This is a redefinition, but the QName " + "value '%s' of the 'base' attribute does not match the " + "type's designation '%s'", + xmlSchemaFormatQName(&str1, type->baseNs, type->base), + xmlSchemaFormatQName(&str2, type->targetNamespace, + type->name), NULL); + FREE_AND_NULL(str1); + FREE_AND_NULL(str2); + /* Avoid confusion and erase the values. */ + type->base = NULL; + type->baseNs = NULL; + } + } + } + /* + * And now for the children... + */ + child = node->children; + if (IS_SCHEMA(child, "annotation")) { + /* + * Add the annotation to the simple type ancestor. + */ + xmlSchemaAddAnnotation((xmlSchemaAnnotItemPtr) type, + xmlSchemaParseAnnotation(ctxt, child, 1)); + child = child->next; + } + if (parentType == XML_SCHEMA_TYPE_SIMPLE) { + /* + * Corresponds to . + */ + if (IS_SCHEMA(child, "simpleType")) { + if (type->base != NULL) { + /* + * src-restriction-base-or-simpleType + * Either the base [attribute] or the simpleType [child] of the + * element must be present, but not both. + */ + xmlSchemaPContentErr(ctxt, + XML_SCHEMAP_SRC_RESTRICTION_BASE_OR_SIMPLETYPE, + NULL, node, child, + "The attribute 'base' and the child are " + "mutually exclusive", NULL); + } else { + type->baseType = (xmlSchemaTypePtr) + xmlSchemaParseSimpleType(ctxt, schema, child, 0); + } + child = child->next; + } else if (type->base == NULL) { + xmlSchemaPContentErr(ctxt, + XML_SCHEMAP_SRC_RESTRICTION_BASE_OR_SIMPLETYPE, + NULL, node, child, + "Either the attribute 'base' or a child " + "must be present", NULL); + } + } else if (parentType == XML_SCHEMA_TYPE_COMPLEX_CONTENT) { + /* + * Corresponds to ... + * followed by: + * + * Model groups , and . + */ + if (IS_SCHEMA(child, "all")) { + type->subtypes = (xmlSchemaTypePtr) + xmlSchemaParseModelGroup(ctxt, schema, child, + XML_SCHEMA_TYPE_ALL, 1); + child = child->next; + } else if (IS_SCHEMA(child, "choice")) { + type->subtypes = (xmlSchemaTypePtr) + xmlSchemaParseModelGroup(ctxt, + schema, child, XML_SCHEMA_TYPE_CHOICE, 1); + child = child->next; + } else if (IS_SCHEMA(child, "sequence")) { + type->subtypes = (xmlSchemaTypePtr) + xmlSchemaParseModelGroup(ctxt, schema, child, + XML_SCHEMA_TYPE_SEQUENCE, 1); + child = child->next; + /* + * Model group reference . + */ + } else if (IS_SCHEMA(child, "group")) { + type->subtypes = (xmlSchemaTypePtr) + xmlSchemaParseModelGroupDefRef(ctxt, schema, child); + /* + * Note that the reference will be resolved in + * xmlSchemaResolveTypeReferences(); + */ + child = child->next; + } + } else if (parentType == XML_SCHEMA_TYPE_SIMPLE_CONTENT) { + /* + * Corresponds to ... + * + * "1.1 the simple type definition corresponding to the + * among the [children] of if there is one;" + */ + if (IS_SCHEMA(child, "simpleType")) { + /* + * We will store the to-be-restricted simple type in + * type->contentTypeDef *temporarily*. + */ + type->contentTypeDef = (xmlSchemaTypePtr) + xmlSchemaParseSimpleType(ctxt, schema, child, 0); + if ( type->contentTypeDef == NULL) + return (NULL); + child = child->next; + } + } + + if ((parentType == XML_SCHEMA_TYPE_SIMPLE) || + (parentType == XML_SCHEMA_TYPE_SIMPLE_CONTENT)) { + xmlSchemaFacetPtr facet, lastfacet = NULL; + /* + * Corresponds to ... + * ... + */ + + /* + * Add the facets to the simple type ancestor. + */ + /* + * TODO: Datatypes: 4.1.3 Constraints on XML Representation of + * Simple Type Definition Schema Representation Constraint: + * *Single Facet Value* + */ + while ((IS_SCHEMA(child, "minInclusive")) || + (IS_SCHEMA(child, "minExclusive")) || + (IS_SCHEMA(child, "maxInclusive")) || + (IS_SCHEMA(child, "maxExclusive")) || + (IS_SCHEMA(child, "totalDigits")) || + (IS_SCHEMA(child, "fractionDigits")) || + (IS_SCHEMA(child, "pattern")) || + (IS_SCHEMA(child, "enumeration")) || + (IS_SCHEMA(child, "whiteSpace")) || + (IS_SCHEMA(child, "length")) || + (IS_SCHEMA(child, "maxLength")) || + (IS_SCHEMA(child, "minLength"))) { + facet = xmlSchemaParseFacet(ctxt, schema, child); + if (facet != NULL) { + if (lastfacet == NULL) + type->facets = facet; + else + lastfacet->next = facet; + lastfacet = facet; + lastfacet->next = NULL; + } + child = child->next; + } + /* + * Create links for derivation and validation. + */ + if (type->facets != NULL) { + xmlSchemaFacetLinkPtr facetLink, lastFacetLink = NULL; + + facet = type->facets; + do { + facetLink = (xmlSchemaFacetLinkPtr) + xmlMalloc(sizeof(xmlSchemaFacetLink)); + if (facetLink == NULL) { + xmlSchemaPErrMemory(ctxt, "allocating a facet link", NULL); + xmlFree(facetLink); + return (NULL); + } + facetLink->facet = facet; + facetLink->next = NULL; + if (lastFacetLink == NULL) + type->facetSet = facetLink; + else + lastFacetLink->next = facetLink; + lastFacetLink = facetLink; + facet = facet->next; + } while (facet != NULL); + } + } + if (type->type == XML_SCHEMA_TYPE_COMPLEX) { + /* + * Attribute uses/declarations. + */ + if (xmlSchemaParseLocalAttributes(ctxt, schema, &child, + (xmlSchemaItemListPtr *) &(type->attrUses), + XML_SCHEMA_TYPE_RESTRICTION, NULL) == -1) + return(NULL); + /* + * Attribute wildcard. + */ + if (IS_SCHEMA(child, "anyAttribute")) { + type->attributeWildcard = + xmlSchemaParseAnyAttribute(ctxt, schema, child); + child = child->next; + } + } + if (child != NULL) { + if (parentType == XML_SCHEMA_TYPE_COMPLEX_CONTENT) { + xmlSchemaPContentErr(ctxt, + XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED, + NULL, node, child, NULL, + "annotation?, (group | all | choice | sequence)?, " + "((attribute | attributeGroup)*, anyAttribute?))"); + } else if (parentType == XML_SCHEMA_TYPE_SIMPLE_CONTENT) { + xmlSchemaPContentErr(ctxt, + XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED, + NULL, node, child, NULL, + "(annotation?, (simpleType?, (minExclusive | minInclusive | " + "maxExclusive | maxInclusive | totalDigits | fractionDigits | " + "length | minLength | maxLength | enumeration | whiteSpace | " + "pattern)*)?, ((attribute | attributeGroup)*, anyAttribute?))"); + } else { + /* Simple type */ + xmlSchemaPContentErr(ctxt, + XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED, + NULL, node, child, NULL, + "(annotation?, (simpleType?, (minExclusive | minInclusive | " + "maxExclusive | maxInclusive | totalDigits | fractionDigits | " + "length | minLength | maxLength | enumeration | whiteSpace | " + "pattern)*))"); + } + } + return (NULL); +} + +/** + * xmlSchemaParseExtension: + * @ctxt: a schema validation context + * @schema: the schema being built + * @node: a subtree containing XML Schema informations + * + * Parses an , which is found inside a + * or . + * *WARNING* this interface is highly subject to change. + * + * TODO: Returns the type definition or NULL in case of error + */ +static xmlSchemaTypePtr +xmlSchemaParseExtension(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, + xmlNodePtr node, xmlSchemaTypeType parentType) +{ + xmlSchemaTypePtr type; + xmlNodePtr child = NULL; + xmlAttrPtr attr; + + if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) + return (NULL); + /* Not a component, don't create it. */ + type = ctxt->ctxtType; + type->flags |= XML_SCHEMAS_TYPE_DERIVATION_METHOD_EXTENSION; + + /* + * Check for illegal attributes. + */ + attr = node->properties; + while (attr != NULL) { + if (attr->ns == NULL) { + if ((!xmlStrEqual(attr->name, BAD_CAST "id")) && + (!xmlStrEqual(attr->name, BAD_CAST "base"))) { + xmlSchemaPIllegalAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + } else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) { + xmlSchemaPIllegalAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + attr = attr->next; + } + + xmlSchemaPValAttrID(ctxt, node, BAD_CAST "id"); + + /* + * Attribute "base" - mandatory. + */ + if ((xmlSchemaPValAttrQName(ctxt, schema, NULL, node, + "base", &(type->baseNs), &(type->base)) == 0) && + (type->base == NULL)) { + xmlSchemaPMissingAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_MISSING, + NULL, node, "base", NULL); + } + /* + * And now for the children... + */ + child = node->children; + if (IS_SCHEMA(child, "annotation")) { + /* + * Add the annotation to the type ancestor. + */ + xmlSchemaAddAnnotation((xmlSchemaAnnotItemPtr) type, + xmlSchemaParseAnnotation(ctxt, child, 1)); + child = child->next; + } + if (parentType == XML_SCHEMA_TYPE_COMPLEX_CONTENT) { + /* + * Corresponds to ... and: + * + * Model groups , , and . + */ + if (IS_SCHEMA(child, "all")) { + type->subtypes = (xmlSchemaTypePtr) + xmlSchemaParseModelGroup(ctxt, schema, + child, XML_SCHEMA_TYPE_ALL, 1); + child = child->next; + } else if (IS_SCHEMA(child, "choice")) { + type->subtypes = (xmlSchemaTypePtr) + xmlSchemaParseModelGroup(ctxt, schema, + child, XML_SCHEMA_TYPE_CHOICE, 1); + child = child->next; + } else if (IS_SCHEMA(child, "sequence")) { + type->subtypes = (xmlSchemaTypePtr) + xmlSchemaParseModelGroup(ctxt, schema, + child, XML_SCHEMA_TYPE_SEQUENCE, 1); + child = child->next; + } else if (IS_SCHEMA(child, "group")) { + type->subtypes = (xmlSchemaTypePtr) + xmlSchemaParseModelGroupDefRef(ctxt, schema, child); + /* + * Note that the reference will be resolved in + * xmlSchemaResolveTypeReferences(); + */ + child = child->next; + } + } + if (child != NULL) { + /* + * Attribute uses/declarations. + */ + if (xmlSchemaParseLocalAttributes(ctxt, schema, &child, + (xmlSchemaItemListPtr *) &(type->attrUses), + XML_SCHEMA_TYPE_EXTENSION, NULL) == -1) + return(NULL); + /* + * Attribute wildcard. + */ + if (IS_SCHEMA(child, "anyAttribute")) { + ctxt->ctxtType->attributeWildcard = + xmlSchemaParseAnyAttribute(ctxt, schema, child); + child = child->next; + } + } + if (child != NULL) { + if (parentType == XML_SCHEMA_TYPE_COMPLEX_CONTENT) { + /* Complex content extension. */ + xmlSchemaPContentErr(ctxt, + XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED, + NULL, node, child, NULL, + "(annotation?, ((group | all | choice | sequence)?, " + "((attribute | attributeGroup)*, anyAttribute?)))"); + } else { + /* Simple content extension. */ + xmlSchemaPContentErr(ctxt, + XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED, + NULL, node, child, NULL, + "(annotation?, ((attribute | attributeGroup)*, " + "anyAttribute?))"); + } + } + return (NULL); +} + +/** + * xmlSchemaParseSimpleContent: + * @ctxt: a schema validation context + * @schema: the schema being built + * @node: a subtree containing XML Schema informations + * + * parse a XML schema SimpleContent definition + * *WARNING* this interface is highly subject to change + * + * Returns the type definition or NULL in case of error + */ +static int +xmlSchemaParseSimpleContent(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaPtr schema, xmlNodePtr node, + int *hasRestrictionOrExtension) +{ + xmlSchemaTypePtr type; + xmlNodePtr child = NULL; + xmlAttrPtr attr; + + if ((ctxt == NULL) || (schema == NULL) || (node == NULL) || + (hasRestrictionOrExtension == NULL)) + return (-1); + *hasRestrictionOrExtension = 0; + /* Not a component, don't create it. */ + type = ctxt->ctxtType; + type->contentType = XML_SCHEMA_CONTENT_SIMPLE; + /* + * Check for illegal attributes. + */ + attr = node->properties; + while (attr != NULL) { + if (attr->ns == NULL) { + if ((!xmlStrEqual(attr->name, BAD_CAST "id"))) { + xmlSchemaPIllegalAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + } else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) { + xmlSchemaPIllegalAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + attr = attr->next; + } + + xmlSchemaPValAttrID(ctxt, node, BAD_CAST "id"); + + /* + * And now for the children... + */ + child = node->children; + if (IS_SCHEMA(child, "annotation")) { + /* + * Add the annotation to the complex type ancestor. + */ + xmlSchemaAddAnnotation((xmlSchemaAnnotItemPtr) type, + xmlSchemaParseAnnotation(ctxt, child, 1)); + child = child->next; + } + if (child == NULL) { + xmlSchemaPContentErr(ctxt, + XML_SCHEMAP_S4S_ELEM_MISSING, + NULL, node, NULL, NULL, + "(annotation?, (restriction | extension))"); + } + if (child == NULL) { + xmlSchemaPContentErr(ctxt, + XML_SCHEMAP_S4S_ELEM_MISSING, + NULL, node, NULL, NULL, + "(annotation?, (restriction | extension))"); + } + if (IS_SCHEMA(child, "restriction")) { + xmlSchemaParseRestriction(ctxt, schema, child, + XML_SCHEMA_TYPE_SIMPLE_CONTENT); + (*hasRestrictionOrExtension) = 1; + child = child->next; + } else if (IS_SCHEMA(child, "extension")) { + xmlSchemaParseExtension(ctxt, schema, child, + XML_SCHEMA_TYPE_SIMPLE_CONTENT); + (*hasRestrictionOrExtension) = 1; + child = child->next; + } + if (child != NULL) { + xmlSchemaPContentErr(ctxt, + XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED, + NULL, node, child, NULL, + "(annotation?, (restriction | extension))"); + } + return (0); +} + +/** + * xmlSchemaParseComplexContent: + * @ctxt: a schema validation context + * @schema: the schema being built + * @node: a subtree containing XML Schema informations + * + * parse a XML schema ComplexContent definition + * *WARNING* this interface is highly subject to change + * + * Returns the type definition or NULL in case of error + */ +static int +xmlSchemaParseComplexContent(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaPtr schema, xmlNodePtr node, + int *hasRestrictionOrExtension) +{ + xmlSchemaTypePtr type; + xmlNodePtr child = NULL; + xmlAttrPtr attr; + + if ((ctxt == NULL) || (schema == NULL) || (node == NULL) || + (hasRestrictionOrExtension == NULL)) + return (-1); + *hasRestrictionOrExtension = 0; + /* Not a component, don't create it. */ + type = ctxt->ctxtType; + /* + * Check for illegal attributes. + */ + attr = node->properties; + while (attr != NULL) { + if (attr->ns == NULL) { + if ((!xmlStrEqual(attr->name, BAD_CAST "id")) && + (!xmlStrEqual(attr->name, BAD_CAST "mixed"))) + { + xmlSchemaPIllegalAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + } else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) { + xmlSchemaPIllegalAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + attr = attr->next; + } + + xmlSchemaPValAttrID(ctxt, node, BAD_CAST "id"); + + /* + * Set the 'mixed' on the complex type ancestor. + */ + if (xmlGetBooleanProp(ctxt, node, "mixed", 0)) { + if ((type->flags & XML_SCHEMAS_TYPE_MIXED) == 0) + type->flags |= XML_SCHEMAS_TYPE_MIXED; + } + child = node->children; + if (IS_SCHEMA(child, "annotation")) { + /* + * Add the annotation to the complex type ancestor. + */ + xmlSchemaAddAnnotation((xmlSchemaAnnotItemPtr) type, + xmlSchemaParseAnnotation(ctxt, child, 1)); + child = child->next; + } + if (child == NULL) { + xmlSchemaPContentErr(ctxt, + XML_SCHEMAP_S4S_ELEM_MISSING, + NULL, node, NULL, + NULL, "(annotation?, (restriction | extension))"); + } + if (child == NULL) { + xmlSchemaPContentErr(ctxt, + XML_SCHEMAP_S4S_ELEM_MISSING, + NULL, node, NULL, + NULL, "(annotation?, (restriction | extension))"); + } + if (IS_SCHEMA(child, "restriction")) { + xmlSchemaParseRestriction(ctxt, schema, child, + XML_SCHEMA_TYPE_COMPLEX_CONTENT); + (*hasRestrictionOrExtension) = 1; + child = child->next; + } else if (IS_SCHEMA(child, "extension")) { + xmlSchemaParseExtension(ctxt, schema, child, + XML_SCHEMA_TYPE_COMPLEX_CONTENT); + (*hasRestrictionOrExtension) = 1; + child = child->next; + } + if (child != NULL) { + xmlSchemaPContentErr(ctxt, + XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED, + NULL, node, child, + NULL, "(annotation?, (restriction | extension))"); + } + return (0); +} + +/** + * xmlSchemaParseComplexType: + * @ctxt: a schema validation context + * @schema: the schema being built + * @node: a subtree containing XML Schema informations + * + * parse a XML schema Complex Type definition + * *WARNING* this interface is highly subject to change + * + * Returns the type definition or NULL in case of error + */ +static xmlSchemaTypePtr +xmlSchemaParseComplexType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, + xmlNodePtr node, int topLevel) +{ + xmlSchemaTypePtr type, ctxtType; + xmlNodePtr child = NULL; + const xmlChar *name = NULL; + xmlAttrPtr attr; + const xmlChar *attrValue; +#ifdef ENABLE_NAMED_LOCALS + char buf[40]; +#endif + int final = 0, block = 0, hasRestrictionOrExtension = 0; + + + if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) + return (NULL); + + ctxtType = ctxt->ctxtType; + + if (topLevel) { + attr = xmlSchemaGetPropNode(node, "name"); + if (attr == NULL) { + xmlSchemaPMissingAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_MISSING, NULL, node, "name", NULL); + return (NULL); + } else if (xmlSchemaPValAttrNode(ctxt, NULL, attr, + xmlSchemaGetBuiltInType(XML_SCHEMAS_NCNAME), &name) != 0) { + return (NULL); + } + } + + if (topLevel == 0) { + /* + * Parse as local complex type definition. + */ +#ifdef ENABLE_NAMED_LOCALS + snprintf(buf, 39, "#CT%d", ctxt->counter++ + 1); + type = xmlSchemaAddType(ctxt, schema, + XML_SCHEMA_TYPE_COMPLEX, + xmlDictLookup(ctxt->dict, (const xmlChar *)buf, -1), + ctxt->targetNamespace, node, 0); +#else + type = xmlSchemaAddType(ctxt, schema, + XML_SCHEMA_TYPE_COMPLEX, + NULL, ctxt->targetNamespace, node, 0); +#endif + if (type == NULL) + return (NULL); + name = type->name; + type->node = node; + type->type = XML_SCHEMA_TYPE_COMPLEX; + /* + * TODO: We need the target namespace. + */ + } else { + /* + * Parse as global complex type definition. + */ + type = xmlSchemaAddType(ctxt, schema, + XML_SCHEMA_TYPE_COMPLEX, + name, ctxt->targetNamespace, node, 1); + if (type == NULL) + return (NULL); + type->node = node; + type->type = XML_SCHEMA_TYPE_COMPLEX; + type->flags |= XML_SCHEMAS_TYPE_GLOBAL; + } + type->targetNamespace = ctxt->targetNamespace; + /* + * Handle attributes. + */ + attr = node->properties; + while (attr != NULL) { + if (attr->ns == NULL) { + if (xmlStrEqual(attr->name, BAD_CAST "id")) { + /* + * Attribute "id". + */ + xmlSchemaPValAttrID(ctxt, node, BAD_CAST "id"); + } else if (xmlStrEqual(attr->name, BAD_CAST "mixed")) { + /* + * Attribute "mixed". + */ + if (xmlSchemaPGetBoolNodeValue(ctxt, + NULL, (xmlNodePtr) attr)) + type->flags |= XML_SCHEMAS_TYPE_MIXED; + } else if (topLevel) { + /* + * Attributes of global complex type definitions. + */ + if (xmlStrEqual(attr->name, BAD_CAST "name")) { + /* Pass. */ + } else if (xmlStrEqual(attr->name, BAD_CAST "abstract")) { + /* + * Attribute "abstract". + */ + if (xmlSchemaPGetBoolNodeValue(ctxt, + NULL, (xmlNodePtr) attr)) + type->flags |= XML_SCHEMAS_TYPE_ABSTRACT; + } else if (xmlStrEqual(attr->name, BAD_CAST "final")) { + /* + * Attribute "final". + */ + attrValue = xmlSchemaGetNodeContent(ctxt, + (xmlNodePtr) attr); + if (xmlSchemaPValAttrBlockFinal(attrValue, + &(type->flags), + -1, + XML_SCHEMAS_TYPE_FINAL_EXTENSION, + XML_SCHEMAS_TYPE_FINAL_RESTRICTION, + -1, -1, -1) != 0) + { + xmlSchemaPSimpleTypeErr(ctxt, + XML_SCHEMAP_S4S_ATTR_INVALID_VALUE, + NULL, (xmlNodePtr) attr, NULL, + "(#all | List of (extension | restriction))", + attrValue, NULL, NULL, NULL); + } else + final = 1; + } else if (xmlStrEqual(attr->name, BAD_CAST "block")) { + /* + * Attribute "block". + */ + attrValue = xmlSchemaGetNodeContent(ctxt, + (xmlNodePtr) attr); + if (xmlSchemaPValAttrBlockFinal(attrValue, &(type->flags), + -1, + XML_SCHEMAS_TYPE_BLOCK_EXTENSION, + XML_SCHEMAS_TYPE_BLOCK_RESTRICTION, + -1, -1, -1) != 0) { + xmlSchemaPSimpleTypeErr(ctxt, + XML_SCHEMAP_S4S_ATTR_INVALID_VALUE, + NULL, (xmlNodePtr) attr, NULL, + "(#all | List of (extension | restriction)) ", + attrValue, NULL, NULL, NULL); + } else + block = 1; + } else { + xmlSchemaPIllegalAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + } else { + xmlSchemaPIllegalAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + } else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) { + xmlSchemaPIllegalAttrErr(ctxt, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr); + } + attr = attr->next; + } + if (! block) { + /* + * Apply default "block" values. + */ + if (schema->flags & XML_SCHEMAS_BLOCK_DEFAULT_RESTRICTION) + type->flags |= XML_SCHEMAS_TYPE_BLOCK_RESTRICTION; + if (schema->flags & XML_SCHEMAS_BLOCK_DEFAULT_EXTENSION) + type->flags |= XML_SCHEMAS_TYPE_BLOCK_EXTENSION; + } + if (! final) { + /* + * Apply default "block" values. + */ + if (schema->flags & XML_SCHEMAS_FINAL_DEFAULT_RESTRICTION) + type->flags |= XML_SCHEMAS_TYPE_FINAL_RESTRICTION; + if (schema->flags & XML_SCHEMAS_FINAL_DEFAULT_EXTENSION) + type->flags |= XML_SCHEMAS_TYPE_FINAL_EXTENSION; + } + /* + * And now for the children... + */ + child = node->children; + if (IS_SCHEMA(child, "annotation")) { + type->annot = xmlSchemaParseAnnotation(ctxt, child, 1); + child = child->next; + } + ctxt->ctxtType = type; + if (IS_SCHEMA(child, "simpleContent")) { + /* + * ... + * 3.4.3 : 2.2 + * Specifying mixed='true' when the + * alternative is chosen has no effect + */ + if (type->flags & XML_SCHEMAS_TYPE_MIXED) + type->flags ^= XML_SCHEMAS_TYPE_MIXED; + xmlSchemaParseSimpleContent(ctxt, schema, child, + &hasRestrictionOrExtension); + child = child->next; + } else if (IS_SCHEMA(child, "complexContent")) { + /* + * ... + */ + type->contentType = XML_SCHEMA_CONTENT_EMPTY; + xmlSchemaParseComplexContent(ctxt, schema, child, + &hasRestrictionOrExtension); + child = child->next; + } else { + /* + * E.g ... or ... etc. + * + * SPEC + * "...the third alternative (neither nor + * ) is chosen. This case is understood as shorthand + * for complex content restricting the �ur-type definition�, and the + * details of the mappings should be modified as necessary. + */ + type->baseType = xmlSchemaGetBuiltInType(XML_SCHEMAS_ANYTYPE); + type->flags |= XML_SCHEMAS_TYPE_DERIVATION_METHOD_RESTRICTION; + /* + * Parse model groups. + */ + if (IS_SCHEMA(child, "all")) { + type->subtypes = (xmlSchemaTypePtr) + xmlSchemaParseModelGroup(ctxt, schema, child, + XML_SCHEMA_TYPE_ALL, 1); + child = child->next; + } else if (IS_SCHEMA(child, "choice")) { + type->subtypes = (xmlSchemaTypePtr) + xmlSchemaParseModelGroup(ctxt, schema, child, + XML_SCHEMA_TYPE_CHOICE, 1); + child = child->next; + } else if (IS_SCHEMA(child, "sequence")) { + type->subtypes = (xmlSchemaTypePtr) + xmlSchemaParseModelGroup(ctxt, schema, child, + XML_SCHEMA_TYPE_SEQUENCE, 1); + child = child->next; + } else if (IS_SCHEMA(child, "group")) { + type->subtypes = (xmlSchemaTypePtr) + xmlSchemaParseModelGroupDefRef(ctxt, schema, child); + /* + * Note that the reference will be resolved in + * xmlSchemaResolveTypeReferences(); + */ + child = child->next; + } + /* + * Parse attribute decls/refs. + */ + if (xmlSchemaParseLocalAttributes(ctxt, schema, &child, + (xmlSchemaItemListPtr *) &(type->attrUses), + XML_SCHEMA_TYPE_RESTRICTION, NULL) == -1) + return(NULL); + /* + * Parse attribute wildcard. + */ + if (IS_SCHEMA(child, "anyAttribute")) { + type->attributeWildcard = xmlSchemaParseAnyAttribute(ctxt, schema, child); + child = child->next; + } + } + if (child != NULL) { + xmlSchemaPContentErr(ctxt, + XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED, + NULL, node, child, + NULL, "(annotation?, (simpleContent | complexContent | " + "((group | all | choice | sequence)?, ((attribute | " + "attributeGroup)*, anyAttribute?))))"); + } + /* + * REDEFINE: SPEC src-redefine (5) + */ + if (topLevel && ctxt->isRedefine && (! hasRestrictionOrExtension)) { + xmlSchemaPCustomErr(ctxt, XML_SCHEMAP_SRC_REDEFINE, + NULL, node, "This is a redefinition, thus the " + " must have a or " + "grand-child", NULL); + } + ctxt->ctxtType = ctxtType; + return (type); +} + +/************************************************************************ + * * + * Validating using Schemas * + * * + ************************************************************************/ + +/************************************************************************ + * * + * Reading/Writing Schemas * + * * + ************************************************************************/ + +#if 0 /* Will be enabled if it is clear what options are needed. */ +/** + * xmlSchemaParserCtxtSetOptions: + * @ctxt: a schema parser context + * @options: a combination of xmlSchemaParserOption + * + * Sets the options to be used during the parse. + * + * Returns 0 in case of success, -1 in case of an + * API error. + */ +static int +xmlSchemaParserCtxtSetOptions(xmlSchemaParserCtxtPtr ctxt, + int options) + +{ + int i; + + if (ctxt == NULL) + return (-1); + /* + * WARNING: Change the start value if adding to the + * xmlSchemaParseOption. + */ + for (i = 1; i < (int) sizeof(int) * 8; i++) { + if (options & 1<options = options; + return (0); +} + +/** + * xmlSchemaValidCtxtGetOptions: + * @ctxt: a schema parser context + * + * Returns the option combination of the parser context. + */ +static int +xmlSchemaParserCtxtGetOptions(xmlSchemaParserCtxtPtr ctxt) + +{ + if (ctxt == NULL) + return (-1); + else + return (ctxt->options); +} +#endif + +/** + * xmlSchemaNewParserCtxt: + * @URL: the location of the schema + * + * Create an XML Schemas parse context for that file/resource expected + * to contain an XML Schemas file. + * + * Returns the parser context or NULL in case of error + */ +xmlSchemaParserCtxtPtr +xmlSchemaNewParserCtxt(const char *URL) +{ + xmlSchemaParserCtxtPtr ret; + + if (URL == NULL) + return (NULL); + + ret = xmlSchemaParserCtxtCreate(); + if (ret == NULL) + return(NULL); + ret->dict = xmlDictCreate(); + ret->URL = xmlDictLookup(ret->dict, (const xmlChar *) URL, -1); + return (ret); +} + +/** + * xmlSchemaNewMemParserCtxt: + * @buffer: a pointer to a char array containing the schemas + * @size: the size of the array + * + * Create an XML Schemas parse context for that memory buffer expected + * to contain an XML Schemas file. + * + * Returns the parser context or NULL in case of error + */ +xmlSchemaParserCtxtPtr +xmlSchemaNewMemParserCtxt(const char *buffer, int size) +{ + xmlSchemaParserCtxtPtr ret; + + if ((buffer == NULL) || (size <= 0)) + return (NULL); + ret = xmlSchemaParserCtxtCreate(); + if (ret == NULL) + return(NULL); + ret->buffer = buffer; + ret->size = size; + ret->dict = xmlDictCreate(); + return (ret); +} + +/** + * xmlSchemaNewDocParserCtxt: + * @doc: a preparsed document tree + * + * Create an XML Schemas parse context for that document. + * NB. The document may be modified during the parsing process. + * + * Returns the parser context or NULL in case of error + */ +xmlSchemaParserCtxtPtr +xmlSchemaNewDocParserCtxt(xmlDocPtr doc) +{ + xmlSchemaParserCtxtPtr ret; + + if (doc == NULL) + return (NULL); + ret = xmlSchemaParserCtxtCreate(); + if (ret == NULL) + return(NULL); + ret->doc = doc; + ret->dict = xmlDictCreate(); + /* The application has responsibility for the document */ + ret->preserve = 1; + + return (ret); +} + +/** + * xmlSchemaFreeParserCtxt: + * @ctxt: the schema parser context + * + * Free the resources associated to the schema parser context + */ +void +xmlSchemaFreeParserCtxt(xmlSchemaParserCtxtPtr ctxt) +{ + if (ctxt == NULL) + return; + if (ctxt->doc != NULL && !ctxt->preserve) + xmlFreeDoc(ctxt->doc); + if (ctxt->vctxt != NULL) { + xmlSchemaFreeValidCtxt(ctxt->vctxt); + } + if (ctxt->ownsConstructor && (ctxt->constructor != NULL)) { + xmlSchemaConstructionCtxtFree(ctxt->constructor); + ctxt->constructor = NULL; + ctxt->ownsConstructor = 0; + } + if (ctxt->attrProhibs != NULL) + xmlSchemaItemListFree(ctxt->attrProhibs); + xmlDictFree(ctxt->dict); + xmlFree(ctxt); +} + +/************************************************************************ + * * + * Building the content models * + * * + ************************************************************************/ + +/** + * xmlSchemaBuildContentModelForSubstGroup: + * + * Returns 1 if nillable, 0 otherwise + */ +static int +xmlSchemaBuildContentModelForSubstGroup(xmlSchemaParserCtxtPtr pctxt, + xmlSchemaParticlePtr particle, int counter, xmlAutomataStatePtr end) +{ + xmlAutomataStatePtr start, tmp; + xmlSchemaElementPtr elemDecl, member; + xmlSchemaSubstGroupPtr substGroup; + int i; + int ret = 0; + + elemDecl = (xmlSchemaElementPtr) particle->children; + /* + * Wrap the substitution group with a CHOICE. + */ + start = pctxt->state; + if (end == NULL) + end = xmlAutomataNewState(pctxt->am); + substGroup = xmlSchemaSubstGroupGet(pctxt, elemDecl); + if (substGroup == NULL) { + xmlSchemaPErr(pctxt, WXS_ITEM_NODE(particle), + XML_SCHEMAP_INTERNAL, + "Internal error: xmlSchemaBuildContentModelForSubstGroup, " + "declaration is marked having a subst. group but none " + "available.\n", elemDecl->name, NULL); + return(0); + } + if (counter >= 0) { + /* + * NOTE that we put the declaration in, even if it's abstract. + * However, an error will be raised during *validation* if an element + * information item shall be validated against an abstract element + * declaration. + */ + tmp = xmlAutomataNewCountedTrans(pctxt->am, start, NULL, counter); + xmlAutomataNewTransition2(pctxt->am, tmp, end, + elemDecl->name, elemDecl->targetNamespace, elemDecl); + /* + * Add subst. group members. + */ + for (i = 0; i < substGroup->members->nbItems; i++) { + member = (xmlSchemaElementPtr) substGroup->members->items[i]; + xmlAutomataNewTransition2(pctxt->am, tmp, end, + member->name, member->targetNamespace, member); + } + } else if (particle->maxOccurs == 1) { + /* + * NOTE that we put the declaration in, even if it's abstract, + */ + xmlAutomataNewEpsilon(pctxt->am, + xmlAutomataNewTransition2(pctxt->am, + start, NULL, + elemDecl->name, elemDecl->targetNamespace, elemDecl), end); + /* + * Add subst. group members. + */ + for (i = 0; i < substGroup->members->nbItems; i++) { + member = (xmlSchemaElementPtr) substGroup->members->items[i]; + /* + * NOTE: This fixes bug #341150. xmlAutomataNewOnceTrans2() + * was incorrectly used instead of xmlAutomataNewTransition2() + * (seems like a copy&paste bug from the XML_SCHEMA_TYPE_ALL + * section in xmlSchemaBuildAContentModel() ). + * TODO: Check if xmlAutomataNewOnceTrans2() was instead + * intended for the above "counter" section originally. I.e., + * check xs:all with subst-groups. + * + * tmp = xmlAutomataNewOnceTrans2(pctxt->am, start, NULL, + * member->name, member->targetNamespace, + * 1, 1, member); + */ + tmp = xmlAutomataNewTransition2(pctxt->am, start, NULL, + member->name, member->targetNamespace, member); + xmlAutomataNewEpsilon(pctxt->am, tmp, end); + } + } else { + xmlAutomataStatePtr hop; + int maxOccurs = particle->maxOccurs == UNBOUNDED ? + UNBOUNDED : particle->maxOccurs - 1; + int minOccurs = particle->minOccurs < 1 ? 0 : particle->minOccurs - 1; + + counter = + xmlAutomataNewCounter(pctxt->am, minOccurs, + maxOccurs); + hop = xmlAutomataNewState(pctxt->am); + + xmlAutomataNewEpsilon(pctxt->am, + xmlAutomataNewTransition2(pctxt->am, + start, NULL, + elemDecl->name, elemDecl->targetNamespace, elemDecl), + hop); + /* + * Add subst. group members. + */ + for (i = 0; i < substGroup->members->nbItems; i++) { + member = (xmlSchemaElementPtr) substGroup->members->items[i]; + xmlAutomataNewEpsilon(pctxt->am, + xmlAutomataNewTransition2(pctxt->am, + start, NULL, + member->name, member->targetNamespace, member), + hop); + } + xmlAutomataNewCountedTrans(pctxt->am, hop, start, counter); + xmlAutomataNewCounterTrans(pctxt->am, hop, end, counter); + } + if (particle->minOccurs == 0) { + xmlAutomataNewEpsilon(pctxt->am, start, end); + ret = 1; + } + pctxt->state = end; + return(ret); +} + +/** + * xmlSchemaBuildContentModelForElement: + * + * Returns 1 if nillable, 0 otherwise + */ +static int +xmlSchemaBuildContentModelForElement(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaParticlePtr particle) +{ + int ret = 0; + + if (((xmlSchemaElementPtr) particle->children)->flags & + XML_SCHEMAS_ELEM_SUBST_GROUP_HEAD) { + /* + * Substitution groups. + */ + ret = xmlSchemaBuildContentModelForSubstGroup(ctxt, particle, -1, NULL); + } else { + xmlSchemaElementPtr elemDecl; + xmlAutomataStatePtr start; + + elemDecl = (xmlSchemaElementPtr) particle->children; + + if (elemDecl->flags & XML_SCHEMAS_ELEM_ABSTRACT) + return(0); + if (particle->maxOccurs == 1) { + start = ctxt->state; + ctxt->state = xmlAutomataNewTransition2(ctxt->am, start, NULL, + elemDecl->name, elemDecl->targetNamespace, elemDecl); + } else if ((particle->maxOccurs >= UNBOUNDED) && + (particle->minOccurs < 2)) { + /* Special case. */ + start = ctxt->state; + ctxt->state = xmlAutomataNewTransition2(ctxt->am, start, NULL, + elemDecl->name, elemDecl->targetNamespace, elemDecl); + ctxt->state = xmlAutomataNewTransition2(ctxt->am, ctxt->state, ctxt->state, + elemDecl->name, elemDecl->targetNamespace, elemDecl); + } else { + int counter; + int maxOccurs = particle->maxOccurs == UNBOUNDED ? + UNBOUNDED : particle->maxOccurs - 1; + int minOccurs = particle->minOccurs < 1 ? + 0 : particle->minOccurs - 1; + + start = xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL); + counter = xmlAutomataNewCounter(ctxt->am, minOccurs, maxOccurs); + ctxt->state = xmlAutomataNewTransition2(ctxt->am, start, NULL, + elemDecl->name, elemDecl->targetNamespace, elemDecl); + xmlAutomataNewCountedTrans(ctxt->am, ctxt->state, start, counter); + ctxt->state = xmlAutomataNewCounterTrans(ctxt->am, ctxt->state, + NULL, counter); + } + if (particle->minOccurs == 0) { + xmlAutomataNewEpsilon(ctxt->am, start, ctxt->state); + ret = 1; + } + } + return(ret); +} + +/** + * xmlSchemaBuildAContentModel: + * @ctxt: the schema parser context + * @particle: the particle component + * @name: the complex type's name whose content is being built + * + * Create the automaton for the {content type} of a complex type. + * + * Returns 1 if the content is nillable, 0 otherwise + */ +static int +xmlSchemaBuildAContentModel(xmlSchemaParserCtxtPtr pctxt, + xmlSchemaParticlePtr particle) +{ + int ret = 0, tmp2; + + if (particle == NULL) { + PERROR_INT("xmlSchemaBuildAContentModel", "particle is NULL"); + return(1); + } + if (particle->children == NULL) { + /* + * Just return in this case. A missing "term" of the particle + * might arise due to an invalid "term" component. + */ + return(1); + } + + switch (particle->children->type) { + case XML_SCHEMA_TYPE_ANY: { + xmlAutomataStatePtr start, end; + xmlSchemaWildcardPtr wild; + xmlSchemaWildcardNsPtr ns; + + wild = (xmlSchemaWildcardPtr) particle->children; + + start = pctxt->state; + end = xmlAutomataNewState(pctxt->am); + + if (particle->maxOccurs == 1) { + if (wild->any == 1) { + /* + * We need to add both transitions: + * + * 1. the {"*", "*"} for elements in a namespace. + */ + pctxt->state = + xmlAutomataNewTransition2(pctxt->am, + start, NULL, BAD_CAST "*", BAD_CAST "*", wild); + xmlAutomataNewEpsilon(pctxt->am, pctxt->state, end); + /* + * 2. the {"*"} for elements in no namespace. + */ + pctxt->state = + xmlAutomataNewTransition2(pctxt->am, + start, NULL, BAD_CAST "*", NULL, wild); + xmlAutomataNewEpsilon(pctxt->am, pctxt->state, end); + + } else if (wild->nsSet != NULL) { + ns = wild->nsSet; + do { + pctxt->state = start; + pctxt->state = xmlAutomataNewTransition2(pctxt->am, + pctxt->state, NULL, BAD_CAST "*", ns->value, wild); + xmlAutomataNewEpsilon(pctxt->am, pctxt->state, end); + ns = ns->next; + } while (ns != NULL); + + } else if (wild->negNsSet != NULL) { + pctxt->state = xmlAutomataNewNegTrans(pctxt->am, + start, end, BAD_CAST "*", wild->negNsSet->value, + wild); + } + } else { + int counter; + xmlAutomataStatePtr hop; + int maxOccurs = + particle->maxOccurs == UNBOUNDED ? UNBOUNDED : + particle->maxOccurs - 1; + int minOccurs = + particle->minOccurs < 1 ? 0 : particle->minOccurs - 1; + + counter = xmlAutomataNewCounter(pctxt->am, minOccurs, maxOccurs); + hop = xmlAutomataNewState(pctxt->am); + if (wild->any == 1) { + pctxt->state = + xmlAutomataNewTransition2(pctxt->am, + start, NULL, BAD_CAST "*", BAD_CAST "*", wild); + xmlAutomataNewEpsilon(pctxt->am, pctxt->state, hop); + pctxt->state = + xmlAutomataNewTransition2(pctxt->am, + start, NULL, BAD_CAST "*", NULL, wild); + xmlAutomataNewEpsilon(pctxt->am, pctxt->state, hop); + } else if (wild->nsSet != NULL) { + ns = wild->nsSet; + do { + pctxt->state = + xmlAutomataNewTransition2(pctxt->am, + start, NULL, BAD_CAST "*", ns->value, wild); + xmlAutomataNewEpsilon(pctxt->am, pctxt->state, hop); + ns = ns->next; + } while (ns != NULL); + + } else if (wild->negNsSet != NULL) { + pctxt->state = xmlAutomataNewNegTrans(pctxt->am, + start, hop, BAD_CAST "*", wild->negNsSet->value, + wild); + } + xmlAutomataNewCountedTrans(pctxt->am, hop, start, counter); + xmlAutomataNewCounterTrans(pctxt->am, hop, end, counter); + } + if (particle->minOccurs == 0) { + xmlAutomataNewEpsilon(pctxt->am, start, end); + ret = 1; + } + pctxt->state = end; + break; + } + case XML_SCHEMA_TYPE_ELEMENT: + ret = xmlSchemaBuildContentModelForElement(pctxt, particle); + break; + case XML_SCHEMA_TYPE_SEQUENCE:{ + xmlSchemaTreeItemPtr sub; + + ret = 1; + /* + * If max and min occurances are default (1) then + * simply iterate over the particles of the . + */ + if ((particle->minOccurs == 1) && (particle->maxOccurs == 1)) { + sub = particle->children->children; + + while (sub != NULL) { + tmp2 = xmlSchemaBuildAContentModel(pctxt, + (xmlSchemaParticlePtr) sub); + if (tmp2 != 1) ret = 0; + sub = sub->next; + } + } else { + xmlAutomataStatePtr oldstate = pctxt->state; + + if (particle->maxOccurs >= UNBOUNDED) { + if (particle->minOccurs > 1) { + xmlAutomataStatePtr tmp; + int counter; + + pctxt->state = xmlAutomataNewEpsilon(pctxt->am, + oldstate, NULL); + oldstate = pctxt->state; + + counter = xmlAutomataNewCounter(pctxt->am, + particle->minOccurs - 1, UNBOUNDED); + + sub = particle->children->children; + while (sub != NULL) { + tmp2 = xmlSchemaBuildAContentModel(pctxt, + (xmlSchemaParticlePtr) sub); + if (tmp2 != 1) ret = 0; + sub = sub->next; + } + tmp = pctxt->state; + xmlAutomataNewCountedTrans(pctxt->am, tmp, + oldstate, counter); + pctxt->state = + xmlAutomataNewCounterTrans(pctxt->am, tmp, + NULL, counter); + if (ret == 1) + xmlAutomataNewEpsilon(pctxt->am, + oldstate, pctxt->state); + + } else { + pctxt->state = xmlAutomataNewEpsilon(pctxt->am, + oldstate, NULL); + oldstate = pctxt->state; + + sub = particle->children->children; + while (sub != NULL) { + tmp2 = xmlSchemaBuildAContentModel(pctxt, + (xmlSchemaParticlePtr) sub); + if (tmp2 != 1) ret = 0; + sub = sub->next; + } + xmlAutomataNewEpsilon(pctxt->am, pctxt->state, + oldstate); + /* + * epsilon needed to block previous trans from + * being allowed to enter back from another + * construct + */ + pctxt->state = xmlAutomataNewEpsilon(pctxt->am, + pctxt->state, NULL); + if (particle->minOccurs == 0) { + xmlAutomataNewEpsilon(pctxt->am, + oldstate, pctxt->state); + ret = 1; + } + } + } else if ((particle->maxOccurs > 1) + || (particle->minOccurs > 1)) { + xmlAutomataStatePtr tmp; + int counter; + + pctxt->state = xmlAutomataNewEpsilon(pctxt->am, + oldstate, NULL); + oldstate = pctxt->state; + + counter = xmlAutomataNewCounter(pctxt->am, + particle->minOccurs - 1, + particle->maxOccurs - 1); + + sub = particle->children->children; + while (sub != NULL) { + tmp2 = xmlSchemaBuildAContentModel(pctxt, + (xmlSchemaParticlePtr) sub); + if (tmp2 != 1) ret = 0; + sub = sub->next; + } + tmp = pctxt->state; + xmlAutomataNewCountedTrans(pctxt->am, + tmp, oldstate, counter); + pctxt->state = + xmlAutomataNewCounterTrans(pctxt->am, tmp, NULL, + counter); + if ((particle->minOccurs == 0) || (ret == 1)) { + xmlAutomataNewEpsilon(pctxt->am, + oldstate, pctxt->state); + ret = 1; + } + } else { + sub = particle->children->children; + while (sub != NULL) { + tmp2 = xmlSchemaBuildAContentModel(pctxt, + (xmlSchemaParticlePtr) sub); + if (tmp2 != 1) ret = 0; + sub = sub->next; + } + if (particle->minOccurs == 0) { + xmlAutomataNewEpsilon(pctxt->am, oldstate, + pctxt->state); + ret = 1; + } + } + } + break; + } + case XML_SCHEMA_TYPE_CHOICE:{ + xmlSchemaTreeItemPtr sub; + xmlAutomataStatePtr start, end; + + ret = 0; + start = pctxt->state; + end = xmlAutomataNewState(pctxt->am); + + /* + * iterate over the subtypes and remerge the end with an + * epsilon transition + */ + if (particle->maxOccurs == 1) { + sub = particle->children->children; + while (sub != NULL) { + pctxt->state = start; + tmp2 = xmlSchemaBuildAContentModel(pctxt, + (xmlSchemaParticlePtr) sub); + if (tmp2 == 1) ret = 1; + xmlAutomataNewEpsilon(pctxt->am, pctxt->state, end); + sub = sub->next; + } + } else { + int counter; + xmlAutomataStatePtr hop, base; + int maxOccurs = particle->maxOccurs == UNBOUNDED ? + UNBOUNDED : particle->maxOccurs - 1; + int minOccurs = + particle->minOccurs < 1 ? 0 : particle->minOccurs - 1; + + /* + * use a counter to keep track of the number of transtions + * which went through the choice. + */ + counter = + xmlAutomataNewCounter(pctxt->am, minOccurs, maxOccurs); + hop = xmlAutomataNewState(pctxt->am); + base = xmlAutomataNewState(pctxt->am); + + sub = particle->children->children; + while (sub != NULL) { + pctxt->state = base; + tmp2 = xmlSchemaBuildAContentModel(pctxt, + (xmlSchemaParticlePtr) sub); + if (tmp2 == 1) ret = 1; + xmlAutomataNewEpsilon(pctxt->am, pctxt->state, hop); + sub = sub->next; + } + xmlAutomataNewEpsilon(pctxt->am, start, base); + xmlAutomataNewCountedTrans(pctxt->am, hop, base, counter); + xmlAutomataNewCounterTrans(pctxt->am, hop, end, counter); + if (ret == 1) + xmlAutomataNewEpsilon(pctxt->am, base, end); + } + if (particle->minOccurs == 0) { + xmlAutomataNewEpsilon(pctxt->am, start, end); + ret = 1; + } + pctxt->state = end; + break; + } + case XML_SCHEMA_TYPE_ALL:{ + xmlAutomataStatePtr start, tmp; + xmlSchemaParticlePtr sub; + xmlSchemaElementPtr elemDecl; + + ret = 1; + + sub = (xmlSchemaParticlePtr) particle->children->children; + if (sub == NULL) + break; + + ret = 0; + + start = pctxt->state; + tmp = xmlAutomataNewState(pctxt->am); + xmlAutomataNewEpsilon(pctxt->am, pctxt->state, tmp); + pctxt->state = tmp; + while (sub != NULL) { + pctxt->state = tmp; + + elemDecl = (xmlSchemaElementPtr) sub->children; + if (elemDecl == NULL) { + PERROR_INT("xmlSchemaBuildAContentModel", + " particle has no term"); + return(ret); + }; + /* + * NOTE: The {max occurs} of all the particles in the + * {particles} of the group must be 0 or 1; this is + * already ensured during the parse of the content of + * . + */ + if (elemDecl->flags & XML_SCHEMAS_ELEM_SUBST_GROUP_HEAD) { + int counter; + + /* + * This is an abstract group, we need to share + * the same counter for all the element transitions + * derived from the group + */ + counter = xmlAutomataNewCounter(pctxt->am, + sub->minOccurs, sub->maxOccurs); + xmlSchemaBuildContentModelForSubstGroup(pctxt, + sub, counter, pctxt->state); + } else { + if ((sub->minOccurs == 1) && + (sub->maxOccurs == 1)) { + xmlAutomataNewOnceTrans2(pctxt->am, pctxt->state, + pctxt->state, + elemDecl->name, + elemDecl->targetNamespace, + 1, 1, elemDecl); + } else if ((sub->minOccurs == 0) && + (sub->maxOccurs == 1)) { + + xmlAutomataNewCountTrans2(pctxt->am, pctxt->state, + pctxt->state, + elemDecl->name, + elemDecl->targetNamespace, + 0, + 1, + elemDecl); + } + } + sub = (xmlSchemaParticlePtr) sub->next; + } + pctxt->state = + xmlAutomataNewAllTrans(pctxt->am, pctxt->state, NULL, 0); + if (particle->minOccurs == 0) { + xmlAutomataNewEpsilon(pctxt->am, start, pctxt->state); + ret = 1; + } + break; + } + case XML_SCHEMA_TYPE_GROUP: + /* + * If we hit a model group definition, then this means that + * it was empty, thus was not substituted for the containing + * model group. Just do nothing in this case. + * TODO: But the group should be substituted and not occur at + * all in the content model at this point. Fix this. + */ + ret = 1; + break; + default: + xmlSchemaInternalErr2(ACTXT_CAST pctxt, + "xmlSchemaBuildAContentModel", + "found unexpected term of type '%s' in content model", + WXS_ITEM_TYPE_NAME(particle->children), NULL); + return(ret); + } + return(ret); +} + +/** + * xmlSchemaBuildContentModel: + * @ctxt: the schema parser context + * @type: the complex type definition + * @name: the element name + * + * Builds the content model of the complex type. + */ +static void +xmlSchemaBuildContentModel(xmlSchemaTypePtr type, + xmlSchemaParserCtxtPtr ctxt) +{ + if ((type->type != XML_SCHEMA_TYPE_COMPLEX) || + (type->contModel != NULL) || + ((type->contentType != XML_SCHEMA_CONTENT_ELEMENTS) && + (type->contentType != XML_SCHEMA_CONTENT_MIXED))) + return; + +#ifdef DEBUG_CONTENT + xmlGenericError(xmlGenericErrorContext, + "Building content model for %s\n", name); +#endif + ctxt->am = NULL; + ctxt->am = xmlNewAutomata(); + if (ctxt->am == NULL) { + xmlGenericError(xmlGenericErrorContext, + "Cannot create automata for complex type %s\n", type->name); + return; + } + ctxt->state = xmlAutomataGetInitState(ctxt->am); + /* + * Build the automaton. + */ + xmlSchemaBuildAContentModel(ctxt, WXS_TYPE_PARTICLE(type)); + xmlAutomataSetFinalState(ctxt->am, ctxt->state); + type->contModel = xmlAutomataCompile(ctxt->am); + if (type->contModel == NULL) { + xmlSchemaPCustomErr(ctxt, + XML_SCHEMAP_INTERNAL, + WXS_BASIC_CAST type, type->node, + "Failed to compile the content model", NULL); + } 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); + } else { +#ifdef DEBUG_CONTENT_REGEXP + xmlGenericError(xmlGenericErrorContext, + "Content model of %s:\n", type->name); + xmlRegexpPrint(stderr, type->contModel); +#endif + } + ctxt->state = NULL; + xmlFreeAutomata(ctxt->am); + ctxt->am = NULL; +} + +/** + * xmlSchemaResolveElementReferences: + * @elem: the schema element context + * @ctxt: the schema parser context + * + * Resolves the references of an element declaration + * or particle, which has an element declaration as it's + * term. + */ +static void +xmlSchemaResolveElementReferences(xmlSchemaElementPtr elemDecl, + xmlSchemaParserCtxtPtr ctxt) +{ + if ((ctxt == NULL) || (elemDecl == NULL) || + ((elemDecl != NULL) && + (elemDecl->flags & XML_SCHEMAS_ELEM_INTERNAL_RESOLVED))) + return; + elemDecl->flags |= XML_SCHEMAS_ELEM_INTERNAL_RESOLVED; + + if ((elemDecl->subtypes == NULL) && (elemDecl->namedType != NULL)) { + xmlSchemaTypePtr type; + + /* (type definition) ... otherwise the type definition �resolved� + * to by the �actual value� of the type [attribute] ... + */ + type = xmlSchemaGetType(ctxt->schema, elemDecl->namedType, + elemDecl->namedTypeNs); + if (type == NULL) { + xmlSchemaPResCompAttrErr(ctxt, + XML_SCHEMAP_SRC_RESOLVE, + WXS_BASIC_CAST elemDecl, elemDecl->node, + "type", elemDecl->namedType, elemDecl->namedTypeNs, + XML_SCHEMA_TYPE_BASIC, "type definition"); + } else + elemDecl->subtypes = type; + } + if (elemDecl->substGroup != NULL) { + xmlSchemaElementPtr substHead; + + /* + * FIXME TODO: Do we need a new field in _xmlSchemaElement for + * substitutionGroup? + */ + substHead = xmlSchemaGetElem(ctxt->schema, elemDecl->substGroup, + elemDecl->substGroupNs); + if (substHead == NULL) { + xmlSchemaPResCompAttrErr(ctxt, + XML_SCHEMAP_SRC_RESOLVE, + WXS_BASIC_CAST elemDecl, NULL, + "substitutionGroup", elemDecl->substGroup, + elemDecl->substGroupNs, XML_SCHEMA_TYPE_ELEMENT, NULL); + } else { + xmlSchemaResolveElementReferences(substHead, ctxt); + /* + * Set the "substitution group affiliation". + * NOTE that now we use the "refDecl" field for this. + */ + WXS_SUBST_HEAD(elemDecl) = substHead; + /* + * The type definitions is set to: + * SPEC "...the {type definition} of the element + * declaration �resolved� to by the �actual value� + * of the substitutionGroup [attribute], if present" + */ + if (elemDecl->subtypes == NULL) + elemDecl->subtypes = substHead->subtypes; + } + } + /* + * SPEC "The definition of anyType serves as the default type definition + * for element declarations whose XML representation does not specify one." + */ + if ((elemDecl->subtypes == NULL) && + (elemDecl->namedType == NULL) && + (elemDecl->substGroup == NULL)) + elemDecl->subtypes = xmlSchemaGetBuiltInType(XML_SCHEMAS_ANYTYPE); +} + +/** + * xmlSchemaResolveUnionMemberTypes: + * @ctxt: the schema parser context + * @type: the schema simple type definition + * + * Checks and builds the "member type definitions" property of the union + * simple type. This handles part (1), part (2) is done in + * xmlSchemaFinishMemberTypeDefinitionsProperty() + * + * Returns -1 in case of an internal error, 0 otherwise. + */ +static int +xmlSchemaResolveUnionMemberTypes(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaTypePtr type) +{ + + xmlSchemaTypeLinkPtr link, lastLink, newLink; + xmlSchemaTypePtr memberType; + + /* + * SPEC (1) "If the alternative is chosen, then [Definition:] + * define the explicit members as the type definitions �resolved� + * to by the items in the �actual value� of the memberTypes [attribute], + * if any, followed by the type definitions corresponding to the + * s among the [children] of , if any." + */ + /* + * Resolve references. + */ + link = type->memberTypes; + lastLink = NULL; + while (link != NULL) { + const xmlChar *name, *nsName; + + name = ((xmlSchemaQNameRefPtr) link->type)->name; + nsName = ((xmlSchemaQNameRefPtr) link->type)->targetNamespace; + + memberType = xmlSchemaGetType(ctxt->schema, name, nsName); + if ((memberType == NULL) || (! WXS_IS_SIMPLE(memberType))) { + xmlSchemaPResCompAttrErr(ctxt, XML_SCHEMAP_SRC_RESOLVE, + WXS_BASIC_CAST type, type->node, "memberTypes", + name, nsName, XML_SCHEMA_TYPE_SIMPLE, NULL); + /* + * Remove the member type link. + */ + if (lastLink == NULL) + type->memberTypes = link->next; + else + lastLink->next = link->next; + newLink = link; + link = link->next; + xmlFree(newLink); + } else { + link->type = memberType; + lastLink = link; + link = link->next; + } + } + /* + * Add local simple types, + */ + memberType = type->subtypes; + while (memberType != NULL) { + link = (xmlSchemaTypeLinkPtr) xmlMalloc(sizeof(xmlSchemaTypeLink)); + if (link == NULL) { + xmlSchemaPErrMemory(ctxt, "allocating a type link", NULL); + return (-1); + } + link->type = memberType; + link->next = NULL; + if (lastLink == NULL) + type->memberTypes = link; + else + lastLink->next = link; + lastLink = link; + memberType = memberType->next; + } + return (0); +} + +/** + * xmlSchemaIsDerivedFromBuiltInType: + * @ctxt: the schema parser context + * @type: the type definition + * @valType: the value type + * + * + * Returns 1 if the type has the given value type, or + * is derived from such a type. + */ +static int +xmlSchemaIsDerivedFromBuiltInType(xmlSchemaTypePtr type, int valType) +{ + if (type == NULL) + return (0); + if (WXS_IS_COMPLEX(type)) + return (0); + if (type->type == XML_SCHEMA_TYPE_BASIC) { + if (type->builtInType == valType) + return(1); + if ((type->builtInType == XML_SCHEMAS_ANYSIMPLETYPE) || + (type->builtInType == XML_SCHEMAS_ANYTYPE)) + return (0); + return(xmlSchemaIsDerivedFromBuiltInType(type->subtypes, valType)); + } + return(xmlSchemaIsDerivedFromBuiltInType(type->subtypes, valType)); +} + +#if 0 +/** + * xmlSchemaIsDerivedFromBuiltInType: + * @ctxt: the schema parser context + * @type: the type definition + * @valType: the value type + * + * + * Returns 1 if the type has the given value type, or + * is derived from such a type. + */ +static int +xmlSchemaIsUserDerivedFromBuiltInType(xmlSchemaTypePtr type, int valType) +{ + if (type == NULL) + return (0); + if (WXS_IS_COMPLEX(type)) + return (0); + if (type->type == XML_SCHEMA_TYPE_BASIC) { + if (type->builtInType == valType) + return(1); + return (0); + } else + return(xmlSchemaIsDerivedFromBuiltInType(type->subtypes, valType)); + + return (0); +} + +static xmlSchemaTypePtr +xmlSchemaQueryBuiltInType(xmlSchemaTypePtr type) +{ + if (type == NULL) + return (NULL); + if (WXS_IS_COMPLEX(type)) + return (NULL); + if (type->type == XML_SCHEMA_TYPE_BASIC) + return(type); + return(xmlSchemaQueryBuiltInType(type->subtypes)); +} +#endif + +/** + * xmlSchemaGetPrimitiveType: + * @type: the simpleType definition + * + * Returns the primitive type of the given type or + * NULL in case of error. + */ +static xmlSchemaTypePtr +xmlSchemaGetPrimitiveType(xmlSchemaTypePtr type) +{ + + while (type != NULL) { + /* + * Note that anySimpleType is actually not a primitive type + * but we need that here. + */ + if ((type->builtInType == XML_SCHEMAS_ANYSIMPLETYPE) || + (type->flags & XML_SCHEMAS_TYPE_BUILTIN_PRIMITIVE)) + return (type); + type = type->baseType; + } + + return (NULL); +} + +#if 0 +/** + * xmlSchemaGetBuiltInTypeAncestor: + * @type: the simpleType definition + * + * Returns the primitive type of the given type or + * NULL in case of error. + */ +static xmlSchemaTypePtr +xmlSchemaGetBuiltInTypeAncestor(xmlSchemaTypePtr type) +{ + if (WXS_IS_LIST(type) || WXS_IS_UNION(type)) + return (0); + while (type != NULL) { + if (type->type == XML_SCHEMA_TYPE_BASIC) + return (type); + type = type->baseType; + } + + return (NULL); +} +#endif + +/** + * xmlSchemaCloneWildcardNsConstraints: + * @ctxt: the schema parser context + * @dest: the destination wildcard + * @source: the source wildcard + * + * Clones the namespace constraints of source + * and assignes them to dest. + * Returns -1 on internal error, 0 otherwise. + */ +static int +xmlSchemaCloneWildcardNsConstraints(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaWildcardPtr dest, + xmlSchemaWildcardPtr source) +{ + xmlSchemaWildcardNsPtr cur, tmp, last; + + if ((source == NULL) || (dest == NULL)) + return(-1); + dest->any = source->any; + cur = source->nsSet; + last = NULL; + while (cur != NULL) { + tmp = xmlSchemaNewWildcardNsConstraint(ctxt); + if (tmp == NULL) + return(-1); + tmp->value = cur->value; + if (last == NULL) + dest->nsSet = tmp; + else + last->next = tmp; + last = tmp; + cur = cur->next; + } + if (dest->negNsSet != NULL) + xmlSchemaFreeWildcardNsSet(dest->negNsSet); + if (source->negNsSet != NULL) { + dest->negNsSet = xmlSchemaNewWildcardNsConstraint(ctxt); + if (dest->negNsSet == NULL) + return(-1); + dest->negNsSet->value = source->negNsSet->value; + } else + dest->negNsSet = NULL; + return(0); +} + +/** + * xmlSchemaUnionWildcards: + * @ctxt: the schema parser context + * @completeWild: the first wildcard + * @curWild: the second wildcard + * + * Unions the namespace constraints of the given wildcards. + * @completeWild will hold the resulting union. + * Returns a positive error code on failure, -1 in case of an + * internal error, 0 otherwise. + */ +static int +xmlSchemaUnionWildcards(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaWildcardPtr completeWild, + xmlSchemaWildcardPtr curWild) +{ + xmlSchemaWildcardNsPtr cur, curB, tmp; + + /* + * 1 If O1 and O2 are the same value, then that value must be the + * value. + */ + if ((completeWild->any == curWild->any) && + ((completeWild->nsSet == NULL) == (curWild->nsSet == NULL)) && + ((completeWild->negNsSet == NULL) == (curWild->negNsSet == NULL))) { + + if ((completeWild->negNsSet == NULL) || + (completeWild->negNsSet->value == curWild->negNsSet->value)) { + + if (completeWild->nsSet != NULL) { + int found = 0; + + /* + * Check equality of sets. + */ + cur = completeWild->nsSet; + while (cur != NULL) { + found = 0; + curB = curWild->nsSet; + while (curB != NULL) { + if (cur->value == curB->value) { + found = 1; + break; + } + curB = curB->next; + } + if (!found) + break; + cur = cur->next; + } + if (found) + return(0); + } else + return(0); + } + } + /* + * 2 If either O1 or O2 is any, then any must be the value + */ + if (completeWild->any != curWild->any) { + if (completeWild->any == 0) { + completeWild->any = 1; + if (completeWild->nsSet != NULL) { + xmlSchemaFreeWildcardNsSet(completeWild->nsSet); + completeWild->nsSet = NULL; + } + if (completeWild->negNsSet != NULL) { + xmlFree(completeWild->negNsSet); + completeWild->negNsSet = NULL; + } + } + return (0); + } + /* + * 3 If both O1 and O2 are sets of (namespace names or �absent�), + * then the union of those sets must be the value. + */ + if ((completeWild->nsSet != NULL) && (curWild->nsSet != NULL)) { + int found; + xmlSchemaWildcardNsPtr start; + + cur = curWild->nsSet; + start = completeWild->nsSet; + while (cur != NULL) { + found = 0; + curB = start; + while (curB != NULL) { + if (cur->value == curB->value) { + found = 1; + break; + } + curB = curB->next; + } + if (!found) { + tmp = xmlSchemaNewWildcardNsConstraint(ctxt); + if (tmp == NULL) + return (-1); + tmp->value = cur->value; + tmp->next = completeWild->nsSet; + completeWild->nsSet = tmp; + } + cur = cur->next; + } + + return(0); + } + /* + * 4 If the two are negations of different values (namespace names + * or �absent�), then a pair of not and �absent� must be the value. + */ + if ((completeWild->negNsSet != NULL) && + (curWild->negNsSet != NULL) && + (completeWild->negNsSet->value != curWild->negNsSet->value)) { + completeWild->negNsSet->value = NULL; + + return(0); + } + /* + * 5. + */ + if (((completeWild->negNsSet != NULL) && + (completeWild->negNsSet->value != NULL) && + (curWild->nsSet != NULL)) || + ((curWild->negNsSet != NULL) && + (curWild->negNsSet->value != NULL) && + (completeWild->nsSet != NULL))) { + + int nsFound, absentFound = 0; + + if (completeWild->nsSet != NULL) { + cur = completeWild->nsSet; + curB = curWild->negNsSet; + } else { + cur = curWild->nsSet; + curB = completeWild->negNsSet; + } + nsFound = 0; + while (cur != NULL) { + if (cur->value == NULL) + absentFound = 1; + else if (cur->value == curB->value) + nsFound = 1; + if (nsFound && absentFound) + break; + cur = cur->next; + } + + if (nsFound && absentFound) { + /* + * 5.1 If the set S includes both the negated namespace + * name and �absent�, then any must be the value. + */ + completeWild->any = 1; + if (completeWild->nsSet != NULL) { + xmlSchemaFreeWildcardNsSet(completeWild->nsSet); + completeWild->nsSet = NULL; + } + if (completeWild->negNsSet != NULL) { + xmlFree(completeWild->negNsSet); + completeWild->negNsSet = NULL; + } + } else if (nsFound && (!absentFound)) { + /* + * 5.2 If the set S includes the negated namespace name + * but not �absent�, then a pair of not and �absent� must + * be the value. + */ + if (completeWild->nsSet != NULL) { + xmlSchemaFreeWildcardNsSet(completeWild->nsSet); + completeWild->nsSet = NULL; + } + if (completeWild->negNsSet == NULL) { + completeWild->negNsSet = xmlSchemaNewWildcardNsConstraint(ctxt); + if (completeWild->negNsSet == NULL) + return (-1); + } + completeWild->negNsSet->value = NULL; + } else if ((!nsFound) && absentFound) { + /* + * 5.3 If the set S includes �absent� but not the negated + * namespace name, then the union is not expressible. + */ + xmlSchemaPErr(ctxt, completeWild->node, + XML_SCHEMAP_UNION_NOT_EXPRESSIBLE, + "The union of the wilcard is not expressible.\n", + NULL, NULL); + return(XML_SCHEMAP_UNION_NOT_EXPRESSIBLE); + } else if ((!nsFound) && (!absentFound)) { + /* + * 5.4 If the set S does not include either the negated namespace + * name or �absent�, then whichever of O1 or O2 is a pair of not + * and a namespace name must be the value. + */ + if (completeWild->negNsSet == NULL) { + if (completeWild->nsSet != NULL) { + xmlSchemaFreeWildcardNsSet(completeWild->nsSet); + completeWild->nsSet = NULL; + } + completeWild->negNsSet = xmlSchemaNewWildcardNsConstraint(ctxt); + if (completeWild->negNsSet == NULL) + return (-1); + completeWild->negNsSet->value = curWild->negNsSet->value; + } + } + return (0); + } + /* + * 6. + */ + if (((completeWild->negNsSet != NULL) && + (completeWild->negNsSet->value == NULL) && + (curWild->nsSet != NULL)) || + ((curWild->negNsSet != NULL) && + (curWild->negNsSet->value == NULL) && + (completeWild->nsSet != NULL))) { + + if (completeWild->nsSet != NULL) { + cur = completeWild->nsSet; + } else { + cur = curWild->nsSet; + } + while (cur != NULL) { + if (cur->value == NULL) { + /* + * 6.1 If the set S includes �absent�, then any must be the + * value. + */ + completeWild->any = 1; + if (completeWild->nsSet != NULL) { + xmlSchemaFreeWildcardNsSet(completeWild->nsSet); + completeWild->nsSet = NULL; + } + if (completeWild->negNsSet != NULL) { + xmlFree(completeWild->negNsSet); + completeWild->negNsSet = NULL; + } + return (0); + } + cur = cur->next; + } + if (completeWild->negNsSet == NULL) { + /* + * 6.2 If the set S does not include �absent�, then a pair of not + * and �absent� must be the value. + */ + if (completeWild->nsSet != NULL) { + xmlSchemaFreeWildcardNsSet(completeWild->nsSet); + completeWild->nsSet = NULL; + } + completeWild->negNsSet = xmlSchemaNewWildcardNsConstraint(ctxt); + if (completeWild->negNsSet == NULL) + return (-1); + completeWild->negNsSet->value = NULL; + } + return (0); + } + return (0); + +} + +/** + * xmlSchemaIntersectWildcards: + * @ctxt: the schema parser context + * @completeWild: the first wildcard + * @curWild: the second wildcard + * + * Intersects the namespace constraints of the given wildcards. + * @completeWild will hold the resulting intersection. + * Returns a positive error code on failure, -1 in case of an + * internal error, 0 otherwise. + */ +static int +xmlSchemaIntersectWildcards(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaWildcardPtr completeWild, + xmlSchemaWildcardPtr curWild) +{ + xmlSchemaWildcardNsPtr cur, curB, prev, tmp; + + /* + * 1 If O1 and O2 are the same value, then that value must be the + * value. + */ + if ((completeWild->any == curWild->any) && + ((completeWild->nsSet == NULL) == (curWild->nsSet == NULL)) && + ((completeWild->negNsSet == NULL) == (curWild->negNsSet == NULL))) { + + if ((completeWild->negNsSet == NULL) || + (completeWild->negNsSet->value == curWild->negNsSet->value)) { + + if (completeWild->nsSet != NULL) { + int found = 0; + + /* + * Check equality of sets. + */ + cur = completeWild->nsSet; + while (cur != NULL) { + found = 0; + curB = curWild->nsSet; + while (curB != NULL) { + if (cur->value == curB->value) { + found = 1; + break; + } + curB = curB->next; + } + if (!found) + break; + cur = cur->next; + } + if (found) + return(0); + } else + return(0); + } + } + /* + * 2 If either O1 or O2 is any, then the other must be the value. + */ + if ((completeWild->any != curWild->any) && (completeWild->any)) { + if (xmlSchemaCloneWildcardNsConstraints(ctxt, completeWild, curWild) == -1) + return(-1); + return(0); + } + /* + * 3 If either O1 or O2 is a pair of not and a value (a namespace + * name or �absent�) and the other is a set of (namespace names or + * �absent�), then that set, minus the negated value if it was in + * the set, minus �absent� if it was in the set, must be the value. + */ + if (((completeWild->negNsSet != NULL) && (curWild->nsSet != NULL)) || + ((curWild->negNsSet != NULL) && (completeWild->nsSet != NULL))) { + const xmlChar *neg; + + if (completeWild->nsSet == NULL) { + neg = completeWild->negNsSet->value; + if (xmlSchemaCloneWildcardNsConstraints(ctxt, completeWild, curWild) == -1) + return(-1); + } else + neg = curWild->negNsSet->value; + /* + * Remove absent and negated. + */ + prev = NULL; + cur = completeWild->nsSet; + while (cur != NULL) { + if (cur->value == NULL) { + if (prev == NULL) + completeWild->nsSet = cur->next; + else + prev->next = cur->next; + xmlFree(cur); + break; + } + prev = cur; + cur = cur->next; + } + if (neg != NULL) { + prev = NULL; + cur = completeWild->nsSet; + while (cur != NULL) { + if (cur->value == neg) { + if (prev == NULL) + completeWild->nsSet = cur->next; + else + prev->next = cur->next; + xmlFree(cur); + break; + } + prev = cur; + cur = cur->next; + } + } + + return(0); + } + /* + * 4 If both O1 and O2 are sets of (namespace names or �absent�), + * then the intersection of those sets must be the value. + */ + if ((completeWild->nsSet != NULL) && (curWild->nsSet != NULL)) { + int found; + + cur = completeWild->nsSet; + prev = NULL; + while (cur != NULL) { + found = 0; + curB = curWild->nsSet; + while (curB != NULL) { + if (cur->value == curB->value) { + found = 1; + break; + } + curB = curB->next; + } + if (!found) { + if (prev == NULL) + completeWild->nsSet = cur->next; + else + prev->next = cur->next; + tmp = cur->next; + xmlFree(cur); + cur = tmp; + continue; + } + prev = cur; + cur = cur->next; + } + + return(0); + } + /* 5 If the two are negations of different namespace names, + * then the intersection is not expressible + */ + if ((completeWild->negNsSet != NULL) && + (curWild->negNsSet != NULL) && + (completeWild->negNsSet->value != curWild->negNsSet->value) && + (completeWild->negNsSet->value != NULL) && + (curWild->negNsSet->value != NULL)) { + + xmlSchemaPErr(ctxt, completeWild->node, XML_SCHEMAP_INTERSECTION_NOT_EXPRESSIBLE, + "The intersection of the wilcard is not expressible.\n", + NULL, NULL); + return(XML_SCHEMAP_INTERSECTION_NOT_EXPRESSIBLE); + } + /* + * 6 If the one is a negation of a namespace name and the other + * is a negation of �absent�, then the one which is the negation + * of a namespace name must be the value. + */ + if ((completeWild->negNsSet != NULL) && (curWild->negNsSet != NULL) && + (completeWild->negNsSet->value != curWild->negNsSet->value) && + (completeWild->negNsSet->value == NULL)) { + completeWild->negNsSet->value = curWild->negNsSet->value; + } + return(0); +} + +/** + * xmlSchemaIsWildcardNsConstraintSubset: + * @ctxt: the schema parser context + * @sub: the first wildcard + * @super: the second wildcard + * + * Schema Component Constraint: Wildcard Subset (cos-ns-subset) + * + * Returns 0 if the namespace constraint of @sub is an intensional + * subset of @super, 1 otherwise. + */ +static int +xmlSchemaCheckCOSNSSubset(xmlSchemaWildcardPtr sub, + xmlSchemaWildcardPtr super) +{ + /* + * 1 super must be any. + */ + if (super->any) + return (0); + /* + * 2.1 sub must be a pair of not and a namespace name or �absent�. + * 2.2 super must be a pair of not and the same value. + */ + if ((sub->negNsSet != NULL) && + (super->negNsSet != NULL) && + (sub->negNsSet->value == sub->negNsSet->value)) + return (0); + /* + * 3.1 sub must be a set whose members are either namespace names or �absent�. + */ + if (sub->nsSet != NULL) { + /* + * 3.2.1 super must be the same set or a superset thereof. + */ + if (super->nsSet != NULL) { + xmlSchemaWildcardNsPtr cur, curB; + int found = 0; + + cur = sub->nsSet; + while (cur != NULL) { + found = 0; + curB = super->nsSet; + while (curB != NULL) { + if (cur->value == curB->value) { + found = 1; + break; + } + curB = curB->next; + } + if (!found) + return (1); + cur = cur->next; + } + if (found) + return (0); + } else if (super->negNsSet != NULL) { + xmlSchemaWildcardNsPtr cur; + /* + * 3.2.2 super must be a pair of not and a namespace name or + * �absent� and that value must not be in sub's set. + */ + cur = sub->nsSet; + while (cur != NULL) { + if (cur->value == super->negNsSet->value) + return (1); + cur = cur->next; + } + return (0); + } + } + return (1); +} + +static int +xmlSchemaGetEffectiveValueConstraint(xmlSchemaAttributeUsePtr attruse, + int *fixed, + const xmlChar **value, + xmlSchemaValPtr *val) +{ + *fixed = 0; + *value = NULL; + if (val != 0) + *val = NULL; + + if (attruse->defValue != NULL) { + *value = attruse->defValue; + if (val != NULL) + *val = attruse->defVal; + if (attruse->flags & XML_SCHEMA_ATTR_USE_FIXED) + *fixed = 1; + return(1); + } else if ((attruse->attrDecl != NULL) && + (attruse->attrDecl->defValue != NULL)) { + *value = attruse->attrDecl->defValue; + if (val != NULL) + *val = attruse->attrDecl->defVal; + if (attruse->attrDecl->flags & XML_SCHEMAS_ATTR_FIXED) + *fixed = 1; + return(1); + } + return(0); +} +/** + * xmlSchemaCheckCVCWildcardNamespace: + * @wild: the wildcard + * @ns: the namespace + * + * Validation Rule: Wildcard allows Namespace Name + * (cvc-wildcard-namespace) + * + * Returns 0 if the given namespace matches the wildcard, + * 1 otherwise and -1 on API errors. + */ +static int +xmlSchemaCheckCVCWildcardNamespace(xmlSchemaWildcardPtr wild, + const xmlChar* ns) +{ + if (wild == NULL) + return(-1); + + if (wild->any) + return(0); + else if (wild->nsSet != NULL) { + xmlSchemaWildcardNsPtr cur; + + cur = wild->nsSet; + while (cur != NULL) { + if (xmlStrEqual(cur->value, ns)) + return(0); + cur = cur->next; + } + } else if ((wild->negNsSet != NULL) && (ns != NULL) && + (!xmlStrEqual(wild->negNsSet->value, ns))) + return(0); + + return(1); +} + +#define XML_SCHEMA_ACTION_DERIVE 0 +#define XML_SCHEMA_ACTION_REDEFINE 1 + +#define WXS_ACTION_STR(a) \ +((a) == XML_SCHEMA_ACTION_DERIVE) ? (const xmlChar *) "base" : (const xmlChar *) "redefined" + +/* +* Schema Component Constraint: +* Derivation Valid (Restriction, Complex) +* derivation-ok-restriction (2) - (4) +* +* ATTENTION: +* In XML Schema 1.1 this will be: +* Validation Rule: +* Checking complex type subsumption (practicalSubsumption) (1, 2 and 3) +* +*/ +static int +xmlSchemaCheckDerivationOKRestriction2to4(xmlSchemaParserCtxtPtr pctxt, + int action, + xmlSchemaBasicItemPtr item, + xmlSchemaBasicItemPtr baseItem, + xmlSchemaItemListPtr uses, + xmlSchemaItemListPtr baseUses, + xmlSchemaWildcardPtr wild, + xmlSchemaWildcardPtr baseWild) +{ + xmlSchemaAttributeUsePtr cur = NULL, bcur; + int i, j, found; /* err = 0; */ + const xmlChar *bEffValue; + int effFixed; + + if (uses != NULL) { + for (i = 0; i < uses->nbItems; i++) { + cur = uses->items[i]; + found = 0; + if (baseUses == NULL) + goto not_found; + for (j = 0; j < baseUses->nbItems; j++) { + bcur = baseUses->items[j]; + if ((WXS_ATTRUSE_DECL_NAME(cur) == + WXS_ATTRUSE_DECL_NAME(bcur)) && + (WXS_ATTRUSE_DECL_TNS(cur) == + WXS_ATTRUSE_DECL_TNS(bcur))) + { + /* + * (2.1) "If there is an attribute use in the {attribute + * uses} of the {base type definition} (call this B) whose + * {attribute declaration} has the same {name} and {target + * namespace}, then all of the following must be true:" + */ + found = 1; + + if ((cur->occurs == XML_SCHEMAS_ATTR_USE_OPTIONAL) && + (bcur->occurs == XML_SCHEMAS_ATTR_USE_REQUIRED)) + { + xmlChar *str = NULL; + /* + * (2.1.1) "one of the following must be true:" + * (2.1.1.1) "B's {required} is false." + * (2.1.1.2) "R's {required} is true." + */ + xmlSchemaPAttrUseErr4(pctxt, + XML_SCHEMAP_DERIVATION_OK_RESTRICTION_2_1_1, + WXS_ITEM_NODE(item), item, cur, + "The 'optional' attribute use is inconsistent " + "with the corresponding 'required' attribute use of " + "the %s %s", + WXS_ACTION_STR(action), + xmlSchemaGetComponentDesignation(&str, baseItem), + NULL, NULL); + FREE_AND_NULL(str); + /* err = pctxt->err; */ + } else if (xmlSchemaCheckCOSSTDerivedOK(ACTXT_CAST pctxt, + WXS_ATTRUSE_TYPEDEF(cur), + WXS_ATTRUSE_TYPEDEF(bcur), 0) != 0) + { + xmlChar *strA = NULL, *strB = NULL, *strC = NULL; + + /* + * SPEC (2.1.2) "R's {attribute declaration}'s + * {type definition} must be validly derived from + * B's {type definition} given the empty set as + * defined in Type Derivation OK (Simple) (�3.14.6)." + */ + xmlSchemaPAttrUseErr4(pctxt, + XML_SCHEMAP_DERIVATION_OK_RESTRICTION_2_1_2, + WXS_ITEM_NODE(item), item, cur, + "The attribute declaration's %s " + "is not validly derived from " + "the corresponding %s of the " + "attribute declaration in the %s %s", + xmlSchemaGetComponentDesignation(&strA, + WXS_ATTRUSE_TYPEDEF(cur)), + xmlSchemaGetComponentDesignation(&strB, + WXS_ATTRUSE_TYPEDEF(bcur)), + WXS_ACTION_STR(action), + xmlSchemaGetComponentDesignation(&strC, baseItem)); + /* xmlSchemaGetComponentDesignation(&str, baseItem), */ + FREE_AND_NULL(strA); + FREE_AND_NULL(strB); + FREE_AND_NULL(strC); + /* err = pctxt->err; */ + } else { + /* + * 2.1.3 [Definition:] Let the effective value + * constraint of an attribute use be its {value + * constraint}, if present, otherwise its {attribute + * declaration}'s {value constraint} . + */ + xmlSchemaGetEffectiveValueConstraint(bcur, + &effFixed, &bEffValue, NULL); + /* + * 2.1.3 ... one of the following must be true + * + * 2.1.3.1 B's �effective value constraint� is + * �absent� or default. + */ + if ((bEffValue != NULL) && + (effFixed == 1)) { + const xmlChar *rEffValue = NULL; + + xmlSchemaGetEffectiveValueConstraint(bcur, + &effFixed, &rEffValue, NULL); + /* + * 2.1.3.2 R's �effective value constraint� is + * fixed with the same string as B's. + * MAYBE TODO: Compare the computed values. + * Hmm, it says "same string" so + * string-equality might really be sufficient. + */ + if ((effFixed == 0) || + (! WXS_ARE_DEFAULT_STR_EQUAL(rEffValue, bEffValue))) + { + xmlChar *str = NULL; + + xmlSchemaPAttrUseErr4(pctxt, + XML_SCHEMAP_DERIVATION_OK_RESTRICTION_2_1_3, + WXS_ITEM_NODE(item), item, cur, + "The effective value constraint of the " + "attribute use is inconsistent with " + "its correspondent in the %s %s", + WXS_ACTION_STR(action), + xmlSchemaGetComponentDesignation(&str, + baseItem), + NULL, NULL); + FREE_AND_NULL(str); + /* err = pctxt->err; */ + } + } + } + break; + } + } +not_found: + if (!found) { + /* + * (2.2) "otherwise the {base type definition} must have an + * {attribute wildcard} and the {target namespace} of the + * R's {attribute declaration} must be �valid� with respect + * to that wildcard, as defined in Wildcard allows Namespace + * Name (�3.10.4)." + */ + if ((baseWild == NULL) || + (xmlSchemaCheckCVCWildcardNamespace(baseWild, + (WXS_ATTRUSE_DECL(cur))->targetNamespace) != 0)) + { + xmlChar *str = NULL; + + xmlSchemaPAttrUseErr4(pctxt, + XML_SCHEMAP_DERIVATION_OK_RESTRICTION_2_2, + WXS_ITEM_NODE(item), item, cur, + "Neither a matching attribute use, " + "nor a matching wildcard exists in the %s %s", + WXS_ACTION_STR(action), + xmlSchemaGetComponentDesignation(&str, baseItem), + NULL, NULL); + FREE_AND_NULL(str); + /* err = pctxt->err; */ + } + } + } + } + /* + * SPEC derivation-ok-restriction (3): + * (3) "For each attribute use in the {attribute uses} of the {base type + * definition} whose {required} is true, there must be an attribute + * use with an {attribute declaration} with the same {name} and + * {target namespace} as its {attribute declaration} in the {attribute + * uses} of the complex type definition itself whose {required} is true. + */ + if (baseUses != NULL) { + for (j = 0; j < baseUses->nbItems; j++) { + bcur = baseUses->items[j]; + if (bcur->occurs != XML_SCHEMAS_ATTR_USE_REQUIRED) + continue; + found = 0; + if (uses != NULL) { + for (i = 0; i < uses->nbItems; i++) { + cur = uses->items[i]; + if ((WXS_ATTRUSE_DECL_NAME(cur) == + WXS_ATTRUSE_DECL_NAME(bcur)) && + (WXS_ATTRUSE_DECL_TNS(cur) == + WXS_ATTRUSE_DECL_TNS(bcur))) { + found = 1; + break; + } + } + } + if (!found) { + xmlChar *strA = NULL, *strB = NULL; + + xmlSchemaCustomErr4(ACTXT_CAST pctxt, + XML_SCHEMAP_DERIVATION_OK_RESTRICTION_3, + NULL, item, + "A matching attribute use for the " + "'required' %s of the %s %s is missing", + xmlSchemaGetComponentDesignation(&strA, bcur), + WXS_ACTION_STR(action), + xmlSchemaGetComponentDesignation(&strB, baseItem), + NULL); + FREE_AND_NULL(strA); + FREE_AND_NULL(strB); + } + } + } + /* + * derivation-ok-restriction (4) + */ + if (wild != NULL) { + /* + * (4) "If there is an {attribute wildcard}, all of the + * following must be true:" + */ + if (baseWild == NULL) { + xmlChar *str = NULL; + + /* + * (4.1) "The {base type definition} must also have one." + */ + xmlSchemaCustomErr4(ACTXT_CAST pctxt, + XML_SCHEMAP_DERIVATION_OK_RESTRICTION_4_1, + NULL, item, + "The %s has an attribute wildcard, " + "but the %s %s '%s' does not have one", + WXS_ITEM_TYPE_NAME(item), + WXS_ACTION_STR(action), + WXS_ITEM_TYPE_NAME(baseItem), + xmlSchemaGetComponentQName(&str, baseItem)); + FREE_AND_NULL(str); + return(pctxt->err); + } else if ((baseWild->any == 0) && + xmlSchemaCheckCOSNSSubset(wild, baseWild)) + { + xmlChar *str = NULL; + /* + * (4.2) "The complex type definition's {attribute wildcard}'s + * {namespace constraint} must be a subset of the {base type + * definition}'s {attribute wildcard}'s {namespace constraint}, + * as defined by Wildcard Subset (�3.10.6)." + */ + xmlSchemaCustomErr4(ACTXT_CAST pctxt, + XML_SCHEMAP_DERIVATION_OK_RESTRICTION_4_2, + NULL, item, + "The attribute wildcard is not a valid " + "subset of the wildcard in the %s %s '%s'", + WXS_ACTION_STR(action), + WXS_ITEM_TYPE_NAME(baseItem), + xmlSchemaGetComponentQName(&str, baseItem), + NULL); + FREE_AND_NULL(str); + return(pctxt->err); + } + /* 4.3 Unless the {base type definition} is the �ur-type + * definition�, the complex type definition's {attribute + * wildcard}'s {process contents} must be identical to or + * stronger than the {base type definition}'s {attribute + * wildcard}'s {process contents}, where strict is stronger + * than lax is stronger than skip. + */ + if ((! WXS_IS_ANYTYPE(baseItem)) && + (wild->processContents < baseWild->processContents)) { + xmlChar *str = NULL; + xmlSchemaCustomErr4(ACTXT_CAST pctxt, + XML_SCHEMAP_DERIVATION_OK_RESTRICTION_4_3, + NULL, baseItem, + "The {process contents} of the attribute wildcard is " + "weaker than the one in the %s %s '%s'", + WXS_ACTION_STR(action), + WXS_ITEM_TYPE_NAME(baseItem), + xmlSchemaGetComponentQName(&str, baseItem), + NULL); + FREE_AND_NULL(str) + return(pctxt->err); + } + } + return(0); +} + + +static int +xmlSchemaExpandAttributeGroupRefs(xmlSchemaParserCtxtPtr pctxt, + xmlSchemaBasicItemPtr item, + xmlSchemaWildcardPtr *completeWild, + xmlSchemaItemListPtr list, + xmlSchemaItemListPtr prohibs); +/** + * xmlSchemaFixupTypeAttributeUses: + * @ctxt: the schema parser context + * @type: the complex type definition + * + * + * Builds the wildcard and the attribute uses on the given complex type. + * Returns -1 if an internal error occurs, 0 otherwise. + * + * ATTENTION TODO: Experimantally this uses pointer comparisons for + * strings, so recheck this if we start to hardcode some schemata, since + * they might not be in the same dict. + * NOTE: It is allowed to "extend" the xs:anyType type. + */ +static int +xmlSchemaFixupTypeAttributeUses(xmlSchemaParserCtxtPtr pctxt, + xmlSchemaTypePtr type) +{ + xmlSchemaTypePtr baseType = NULL; + xmlSchemaAttributeUsePtr use; + xmlSchemaItemListPtr uses, baseUses, prohibs = NULL; + + if (type->baseType == NULL) { + PERROR_INT("xmlSchemaFixupTypeAttributeUses", + "no base type"); + return (-1); + } + baseType = type->baseType; + if (WXS_IS_TYPE_NOT_FIXED(baseType)) + if (xmlSchemaTypeFixup(baseType, ACTXT_CAST pctxt) == -1) + return(-1); + + uses = type->attrUses; + baseUses = baseType->attrUses; + /* + * Expand attribute group references. And build the 'complete' + * wildcard, i.e. intersect multiple wildcards. + * Move attribute prohibitions into a separate list. + */ + if (uses != NULL) { + if (WXS_IS_RESTRICTION(type)) { + /* + * This one will transfer all attr. prohibitions + * into pctxt->attrProhibs. + */ + if (xmlSchemaExpandAttributeGroupRefs(pctxt, + WXS_BASIC_CAST type, &(type->attributeWildcard), uses, + pctxt->attrProhibs) == -1) + { + PERROR_INT("xmlSchemaFixupTypeAttributeUses", + "failed to expand attributes"); + } + if (pctxt->attrProhibs->nbItems != 0) + prohibs = pctxt->attrProhibs; + } else { + if (xmlSchemaExpandAttributeGroupRefs(pctxt, + WXS_BASIC_CAST type, &(type->attributeWildcard), uses, + NULL) == -1) + { + PERROR_INT("xmlSchemaFixupTypeAttributeUses", + "failed to expand attributes"); + } + } + } + /* + * Inherit the attribute uses of the base type. + */ + if (baseUses != NULL) { + int i, j; + xmlSchemaAttributeUseProhibPtr pro; + + if (WXS_IS_RESTRICTION(type)) { + int usesCount; + xmlSchemaAttributeUsePtr tmp; + + if (uses != NULL) + usesCount = uses->nbItems; + else + usesCount = 0; + + /* Restriction. */ + for (i = 0; i < baseUses->nbItems; i++) { + use = baseUses->items[i]; + if (prohibs) { + /* + * Filter out prohibited uses. + */ + for (j = 0; j < prohibs->nbItems; j++) { + pro = prohibs->items[j]; + if ((WXS_ATTRUSE_DECL_NAME(use) == pro->name) && + (WXS_ATTRUSE_DECL_TNS(use) == + pro->targetNamespace)) + { + goto inherit_next; + } + } + } + if (usesCount) { + /* + * Filter out existing uses. + */ + for (j = 0; j < usesCount; j++) { + tmp = uses->items[j]; + if ((WXS_ATTRUSE_DECL_NAME(use) == + WXS_ATTRUSE_DECL_NAME(tmp)) && + (WXS_ATTRUSE_DECL_TNS(use) == + WXS_ATTRUSE_DECL_TNS(tmp))) + { + goto inherit_next; + } + } + } + if (uses == NULL) { + type->attrUses = xmlSchemaItemListCreate(); + if (type->attrUses == NULL) + goto exit_failure; + uses = type->attrUses; + } + xmlSchemaItemListAddSize(uses, 2, use); +inherit_next: {} + } + } else { + /* Extension. */ + for (i = 0; i < baseUses->nbItems; i++) { + use = baseUses->items[i]; + if (uses == NULL) { + type->attrUses = xmlSchemaItemListCreate(); + if (type->attrUses == NULL) + goto exit_failure; + uses = type->attrUses; + } + xmlSchemaItemListAddSize(uses, baseUses->nbItems, use); + } + } + } + /* + * Shrink attr. uses. + */ + if (uses) { + if (uses->nbItems == 0) { + xmlSchemaItemListFree(uses); + type->attrUses = NULL; + } + /* + * TODO: We could shrink the size of the array + * to fit the actual number of items. + */ + } + /* + * Compute the complete wildcard. + */ + if (WXS_IS_EXTENSION(type)) { + if (baseType->attributeWildcard != NULL) { + /* + * (3.2.2.1) "If the �base wildcard� is non-�absent�, then + * the appropriate case among the following:" + */ + if (type->attributeWildcard != NULL) { + /* + * Union the complete wildcard with the base wildcard. + * SPEC {attribute wildcard} + * (3.2.2.1.2) "otherwise a wildcard whose {process contents} + * and {annotation} are those of the �complete wildcard�, + * and whose {namespace constraint} is the intensional union + * of the {namespace constraint} of the �complete wildcard� + * and of the �base wildcard�, as defined in Attribute + * Wildcard Union (�3.10.6)." + */ + if (xmlSchemaUnionWildcards(pctxt, type->attributeWildcard, + baseType->attributeWildcard) == -1) + goto exit_failure; + } else { + /* + * (3.2.2.1.1) "If the �complete wildcard� is �absent�, + * then the �base wildcard�." + */ + type->attributeWildcard = baseType->attributeWildcard; + } + } else { + /* + * (3.2.2.2) "otherwise (the �base wildcard� is �absent�) the + * �complete wildcard" + * NOOP + */ + } + } else { + /* + * SPEC {attribute wildcard} + * (3.1) "If the alternative is chosen, then the + * �complete wildcard�;" + * NOOP + */ + } + + return (0); + +exit_failure: + return(-1); +} + +/** + * xmlSchemaTypeFinalContains: + * @schema: the schema + * @type: the type definition + * @final: the final + * + * Evaluates if a type definition contains the given "final". + * This does take "finalDefault" into account as well. + * + * Returns 1 if the type does containt the given "final", + * 0 otherwise. + */ +static int +xmlSchemaTypeFinalContains(xmlSchemaTypePtr type, int final) +{ + if (type == NULL) + return (0); + if (type->flags & final) + return (1); + else + return (0); +} + +/** + * xmlSchemaGetUnionSimpleTypeMemberTypes: + * @type: the Union Simple Type + * + * Returns a list of member types of @type if existing, + * returns NULL otherwise. + */ +static xmlSchemaTypeLinkPtr +xmlSchemaGetUnionSimpleTypeMemberTypes(xmlSchemaTypePtr type) +{ + while ((type != NULL) && (type->type == XML_SCHEMA_TYPE_SIMPLE)) { + if (type->memberTypes != NULL) + return (type->memberTypes); + else + type = type->baseType; + } + return (NULL); +} + +/** + * xmlSchemaGetParticleTotalRangeMin: + * @particle: the particle + * + * Schema Component Constraint: Effective Total Range + * (all and sequence) + (choice) + * + * Returns the minimun Effective Total Range. + */ +static int +xmlSchemaGetParticleTotalRangeMin(xmlSchemaParticlePtr particle) +{ + if ((particle->children == NULL) || + (particle->minOccurs == 0)) + return (0); + if (particle->children->type == XML_SCHEMA_TYPE_CHOICE) { + int min = -1, cur; + xmlSchemaParticlePtr part = + (xmlSchemaParticlePtr) particle->children->children; + + if (part == NULL) + return (0); + while (part != NULL) { + if ((part->children->type == XML_SCHEMA_TYPE_ELEMENT) || + (part->children->type == XML_SCHEMA_TYPE_ANY)) + cur = part->minOccurs; + else + cur = xmlSchemaGetParticleTotalRangeMin(part); + if (cur == 0) + return (0); + if ((min > cur) || (min == -1)) + min = cur; + part = (xmlSchemaParticlePtr) part->next; + } + return (particle->minOccurs * min); + } else { + /* and */ + int sum = 0; + xmlSchemaParticlePtr part = + (xmlSchemaParticlePtr) particle->children->children; + + if (part == NULL) + return (0); + do { + if ((part->children->type == XML_SCHEMA_TYPE_ELEMENT) || + (part->children->type == XML_SCHEMA_TYPE_ANY)) + sum += part->minOccurs; + else + sum += xmlSchemaGetParticleTotalRangeMin(part); + part = (xmlSchemaParticlePtr) part->next; + } while (part != NULL); + return (particle->minOccurs * sum); + } +} + +#if 0 +/** + * xmlSchemaGetParticleTotalRangeMax: + * @particle: the particle + * + * Schema Component Constraint: Effective Total Range + * (all and sequence) + (choice) + * + * Returns the maximum Effective Total Range. + */ +static int +xmlSchemaGetParticleTotalRangeMax(xmlSchemaParticlePtr particle) +{ + if ((particle->children == NULL) || + (particle->children->children == NULL)) + return (0); + if (particle->children->type == XML_SCHEMA_TYPE_CHOICE) { + int max = -1, cur; + xmlSchemaParticlePtr part = + (xmlSchemaParticlePtr) particle->children->children; + + for (; part != NULL; part = (xmlSchemaParticlePtr) part->next) { + if (part->children == NULL) + continue; + if ((part->children->type == XML_SCHEMA_TYPE_ELEMENT) || + (part->children->type == XML_SCHEMA_TYPE_ANY)) + cur = part->maxOccurs; + else + cur = xmlSchemaGetParticleTotalRangeMax(part); + if (cur == UNBOUNDED) + return (UNBOUNDED); + if ((max < cur) || (max == -1)) + max = cur; + } + /* TODO: Handle overflows? */ + return (particle->maxOccurs * max); + } else { + /* and */ + int sum = 0, cur; + xmlSchemaParticlePtr part = + (xmlSchemaParticlePtr) particle->children->children; + + for (; part != NULL; part = (xmlSchemaParticlePtr) part->next) { + if (part->children == NULL) + continue; + if ((part->children->type == XML_SCHEMA_TYPE_ELEMENT) || + (part->children->type == XML_SCHEMA_TYPE_ANY)) + cur = part->maxOccurs; + else + cur = xmlSchemaGetParticleTotalRangeMax(part); + if (cur == UNBOUNDED) + return (UNBOUNDED); + if ((cur > 0) && (particle->maxOccurs == UNBOUNDED)) + return (UNBOUNDED); + sum += cur; + } + /* TODO: Handle overflows? */ + return (particle->maxOccurs * sum); + } +} +#endif + +/** + * xmlSchemaIsParticleEmptiable: + * @particle: the particle + * + * Schema Component Constraint: Particle Emptiable + * Checks whether the given particle is emptiable. + * + * Returns 1 if emptiable, 0 otherwise. + */ +static int +xmlSchemaIsParticleEmptiable(xmlSchemaParticlePtr particle) +{ + /* + * SPEC (1) "Its {min occurs} is 0." + */ + if ((particle == NULL) || (particle->minOccurs == 0) || + (particle->children == NULL)) + return (1); + /* + * SPEC (2) "Its {term} is a group and the minimum part of the + * effective total range of that group, [...] is 0." + */ + if (WXS_IS_MODEL_GROUP(particle->children)) { + if (xmlSchemaGetParticleTotalRangeMin(particle) == 0) + return (1); + } + return (0); +} + +/** + * xmlSchemaCheckCOSSTDerivedOK: + * @actxt: a context + * @type: the derived simple type definition + * @baseType: the base type definition + * @subset: the subset of ('restriction', ect.) + * + * Schema Component Constraint: + * Type Derivation OK (Simple) (cos-st-derived-OK) + * + * Checks wheter @type can be validly + * derived from @baseType. + * + * Returns 0 on success, an positive error code otherwise. + */ +static int +xmlSchemaCheckCOSSTDerivedOK(xmlSchemaAbstractCtxtPtr actxt, + xmlSchemaTypePtr type, + xmlSchemaTypePtr baseType, + int subset) +{ + /* + * 1 They are the same type definition. + * TODO: The identy check might have to be more complex than this. + */ + if (type == baseType) + return (0); + /* + * 2.1 restriction is not in the subset, or in the {final} + * of its own {base type definition}; + * + * NOTE that this will be used also via "xsi:type". + * + * TODO: Revise this, it looks strange. How can the "type" + * not be fixed or *in* fixing? + */ + if (WXS_IS_TYPE_NOT_FIXED(type)) + if (xmlSchemaTypeFixup(type, actxt) == -1) + return(-1); + if (WXS_IS_TYPE_NOT_FIXED(baseType)) + if (xmlSchemaTypeFixup(baseType, actxt) == -1) + return(-1); + if ((subset & SUBSET_RESTRICTION) || + (xmlSchemaTypeFinalContains(type->baseType, + XML_SCHEMAS_TYPE_FINAL_RESTRICTION))) { + return (XML_SCHEMAP_COS_ST_DERIVED_OK_2_1); + } + /* 2.2 */ + if (type->baseType == baseType) { + /* + * 2.2.1 D's �base type definition� is B. + */ + return (0); + } + /* + * 2.2.2 D's �base type definition� is not the �ur-type definition� + * and is validly derived from B given the subset, as defined by this + * constraint. + */ + if ((! WXS_IS_ANYTYPE(type->baseType)) && + (xmlSchemaCheckCOSSTDerivedOK(actxt, type->baseType, + baseType, subset) == 0)) { + return (0); + } + /* + * 2.2.3 D's {variety} is list or union and B is the �simple ur-type + * definition�. + */ + if (WXS_IS_ANY_SIMPLE_TYPE(baseType) && + (WXS_IS_LIST(type) || WXS_IS_UNION(type))) { + return (0); + } + /* + * 2.2.4 B's {variety} is union and D is validly derived from a type + * definition in B's {member type definitions} given the subset, as + * defined by this constraint. + * + * NOTE: This seems not to involve built-in types, since there is no + * built-in Union Simple Type. + */ + if (WXS_IS_UNION(baseType)) { + xmlSchemaTypeLinkPtr cur; + + cur = baseType->memberTypes; + while (cur != NULL) { + if (WXS_IS_TYPE_NOT_FIXED(cur->type)) + if (xmlSchemaTypeFixup(cur->type, actxt) == -1) + return(-1); + if (xmlSchemaCheckCOSSTDerivedOK(actxt, + type, cur->type, subset) == 0) + { + /* + * It just has to be validly derived from at least one + * member-type. + */ + return (0); + } + cur = cur->next; + } + } + return (XML_SCHEMAP_COS_ST_DERIVED_OK_2_2); +} + +/** + * xmlSchemaCheckTypeDefCircularInternal: + * @pctxt: the schema parser context + * @ctxtType: the type definition + * @ancestor: an ancestor of @ctxtType + * + * Checks st-props-correct (2) + ct-props-correct (3). + * Circular type definitions are not allowed. + * + * Returns XML_SCHEMAP_ST_PROPS_CORRECT_2 if the given type is + * circular, 0 otherwise. + */ +static int +xmlSchemaCheckTypeDefCircularInternal(xmlSchemaParserCtxtPtr pctxt, + xmlSchemaTypePtr ctxtType, + xmlSchemaTypePtr ancestor) +{ + int ret; + + if ((ancestor == NULL) || (ancestor->type == XML_SCHEMA_TYPE_BASIC)) + return (0); + + if (ctxtType == ancestor) { + xmlSchemaPCustomErr(pctxt, + XML_SCHEMAP_ST_PROPS_CORRECT_2, + WXS_BASIC_CAST ctxtType, WXS_ITEM_NODE(ctxtType), + "The definition is circular", NULL); + return (XML_SCHEMAP_ST_PROPS_CORRECT_2); + } + if (ancestor->flags & XML_SCHEMAS_TYPE_MARKED) { + /* + * Avoid inifinite recursion on circular types not yet checked. + */ + return (0); + } + ancestor->flags |= XML_SCHEMAS_TYPE_MARKED; + ret = xmlSchemaCheckTypeDefCircularInternal(pctxt, ctxtType, + ancestor->baseType); + ancestor->flags ^= XML_SCHEMAS_TYPE_MARKED; + return (ret); +} + +/** + * xmlSchemaCheckTypeDefCircular: + * @item: the complex/simple type definition + * @ctxt: the parser context + * @name: the name + * + * Checks for circular type definitions. + */ +static void +xmlSchemaCheckTypeDefCircular(xmlSchemaTypePtr item, + xmlSchemaParserCtxtPtr ctxt) +{ + if ((item == NULL) || + (item->type == XML_SCHEMA_TYPE_BASIC) || + (item->baseType == NULL)) + return; + xmlSchemaCheckTypeDefCircularInternal(ctxt, item, + item->baseType); +} + +/* +* Simple Type Definition Representation OK (src-simple-type) 4 +* +* "4 Circular union type definition is disallowed. That is, if the +* alternative is chosen, there must not be any entries in the +* memberTypes [attribute] at any depth which resolve to the component +* corresponding to the ." +* +* Note that this should work on the *representation* of a component, +* thus assumes any union types in the member types not being yet +* substituted. At this stage we need the variety of the types +* to be already computed. +*/ +static int +xmlSchemaCheckUnionTypeDefCircularRecur(xmlSchemaParserCtxtPtr pctxt, + xmlSchemaTypePtr ctxType, + xmlSchemaTypeLinkPtr members) +{ + xmlSchemaTypeLinkPtr member; + xmlSchemaTypePtr memberType; + + member = members; + while (member != NULL) { + memberType = member->type; + while ((memberType != NULL) && + (memberType->type != XML_SCHEMA_TYPE_BASIC)) { + if (memberType == ctxType) { + xmlSchemaPCustomErr(pctxt, + XML_SCHEMAP_SRC_SIMPLE_TYPE_4, + WXS_BASIC_CAST ctxType, NULL, + "The union type definition is circular", NULL); + return (XML_SCHEMAP_SRC_SIMPLE_TYPE_4); + } + if ((WXS_IS_UNION(memberType)) && + ((memberType->flags & XML_SCHEMAS_TYPE_MARKED) == 0)) + { + int res; + memberType->flags |= XML_SCHEMAS_TYPE_MARKED; + res = xmlSchemaCheckUnionTypeDefCircularRecur(pctxt, + ctxType, + xmlSchemaGetUnionSimpleTypeMemberTypes(memberType)); + memberType->flags ^= XML_SCHEMAS_TYPE_MARKED; + if (res != 0) + return(res); + } + memberType = memberType->baseType; + } + member = member->next; + } + return(0); +} + +static int +xmlSchemaCheckUnionTypeDefCircular(xmlSchemaParserCtxtPtr pctxt, + xmlSchemaTypePtr type) +{ + if (! WXS_IS_UNION(type)) + return(0); + return(xmlSchemaCheckUnionTypeDefCircularRecur(pctxt, type, + type->memberTypes)); +} + +/** + * xmlSchemaResolveTypeReferences: + * @item: the complex/simple type definition + * @ctxt: the parser context + * @name: the name + * + * Resolvese type definition references + */ +static void +xmlSchemaResolveTypeReferences(xmlSchemaTypePtr typeDef, + xmlSchemaParserCtxtPtr ctxt) +{ + if (typeDef == NULL) + return; + + /* + * Resolve the base type. + */ + if (typeDef->baseType == NULL) { + typeDef->baseType = xmlSchemaGetType(ctxt->schema, + typeDef->base, typeDef->baseNs); + if (typeDef->baseType == NULL) { + xmlSchemaPResCompAttrErr(ctxt, + XML_SCHEMAP_SRC_RESOLVE, + WXS_BASIC_CAST typeDef, typeDef->node, + "base", typeDef->base, typeDef->baseNs, + XML_SCHEMA_TYPE_SIMPLE, NULL); + return; + } + } + if (WXS_IS_SIMPLE(typeDef)) { + if (WXS_IS_UNION(typeDef)) { + /* + * Resolve the memberTypes. + */ + xmlSchemaResolveUnionMemberTypes(ctxt, typeDef); + return; + } else if (WXS_IS_LIST(typeDef)) { + /* + * Resolve the itemType. + */ + if ((typeDef->subtypes == NULL) && (typeDef->base != NULL)) { + + typeDef->subtypes = xmlSchemaGetType(ctxt->schema, + typeDef->base, typeDef->baseNs); + + if ((typeDef->subtypes == NULL) || + (! WXS_IS_SIMPLE(typeDef->subtypes))) + { + typeDef->subtypes = NULL; + xmlSchemaPResCompAttrErr(ctxt, + XML_SCHEMAP_SRC_RESOLVE, + WXS_BASIC_CAST typeDef, typeDef->node, + "itemType", typeDef->base, typeDef->baseNs, + XML_SCHEMA_TYPE_SIMPLE, NULL); + } + } + return; + } + } + /* + * The ball of letters below means, that if we have a particle + * which has a QName-helper component as its {term}, we want + * to resolve it... + */ + else if ((WXS_TYPE_CONTENTTYPE(typeDef) != NULL) && + ((WXS_TYPE_CONTENTTYPE(typeDef))->type == + XML_SCHEMA_TYPE_PARTICLE) && + (WXS_TYPE_PARTICLE_TERM(typeDef) != NULL) && + ((WXS_TYPE_PARTICLE_TERM(typeDef))->type == + XML_SCHEMA_EXTRA_QNAMEREF)) + { + xmlSchemaQNameRefPtr ref = + WXS_QNAME_CAST WXS_TYPE_PARTICLE_TERM(typeDef); + xmlSchemaModelGroupDefPtr groupDef; + + /* + * URGENT TODO: Test this. + */ + WXS_TYPE_PARTICLE_TERM(typeDef) = NULL; + /* + * Resolve the MG definition reference. + */ + groupDef = + WXS_MODEL_GROUPDEF_CAST xmlSchemaGetNamedComponent(ctxt->schema, + ref->itemType, ref->name, ref->targetNamespace); + if (groupDef == NULL) { + xmlSchemaPResCompAttrErr(ctxt, XML_SCHEMAP_SRC_RESOLVE, + NULL, WXS_ITEM_NODE(WXS_TYPE_PARTICLE(typeDef)), + "ref", ref->name, ref->targetNamespace, ref->itemType, + NULL); + /* Remove the particle. */ + WXS_TYPE_CONTENTTYPE(typeDef) = NULL; + } else if (WXS_MODELGROUPDEF_MODEL(groupDef) == NULL) + /* Remove the particle. */ + WXS_TYPE_CONTENTTYPE(typeDef) = NULL; + else { + /* + * Assign the MG definition's {model group} to the + * particle's {term}. + */ + WXS_TYPE_PARTICLE_TERM(typeDef) = WXS_MODELGROUPDEF_MODEL(groupDef); + + if (WXS_MODELGROUPDEF_MODEL(groupDef)->type == XML_SCHEMA_TYPE_ALL) { + /* + * SPEC cos-all-limited (1.2) + * "1.2 the {term} property of a particle with + * {max occurs}=1 which is part of a pair which constitutes + * the {content type} of a complex type definition." + */ + if ((WXS_TYPE_PARTICLE(typeDef))->maxOccurs != 1) { + xmlSchemaCustomErr(ACTXT_CAST ctxt, + /* TODO: error code */ + XML_SCHEMAP_COS_ALL_LIMITED, + WXS_ITEM_NODE(WXS_TYPE_PARTICLE(typeDef)), NULL, + "The particle's {max occurs} must be 1, since the " + "reference resolves to an 'all' model group", + NULL, NULL); + } + } + } + } +} + + + +/** + * xmlSchemaCheckSTPropsCorrect: + * @ctxt: the schema parser context + * @type: the simple type definition + * + * Checks st-props-correct. + * + * Returns 0 if the properties are correct, + * if not, a positive error code and -1 on internal + * errors. + */ +static int +xmlSchemaCheckSTPropsCorrect(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaTypePtr type) +{ + xmlSchemaTypePtr baseType = type->baseType; + xmlChar *str = NULL; + + /* STATE: error funcs converted. */ + /* + * Schema Component Constraint: Simple Type Definition Properties Correct + * + * NOTE: This is somehow redundant, since we actually built a simple type + * to have all the needed information; this acts as an self test. + */ + /* Base type: If the datatype has been �derived� by �restriction� + * then the Simple Type Definition component from which it is �derived�, + * otherwise the Simple Type Definition for anySimpleType (�4.1.6). + */ + if (baseType == NULL) { + /* + * TODO: Think about: "modulo the impact of Missing + * Sub-components (�5.3)." + */ + xmlSchemaPCustomErr(ctxt, + XML_SCHEMAP_ST_PROPS_CORRECT_1, + WXS_BASIC_CAST type, NULL, + "No base type existent", NULL); + return (XML_SCHEMAP_ST_PROPS_CORRECT_1); + + } + if (! WXS_IS_SIMPLE(baseType)) { + xmlSchemaPCustomErr(ctxt, + XML_SCHEMAP_ST_PROPS_CORRECT_1, + WXS_BASIC_CAST type, NULL, + "The base type '%s' is not a simple type", + xmlSchemaGetComponentQName(&str, baseType)); + FREE_AND_NULL(str) + return (XML_SCHEMAP_ST_PROPS_CORRECT_1); + } + if ((WXS_IS_LIST(type) || WXS_IS_UNION(type)) && + (WXS_IS_RESTRICTION(type) == 0) && + ((! WXS_IS_ANY_SIMPLE_TYPE(baseType)) && + (baseType->type != XML_SCHEMA_TYPE_SIMPLE))) { + xmlSchemaPCustomErr(ctxt, + XML_SCHEMAP_ST_PROPS_CORRECT_1, + WXS_BASIC_CAST type, NULL, + "A type, derived by list or union, must have " + "the simple ur-type definition as base type, not '%s'", + xmlSchemaGetComponentQName(&str, baseType)); + FREE_AND_NULL(str) + return (XML_SCHEMAP_ST_PROPS_CORRECT_1); + } + /* + * Variety: One of {atomic, list, union}. + */ + if ((! WXS_IS_ATOMIC(type)) && (! WXS_IS_UNION(type)) && + (! WXS_IS_LIST(type))) { + xmlSchemaPCustomErr(ctxt, + XML_SCHEMAP_ST_PROPS_CORRECT_1, + WXS_BASIC_CAST type, NULL, + "The variety is absent", NULL); + return (XML_SCHEMAP_ST_PROPS_CORRECT_1); + } + /* TODO: Finish this. Hmm, is this finished? */ + + /* + * 3 The {final} of the {base type definition} must not contain restriction. + */ + if (xmlSchemaTypeFinalContains(baseType, + XML_SCHEMAS_TYPE_FINAL_RESTRICTION)) { + xmlSchemaPCustomErr(ctxt, + XML_SCHEMAP_ST_PROPS_CORRECT_3, + WXS_BASIC_CAST type, NULL, + "The 'final' of its base type '%s' must not contain " + "'restriction'", + xmlSchemaGetComponentQName(&str, baseType)); + FREE_AND_NULL(str) + return (XML_SCHEMAP_ST_PROPS_CORRECT_3); + } + + /* + * 2 All simple type definitions must be derived ultimately from the �simple + * ur-type definition (so� circular definitions are disallowed). That is, it + * must be possible to reach a built-in primitive datatype or the �simple + * ur-type definition� by repeatedly following the {base type definition}. + * + * NOTE: this is done in xmlSchemaCheckTypeDefCircular(). + */ + return (0); +} + +/** + * xmlSchemaCheckCOSSTRestricts: + * @ctxt: the schema parser context + * @type: the simple type definition + * + * Schema Component Constraint: + * Derivation Valid (Restriction, Simple) (cos-st-restricts) + + * Checks if the given @type (simpleType) is derived validly by restriction. + * STATUS: + * + * Returns -1 on internal errors, 0 if the type is validly derived, + * a positive error code otherwise. + */ +static int +xmlSchemaCheckCOSSTRestricts(xmlSchemaParserCtxtPtr pctxt, + xmlSchemaTypePtr type) +{ + xmlChar *str = NULL; + + if (type->type != XML_SCHEMA_TYPE_SIMPLE) { + PERROR_INT("xmlSchemaCheckCOSSTRestricts", + "given type is not a user-derived simpleType"); + return (-1); + } + + if (WXS_IS_ATOMIC(type)) { + xmlSchemaTypePtr primitive; + /* + * 1.1 The {base type definition} must be an atomic simple + * type definition or a built-in primitive datatype. + */ + if (! WXS_IS_ATOMIC(type->baseType)) { + xmlSchemaPCustomErr(pctxt, + XML_SCHEMAP_COS_ST_RESTRICTS_1_1, + WXS_BASIC_CAST type, NULL, + "The base type '%s' is not an atomic simple type", + xmlSchemaGetComponentQName(&str, type->baseType)); + FREE_AND_NULL(str) + return (XML_SCHEMAP_COS_ST_RESTRICTS_1_1); + } + /* 1.2 The {final} of the {base type definition} must not contain + * restriction. + */ + /* OPTIMIZE TODO : This is already done in xmlSchemaCheckStPropsCorrect */ + if (xmlSchemaTypeFinalContains(type->baseType, + XML_SCHEMAS_TYPE_FINAL_RESTRICTION)) { + xmlSchemaPCustomErr(pctxt, + XML_SCHEMAP_COS_ST_RESTRICTS_1_2, + WXS_BASIC_CAST type, NULL, + "The final of its base type '%s' must not contain 'restriction'", + xmlSchemaGetComponentQName(&str, type->baseType)); + FREE_AND_NULL(str) + return (XML_SCHEMAP_COS_ST_RESTRICTS_1_2); + } + + /* + * 1.3.1 DF must be an allowed constraining facet for the {primitive + * type definition}, as specified in the appropriate subsection of 3.2 + * Primitive datatypes. + */ + if (type->facets != NULL) { + xmlSchemaFacetPtr facet; + int ok = 1; + + primitive = xmlSchemaGetPrimitiveType(type); + if (primitive == NULL) { + PERROR_INT("xmlSchemaCheckCOSSTRestricts", + "failed to get primitive type"); + return (-1); + } + facet = type->facets; + do { + if (xmlSchemaIsBuiltInTypeFacet(primitive, facet->type) == 0) { + ok = 0; + xmlSchemaPIllegalFacetAtomicErr(pctxt, + XML_SCHEMAP_COS_ST_RESTRICTS_1_3_1, + type, primitive, facet); + } + facet = facet->next; + } while (facet != NULL); + if (ok == 0) + return (XML_SCHEMAP_COS_ST_RESTRICTS_1_3_1); + } + /* + * SPEC (1.3.2) "If there is a facet of the same kind in the {facets} + * of the {base type definition} (call this BF),then the DF's {value} + * must be a valid restriction of BF's {value} as defined in + * [XML Schemas: Datatypes]." + * + * NOTE (1.3.2) Facet derivation constraints are currently handled in + * xmlSchemaDeriveAndValidateFacets() + */ + } else if (WXS_IS_LIST(type)) { + xmlSchemaTypePtr itemType = NULL; + + itemType = type->subtypes; + if ((itemType == NULL) || (! WXS_IS_SIMPLE(itemType))) { + PERROR_INT("xmlSchemaCheckCOSSTRestricts", + "failed to evaluate the item type"); + return (-1); + } + if (WXS_IS_TYPE_NOT_FIXED(itemType)) + xmlSchemaTypeFixup(itemType, ACTXT_CAST pctxt); + /* + * 2.1 The {item type definition} must have a {variety} of atomic or + * union (in which case all the {member type definitions} + * must be atomic). + */ + if ((! WXS_IS_ATOMIC(itemType)) && + (! WXS_IS_UNION(itemType))) { + xmlSchemaPCustomErr(pctxt, + XML_SCHEMAP_COS_ST_RESTRICTS_2_1, + WXS_BASIC_CAST type, NULL, + "The item type '%s' does not have a variety of atomic or union", + xmlSchemaGetComponentQName(&str, itemType)); + FREE_AND_NULL(str) + return (XML_SCHEMAP_COS_ST_RESTRICTS_2_1); + } else if (WXS_IS_UNION(itemType)) { + xmlSchemaTypeLinkPtr member; + + member = itemType->memberTypes; + while (member != NULL) { + if (! WXS_IS_ATOMIC(member->type)) { + xmlSchemaPCustomErr(pctxt, + XML_SCHEMAP_COS_ST_RESTRICTS_2_1, + WXS_BASIC_CAST type, NULL, + "The item type is a union type, but the " + "member type '%s' of this item type is not atomic", + xmlSchemaGetComponentQName(&str, member->type)); + FREE_AND_NULL(str) + return (XML_SCHEMAP_COS_ST_RESTRICTS_2_1); + } + member = member->next; + } + } + + if (WXS_IS_ANY_SIMPLE_TYPE(type->baseType)) { + xmlSchemaFacetPtr facet; + /* + * This is the case if we have: facets != NULL) { + facet = type->facets; + do { + if (facet->type != XML_SCHEMA_FACET_WHITESPACE) { + xmlSchemaPIllegalFacetListUnionErr(pctxt, + XML_SCHEMAP_COS_ST_RESTRICTS_2_3_1_2, + type, facet); + return (XML_SCHEMAP_COS_ST_RESTRICTS_2_3_1_2); + } + facet = facet->next; + } while (facet != NULL); + } + /* + * MAYBE TODO: (Hmm, not really) Datatypes states: + * A �list� datatype can be �derived� from an �atomic� datatype + * whose �lexical space� allows space (such as string or anyURI)or + * a �union� datatype any of whose {member type definitions}'s + * �lexical space� allows space. + */ + } else { + /* + * This is the case if we have: baseType)) { + xmlSchemaPCustomErr(pctxt, + XML_SCHEMAP_COS_ST_RESTRICTS_2_3_2_1, + WXS_BASIC_CAST type, NULL, + "The base type '%s' must be a list type", + xmlSchemaGetComponentQName(&str, type->baseType)); + FREE_AND_NULL(str) + return (XML_SCHEMAP_COS_ST_RESTRICTS_2_3_2_1); + } + /* + * 2.3.2.2 The {final} of the {base type definition} must not + * contain restriction. + */ + if (xmlSchemaTypeFinalContains(type->baseType, + XML_SCHEMAS_TYPE_FINAL_RESTRICTION)) { + xmlSchemaPCustomErr(pctxt, + XML_SCHEMAP_COS_ST_RESTRICTS_2_3_2_2, + WXS_BASIC_CAST type, NULL, + "The 'final' of the base type '%s' must not contain 'restriction'", + xmlSchemaGetComponentQName(&str, type->baseType)); + FREE_AND_NULL(str) + return (XML_SCHEMAP_COS_ST_RESTRICTS_2_3_2_2); + } + /* + * 2.3.2.3 The {item type definition} must be validly derived + * from the {base type definition}'s {item type definition} given + * the empty set, as defined in Type Derivation OK (Simple) (�3.14.6). + */ + { + xmlSchemaTypePtr baseItemType; + + baseItemType = type->baseType->subtypes; + if ((baseItemType == NULL) || (! WXS_IS_SIMPLE(baseItemType))) { + PERROR_INT("xmlSchemaCheckCOSSTRestricts", + "failed to eval the item type of a base type"); + return (-1); + } + if ((itemType != baseItemType) && + (xmlSchemaCheckCOSSTDerivedOK(ACTXT_CAST pctxt, itemType, + baseItemType, 0) != 0)) { + xmlChar *strBIT = NULL, *strBT = NULL; + xmlSchemaPCustomErrExt(pctxt, + XML_SCHEMAP_COS_ST_RESTRICTS_2_3_2_3, + WXS_BASIC_CAST type, NULL, + "The item type '%s' is not validly derived from " + "the item type '%s' of the base type '%s'", + xmlSchemaGetComponentQName(&str, itemType), + xmlSchemaGetComponentQName(&strBIT, baseItemType), + xmlSchemaGetComponentQName(&strBT, type->baseType)); + + FREE_AND_NULL(str) + FREE_AND_NULL(strBIT) + FREE_AND_NULL(strBT) + return (XML_SCHEMAP_COS_ST_RESTRICTS_2_3_2_3); + } + } + + if (type->facets != NULL) { + xmlSchemaFacetPtr facet; + int ok = 1; + /* + * 2.3.2.4 Only length, minLength, maxLength, whiteSpace, pattern + * and enumeration facet components are allowed among the {facets}. + */ + facet = type->facets; + do { + switch (facet->type) { + case XML_SCHEMA_FACET_LENGTH: + case XML_SCHEMA_FACET_MINLENGTH: + case XML_SCHEMA_FACET_MAXLENGTH: + case XML_SCHEMA_FACET_WHITESPACE: + /* + * TODO: 2.5.1.2 List datatypes + * The value of �whiteSpace� is fixed to the value collapse. + */ + case XML_SCHEMA_FACET_PATTERN: + case XML_SCHEMA_FACET_ENUMERATION: + break; + default: { + xmlSchemaPIllegalFacetListUnionErr(pctxt, + XML_SCHEMAP_COS_ST_RESTRICTS_2_3_2_4, + type, facet); + /* + * We could return, but it's nicer to report all + * invalid facets. + */ + ok = 0; + } + } + facet = facet->next; + } while (facet != NULL); + if (ok == 0) + return (XML_SCHEMAP_COS_ST_RESTRICTS_2_3_2_4); + /* + * SPEC (2.3.2.5) (same as 1.3.2) + * + * NOTE (2.3.2.5) This is currently done in + * xmlSchemaDeriveAndValidateFacets() + */ + } + } + } else if (WXS_IS_UNION(type)) { + /* + * 3.1 The {member type definitions} must all have {variety} of + * atomic or list. + */ + xmlSchemaTypeLinkPtr member; + + member = type->memberTypes; + while (member != NULL) { + if (WXS_IS_TYPE_NOT_FIXED(member->type)) + xmlSchemaTypeFixup(member->type, ACTXT_CAST pctxt); + + if ((! WXS_IS_ATOMIC(member->type)) && + (! WXS_IS_LIST(member->type))) { + xmlSchemaPCustomErr(pctxt, + XML_SCHEMAP_COS_ST_RESTRICTS_3_1, + WXS_BASIC_CAST type, NULL, + "The member type '%s' is neither an atomic, nor a list type", + xmlSchemaGetComponentQName(&str, member->type)); + FREE_AND_NULL(str) + return (XML_SCHEMAP_COS_ST_RESTRICTS_3_1); + } + member = member->next; + } + /* + * 3.3.1 If the {base type definition} is the �simple ur-type + * definition� + */ + if (type->baseType->builtInType == XML_SCHEMAS_ANYSIMPLETYPE) { + /* + * 3.3.1.1 All of the {member type definitions} must have a + * {final} which does not contain union. + */ + member = type->memberTypes; + while (member != NULL) { + if (xmlSchemaTypeFinalContains(member->type, + XML_SCHEMAS_TYPE_FINAL_UNION)) { + xmlSchemaPCustomErr(pctxt, + XML_SCHEMAP_COS_ST_RESTRICTS_3_3_1, + WXS_BASIC_CAST type, NULL, + "The 'final' of member type '%s' contains 'union'", + xmlSchemaGetComponentQName(&str, member->type)); + FREE_AND_NULL(str) + return (XML_SCHEMAP_COS_ST_RESTRICTS_3_3_1); + } + member = member->next; + } + /* + * 3.3.1.2 The {facets} must be empty. + */ + if (type->facetSet != NULL) { + xmlSchemaPCustomErr(pctxt, + XML_SCHEMAP_COS_ST_RESTRICTS_3_3_1_2, + WXS_BASIC_CAST type, NULL, + "No facets allowed", NULL); + return (XML_SCHEMAP_COS_ST_RESTRICTS_3_3_1_2); + } + } else { + /* + * 3.3.2.1 The {base type definition} must have a {variety} of union. + * I.e. the variety of "list" is inherited. + */ + if (! WXS_IS_UNION(type->baseType)) { + xmlSchemaPCustomErr(pctxt, + XML_SCHEMAP_COS_ST_RESTRICTS_3_3_2_1, + WXS_BASIC_CAST type, NULL, + "The base type '%s' is not a union type", + xmlSchemaGetComponentQName(&str, type->baseType)); + FREE_AND_NULL(str) + return (XML_SCHEMAP_COS_ST_RESTRICTS_3_3_2_1); + } + /* + * 3.3.2.2 The {final} of the {base type definition} must not contain restriction. + */ + if (xmlSchemaTypeFinalContains(type->baseType, + XML_SCHEMAS_TYPE_FINAL_RESTRICTION)) { + xmlSchemaPCustomErr(pctxt, + XML_SCHEMAP_COS_ST_RESTRICTS_3_3_2_2, + WXS_BASIC_CAST type, NULL, + "The 'final' of its base type '%s' must not contain 'restriction'", + xmlSchemaGetComponentQName(&str, type->baseType)); + FREE_AND_NULL(str) + return (XML_SCHEMAP_COS_ST_RESTRICTS_3_3_2_2); + } + /* + * 3.3.2.3 The {member type definitions}, in order, must be validly + * derived from the corresponding type definitions in the {base + * type definition}'s {member type definitions} given the empty set, + * as defined in Type Derivation OK (Simple) (�3.14.6). + */ + { + xmlSchemaTypeLinkPtr baseMember; + + /* + * OPTIMIZE: if the type is restricting, it has no local defined + * member types and inherits the member types of the base type; + * thus a check for equality can be skipped. + */ + /* + * Even worse: I cannot see a scenario where a restricting + * union simple type can have other member types as the member + * types of it's base type. This check seems not necessary with + * respect to the derivation process in libxml2. + * But necessary if constructing types with an API. + */ + if (type->memberTypes != NULL) { + member = type->memberTypes; + baseMember = xmlSchemaGetUnionSimpleTypeMemberTypes(type->baseType); + if ((member == NULL) && (baseMember != NULL)) { + PERROR_INT("xmlSchemaCheckCOSSTRestricts", + "different number of member types in base"); + } + while (member != NULL) { + if (baseMember == NULL) { + PERROR_INT("xmlSchemaCheckCOSSTRestricts", + "different number of member types in base"); + } else if ((member->type != baseMember->type) && + (xmlSchemaCheckCOSSTDerivedOK(ACTXT_CAST pctxt, + member->type, baseMember->type, 0) != 0)) { + xmlChar *strBMT = NULL, *strBT = NULL; + + xmlSchemaPCustomErrExt(pctxt, + XML_SCHEMAP_COS_ST_RESTRICTS_3_3_2_3, + WXS_BASIC_CAST type, NULL, + "The member type %s is not validly " + "derived from its corresponding member " + "type %s of the base type %s", + xmlSchemaGetComponentQName(&str, member->type), + xmlSchemaGetComponentQName(&strBMT, baseMember->type), + xmlSchemaGetComponentQName(&strBT, type->baseType)); + FREE_AND_NULL(str) + FREE_AND_NULL(strBMT) + FREE_AND_NULL(strBT) + return (XML_SCHEMAP_COS_ST_RESTRICTS_3_3_2_3); + } + member = member->next; + if (baseMember != NULL) + baseMember = baseMember->next; + } + } + } + /* + * 3.3.2.4 Only pattern and enumeration facet components are + * allowed among the {facets}. + */ + if (type->facets != NULL) { + xmlSchemaFacetPtr facet; + int ok = 1; + + facet = type->facets; + do { + if ((facet->type != XML_SCHEMA_FACET_PATTERN) && + (facet->type != XML_SCHEMA_FACET_ENUMERATION)) { + xmlSchemaPIllegalFacetListUnionErr(pctxt, + XML_SCHEMAP_COS_ST_RESTRICTS_3_3_2_4, + type, facet); + ok = 0; + } + facet = facet->next; + } while (facet != NULL); + if (ok == 0) + return (XML_SCHEMAP_COS_ST_RESTRICTS_3_3_2_4); + + } + /* + * SPEC (3.3.2.5) (same as 1.3.2) + * + * NOTE (3.3.2.5) This is currently done in + * xmlSchemaDeriveAndValidateFacets() + */ + } + } + + return (0); +} + +/** + * xmlSchemaCheckSRCSimpleType: + * @ctxt: the schema parser context + * @type: the simple type definition + * + * Checks crc-simple-type constraints. + * + * Returns 0 if the constraints are satisfied, + * if not a positive error code and -1 on internal + * errors. + */ +#if 0 +static int +xmlSchemaCheckSRCSimpleType(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaTypePtr type) +{ + /* + * src-simple-type.1 The corresponding simple type definition, if any, + * must satisfy the conditions set out in Constraints on Simple Type + * Definition Schema Components (�3.14.6). + */ + if (WXS_IS_RESTRICTION(type)) { + /* + * src-simple-type.2 "If the alternative is chosen, + * either it must have a base [attribute] or a among its + * [children], but not both." + * NOTE: This is checked in the parse function of . + */ + /* + * + */ + } else if (WXS_IS_LIST(type)) { + /* src-simple-type.3 "If the alternative is chosen, either it must have + * an itemType [attribute] or a among its [children], + * but not both." + * + * NOTE: This is checked in the parse function of . + */ + } else if (WXS_IS_UNION(type)) { + /* + * src-simple-type.4 is checked in xmlSchemaCheckUnionTypeDefCircular(). + */ + } + return (0); +} +#endif + +static int +xmlSchemaCreateVCtxtOnPCtxt(xmlSchemaParserCtxtPtr ctxt) +{ + if (ctxt->vctxt == NULL) { + ctxt->vctxt = xmlSchemaNewValidCtxt(NULL); + if (ctxt->vctxt == NULL) { + xmlSchemaPErr(ctxt, NULL, + XML_SCHEMAP_INTERNAL, + "Internal error: xmlSchemaCreateVCtxtOnPCtxt, " + "failed to create a temp. validation context.\n", + NULL, NULL); + return (-1); + } + /* TODO: Pass user data. */ + xmlSchemaSetValidErrors(ctxt->vctxt, + ctxt->error, ctxt->warning, ctxt->errCtxt); + xmlSchemaSetValidStructuredErrors(ctxt->vctxt, + ctxt->serror, ctxt->errCtxt); + } + return (0); +} + +static int +xmlSchemaVCheckCVCSimpleType(xmlSchemaAbstractCtxtPtr actxt, + xmlNodePtr node, + xmlSchemaTypePtr type, + const xmlChar *value, + xmlSchemaValPtr *retVal, + int fireErrors, + int normalize, + int isNormalized); + +/** + * xmlSchemaParseCheckCOSValidDefault: + * @pctxt: the schema parser context + * @type: the simple type definition + * @value: the default value + * @node: an optional node (the holder of the value) + * + * Schema Component Constraint: Element Default Valid (Immediate) + * (cos-valid-default) + * This will be used by the parser only. For the validator there's + * an other version. + * + * Returns 0 if the constraints are satisfied, + * if not, a positive error code and -1 on internal + * errors. + */ +static int +xmlSchemaParseCheckCOSValidDefault(xmlSchemaParserCtxtPtr pctxt, + xmlNodePtr node, + xmlSchemaTypePtr type, + const xmlChar *value, + xmlSchemaValPtr *val) +{ + int ret = 0; + + /* + * cos-valid-default: + * Schema Component Constraint: Element Default Valid (Immediate) + * For a string to be a valid default with respect to a type + * definition the appropriate case among the following must be true: + */ + if WXS_IS_COMPLEX(type) { + /* + * Complex type. + * + * SPEC (2.1) "its {content type} must be a simple type definition + * or mixed." + * SPEC (2.2.2) "If the {content type} is mixed, then the {content + * type}'s particle must be �emptiable� as defined by + * Particle Emptiable (�3.9.6)." + */ + if ((! WXS_HAS_SIMPLE_CONTENT(type)) && + ((! WXS_HAS_MIXED_CONTENT(type)) || (! WXS_EMPTIABLE(type)))) { + /* NOTE that this covers (2.2.2) as well. */ + xmlSchemaPCustomErr(pctxt, + XML_SCHEMAP_COS_VALID_DEFAULT_2_1, + WXS_BASIC_CAST type, type->node, + "For a string to be a valid default, the type definition " + "must be a simple type or a complex type with mixed content " + "and a particle emptiable", NULL); + return(XML_SCHEMAP_COS_VALID_DEFAULT_2_1); + } + } + /* + * 1 If the type definition is a simple type definition, then the string + * must be �valid� with respect to that definition as defined by String + * Valid (�3.14.4). + * + * AND + * + * 2.2.1 If the {content type} is a simple type definition, then the + * string must be �valid� with respect to that simple type definition + * as defined by String Valid (�3.14.4). + */ + if (WXS_IS_SIMPLE(type)) + ret = xmlSchemaVCheckCVCSimpleType(ACTXT_CAST pctxt, node, + type, value, val, 1, 1, 0); + else if (WXS_HAS_SIMPLE_CONTENT(type)) + ret = xmlSchemaVCheckCVCSimpleType(ACTXT_CAST pctxt, node, + type->contentTypeDef, value, val, 1, 1, 0); + else + return (ret); + + if (ret < 0) { + PERROR_INT("xmlSchemaParseCheckCOSValidDefault", + "calling xmlSchemaVCheckCVCSimpleType()"); + } + + return (ret); +} + +/** + * xmlSchemaCheckCTPropsCorrect: + * @ctxt: the schema parser context + * @type: the complex type definition + * + *.(4.6) Constraints on Complex Type Definition Schema Components + * Schema Component Constraint: + * Complex Type Definition Properties Correct (ct-props-correct) + * STATUS: (seems) complete + * + * Returns 0 if the constraints are satisfied, a positive + * error code if not and -1 if an internal error occured. + */ +static int +xmlSchemaCheckCTPropsCorrect(xmlSchemaParserCtxtPtr pctxt, + xmlSchemaTypePtr type) +{ + /* + * TODO: Correct the error code; XML_SCHEMAP_SRC_CT_1 is used temporarily. + * + * SPEC (1) "The values of the properties of a complex type definition must + * be as described in the property tableau in The Complex Type Definition + * Schema Component (�3.4.1), modulo the impact of Missing + * Sub-components (�5.3)." + */ + if ((type->baseType != NULL) && + (WXS_IS_SIMPLE(type->baseType)) && + (WXS_IS_EXTENSION(type) == 0)) { + /* + * SPEC (2) "If the {base type definition} is a simple type definition, + * the {derivation method} must be extension." + */ + xmlSchemaCustomErr(ACTXT_CAST pctxt, + XML_SCHEMAP_SRC_CT_1, + NULL, WXS_BASIC_CAST type, + "If the base type is a simple type, the derivation method must be " + "'extension'", NULL, NULL); + return (XML_SCHEMAP_SRC_CT_1); + } + /* + * SPEC (3) "Circular definitions are disallowed, except for the �ur-type + * definition�. That is, it must be possible to reach the �ur-type + * definition by repeatedly following the {base type definition}." + * + * NOTE (3) is done in xmlSchemaCheckTypeDefCircular(). + */ + /* + * NOTE that (4) and (5) need the following: + * - attribute uses need to be already inherited (apply attr. prohibitions) + * - attribute group references need to be expanded already + * - simple types need to be typefixed already + */ + if (type->attrUses && + (((xmlSchemaItemListPtr) type->attrUses)->nbItems > 1)) + { + xmlSchemaItemListPtr uses = (xmlSchemaItemListPtr) type->attrUses; + xmlSchemaAttributeUsePtr use, tmp; + int i, j, hasId = 0; + + for (i = uses->nbItems -1; i >= 0; i--) { + use = uses->items[i]; + + /* + * SPEC ct-props-correct + * (4) "Two distinct attribute declarations in the + * {attribute uses} must not have identical {name}s and + * {target namespace}s." + */ + if (i > 0) { + for (j = i -1; j >= 0; j--) { + tmp = uses->items[j]; + if ((WXS_ATTRUSE_DECL_NAME(use) == + WXS_ATTRUSE_DECL_NAME(tmp)) && + (WXS_ATTRUSE_DECL_TNS(use) == + WXS_ATTRUSE_DECL_TNS(tmp))) + { + xmlChar *str = NULL; + + xmlSchemaCustomErr(ACTXT_CAST pctxt, + XML_SCHEMAP_AG_PROPS_CORRECT, + NULL, WXS_BASIC_CAST type, + "Duplicate %s", + xmlSchemaGetComponentDesignation(&str, use), + NULL); + FREE_AND_NULL(str); + /* + * Remove the duplicate. + */ + if (xmlSchemaItemListRemove(uses, i) == -1) + goto exit_failure; + goto next_use; + } + } + } + /* + * SPEC ct-props-correct + * (5) "Two distinct attribute declarations in the + * {attribute uses} must not have {type definition}s which + * are or are derived from ID." + */ + if (WXS_ATTRUSE_TYPEDEF(use) != NULL) { + if (xmlSchemaIsDerivedFromBuiltInType( + WXS_ATTRUSE_TYPEDEF(use), XML_SCHEMAS_ID)) + { + if (hasId) { + xmlChar *str = NULL; + + xmlSchemaCustomErr(ACTXT_CAST pctxt, + XML_SCHEMAP_AG_PROPS_CORRECT, + NULL, WXS_BASIC_CAST type, + "There must not exist more than one attribute " + "declaration of type 'xs:ID' " + "(or derived from 'xs:ID'). The %s violates this " + "constraint", + xmlSchemaGetComponentDesignation(&str, use), + NULL); + FREE_AND_NULL(str); + if (xmlSchemaItemListRemove(uses, i) == -1) + goto exit_failure; + } + + hasId = 1; + } + } +next_use: {} + } + } + return (0); +exit_failure: + return(-1); +} + +static int +xmlSchemaAreEqualTypes(xmlSchemaTypePtr typeA, + xmlSchemaTypePtr typeB) +{ + /* + * TODO: This should implement component-identity + * in the future. + */ + if ((typeA == NULL) || (typeB == NULL)) + return (0); + return (typeA == typeB); +} + +/** + * xmlSchemaCheckCOSCTDerivedOK: + * @ctxt: the schema parser context + * @type: the to-be derived complex type definition + * @baseType: the base complex type definition + * @set: the given set + * + * Schema Component Constraint: + * Type Derivation OK (Complex) (cos-ct-derived-ok) + * + * STATUS: completed + * + * Returns 0 if the constraints are satisfied, or 1 + * if not. + */ +static int +xmlSchemaCheckCOSCTDerivedOK(xmlSchemaAbstractCtxtPtr actxt, + xmlSchemaTypePtr type, + xmlSchemaTypePtr baseType, + int set) +{ + int equal = xmlSchemaAreEqualTypes(type, baseType); + /* TODO: Error codes. */ + /* + * SPEC "For a complex type definition (call it D, for derived) + * to be validly derived from a type definition (call this + * B, for base) given a subset of {extension, restriction} + * all of the following must be true:" + */ + if (! equal) { + /* + * SPEC (1) "If B and D are not the same type definition, then the + * {derivation method} of D must not be in the subset." + */ + if (((set & SUBSET_EXTENSION) && (WXS_IS_EXTENSION(type))) || + ((set & SUBSET_RESTRICTION) && (WXS_IS_RESTRICTION(type)))) + return (1); + } else { + /* + * SPEC (2.1) "B and D must be the same type definition." + */ + return (0); + } + /* + * SPEC (2.2) "B must be D's {base type definition}." + */ + if (type->baseType == baseType) + return (0); + /* + * SPEC (2.3.1) "D's {base type definition} must not be the �ur-type + * definition�." + */ + if (WXS_IS_ANYTYPE(type->baseType)) + return (1); + + if (WXS_IS_COMPLEX(type->baseType)) { + /* + * SPEC (2.3.2.1) "If D's {base type definition} is complex, then it + * must be validly derived from B given the subset as defined by this + * constraint." + */ + return (xmlSchemaCheckCOSCTDerivedOK(actxt, type->baseType, + baseType, set)); + } else { + /* + * SPEC (2.3.2.2) "If D's {base type definition} is simple, then it + * must be validly derived from B given the subset as defined in Type + * Derivation OK (Simple) (�3.14.6). + */ + return (xmlSchemaCheckCOSSTDerivedOK(actxt, type->baseType, + baseType, set)); + } +} + +/** + * xmlSchemaCheckCOSDerivedOK: + * @type: the derived simple type definition + * @baseType: the base type definition + * + * Calls: + * Type Derivation OK (Simple) AND Type Derivation OK (Complex) + * + * Checks wheter @type can be validly derived from @baseType. + * + * Returns 0 on success, an positive error code otherwise. + */ +static int +xmlSchemaCheckCOSDerivedOK(xmlSchemaAbstractCtxtPtr actxt, + xmlSchemaTypePtr type, + xmlSchemaTypePtr baseType, + int set) +{ + if (WXS_IS_SIMPLE(type)) + return (xmlSchemaCheckCOSSTDerivedOK(actxt, type, baseType, set)); + else + return (xmlSchemaCheckCOSCTDerivedOK(actxt, type, baseType, set)); +} + +/** + * xmlSchemaCheckCOSCTExtends: + * @ctxt: the schema parser context + * @type: the complex type definition + * + * (3.4.6) Constraints on Complex Type Definition Schema Components + * Schema Component Constraint: + * Derivation Valid (Extension) (cos-ct-extends) + * + * STATUS: + * missing: + * (1.5) + * (1.4.3.2.2.2) "Particle Valid (Extension)" + * + * Returns 0 if the constraints are satisfied, a positive + * error code if not and -1 if an internal error occured. + */ +static int +xmlSchemaCheckCOSCTExtends(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaTypePtr type) +{ + xmlSchemaTypePtr base = type->baseType; + /* + * TODO: Correct the error code; XML_SCHEMAP_COS_CT_EXTENDS_1_1 is used + * temporarily only. + */ + /* + * SPEC (1) "If the {base type definition} is a complex type definition, + * then all of the following must be true:" + */ + if (WXS_IS_COMPLEX(base)) { + /* + * SPEC (1.1) "The {final} of the {base type definition} must not + * contain extension." + */ + if (base->flags & XML_SCHEMAS_TYPE_FINAL_EXTENSION) { + xmlSchemaPCustomErr(ctxt, + XML_SCHEMAP_COS_CT_EXTENDS_1_1, + WXS_BASIC_CAST type, NULL, + "The 'final' of the base type definition " + "contains 'extension'", NULL); + return (XML_SCHEMAP_COS_CT_EXTENDS_1_1); + } + + /* + * ATTENTION: The constrains (1.2) and (1.3) are not applied, + * since they are automatically satisfied through the + * inheriting mechanism. + * Note that even if redefining components, the inheriting mechanism + * is used. + */ +#if 0 + /* + * SPEC (1.2) "Its {attribute uses} must be a subset of the {attribute + * uses} + * of the complex type definition itself, that is, for every attribute + * use in the {attribute uses} of the {base type definition}, there + * must be an attribute use in the {attribute uses} of the complex + * type definition itself whose {attribute declaration} has the same + * {name}, {target namespace} and {type definition} as its attribute + * declaration" + */ + if (base->attrUses != NULL) { + int i, j, found; + xmlSchemaAttributeUsePtr use, buse; + + for (i = 0; i < (WXS_LIST_CAST base->attrUses)->nbItems; i ++) { + buse = (WXS_LIST_CAST base->attrUses)->items[i]; + found = 0; + if (type->attrUses != NULL) { + use = (WXS_LIST_CAST type->attrUses)->items[j]; + for (j = 0; j < (WXS_LIST_CAST type->attrUses)->nbItems; j ++) + { + if ((WXS_ATTRUSE_DECL_NAME(use) == + WXS_ATTRUSE_DECL_NAME(buse)) && + (WXS_ATTRUSE_DECL_TNS(use) == + WXS_ATTRUSE_DECL_TNS(buse)) && + (WXS_ATTRUSE_TYPEDEF(use) == + WXS_ATTRUSE_TYPEDEF(buse)) + { + found = 1; + break; + } + } + } + if (! found) { + xmlChar *str = NULL; + + xmlSchemaCustomErr(ACTXT_CAST ctxt, + XML_SCHEMAP_COS_CT_EXTENDS_1_2, + NULL, WXS_BASIC_CAST type, + /* + * TODO: The report does not indicate that also the + * type needs to be the same. + */ + "This type is missing a matching correspondent " + "for its {base type}'s %s in its {attribute uses}", + xmlSchemaGetComponentDesignation(&str, + buse->children), + NULL); + FREE_AND_NULL(str) + } + } + } + /* + * SPEC (1.3) "If it has an {attribute wildcard}, the complex type + * definition must also have one, and the base type definition's + * {attribute wildcard}'s {namespace constraint} must be a subset + * of the complex type definition's {attribute wildcard}'s {namespace + * constraint}, as defined by Wildcard Subset (�3.10.6)." + */ + + /* + * MAYBE TODO: Enable if ever needed. But this will be needed only + * if created the type via a schema construction API. + */ + if (base->attributeWildcard != NULL) { + if (type->attributeWilcard == NULL) { + xmlChar *str = NULL; + + xmlSchemaCustomErr(ACTXT_CAST pctxt, + XML_SCHEMAP_COS_CT_EXTENDS_1_3, + NULL, type, + "The base %s has an attribute wildcard, " + "but this type is missing an attribute wildcard", + xmlSchemaGetComponentDesignation(&str, base)); + FREE_AND_NULL(str) + + } else if (xmlSchemaCheckCOSNSSubset( + base->attributeWildcard, type->attributeWildcard)) + { + xmlChar *str = NULL; + + xmlSchemaCustomErr(ACTXT_CAST pctxt, + XML_SCHEMAP_COS_CT_EXTENDS_1_3, + NULL, type, + "The attribute wildcard is not a valid " + "superset of the one in the base %s", + xmlSchemaGetComponentDesignation(&str, base)); + FREE_AND_NULL(str) + } + } +#endif + /* + * SPEC (1.4) "One of the following must be true:" + */ + if ((type->contentTypeDef != NULL) && + (type->contentTypeDef == base->contentTypeDef)) { + /* + * SPEC (1.4.1) "The {content type} of the {base type definition} + * and the {content type} of the complex type definition itself + * must be the same simple type definition" + * PASS + */ + } else if ((type->contentType == XML_SCHEMA_CONTENT_EMPTY) && + (base->contentType == XML_SCHEMA_CONTENT_EMPTY) ) { + /* + * SPEC (1.4.2) "The {content type} of both the {base type + * definition} and the complex type definition itself must + * be empty." + * PASS + */ + } else { + /* + * SPEC (1.4.3) "All of the following must be true:" + */ + if (type->subtypes == NULL) { + /* + * SPEC 1.4.3.1 The {content type} of the complex type + * definition itself must specify a particle. + */ + xmlSchemaPCustomErr(ctxt, + XML_SCHEMAP_COS_CT_EXTENDS_1_1, + WXS_BASIC_CAST type, NULL, + "The content type must specify a particle", NULL); + return (XML_SCHEMAP_COS_CT_EXTENDS_1_1); + } + /* + * SPEC (1.4.3.2) "One of the following must be true:" + */ + if (base->contentType == XML_SCHEMA_CONTENT_EMPTY) { + /* + * SPEC (1.4.3.2.1) "The {content type} of the {base type + * definition} must be empty. + * PASS + */ + } else { + /* + * SPEC (1.4.3.2.2) "All of the following must be true:" + */ + if ((type->contentType != base->contentType) || + ((type->contentType != XML_SCHEMA_CONTENT_MIXED) && + (type->contentType != XML_SCHEMA_CONTENT_ELEMENTS))) { + /* + * SPEC (1.4.3.2.2.1) "Both {content type}s must be mixed + * or both must be element-only." + */ + xmlSchemaPCustomErr(ctxt, + XML_SCHEMAP_COS_CT_EXTENDS_1_1, + WXS_BASIC_CAST type, NULL, + "The content type of both, the type and its base " + "type, must either 'mixed' or 'element-only'", NULL); + return (XML_SCHEMAP_COS_CT_EXTENDS_1_1); + } + /* + * URGENT TODO SPEC (1.4.3.2.2.2) "The particle of the + * complex type definition must be a �valid extension� + * of the {base type definition}'s particle, as defined + * in Particle Valid (Extension) (�3.9.6)." + * + * NOTE that we won't check "Particle Valid (Extension)", + * since it is ensured by the derivation process in + * xmlSchemaTypeFixup(). We need to implement this when heading + * for a construction API + * TODO: !! This is needed to be checked if redefining a type !! + */ + } + /* + * URGENT TODO (1.5) + */ + } + } else { + /* + * SPEC (2) "If the {base type definition} is a simple type definition, + * then all of the following must be true:" + */ + if (type->contentTypeDef != base) { + /* + * SPEC (2.1) "The {content type} must be the same simple type + * definition." + */ + xmlSchemaPCustomErr(ctxt, + XML_SCHEMAP_COS_CT_EXTENDS_1_1, + WXS_BASIC_CAST type, NULL, + "The content type must be the simple base type", NULL); + return (XML_SCHEMAP_COS_CT_EXTENDS_1_1); + } + if (base->flags & XML_SCHEMAS_TYPE_FINAL_EXTENSION) { + /* + * SPEC (2.2) "The {final} of the {base type definition} must not + * contain extension" + * NOTE that this is the same as (1.1). + */ + xmlSchemaPCustomErr(ctxt, + XML_SCHEMAP_COS_CT_EXTENDS_1_1, + WXS_BASIC_CAST type, NULL, + "The 'final' of the base type definition " + "contains 'extension'", NULL); + return (XML_SCHEMAP_COS_CT_EXTENDS_1_1); + } + } + return (0); +} + +/** + * xmlSchemaCheckDerivationOKRestriction: + * @ctxt: the schema parser context + * @type: the complex type definition + * + * (3.4.6) Constraints on Complex Type Definition Schema Components + * Schema Component Constraint: + * Derivation Valid (Restriction, Complex) (derivation-ok-restriction) + * + * STATUS: + * missing: + * (5.4.2) ??? + * + * ATTENTION: + * In XML Schema 1.1 this will be: + * Validation Rule: Checking complex type subsumption + * + * Returns 0 if the constraints are satisfied, a positive + * error code if not and -1 if an internal error occured. + */ +static int +xmlSchemaCheckDerivationOKRestriction(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaTypePtr type) +{ + xmlSchemaTypePtr base; + + /* + * TODO: Correct the error code; XML_SCHEMAP_DERIVATION_OK_RESTRICTION_1 is used + * temporarily only. + */ + base = type->baseType; + if (! WXS_IS_COMPLEX(base)) { + xmlSchemaCustomErr(ACTXT_CAST ctxt, + XML_SCHEMAP_DERIVATION_OK_RESTRICTION_1, + type->node, WXS_BASIC_CAST type, + "The base type must be a complex type", NULL, NULL); + return(ctxt->err); + } + if (base->flags & XML_SCHEMAS_TYPE_FINAL_RESTRICTION) { + /* + * SPEC (1) "The {base type definition} must be a complex type + * definition whose {final} does not contain restriction." + */ + xmlSchemaCustomErr(ACTXT_CAST ctxt, + XML_SCHEMAP_DERIVATION_OK_RESTRICTION_1, + type->node, WXS_BASIC_CAST type, + "The 'final' of the base type definition " + "contains 'restriction'", NULL, NULL); + return (ctxt->err); + } + /* + * SPEC (2), (3) and (4) + * Those are handled in a separate function, since the + * same constraints are needed for redefinition of + * attribute groups as well. + */ + if (xmlSchemaCheckDerivationOKRestriction2to4(ctxt, + XML_SCHEMA_ACTION_DERIVE, + WXS_BASIC_CAST type, WXS_BASIC_CAST base, + type->attrUses, base->attrUses, + type->attributeWildcard, + base->attributeWildcard) == -1) + { + return(-1); + } + /* + * SPEC (5) "One of the following must be true:" + */ + if (base->builtInType == XML_SCHEMAS_ANYTYPE) { + /* + * SPEC (5.1) "The {base type definition} must be the + * �ur-type definition�." + * PASS + */ + } else if ((type->contentType == XML_SCHEMA_CONTENT_SIMPLE) || + (type->contentType == XML_SCHEMA_CONTENT_BASIC)) { + /* + * SPEC (5.2.1) "The {content type} of the complex type definition + * must be a simple type definition" + * + * SPEC (5.2.2) "One of the following must be true:" + */ + if ((base->contentType == XML_SCHEMA_CONTENT_SIMPLE) || + (base->contentType == XML_SCHEMA_CONTENT_BASIC)) + { + int err; + /* + * SPEC (5.2.2.1) "The {content type} of the {base type + * definition} must be a simple type definition from which + * the {content type} is validly derived given the empty + * set as defined in Type Derivation OK (Simple) (�3.14.6)." + * + * ATTENTION TODO: This seems not needed if the type implicitely + * derived from the base type. + * + */ + err = xmlSchemaCheckCOSSTDerivedOK(ACTXT_CAST ctxt, + type->contentTypeDef, base->contentTypeDef, 0); + if (err != 0) { + xmlChar *strA = NULL, *strB = NULL; + + if (err == -1) + return(-1); + xmlSchemaCustomErr(ACTXT_CAST ctxt, + XML_SCHEMAP_DERIVATION_OK_RESTRICTION_1, + NULL, WXS_BASIC_CAST type, + "The {content type} %s is not validly derived from the " + "base type's {content type} %s", + xmlSchemaGetComponentDesignation(&strA, + type->contentTypeDef), + xmlSchemaGetComponentDesignation(&strB, + base->contentTypeDef)); + FREE_AND_NULL(strA); + FREE_AND_NULL(strB); + return(ctxt->err); + } + } else if ((base->contentType == XML_SCHEMA_CONTENT_MIXED) && + (xmlSchemaIsParticleEmptiable( + (xmlSchemaParticlePtr) base->subtypes))) { + /* + * SPEC (5.2.2.2) "The {base type definition} must be mixed + * and have a particle which is �emptiable� as defined in + * Particle Emptiable (�3.9.6)." + * PASS + */ + } else { + xmlSchemaPCustomErr(ctxt, + XML_SCHEMAP_DERIVATION_OK_RESTRICTION_1, + WXS_BASIC_CAST type, NULL, + "The content type of the base type must be either " + "a simple type or 'mixed' and an emptiable particle", NULL); + return (ctxt->err); + } + } else if (type->contentType == XML_SCHEMA_CONTENT_EMPTY) { + /* + * SPEC (5.3.1) "The {content type} of the complex type itself must + * be empty" + */ + if (base->contentType == XML_SCHEMA_CONTENT_EMPTY) { + /* + * SPEC (5.3.2.1) "The {content type} of the {base type + * definition} must also be empty." + * PASS + */ + } else if (((base->contentType == XML_SCHEMA_CONTENT_ELEMENTS) || + (base->contentType == XML_SCHEMA_CONTENT_MIXED)) && + xmlSchemaIsParticleEmptiable( + (xmlSchemaParticlePtr) base->subtypes)) { + /* + * SPEC (5.3.2.2) "The {content type} of the {base type + * definition} must be elementOnly or mixed and have a particle + * which is �emptiable� as defined in Particle Emptiable (�3.9.6)." + * PASS + */ + } else { + xmlSchemaPCustomErr(ctxt, + XML_SCHEMAP_DERIVATION_OK_RESTRICTION_1, + WXS_BASIC_CAST type, NULL, + "The content type of the base type must be either " + "empty or 'mixed' (or 'elements-only') and an emptiable " + "particle", NULL); + return (ctxt->err); + } + } else if ((type->contentType == XML_SCHEMA_CONTENT_ELEMENTS) || + WXS_HAS_MIXED_CONTENT(type)) { + /* + * SPEC (5.4.1.1) "The {content type} of the complex type definition + * itself must be element-only" + */ + if (WXS_HAS_MIXED_CONTENT(type) && (! WXS_HAS_MIXED_CONTENT(base))) { + /* + * SPEC (5.4.1.2) "The {content type} of the complex type + * definition itself and of the {base type definition} must be + * mixed" + */ + xmlSchemaPCustomErr(ctxt, + XML_SCHEMAP_DERIVATION_OK_RESTRICTION_1, + WXS_BASIC_CAST type, NULL, + "If the content type is 'mixed', then the content type of the " + "base type must also be 'mixed'", NULL); + return (ctxt->err); + } + /* + * SPEC (5.4.2) "The particle of the complex type definition itself + * must be a �valid restriction� of the particle of the {content + * type} of the {base type definition} as defined in Particle Valid + * (Restriction) (�3.9.6). + * + * URGENT TODO: (5.4.2) + */ + } else { + xmlSchemaPCustomErr(ctxt, + XML_SCHEMAP_DERIVATION_OK_RESTRICTION_1, + WXS_BASIC_CAST type, NULL, + "The type is not a valid restriction of its base type", NULL); + return (ctxt->err); + } + return (0); +} + +/** + * xmlSchemaCheckCTComponent: + * @ctxt: the schema parser context + * @type: the complex type definition + * + * (3.4.6) Constraints on Complex Type Definition Schema Components + * + * Returns 0 if the constraints are satisfied, a positive + * error code if not and -1 if an internal error occured. + */ +static int +xmlSchemaCheckCTComponent(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaTypePtr type) +{ + int ret; + /* + * Complex Type Definition Properties Correct + */ + ret = xmlSchemaCheckCTPropsCorrect(ctxt, type); + if (ret != 0) + return (ret); + if (WXS_IS_EXTENSION(type)) + ret = xmlSchemaCheckCOSCTExtends(ctxt, type); + else + ret = xmlSchemaCheckDerivationOKRestriction(ctxt, type); + return (ret); +} + +/** + * xmlSchemaCheckSRCCT: + * @ctxt: the schema parser context + * @type: the complex type definition + * + * (3.4.3) Constraints on XML Representations of Complex Type Definitions: + * Schema Representation Constraint: + * Complex Type Definition Representation OK (src-ct) + * + * Returns 0 if the constraints are satisfied, a positive + * error code if not and -1 if an internal error occured. + */ +static int +xmlSchemaCheckSRCCT(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaTypePtr type) +{ + xmlSchemaTypePtr base; + int ret = 0; + + /* + * TODO: Adjust the error codes here, as I used + * XML_SCHEMAP_SRC_CT_1 only yet. + */ + base = type->baseType; + if (! WXS_HAS_SIMPLE_CONTENT(type)) { + /* + * 1 If the alternative is chosen, the type definition + * �resolved� to by the �actual value� of the base [attribute] + * must be a complex type definition; + */ + if (! WXS_IS_COMPLEX(base)) { + xmlChar *str = NULL; + xmlSchemaPCustomErr(ctxt, + XML_SCHEMAP_SRC_CT_1, + WXS_BASIC_CAST type, type->node, + "If using , the base type is expected to be " + "a complex type. The base type '%s' is a simple type", + xmlSchemaFormatQName(&str, base->targetNamespace, + base->name)); + FREE_AND_NULL(str) + return (XML_SCHEMAP_SRC_CT_1); + } + } else { + /* + * SPEC + * 2 If the alternative is chosen, all of the + * following must be true: + * 2.1 The type definition �resolved� to by the �actual value� of the + * base [attribute] must be one of the following: + */ + if (WXS_IS_SIMPLE(base)) { + if (WXS_IS_EXTENSION(type) == 0) { + xmlChar *str = NULL; + /* + * 2.1.3 only if the alternative is also + * chosen, a simple type definition. + */ + /* TODO: Change error code to ..._SRC_CT_2_1_3. */ + xmlSchemaPCustomErr(ctxt, + XML_SCHEMAP_SRC_CT_1, + WXS_BASIC_CAST type, NULL, + "If using and , the base " + "type must be a complex type. The base type '%s' is " + "a simple type", + xmlSchemaFormatQName(&str, base->targetNamespace, + base->name)); + FREE_AND_NULL(str) + return (XML_SCHEMAP_SRC_CT_1); + } + } else { + /* Base type is a complex type. */ + if ((base->contentType == XML_SCHEMA_CONTENT_SIMPLE) || + (base->contentType == XML_SCHEMA_CONTENT_BASIC)) { + /* + * 2.1.1 a complex type definition whose {content type} is a + * simple type definition; + * PASS + */ + if (base->contentTypeDef == NULL) { + xmlSchemaPCustomErr(ctxt, XML_SCHEMAP_INTERNAL, + WXS_BASIC_CAST type, NULL, + "Internal error: xmlSchemaCheckSRCCT, " + "'%s', base type has no content type", + type->name); + return (-1); + } + } else if ((base->contentType == XML_SCHEMA_CONTENT_MIXED) && + (WXS_IS_RESTRICTION(type))) { + + /* + * 2.1.2 only if the alternative is also + * chosen, a complex type definition whose {content type} + * is mixed and a particle emptiable. + */ + if (! xmlSchemaIsParticleEmptiable( + (xmlSchemaParticlePtr) base->subtypes)) { + ret = XML_SCHEMAP_SRC_CT_1; + } else + /* + * Attention: at this point the child is in + * ->contentTypeDef (put there during parsing). + */ + if (type->contentTypeDef == NULL) { + xmlChar *str = NULL; + /* + * 2.2 If clause 2.1.2 above is satisfied, then there + * must be a among the [children] of + * . + */ + /* TODO: Change error code to ..._SRC_CT_2_2. */ + xmlSchemaPCustomErr(ctxt, + XML_SCHEMAP_SRC_CT_1, + WXS_BASIC_CAST type, NULL, + "A is expected among the children " + "of , if is used and " + "the base type '%s' is a complex type", + xmlSchemaFormatQName(&str, base->targetNamespace, + base->name)); + FREE_AND_NULL(str) + return (XML_SCHEMAP_SRC_CT_1); + } + } else { + ret = XML_SCHEMAP_SRC_CT_1; + } + } + if (ret > 0) { + xmlChar *str = NULL; + if (WXS_IS_RESTRICTION(type)) { + xmlSchemaPCustomErr(ctxt, + XML_SCHEMAP_SRC_CT_1, + WXS_BASIC_CAST type, NULL, + "If and is used, the " + "base type must be a simple type or a complex type with " + "mixed content and particle emptiable. The base type " + "'%s' is none of those", + xmlSchemaFormatQName(&str, base->targetNamespace, + base->name)); + } else { + xmlSchemaPCustomErr(ctxt, + XML_SCHEMAP_SRC_CT_1, + WXS_BASIC_CAST type, NULL, + "If and is used, the " + "base type must be a simple type. The base type '%s' " + "is a complex type", + xmlSchemaFormatQName(&str, base->targetNamespace, + base->name)); + } + FREE_AND_NULL(str) + } + } + /* + * SPEC (3) "The corresponding complex type definition component must + * satisfy the conditions set out in Constraints on Complex Type + * Definition Schema Components (�3.4.6);" + * NOTE (3) will be done in xmlSchemaTypeFixup(). + */ + /* + * SPEC (4) If clause 2.2.1 or clause 2.2.2 in the correspondence specification + * above for {attribute wildcard} is satisfied, the intensional + * intersection must be expressible, as defined in Attribute Wildcard + * Intersection (�3.10.6). + * NOTE (4) is done in xmlSchemaFixupTypeAttributeUses(). + */ + return (ret); +} + +#ifdef ENABLE_PARTICLE_RESTRICTION +/** + * xmlSchemaCheckParticleRangeOK: + * @ctxt: the schema parser context + * @type: the complex type definition + * + * (3.9.6) Constraints on Particle Schema Components + * Schema Component Constraint: + * Occurrence Range OK (range-ok) + * + * STATUS: complete + * + * Returns 0 if the constraints are satisfied, a positive + * error code if not and -1 if an internal error occured. + */ +static int +xmlSchemaCheckParticleRangeOK(int rmin, int rmax, + int bmin, int bmax) +{ + if (rmin < bmin) + return (1); + if ((bmax != UNBOUNDED) && + (rmax > bmax)) + return (1); + return (0); +} + +/** + * xmlSchemaCheckRCaseNameAndTypeOK: + * @ctxt: the schema parser context + * @r: the restricting element declaration particle + * @b: the base element declaration particle + * + * (3.9.6) Constraints on Particle Schema Components + * Schema Component Constraint: + * Particle Restriction OK (Elt:Elt -- NameAndTypeOK) + * (rcase-NameAndTypeOK) + * + * STATUS: + * MISSING (3.2.3) + * CLARIFY: (3.2.2) + * + * Returns 0 if the constraints are satisfied, a positive + * error code if not and -1 if an internal error occured. + */ +static int +xmlSchemaCheckRCaseNameAndTypeOK(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaParticlePtr r, + xmlSchemaParticlePtr b) +{ + xmlSchemaElementPtr elemR, elemB; + + /* TODO: Error codes (rcase-NameAndTypeOK). */ + elemR = (xmlSchemaElementPtr) r->children; + elemB = (xmlSchemaElementPtr) b->children; + /* + * SPEC (1) "The declarations' {name}s and {target namespace}s are + * the same." + */ + if ((elemR != elemB) && + ((! xmlStrEqual(elemR->name, elemB->name)) || + (! xmlStrEqual(elemR->targetNamespace, elemB->targetNamespace)))) + return (1); + /* + * SPEC (2) "R's occurrence range is a valid restriction of B's + * occurrence range as defined by Occurrence Range OK (�3.9.6)." + */ + if (xmlSchemaCheckParticleRangeOK(r->minOccurs, r->maxOccurs, + b->minOccurs, b->maxOccurs) != 0) + return (1); + /* + * SPEC (3.1) "Both B's declaration's {scope} and R's declaration's + * {scope} are global." + */ + if (elemR == elemB) + return (0); + /* + * SPEC (3.2.1) "Either B's {nillable} is true or R's {nillable} is false." + */ + if (((elemB->flags & XML_SCHEMAS_ELEM_NILLABLE) == 0) && + (elemR->flags & XML_SCHEMAS_ELEM_NILLABLE)) + return (1); + /* + * SPEC (3.2.2) "either B's declaration's {value constraint} is absent, + * or is not fixed, or R's declaration's {value constraint} is fixed + * with the same value." + */ + if ((elemB->value != NULL) && (elemB->flags & XML_SCHEMAS_ELEM_FIXED) && + ((elemR->value == NULL) || + ((elemR->flags & XML_SCHEMAS_ELEM_FIXED) == 0) || + /* TODO: Equality of the initial value or normalized or canonical? */ + (! xmlStrEqual(elemR->value, elemB->value)))) + return (1); + /* + * TODO: SPEC (3.2.3) "R's declaration's {identity-constraint + * definitions} is a subset of B's declaration's {identity-constraint + * definitions}, if any." + */ + if (elemB->idcs != NULL) { + /* TODO */ + } + /* + * SPEC (3.2.4) "R's declaration's {disallowed substitutions} is a + * superset of B's declaration's {disallowed substitutions}." + */ + if (((elemB->flags & XML_SCHEMAS_ELEM_BLOCK_EXTENSION) && + ((elemR->flags & XML_SCHEMAS_ELEM_BLOCK_EXTENSION) == 0)) || + ((elemB->flags & XML_SCHEMAS_ELEM_BLOCK_RESTRICTION) && + ((elemR->flags & XML_SCHEMAS_ELEM_BLOCK_RESTRICTION) == 0)) || + ((elemB->flags & XML_SCHEMAS_ELEM_BLOCK_SUBSTITUTION) && + ((elemR->flags & XML_SCHEMAS_ELEM_BLOCK_SUBSTITUTION) == 0))) + return (1); + /* + * SPEC (3.2.5) "R's {type definition} is validly derived given + * {extension, list, union} from B's {type definition}" + * + * BADSPEC TODO: What's the point of adding "list" and "union" to the + * set, if the corresponding constraints handle "restriction" and + * "extension" only? + * + */ + { + int set = 0; + + set |= SUBSET_EXTENSION; + set |= SUBSET_LIST; + set |= SUBSET_UNION; + if (xmlSchemaCheckCOSDerivedOK(ACTXT_CAST ctxt, elemR->subtypes, + elemB->subtypes, set) != 0) + return (1); + } + return (0); +} + +/** + * xmlSchemaCheckRCaseNSCompat: + * @ctxt: the schema parser context + * @r: the restricting element declaration particle + * @b: the base wildcard particle + * + * (3.9.6) Constraints on Particle Schema Components + * Schema Component Constraint: + * Particle Derivation OK (Elt:Any -- NSCompat) + * (rcase-NSCompat) + * + * STATUS: complete + * + * Returns 0 if the constraints are satisfied, a positive + * error code if not and -1 if an internal error occured. + */ +static int +xmlSchemaCheckRCaseNSCompat(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaParticlePtr r, + xmlSchemaParticlePtr b) +{ + /* TODO:Error codes (rcase-NSCompat). */ + /* + * SPEC "For an element declaration particle to be a �valid restriction� + * of a wildcard particle all of the following must be true:" + * + * SPEC (1) "The element declaration's {target namespace} is �valid� + * with respect to the wildcard's {namespace constraint} as defined by + * Wildcard allows Namespace Name (�3.10.4)." + */ + if (xmlSchemaCheckCVCWildcardNamespace((xmlSchemaWildcardPtr) b->children, + ((xmlSchemaElementPtr) r->children)->targetNamespace) != 0) + return (1); + /* + * SPEC (2) "R's occurrence range is a valid restriction of B's + * occurrence range as defined by Occurrence Range OK (�3.9.6)." + */ + if (xmlSchemaCheckParticleRangeOK(r->minOccurs, r->maxOccurs, + b->minOccurs, b->maxOccurs) != 0) + return (1); + + return (0); +} + +/** + * xmlSchemaCheckRCaseRecurseAsIfGroup: + * @ctxt: the schema parser context + * @r: the restricting element declaration particle + * @b: the base model group particle + * + * (3.9.6) Constraints on Particle Schema Components + * Schema Component Constraint: + * Particle Derivation OK (Elt:All/Choice/Sequence -- RecurseAsIfGroup) + * (rcase-RecurseAsIfGroup) + * + * STATUS: TODO + * + * Returns 0 if the constraints are satisfied, a positive + * error code if not and -1 if an internal error occured. + */ +static int +xmlSchemaCheckRCaseRecurseAsIfGroup(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaParticlePtr r, + xmlSchemaParticlePtr b) +{ + /* TODO: Error codes (rcase-RecurseAsIfGroup). */ + TODO + return (0); +} + +/** + * xmlSchemaCheckRCaseNSSubset: + * @ctxt: the schema parser context + * @r: the restricting wildcard particle + * @b: the base wildcard particle + * + * (3.9.6) Constraints on Particle Schema Components + * Schema Component Constraint: + * Particle Derivation OK (Any:Any -- NSSubset) + * (rcase-NSSubset) + * + * STATUS: complete + * + * Returns 0 if the constraints are satisfied, a positive + * error code if not and -1 if an internal error occured. + */ +static int +xmlSchemaCheckRCaseNSSubset(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaParticlePtr r, + xmlSchemaParticlePtr b, + int isAnyTypeBase) +{ + /* TODO: Error codes (rcase-NSSubset). */ + /* + * SPEC (1) "R's occurrence range is a valid restriction of B's + * occurrence range as defined by Occurrence Range OK (�3.9.6)." + */ + if (xmlSchemaCheckParticleRangeOK(r->minOccurs, r->maxOccurs, + b->minOccurs, b->maxOccurs)) + return (1); + /* + * SPEC (2) "R's {namespace constraint} must be an intensional subset + * of B's {namespace constraint} as defined by Wildcard Subset (�3.10.6)." + */ + if (xmlSchemaCheckCOSNSSubset((xmlSchemaWildcardPtr) r->children, + (xmlSchemaWildcardPtr) b->children)) + return (1); + /* + * SPEC (3) "Unless B is the content model wildcard of the �ur-type + * definition�, R's {process contents} must be identical to or stronger + * than B's {process contents}, where strict is stronger than lax is + * stronger than skip." + */ + if (! isAnyTypeBase) { + if ( ((xmlSchemaWildcardPtr) r->children)->processContents < + ((xmlSchemaWildcardPtr) b->children)->processContents) + return (1); + } + + return (0); +} + +/** + * xmlSchemaCheckCOSParticleRestrict: + * @ctxt: the schema parser context + * @type: the complex type definition + * + * (3.9.6) Constraints on Particle Schema Components + * Schema Component Constraint: + * Particle Valid (Restriction) (cos-particle-restrict) + * + * STATUS: TODO + * + * Returns 0 if the constraints are satisfied, a positive + * error code if not and -1 if an internal error occured. + */ +static int +xmlSchemaCheckCOSParticleRestrict(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaParticlePtr r, + xmlSchemaParticlePtr b) +{ + int ret = 0; + + /*part = WXS_TYPE_PARTICLE(type); + basePart = WXS_TYPE_PARTICLE(base); + */ + + TODO + + /* + * SPEC (1) "They are the same particle." + */ + if (r == b) + return (0); + + + return (0); +} + +#if 0 +/** + * xmlSchemaCheckRCaseNSRecurseCheckCardinality: + * @ctxt: the schema parser context + * @r: the model group particle + * @b: the base wildcard particle + * + * (3.9.6) Constraints on Particle Schema Components + * Schema Component Constraint: + * Particle Derivation OK (All/Choice/Sequence:Any -- + * NSRecurseCheckCardinality) + * (rcase-NSRecurseCheckCardinality) + * + * STATUS: TODO: subst-groups + * + * Returns 0 if the constraints are satisfied, a positive + * error code if not and -1 if an internal error occured. + */ +static int +xmlSchemaCheckRCaseNSRecurseCheckCardinality(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaParticlePtr r, + xmlSchemaParticlePtr b) +{ + xmlSchemaParticlePtr part; + /* TODO: Error codes (rcase-NSRecurseCheckCardinality). */ + if ((r->children == NULL) || (r->children->children == NULL)) + return (-1); + /* + * SPEC "For a group particle to be a �valid restriction� of a + * wildcard particle..." + * + * SPEC (1) "Every member of the {particles} of the group is a �valid + * restriction� of the wildcard as defined by + * Particle Valid (Restriction) (�3.9.6)." + */ + part = (xmlSchemaParticlePtr) r->children->children; + do { + if (xmlSchemaCheckCOSParticleRestrict(ctxt, part, b)) + return (1); + part = (xmlSchemaParticlePtr) part->next; + } while (part != NULL); + /* + * SPEC (2) "The effective total range of the group [...] is a + * valid restriction of B's occurrence range as defined by + * Occurrence Range OK (�3.9.6)." + */ + if (xmlSchemaCheckParticleRangeOK( + xmlSchemaGetParticleTotalRangeMin(r), + xmlSchemaGetParticleTotalRangeMax(r), + b->minOccurs, b->maxOccurs) != 0) + return (1); + return (0); +} +#endif + +/** + * xmlSchemaCheckRCaseRecurse: + * @ctxt: the schema parser context + * @r: the or model group particle + * @b: the base or model group particle + * + * (3.9.6) Constraints on Particle Schema Components + * Schema Component Constraint: + * Particle Derivation OK (All:All,Sequence:Sequence -- + Recurse) + * (rcase-Recurse) + * + * STATUS: ? + * TODO: subst-groups + * + * Returns 0 if the constraints are satisfied, a positive + * error code if not and -1 if an internal error occured. + */ +static int +xmlSchemaCheckRCaseRecurse(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaParticlePtr r, + xmlSchemaParticlePtr b) +{ + /* xmlSchemaParticlePtr part; */ + /* TODO: Error codes (rcase-Recurse). */ + if ((r->children == NULL) || (b->children == NULL) || + (r->children->type != b->children->type)) + return (-1); + /* + * SPEC "For an all or sequence group particle to be a �valid + * restriction� of another group particle with the same {compositor}..." + * + * SPEC (1) "R's occurrence range is a valid restriction of B's + * occurrence range as defined by Occurrence Range OK (�3.9.6)." + */ + if (xmlSchemaCheckParticleRangeOK(r->minOccurs, r->maxOccurs, + b->minOccurs, b->maxOccurs)) + return (1); + + + return (0); +} + +#endif + +#define FACET_RESTR_MUTUAL_ERR(fac1, fac2) \ + xmlSchemaPCustomErrExt(pctxt, \ + XML_SCHEMAP_INVALID_FACET_VALUE, \ + WXS_BASIC_CAST fac1, fac1->node, \ + "It is an error for both '%s' and '%s' to be specified on the "\ + "same type definition", \ + BAD_CAST xmlSchemaFacetTypeToString(fac1->type), \ + BAD_CAST xmlSchemaFacetTypeToString(fac2->type), NULL); + +#define FACET_RESTR_ERR(fac1, msg) \ + xmlSchemaPCustomErr(pctxt, \ + XML_SCHEMAP_INVALID_FACET_VALUE, \ + WXS_BASIC_CAST fac1, fac1->node, \ + msg, NULL); + +#define FACET_RESTR_FIXED_ERR(fac) \ + xmlSchemaPCustomErr(pctxt, \ + XML_SCHEMAP_INVALID_FACET_VALUE, \ + WXS_BASIC_CAST fac, fac->node, \ + "The base type's facet is 'fixed', thus the value must not " \ + "differ", NULL); + +static void +xmlSchemaDeriveFacetErr(xmlSchemaParserCtxtPtr pctxt, + xmlSchemaFacetPtr facet1, + xmlSchemaFacetPtr facet2, + int lessGreater, + int orEqual, + int ofBase) +{ + xmlChar *msg = NULL; + + msg = xmlStrdup(BAD_CAST "'"); + msg = xmlStrcat(msg, xmlSchemaFacetTypeToString(facet1->type)); + msg = xmlStrcat(msg, BAD_CAST "' has to be"); + if (lessGreater == 0) + msg = xmlStrcat(msg, BAD_CAST " equal to"); + if (lessGreater == 1) + msg = xmlStrcat(msg, BAD_CAST " greater than"); + else + msg = xmlStrcat(msg, BAD_CAST " less than"); + + if (orEqual) + msg = xmlStrcat(msg, BAD_CAST " or equal to"); + msg = xmlStrcat(msg, BAD_CAST " '"); + msg = xmlStrcat(msg, xmlSchemaFacetTypeToString(facet2->type)); + if (ofBase) + msg = xmlStrcat(msg, BAD_CAST "' of the base type"); + else + msg = xmlStrcat(msg, BAD_CAST "'"); + + xmlSchemaPCustomErr(pctxt, + XML_SCHEMAP_INVALID_FACET_VALUE, + WXS_BASIC_CAST facet1, NULL, + (const char *) msg, NULL); + + if (msg != NULL) + xmlFree(msg); +} + +/* +* xmlSchemaDeriveAndValidateFacets: +* +* Schema Component Constraint: Simple Type Restriction (Facets) +* (st-restrict-facets) +*/ +static int +xmlSchemaDeriveAndValidateFacets(xmlSchemaParserCtxtPtr pctxt, + xmlSchemaTypePtr type) +{ + xmlSchemaTypePtr base = type->baseType; + xmlSchemaFacetLinkPtr link, cur, last = NULL; + xmlSchemaFacetPtr facet, bfacet, + flength = NULL, ftotdig = NULL, ffracdig = NULL, + fmaxlen = NULL, fminlen = NULL, /* facets of the current type */ + fmininc = NULL, fmaxinc = NULL, + fminexc = NULL, fmaxexc = NULL, + bflength = NULL, bftotdig = NULL, bffracdig = NULL, + bfmaxlen = NULL, bfminlen = NULL, /* facets of the base type */ + bfmininc = NULL, bfmaxinc = NULL, + bfminexc = NULL, bfmaxexc = NULL; + int res; /* err = 0, fixedErr; */ + + /* + * SPEC st-restrict-facets 1: + * "The {variety} of R is the same as that of B." + */ + /* + * SPEC st-restrict-facets 2: + * "If {variety} is atomic, the {primitive type definition} + * of R is the same as that of B." + * + * NOTE: we leave 1 & 2 out for now, since this will be + * satisfied by the derivation process. + * CONSTRUCTION TODO: Maybe needed if using a construction API. + */ + /* + * SPEC st-restrict-facets 3: + * "The {facets} of R are the union of S and the {facets} + * of B, eliminating duplicates. To eliminate duplicates, + * when a facet of the same kind occurs in both S and the + * {facets} of B, the one in the {facets} of B is not + * included, with the exception of enumeration and pattern + * facets, for which multiple occurrences with distinct values + * are allowed." + */ + + if ((type->facetSet == NULL) && (base->facetSet == NULL)) + return (0); + + last = type->facetSet; + if (last != NULL) + while (last->next != NULL) + last = last->next; + + for (cur = type->facetSet; cur != NULL; cur = cur->next) { + facet = cur->facet; + switch (facet->type) { + case XML_SCHEMA_FACET_LENGTH: + flength = facet; break; + case XML_SCHEMA_FACET_MINLENGTH: + fminlen = facet; break; + case XML_SCHEMA_FACET_MININCLUSIVE: + fmininc = facet; break; + case XML_SCHEMA_FACET_MINEXCLUSIVE: + fminexc = facet; break; + case XML_SCHEMA_FACET_MAXLENGTH: + fmaxlen = facet; break; + case XML_SCHEMA_FACET_MAXINCLUSIVE: + fmaxinc = facet; break; + case XML_SCHEMA_FACET_MAXEXCLUSIVE: + fmaxexc = facet; break; + case XML_SCHEMA_FACET_TOTALDIGITS: + ftotdig = facet; break; + case XML_SCHEMA_FACET_FRACTIONDIGITS: + ffracdig = facet; break; + default: + break; + } + } + for (cur = base->facetSet; cur != NULL; cur = cur->next) { + facet = cur->facet; + switch (facet->type) { + case XML_SCHEMA_FACET_LENGTH: + bflength = facet; break; + case XML_SCHEMA_FACET_MINLENGTH: + bfminlen = facet; break; + case XML_SCHEMA_FACET_MININCLUSIVE: + bfmininc = facet; break; + case XML_SCHEMA_FACET_MINEXCLUSIVE: + bfminexc = facet; break; + case XML_SCHEMA_FACET_MAXLENGTH: + bfmaxlen = facet; break; + case XML_SCHEMA_FACET_MAXINCLUSIVE: + bfmaxinc = facet; break; + case XML_SCHEMA_FACET_MAXEXCLUSIVE: + bfmaxexc = facet; break; + case XML_SCHEMA_FACET_TOTALDIGITS: + bftotdig = facet; break; + case XML_SCHEMA_FACET_FRACTIONDIGITS: + bffracdig = facet; break; + default: + break; + } + } + /* + * length and minLength or maxLength (2.2) + (3.2) + */ + if (flength && (fminlen || fmaxlen)) { + FACET_RESTR_ERR(flength, "It is an error for both 'length' and " + "either of 'minLength' or 'maxLength' to be specified on " + "the same type definition") + } + /* + * Mutual exclusions in the same derivation step. + */ + if ((fmaxinc) && (fmaxexc)) { + /* + * SCC "maxInclusive and maxExclusive" + */ + FACET_RESTR_MUTUAL_ERR(fmaxinc, fmaxexc) + } + if ((fmininc) && (fminexc)) { + /* + * SCC "minInclusive and minExclusive" + */ + FACET_RESTR_MUTUAL_ERR(fmininc, fminexc) + } + + if (flength && bflength) { + /* + * SCC "length valid restriction" + * The values have to be equal. + */ + res = xmlSchemaCompareValues(flength->val, bflength->val); + if (res == -2) + goto internal_error; + if (res != 0) + xmlSchemaDeriveFacetErr(pctxt, flength, bflength, 0, 0, 1); + if ((res != 0) && (bflength->fixed)) { + FACET_RESTR_FIXED_ERR(flength) + } + + } + if (fminlen && bfminlen) { + /* + * SCC "minLength valid restriction" + * minLength >= BASE minLength + */ + res = xmlSchemaCompareValues(fminlen->val, bfminlen->val); + if (res == -2) + goto internal_error; + if (res == -1) + xmlSchemaDeriveFacetErr(pctxt, fminlen, bfminlen, 1, 1, 1); + if ((res != 0) && (bfminlen->fixed)) { + FACET_RESTR_FIXED_ERR(fminlen) + } + } + if (fmaxlen && bfmaxlen) { + /* + * SCC "maxLength valid restriction" + * maxLength <= BASE minLength + */ + res = xmlSchemaCompareValues(fmaxlen->val, bfmaxlen->val); + if (res == -2) + goto internal_error; + if (res == 1) + xmlSchemaDeriveFacetErr(pctxt, fmaxlen, bfmaxlen, -1, 1, 1); + if ((res != 0) && (bfmaxlen->fixed)) { + FACET_RESTR_FIXED_ERR(fmaxlen) + } + } + /* + * SCC "length and minLength or maxLength" + */ + if (! flength) + flength = bflength; + if (flength) { + if (! fminlen) + fminlen = bfminlen; + if (fminlen) { + /* (1.1) length >= minLength */ + res = xmlSchemaCompareValues(flength->val, fminlen->val); + if (res == -2) + goto internal_error; + if (res == -1) + xmlSchemaDeriveFacetErr(pctxt, flength, fminlen, 1, 1, 0); + } + if (! fmaxlen) + fmaxlen = bfmaxlen; + if (fmaxlen) { + /* (2.1) length <= maxLength */ + res = xmlSchemaCompareValues(flength->val, fmaxlen->val); + if (res == -2) + goto internal_error; + if (res == 1) + xmlSchemaDeriveFacetErr(pctxt, flength, fmaxlen, -1, 1, 0); + } + } + if (fmaxinc) { + /* + * "maxInclusive" + */ + if (fmininc) { + /* SCC "maxInclusive >= minInclusive" */ + res = xmlSchemaCompareValues(fmaxinc->val, fmininc->val); + if (res == -2) + goto internal_error; + if (res == -1) { + xmlSchemaDeriveFacetErr(pctxt, fmaxinc, fmininc, 1, 1, 0); + } + } + /* + * SCC "maxInclusive valid restriction" + */ + if (bfmaxinc) { + /* maxInclusive <= BASE maxInclusive */ + res = xmlSchemaCompareValues(fmaxinc->val, bfmaxinc->val); + if (res == -2) + goto internal_error; + if (res == 1) + xmlSchemaDeriveFacetErr(pctxt, fmaxinc, bfmaxinc, -1, 1, 1); + if ((res != 0) && (bfmaxinc->fixed)) { + FACET_RESTR_FIXED_ERR(fmaxinc) + } + } + if (bfmaxexc) { + /* maxInclusive < BASE maxExclusive */ + res = xmlSchemaCompareValues(fmaxinc->val, bfmaxexc->val); + if (res == -2) + goto internal_error; + if (res != -1) { + xmlSchemaDeriveFacetErr(pctxt, fmaxinc, bfmaxexc, -1, 0, 1); + } + } + if (bfmininc) { + /* maxInclusive >= BASE minInclusive */ + res = xmlSchemaCompareValues(fmaxinc->val, bfmininc->val); + if (res == -2) + goto internal_error; + if (res == -1) { + xmlSchemaDeriveFacetErr(pctxt, fmaxinc, bfmininc, 1, 1, 1); + } + } + if (bfminexc) { + /* maxInclusive > BASE minExclusive */ + res = xmlSchemaCompareValues(fmaxinc->val, bfminexc->val); + if (res == -2) + goto internal_error; + if (res != 1) { + xmlSchemaDeriveFacetErr(pctxt, fmaxinc, bfminexc, 1, 0, 1); + } + } + } + if (fmaxexc) { + /* + * "maxExclusive >= minExclusive" + */ + if (fminexc) { + res = xmlSchemaCompareValues(fmaxexc->val, fminexc->val); + if (res == -2) + goto internal_error; + if (res == -1) { + xmlSchemaDeriveFacetErr(pctxt, fmaxexc, fminexc, 1, 1, 0); + } + } + /* + * "maxExclusive valid restriction" + */ + if (bfmaxexc) { + /* maxExclusive <= BASE maxExclusive */ + res = xmlSchemaCompareValues(fmaxexc->val, bfmaxexc->val); + if (res == -2) + goto internal_error; + if (res == 1) { + xmlSchemaDeriveFacetErr(pctxt, fmaxexc, bfmaxexc, -1, 1, 1); + } + if ((res != 0) && (bfmaxexc->fixed)) { + FACET_RESTR_FIXED_ERR(fmaxexc) + } + } + if (bfmaxinc) { + /* maxExclusive <= BASE maxInclusive */ + res = xmlSchemaCompareValues(fmaxexc->val, bfmaxinc->val); + if (res == -2) + goto internal_error; + if (res == 1) { + xmlSchemaDeriveFacetErr(pctxt, fmaxexc, bfmaxinc, -1, 1, 1); + } + } + if (bfmininc) { + /* maxExclusive > BASE minInclusive */ + res = xmlSchemaCompareValues(fmaxexc->val, bfmininc->val); + if (res == -2) + goto internal_error; + if (res != 1) { + xmlSchemaDeriveFacetErr(pctxt, fmaxexc, bfmininc, 1, 0, 1); + } + } + if (bfminexc) { + /* maxExclusive > BASE minExclusive */ + res = xmlSchemaCompareValues(fmaxexc->val, bfminexc->val); + if (res == -2) + goto internal_error; + if (res != 1) { + xmlSchemaDeriveFacetErr(pctxt, fmaxexc, bfminexc, 1, 0, 1); + } + } + } + if (fminexc) { + /* + * "minExclusive < maxInclusive" + */ + if (fmaxinc) { + res = xmlSchemaCompareValues(fminexc->val, fmaxinc->val); + if (res == -2) + goto internal_error; + if (res != -1) { + xmlSchemaDeriveFacetErr(pctxt, fminexc, fmaxinc, -1, 0, 0); + } + } + /* + * "minExclusive valid restriction" + */ + if (bfminexc) { + /* minExclusive >= BASE minExclusive */ + res = xmlSchemaCompareValues(fminexc->val, bfminexc->val); + if (res == -2) + goto internal_error; + if (res == -1) { + xmlSchemaDeriveFacetErr(pctxt, fminexc, bfminexc, 1, 1, 1); + } + if ((res != 0) && (bfminexc->fixed)) { + FACET_RESTR_FIXED_ERR(fminexc) + } + } + if (bfmaxinc) { + /* minExclusive <= BASE maxInclusive */ + res = xmlSchemaCompareValues(fminexc->val, bfmaxinc->val); + if (res == -2) + goto internal_error; + if (res == 1) { + xmlSchemaDeriveFacetErr(pctxt, fminexc, bfmaxinc, -1, 1, 1); + } + } + if (bfmininc) { + /* minExclusive >= BASE minInclusive */ + res = xmlSchemaCompareValues(fminexc->val, bfmininc->val); + if (res == -2) + goto internal_error; + if (res == -1) { + xmlSchemaDeriveFacetErr(pctxt, fminexc, bfmininc, 1, 1, 1); + } + } + if (bfmaxexc) { + /* minExclusive < BASE maxExclusive */ + res = xmlSchemaCompareValues(fminexc->val, bfmaxexc->val); + if (res == -2) + goto internal_error; + if (res != -1) { + xmlSchemaDeriveFacetErr(pctxt, fminexc, bfmaxexc, -1, 0, 1); + } + } + } + if (fmininc) { + /* + * "minInclusive < maxExclusive" + */ + if (fmaxexc) { + res = xmlSchemaCompareValues(fmininc->val, fmaxexc->val); + if (res == -2) + goto internal_error; + if (res != -1) { + xmlSchemaDeriveFacetErr(pctxt, fmininc, fmaxexc, -1, 0, 0); + } + } + /* + * "minExclusive valid restriction" + */ + if (bfmininc) { + /* minInclusive >= BASE minInclusive */ + res = xmlSchemaCompareValues(fmininc->val, bfmininc->val); + if (res == -2) + goto internal_error; + if (res == -1) { + xmlSchemaDeriveFacetErr(pctxt, fmininc, bfmininc, 1, 1, 1); + } + if ((res != 0) && (bfmininc->fixed)) { + FACET_RESTR_FIXED_ERR(fmininc) + } + } + if (bfmaxinc) { + /* minInclusive <= BASE maxInclusive */ + res = xmlSchemaCompareValues(fmininc->val, bfmaxinc->val); + if (res == -2) + goto internal_error; + if (res == 1) { + xmlSchemaDeriveFacetErr(pctxt, fmininc, bfmaxinc, -1, 1, 1); + } + } + if (bfminexc) { + /* minInclusive > BASE minExclusive */ + res = xmlSchemaCompareValues(fmininc->val, bfminexc->val); + if (res == -2) + goto internal_error; + if (res != 1) + xmlSchemaDeriveFacetErr(pctxt, fmininc, bfminexc, 1, 0, 1); + } + if (bfmaxexc) { + /* minInclusive < BASE maxExclusive */ + res = xmlSchemaCompareValues(fmininc->val, bfmaxexc->val); + if (res == -2) + goto internal_error; + if (res != -1) + xmlSchemaDeriveFacetErr(pctxt, fmininc, bfmaxexc, -1, 0, 1); + } + } + if (ftotdig && bftotdig) { + /* + * SCC " totalDigits valid restriction" + * totalDigits <= BASE totalDigits + */ + res = xmlSchemaCompareValues(ftotdig->val, bftotdig->val); + if (res == -2) + goto internal_error; + if (res == 1) + xmlSchemaDeriveFacetErr(pctxt, ftotdig, bftotdig, + -1, 1, 1); + if ((res != 0) && (bftotdig->fixed)) { + FACET_RESTR_FIXED_ERR(ftotdig) + } + } + if (ffracdig && bffracdig) { + /* + * SCC "fractionDigits valid restriction" + * fractionDigits <= BASE fractionDigits + */ + res = xmlSchemaCompareValues(ffracdig->val, bffracdig->val); + if (res == -2) + goto internal_error; + if (res == 1) + xmlSchemaDeriveFacetErr(pctxt, ffracdig, bffracdig, + -1, 1, 1); + if ((res != 0) && (bffracdig->fixed)) { + FACET_RESTR_FIXED_ERR(ffracdig) + } + } + /* + * SCC "fractionDigits less than or equal to totalDigits" + */ + if (! ftotdig) + ftotdig = bftotdig; + if (! ffracdig) + ffracdig = bffracdig; + if (ftotdig && ffracdig) { + res = xmlSchemaCompareValues(ffracdig->val, ftotdig->val); + if (res == -2) + goto internal_error; + if (res == 1) + xmlSchemaDeriveFacetErr(pctxt, ffracdig, ftotdig, + -1, 1, 0); + } + /* + * *Enumerations* won' be added here, since only the first set + * of enumerations in the ancestor-or-self axis is used + * for validation, plus we need to use the base type of those + * enumerations for whitespace. + * + * *Patterns*: won't be add here, since they are ORed at + * type level and ANDed at ancestor level. This will + * happed during validation by walking the base axis + * of the type. + */ + for (cur = base->facetSet; cur != NULL; cur = cur->next) { + bfacet = cur->facet; + /* + * Special handling of enumerations and patterns. + * TODO: hmm, they should not appear in the set, so remove this. + */ + if ((bfacet->type == XML_SCHEMA_FACET_PATTERN) || + (bfacet->type == XML_SCHEMA_FACET_ENUMERATION)) + continue; + /* + * Search for a duplicate facet in the current type. + */ + link = type->facetSet; + /* err = 0; */ + /* fixedErr = 0; */ + while (link != NULL) { + facet = link->facet; + if (facet->type == bfacet->type) { + switch (facet->type) { + case XML_SCHEMA_FACET_WHITESPACE: + /* + * The whitespace must be stronger. + */ + if (facet->whitespace < bfacet->whitespace) { + FACET_RESTR_ERR(facet, + "The 'whitespace' value has to be equal to " + "or stronger than the 'whitespace' value of " + "the base type") + } + if ((bfacet->fixed) && + (facet->whitespace != bfacet->whitespace)) { + FACET_RESTR_FIXED_ERR(facet) + } + break; + default: + break; + } + /* Duplicate found. */ + break; + } + link = link->next; + } + /* + * If no duplicate was found: add the base types's facet + * to the set. + */ + if (link == NULL) { + link = (xmlSchemaFacetLinkPtr) + xmlMalloc(sizeof(xmlSchemaFacetLink)); + if (link == NULL) { + xmlSchemaPErrMemory(pctxt, + "deriving facets, creating a facet link", NULL); + return (-1); + } + link->facet = cur->facet; + link->next = NULL; + if (last == NULL) + type->facetSet = link; + else + last->next = link; + last = link; + } + + } + + return (0); +internal_error: + PERROR_INT("xmlSchemaDeriveAndValidateFacets", + "an error occured"); + return (-1); +} + +static int +xmlSchemaFinishMemberTypeDefinitionsProperty(xmlSchemaParserCtxtPtr pctxt, + xmlSchemaTypePtr type) +{ + xmlSchemaTypeLinkPtr link, lastLink, prevLink, subLink, newLink; + /* + * The actual value is then formed by replacing any union type + * definition in the �explicit members� with the members of their + * {member type definitions}, in order. + * + * TODO: There's a bug entry at + * "http://lists.w3.org/Archives/Public/www-xml-schema-comments/2005JulSep/0287.html" + * which indicates that we'll keep the union types the future. + */ + link = type->memberTypes; + while (link != NULL) { + + if (WXS_IS_TYPE_NOT_FIXED(link->type)) + xmlSchemaTypeFixup(link->type, ACTXT_CAST pctxt); + + if (WXS_IS_UNION(link->type)) { + subLink = xmlSchemaGetUnionSimpleTypeMemberTypes(link->type); + if (subLink != NULL) { + link->type = subLink->type; + if (subLink->next != NULL) { + lastLink = link->next; + subLink = subLink->next; + prevLink = link; + while (subLink != NULL) { + newLink = (xmlSchemaTypeLinkPtr) + xmlMalloc(sizeof(xmlSchemaTypeLink)); + if (newLink == NULL) { + xmlSchemaPErrMemory(pctxt, "allocating a type link", + NULL); + return (-1); + } + newLink->type = subLink->type; + prevLink->next = newLink; + prevLink = newLink; + newLink->next = lastLink; + + subLink = subLink->next; + } + } + } + } + link = link->next; + } + return (0); +} + +static void +xmlSchemaTypeFixupOptimFacets(xmlSchemaTypePtr type) +{ + int has = 0, needVal = 0, normVal = 0; + + has = (type->baseType->flags & XML_SCHEMAS_TYPE_HAS_FACETS) ? 1 : 0; + if (has) { + needVal = (type->baseType->flags & + XML_SCHEMAS_TYPE_FACETSNEEDVALUE) ? 1 : 0; + normVal = (type->baseType->flags & + XML_SCHEMAS_TYPE_NORMVALUENEEDED) ? 1 : 0; + } + if (type->facets != NULL) { + xmlSchemaFacetPtr fac; + + for (fac = type->facets; fac != NULL; fac = fac->next) { + switch (fac->type) { + case XML_SCHEMA_FACET_WHITESPACE: + break; + case XML_SCHEMA_FACET_PATTERN: + normVal = 1; + has = 1; + break; + case XML_SCHEMA_FACET_ENUMERATION: + needVal = 1; + normVal = 1; + has = 1; + break; + default: + has = 1; + break; + } + } + } + if (normVal) + type->flags |= XML_SCHEMAS_TYPE_NORMVALUENEEDED; + if (needVal) + type->flags |= XML_SCHEMAS_TYPE_FACETSNEEDVALUE; + if (has) + type->flags |= XML_SCHEMAS_TYPE_HAS_FACETS; + + if (has && (! needVal) && WXS_IS_ATOMIC(type)) { + xmlSchemaTypePtr prim = xmlSchemaGetPrimitiveType(type); + /* + * OPTIMIZE VAL TODO: Some facets need a computed value. + */ + if ((prim->builtInType != XML_SCHEMAS_ANYSIMPLETYPE) && + (prim->builtInType != XML_SCHEMAS_STRING)) { + type->flags |= XML_SCHEMAS_TYPE_FACETSNEEDVALUE; + } + } +} + +static int +xmlSchemaTypeFixupWhitespace(xmlSchemaTypePtr type) +{ + + + /* + * Evaluate the whitespace-facet value. + */ + if (WXS_IS_LIST(type)) { + type->flags |= XML_SCHEMAS_TYPE_WHITESPACE_COLLAPSE; + return (0); + } else if (WXS_IS_UNION(type)) + return (0); + + if (type->facetSet != NULL) { + xmlSchemaFacetLinkPtr lin; + + for (lin = type->facetSet; lin != NULL; lin = lin->next) { + if (lin->facet->type == XML_SCHEMA_FACET_WHITESPACE) { + switch (lin->facet->whitespace) { + case XML_SCHEMAS_FACET_PRESERVE: + type->flags |= XML_SCHEMAS_TYPE_WHITESPACE_PRESERVE; + break; + case XML_SCHEMAS_FACET_REPLACE: + type->flags |= XML_SCHEMAS_TYPE_WHITESPACE_REPLACE; + break; + case XML_SCHEMAS_FACET_COLLAPSE: + type->flags |= XML_SCHEMAS_TYPE_WHITESPACE_COLLAPSE; + break; + default: + return (-1); + } + return (0); + } + } + } + /* + * For all �atomic� datatypes other than string (and types �derived� + * by �restriction� from it) the value of whiteSpace is fixed to + * collapse + */ + { + xmlSchemaTypePtr anc; + + for (anc = type->baseType; anc != NULL && + anc->builtInType != XML_SCHEMAS_ANYTYPE; + anc = anc->baseType) { + + if (anc->type == XML_SCHEMA_TYPE_BASIC) { + if (anc->builtInType == XML_SCHEMAS_NORMSTRING) { + type->flags |= XML_SCHEMAS_TYPE_WHITESPACE_REPLACE; + + } else if ((anc->builtInType == XML_SCHEMAS_STRING) || + (anc->builtInType == XML_SCHEMAS_ANYSIMPLETYPE)) { + type->flags |= XML_SCHEMAS_TYPE_WHITESPACE_PRESERVE; + + } else + type->flags |= XML_SCHEMAS_TYPE_WHITESPACE_COLLAPSE; + break; + } + } + } + return (0); +} + +static int +xmlSchemaFixupSimpleTypeStageOne(xmlSchemaParserCtxtPtr pctxt, + xmlSchemaTypePtr type) +{ + if (type->type != XML_SCHEMA_TYPE_SIMPLE) + return(0); + if (! WXS_IS_TYPE_NOT_FIXED_1(type)) + return(0); + type->flags |= XML_SCHEMAS_TYPE_FIXUP_1; + + if (WXS_IS_LIST(type)) { + /* + * Corresponds to ... + */ + if (type->subtypes == NULL) { + /* + * This one is really needed, so get out. + */ + PERROR_INT("xmlSchemaFixupSimpleTypeStageOne", + "list type has no item-type assigned"); + return(-1); + } + } else if (WXS_IS_UNION(type)) { + /* + * Corresponds to ... + */ + if (type->memberTypes == NULL) { + /* + * This one is really needed, so get out. + */ + PERROR_INT("xmlSchemaFixupSimpleTypeStageOne", + "union type has no member-types assigned"); + return(-1); + } + } else { + /* + * Corresponds to ... + */ + if (type->baseType == NULL) { + PERROR_INT("xmlSchemaFixupSimpleTypeStageOne", + "type has no base-type assigned"); + return(-1); + } + if (WXS_IS_TYPE_NOT_FIXED_1(type->baseType)) + if (xmlSchemaFixupSimpleTypeStageOne(pctxt, type->baseType) == -1) + return(-1); + /* + * Variety + * If the alternative is chosen, then the + * {variety} of the {base type definition}. + */ + if (WXS_IS_ATOMIC(type->baseType)) + type->flags |= XML_SCHEMAS_TYPE_VARIETY_ATOMIC; + else if (WXS_IS_LIST(type->baseType)) { + type->flags |= XML_SCHEMAS_TYPE_VARIETY_LIST; + /* + * Inherit the itemType. + */ + type->subtypes = type->baseType->subtypes; + } else if (WXS_IS_UNION(type->baseType)) { + type->flags |= XML_SCHEMAS_TYPE_VARIETY_UNION; + /* + * NOTE that we won't assign the memberTypes of the base, + * since this will make trouble when freeing them; we will + * use a lookup function to access them instead. + */ + } + } + return(0); +} + +#ifdef DEBUG_TYPE +static void +xmlSchemaDebugFixedType(xmlSchemaParserCtxtPtr pctxt, + xmlSchemaTypePtr type) +{ + if (type->node != NULL) { + xmlGenericError(xmlGenericErrorContext, + "Type of %s : %s:%d :", name, + type->node->doc->URL, + xmlGetLineNo(type->node)); + } else { + xmlGenericError(xmlGenericErrorContext, "Type of %s :", name); + } + if ((WXS_IS_SIMPLE(type)) || (WXS_IS_COMPLEX(type))) { + switch (type->contentType) { + case XML_SCHEMA_CONTENT_SIMPLE: + xmlGenericError(xmlGenericErrorContext, "simple\n"); + break; + case XML_SCHEMA_CONTENT_ELEMENTS: + xmlGenericError(xmlGenericErrorContext, "elements\n"); + break; + case XML_SCHEMA_CONTENT_UNKNOWN: + xmlGenericError(xmlGenericErrorContext, "unknown !!!\n"); + break; + case XML_SCHEMA_CONTENT_EMPTY: + xmlGenericError(xmlGenericErrorContext, "empty\n"); + break; + case XML_SCHEMA_CONTENT_MIXED: + if (xmlSchemaIsParticleEmptiable((xmlSchemaParticlePtr) + type->subtypes)) + xmlGenericError(xmlGenericErrorContext, + "mixed as emptiable particle\n"); + else + xmlGenericError(xmlGenericErrorContext, "mixed\n"); + break; + /* Removed, since not used. */ + /* + case XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS: + xmlGenericError(xmlGenericErrorContext, "mixed or elems\n"); + break; + */ + case XML_SCHEMA_CONTENT_BASIC: + xmlGenericError(xmlGenericErrorContext, "basic\n"); + break; + default: + xmlGenericError(xmlGenericErrorContext, + "not registered !!!\n"); + break; + } + } +} +#endif + +/* +* 3.14.6 Constraints on Simple Type Definition Schema Components +*/ +static int +xmlSchemaFixupSimpleTypeStageTwo(xmlSchemaParserCtxtPtr pctxt, + xmlSchemaTypePtr type) +{ + int res, olderrs = pctxt->nberrors; + + if (type->type != XML_SCHEMA_TYPE_SIMPLE) + return(-1); + + if (! WXS_IS_TYPE_NOT_FIXED(type)) + return(0); + + type->flags |= XML_SCHEMAS_TYPE_INTERNAL_RESOLVED; + type->contentType = XML_SCHEMA_CONTENT_SIMPLE; + + if (type->baseType == NULL) { + PERROR_INT("xmlSchemaFixupSimpleTypeStageTwo", + "missing baseType"); + goto exit_failure; + } + if (WXS_IS_TYPE_NOT_FIXED(type->baseType)) + xmlSchemaTypeFixup(type->baseType, ACTXT_CAST pctxt); + /* + * If a member type of a union is a union itself, we need to substitute + * that member type for its member types. + * NOTE that this might change in WXS 1.1; i.e. we will keep the union + * types in WXS 1.1. + */ + if ((type->memberTypes != NULL) && + (xmlSchemaFinishMemberTypeDefinitionsProperty(pctxt, type) == -1)) + return(-1); + /* + * SPEC src-simple-type 1 + * "The corresponding simple type definition, if any, must satisfy + * the conditions set out in Constraints on Simple Type Definition + * Schema Components (�3.14.6)." + */ + /* + * Schema Component Constraint: Simple Type Definition Properties Correct + * (st-props-correct) + */ + res = xmlSchemaCheckSTPropsCorrect(pctxt, type); + HFAILURE HERROR + /* + * Schema Component Constraint: Derivation Valid (Restriction, Simple) + * (cos-st-restricts) + */ + res = xmlSchemaCheckCOSSTRestricts(pctxt, type); + HFAILURE HERROR + /* + * TODO: Removed the error report, since it got annoying to get an + * extra error report, if anything failed until now. + * Enable this if needed. + * + * xmlSchemaPErr(ctxt, type->node, + * XML_SCHEMAP_SRC_SIMPLE_TYPE_1, + * "Simple type '%s' does not satisfy the constraints " + * "on simple type definitions.\n", + * type->name, NULL); + */ + /* + * Schema Component Constraint: Simple Type Restriction (Facets) + * (st-restrict-facets) + */ + res = xmlSchemaCheckFacetValues(type, pctxt); + HFAILURE HERROR + if ((type->facetSet != NULL) || + (type->baseType->facetSet != NULL)) { + res = xmlSchemaDeriveAndValidateFacets(pctxt, type); + HFAILURE HERROR + } + /* + * Whitespace value. + */ + res = xmlSchemaTypeFixupWhitespace(type); + HFAILURE HERROR + xmlSchemaTypeFixupOptimFacets(type); + +exit_error: +#ifdef DEBUG_TYPE + xmlSchemaDebugFixedType(pctxt, type); +#endif + if (olderrs != pctxt->nberrors) + return(pctxt->err); + return(0); + +exit_failure: +#ifdef DEBUG_TYPE + xmlSchemaDebugFixedType(pctxt, type); +#endif + return(-1); +} + +static int +xmlSchemaFixupComplexType(xmlSchemaParserCtxtPtr pctxt, + xmlSchemaTypePtr type) +{ + int res = 0, olderrs = pctxt->nberrors; + xmlSchemaTypePtr baseType = type->baseType; + + if (! WXS_IS_TYPE_NOT_FIXED(type)) + return(0); + type->flags |= XML_SCHEMAS_TYPE_INTERNAL_RESOLVED; + if (baseType == NULL) { + PERROR_INT("xmlSchemaFixupComplexType", + "missing baseType"); + goto exit_failure; + } + /* + * Fixup the base type. + */ + if (WXS_IS_TYPE_NOT_FIXED(baseType)) + xmlSchemaTypeFixup(baseType, ACTXT_CAST pctxt); + if (baseType->flags & XML_SCHEMAS_TYPE_INTERNAL_INVALID) { + /* + * Skip fixup if the base type is invalid. + * TODO: Generate a warning! + */ + return(0); + } + /* + * This basically checks if the base type can be derived. + */ + res = xmlSchemaCheckSRCCT(pctxt, type); + HFAILURE HERROR + /* + * Fixup the content type. + */ + if (type->contentType == XML_SCHEMA_CONTENT_SIMPLE) { + /* + * Corresponds to ... + */ + if ((WXS_IS_COMPLEX(baseType)) && + (baseType->contentTypeDef != NULL) && + (WXS_IS_RESTRICTION(type))) { + xmlSchemaTypePtr contentBase, content; +#ifdef ENABLE_NAMED_LOCALS + char buf[30]; + const xmlChar *tmpname; +#endif + /* + * SPEC (1) If + base type is , + * "whose own {content type} is a simple type..." + */ + if (type->contentTypeDef != NULL) { + /* + * SPEC (1.1) "the simple type definition corresponding to the + * among the [children] of if there + * is one;" + * Note that this " among the [children]" was put + * into ->contentTypeDef during parsing. + */ + contentBase = type->contentTypeDef; + type->contentTypeDef = NULL; + } else { + /* + * (1.2) "...otherwise ( has no + * among its [children]), the simple type definition which + * is the {content type} of the ... base type." + */ + contentBase = baseType->contentTypeDef; + } + /* + * SPEC + * "... a simple type definition which restricts the simple + * type definition identified in clause 1.1 or clause 1.2 + * with a set of facet components" + * + * Create the anonymous simple type, which will be the content + * type of the complex type. + */ +#ifdef ENABLE_NAMED_LOCALS + snprintf(buf, 29, "#scST%d", ++(pctxt->counter)); + tmpname = xmlDictLookup(pctxt->dict, BAD_CAST buf, -1); + content = xmlSchemaAddType(pctxt, pctxt->schema, + XML_SCHEMA_TYPE_SIMPLE, tmpname, type->targetNamespace, + type->node, 0); +#else + content = xmlSchemaAddType(pctxt, pctxt->schema, + XML_SCHEMA_TYPE_SIMPLE, NULL, type->targetNamespace, + type->node, 0); +#endif + if (content == NULL) + goto exit_failure; + /* + * We will use the same node as for the + * to have it somehow anchored in the schema doc. + */ + content->type = XML_SCHEMA_TYPE_SIMPLE; + content->baseType = contentBase; + /* + * Move the facets, previously anchored on the + * complexType during parsing. + */ + content->facets = type->facets; + type->facets = NULL; + content->facetSet = type->facetSet; + type->facetSet = NULL; + + type->contentTypeDef = content; + if (WXS_IS_TYPE_NOT_FIXED(contentBase)) + xmlSchemaTypeFixup(contentBase, ACTXT_CAST pctxt); + /* + * Fixup the newly created type. We don't need to check + * for circularity here. + */ + res = xmlSchemaFixupSimpleTypeStageOne(pctxt, content); + HFAILURE HERROR + res = xmlSchemaFixupSimpleTypeStageTwo(pctxt, content); + HFAILURE HERROR + + } else if ((WXS_IS_COMPLEX(baseType)) && + (baseType->contentType == XML_SCHEMA_CONTENT_MIXED) && + (WXS_IS_RESTRICTION(type))) { + /* + * SPEC (2) If + base is a mixed with + * an emptiable particle, then a simple type definition which + * restricts the 's child. + */ + if ((type->contentTypeDef == NULL) || + (type->contentTypeDef->baseType == NULL)) { + /* + * TODO: Check if this ever happens. + */ + xmlSchemaPCustomErr(pctxt, + XML_SCHEMAP_INTERNAL, + WXS_BASIC_CAST type, NULL, + "Internal error: xmlSchemaTypeFixup, " + "complex type '%s': the " + "is missing a child, but was not catched " + "by xmlSchemaCheckSRCCT()", type->name); + goto exit_failure; + } + } else if ((WXS_IS_COMPLEX(baseType)) && WXS_IS_EXTENSION(type)) { + /* + * SPEC (3) If + base is with + * content, "...then the {content type} of that + * complex type definition" + */ + if (baseType->contentTypeDef == NULL) { + /* + * TODO: Check if this ever happens. xmlSchemaCheckSRCCT + * should have catched this already. + */ + xmlSchemaPCustomErr(pctxt, + XML_SCHEMAP_INTERNAL, + WXS_BASIC_CAST type, NULL, + "Internal error: xmlSchemaTypeFixup, " + "complex type '%s': the ed base type is " + "a complex type with no simple content type", + type->name); + goto exit_failure; + } + type->contentTypeDef = baseType->contentTypeDef; + } else if ((WXS_IS_SIMPLE(baseType)) && WXS_IS_EXTENSION(type)) { + /* + * SPEC (4) + base is + * "... then that simple type definition" + */ + type->contentTypeDef = baseType; + } else { + /* + * TODO: Check if this ever happens. + */ + xmlSchemaPCustomErr(pctxt, + XML_SCHEMAP_INTERNAL, + WXS_BASIC_CAST type, NULL, + "Internal error: xmlSchemaTypeFixup, " + "complex type '%s' with : unhandled " + "derivation case", type->name); + goto exit_failure; + } + } else { + int dummySequence = 0; + xmlSchemaParticlePtr particle = + (xmlSchemaParticlePtr) type->subtypes; + /* + * Corresponds to ... + * + * NOTE that the effective mixed was already set during parsing of + * and ; its flag value is + * XML_SCHEMAS_TYPE_MIXED. + * + * Compute the "effective content": + * (2.1.1) + (2.1.2) + (2.1.3) + */ + if ((particle == NULL) || + ((particle->type == XML_SCHEMA_TYPE_PARTICLE) && + ((particle->children->type == XML_SCHEMA_TYPE_ALL) || + (particle->children->type == XML_SCHEMA_TYPE_SEQUENCE) || + ((particle->children->type == XML_SCHEMA_TYPE_CHOICE) && + (particle->minOccurs == 0))) && + ( ((xmlSchemaTreeItemPtr) particle->children)->children == NULL))) { + if (type->flags & XML_SCHEMAS_TYPE_MIXED) { + /* + * SPEC (2.1.4) "If the �effective mixed� is true, then + * a particle whose properties are as follows:..." + * + * Empty sequence model group with + * minOccurs/maxOccurs = 1 (i.e. a "particle emptiable"). + * NOTE that we sill assign it the node to + * somehow anchor it in the doc. + */ + if ((particle == NULL) || + (particle->children->type != XML_SCHEMA_TYPE_SEQUENCE)) { + /* + * Create the particle. + */ + particle = xmlSchemaAddParticle(pctxt, + type->node, 1, 1); + if (particle == NULL) + goto exit_failure; + /* + * Create the model group. + */ /* URGENT TODO: avoid adding to pending items. */ + particle->children = (xmlSchemaTreeItemPtr) + xmlSchemaAddModelGroup(pctxt, pctxt->schema, + XML_SCHEMA_TYPE_SEQUENCE, type->node); + if (particle->children == NULL) + goto exit_failure; + + type->subtypes = (xmlSchemaTypePtr) particle; + } + dummySequence = 1; + type->contentType = XML_SCHEMA_CONTENT_ELEMENTS; + } else { + /* + * SPEC (2.1.5) "otherwise empty" + */ + type->contentType = XML_SCHEMA_CONTENT_EMPTY; + } + } else { + /* + * SPEC (2.2) "otherwise the particle corresponding to the + * , , or among the + * [children]." + */ + type->contentType = XML_SCHEMA_CONTENT_ELEMENTS; + } + /* + * Compute the "content type". + */ + if (WXS_IS_RESTRICTION(type)) { + /* + * SPEC (3.1) "If ..." + * (3.1.1) + (3.1.2) */ + if (type->contentType != XML_SCHEMA_CONTENT_EMPTY) { + if (type->flags & XML_SCHEMAS_TYPE_MIXED) + type->contentType = XML_SCHEMA_CONTENT_MIXED; + } + } else { + /* + * SPEC (3.2) "If ..." + */ + if (type->contentType == XML_SCHEMA_CONTENT_EMPTY) { + /* + * SPEC (3.2.1) + * "If the �effective content� is empty, then the + * {content type} of the [...] base ..." + */ + type->contentType = baseType->contentType; + type->subtypes = baseType->subtypes; + /* + * Fixes bug #347316: + * This is the case when the base type has a simple + * type definition as content. + */ + type->contentTypeDef = baseType->contentTypeDef; + /* + * NOTE that the effective mixed is ignored here. + */ + } else if (baseType->contentType == XML_SCHEMA_CONTENT_EMPTY) { + /* + * SPEC (3.2.2) + */ + if (type->flags & XML_SCHEMAS_TYPE_MIXED) + type->contentType = XML_SCHEMA_CONTENT_MIXED; + } else { + /* + * SPEC (3.2.3) + */ + if (type->flags & XML_SCHEMAS_TYPE_MIXED) + type->contentType = XML_SCHEMA_CONTENT_MIXED; + /* + * "A model group whose {compositor} is sequence and whose + * {particles} are..." + */ + if ((WXS_TYPE_PARTICLE(type) != NULL) && + (WXS_TYPE_PARTICLE_TERM(type) != NULL) && + ((WXS_TYPE_PARTICLE_TERM(type))->type == + XML_SCHEMA_TYPE_ALL)) + { + /* + * SPEC cos-all-limited (1) + */ + xmlSchemaCustomErr(ACTXT_CAST pctxt, + /* TODO: error code */ + XML_SCHEMAP_COS_ALL_LIMITED, + WXS_ITEM_NODE(type), NULL, + "The type has an 'all' model group in its " + "{content type} and thus cannot be derived from " + "a non-empty type, since this would produce a " + "'sequence' model group containing the 'all' " + "model group; 'all' model groups are not " + "allowed to appear inside other model groups", + NULL, NULL); + + } else if ((WXS_TYPE_PARTICLE(baseType) != NULL) && + (WXS_TYPE_PARTICLE_TERM(baseType) != NULL) && + ((WXS_TYPE_PARTICLE_TERM(baseType))->type == + XML_SCHEMA_TYPE_ALL)) + { + /* + * SPEC cos-all-limited (1) + */ + xmlSchemaCustomErr(ACTXT_CAST pctxt, + /* TODO: error code */ + XML_SCHEMAP_COS_ALL_LIMITED, + WXS_ITEM_NODE(type), NULL, + "A type cannot be derived by extension from a type " + "which has an 'all' model group in its " + "{content type}, since this would produce a " + "'sequence' model group containing the 'all' " + "model group; 'all' model groups are not " + "allowed to appear inside other model groups", + NULL, NULL); + + } else if (! dummySequence) { + xmlSchemaTreeItemPtr effectiveContent = + (xmlSchemaTreeItemPtr) type->subtypes; + /* + * Create the particle. + */ + particle = xmlSchemaAddParticle(pctxt, + type->node, 1, 1); + if (particle == NULL) + goto exit_failure; + /* + * Create the "sequence" model group. + */ + particle->children = (xmlSchemaTreeItemPtr) + xmlSchemaAddModelGroup(pctxt, pctxt->schema, + XML_SCHEMA_TYPE_SEQUENCE, type->node); + if (particle->children == NULL) + goto exit_failure; + WXS_TYPE_CONTENTTYPE(type) = (xmlSchemaTypePtr) particle; + /* + * SPEC "the particle of the {content type} of + * the ... base ..." + * Create a duplicate of the base type's particle + * and assign its "term" to it. + */ + particle->children->children = + (xmlSchemaTreeItemPtr) xmlSchemaAddParticle(pctxt, + type->node, + ((xmlSchemaParticlePtr) type->subtypes)->minOccurs, + ((xmlSchemaParticlePtr) type->subtypes)->maxOccurs); + if (particle->children->children == NULL) + goto exit_failure; + particle = (xmlSchemaParticlePtr) + particle->children->children; + particle->children = + ((xmlSchemaParticlePtr) baseType->subtypes)->children; + /* + * SPEC "followed by the �effective content�." + */ + particle->next = effectiveContent; + /* + * This all will result in: + * new-particle + * --> new-sequence( + * new-particle + * --> base-model, + * this-particle + * --> this-model + * ) + */ + } else { + /* + * This is the case when there is already an empty + * with minOccurs==maxOccurs==1. + * Just add the base types's content type. + * NOTE that, although we miss to add an intermediate + * , this should produce no difference to + * neither the regex compilation of the content model, + * nor to the complex type contraints. + */ + particle->children->children = + (xmlSchemaTreeItemPtr) baseType->subtypes; + } + } + } + } + /* + * Now fixup attribute uses: + * - expand attr. group references + * - intersect attribute wildcards + * - inherit attribute uses of the base type + * - inherit or union attr. wildcards if extending + * - apply attr. use prohibitions if restricting + */ + res = xmlSchemaFixupTypeAttributeUses(pctxt, type); + HFAILURE HERROR + /* + * Apply the complex type component constraints; this will not + * check attributes, since this is done in + * xmlSchemaFixupTypeAttributeUses(). + */ + res = xmlSchemaCheckCTComponent(pctxt, type); + HFAILURE HERROR + +#ifdef DEBUG_TYPE + xmlSchemaDebugFixedType(pctxt, type); +#endif + if (olderrs != pctxt->nberrors) + return(pctxt->err); + else + return(0); + +exit_error: + type->flags |= XML_SCHEMAS_TYPE_INTERNAL_INVALID; +#ifdef DEBUG_TYPE + xmlSchemaDebugFixedType(pctxt, type); +#endif + return(pctxt->err); + +exit_failure: + type->flags |= XML_SCHEMAS_TYPE_INTERNAL_INVALID; +#ifdef DEBUG_TYPE + xmlSchemaDebugFixedType(pctxt, type); +#endif + return(-1); +} + + +/** + * xmlSchemaTypeFixup: + * @typeDecl: the schema type definition + * @ctxt: the schema parser context + * + * Fixes the content model of the type. + * URGENT TODO: We need an int result! + */ +static int +xmlSchemaTypeFixup(xmlSchemaTypePtr type, + xmlSchemaAbstractCtxtPtr actxt) +{ + if (type == NULL) + return(0); + if (actxt->type != XML_SCHEMA_CTXT_PARSER) { + AERROR_INT("xmlSchemaTypeFixup", + "this function needs a parser context"); + return(-1); + } + if (! WXS_IS_TYPE_NOT_FIXED(type)) + return(0); + if (type->type == XML_SCHEMA_TYPE_COMPLEX) + return(xmlSchemaFixupComplexType(PCTXT_CAST actxt, type)); + else if (type->type == XML_SCHEMA_TYPE_SIMPLE) + return(xmlSchemaFixupSimpleTypeStageTwo(PCTXT_CAST actxt, type)); + return(0); +} + +/** + * xmlSchemaCheckFacet: + * @facet: the facet + * @typeDecl: the schema type definition + * @pctxt: the schema parser context or NULL + * @name: the optional name of the type + * + * Checks and computes the values of facets. + * + * Returns 0 if valid, a positive error code if not valid and + * -1 in case of an internal or API error. + */ +int +xmlSchemaCheckFacet(xmlSchemaFacetPtr facet, + xmlSchemaTypePtr typeDecl, + xmlSchemaParserCtxtPtr pctxt, + const xmlChar * name ATTRIBUTE_UNUSED) +{ + int ret = 0, ctxtGiven; + + if ((facet == NULL) || (typeDecl == NULL)) + return(-1); + /* + * TODO: will the parser context be given if used from + * the relaxNG module? + */ + if (pctxt == NULL) + ctxtGiven = 0; + else + ctxtGiven = 1; + + switch (facet->type) { + case XML_SCHEMA_FACET_MININCLUSIVE: + case XML_SCHEMA_FACET_MINEXCLUSIVE: + case XML_SCHEMA_FACET_MAXINCLUSIVE: + case XML_SCHEMA_FACET_MAXEXCLUSIVE: + case XML_SCHEMA_FACET_ENUMERATION: { + /* + * Okay we need to validate the value + * at that point. + */ + xmlSchemaTypePtr base; + + /* 4.3.5.5 Constraints on enumeration Schema Components + * Schema Component Constraint: enumeration valid restriction + * It is an �error� if any member of {value} is not in the + * �value space� of {base type definition}. + * + * minInclusive, maxInclusive, minExclusive, maxExclusive: + * The value �must� be in the + * �value space� of the �base type�. + */ + /* + * This function is intended to deliver a compiled value + * on the facet. In this implementation of XML Schemata the + * type holding a facet, won't be a built-in type. + * Thus to ensure that other API + * calls (relaxng) do work, if the given type is a built-in + * type, we will assume that the given built-in type *is + * already* the base type. + */ + if (typeDecl->type != XML_SCHEMA_TYPE_BASIC) { + base = typeDecl->baseType; + if (base == NULL) { + PERROR_INT("xmlSchemaCheckFacet", + "a type user derived type has no base type"); + return (-1); + } + } else + base = typeDecl; + + if (! ctxtGiven) { + /* + * A context is needed if called from RelaxNG. + */ + pctxt = xmlSchemaNewParserCtxt("*"); + if (pctxt == NULL) + return (-1); + } + /* + * NOTE: This call does not check the content nodes, + * since they are not available: + * facet->node is just the node holding the facet + * definition, *not* the attribute holding the *value* + * of the facet. + */ + ret = xmlSchemaVCheckCVCSimpleType( + ACTXT_CAST pctxt, facet->node, base, + facet->value, &(facet->val), 1, 1, 0); + if (ret != 0) { + if (ret < 0) { + /* No error message for RelaxNG. */ + if (ctxtGiven) { + xmlSchemaCustomErr(ACTXT_CAST pctxt, + XML_SCHEMAP_INTERNAL, facet->node, NULL, + "Internal error: xmlSchemaCheckFacet, " + "failed to validate the value '%s' of the " + "facet '%s' against the base type", + facet->value, xmlSchemaFacetTypeToString(facet->type)); + } + goto internal_error; + } + ret = XML_SCHEMAP_INVALID_FACET_VALUE; + /* No error message for RelaxNG. */ + if (ctxtGiven) { + xmlChar *str = NULL; + + xmlSchemaCustomErr(ACTXT_CAST pctxt, + ret, facet->node, WXS_BASIC_CAST facet, + "The value '%s' of the facet does not validate " + "against the base type '%s'", + facet->value, + xmlSchemaFormatQName(&str, + base->targetNamespace, base->name)); + FREE_AND_NULL(str); + } + goto exit; + } else if (facet->val == NULL) { + if (ctxtGiven) { + PERROR_INT("xmlSchemaCheckFacet", + "value was not computed"); + } + TODO + } + break; + } + case XML_SCHEMA_FACET_PATTERN: + facet->regexp = xmlRegexpCompile(facet->value); + if (facet->regexp == NULL) { + ret = XML_SCHEMAP_REGEXP_INVALID; + /* No error message for RelaxNG. */ + if (ctxtGiven) { + xmlSchemaCustomErr(ACTXT_CAST pctxt, + ret, facet->node, WXS_BASIC_CAST typeDecl, + "The value '%s' of the facet 'pattern' is not a " + "valid regular expression", + facet->value, NULL); + } + } + break; + case XML_SCHEMA_FACET_TOTALDIGITS: + case XML_SCHEMA_FACET_FRACTIONDIGITS: + case XML_SCHEMA_FACET_LENGTH: + case XML_SCHEMA_FACET_MAXLENGTH: + case XML_SCHEMA_FACET_MINLENGTH: + + if (facet->type == XML_SCHEMA_FACET_TOTALDIGITS) { + ret = xmlSchemaValidatePredefinedType( + xmlSchemaGetBuiltInType(XML_SCHEMAS_PINTEGER), + facet->value, &(facet->val)); + } else { + ret = xmlSchemaValidatePredefinedType( + xmlSchemaGetBuiltInType(XML_SCHEMAS_NNINTEGER), + facet->value, &(facet->val)); + } + if (ret != 0) { + if (ret < 0) { + /* No error message for RelaxNG. */ + if (ctxtGiven) { + PERROR_INT("xmlSchemaCheckFacet", + "validating facet value"); + } + goto internal_error; + } + ret = XML_SCHEMAP_INVALID_FACET_VALUE; + /* No error message for RelaxNG. */ + if (ctxtGiven) { + /* error code */ + xmlSchemaCustomErr4(ACTXT_CAST pctxt, + ret, facet->node, WXS_BASIC_CAST typeDecl, + "The value '%s' of the facet '%s' is not a valid '%s'", + facet->value, + xmlSchemaFacetTypeToString(facet->type), + (facet->type != XML_SCHEMA_FACET_TOTALDIGITS) ? + BAD_CAST "nonNegativeInteger" : + BAD_CAST "positiveInteger", + NULL); + } + } + break; + + case XML_SCHEMA_FACET_WHITESPACE:{ + if (xmlStrEqual(facet->value, BAD_CAST "preserve")) { + facet->whitespace = XML_SCHEMAS_FACET_PRESERVE; + } else if (xmlStrEqual(facet->value, BAD_CAST "replace")) { + facet->whitespace = XML_SCHEMAS_FACET_REPLACE; + } else if (xmlStrEqual(facet->value, BAD_CAST "collapse")) { + facet->whitespace = XML_SCHEMAS_FACET_COLLAPSE; + } else { + ret = XML_SCHEMAP_INVALID_FACET_VALUE; + /* No error message for RelaxNG. */ + if (ctxtGiven) { + /* error was previously: XML_SCHEMAP_INVALID_WHITE_SPACE */ + xmlSchemaCustomErr(ACTXT_CAST pctxt, + ret, facet->node, WXS_BASIC_CAST typeDecl, + "The value '%s' of the facet 'whitespace' is not " + "valid", facet->value, NULL); + } + } + } + default: + break; + } +exit: + if ((! ctxtGiven) && (pctxt != NULL)) + xmlSchemaFreeParserCtxt(pctxt); + return (ret); +internal_error: + if ((! ctxtGiven) && (pctxt != NULL)) + xmlSchemaFreeParserCtxt(pctxt); + return (-1); +} + +/** + * xmlSchemaCheckFacetValues: + * @typeDecl: the schema type definition + * @ctxt: the schema parser context + * + * Checks the default values types, especially for facets + */ +static int +xmlSchemaCheckFacetValues(xmlSchemaTypePtr typeDecl, + xmlSchemaParserCtxtPtr pctxt) +{ + int res, olderrs = pctxt->nberrors; + const xmlChar *name = typeDecl->name; + /* + * NOTE: It is intended to use the facets list, instead + * of facetSet. + */ + if (typeDecl->facets != NULL) { + xmlSchemaFacetPtr facet = typeDecl->facets; + + /* + * Temporarily assign the "schema" to the validation context + * of the parser context. This is needed for NOTATION validation. + */ + if (pctxt->vctxt == NULL) { + if (xmlSchemaCreateVCtxtOnPCtxt(pctxt) == -1) + return(-1); + } + pctxt->vctxt->schema = pctxt->schema; + while (facet != NULL) { + res = xmlSchemaCheckFacet(facet, typeDecl, pctxt, name); + HFAILURE + facet = facet->next; + } + pctxt->vctxt->schema = NULL; + } + if (olderrs != pctxt->nberrors) + return(pctxt->err); + return(0); +exit_failure: + return(-1); +} + +/** + * xmlSchemaGetCircModelGrDefRef: + * @ctxtMGroup: the searched model group + * @selfMGroup: the second searched model group + * @particle: the first particle + * + * This one is intended to be used by + * xmlSchemaCheckGroupDefCircular only. + * + * Returns the particle with the circular model group definition reference, + * otherwise NULL. + */ +static xmlSchemaTreeItemPtr +xmlSchemaGetCircModelGrDefRef(xmlSchemaModelGroupDefPtr groupDef, + xmlSchemaTreeItemPtr particle) +{ + xmlSchemaTreeItemPtr circ = NULL; + xmlSchemaTreeItemPtr term; + xmlSchemaModelGroupDefPtr gdef; + + for (; particle != NULL; particle = particle->next) { + term = particle->children; + if (term == NULL) + continue; + switch (term->type) { + case XML_SCHEMA_TYPE_GROUP: + gdef = (xmlSchemaModelGroupDefPtr) term; + if (gdef == groupDef) + return (particle); + /* + * Mark this model group definition to avoid infinite + * recursion on circular references not yet examined. + */ + if (gdef->flags & XML_SCHEMA_MODEL_GROUP_DEF_MARKED) + continue; + if (gdef->children != NULL) { + gdef->flags |= XML_SCHEMA_MODEL_GROUP_DEF_MARKED; + circ = xmlSchemaGetCircModelGrDefRef(groupDef, + gdef->children->children); + gdef->flags ^= XML_SCHEMA_MODEL_GROUP_DEF_MARKED; + if (circ != NULL) + return (circ); + } + break; + case XML_SCHEMA_TYPE_SEQUENCE: + case XML_SCHEMA_TYPE_CHOICE: + case XML_SCHEMA_TYPE_ALL: + circ = xmlSchemaGetCircModelGrDefRef(groupDef, term->children); + if (circ != NULL) + return (circ); + break; + default: + break; + } + } + return (NULL); +} + +/** + * xmlSchemaCheckGroupDefCircular: + * @item: the model group definition + * @ctxt: the parser context + * @name: the name + * + * Checks for circular references to model group definitions. + */ +static void +xmlSchemaCheckGroupDefCircular(xmlSchemaModelGroupDefPtr item, + xmlSchemaParserCtxtPtr ctxt) +{ + /* + * Schema Component Constraint: Model Group Correct + * 2 Circular groups are disallowed. That is, within the {particles} + * of a group there must not be at any depth a particle whose {term} + * is the group itself. + */ + if ((item == NULL) || + (item->type != XML_SCHEMA_TYPE_GROUP) || + (item->children == NULL)) + return; + { + xmlSchemaTreeItemPtr circ; + + circ = xmlSchemaGetCircModelGrDefRef(item, item->children->children); + if (circ != NULL) { + xmlChar *str = NULL; + /* + * TODO: The error report is not adequate: this constraint + * is defined for model groups but not definitions, but since + * there cannot be any circular model groups without a model group + * definition (if not using a construction API), we check those + * defintions only. + */ + xmlSchemaPCustomErr(ctxt, + XML_SCHEMAP_MG_PROPS_CORRECT_2, + NULL, WXS_ITEM_NODE(circ), + "Circular reference to the model group definition '%s' " + "defined", xmlSchemaFormatQName(&str, + item->targetNamespace, item->name)); + FREE_AND_NULL(str) + /* + * NOTE: We will cut the reference to avoid further + * confusion of the processor. This is a fatal error. + */ + circ->children = NULL; + } + } +} + +/** + * xmlSchemaModelGroupToModelGroupDefFixup: + * @ctxt: the parser context + * @mg: the model group + * + * Assigns the model group of model group definitions to the "term" + * of the referencing particle. + * In xmlSchemaResolveModelGroupParticleReferences the model group + * definitions were assigned to the "term", since needed for the + * circularity check. + * + * Schema Component Constraint: + * All Group Limited (cos-all-limited) (1.2) + */ +static void +xmlSchemaModelGroupToModelGroupDefFixup( + xmlSchemaParserCtxtPtr ctxt ATTRIBUTE_UNUSED, + xmlSchemaModelGroupPtr mg) +{ + xmlSchemaParticlePtr particle = WXS_MODELGROUP_PARTICLE(mg); + + while (particle != NULL) { + if ((WXS_PARTICLE_TERM(particle) == NULL) || + ((WXS_PARTICLE_TERM(particle))->type != + XML_SCHEMA_TYPE_GROUP)) + { + particle = WXS_PTC_CAST particle->next; + continue; + } + if (WXS_MODELGROUPDEF_MODEL(WXS_PARTICLE_TERM(particle)) == NULL) { + /* + * TODO: Remove the particle. + */ + WXS_PARTICLE_TERM(particle) = NULL; + particle = WXS_PTC_CAST particle->next; + continue; + } + /* + * Assign the model group to the {term} of the particle. + */ + WXS_PARTICLE_TERM(particle) = + WXS_TREE_CAST WXS_MODELGROUPDEF_MODEL(WXS_PARTICLE_TERM(particle)); + + particle = WXS_PTC_CAST particle->next; + } +} + +/** + * xmlSchemaCheckAttrGroupCircularRecur: + * @ctxtGr: the searched attribute group + * @attr: the current attribute list to be processed + * + * This one is intended to be used by + * xmlSchemaCheckAttrGroupCircular only. + * + * Returns the circular attribute grou reference, otherwise NULL. + */ +static xmlSchemaQNameRefPtr +xmlSchemaCheckAttrGroupCircularRecur(xmlSchemaAttributeGroupPtr ctxtGr, + xmlSchemaItemListPtr list) +{ + xmlSchemaAttributeGroupPtr gr; + xmlSchemaQNameRefPtr ref, circ; + int i; + /* + * We will search for an attribute group reference which + * references the context attribute group. + */ + for (i = 0; i < list->nbItems; i++) { + ref = list->items[i]; + if ((ref->type == XML_SCHEMA_EXTRA_QNAMEREF) && + (ref->itemType == XML_SCHEMA_TYPE_ATTRIBUTEGROUP) && + (ref->item != NULL)) + { + gr = WXS_ATTR_GROUP_CAST ref->item; + if (gr == ctxtGr) + return(ref); + if (gr->flags & XML_SCHEMAS_ATTRGROUP_MARKED) + continue; + /* + * Mark as visited to avoid infinite recursion on + * circular references not yet examined. + */ + if ((gr->attrUses) && + (gr->flags & XML_SCHEMAS_ATTRGROUP_HAS_REFS)) + { + gr->flags |= XML_SCHEMAS_ATTRGROUP_MARKED; + circ = xmlSchemaCheckAttrGroupCircularRecur(ctxtGr, + (xmlSchemaItemListPtr) gr->attrUses); + gr->flags ^= XML_SCHEMAS_ATTRGROUP_MARKED; + if (circ != NULL) + return (circ); + } + + } + } + return (NULL); +} + +/** + * xmlSchemaCheckAttrGroupCircular: + * attrGr: the attribute group definition + * @ctxt: the parser context + * @name: the name + * + * Checks for circular references of attribute groups. + */ +static int +xmlSchemaCheckAttrGroupCircular(xmlSchemaAttributeGroupPtr attrGr, + xmlSchemaParserCtxtPtr ctxt) +{ + /* + * Schema Representation Constraint: + * Attribute Group Definition Representation OK + * 3 Circular group reference is disallowed outside . + * That is, unless this element information item's parent is + * , then among the [children], if any, there must + * not be an with ref [attribute] which resolves + * to the component corresponding to this . Indirect + * circularity is also ruled out. That is, when QName resolution + * (Schema Document) (�3.15.3) is applied to a �QName� arising from + * any s with a ref [attribute] among the [children], + * it must not be the case that a �QName� is encountered at any depth + * which resolves to the component corresponding to this . + */ + if (attrGr->attrUses == NULL) + return(0); + else if ((attrGr->flags & XML_SCHEMAS_ATTRGROUP_HAS_REFS) == 0) + return(0); + else { + xmlSchemaQNameRefPtr circ; + + circ = xmlSchemaCheckAttrGroupCircularRecur(attrGr, + (xmlSchemaItemListPtr) attrGr->attrUses); + if (circ != NULL) { + xmlChar *str = NULL; + /* + * TODO: Report the referenced attr group as QName. + */ + xmlSchemaPCustomErr(ctxt, + XML_SCHEMAP_SRC_ATTRIBUTE_GROUP_3, + NULL, WXS_ITEM_NODE(WXS_BASIC_CAST circ), + "Circular reference to the attribute group '%s' " + "defined", xmlSchemaGetComponentQName(&str, attrGr)); + FREE_AND_NULL(str); + /* + * NOTE: We will cut the reference to avoid further + * confusion of the processor. + * BADSPEC TODO: The spec should define how to process in this case. + */ + circ->item = NULL; + return(ctxt->err); + } + } + return(0); +} + +static int +xmlSchemaAttributeGroupExpandRefs(xmlSchemaParserCtxtPtr pctxt, + xmlSchemaAttributeGroupPtr attrGr); + +/** + * xmlSchemaExpandAttributeGroupRefs: + * @pctxt: the parser context + * @node: the node of the component holding the attribute uses + * @completeWild: the intersected wildcard to be returned + * @list: the attribute uses + * + * Substitutes contained attribute group references + * for their attribute uses. Wilcards are intersected. + * Attribute use prohibitions are removed from the list + * and returned via the @prohibs list. + * Pointlessness of attr. prohibs, if a matching attr. decl + * is existent a well, are checked. + */ +static int +xmlSchemaExpandAttributeGroupRefs(xmlSchemaParserCtxtPtr pctxt, + xmlSchemaBasicItemPtr item, + xmlSchemaWildcardPtr *completeWild, + xmlSchemaItemListPtr list, + xmlSchemaItemListPtr prohibs) +{ + xmlSchemaAttributeGroupPtr gr; + xmlSchemaAttributeUsePtr use; + xmlSchemaItemListPtr sublist; + int i, j; + int created = (*completeWild == NULL) ? 0 : 1; + + if (prohibs) + prohibs->nbItems = 0; + + for (i = 0; i < list->nbItems; i++) { + use = list->items[i]; + + if (use->type == XML_SCHEMA_EXTRA_ATTR_USE_PROHIB) { + if (prohibs == NULL) { + PERROR_INT("xmlSchemaExpandAttributeGroupRefs", + "unexpected attr prohibition found"); + return(-1); + } + /* + * Remove from attribute uses. + */ + if (xmlSchemaItemListRemove(list, i) == -1) + return(-1); + i--; + /* + * Note that duplicate prohibitions were already + * handled at parsing time. + */ + /* + * Add to list of prohibitions. + */ + xmlSchemaItemListAddSize(prohibs, 2, use); + continue; + } + if ((use->type == XML_SCHEMA_EXTRA_QNAMEREF) && + ((WXS_QNAME_CAST use)->itemType == XML_SCHEMA_TYPE_ATTRIBUTEGROUP)) + { + if ((WXS_QNAME_CAST use)->item == NULL) + return(-1); + gr = WXS_ATTR_GROUP_CAST (WXS_QNAME_CAST use)->item; + /* + * Expand the referenced attr. group. + * TODO: remove this, this is done in a previous step, so + * already done here. + */ + if ((gr->flags & XML_SCHEMAS_ATTRGROUP_WILDCARD_BUILDED) == 0) { + if (xmlSchemaAttributeGroupExpandRefs(pctxt, gr) == -1) + return(-1); + } + /* + * Build the 'complete' wildcard; i.e. intersect multiple + * wildcards. + */ + if (gr->attributeWildcard != NULL) { + if (*completeWild == NULL) { + *completeWild = gr->attributeWildcard; + } else { + if (! created) { + xmlSchemaWildcardPtr tmpWild; + + /* + * Copy the first encountered wildcard as context, + * except for the annotation. + * + * Although the complete wildcard might not correspond + * to any node in the schema, we will anchor it on + * the node of the owner component. + */ + tmpWild = xmlSchemaAddWildcard(pctxt, pctxt->schema, + XML_SCHEMA_TYPE_ANY_ATTRIBUTE, + WXS_ITEM_NODE(item)); + if (tmpWild == NULL) + return(-1); + if (xmlSchemaCloneWildcardNsConstraints(pctxt, + tmpWild, *completeWild) == -1) + return (-1); + tmpWild->processContents = (*completeWild)->processContents; + *completeWild = tmpWild; + created = 1; + } + + if (xmlSchemaIntersectWildcards(pctxt, *completeWild, + gr->attributeWildcard) == -1) + return(-1); + } + } + /* + * Just remove the reference if the referenced group does not + * contain any attribute uses. + */ + sublist = ((xmlSchemaItemListPtr) gr->attrUses); + if ((sublist == NULL) || sublist->nbItems == 0) { + if (xmlSchemaItemListRemove(list, i) == -1) + return(-1); + i--; + continue; + } + /* + * Add the attribute uses. + */ + list->items[i] = sublist->items[0]; + if (sublist->nbItems != 1) { + for (j = 1; j < sublist->nbItems; j++) { + i++; + if (xmlSchemaItemListInsert(list, + sublist->items[j], i) == -1) + return(-1); + } + } + } + + } + /* + * Handle pointless prohibitions of declared attributes. + */ + if (prohibs && (prohibs->nbItems != 0) && (list->nbItems != 0)) { + xmlSchemaAttributeUseProhibPtr prohib; + + for (i = prohibs->nbItems -1; i >= 0; i--) { + prohib = prohibs->items[i]; + for (j = 0; j < list->nbItems; j++) { + use = list->items[j]; + + if ((prohib->name == WXS_ATTRUSE_DECL_NAME(use)) && + (prohib->targetNamespace == WXS_ATTRUSE_DECL_TNS(use))) + { + xmlChar *str = NULL; + + xmlSchemaCustomWarning(ACTXT_CAST pctxt, + XML_SCHEMAP_WARN_ATTR_POINTLESS_PROH, + prohib->node, NULL, + "Skipping pointless attribute use prohibition " + "'%s', since a corresponding attribute use " + "exists already in the type definition", + xmlSchemaFormatQName(&str, + prohib->targetNamespace, prohib->name), + NULL, NULL); + FREE_AND_NULL(str); + /* + * Remove the prohibition. + */ + if (xmlSchemaItemListRemove(prohibs, i) == -1) + return(-1); + break; + } + } + } + } + return(0); +} + +/** + * xmlSchemaAttributeGroupExpandRefs: + * @pctxt: the parser context + * @attrGr: the attribute group definition + * + * Computation of: + * {attribute uses} property + * {attribute wildcard} property + * + * Substitutes contained attribute group references + * for their attribute uses. Wilcards are intersected. + */ +static int +xmlSchemaAttributeGroupExpandRefs(xmlSchemaParserCtxtPtr pctxt, + xmlSchemaAttributeGroupPtr attrGr) +{ + if ((attrGr->attrUses == NULL) || + (attrGr->flags & XML_SCHEMAS_ATTRGROUP_WILDCARD_BUILDED)) + return(0); + + attrGr->flags |= XML_SCHEMAS_ATTRGROUP_WILDCARD_BUILDED; + if (xmlSchemaExpandAttributeGroupRefs(pctxt, WXS_BASIC_CAST attrGr, + &(attrGr->attributeWildcard), attrGr->attrUses, NULL) == -1) + return(-1); + return(0); +} + +/** + * xmlSchemaAttributeGroupExpandRefs: + * @pctxt: the parser context + * @attrGr: the attribute group definition + * + * Substitutes contained attribute group references + * for their attribute uses. Wilcards are intersected. + * + * Schema Component Constraint: + * Attribute Group Definition Properties Correct (ag-props-correct) + */ +static int +xmlSchemaCheckAGPropsCorrect(xmlSchemaParserCtxtPtr pctxt, + xmlSchemaAttributeGroupPtr attrGr) +{ + /* + * SPEC ag-props-correct + * (1) "The values of the properties of an attribute group definition + * must be as described in the property tableau in The Attribute + * Group Definition Schema Component (�3.6.1), modulo the impact of + * Missing Sub-components (�5.3);" + */ + + if ((attrGr->attrUses != NULL) && + (WXS_LIST_CAST attrGr->attrUses)->nbItems > 1) + { + xmlSchemaItemListPtr uses = WXS_LIST_CAST attrGr->attrUses; + xmlSchemaAttributeUsePtr use, tmp; + int i, j, hasId = 0; + + for (i = uses->nbItems -1; i >= 0; i--) { + use = uses->items[i]; + /* + * SPEC ag-props-correct + * (2) "Two distinct members of the {attribute uses} must not have + * {attribute declaration}s both of whose {name}s match and whose + * {target namespace}s are identical." + */ + if (i > 0) { + for (j = i -1; j >= 0; j--) { + tmp = uses->items[j]; + if ((WXS_ATTRUSE_DECL_NAME(use) == + WXS_ATTRUSE_DECL_NAME(tmp)) && + (WXS_ATTRUSE_DECL_TNS(use) == + WXS_ATTRUSE_DECL_TNS(tmp))) + { + xmlChar *str = NULL; + + xmlSchemaCustomErr(ACTXT_CAST pctxt, + XML_SCHEMAP_AG_PROPS_CORRECT, + attrGr->node, WXS_BASIC_CAST attrGr, + "Duplicate %s", + xmlSchemaGetComponentDesignation(&str, use), + NULL); + FREE_AND_NULL(str); + /* + * Remove the duplicate. + */ + if (xmlSchemaItemListRemove(uses, i) == -1) + return(-1); + goto next_use; + } + } + } + /* + * SPEC ag-props-correct + * (3) "Two distinct members of the {attribute uses} must not have + * {attribute declaration}s both of whose {type definition}s are or + * are derived from ID." + * TODO: Does 'derived' include member-types of unions? + */ + if (WXS_ATTRUSE_TYPEDEF(use) != NULL) { + if (xmlSchemaIsDerivedFromBuiltInType( + WXS_ATTRUSE_TYPEDEF(use), XML_SCHEMAS_ID)) + { + if (hasId) { + xmlChar *str = NULL; + + xmlSchemaCustomErr(ACTXT_CAST pctxt, + XML_SCHEMAP_AG_PROPS_CORRECT, + attrGr->node, WXS_BASIC_CAST attrGr, + "There must not exist more than one attribute " + "declaration of type 'xs:ID' " + "(or derived from 'xs:ID'). The %s violates this " + "constraint", + xmlSchemaGetComponentDesignation(&str, use), + NULL); + FREE_AND_NULL(str); + if (xmlSchemaItemListRemove(uses, i) == -1) + return(-1); + } + hasId = 1; + } + } +next_use: {} + } + } + return(0); +} + +/** + * xmlSchemaResolveAttrGroupReferences: + * @attrgrpDecl: the schema attribute definition + * @ctxt: the schema parser context + * @name: the attribute name + * + * Resolves references to attribute group definitions. + */ +static int +xmlSchemaResolveAttrGroupReferences(xmlSchemaQNameRefPtr ref, + xmlSchemaParserCtxtPtr ctxt) +{ + xmlSchemaAttributeGroupPtr group; + + if (ref->item != NULL) + return(0); + group = xmlSchemaGetAttributeGroup(ctxt->schema, + ref->name, + ref->targetNamespace); + if (group == NULL) { + xmlSchemaPResCompAttrErr(ctxt, + XML_SCHEMAP_SRC_RESOLVE, + NULL, ref->node, + "ref", ref->name, ref->targetNamespace, + ref->itemType, NULL); + return(ctxt->err); + } + ref->item = WXS_BASIC_CAST group; + return(0); +} + +/** + * xmlSchemaCheckAttrPropsCorrect: + * @item: an schema attribute declaration/use + * @ctxt: a schema parser context + * @name: the name of the attribute + * + * + * Schema Component Constraint: + * Attribute Declaration Properties Correct (a-props-correct) + * + * Validates the value constraints of an attribute declaration/use. + * NOTE that this needs the simle type definitions to be already + * builded and checked. + */ +static int +xmlSchemaCheckAttrPropsCorrect(xmlSchemaParserCtxtPtr pctxt, + xmlSchemaAttributePtr attr) +{ + + /* + * SPEC a-props-correct (1) + * "The values of the properties of an attribute declaration must + * be as described in the property tableau in The Attribute + * Declaration Schema Component (�3.2.1), modulo the impact of + * Missing Sub-components (�5.3)." + */ + + if (WXS_ATTR_TYPEDEF(attr) == NULL) + return(0); + + if (attr->defValue != NULL) { + int ret; + + /* + * SPEC a-props-correct (3) + * "If the {type definition} is or is derived from ID then there + * must not be a {value constraint}." + */ + if (xmlSchemaIsDerivedFromBuiltInType( + WXS_ATTR_TYPEDEF(attr), XML_SCHEMAS_ID)) + { + xmlSchemaCustomErr(ACTXT_CAST pctxt, + XML_SCHEMAP_A_PROPS_CORRECT_3, + NULL, WXS_BASIC_CAST attr, + "Value constraints are not allowed if the type definition " + "is or is derived from xs:ID", + NULL, NULL); + return(pctxt->err); + } + /* + * SPEC a-props-correct (2) + * "if there is a {value constraint}, the canonical lexical + * representation of its value must be �valid� with respect + * to the {type definition} as defined in String Valid (�3.14.4)." + * TODO: Don't care about the *cononical* stuff here, this requirement + * will be removed in WXS 1.1 anyway. + */ + ret = xmlSchemaVCheckCVCSimpleType(ACTXT_CAST pctxt, + attr->node, WXS_ATTR_TYPEDEF(attr), + attr->defValue, &(attr->defVal), + 1, 1, 0); + if (ret != 0) { + if (ret < 0) { + PERROR_INT("xmlSchemaCheckAttrPropsCorrect", + "calling xmlSchemaVCheckCVCSimpleType()"); + return(-1); + } + xmlSchemaCustomErr(ACTXT_CAST pctxt, + XML_SCHEMAP_A_PROPS_CORRECT_2, + NULL, WXS_BASIC_CAST attr, + "The value of the value constraint is not valid", + NULL, NULL); + return(pctxt->err); + } + } + + return(0); +} + +static xmlSchemaElementPtr +xmlSchemaCheckSubstGroupCircular(xmlSchemaElementPtr elemDecl, + xmlSchemaElementPtr ancestor) +{ + xmlSchemaElementPtr ret; + + if (WXS_SUBST_HEAD(ancestor) == NULL) + return (NULL); + if (WXS_SUBST_HEAD(ancestor) == elemDecl) + return (ancestor); + + if (WXS_SUBST_HEAD(ancestor)->flags & XML_SCHEMAS_ELEM_CIRCULAR) + return (NULL); + WXS_SUBST_HEAD(ancestor)->flags |= XML_SCHEMAS_ELEM_CIRCULAR; + ret = xmlSchemaCheckSubstGroupCircular(elemDecl, + WXS_SUBST_HEAD(ancestor)); + WXS_SUBST_HEAD(ancestor)->flags ^= XML_SCHEMAS_ELEM_CIRCULAR; + + return (ret); +} + +/** + * xmlSchemaCheckElemPropsCorrect: + * @ctxt: a schema parser context + * @decl: the element declaration + * @name: the name of the attribute + * + * Schema Component Constraint: + * Element Declaration Properties Correct (e-props-correct) + * + * STATUS: + * missing: (6) + */ +static int +xmlSchemaCheckElemPropsCorrect(xmlSchemaParserCtxtPtr pctxt, + xmlSchemaElementPtr elemDecl) +{ + int ret = 0; + xmlSchemaTypePtr typeDef = WXS_ELEM_TYPEDEF(elemDecl); + /* + * SPEC (1) "The values of the properties of an element declaration + * must be as described in the property tableau in The Element + * Declaration Schema Component (�3.3.1), modulo the impact of Missing + * Sub-components (�5.3)." + */ + if (WXS_SUBST_HEAD(elemDecl) != NULL) { + xmlSchemaElementPtr head = WXS_SUBST_HEAD(elemDecl), circ; + + xmlSchemaCheckElementDeclComponent(head, pctxt); + /* + * SPEC (3) "If there is a non-�absent� {substitution group + * affiliation}, then {scope} must be global." + */ + if ((elemDecl->flags & XML_SCHEMAS_ELEM_GLOBAL) == 0) { + xmlSchemaPCustomErr(pctxt, + XML_SCHEMAP_E_PROPS_CORRECT_3, + WXS_BASIC_CAST elemDecl, NULL, + "Only global element declarations can have a " + "substitution group affiliation", NULL); + ret = XML_SCHEMAP_E_PROPS_CORRECT_3; + } + /* + * TODO: SPEC (6) "Circular substitution groups are disallowed. + * That is, it must not be possible to return to an element declaration + * by repeatedly following the {substitution group affiliation} + * property." + */ + if (head == elemDecl) + circ = head; + else if (WXS_SUBST_HEAD(head) != NULL) + circ = xmlSchemaCheckSubstGroupCircular(head, head); + else + circ = NULL; + if (circ != NULL) { + xmlChar *strA = NULL, *strB = NULL; + + xmlSchemaPCustomErrExt(pctxt, + XML_SCHEMAP_E_PROPS_CORRECT_6, + WXS_BASIC_CAST circ, NULL, + "The element declaration '%s' defines a circular " + "substitution group to element declaration '%s'", + xmlSchemaGetComponentQName(&strA, circ), + xmlSchemaGetComponentQName(&strB, head), + NULL); + FREE_AND_NULL(strA) + FREE_AND_NULL(strB) + ret = XML_SCHEMAP_E_PROPS_CORRECT_6; + } + /* + * SPEC (4) "If there is a {substitution group affiliation}, + * the {type definition} + * of the element declaration must be validly derived from the {type + * definition} of the {substitution group affiliation}, given the value + * of the {substitution group exclusions} of the {substitution group + * affiliation}, as defined in Type Derivation OK (Complex) (�3.4.6) + * (if the {type definition} is complex) or as defined in + * Type Derivation OK (Simple) (�3.14.6) (if the {type definition} is + * simple)." + * + * NOTE: {substitution group exclusions} means the values of the + * attribute "final". + */ + + if (typeDef != WXS_ELEM_TYPEDEF(WXS_SUBST_HEAD(elemDecl))) { + int set = 0; + + if (head->flags & XML_SCHEMAS_ELEM_FINAL_EXTENSION) + set |= SUBSET_EXTENSION; + if (head->flags & XML_SCHEMAS_ELEM_FINAL_RESTRICTION) + set |= SUBSET_RESTRICTION; + + if (xmlSchemaCheckCOSDerivedOK(ACTXT_CAST pctxt, typeDef, + WXS_ELEM_TYPEDEF(head), set) != 0) { + xmlChar *strA = NULL, *strB = NULL, *strC = NULL; + + ret = XML_SCHEMAP_E_PROPS_CORRECT_4; + xmlSchemaPCustomErrExt(pctxt, + XML_SCHEMAP_E_PROPS_CORRECT_4, + WXS_BASIC_CAST elemDecl, NULL, + "The type definition '%s' was " + "either rejected by the substitution group " + "affiliation '%s', or not validly derived from its type " + "definition '%s'", + xmlSchemaGetComponentQName(&strA, typeDef), + xmlSchemaGetComponentQName(&strB, head), + xmlSchemaGetComponentQName(&strC, WXS_ELEM_TYPEDEF(head))); + FREE_AND_NULL(strA) + FREE_AND_NULL(strB) + FREE_AND_NULL(strC) + } + } + } + /* + * SPEC (5) "If the {type definition} or {type definition}'s + * {content type} + * is or is derived from ID then there must not be a {value constraint}. + * Note: The use of ID as a type definition for elements goes beyond + * XML 1.0, and should be avoided if backwards compatibility is desired" + */ + if ((elemDecl->value != NULL) && + ((WXS_IS_SIMPLE(typeDef) && + xmlSchemaIsDerivedFromBuiltInType(typeDef, XML_SCHEMAS_ID)) || + (WXS_IS_COMPLEX(typeDef) && + WXS_HAS_SIMPLE_CONTENT(typeDef) && + xmlSchemaIsDerivedFromBuiltInType(typeDef->contentTypeDef, + XML_SCHEMAS_ID)))) { + + ret = XML_SCHEMAP_E_PROPS_CORRECT_5; + xmlSchemaPCustomErr(pctxt, + XML_SCHEMAP_E_PROPS_CORRECT_5, + WXS_BASIC_CAST elemDecl, NULL, + "The type definition (or type definition's content type) is or " + "is derived from ID; value constraints are not allowed in " + "conjunction with such a type definition", NULL); + } else if (elemDecl->value != NULL) { + int vcret; + xmlNodePtr node = NULL; + + /* + * SPEC (2) "If there is a {value constraint}, the canonical lexical + * representation of its value must be �valid� with respect to the + * {type definition} as defined in Element Default Valid (Immediate) + * (�3.3.6)." + */ + if (typeDef == NULL) { + xmlSchemaPErr(pctxt, elemDecl->node, + XML_SCHEMAP_INTERNAL, + "Internal error: xmlSchemaCheckElemPropsCorrect, " + "type is missing... skipping validation of " + "the value constraint", NULL, NULL); + return (-1); + } + if (elemDecl->node != NULL) { + if (elemDecl->flags & XML_SCHEMAS_ELEM_FIXED) + node = (xmlNodePtr) xmlHasProp(elemDecl->node, + BAD_CAST "fixed"); + else + node = (xmlNodePtr) xmlHasProp(elemDecl->node, + BAD_CAST "default"); + } + vcret = xmlSchemaParseCheckCOSValidDefault(pctxt, node, + typeDef, elemDecl->value, &(elemDecl->defVal)); + if (vcret != 0) { + if (vcret < 0) { + PERROR_INT("xmlSchemaElemCheckValConstr", + "failed to validate the value constraint of an " + "element declaration"); + return (-1); + } + return (vcret); + } + } + + return (ret); +} + +/** + * xmlSchemaCheckElemSubstGroup: + * @ctxt: a schema parser context + * @decl: the element declaration + * @name: the name of the attribute + * + * Schema Component Constraint: + * Substitution Group (cos-equiv-class) + * + * In Libxml2 the subst. groups will be precomputed, in terms of that + * a list will be built for each subst. group head, holding all direct + * referents to this head. + * NOTE that this function needs: + * 1. circular subst. groups to be checked beforehand + * 2. the declaration's type to be derived from the head's type + * + * STATUS: + * + */ +static void +xmlSchemaCheckElemSubstGroup(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaElementPtr elemDecl) +{ + if ((WXS_SUBST_HEAD(elemDecl) == NULL) || + /* SPEC (1) "Its {abstract} is false." */ + (elemDecl->flags & XML_SCHEMAS_ELEM_ABSTRACT)) + return; + { + xmlSchemaElementPtr head; + xmlSchemaTypePtr headType, type; + int set, methSet; + /* + * SPEC (2) "It is validly substitutable for HEAD subject to HEAD's + * {disallowed substitutions} as the blocking constraint, as defined in + * Substitution Group OK (Transitive) (�3.3.6)." + */ + for (head = WXS_SUBST_HEAD(elemDecl); head != NULL; + head = WXS_SUBST_HEAD(head)) { + set = 0; + methSet = 0; + /* + * The blocking constraints. + */ + if (head->flags & XML_SCHEMAS_ELEM_BLOCK_SUBSTITUTION) + continue; + headType = head->subtypes; + type = elemDecl->subtypes; + if (headType == type) + goto add_member; + if (head->flags & XML_SCHEMAS_ELEM_BLOCK_RESTRICTION) + set |= XML_SCHEMAS_TYPE_BLOCK_RESTRICTION; + if (head->flags & XML_SCHEMAS_ELEM_BLOCK_EXTENSION) + set |= XML_SCHEMAS_TYPE_BLOCK_EXTENSION; + /* + * SPEC: Substitution Group OK (Transitive) (2.3) + * "The set of all {derivation method}s involved in the + * derivation of D's {type definition} from C's {type definition} + * does not intersect with the union of the blocking constraint, + * C's {prohibited substitutions} (if C is complex, otherwise the + * empty set) and the {prohibited substitutions} (respectively the + * empty set) of any intermediate {type definition}s in the + * derivation of D's {type definition} from C's {type definition}." + */ + /* + * OPTIMIZE TODO: Optimize this a bit, since, if traversing the + * subst.head axis, the methSet does not need to be computed for + * the full depth over and over. + */ + /* + * The set of all {derivation method}s involved in the derivation + */ + while ((type != NULL) && (type != headType)) { + if ((WXS_IS_EXTENSION(type)) && + ((methSet & XML_SCHEMAS_TYPE_BLOCK_RESTRICTION) == 0)) + methSet |= XML_SCHEMAS_TYPE_BLOCK_EXTENSION; + + if (WXS_IS_RESTRICTION(type) && + ((methSet & XML_SCHEMAS_TYPE_BLOCK_RESTRICTION) == 0)) + methSet |= XML_SCHEMAS_TYPE_BLOCK_RESTRICTION; + + type = type->baseType; + } + /* + * The {prohibited substitutions} of all intermediate types + + * the head's type. + */ + type = elemDecl->subtypes->baseType; + while (type != NULL) { + if (WXS_IS_COMPLEX(type)) { + if ((type->flags & + XML_SCHEMAS_TYPE_BLOCK_EXTENSION) && + ((set & XML_SCHEMAS_TYPE_BLOCK_EXTENSION) == 0)) + set |= XML_SCHEMAS_TYPE_BLOCK_EXTENSION; + if ((type->flags & + XML_SCHEMAS_TYPE_BLOCK_RESTRICTION) && + ((set & XML_SCHEMAS_TYPE_BLOCK_RESTRICTION) == 0)) + set |= XML_SCHEMAS_TYPE_BLOCK_RESTRICTION; + } else + break; + if (type == headType) + break; + type = type->baseType; + } + if ((set != 0) && + (((set & XML_SCHEMAS_TYPE_BLOCK_EXTENSION) && + (methSet & XML_SCHEMAS_TYPE_BLOCK_EXTENSION)) || + ((set & XML_SCHEMAS_TYPE_BLOCK_RESTRICTION) && + (methSet & XML_SCHEMAS_TYPE_BLOCK_RESTRICTION)))) { + continue; + } +add_member: + xmlSchemaAddElementSubstitutionMember(ctxt, head, elemDecl); + if ((head->flags & XML_SCHEMAS_ELEM_SUBST_GROUP_HEAD) == 0) + head->flags |= XML_SCHEMAS_ELEM_SUBST_GROUP_HEAD; + } + } +} + +#ifdef WXS_ELEM_DECL_CONS_ENABLED /* enable when finished */ +/** + * xmlSchemaCheckElementDeclComponent + * @pctxt: the schema parser context + * @ctxtComponent: the context component (an element declaration) + * @ctxtParticle: the first particle of the context component + * @searchParticle: the element declaration particle to be analysed + * + * Schema Component Constraint: Element Declarations Consistent + */ +static int +xmlSchemaCheckElementDeclConsistent(xmlSchemaParserCtxtPtr pctxt, + xmlSchemaBasicItemPtr ctxtComponent, + xmlSchemaParticlePtr ctxtParticle, + xmlSchemaParticlePtr searchParticle, + xmlSchemaParticlePtr curParticle, + int search) +{ + return(0); + + int ret = 0; + xmlSchemaParticlePtr cur = curParticle; + if (curParticle == NULL) { + return(0); + } + if (WXS_PARTICLE_TERM(curParticle) == NULL) { + /* + * Just return in this case. A missing "term" of the particle + * might arise due to an invalid "term" component. + */ + return(0); + } + while (cur != NULL) { + switch (WXS_PARTICLE_TERM(cur)->type) { + case XML_SCHEMA_TYPE_ANY: + break; + case XML_SCHEMA_TYPE_ELEMENT: + if (search == 0) { + ret = xmlSchemaCheckElementDeclConsistent(pctxt, + ctxtComponent, ctxtParticle, cur, ctxtParticle, 1); + if (ret != 0) + return(ret); + } else { + xmlSchemaElementPtr elem = + WXS_ELEM_CAST(WXS_PARTICLE_TERM(cur)); + /* + * SPEC Element Declarations Consistent: + * "If the {particles} contains, either directly, + * indirectly (that is, within the {particles} of a + * contained model group, recursively) or �implicitly� + * two or more element declaration particles with + * the same {name} and {target namespace}, then + * all their type definitions must be the same + * top-level definition [...]" + */ + if (xmlStrEqual(WXS_PARTICLE_TERM_AS_ELEM(cur)->name, + WXS_PARTICLE_TERM_AS_ELEM(searchParticle)->name) && + xmlStrEqual(WXS_PARTICLE_TERM_AS_ELEM(cur)->targetNamespace, + WXS_PARTICLE_TERM_AS_ELEM(searchParticle)->targetNamespace)) + { + xmlChar *strA = NULL, *strB = NULL; + + xmlSchemaCustomErr(ACTXT_CAST pctxt, + /* TODO: error code */ + XML_SCHEMAP_COS_NONAMBIG, + WXS_ITEM_NODE(cur), NULL, + "In the content model of %s, there are multiple " + "element declarations for '%s' with different " + "type definitions", + xmlSchemaGetComponentDesignation(&strA, + ctxtComponent), + xmlSchemaFormatQName(&strB, + WXS_PARTICLE_TERM_AS_ELEM(cur)->targetNamespace, + WXS_PARTICLE_TERM_AS_ELEM(cur)->name)); + FREE_AND_NULL(strA); + FREE_AND_NULL(strB); + return(XML_SCHEMAP_COS_NONAMBIG); + } + } + break; + case XML_SCHEMA_TYPE_SEQUENCE: { + break; + } + case XML_SCHEMA_TYPE_CHOICE:{ + /* + xmlSchemaTreeItemPtr sub; + + sub = WXS_PARTICLE_TERM(particle)->children; (xmlSchemaParticlePtr) + while (sub != NULL) { + ret = xmlSchemaCheckElementDeclConsistent(pctxt, ctxtComponent, + ctxtParticle, ctxtElem); + if (ret != 0) + return(ret); + sub = sub->next; + } + */ + break; + } + case XML_SCHEMA_TYPE_ALL: + break; + case XML_SCHEMA_TYPE_GROUP: + break; + default: + xmlSchemaInternalErr2(ACTXT_CAST pctxt, + "xmlSchemaCheckElementDeclConsistent", + "found unexpected term of type '%s' in content model", + WXS_ITEM_TYPE_NAME(WXS_PARTICLE_TERM(cur)), NULL); + return(-1); + } + cur = (xmlSchemaParticlePtr) cur->next; + } + +exit: + return(ret); +} +#endif + +/** + * xmlSchemaCheckElementDeclComponent + * @item: an schema element declaration/particle + * @ctxt: a schema parser context + * @name: the name of the attribute + * + * Validates the value constraints of an element declaration. + * Adds substitution group members. + */ +static void +xmlSchemaCheckElementDeclComponent(xmlSchemaElementPtr elemDecl, + xmlSchemaParserCtxtPtr ctxt) +{ + if (elemDecl == NULL) + return; + if (elemDecl->flags & XML_SCHEMAS_ELEM_INTERNAL_CHECKED) + return; + elemDecl->flags |= XML_SCHEMAS_ELEM_INTERNAL_CHECKED; + if (xmlSchemaCheckElemPropsCorrect(ctxt, elemDecl) == 0) { + /* + * Adds substitution group members. + */ + xmlSchemaCheckElemSubstGroup(ctxt, elemDecl); + } +} + +/** + * xmlSchemaResolveModelGroupParticleReferences: + * @particle: a particle component + * @ctxt: a parser context + * + * Resolves references of a model group's {particles} to + * model group definitions and to element declarations. + */ +static void +xmlSchemaResolveModelGroupParticleReferences( + xmlSchemaParserCtxtPtr ctxt, + xmlSchemaModelGroupPtr mg) +{ + xmlSchemaParticlePtr particle = WXS_MODELGROUP_PARTICLE(mg); + xmlSchemaQNameRefPtr ref; + xmlSchemaBasicItemPtr refItem; + + /* + * URGENT TODO: Test this. + */ + while (particle != NULL) { + if ((WXS_PARTICLE_TERM(particle) == NULL) || + ((WXS_PARTICLE_TERM(particle))->type != + XML_SCHEMA_EXTRA_QNAMEREF)) + { + goto next_particle; + } + ref = WXS_QNAME_CAST WXS_PARTICLE_TERM(particle); + /* + * Resolve the reference. + * NULL the {term} by default. + */ + particle->children = NULL; + + refItem = xmlSchemaGetNamedComponent(ctxt->schema, + ref->itemType, ref->name, ref->targetNamespace); + if (refItem == NULL) { + xmlSchemaPResCompAttrErr(ctxt, XML_SCHEMAP_SRC_RESOLVE, + NULL, WXS_ITEM_NODE(particle), "ref", ref->name, + ref->targetNamespace, ref->itemType, NULL); + /* TODO: remove the particle. */ + goto next_particle; + } + if (refItem->type == XML_SCHEMA_TYPE_GROUP) { + if (WXS_MODELGROUPDEF_MODEL(refItem) == NULL) + /* TODO: remove the particle. */ + goto next_particle; + /* + * NOTE that we will assign the model group definition + * itself to the "term" of the particle. This will ease + * the check for circular model group definitions. After + * that the "term" will be assigned the model group of the + * model group definition. + */ + if ((WXS_MODELGROUPDEF_MODEL(refItem))->type == + XML_SCHEMA_TYPE_ALL) { + /* + * SPEC cos-all-limited (1) + * SPEC cos-all-limited (1.2) + * "It appears only as the value of one or both of the + * following properties:" + * (1.1) "the {model group} property of a model group + * definition." + * (1.2) "the {term} property of a particle [... of] the " + * {content type} of a complex type definition." + */ + xmlSchemaCustomErr(ACTXT_CAST ctxt, + /* TODO: error code */ + XML_SCHEMAP_COS_ALL_LIMITED, + WXS_ITEM_NODE(particle), NULL, + "A model group definition is referenced, but " + "it contains an 'all' model group, which " + "cannot be contained by model groups", + NULL, NULL); + /* TODO: remove the particle. */ + goto next_particle; + } + particle->children = (xmlSchemaTreeItemPtr) refItem; + } else { + /* + * TODO: Are referenced element declarations the only + * other components we expect here? + */ + particle->children = (xmlSchemaTreeItemPtr) refItem; + } +next_particle: + particle = WXS_PTC_CAST particle->next; + } +} + +static int +xmlSchemaAreValuesEqual(xmlSchemaValPtr x, + xmlSchemaValPtr y) +{ + xmlSchemaTypePtr tx, ty, ptx, pty; + int ret; + + while (x != NULL) { + /* Same types. */ + tx = xmlSchemaGetBuiltInType(xmlSchemaGetValType(x)); + ty = xmlSchemaGetBuiltInType(xmlSchemaGetValType(y)); + ptx = xmlSchemaGetPrimitiveType(tx); + pty = xmlSchemaGetPrimitiveType(ty); + /* + * (1) if a datatype T' is �derived� by �restriction� from an + * atomic datatype T then the �value space� of T' is a subset of + * the �value space� of T. */ + /* + * (2) if datatypes T' and T'' are �derived� by �restriction� + * from a common atomic ancestor T then the �value space�s of T' + * and T'' may overlap. + */ + if (ptx != pty) + return(0); + /* + * We assume computed values to be normalized, so do a fast + * string comparison for string based types. + */ + if ((ptx->builtInType == XML_SCHEMAS_STRING) || + WXS_IS_ANY_SIMPLE_TYPE(ptx)) { + if (! xmlStrEqual( + xmlSchemaValueGetAsString(x), + xmlSchemaValueGetAsString(y))) + return (0); + } else { + ret = xmlSchemaCompareValuesWhtsp( + x, XML_SCHEMA_WHITESPACE_PRESERVE, + y, XML_SCHEMA_WHITESPACE_PRESERVE); + if (ret == -2) + return(-1); + if (ret != 0) + return(0); + } + /* + * Lists. + */ + x = xmlSchemaValueGetNext(x); + if (x != NULL) { + y = xmlSchemaValueGetNext(y); + if (y == NULL) + return (0); + } else if (xmlSchemaValueGetNext(y) != NULL) + return (0); + else + return (1); + } + return (0); +} + +/** + * xmlSchemaResolveAttrUseReferences: + * @item: an attribute use + * @ctxt: a parser context + * + * Resolves the referenced attribute declaration. + */ +static int +xmlSchemaResolveAttrUseReferences(xmlSchemaAttributeUsePtr ause, + xmlSchemaParserCtxtPtr ctxt) +{ + if ((ctxt == NULL) || (ause == NULL)) + return(-1); + if ((ause->attrDecl == NULL) || + (ause->attrDecl->type != XML_SCHEMA_EXTRA_QNAMEREF)) + return(0); + + { + xmlSchemaQNameRefPtr ref = WXS_QNAME_CAST ause->attrDecl; + + /* + * TODO: Evaluate, what errors could occur if the declaration is not + * found. + */ + ause->attrDecl = xmlSchemaGetAttributeDecl(ctxt->schema, + ref->name, ref->targetNamespace); + if (ause->attrDecl == NULL) { + xmlSchemaPResCompAttrErr(ctxt, + XML_SCHEMAP_SRC_RESOLVE, + WXS_BASIC_CAST ause, ause->node, + "ref", ref->name, ref->targetNamespace, + XML_SCHEMA_TYPE_ATTRIBUTE, NULL); + return(ctxt->err);; + } + } + return(0); +} + +/** + * xmlSchemaCheckAttrUsePropsCorrect: + * @ctxt: a parser context + * @use: an attribute use + * + * Schema Component Constraint: + * Attribute Use Correct (au-props-correct) + * + */ +static int +xmlSchemaCheckAttrUsePropsCorrect(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaAttributeUsePtr use) +{ + if ((ctxt == NULL) || (use == NULL)) + return(-1); + if ((use->defValue == NULL) || (WXS_ATTRUSE_DECL(use) == NULL) || + ((WXS_ATTRUSE_DECL(use))->type != XML_SCHEMA_TYPE_ATTRIBUTE)) + return(0); + + /* + * SPEC au-props-correct (1) + * "The values of the properties of an attribute use must be as + * described in the property tableau in The Attribute Use Schema + * Component (�3.5.1), modulo the impact of Missing + * Sub-components (�5.3)." + */ + + if (((WXS_ATTRUSE_DECL(use))->defValue != NULL) && + ((WXS_ATTRUSE_DECL(use))->flags & XML_SCHEMAS_ATTR_FIXED) && + ((use->flags & XML_SCHEMA_ATTR_USE_FIXED) == 0)) + { + xmlSchemaPCustomErr(ctxt, + XML_SCHEMAP_AU_PROPS_CORRECT_2, + WXS_BASIC_CAST use, NULL, + "The attribute declaration has a 'fixed' value constraint " + ", thus the attribute use must also have a 'fixed' value " + "constraint", + NULL); + return(ctxt->err); + } + /* + * Compute and check the value constraint's value. + */ + if ((use->defVal != NULL) && (WXS_ATTRUSE_TYPEDEF(use) != NULL)) { + int ret; + /* + * TODO: The spec seems to be missing a check of the + * value constraint of the attribute use. We will do it here. + */ + /* + * SPEC a-props-correct (3) + */ + if (xmlSchemaIsDerivedFromBuiltInType( + WXS_ATTRUSE_TYPEDEF(use), XML_SCHEMAS_ID)) + { + xmlSchemaCustomErr(ACTXT_CAST ctxt, + XML_SCHEMAP_AU_PROPS_CORRECT, + NULL, WXS_BASIC_CAST use, + "Value constraints are not allowed if the type definition " + "is or is derived from xs:ID", + NULL, NULL); + return(ctxt->err); + } + + ret = xmlSchemaVCheckCVCSimpleType(ACTXT_CAST ctxt, + use->node, WXS_ATTRUSE_TYPEDEF(use), + use->defValue, &(use->defVal), + 1, 1, 0); + if (ret != 0) { + if (ret < 0) { + PERROR_INT2("xmlSchemaCheckAttrUsePropsCorrect", + "calling xmlSchemaVCheckCVCSimpleType()"); + return(-1); + } + xmlSchemaCustomErr(ACTXT_CAST ctxt, + XML_SCHEMAP_AU_PROPS_CORRECT, + NULL, WXS_BASIC_CAST use, + "The value of the value constraint is not valid", + NULL, NULL); + return(ctxt->err); + } + } + /* + * SPEC au-props-correct (2) + * "If the {attribute declaration} has a fixed + * {value constraint}, then if the attribute use itself has a + * {value constraint}, it must also be fixed and its value must match + * that of the {attribute declaration}'s {value constraint}." + */ + if (((WXS_ATTRUSE_DECL(use))->defVal != NULL) && + (((WXS_ATTRUSE_DECL(use))->flags & XML_SCHEMA_ATTR_USE_FIXED) == 0)) + { + if (! xmlSchemaAreValuesEqual(use->defVal, + (WXS_ATTRUSE_DECL(use))->defVal)) + { + xmlSchemaPCustomErr(ctxt, + XML_SCHEMAP_AU_PROPS_CORRECT_2, + WXS_BASIC_CAST use, NULL, + "The 'fixed' value constraint of the attribute use " + "must match the attribute declaration's value " + "constraint '%s'", + (WXS_ATTRUSE_DECL(use))->defValue); + } + return(ctxt->err); + } + return(0); +} + + + + +/** + * xmlSchemaResolveAttrTypeReferences: + * @item: an attribute declaration + * @ctxt: a parser context + * + * Resolves the referenced type definition component. + */ +static int +xmlSchemaResolveAttrTypeReferences(xmlSchemaAttributePtr item, + xmlSchemaParserCtxtPtr ctxt) +{ + /* + * The simple type definition corresponding to the element + * information item in the [children], if present, otherwise the simple + * type definition �resolved� to by the �actual value� of the type + * [attribute], if present, otherwise the �simple ur-type definition�. + */ + if (item->flags & XML_SCHEMAS_ATTR_INTERNAL_RESOLVED) + return(0); + item->flags |= XML_SCHEMAS_ATTR_INTERNAL_RESOLVED; + if (item->subtypes != NULL) + return(0); + if (item->typeName != NULL) { + xmlSchemaTypePtr type; + + type = xmlSchemaGetType(ctxt->schema, item->typeName, + item->typeNs); + if ((type == NULL) || (! WXS_IS_SIMPLE(type))) { + xmlSchemaPResCompAttrErr(ctxt, + XML_SCHEMAP_SRC_RESOLVE, + WXS_BASIC_CAST item, item->node, + "type", item->typeName, item->typeNs, + XML_SCHEMA_TYPE_SIMPLE, NULL); + return(ctxt->err); + } else + item->subtypes = type; + + } else { + /* + * The type defaults to the xs:anySimpleType. + */ + item->subtypes = xmlSchemaGetBuiltInType(XML_SCHEMAS_ANYSIMPLETYPE); + } + return(0); +} + +/** + * xmlSchemaResolveIDCKeyReferences: + * @idc: the identity-constraint definition + * @ctxt: the schema parser context + * @name: the attribute name + * + * Resolve keyRef references to key/unique IDCs. + * Schema Component Constraint: + * Identity-constraint Definition Properties Correct (c-props-correct) + */ +static int +xmlSchemaResolveIDCKeyReferences(xmlSchemaIDCPtr idc, + xmlSchemaParserCtxtPtr pctxt) +{ + if (idc->type != XML_SCHEMA_TYPE_IDC_KEYREF) + return(0); + if (idc->ref->name != NULL) { + idc->ref->item = (xmlSchemaBasicItemPtr) + xmlSchemaGetIDC(pctxt->schema, idc->ref->name, + idc->ref->targetNamespace); + if (idc->ref->item == NULL) { + /* + * TODO: It is actually not an error to fail to resolve + * at this stage. BUT we need to be that strict! + */ + xmlSchemaPResCompAttrErr(pctxt, + XML_SCHEMAP_SRC_RESOLVE, + WXS_BASIC_CAST idc, idc->node, + "refer", idc->ref->name, + idc->ref->targetNamespace, + XML_SCHEMA_TYPE_IDC_KEY, NULL); + return(pctxt->err); + } else if (idc->ref->item->type == XML_SCHEMA_TYPE_IDC_KEYREF) { + /* + * SPEC c-props-correct (1) + */ + xmlSchemaCustomErr(ACTXT_CAST pctxt, + XML_SCHEMAP_C_PROPS_CORRECT, + NULL, WXS_BASIC_CAST idc, + "The keyref references a keyref", + NULL, NULL); + idc->ref->item = NULL; + return(pctxt->err); + } else { + if (idc->nbFields != + ((xmlSchemaIDCPtr) idc->ref->item)->nbFields) { + xmlChar *str = NULL; + xmlSchemaIDCPtr refer; + + refer = (xmlSchemaIDCPtr) idc->ref->item; + /* + * SPEC c-props-correct(2) + * "If the {identity-constraint category} is keyref, + * the cardinality of the {fields} must equal that of + * the {fields} of the {referenced key}. + */ + xmlSchemaCustomErr(ACTXT_CAST pctxt, + XML_SCHEMAP_C_PROPS_CORRECT, + NULL, WXS_BASIC_CAST idc, + "The cardinality of the keyref differs from the " + "cardinality of the referenced key/unique '%s'", + xmlSchemaFormatQName(&str, refer->targetNamespace, + refer->name), + NULL); + FREE_AND_NULL(str) + return(pctxt->err); + } + } + } + return(0); +} + +static int +xmlSchemaResolveAttrUseProhibReferences(xmlSchemaAttributeUseProhibPtr prohib, + xmlSchemaParserCtxtPtr pctxt) +{ + if (xmlSchemaGetAttributeDecl(pctxt->schema, prohib->name, + prohib->targetNamespace) == NULL) { + + xmlSchemaPResCompAttrErr(pctxt, + XML_SCHEMAP_SRC_RESOLVE, + NULL, prohib->node, + "ref", prohib->name, prohib->targetNamespace, + XML_SCHEMA_TYPE_ATTRIBUTE, NULL); + return(XML_SCHEMAP_SRC_RESOLVE); + } + return(0); +} + +#define WXS_REDEFINED_TYPE(c) \ +(((xmlSchemaTypePtr) item)->flags & XML_SCHEMAS_TYPE_REDEFINED) + +#define WXS_REDEFINED_MODEL_GROUP_DEF(c) \ +(((xmlSchemaModelGroupDefPtr) item)->flags & XML_SCHEMA_MODEL_GROUP_DEF_REDEFINED) + +#define WXS_REDEFINED_ATTR_GROUP(c) \ +(((xmlSchemaAttributeGroupPtr) item)->flags & XML_SCHEMAS_ATTRGROUP_REDEFINED) + +static int +xmlSchemaCheckSRCRedefineFirst(xmlSchemaParserCtxtPtr pctxt) +{ + int err = 0; + xmlSchemaRedefPtr redef = WXS_CONSTRUCTOR(pctxt)->redefs; + xmlSchemaBasicItemPtr prev, item; + int wasRedefined; + + if (redef == NULL) + return(0); + + do { + item = redef->item; + /* + * First try to locate the redefined component in the + * schema graph starting with the redefined schema. + * NOTE: According to this schema bug entry: + * http://lists.w3.org/Archives/Public/www-xml-schema-comments/2005OctDec/0019.html + * it's not clear if the referenced component needs to originate + * from the d schema _document_ or the schema; the latter + * would include all imported and included sub-schemas of the + * d schema. Currenlty we latter approach is used. + * SUPPLEMENT: It seems that the WG moves towards the latter + * approach, so we are doing it right. + * + */ + prev = xmlSchemaFindRedefCompInGraph( + redef->targetBucket, item->type, + redef->refName, redef->refTargetNs); + if (prev == NULL) { + xmlChar *str = NULL; + xmlNodePtr node; + + /* + * SPEC src-redefine: + * (6.2.1) "The �actual value� of its own name attribute plus + * target namespace must successfully �resolve� to a model + * group definition in I." + * (7.2.1) "The �actual value� of its own name attribute plus + * target namespace must successfully �resolve� to an attribute + * group definition in I." + + * + * Note that, if we are redefining with the use of references + * to components, the spec assumes the src-resolve to be used; + * but this won't assure that we search only *inside* the + * redefined schema. + */ + if (redef->reference) + node = WXS_ITEM_NODE(redef->reference); + else + node = WXS_ITEM_NODE(item); + xmlSchemaCustomErr(ACTXT_CAST pctxt, + /* + * TODO: error code. + * Probably XML_SCHEMAP_SRC_RESOLVE, if this is using the + * reference kind. + */ + XML_SCHEMAP_SRC_REDEFINE, node, NULL, + "The %s '%s' to be redefined could not be found in " + "the redefined schema", + WXS_ITEM_TYPE_NAME(item), + xmlSchemaFormatQName(&str, redef->refTargetNs, + redef->refName)); + FREE_AND_NULL(str); + err = pctxt->err; + redef = redef->next; + continue; + } + /* + * TODO: Obtaining and setting the redefinition state is really + * clumsy. + */ + wasRedefined = 0; + switch (item->type) { + case XML_SCHEMA_TYPE_COMPLEX: + case XML_SCHEMA_TYPE_SIMPLE: + if ((WXS_TYPE_CAST prev)->flags & + XML_SCHEMAS_TYPE_REDEFINED) + { + wasRedefined = 1; + break; + } + /* Mark it as redefined. */ + (WXS_TYPE_CAST prev)->flags |= XML_SCHEMAS_TYPE_REDEFINED; + /* + * Assign the redefined type to the + * base type of the redefining type. + * TODO: How + */ + ((xmlSchemaTypePtr) item)->baseType = + (xmlSchemaTypePtr) prev; + break; + case XML_SCHEMA_TYPE_GROUP: + if ((WXS_MODEL_GROUPDEF_CAST prev)->flags & + XML_SCHEMA_MODEL_GROUP_DEF_REDEFINED) + { + wasRedefined = 1; + break; + } + /* Mark it as redefined. */ + (WXS_MODEL_GROUPDEF_CAST prev)->flags |= + XML_SCHEMA_MODEL_GROUP_DEF_REDEFINED; + if (redef->reference != NULL) { + /* + * Overwrite the QName-reference with the + * referenced model group def. + */ + (WXS_PTC_CAST redef->reference)->children = + WXS_TREE_CAST prev; + } + redef->target = prev; + break; + case XML_SCHEMA_TYPE_ATTRIBUTEGROUP: + if ((WXS_ATTR_GROUP_CAST prev)->flags & + XML_SCHEMAS_ATTRGROUP_REDEFINED) + { + wasRedefined = 1; + break; + } + (WXS_ATTR_GROUP_CAST prev)->flags |= + XML_SCHEMAS_ATTRGROUP_REDEFINED; + if (redef->reference != NULL) { + /* + * Assign the redefined attribute group to the + * QName-reference component. + * This is the easy case, since we will just + * expand the redefined group. + */ + (WXS_QNAME_CAST redef->reference)->item = prev; + redef->target = NULL; + } else { + /* + * This is the complicated case: we need + * to apply src-redefine (7.2.2) at a later + * stage, i.e. when attribute group references + * have beed expanded and simple types have + * beed fixed. + */ + redef->target = prev; + } + break; + default: + PERROR_INT("xmlSchemaResolveRedefReferences", + "Unexpected redefined component type"); + return(-1); + } + if (wasRedefined) { + xmlChar *str = NULL; + xmlNodePtr node; + + if (redef->reference) + node = WXS_ITEM_NODE(redef->reference); + else + node = WXS_ITEM_NODE(redef->item); + + xmlSchemaCustomErr(ACTXT_CAST pctxt, + /* TODO: error code. */ + XML_SCHEMAP_SRC_REDEFINE, + node, NULL, + "The referenced %s was already redefined. Multiple " + "redefinition of the same component is not supported", + xmlSchemaGetComponentDesignation(&str, prev), + NULL); + FREE_AND_NULL(str) + err = pctxt->err; + redef = redef->next; + continue; + } + redef = redef->next; + } while (redef != NULL); + + return(err); +} + +static int +xmlSchemaCheckSRCRedefineSecond(xmlSchemaParserCtxtPtr pctxt) +{ + int err = 0; + xmlSchemaRedefPtr redef = WXS_CONSTRUCTOR(pctxt)->redefs; + xmlSchemaBasicItemPtr item; + + if (redef == NULL) + return(0); + + do { + if (redef->target == NULL) { + redef = redef->next; + continue; + } + item = redef->item; + + switch (item->type) { + case XML_SCHEMA_TYPE_SIMPLE: + case XML_SCHEMA_TYPE_COMPLEX: + /* + * Since the spec wants the {name} of the redefined + * type to be 'absent', we'll NULL it. + */ + (WXS_TYPE_CAST redef->target)->name = NULL; + + /* + * TODO: Seems like there's nothing more to do. The normal + * inheritance mechanism is used. But not 100% sure. + */ + break; + case XML_SCHEMA_TYPE_GROUP: + /* + * URGENT TODO: + * SPEC src-redefine: + * (6.2.2) "The {model group} of the model group definition + * which corresponds to it per XML Representation of Model + * Group Definition Schema Components (�3.7.2) must be a + * �valid restriction� of the {model group} of that model + * group definition in I, as defined in Particle Valid + * (Restriction) (�3.9.6)." + */ + break; + case XML_SCHEMA_TYPE_ATTRIBUTEGROUP: + /* + * SPEC src-redefine: + * (7.2.2) "The {attribute uses} and {attribute wildcard} of + * the attribute group definition which corresponds to it + * per XML Representation of Attribute Group Definition Schema + * Components (�3.6.2) must be �valid restrictions� of the + * {attribute uses} and {attribute wildcard} of that attribute + * group definition in I, as defined in clause 2, clause 3 and + * clause 4 of Derivation Valid (Restriction, Complex) + * (�3.4.6) (where references to the base type definition are + * understood as references to the attribute group definition + * in I)." + */ + err = xmlSchemaCheckDerivationOKRestriction2to4(pctxt, + XML_SCHEMA_ACTION_REDEFINE, + item, redef->target, + (WXS_ATTR_GROUP_CAST item)->attrUses, + (WXS_ATTR_GROUP_CAST redef->target)->attrUses, + (WXS_ATTR_GROUP_CAST item)->attributeWildcard, + (WXS_ATTR_GROUP_CAST redef->target)->attributeWildcard); + if (err == -1) + return(-1); + break; + default: + break; + } + redef = redef->next; + } while (redef != NULL); + return(0); +} + + +static int +xmlSchemaAddComponents(xmlSchemaParserCtxtPtr pctxt, + xmlSchemaBucketPtr bucket) +{ + xmlSchemaBasicItemPtr item; + int err; + xmlHashTablePtr *table; + const xmlChar *name; + int i; + +#define WXS_GET_GLOBAL_HASH(c, slot) { \ + if (WXS_IS_BUCKET_IMPMAIN((c)->type)) \ + table = &(WXS_IMPBUCKET((c))->schema->slot); \ + else \ + table = &(WXS_INCBUCKET((c))->ownerImport->schema->slot); } + + /* + * Add global components to the schema's hash tables. + * This is the place where duplicate components will be + * detected. + * TODO: I think normally we should support imports of the + * same namespace from multiple locations. We don't do currently, + * but if we do then according to: + * http://www.w3.org/Bugs/Public/show_bug.cgi?id=2224 + * we would need, if imported directly, to import redefined + * components as well to be able to catch clashing components. + * (I hope I'll still know what this means after some months :-() + */ + if (bucket == NULL) + return(-1); + if (bucket->flags & XML_SCHEMA_BUCKET_COMPS_ADDED) + return(0); + bucket->flags |= XML_SCHEMA_BUCKET_COMPS_ADDED; + + for (i = 0; i < bucket->globals->nbItems; i++) { + item = bucket->globals->items[i]; + table = NULL; + switch (item->type) { + case XML_SCHEMA_TYPE_COMPLEX: + case XML_SCHEMA_TYPE_SIMPLE: + if (WXS_REDEFINED_TYPE(item)) + continue; + name = (WXS_TYPE_CAST item)->name; + WXS_GET_GLOBAL_HASH(bucket, typeDecl) + break; + case XML_SCHEMA_TYPE_ELEMENT: + name = (WXS_ELEM_CAST item)->name; + WXS_GET_GLOBAL_HASH(bucket, elemDecl) + break; + case XML_SCHEMA_TYPE_ATTRIBUTE: + name = (WXS_ATTR_CAST item)->name; + WXS_GET_GLOBAL_HASH(bucket, attrDecl) + break; + case XML_SCHEMA_TYPE_GROUP: + if (WXS_REDEFINED_MODEL_GROUP_DEF(item)) + continue; + name = (WXS_MODEL_GROUPDEF_CAST item)->name; + WXS_GET_GLOBAL_HASH(bucket, groupDecl) + break; + case XML_SCHEMA_TYPE_ATTRIBUTEGROUP: + if (WXS_REDEFINED_ATTR_GROUP(item)) + continue; + name = (WXS_ATTR_GROUP_CAST item)->name; + WXS_GET_GLOBAL_HASH(bucket, attrgrpDecl) + break; + case XML_SCHEMA_TYPE_IDC_KEY: + case XML_SCHEMA_TYPE_IDC_UNIQUE: + case XML_SCHEMA_TYPE_IDC_KEYREF: + name = (WXS_IDC_CAST item)->name; + WXS_GET_GLOBAL_HASH(bucket, idcDef) + break; + case XML_SCHEMA_TYPE_NOTATION: + name = ((xmlSchemaNotationPtr) item)->name; + WXS_GET_GLOBAL_HASH(bucket, notaDecl) + break; + default: + PERROR_INT("xmlSchemaAddComponents", + "Unexpected global component type"); + continue; + } + if (*table == NULL) { + *table = xmlHashCreateDict(10, pctxt->dict); + if (*table == NULL) { + PERROR_INT("xmlSchemaAddComponents", + "failed to create a component hash table"); + return(-1); + } + } + err = xmlHashAddEntry(*table, name, item); + if (err != 0) { + xmlChar *str = NULL; + + xmlSchemaCustomErr(ACTXT_CAST pctxt, + XML_SCHEMAP_REDEFINED_TYPE, + WXS_ITEM_NODE(item), + WXS_BASIC_CAST item, + "A global %s '%s' does already exist", + WXS_ITEM_TYPE_NAME(item), + xmlSchemaGetComponentQName(&str, item)); + FREE_AND_NULL(str); + } + } + /* + * Process imported/included schemas. + */ + if (bucket->relations != NULL) { + xmlSchemaSchemaRelationPtr rel = bucket->relations; + do { + if ((rel->bucket != NULL) && + ((rel->bucket->flags & XML_SCHEMA_BUCKET_COMPS_ADDED) == 0)) { + if (xmlSchemaAddComponents(pctxt, rel->bucket) == -1) + return(-1); + } + rel = rel->next; + } while (rel != NULL); + } + return(0); +} + +static int +xmlSchemaFixupComponents(xmlSchemaParserCtxtPtr pctxt, + xmlSchemaBucketPtr rootBucket) +{ + xmlSchemaConstructionCtxtPtr con = pctxt->constructor; + xmlSchemaTreeItemPtr item, *items; + int nbItems, i, ret = 0; + xmlSchemaBucketPtr oldbucket = con->bucket; + xmlSchemaElementPtr elemDecl; + +#define FIXHFAILURE if (pctxt->err == XML_SCHEMAP_INTERNAL) goto exit_failure; + + if ((con->pending == NULL) || + (con->pending->nbItems == 0)) + return(0); + + /* + * Since xmlSchemaFixupComplexType() will create new particles + * (local components), and those particle components need a bucket + * on the constructor, we'll assure here that the constructor has + * a bucket. + * TODO: Think about storing locals _only_ on the main bucket. + */ + if (con->bucket == NULL) + con->bucket = rootBucket; + + /* TODO: + * SPEC (src-redefine): + * (6.2) "If it has no such self-reference, then all of the + * following must be true:" + + * (6.2.2) The {model group} of the model group definition which + * corresponds to it per XML Representation of Model Group + * Definition Schema Components (�3.7.2) must be a �valid + * restriction� of the {model group} of that model group definition + * in I, as defined in Particle Valid (Restriction) (�3.9.6)." + */ + xmlSchemaCheckSRCRedefineFirst(pctxt); + + /* + * Add global components to the schemata's hash tables. + */ + xmlSchemaAddComponents(pctxt, rootBucket); + + pctxt->ctxtType = NULL; + items = (xmlSchemaTreeItemPtr *) con->pending->items; + nbItems = con->pending->nbItems; + /* + * Now that we have parsed *all* the schema document(s) and converted + * them to schema components, we can resolve references, apply component + * constraints, create the FSA from the content model, etc. + */ + /* + * Resolve references of.. + * + * 1. element declarations: + * - the type definition + * - the substitution group affiliation + * 2. simple/complex types: + * - the base type definition + * - the memberTypes of union types + * - the itemType of list types + * 3. attributes declarations and attribute uses: + * - the type definition + * - if an attribute use, then the attribute declaration + * 4. attribute group references: + * - the attribute group definition + * 5. particles: + * - the term of the particle (e.g. a model group) + * 6. IDC key-references: + * - the referenced IDC 'key' or 'unique' definition + * 7. Attribute prohibitions which had a "ref" attribute. + */ + for (i = 0; i < nbItems; i++) { + item = items[i]; + switch (item->type) { + case XML_SCHEMA_TYPE_ELEMENT: + xmlSchemaResolveElementReferences( + (xmlSchemaElementPtr) item, pctxt); + FIXHFAILURE; + break; + case XML_SCHEMA_TYPE_COMPLEX: + case XML_SCHEMA_TYPE_SIMPLE: + xmlSchemaResolveTypeReferences( + (xmlSchemaTypePtr) item, pctxt); + FIXHFAILURE; + break; + case XML_SCHEMA_TYPE_ATTRIBUTE: + xmlSchemaResolveAttrTypeReferences( + (xmlSchemaAttributePtr) item, pctxt); + FIXHFAILURE; + break; + case XML_SCHEMA_TYPE_ATTRIBUTE_USE: + xmlSchemaResolveAttrUseReferences( + (xmlSchemaAttributeUsePtr) item, pctxt); + FIXHFAILURE; + break; + case XML_SCHEMA_EXTRA_QNAMEREF: + if ((WXS_QNAME_CAST item)->itemType == + XML_SCHEMA_TYPE_ATTRIBUTEGROUP) + { + xmlSchemaResolveAttrGroupReferences( + WXS_QNAME_CAST item, pctxt); + } + FIXHFAILURE; + break; + case XML_SCHEMA_TYPE_SEQUENCE: + case XML_SCHEMA_TYPE_CHOICE: + case XML_SCHEMA_TYPE_ALL: + xmlSchemaResolveModelGroupParticleReferences(pctxt, + WXS_MODEL_GROUP_CAST item); + FIXHFAILURE; + break; + case XML_SCHEMA_TYPE_IDC_KEY: + case XML_SCHEMA_TYPE_IDC_UNIQUE: + case XML_SCHEMA_TYPE_IDC_KEYREF: + xmlSchemaResolveIDCKeyReferences( + (xmlSchemaIDCPtr) item, pctxt); + FIXHFAILURE; + break; + case XML_SCHEMA_EXTRA_ATTR_USE_PROHIB: + /* + * Handle attribue prohibition which had a + * "ref" attribute. + */ + xmlSchemaResolveAttrUseProhibReferences( + WXS_ATTR_PROHIB_CAST item, pctxt); + FIXHFAILURE; + break; + default: + break; + } + } + if (pctxt->nberrors != 0) + goto exit_error; + + /* + * Now that all references are resolved we + * can check for circularity of... + * 1. the base axis of type definitions + * 2. nested model group definitions + * 3. nested attribute group definitions + * TODO: check for circual substitution groups. + */ + for (i = 0; i < nbItems; i++) { + item = items[i]; + /* + * Let's better stop on the first error here. + */ + switch (item->type) { + case XML_SCHEMA_TYPE_COMPLEX: + case XML_SCHEMA_TYPE_SIMPLE: + xmlSchemaCheckTypeDefCircular( + (xmlSchemaTypePtr) item, pctxt); + FIXHFAILURE; + if (pctxt->nberrors != 0) + goto exit_error; + break; + case XML_SCHEMA_TYPE_GROUP: + xmlSchemaCheckGroupDefCircular( + (xmlSchemaModelGroupDefPtr) item, pctxt); + FIXHFAILURE; + if (pctxt->nberrors != 0) + goto exit_error; + break; + case XML_SCHEMA_TYPE_ATTRIBUTEGROUP: + xmlSchemaCheckAttrGroupCircular( + (xmlSchemaAttributeGroupPtr) item, pctxt); + FIXHFAILURE; + if (pctxt->nberrors != 0) + goto exit_error; + break; + default: + break; + } + } + if (pctxt->nberrors != 0) + goto exit_error; + /* + * Model group definition references: + * Such a reference is reflected by a particle at the component + * level. Until now the 'term' of such particles pointed + * to the model group definition; this was done, in order to + * ease circularity checks. Now we need to set the 'term' of + * such particles to the model group of the model group definition. + */ + for (i = 0; i < nbItems; i++) { + item = items[i]; + switch (item->type) { + case XML_SCHEMA_TYPE_SEQUENCE: + case XML_SCHEMA_TYPE_CHOICE: + xmlSchemaModelGroupToModelGroupDefFixup(pctxt, + WXS_MODEL_GROUP_CAST item); + break; + default: + break; + } + } + if (pctxt->nberrors != 0) + goto exit_error; + /* + * Expand attribute group references of attribute group definitions. + */ + for (i = 0; i < nbItems; i++) { + item = items[i]; + switch (item->type) { + case XML_SCHEMA_TYPE_ATTRIBUTEGROUP: + if ((! WXS_ATTR_GROUP_EXPANDED(item)) && + WXS_ATTR_GROUP_HAS_REFS(item)) + { + xmlSchemaAttributeGroupExpandRefs(pctxt, + WXS_ATTR_GROUP_CAST item); + FIXHFAILURE; + } + break; + default: + break; + } + } + if (pctxt->nberrors != 0) + goto exit_error; + /* + * First compute the variety of simple types. This is needed as + * a seperate step, since otherwise we won't be able to detect + * circular union types in all cases. + */ + for (i = 0; i < nbItems; i++) { + item = items[i]; + switch (item->type) { + case XML_SCHEMA_TYPE_SIMPLE: + if (WXS_IS_TYPE_NOT_FIXED_1((xmlSchemaTypePtr) item)) { + xmlSchemaFixupSimpleTypeStageOne(pctxt, + (xmlSchemaTypePtr) item); + FIXHFAILURE; + } + break; + default: + break; + } + } + if (pctxt->nberrors != 0) + goto exit_error; + /* + * Detect circular union types. Note that this needs the variety to + * be already computed. + */ + for (i = 0; i < nbItems; i++) { + item = items[i]; + switch (item->type) { + case XML_SCHEMA_TYPE_SIMPLE: + if (((xmlSchemaTypePtr) item)->memberTypes != NULL) { + xmlSchemaCheckUnionTypeDefCircular(pctxt, + (xmlSchemaTypePtr) item); + FIXHFAILURE; + } + break; + default: + break; + } + } + if (pctxt->nberrors != 0) + goto exit_error; + + /* + * Do the complete type fixup for simple types. + */ + for (i = 0; i < nbItems; i++) { + item = items[i]; + switch (item->type) { + case XML_SCHEMA_TYPE_SIMPLE: + if (WXS_IS_TYPE_NOT_FIXED(WXS_TYPE_CAST item)) { + xmlSchemaFixupSimpleTypeStageTwo(pctxt, WXS_TYPE_CAST item); + FIXHFAILURE; + } + break; + default: + break; + } + } + if (pctxt->nberrors != 0) + goto exit_error; + /* + * At this point we need build and check all simple types. + */ + /* + * Apply contraints for attribute declarations. + */ + for (i = 0; i < nbItems; i++) { + item = items[i]; + switch (item->type) { + case XML_SCHEMA_TYPE_ATTRIBUTE: + xmlSchemaCheckAttrPropsCorrect(pctxt, WXS_ATTR_CAST item); + FIXHFAILURE; + break; + default: + break; + } + } + if (pctxt->nberrors != 0) + goto exit_error; + /* + * Apply constraints for attribute uses. + */ + for (i = 0; i < nbItems; i++) { + item = items[i]; + switch (item->type) { + case XML_SCHEMA_TYPE_ATTRIBUTE_USE: + if (((xmlSchemaAttributeUsePtr)item)->defValue != NULL) { + xmlSchemaCheckAttrUsePropsCorrect(pctxt, + WXS_ATTR_USE_CAST item); + FIXHFAILURE; + } + break; + default: + break; + } + } + if (pctxt->nberrors != 0) + goto exit_error; + + /* + * Apply constraints for attribute group definitions. + */ + for (i = 0; i < nbItems; i++) { + item = items[i]; + switch (item->type) { + case XML_SCHEMA_TYPE_ATTRIBUTEGROUP: + if (( (WXS_ATTR_GROUP_CAST item)->attrUses != NULL) && + ( (WXS_LIST_CAST (WXS_ATTR_GROUP_CAST item)->attrUses)->nbItems > 1)) + { + xmlSchemaCheckAGPropsCorrect(pctxt, WXS_ATTR_GROUP_CAST item); + FIXHFAILURE; + } + break; + default: + break; + } + } + if (pctxt->nberrors != 0) + goto exit_error; + + /* + * Apply constraints for redefinitions. + */ + if (WXS_CONSTRUCTOR(pctxt)->redefs != NULL) + xmlSchemaCheckSRCRedefineSecond(pctxt); + if (pctxt->nberrors != 0) + goto exit_error; + + /* + * Complex types are builded and checked. + */ + for (i = 0; i < nbItems; i++) { + item = con->pending->items[i]; + switch (item->type) { + case XML_SCHEMA_TYPE_COMPLEX: + if (WXS_IS_TYPE_NOT_FIXED(WXS_TYPE_CAST item)) { + xmlSchemaFixupComplexType(pctxt, WXS_TYPE_CAST item); + FIXHFAILURE; + } + break; + default: + break; + } + } + if (pctxt->nberrors != 0) + goto exit_error; + + /* + * The list could have changed, since xmlSchemaFixupComplexType() + * will create particles and model groups in some cases. + */ + items = (xmlSchemaTreeItemPtr *) con->pending->items; + nbItems = con->pending->nbItems; + + /* + * Apply some constraints for element declarations. + */ + for (i = 0; i < nbItems; i++) { + item = items[i]; + switch (item->type) { + case XML_SCHEMA_TYPE_ELEMENT: + elemDecl = (xmlSchemaElementPtr) item; + + if ((elemDecl->flags & XML_SCHEMAS_ELEM_INTERNAL_CHECKED) == 0) + { + xmlSchemaCheckElementDeclComponent( + (xmlSchemaElementPtr) elemDecl, pctxt); + FIXHFAILURE; + } + +#ifdef WXS_ELEM_DECL_CONS_ENABLED + /* + * Schema Component Constraint: Element Declarations Consistent + * Apply this constraint to local types of element declarations. + */ + if ((WXS_ELEM_TYPEDEF(elemDecl) != NULL) && + (WXS_IS_COMPLEX(WXS_ELEM_TYPEDEF(elemDecl))) && + (WXS_TYPE_IS_LOCAL(WXS_ELEM_TYPEDEF(elemDecl)))) + { + xmlSchemaCheckElementDeclConsistent(pctxt, + WXS_BASIC_CAST elemDecl, + WXS_TYPE_PARTICLE(WXS_ELEM_TYPEDEF(elemDecl)), + NULL, NULL, 0); + } +#endif + break; + default: + break; + } + } + if (pctxt->nberrors != 0) + goto exit_error; + + /* + * Finally we can build the automaton from the content model of + * complex types. + */ + + for (i = 0; i < nbItems; i++) { + item = items[i]; + switch (item->type) { + case XML_SCHEMA_TYPE_COMPLEX: + xmlSchemaBuildContentModel((xmlSchemaTypePtr) item, pctxt); + /* FIXHFAILURE; */ + break; + default: + break; + } + } + if (pctxt->nberrors != 0) + goto exit_error; + /* + * URGENT TODO: cos-element-consistent + */ + goto exit; + +exit_error: + ret = pctxt->err; + goto exit; + +exit_failure: + ret = -1; + +exit: + /* + * Reset the constructor. This is needed for XSI acquisition, since + * those items will be processed over and over again for every XSI + * if not cleared here. + */ + con->bucket = oldbucket; + con->pending->nbItems = 0; + if (con->substGroups != NULL) { + xmlHashFree(con->substGroups, + (xmlHashDeallocator) xmlSchemaSubstGroupFree); + con->substGroups = NULL; + } + if (con->redefs != NULL) { + xmlSchemaRedefListFree(con->redefs); + con->redefs = NULL; + } + return(ret); +} +/** + * xmlSchemaParse: + * @ctxt: a schema validation context + * + * parse a schema definition resource and build an internal + * XML Shema struture which can be used to validate instances. + * + * Returns the internal XML Schema structure built from the resource or + * NULL in case of error + */ +xmlSchemaPtr +xmlSchemaParse(xmlSchemaParserCtxtPtr ctxt) +{ + xmlSchemaPtr mainSchema = NULL; + xmlSchemaBucketPtr bucket = NULL; + int res; + + /* + * This one is used if the schema to be parsed was specified via + * the API; i.e. not automatically by the validated instance document. + */ + + xmlSchemaInitTypes(); + + if (ctxt == NULL) + return (NULL); + + /* TODO: Init the context. Is this all we need?*/ + ctxt->nberrors = 0; + ctxt->err = 0; + ctxt->counter = 0; + + /* Create the *main* schema. */ + mainSchema = xmlSchemaNewSchema(ctxt); + if (mainSchema == NULL) + goto exit_failure; + /* + * Create the schema constructor. + */ + if (ctxt->constructor == NULL) { + ctxt->constructor = xmlSchemaConstructionCtxtCreate(ctxt->dict); + if (ctxt->constructor == NULL) + return(NULL); + /* Take ownership of the constructor to be able to free it. */ + ctxt->ownsConstructor = 1; + } + ctxt->constructor->mainSchema = mainSchema; + /* + * Locate and add the schema document. + */ + res = xmlSchemaAddSchemaDoc(ctxt, XML_SCHEMA_SCHEMA_MAIN, + ctxt->URL, ctxt->doc, ctxt->buffer, ctxt->size, NULL, + NULL, NULL, &bucket); + if (res == -1) + goto exit_failure; + if (res != 0) + goto exit; + + if (bucket == NULL) { + /* TODO: Error code, actually we failed to *locate* the schema. */ + if (ctxt->URL) + xmlSchemaCustomErr(ACTXT_CAST ctxt, XML_SCHEMAP_FAILED_LOAD, + NULL, NULL, + "Failed to locate the main schema resource at '%s'", + ctxt->URL, NULL); + else + xmlSchemaCustomErr(ACTXT_CAST ctxt, XML_SCHEMAP_FAILED_LOAD, + NULL, NULL, + "Failed to locate the main schema resource", + NULL, NULL); + goto exit; + } + /* Then do the parsing for good. */ + if (xmlSchemaParseNewDocWithContext(ctxt, mainSchema, bucket) == -1) + goto exit_failure; + if (ctxt->nberrors != 0) + goto exit; + + mainSchema->doc = bucket->doc; + mainSchema->preserve = ctxt->preserve; + + ctxt->schema = mainSchema; + + if (xmlSchemaFixupComponents(ctxt, WXS_CONSTRUCTOR(ctxt)->mainBucket) == -1) + goto exit_failure; + + /* + * TODO: This is not nice, since we cannot distinguish from the + * result if there was an internal error or not. + */ +exit: + if (ctxt->nberrors != 0) { + if (mainSchema) { + xmlSchemaFree(mainSchema); + mainSchema = NULL; + } + if (ctxt->constructor) { + xmlSchemaConstructionCtxtFree(ctxt->constructor); + ctxt->constructor = NULL; + ctxt->ownsConstructor = 0; + } + } + ctxt->schema = NULL; + return(mainSchema); +exit_failure: + /* + * Quite verbose, but should catch internal errors, which were + * not communitated. + */ + if (mainSchema) { + xmlSchemaFree(mainSchema); + mainSchema = NULL; + } + if (ctxt->constructor) { + xmlSchemaConstructionCtxtFree(ctxt->constructor); + ctxt->constructor = NULL; + ctxt->ownsConstructor = 0; + } + PERROR_INT2("xmlSchemaParse", + "An internal error occured"); + ctxt->schema = NULL; + return(NULL); +} + +/** + * xmlSchemaSetParserErrors: + * @ctxt: a schema validation context + * @err: the error callback + * @warn: the warning callback + * @ctx: contextual data for the callbacks + * + * Set the callback functions used to handle errors for a validation context + */ +void +xmlSchemaSetParserErrors(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaValidityErrorFunc err, + xmlSchemaValidityWarningFunc warn, void *ctx) +{ + if (ctxt == NULL) + return; + ctxt->error = err; + ctxt->warning = warn; + ctxt->errCtxt = ctx; + if (ctxt->vctxt != NULL) + xmlSchemaSetValidErrors(ctxt->vctxt, err, warn, ctx); +} + +/** + * xmlSchemaSetParserStructuredErrors: + * @ctxt: a schema parser context + * @serror: the structured error function + * @ctx: the functions context + * + * Set the structured error callback + */ +void +xmlSchemaSetParserStructuredErrors(xmlSchemaParserCtxtPtr ctxt, + xmlStructuredErrorFunc serror, + void *ctx) +{ + if (ctxt == NULL) + return; + ctxt->serror = serror; + ctxt->errCtxt = ctx; + if (ctxt->vctxt != NULL) + xmlSchemaSetValidStructuredErrors(ctxt->vctxt, serror, ctx); +} + +/** + * xmlSchemaGetParserErrors: + * @ctxt: a XMl-Schema parser context + * @err: the error callback result + * @warn: the warning callback result + * @ctx: contextual data for the callbacks result + * + * Get the callback information used to handle errors for a parser context + * + * Returns -1 in case of failure, 0 otherwise + */ +int +xmlSchemaGetParserErrors(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaValidityErrorFunc * err, + xmlSchemaValidityWarningFunc * warn, void **ctx) +{ + if (ctxt == NULL) + return(-1); + if (err != NULL) + *err = ctxt->error; + if (warn != NULL) + *warn = ctxt->warning; + if (ctx != NULL) + *ctx = ctxt->errCtxt; + return(0); +} + +/** + * xmlSchemaFacetTypeToString: + * @type: the facet type + * + * Convert the xmlSchemaTypeType to a char string. + * + * Returns the char string representation of the facet type if the + * type is a facet and an "Internal Error" string otherwise. + */ +static const xmlChar * +xmlSchemaFacetTypeToString(xmlSchemaTypeType type) +{ + switch (type) { + case XML_SCHEMA_FACET_PATTERN: + return (BAD_CAST "pattern"); + case XML_SCHEMA_FACET_MAXEXCLUSIVE: + return (BAD_CAST "maxExclusive"); + case XML_SCHEMA_FACET_MAXINCLUSIVE: + return (BAD_CAST "maxInclusive"); + case XML_SCHEMA_FACET_MINEXCLUSIVE: + return (BAD_CAST "minExclusive"); + case XML_SCHEMA_FACET_MININCLUSIVE: + return (BAD_CAST "minInclusive"); + case XML_SCHEMA_FACET_WHITESPACE: + return (BAD_CAST "whiteSpace"); + case XML_SCHEMA_FACET_ENUMERATION: + return (BAD_CAST "enumeration"); + case XML_SCHEMA_FACET_LENGTH: + return (BAD_CAST "length"); + case XML_SCHEMA_FACET_MAXLENGTH: + return (BAD_CAST "maxLength"); + case XML_SCHEMA_FACET_MINLENGTH: + return (BAD_CAST "minLength"); + case XML_SCHEMA_FACET_TOTALDIGITS: + return (BAD_CAST "totalDigits"); + case XML_SCHEMA_FACET_FRACTIONDIGITS: + return (BAD_CAST "fractionDigits"); + default: + break; + } + return (BAD_CAST "Internal Error"); +} + +static xmlSchemaWhitespaceValueType +xmlSchemaGetWhiteSpaceFacetValue(xmlSchemaTypePtr type) +{ + /* + * The normalization type can be changed only for types which are derived + * from xsd:string. + */ + if (type->type == XML_SCHEMA_TYPE_BASIC) { + /* + * Note that we assume a whitespace of preserve for anySimpleType. + */ + if ((type->builtInType == XML_SCHEMAS_STRING) || + (type->builtInType == XML_SCHEMAS_ANYSIMPLETYPE)) + return(XML_SCHEMA_WHITESPACE_PRESERVE); + else if (type->builtInType == XML_SCHEMAS_NORMSTRING) + return(XML_SCHEMA_WHITESPACE_REPLACE); + else { + /* + * For all �atomic� datatypes other than string (and types �derived� + * by �restriction� from it) the value of whiteSpace is fixed to + * collapse + * Note that this includes built-in list datatypes. + */ + return(XML_SCHEMA_WHITESPACE_COLLAPSE); + } + } else if (WXS_IS_LIST(type)) { + /* + * For list types the facet "whiteSpace" is fixed to "collapse". + */ + return (XML_SCHEMA_WHITESPACE_COLLAPSE); + } else if (WXS_IS_UNION(type)) { + return (XML_SCHEMA_WHITESPACE_UNKNOWN); + } else if (WXS_IS_ATOMIC(type)) { + if (type->flags & XML_SCHEMAS_TYPE_WHITESPACE_PRESERVE) + return (XML_SCHEMA_WHITESPACE_PRESERVE); + else if (type->flags & XML_SCHEMAS_TYPE_WHITESPACE_REPLACE) + return (XML_SCHEMA_WHITESPACE_REPLACE); + else + return (XML_SCHEMA_WHITESPACE_COLLAPSE); + } + return (-1); +} + +/************************************************************************ + * * + * Simple type validation * + * * + ************************************************************************/ + + +/************************************************************************ + * * + * DOM Validation code * + * * + ************************************************************************/ + +/** + * xmlSchemaAssembleByLocation: + * @pctxt: a schema parser context + * @vctxt: a schema validation context + * @schema: the existing schema + * @node: the node that fired the assembling + * @nsName: the namespace name of the new schema + * @location: the location of the schema + * + * Expands an existing schema by an additional schema. + * + * Returns 0 if the new schema is correct, a positive error code + * number otherwise and -1 in case of an internal or API error. + */ +static int +xmlSchemaAssembleByLocation(xmlSchemaValidCtxtPtr vctxt, + xmlSchemaPtr schema, + xmlNodePtr node, + const xmlChar *nsName, + const xmlChar *location) +{ + int ret = 0; + xmlSchemaParserCtxtPtr pctxt; + xmlSchemaBucketPtr bucket = NULL; + + if ((vctxt == NULL) || (schema == NULL)) + return (-1); + + if (vctxt->pctxt == NULL) { + VERROR_INT("xmlSchemaAssembleByLocation", + "no parser context available"); + return(-1); + } + pctxt = vctxt->pctxt; + if (pctxt->constructor == NULL) { + PERROR_INT("xmlSchemaAssembleByLocation", + "no constructor"); + return(-1); + } + /* + * Acquire the schema document. + */ + location = xmlSchemaBuildAbsoluteURI(pctxt->dict, + location, node); + /* + * Note that we pass XML_SCHEMA_SCHEMA_IMPORT here; + * the process will automatically change this to + * XML_SCHEMA_SCHEMA_MAIN if it is the first schema document. + */ + ret = xmlSchemaAddSchemaDoc(pctxt, XML_SCHEMA_SCHEMA_IMPORT, + location, NULL, NULL, 0, node, NULL, nsName, + &bucket); + if (ret != 0) + return(ret); + if (bucket == NULL) { + /* + * Generate a warning that the document could not be located. + */ + xmlSchemaCustomWarning(ACTXT_CAST vctxt, XML_SCHEMAV_MISC, + node, NULL, + "The document at location '%s' could not be acquired", + location, NULL, NULL); + return(ret); + } + /* + * The first located schema will be handled as if all other + * schemas imported by XSI were imported by this first schema. + */ + if ((bucket != NULL) && + (WXS_CONSTRUCTOR(pctxt)->bucket == NULL)) + WXS_CONSTRUCTOR(pctxt)->bucket = bucket; + /* + * TODO: Is this handled like an import? I.e. is it not an error + * if the schema cannot be located? + */ + if ((bucket == NULL) || (! CAN_PARSE_SCHEMA(bucket))) + return(0); + /* + * We will reuse the parser context for every schema imported + * directly via XSI. So reset the context. + */ + pctxt->nberrors = 0; + pctxt->err = 0; + pctxt->doc = bucket->doc; + + ret = xmlSchemaParseNewDocWithContext(pctxt, schema, bucket); + if (ret == -1) { + pctxt->doc = NULL; + goto exit_failure; + } + /* Paranoid error channelling. */ + if ((ret == 0) && (pctxt->nberrors != 0)) + ret = pctxt->err; + if (pctxt->nberrors == 0) { + /* + * Only bother to fixup pending components, if there was + * no error yet. + * For every XSI acquired schema (and its sub-schemata) we will + * fixup the components. + */ + xmlSchemaFixupComponents(pctxt, bucket); + ret = pctxt->err; + /* + * Not nice, but we need somehow to channel the schema parser + * error to the validation context. + */ + if ((ret != 0) && (vctxt->err == 0)) + vctxt->err = ret; + vctxt->nberrors += pctxt->nberrors; + } else { + /* Add to validation error sum. */ + vctxt->nberrors += pctxt->nberrors; + } + pctxt->doc = NULL; + return(ret); +exit_failure: + pctxt->doc = NULL; + return (-1); +} + +static xmlSchemaAttrInfoPtr +xmlSchemaGetMetaAttrInfo(xmlSchemaValidCtxtPtr vctxt, + int metaType) +{ + if (vctxt->nbAttrInfos == 0) + return (NULL); + { + int i; + xmlSchemaAttrInfoPtr iattr; + + for (i = 0; i < vctxt->nbAttrInfos; i++) { + iattr = vctxt->attrInfos[i]; + if (iattr->metaType == metaType) + return (iattr); + } + + } + return (NULL); +} + +/** + * xmlSchemaAssembleByXSI: + * @vctxt: a schema validation context + * + * Expands an existing schema by an additional schema using + * the xsi:schemaLocation or xsi:noNamespaceSchemaLocation attribute + * of an instance. If xsi:noNamespaceSchemaLocation is used, @noNamespace + * must be set to 1. + * + * Returns 0 if the new schema is correct, a positive error code + * number otherwise and -1 in case of an internal or API error. + */ +static int +xmlSchemaAssembleByXSI(xmlSchemaValidCtxtPtr vctxt) +{ + const xmlChar *cur, *end; + const xmlChar *nsname = NULL, *location; + int count = 0; + int ret = 0; + xmlSchemaAttrInfoPtr iattr; + + /* + * Parse the value; we will assume an even number of values + * to be given (this is how Xerces and XSV work). + * + * URGENT TODO: !! This needs to work for both + * @noNamespaceSchemaLocation AND @schemaLocation on the same + * element !! + */ + iattr = xmlSchemaGetMetaAttrInfo(vctxt, + XML_SCHEMA_ATTR_INFO_META_XSI_SCHEMA_LOC); + if (iattr == NULL) + iattr = xmlSchemaGetMetaAttrInfo(vctxt, + XML_SCHEMA_ATTR_INFO_META_XSI_NO_NS_SCHEMA_LOC); + if (iattr == NULL) + return (0); + cur = iattr->value; + do { + /* + * TODO: Move the string parsing mechanism away from here. + */ + if (iattr->metaType == XML_SCHEMA_ATTR_INFO_META_XSI_SCHEMA_LOC) { + /* + * Get the namespace name. + */ + while (IS_BLANK_CH(*cur)) + cur++; + end = cur; + while ((*end != 0) && (!(IS_BLANK_CH(*end)))) + end++; + if (end == cur) + break; + count++; /* TODO: Don't use the schema's dict. */ + nsname = xmlDictLookup(vctxt->schema->dict, cur, end - cur); + cur = end; + } + /* + * Get the URI. + */ + while (IS_BLANK_CH(*cur)) + cur++; + end = cur; + while ((*end != 0) && (!(IS_BLANK_CH(*end)))) + end++; + if (end == cur) { + if (iattr->metaType == + XML_SCHEMA_ATTR_INFO_META_XSI_SCHEMA_LOC) + { + /* + * If using @schemaLocation then tuples are expected. + * I.e. the namespace name *and* the document's URI. + */ + xmlSchemaCustomWarning(ACTXT_CAST vctxt, XML_SCHEMAV_MISC, + iattr->node, NULL, + "The value must consist of tuples: the target namespace " + "name and the document's URI", NULL, NULL, NULL); + } + break; + } + count++; /* TODO: Don't use the schema's dict. */ + location = xmlDictLookup(vctxt->schema->dict, cur, end - cur); + cur = end; + ret = xmlSchemaAssembleByLocation(vctxt, vctxt->schema, + iattr->node, nsname, location); + if (ret == -1) { + VERROR_INT("xmlSchemaAssembleByXSI", + "assembling schemata"); + return (-1); + } + } while (*cur != 0); + return (ret); +} + +static const xmlChar * +xmlSchemaLookupNamespace(xmlSchemaValidCtxtPtr vctxt, + const xmlChar *prefix) +{ + if (vctxt->sax != NULL) { + int i, j; + xmlSchemaNodeInfoPtr inode; + + for (i = vctxt->depth; i >= 0; i--) { + if (vctxt->elemInfos[i]->nbNsBindings != 0) { + inode = vctxt->elemInfos[i]; + for (j = 0; j < inode->nbNsBindings * 2; j += 2) { + if (((prefix == NULL) && + (inode->nsBindings[j] == NULL)) || + ((prefix != NULL) && xmlStrEqual(prefix, + inode->nsBindings[j]))) { + + /* + * Note that the namespace bindings are already + * in a string dict. + */ + return (inode->nsBindings[j+1]); + } + } + } + } + return (NULL); +#ifdef LIBXML_READER_ENABLED + } else if (vctxt->reader != NULL) { + xmlChar *nsName; + + nsName = xmlTextReaderLookupNamespace(vctxt->reader, prefix); + if (nsName != NULL) { + const xmlChar *ret; + + ret = xmlDictLookup(vctxt->dict, nsName, -1); + xmlFree(nsName); + return (ret); + } else + return (NULL); +#endif + } else { + xmlNsPtr ns; + + if ((vctxt->inode->node == NULL) || + (vctxt->inode->node->doc == NULL)) { + VERROR_INT("xmlSchemaLookupNamespace", + "no node or node's doc avaliable"); + return (NULL); + } + ns = xmlSearchNs(vctxt->inode->node->doc, + vctxt->inode->node, prefix); + if (ns != NULL) + return (ns->href); + return (NULL); + } +} + +/* +* This one works on the schema of the validation context. +*/ +static int +xmlSchemaValidateNotation(xmlSchemaValidCtxtPtr vctxt, + xmlSchemaPtr schema, + xmlNodePtr node, + const xmlChar *value, + xmlSchemaValPtr *val, + int valNeeded) +{ + int ret; + + if (vctxt && (vctxt->schema == NULL)) { + VERROR_INT("xmlSchemaValidateNotation", + "a schema is needed on the validation context"); + return (-1); + } + ret = xmlValidateQName(value, 1); + if (ret != 0) + return (ret); + { + xmlChar *localName = NULL; + xmlChar *prefix = NULL; + + localName = xmlSplitQName2(value, &prefix); + if (prefix != NULL) { + const xmlChar *nsName = NULL; + + if (vctxt != NULL) + nsName = xmlSchemaLookupNamespace(vctxt, BAD_CAST prefix); + else if (node != NULL) { + xmlNsPtr ns = xmlSearchNs(node->doc, node, prefix); + if (ns != NULL) + nsName = ns->href; + } else { + xmlFree(prefix); + xmlFree(localName); + return (1); + } + if (nsName == NULL) { + xmlFree(prefix); + xmlFree(localName); + return (1); + } + if (xmlSchemaGetNotation(schema, localName, nsName) != NULL) { + if ((valNeeded) && (val != NULL)) { + (*val) = xmlSchemaNewNOTATIONValue(xmlStrdup(localName), + xmlStrdup(nsName)); + if (*val == NULL) + ret = -1; + } + } else + ret = 1; + xmlFree(prefix); + xmlFree(localName); + } else { + if (xmlSchemaGetNotation(schema, value, NULL) != NULL) { + if (valNeeded && (val != NULL)) { + (*val) = xmlSchemaNewNOTATIONValue( + BAD_CAST xmlStrdup(value), NULL); + if (*val == NULL) + ret = -1; + } + } else + return (1); + } + } + return (ret); +} + +static int +xmlSchemaVAddNodeQName(xmlSchemaValidCtxtPtr vctxt, + const xmlChar* lname, + const xmlChar* nsname) +{ + int i; + + lname = xmlDictLookup(vctxt->dict, lname, -1); + if (lname == NULL) + return(-1); + if (nsname != NULL) { + nsname = xmlDictLookup(vctxt->dict, nsname, -1); + if (nsname == NULL) + return(-1); + } + for (i = 0; i < vctxt->nodeQNames->nbItems; i += 2) { + if ((vctxt->nodeQNames->items [i] == lname) && + (vctxt->nodeQNames->items[i +1] == nsname)) + /* Already there */ + return(i); + } + /* Add new entry. */ + i = vctxt->nodeQNames->nbItems; + xmlSchemaItemListAdd(vctxt->nodeQNames, (void *) lname); + xmlSchemaItemListAdd(vctxt->nodeQNames, (void *) nsname); + return(i); +} + +/************************************************************************ + * * + * Validation of identity-constraints (IDC) * + * * + ************************************************************************/ + +/** + * xmlSchemaAugmentIDC: + * @idcDef: the IDC definition + * + * Creates an augmented IDC definition item. + * + * Returns the item, or NULL on internal errors. + */ +static void +xmlSchemaAugmentIDC(xmlSchemaIDCPtr idcDef, + xmlSchemaValidCtxtPtr vctxt) +{ + xmlSchemaIDCAugPtr aidc; + + aidc = (xmlSchemaIDCAugPtr) xmlMalloc(sizeof(xmlSchemaIDCAug)); + if (aidc == NULL) { + xmlSchemaVErrMemory(vctxt, + "xmlSchemaAugmentIDC: allocating an augmented IDC definition", + NULL); + return; + } + aidc->keyrefDepth = -1; + aidc->def = idcDef; + aidc->next = NULL; + if (vctxt->aidcs == NULL) + vctxt->aidcs = aidc; + else { + aidc->next = vctxt->aidcs; + vctxt->aidcs = aidc; + } + /* + * Save if we have keyrefs at all. + */ + if ((vctxt->hasKeyrefs == 0) && + (idcDef->type == XML_SCHEMA_TYPE_IDC_KEYREF)) + vctxt->hasKeyrefs = 1; +} + +/** + * xmlSchemaAugmentImportedIDC: + * @imported: the imported schema + * + * Creates an augmented IDC definition for the imported schema. + */ +static void +xmlSchemaAugmentImportedIDC(xmlSchemaImportPtr imported, xmlSchemaValidCtxtPtr vctxt) { + if (imported->schema->idcDef != NULL) { + xmlHashScan(imported->schema->idcDef , + (xmlHashScanner) xmlSchemaAugmentIDC, vctxt); + } +} + +/** + * xmlSchemaIDCNewBinding: + * @idcDef: the IDC definition of this binding + * + * Creates a new IDC binding. + * + * Returns the new IDC binding, NULL on internal errors. + */ +static xmlSchemaPSVIIDCBindingPtr +xmlSchemaIDCNewBinding(xmlSchemaIDCPtr idcDef) +{ + xmlSchemaPSVIIDCBindingPtr ret; + + ret = (xmlSchemaPSVIIDCBindingPtr) xmlMalloc( + sizeof(xmlSchemaPSVIIDCBinding)); + if (ret == NULL) { + xmlSchemaVErrMemory(NULL, + "allocating a PSVI IDC binding item", NULL); + return (NULL); + } + memset(ret, 0, sizeof(xmlSchemaPSVIIDCBinding)); + ret->definition = idcDef; + return (ret); +} + +/** + * xmlSchemaIDCStoreNodeTableItem: + * @vctxt: the WXS validation context + * @item: the IDC node table item + * + * The validation context is used to store IDC node table items. + * They are stored to avoid copying them if IDC node-tables are merged + * with corresponding parent IDC node-tables (bubbling). + * + * Returns 0 if succeeded, -1 on internal errors. + */ +static int +xmlSchemaIDCStoreNodeTableItem(xmlSchemaValidCtxtPtr vctxt, + xmlSchemaPSVIIDCNodePtr item) +{ + /* + * Add to gobal list. + */ + if (vctxt->idcNodes == NULL) { + vctxt->idcNodes = (xmlSchemaPSVIIDCNodePtr *) + xmlMalloc(20 * sizeof(xmlSchemaPSVIIDCNodePtr)); + if (vctxt->idcNodes == NULL) { + xmlSchemaVErrMemory(vctxt, + "allocating the IDC node table item list", NULL); + return (-1); + } + vctxt->sizeIdcNodes = 20; + } else if (vctxt->sizeIdcNodes <= vctxt->nbIdcNodes) { + vctxt->sizeIdcNodes *= 2; + vctxt->idcNodes = (xmlSchemaPSVIIDCNodePtr *) + xmlRealloc(vctxt->idcNodes, vctxt->sizeIdcNodes * + sizeof(xmlSchemaPSVIIDCNodePtr)); + if (vctxt->idcNodes == NULL) { + xmlSchemaVErrMemory(vctxt, + "re-allocating the IDC node table item list", NULL); + return (-1); + } + } + vctxt->idcNodes[vctxt->nbIdcNodes++] = item; + + return (0); +} + +/** + * xmlSchemaIDCStoreKey: + * @vctxt: the WXS validation context + * @item: the IDC key + * + * The validation context is used to store an IDC key. + * + * Returns 0 if succeeded, -1 on internal errors. + */ +static int +xmlSchemaIDCStoreKey(xmlSchemaValidCtxtPtr vctxt, + xmlSchemaPSVIIDCKeyPtr key) +{ + /* + * Add to gobal list. + */ + if (vctxt->idcKeys == NULL) { + vctxt->idcKeys = (xmlSchemaPSVIIDCKeyPtr *) + xmlMalloc(40 * sizeof(xmlSchemaPSVIIDCKeyPtr)); + if (vctxt->idcKeys == NULL) { + xmlSchemaVErrMemory(vctxt, + "allocating the IDC key storage list", NULL); + return (-1); + } + vctxt->sizeIdcKeys = 40; + } else if (vctxt->sizeIdcKeys <= vctxt->nbIdcKeys) { + vctxt->sizeIdcKeys *= 2; + vctxt->idcKeys = (xmlSchemaPSVIIDCKeyPtr *) + xmlRealloc(vctxt->idcKeys, vctxt->sizeIdcKeys * + sizeof(xmlSchemaPSVIIDCKeyPtr)); + if (vctxt->idcKeys == NULL) { + xmlSchemaVErrMemory(vctxt, + "re-allocating the IDC key storage list", NULL); + return (-1); + } + } + vctxt->idcKeys[vctxt->nbIdcKeys++] = key; + + return (0); +} + +/** + * xmlSchemaIDCAppendNodeTableItem: + * @bind: the IDC binding + * @ntItem: the node-table item + * + * Appends the IDC node-table item to the binding. + * + * Returns 0 on success and -1 on internal errors. + */ +static int +xmlSchemaIDCAppendNodeTableItem(xmlSchemaPSVIIDCBindingPtr bind, + xmlSchemaPSVIIDCNodePtr ntItem) +{ + if (bind->nodeTable == NULL) { + bind->sizeNodes = 10; + bind->nodeTable = (xmlSchemaPSVIIDCNodePtr *) + xmlMalloc(10 * sizeof(xmlSchemaPSVIIDCNodePtr)); + if (bind->nodeTable == NULL) { + xmlSchemaVErrMemory(NULL, + "allocating an array of IDC node-table items", NULL); + return(-1); + } + } else if (bind->sizeNodes <= bind->nbNodes) { + bind->sizeNodes *= 2; + bind->nodeTable = (xmlSchemaPSVIIDCNodePtr *) + xmlRealloc(bind->nodeTable, bind->sizeNodes * + sizeof(xmlSchemaPSVIIDCNodePtr)); + if (bind->nodeTable == NULL) { + xmlSchemaVErrMemory(NULL, + "re-allocating an array of IDC node-table items", NULL); + return(-1); + } + } + bind->nodeTable[bind->nbNodes++] = ntItem; + return(0); +} + +/** + * xmlSchemaIDCAcquireBinding: + * @vctxt: the WXS validation context + * @matcher: the IDC matcher + * + * Looks up an PSVI IDC binding, for the IDC definition and + * of the given matcher. If none found, a new one is created + * and added to the IDC table. + * + * Returns an IDC binding or NULL on internal errors. + */ +static xmlSchemaPSVIIDCBindingPtr +xmlSchemaIDCAcquireBinding(xmlSchemaValidCtxtPtr vctxt, + xmlSchemaIDCMatcherPtr matcher) +{ + xmlSchemaNodeInfoPtr ielem; + + ielem = vctxt->elemInfos[matcher->depth]; + + if (ielem->idcTable == NULL) { + ielem->idcTable = xmlSchemaIDCNewBinding(matcher->aidc->def); + if (ielem->idcTable == NULL) + return (NULL); + return(ielem->idcTable); + } else { + xmlSchemaPSVIIDCBindingPtr bind = NULL; + + bind = ielem->idcTable; + do { + if (bind->definition == matcher->aidc->def) + return(bind); + if (bind->next == NULL) { + bind->next = xmlSchemaIDCNewBinding(matcher->aidc->def); + if (bind->next == NULL) + return (NULL); + return(bind->next); + } + bind = bind->next; + } while (bind != NULL); + } + return (NULL); +} + +static xmlSchemaItemListPtr +xmlSchemaIDCAcquireTargetList(xmlSchemaValidCtxtPtr vctxt ATTRIBUTE_UNUSED, + xmlSchemaIDCMatcherPtr matcher) +{ + if (matcher->targets == NULL) + matcher->targets = xmlSchemaItemListCreate(); + return(matcher->targets); +} + +/** + * xmlSchemaIDCFreeKey: + * @key: the IDC key + * + * Frees an IDC key together with its compiled value. + */ +static void +xmlSchemaIDCFreeKey(xmlSchemaPSVIIDCKeyPtr key) +{ + if (key->val != NULL) + xmlSchemaFreeValue(key->val); + xmlFree(key); +} + +/** + * xmlSchemaIDCFreeBinding: + * + * Frees an IDC binding. Note that the node table-items + * are not freed. + */ +static void +xmlSchemaIDCFreeBinding(xmlSchemaPSVIIDCBindingPtr bind) +{ + if (bind->nodeTable != NULL) + xmlFree(bind->nodeTable); + if (bind->dupls != NULL) + xmlSchemaItemListFree(bind->dupls); + xmlFree(bind); +} + +/** + * xmlSchemaIDCFreeIDCTable: + * @bind: the first IDC binding in the list + * + * Frees an IDC table, i.e. all the IDC bindings in the list. + */ +static void +xmlSchemaIDCFreeIDCTable(xmlSchemaPSVIIDCBindingPtr bind) +{ + xmlSchemaPSVIIDCBindingPtr prev; + + while (bind != NULL) { + prev = bind; + bind = bind->next; + xmlSchemaIDCFreeBinding(prev); + } +} + +/** + * xmlSchemaIDCFreeMatcherList: + * @matcher: the first IDC matcher in the list + * + * Frees a list of IDC matchers. + */ +static void +xmlSchemaIDCFreeMatcherList(xmlSchemaIDCMatcherPtr matcher) +{ + xmlSchemaIDCMatcherPtr next; + + while (matcher != NULL) { + next = matcher->next; + if (matcher->keySeqs != NULL) { + int i; + for (i = 0; i < matcher->sizeKeySeqs; i++) + if (matcher->keySeqs[i] != NULL) + xmlFree(matcher->keySeqs[i]); + xmlFree(matcher->keySeqs); + } + if (matcher->targets != NULL) { + if (matcher->idcType == XML_SCHEMA_TYPE_IDC_KEYREF) { + int i; + xmlSchemaPSVIIDCNodePtr idcNode; + /* + * Node-table items for keyrefs are not stored globally + * to the validation context, since they are not bubbled. + * We need to free them here. + */ + for (i = 0; i < matcher->targets->nbItems; i++) { + idcNode = + (xmlSchemaPSVIIDCNodePtr) matcher->targets->items[i]; + xmlFree(idcNode->keys); + xmlFree(idcNode); + } + } + xmlSchemaItemListFree(matcher->targets); + } + xmlFree(matcher); + matcher = next; + } +} + +/** + * xmlSchemaIDCReleaseMatcherList: + * @vctxt: the WXS validation context + * @matcher: the first IDC matcher in the list + * + * Caches a list of IDC matchers for reuse. + */ +static void +xmlSchemaIDCReleaseMatcherList(xmlSchemaValidCtxtPtr vctxt, + xmlSchemaIDCMatcherPtr matcher) +{ + xmlSchemaIDCMatcherPtr next; + + while (matcher != NULL) { + next = matcher->next; + if (matcher->keySeqs != NULL) { + int i; + /* + * Don't free the array, but only the content. + */ + for (i = 0; i < matcher->sizeKeySeqs; i++) + if (matcher->keySeqs[i] != NULL) { + xmlFree(matcher->keySeqs[i]); + matcher->keySeqs[i] = NULL; + } + } + if (matcher->targets) { + if (matcher->idcType == XML_SCHEMA_TYPE_IDC_KEYREF) { + int i; + xmlSchemaPSVIIDCNodePtr idcNode; + /* + * Node-table items for keyrefs are not stored globally + * to the validation context, since they are not bubbled. + * We need to free them here. + */ + for (i = 0; i < matcher->targets->nbItems; i++) { + idcNode = + (xmlSchemaPSVIIDCNodePtr) matcher->targets->items[i]; + xmlFree(idcNode->keys); + xmlFree(idcNode); + } + } + xmlSchemaItemListFree(matcher->targets); + matcher->targets = NULL; + } + matcher->next = NULL; + /* + * Cache the matcher. + */ + if (vctxt->idcMatcherCache != NULL) + matcher->nextCached = vctxt->idcMatcherCache; + vctxt->idcMatcherCache = matcher; + + matcher = next; + } +} + +/** + * xmlSchemaIDCAddStateObject: + * @vctxt: the WXS validation context + * @matcher: the IDC matcher + * @sel: the XPath information + * @parent: the parent "selector" state object if any + * @type: "selector" or "field" + * + * Creates/reuses and activates state objects for the given + * XPath information; if the XPath expression consists of unions, + * multiple state objects are created for every unioned expression. + * + * Returns 0 on success and -1 on internal errors. + */ +static int +xmlSchemaIDCAddStateObject(xmlSchemaValidCtxtPtr vctxt, + xmlSchemaIDCMatcherPtr matcher, + xmlSchemaIDCSelectPtr sel, + int type) +{ + xmlSchemaIDCStateObjPtr sto; + + /* + * Reuse the state objects from the pool. + */ + if (vctxt->xpathStatePool != NULL) { + sto = vctxt->xpathStatePool; + vctxt->xpathStatePool = sto->next; + sto->next = NULL; + } else { + /* + * Create a new state object. + */ + sto = (xmlSchemaIDCStateObjPtr) xmlMalloc(sizeof(xmlSchemaIDCStateObj)); + if (sto == NULL) { + xmlSchemaVErrMemory(NULL, + "allocating an IDC state object", NULL); + return (-1); + } + memset(sto, 0, sizeof(xmlSchemaIDCStateObj)); + } + /* + * Add to global list. + */ + if (vctxt->xpathStates != NULL) + sto->next = vctxt->xpathStates; + vctxt->xpathStates = sto; + + /* + * Free the old xpath validation context. + */ + if (sto->xpathCtxt != NULL) + xmlFreeStreamCtxt((xmlStreamCtxtPtr) sto->xpathCtxt); + + /* + * Create a new XPath (pattern) validation context. + */ + sto->xpathCtxt = (void *) xmlPatternGetStreamCtxt( + (xmlPatternPtr) sel->xpathComp); + if (sto->xpathCtxt == NULL) { + VERROR_INT("xmlSchemaIDCAddStateObject", + "failed to create an XPath validation context"); + return (-1); + } + sto->type = type; + sto->depth = vctxt->depth; + sto->matcher = matcher; + sto->sel = sel; + sto->nbHistory = 0; + +#ifdef DEBUG_IDC + xmlGenericError(xmlGenericErrorContext, "IDC: STO push '%s'\n", + sto->sel->xpath); +#endif + return (0); +} + +/** + * xmlSchemaXPathEvaluate: + * @vctxt: the WXS validation context + * @nodeType: the nodeType of the current node + * + * Evaluates all active XPath state objects. + * + * Returns the number of IC "field" state objects which resolved to + * this node, 0 if none resolved and -1 on internal errors. + */ +static int +xmlSchemaXPathEvaluate(xmlSchemaValidCtxtPtr vctxt, + xmlElementType nodeType) +{ + xmlSchemaIDCStateObjPtr sto, head = NULL, first; + int res, resolved = 0, depth = vctxt->depth; + + if (vctxt->xpathStates == NULL) + return (0); + + if (nodeType == XML_ATTRIBUTE_NODE) + depth++; +#ifdef DEBUG_IDC + { + xmlChar *str = NULL; + xmlGenericError(xmlGenericErrorContext, + "IDC: EVAL on %s, depth %d, type %d\n", + xmlSchemaFormatQName(&str, vctxt->inode->nsName, + vctxt->inode->localName), depth, nodeType); + FREE_AND_NULL(str) + } +#endif + /* + * Process all active XPath state objects. + */ + first = vctxt->xpathStates; + sto = first; + while (sto != head) { +#ifdef DEBUG_IDC + if (sto->type == XPATH_STATE_OBJ_TYPE_IDC_SELECTOR) + xmlGenericError(xmlGenericErrorContext, "IDC: ['%s'] selector '%s'\n", + sto->matcher->aidc->def->name, sto->sel->xpath); + else + xmlGenericError(xmlGenericErrorContext, "IDC: ['%s'] field '%s'\n", + sto->matcher->aidc->def->name, sto->sel->xpath); +#endif + if (nodeType == XML_ELEMENT_NODE) + res = xmlStreamPush((xmlStreamCtxtPtr) sto->xpathCtxt, + vctxt->inode->localName, vctxt->inode->nsName); + else + res = xmlStreamPushAttr((xmlStreamCtxtPtr) sto->xpathCtxt, + vctxt->inode->localName, vctxt->inode->nsName); + + if (res == -1) { + VERROR_INT("xmlSchemaXPathEvaluate", + "calling xmlStreamPush()"); + return (-1); + } + if (res == 0) + goto next_sto; + /* + * Full match. + */ +#ifdef DEBUG_IDC + xmlGenericError(xmlGenericErrorContext, "IDC: " + "MATCH\n"); +#endif + /* + * Register a match in the state object history. + */ + if (sto->history == NULL) { + sto->history = (int *) xmlMalloc(5 * sizeof(int)); + if (sto->history == NULL) { + xmlSchemaVErrMemory(NULL, + "allocating the state object history", NULL); + return(-1); + } + sto->sizeHistory = 5; + } else if (sto->sizeHistory <= sto->nbHistory) { + sto->sizeHistory *= 2; + sto->history = (int *) xmlRealloc(sto->history, + sto->sizeHistory * sizeof(int)); + if (sto->history == NULL) { + xmlSchemaVErrMemory(NULL, + "re-allocating the state object history", NULL); + return(-1); + } + } + sto->history[sto->nbHistory++] = depth; + +#ifdef DEBUG_IDC + xmlGenericError(xmlGenericErrorContext, "IDC: push match '%d'\n", + vctxt->depth); +#endif + + if (sto->type == XPATH_STATE_OBJ_TYPE_IDC_SELECTOR) { + xmlSchemaIDCSelectPtr sel; + /* + * Activate state objects for the IDC fields of + * the IDC selector. + */ +#ifdef DEBUG_IDC + xmlGenericError(xmlGenericErrorContext, "IDC: " + "activating field states\n"); +#endif + sel = sto->matcher->aidc->def->fields; + while (sel != NULL) { + if (xmlSchemaIDCAddStateObject(vctxt, sto->matcher, + sel, XPATH_STATE_OBJ_TYPE_IDC_FIELD) == -1) + return (-1); + sel = sel->next; + } + } else if (sto->type == XPATH_STATE_OBJ_TYPE_IDC_FIELD) { + /* + * An IDC key node was found by the IDC field. + */ +#ifdef DEBUG_IDC + xmlGenericError(xmlGenericErrorContext, + "IDC: key found\n"); +#endif + /* + * Notify that the character value of this node is + * needed. + */ + if (resolved == 0) { + if ((vctxt->inode->flags & + XML_SCHEMA_NODE_INFO_VALUE_NEEDED) == 0) + vctxt->inode->flags |= XML_SCHEMA_NODE_INFO_VALUE_NEEDED; + } + resolved++; + } +next_sto: + if (sto->next == NULL) { + /* + * Evaluate field state objects created on this node as well. + */ + head = first; + sto = vctxt->xpathStates; + } else + sto = sto->next; + } + return (resolved); +} + +static const xmlChar * +xmlSchemaFormatIDCKeySequence(xmlSchemaValidCtxtPtr vctxt, + xmlChar **buf, + xmlSchemaPSVIIDCKeyPtr *seq, + int count) +{ + int i, res; + xmlChar *value = NULL; + + *buf = xmlStrdup(BAD_CAST "["); + for (i = 0; i < count; i++) { + *buf = xmlStrcat(*buf, BAD_CAST "'"); + res = xmlSchemaGetCanonValueWhtspExt(seq[i]->val, + xmlSchemaGetWhiteSpaceFacetValue(seq[i]->type), + &value); + if (res == 0) + *buf = xmlStrcat(*buf, BAD_CAST value); + else { + VERROR_INT("xmlSchemaFormatIDCKeySequence", + "failed to compute a canonical value"); + *buf = xmlStrcat(*buf, BAD_CAST "???"); + } + if (i < count -1) + *buf = xmlStrcat(*buf, BAD_CAST "', "); + else + *buf = xmlStrcat(*buf, BAD_CAST "'"); + if (value != NULL) { + xmlFree(value); + value = NULL; + } + } + *buf = xmlStrcat(*buf, BAD_CAST "]"); + + return (BAD_CAST *buf); +} + +/** + * xmlSchemaXPathPop: + * @vctxt: the WXS validation context + * + * Pops all XPath states. + * + * Returns 0 on success and -1 on internal errors. + */ +static int +xmlSchemaXPathPop(xmlSchemaValidCtxtPtr vctxt) +{ + xmlSchemaIDCStateObjPtr sto; + int res; + + if (vctxt->xpathStates == NULL) + return(0); + sto = vctxt->xpathStates; + do { + res = xmlStreamPop((xmlStreamCtxtPtr) sto->xpathCtxt); + if (res == -1) + return (-1); + sto = sto->next; + } while (sto != NULL); + return(0); +} + +/** + * xmlSchemaXPathProcessHistory: + * @vctxt: the WXS validation context + * @type: the simple/complex type of the current node if any at all + * @val: the precompiled value + * + * Processes and pops the history items of the IDC state objects. + * IDC key-sequences are validated/created on IDC bindings. + * + * Returns 0 on success and -1 on internal errors. + */ +static int +xmlSchemaXPathProcessHistory(xmlSchemaValidCtxtPtr vctxt, + int depth) +{ + xmlSchemaIDCStateObjPtr sto, nextsto; + int res, matchDepth; + xmlSchemaPSVIIDCKeyPtr key = NULL; + xmlSchemaTypePtr type = vctxt->inode->typeDef, simpleType = NULL; + + if (vctxt->xpathStates == NULL) + return (0); + sto = vctxt->xpathStates; + +#ifdef DEBUG_IDC + { + xmlChar *str = NULL; + xmlGenericError(xmlGenericErrorContext, + "IDC: BACK on %s, depth %d\n", + xmlSchemaFormatQName(&str, vctxt->inode->nsName, + vctxt->inode->localName), vctxt->depth); + FREE_AND_NULL(str) + } +#endif + /* + * Evaluate the state objects. + */ + while (sto != NULL) { + res = xmlStreamPop((xmlStreamCtxtPtr) sto->xpathCtxt); + if (res == -1) { + VERROR_INT("xmlSchemaXPathProcessHistory", + "calling xmlStreamPop()"); + return (-1); + } +#ifdef DEBUG_IDC + xmlGenericError(xmlGenericErrorContext, "IDC: stream pop '%s'\n", + sto->sel->xpath); +#endif + if (sto->nbHistory == 0) + goto deregister_check; + + matchDepth = sto->history[sto->nbHistory -1]; + + /* + * Only matches at the current depth are of interest. + */ + if (matchDepth != depth) { + sto = sto->next; + continue; + } + if (sto->type == XPATH_STATE_OBJ_TYPE_IDC_FIELD) { + /* + * NOTE: According to + * http://www.w3.org/Bugs/Public/show_bug.cgi?id=2198 + * ... the simple-content of complex types is also allowed. + */ + + if (WXS_IS_COMPLEX(type)) { + if (WXS_HAS_SIMPLE_CONTENT(type)) { + /* + * Sanity check for complex types with simple content. + */ + simpleType = type->contentTypeDef; + if (simpleType == NULL) { + VERROR_INT("xmlSchemaXPathProcessHistory", + "field resolves to a CT with simple content " + "but the CT is missing the ST definition"); + return (-1); + } + } else + simpleType = NULL; + } else + simpleType = type; + if (simpleType == NULL) { + xmlChar *str = NULL; + + /* + * Not qualified if the field resolves to a node of non + * simple type. + */ + xmlSchemaCustomErr(ACTXT_CAST vctxt, + XML_SCHEMAV_CVC_IDC, NULL, + WXS_BASIC_CAST sto->matcher->aidc->def, + "The XPath '%s' of a field of %s does evaluate to a node of " + "non-simple type", + sto->sel->xpath, + xmlSchemaGetIDCDesignation(&str, sto->matcher->aidc->def)); + FREE_AND_NULL(str); + sto->nbHistory--; + goto deregister_check; + } + + if ((key == NULL) && (vctxt->inode->val == NULL)) { + /* + * Failed to provide the normalized value; maybe + * the value was invalid. + */ + VERROR(XML_SCHEMAV_CVC_IDC, + WXS_BASIC_CAST sto->matcher->aidc->def, + "Warning: No precomputed value available, the value " + "was either invalid or something strange happend"); + sto->nbHistory--; + goto deregister_check; + } else { + xmlSchemaIDCMatcherPtr matcher = sto->matcher; + xmlSchemaPSVIIDCKeyPtr *keySeq; + int pos, idx; + + /* + * The key will be anchored on the matcher's list of + * key-sequences. The position in this list is determined + * by the target node's depth relative to the matcher's + * depth of creation (i.e. the depth of the scope element). + * + * Element Depth Pos List-entries + * 0 NULL + * 1 NULL + * 2 2 target + * + * + * + * The size of the list is only dependant on the depth of + * the tree. + * An entry will be NULLed in selector_leave, i.e. when + * we hit the target's + */ + pos = sto->depth - matcher->depth; + idx = sto->sel->index; + + /* + * Create/grow the array of key-sequences. + */ + if (matcher->keySeqs == NULL) { + if (pos > 9) + matcher->sizeKeySeqs = pos * 2; + else + matcher->sizeKeySeqs = 10; + matcher->keySeqs = (xmlSchemaPSVIIDCKeyPtr **) + xmlMalloc(matcher->sizeKeySeqs * + sizeof(xmlSchemaPSVIIDCKeyPtr *)); + if (matcher->keySeqs == NULL) { + xmlSchemaVErrMemory(NULL, + "allocating an array of key-sequences", + NULL); + return(-1); + } + memset(matcher->keySeqs, 0, + matcher->sizeKeySeqs * + sizeof(xmlSchemaPSVIIDCKeyPtr *)); + } else if (pos >= matcher->sizeKeySeqs) { + int i = matcher->sizeKeySeqs; + + matcher->sizeKeySeqs *= 2; + matcher->keySeqs = (xmlSchemaPSVIIDCKeyPtr **) + xmlRealloc(matcher->keySeqs, + matcher->sizeKeySeqs * + sizeof(xmlSchemaPSVIIDCKeyPtr *)); + if (matcher->keySeqs == NULL) { + xmlSchemaVErrMemory(NULL, + "reallocating an array of key-sequences", + NULL); + return (-1); + } + /* + * The array needs to be NULLed. + * TODO: Use memset? + */ + for (; i < matcher->sizeKeySeqs; i++) + matcher->keySeqs[i] = NULL; + } + + /* + * Get/create the key-sequence. + */ + keySeq = matcher->keySeqs[pos]; + if (keySeq == NULL) { + goto create_sequence; + } else if (keySeq[idx] != NULL) { + xmlChar *str = NULL; + /* + * cvc-identity-constraint: + * 3 For each node in the �target node set� all + * of the {fields}, with that node as the context + * node, evaluate to either an empty node-set or + * a node-set with exactly one member, which must + * have a simple type. + * + * The key was already set; report an error. + */ + xmlSchemaCustomErr(ACTXT_CAST vctxt, + XML_SCHEMAV_CVC_IDC, NULL, + WXS_BASIC_CAST matcher->aidc->def, + "The XPath '%s' of a field of %s evaluates to a " + "node-set with more than one member", + sto->sel->xpath, + xmlSchemaGetIDCDesignation(&str, matcher->aidc->def)); + FREE_AND_NULL(str); + sto->nbHistory--; + goto deregister_check; + } else + goto create_key; + +create_sequence: + /* + * Create a key-sequence. + */ + keySeq = (xmlSchemaPSVIIDCKeyPtr *) xmlMalloc( + matcher->aidc->def->nbFields * + sizeof(xmlSchemaPSVIIDCKeyPtr)); + if (keySeq == NULL) { + xmlSchemaVErrMemory(NULL, + "allocating an IDC key-sequence", NULL); + return(-1); + } + memset(keySeq, 0, matcher->aidc->def->nbFields * + sizeof(xmlSchemaPSVIIDCKeyPtr)); + matcher->keySeqs[pos] = keySeq; +create_key: + /* + * Create a key once per node only. + */ + if (key == NULL) { + key = (xmlSchemaPSVIIDCKeyPtr) xmlMalloc( + sizeof(xmlSchemaPSVIIDCKey)); + if (key == NULL) { + xmlSchemaVErrMemory(NULL, + "allocating a IDC key", NULL); + xmlFree(keySeq); + matcher->keySeqs[pos] = NULL; + return(-1); + } + /* + * Consume the compiled value. + */ + key->type = simpleType; + key->val = vctxt->inode->val; + vctxt->inode->val = NULL; + /* + * Store the key in a global list. + */ + if (xmlSchemaIDCStoreKey(vctxt, key) == -1) { + xmlSchemaIDCFreeKey(key); + return (-1); + } + } + keySeq[idx] = key; + } + } else if (sto->type == XPATH_STATE_OBJ_TYPE_IDC_SELECTOR) { + + xmlSchemaPSVIIDCKeyPtr **keySeq = NULL; + /* xmlSchemaPSVIIDCBindingPtr bind; */ + xmlSchemaPSVIIDCNodePtr ntItem; + xmlSchemaIDCMatcherPtr matcher; + xmlSchemaIDCPtr idc; + xmlSchemaItemListPtr targets; + int pos, i, j, nbKeys; + /* + * Here we have the following scenario: + * An IDC 'selector' state object resolved to a target node, + * during the time this target node was in the + * ancestor-or-self axis, the 'field' state object(s) looked + * out for matching nodes to create a key-sequence for this + * target node. Now we are back to this target node and need + * to put the key-sequence, together with the target node + * itself, into the node-table of the corresponding IDC + * binding. + */ + matcher = sto->matcher; + idc = matcher->aidc->def; + nbKeys = idc->nbFields; + pos = depth - matcher->depth; + /* + * Check if the matcher has any key-sequences at all, plus + * if it has a key-sequence for the current target node. + */ + if ((matcher->keySeqs == NULL) || + (matcher->sizeKeySeqs <= pos)) { + if (idc->type == XML_SCHEMA_TYPE_IDC_KEY) + goto selector_key_error; + else + goto selector_leave; + } + + keySeq = &(matcher->keySeqs[pos]); + if (*keySeq == NULL) { + if (idc->type == XML_SCHEMA_TYPE_IDC_KEY) + goto selector_key_error; + else + goto selector_leave; + } + + for (i = 0; i < nbKeys; i++) { + if ((*keySeq)[i] == NULL) { + /* + * Not qualified, if not all fields did resolve. + */ + if (idc->type == XML_SCHEMA_TYPE_IDC_KEY) { + /* + * All fields of a "key" IDC must resolve. + */ + goto selector_key_error; + } + goto selector_leave; + } + } + /* + * All fields did resolve. + */ + + /* + * 4.1 If the {identity-constraint category} is unique(/key), + * then no two members of the �qualified node set� have + * �key-sequences� whose members are pairwise equal, as + * defined by Equal in [XML Schemas: Datatypes]. + * + * Get the IDC binding from the matcher and check for + * duplicate key-sequences. + */ +#if 0 + bind = xmlSchemaIDCAcquireBinding(vctxt, matcher); +#endif + targets = xmlSchemaIDCAcquireTargetList(vctxt, matcher); + if ((idc->type != XML_SCHEMA_TYPE_IDC_KEYREF) && + (targets->nbItems != 0)) { + xmlSchemaPSVIIDCKeyPtr ckey, bkey, *bkeySeq; + + i = 0; + res = 0; + /* + * Compare the key-sequences, key by key. + */ + do { + bkeySeq = + ((xmlSchemaPSVIIDCNodePtr) targets->items[i])->keys; + for (j = 0; j < nbKeys; j++) { + ckey = (*keySeq)[j]; + bkey = bkeySeq[j]; + res = xmlSchemaAreValuesEqual(ckey->val, bkey->val); + if (res == -1) { + return (-1); + } else if (res == 0) { + /* + * One of the keys differs, so the key-sequence + * won't be equal; get out. + */ + break; + } + } + if (res == 1) { + /* + * Duplicate key-sequence found. + */ + break; + } + i++; + } while (i < targets->nbItems); + if (i != targets->nbItems) { + xmlChar *str = NULL, *strB = NULL; + /* + * TODO: Try to report the key-sequence. + */ + xmlSchemaCustomErr(ACTXT_CAST vctxt, + XML_SCHEMAV_CVC_IDC, NULL, + WXS_BASIC_CAST idc, + "Duplicate key-sequence %s in %s", + xmlSchemaFormatIDCKeySequence(vctxt, &str, + (*keySeq), nbKeys), + xmlSchemaGetIDCDesignation(&strB, idc)); + FREE_AND_NULL(str); + FREE_AND_NULL(strB); + goto selector_leave; + } + } + /* + * Add a node-table item to the IDC binding. + */ + ntItem = (xmlSchemaPSVIIDCNodePtr) xmlMalloc( + sizeof(xmlSchemaPSVIIDCNode)); + if (ntItem == NULL) { + xmlSchemaVErrMemory(NULL, + "allocating an IDC node-table item", NULL); + xmlFree(*keySeq); + *keySeq = NULL; + return(-1); + } + memset(ntItem, 0, sizeof(xmlSchemaPSVIIDCNode)); + + /* + * Store the node-table item in a global list. + */ + if (idc->type != XML_SCHEMA_TYPE_IDC_KEYREF) { + if (xmlSchemaIDCStoreNodeTableItem(vctxt, ntItem) == -1) { + xmlFree(ntItem); + xmlFree(*keySeq); + *keySeq = NULL; + return (-1); + } + ntItem->nodeQNameID = -1; + } else { + /* + * Save a cached QName for this node on the IDC node, to be + * able to report it, even if the node is not saved. + */ + ntItem->nodeQNameID = xmlSchemaVAddNodeQName(vctxt, + vctxt->inode->localName, vctxt->inode->nsName); + if (ntItem->nodeQNameID == -1) { + xmlFree(ntItem); + xmlFree(*keySeq); + *keySeq = NULL; + return (-1); + } + } + /* + * Init the node-table item: Save the node, position and + * consume the key-sequence. + */ + ntItem->node = vctxt->node; + ntItem->nodeLine = vctxt->inode->nodeLine; + ntItem->keys = *keySeq; + *keySeq = NULL; +#if 0 + if (xmlSchemaIDCAppendNodeTableItem(bind, ntItem) == -1) +#endif + if (xmlSchemaItemListAdd(targets, ntItem) == -1) { + if (idc->type == XML_SCHEMA_TYPE_IDC_KEYREF) { + /* + * Free the item, since keyref items won't be + * put on a global list. + */ + xmlFree(ntItem->keys); + xmlFree(ntItem); + } + return (-1); + } + + goto selector_leave; +selector_key_error: + { + xmlChar *str = NULL; + /* + * 4.2.1 (KEY) The �target node set� and the + * �qualified node set� are equal, that is, every + * member of the �target node set� is also a member + * of the �qualified node set� and vice versa. + */ + xmlSchemaCustomErr(ACTXT_CAST vctxt, + XML_SCHEMAV_CVC_IDC, NULL, + WXS_BASIC_CAST idc, + "Not all fields of %s evaluate to a node", + xmlSchemaGetIDCDesignation(&str, idc), NULL); + FREE_AND_NULL(str); + } +selector_leave: + /* + * Free the key-sequence if not added to the IDC table. + */ + if ((keySeq != NULL) && (*keySeq != NULL)) { + xmlFree(*keySeq); + *keySeq = NULL; + } + } /* if selector */ + + sto->nbHistory--; + +deregister_check: + /* + * Deregister state objects if they reach the depth of creation. + */ + if ((sto->nbHistory == 0) && (sto->depth == depth)) { +#ifdef DEBUG_IDC + xmlGenericError(xmlGenericErrorContext, "IDC: STO pop '%s'\n", + sto->sel->xpath); +#endif + if (vctxt->xpathStates != sto) { + VERROR_INT("xmlSchemaXPathProcessHistory", + "The state object to be removed is not the first " + "in the list"); + } + nextsto = sto->next; + /* + * Unlink from the list of active XPath state objects. + */ + vctxt->xpathStates = sto->next; + sto->next = vctxt->xpathStatePool; + /* + * Link it to the pool of reusable state objects. + */ + vctxt->xpathStatePool = sto; + sto = nextsto; + } else + sto = sto->next; + } /* while (sto != NULL) */ + return (0); +} + +/** + * xmlSchemaIDCRegisterMatchers: + * @vctxt: the WXS validation context + * @elemDecl: the element declaration + * + * Creates helper objects to evaluate IDC selectors/fields + * successively. + * + * Returns 0 if OK and -1 on internal errors. + */ +static int +xmlSchemaIDCRegisterMatchers(xmlSchemaValidCtxtPtr vctxt, + xmlSchemaElementPtr elemDecl) +{ + xmlSchemaIDCMatcherPtr matcher, last = NULL; + xmlSchemaIDCPtr idc, refIdc; + xmlSchemaIDCAugPtr aidc; + + idc = (xmlSchemaIDCPtr) elemDecl->idcs; + if (idc == NULL) + return (0); + +#ifdef DEBUG_IDC + { + xmlChar *str = NULL; + xmlGenericError(xmlGenericErrorContext, + "IDC: REGISTER on %s, depth %d\n", + (char *) xmlSchemaFormatQName(&str, vctxt->inode->nsName, + vctxt->inode->localName), vctxt->depth); + FREE_AND_NULL(str) + } +#endif + if (vctxt->inode->idcMatchers != NULL) { + VERROR_INT("xmlSchemaIDCRegisterMatchers", + "The chain of IDC matchers is expected to be empty"); + return (-1); + } + do { + if (idc->type == XML_SCHEMA_TYPE_IDC_KEYREF) { + /* + * Since IDCs bubbles are expensive we need to know the + * depth at which the bubbles should stop; this will be + * the depth of the top-most keyref IDC. If no keyref + * references a key/unique IDC, the keyrefDepth will + * be -1, indicating that no bubbles are needed. + */ + refIdc = (xmlSchemaIDCPtr) idc->ref->item; + if (refIdc != NULL) { + /* + * Remember that we have keyrefs on this node. + */ + vctxt->inode->hasKeyrefs = 1; + /* + * Lookup the referenced augmented IDC info. + */ + aidc = vctxt->aidcs; + while (aidc != NULL) { + if (aidc->def == refIdc) + break; + aidc = aidc->next; + } + if (aidc == NULL) { + VERROR_INT("xmlSchemaIDCRegisterMatchers", + "Could not find an augmented IDC item for an IDC " + "definition"); + return (-1); + } + if ((aidc->keyrefDepth == -1) || + (vctxt->depth < aidc->keyrefDepth)) + aidc->keyrefDepth = vctxt->depth; + } + } + /* + * Lookup the augmented IDC item for the IDC definition. + */ + aidc = vctxt->aidcs; + while (aidc != NULL) { + if (aidc->def == idc) + break; + aidc = aidc->next; + } + if (aidc == NULL) { + VERROR_INT("xmlSchemaIDCRegisterMatchers", + "Could not find an augmented IDC item for an IDC definition"); + return (-1); + } + /* + * Create an IDC matcher for every IDC definition. + */ + if (vctxt->idcMatcherCache != NULL) { + /* + * Reuse a cached matcher. + */ + matcher = vctxt->idcMatcherCache; + vctxt->idcMatcherCache = matcher->nextCached; + matcher->nextCached = NULL; + } else { + matcher = (xmlSchemaIDCMatcherPtr) + xmlMalloc(sizeof(xmlSchemaIDCMatcher)); + if (matcher == NULL) { + xmlSchemaVErrMemory(vctxt, + "allocating an IDC matcher", NULL); + return (-1); + } + memset(matcher, 0, sizeof(xmlSchemaIDCMatcher)); + } + if (last == NULL) + vctxt->inode->idcMatchers = matcher; + else + last->next = matcher; + last = matcher; + + matcher->type = IDC_MATCHER; + matcher->depth = vctxt->depth; + matcher->aidc = aidc; + matcher->idcType = aidc->def->type; +#ifdef DEBUG_IDC + xmlGenericError(xmlGenericErrorContext, "IDC: register matcher\n"); +#endif + /* + * Init the automaton state object. + */ + if (xmlSchemaIDCAddStateObject(vctxt, matcher, + idc->selector, XPATH_STATE_OBJ_TYPE_IDC_SELECTOR) == -1) + return (-1); + + idc = idc->next; + } while (idc != NULL); + return (0); +} + +static int +xmlSchemaIDCFillNodeTables(xmlSchemaValidCtxtPtr vctxt, + xmlSchemaNodeInfoPtr ielem) +{ + xmlSchemaPSVIIDCBindingPtr bind; + int res, i, j, k, nbTargets, nbFields, nbDupls, nbNodeTable; + xmlSchemaPSVIIDCKeyPtr *keys, *ntkeys; + xmlSchemaPSVIIDCNodePtr *targets, *dupls; + + xmlSchemaIDCMatcherPtr matcher = ielem->idcMatchers; + /* vctxt->createIDCNodeTables */ + while (matcher != NULL) { + /* + * Skip keyref IDCs and empty IDC target-lists. + */ + if ((matcher->aidc->def->type == XML_SCHEMA_TYPE_IDC_KEYREF) || + WXS_ILIST_IS_EMPTY(matcher->targets)) + { + matcher = matcher->next; + continue; + } + /* + * If we _want_ the IDC node-table to be created in any case + * then do so. Otherwise create them only if keyrefs need them. + */ + if ((! vctxt->createIDCNodeTables) && + ((matcher->aidc->keyrefDepth == -1) || + (matcher->aidc->keyrefDepth > vctxt->depth))) + { + matcher = matcher->next; + continue; + } + /* + * Get/create the IDC binding on this element for the IDC definition. + */ + bind = xmlSchemaIDCAcquireBinding(vctxt, matcher); + + if (! WXS_ILIST_IS_EMPTY(bind->dupls)) { + dupls = (xmlSchemaPSVIIDCNodePtr *) bind->dupls->items; + nbDupls = bind->dupls->nbItems; + } else { + dupls = NULL; + nbDupls = 0; + } + if (bind->nodeTable != NULL) { + nbNodeTable = bind->nbNodes; + } else { + nbNodeTable = 0; + } + + if ((nbNodeTable == 0) && (nbDupls == 0)) { + /* + * Transfer all IDC target-nodes to the IDC node-table. + */ + bind->nodeTable = + (xmlSchemaPSVIIDCNodePtr *) matcher->targets->items; + bind->sizeNodes = matcher->targets->sizeItems; + bind->nbNodes = matcher->targets->nbItems; + + matcher->targets->items = NULL; + matcher->targets->sizeItems = 0; + matcher->targets->nbItems = 0; + } else { + /* + * Compare the key-sequences and add to the IDC node-table. + */ + nbTargets = matcher->targets->nbItems; + targets = (xmlSchemaPSVIIDCNodePtr *) matcher->targets->items; + nbFields = matcher->aidc->def->nbFields; + i = 0; + do { + keys = targets[i]->keys; + if (nbDupls) { + /* + * Search in already found duplicates first. + */ + j = 0; + do { + if (nbFields == 1) { + res = xmlSchemaAreValuesEqual(keys[0]->val, + dupls[j]->keys[0]->val); + if (res == -1) + goto internal_error; + if (res == 1) { + /* + * Equal key-sequence. + */ + goto next_target; + } + } else { + res = 0; + ntkeys = dupls[j]->keys; + for (k = 0; k < nbFields; k++) { + res = xmlSchemaAreValuesEqual(keys[k]->val, + ntkeys[k]->val); + if (res == -1) + goto internal_error; + if (res == 0) { + /* + * One of the keys differs. + */ + break; + } + } + if (res == 1) { + /* + * Equal key-sequence found. + */ + goto next_target; + } + } + j++; + } while (j < nbDupls); + } + if (nbNodeTable) { + j = 0; + do { + if (nbFields == 1) { + res = xmlSchemaAreValuesEqual(keys[0]->val, + bind->nodeTable[j]->keys[0]->val); + if (res == -1) + goto internal_error; + if (res == 0) { + /* + * The key-sequence differs. + */ + goto next_node_table_entry; + } + } else { + res = 0; + ntkeys = bind->nodeTable[j]->keys; + for (k = 0; k < nbFields; k++) { + res = xmlSchemaAreValuesEqual(keys[k]->val, + ntkeys[k]->val); + if (res == -1) + goto internal_error; + if (res == 0) { + /* + * One of the keys differs. + */ + goto next_node_table_entry; + } + } + } + /* + * Add the duplicate to the list of duplicates. + */ + if (bind->dupls == NULL) { + bind->dupls = xmlSchemaItemListCreate(); + if (bind->dupls == NULL) + goto internal_error; + } + if (xmlSchemaItemListAdd(bind->dupls, bind->nodeTable[j]) == -1) + goto internal_error; + /* + * Remove the duplicate entry from the IDC node-table. + */ + bind->nodeTable[j] = bind->nodeTable[bind->nbNodes -1]; + bind->nbNodes--; + + goto next_target; + +next_node_table_entry: + j++; + } while (j < nbNodeTable); + } + /* + * If everything is fine, then add the IDC target-node to + * the IDC node-table. + */ + if (xmlSchemaIDCAppendNodeTableItem(bind, targets[i]) == -1) + goto internal_error; + +next_target: + i++; + } while (i < nbTargets); + } + matcher = matcher->next; + } + return(0); + +internal_error: + return(-1); +} + +/** + * xmlSchemaBubbleIDCNodeTables: + * @depth: the current tree depth + * + * Merges IDC bindings of an element at @depth into the corresponding IDC + * bindings of its parent element. If a duplicate note-table entry is found, + * both, the parent node-table entry and child entry are discarded from the + * node-table of the parent. + * + * Returns 0 if OK and -1 on internal errors. + */ +static int +xmlSchemaBubbleIDCNodeTables(xmlSchemaValidCtxtPtr vctxt) +{ + xmlSchemaPSVIIDCBindingPtr bind; /* IDC bindings of the current node. */ + xmlSchemaPSVIIDCBindingPtr *parTable, parBind = NULL; /* parent IDC bindings. */ + xmlSchemaPSVIIDCNodePtr node, parNode = NULL, *dupls, *parNodes; /* node-table entries. */ + xmlSchemaIDCAugPtr aidc; + int i, j, k, ret = 0, nbFields, oldNum, oldDupls; + + bind = vctxt->inode->idcTable; + if (bind == NULL) { + /* Fine, no table, no bubbles. */ + return (0); + } + + parTable = &(vctxt->elemInfos[vctxt->depth -1]->idcTable); + /* + * Walk all bindings; create new or add to existing bindings. + * Remove duplicate key-sequences. + */ + while (bind != NULL) { + + if ((bind->nbNodes == 0) && WXS_ILIST_IS_EMPTY(bind->dupls)) + goto next_binding; + /* + * Check if the key/unique IDC table needs to be bubbled. + */ + if (! vctxt->createIDCNodeTables) { + aidc = vctxt->aidcs; + do { + if (aidc->def == bind->definition) { + if ((aidc->keyrefDepth == -1) || + (aidc->keyrefDepth >= vctxt->depth)) { + goto next_binding; + } + break; + } + aidc = aidc->next; + } while (aidc != NULL); + } + + if (parTable != NULL) + parBind = *parTable; + /* + * Search a matching parent binding for the + * IDC definition. + */ + while (parBind != NULL) { + if (parBind->definition == bind->definition) + break; + parBind = parBind->next; + } + + if (parBind != NULL) { + /* + * Compare every node-table entry of the child node, + * i.e. the key-sequence within, ... + */ + oldNum = parBind->nbNodes; /* Skip newly added items. */ + + if (! WXS_ILIST_IS_EMPTY(parBind->dupls)) { + oldDupls = parBind->dupls->nbItems; + dupls = (xmlSchemaPSVIIDCNodePtr *) parBind->dupls->items; + } else { + dupls = NULL; + oldDupls = 0; + } + + parNodes = parBind->nodeTable; + nbFields = bind->definition->nbFields; + + for (i = 0; i < bind->nbNodes; i++) { + node = bind->nodeTable[i]; + if (node == NULL) + continue; + /* + * ...with every key-sequence of the parent node, already + * evaluated to be a duplicate key-sequence. + */ + if (oldDupls) { + j = 0; + while (j < oldDupls) { + if (nbFields == 1) { + ret = xmlSchemaAreValuesEqual( + node->keys[0]->val, + dupls[j]->keys[0]->val); + if (ret == -1) + goto internal_error; + if (ret == 0) { + j++; + continue; + } + } else { + parNode = dupls[j]; + for (k = 0; k < nbFields; k++) { + ret = xmlSchemaAreValuesEqual( + node->keys[k]->val, + parNode->keys[k]->val); + if (ret == -1) + goto internal_error; + if (ret == 0) + break; + } + } + if (ret == 1) + /* Duplicate found. */ + break; + j++; + } + if (j != oldDupls) { + /* Duplicate found. Skip this entry. */ + continue; + } + } + /* + * ... and with every key-sequence of the parent node. + */ + if (oldNum) { + j = 0; + while (j < oldNum) { + parNode = parNodes[j]; + if (nbFields == 1) { + ret = xmlSchemaAreValuesEqual( + node->keys[0]->val, + parNode->keys[0]->val); + if (ret == -1) + goto internal_error; + if (ret == 0) { + j++; + continue; + } + } else { + for (k = 0; k < nbFields; k++) { + ret = xmlSchemaAreValuesEqual( + node->keys[k]->val, + parNode->keys[k]->val); + if (ret == -1) + goto internal_error; + if (ret == 0) + break; + } + } + if (ret == 1) + /* Duplicate found. */ + break; + j++; + } + if (j != oldNum) { + /* + * Handle duplicates. Move the duplicate in + * the parent's node-table to the list of + * duplicates. + */ + oldNum--; + parBind->nbNodes--; + /* + * Move last old item to pos of duplicate. + */ + parNodes[j] = parNodes[oldNum]; + + if (parBind->nbNodes != oldNum) { + /* + * If new items exist, move last new item to + * last of old items. + */ + parNodes[oldNum] = + parNodes[parBind->nbNodes]; + } + if (parBind->dupls == NULL) { + parBind->dupls = xmlSchemaItemListCreate(); + if (parBind->dupls == NULL) + goto internal_error; + } + xmlSchemaItemListAdd(parBind->dupls, parNode); + } else { + /* + * Add the node-table entry (node and key-sequence) of + * the child node to the node table of the parent node. + */ + if (parBind->nodeTable == NULL) { + parBind->nodeTable = (xmlSchemaPSVIIDCNodePtr *) + xmlMalloc(10 * sizeof(xmlSchemaPSVIIDCNodePtr)); + if (parBind->nodeTable == NULL) { + xmlSchemaVErrMemory(NULL, + "allocating IDC list of node-table items", NULL); + goto internal_error; + } + parBind->sizeNodes = 1; + } else if (parBind->nbNodes >= parBind->sizeNodes) { + parBind->sizeNodes *= 2; + parBind->nodeTable = (xmlSchemaPSVIIDCNodePtr *) + xmlRealloc(parBind->nodeTable, parBind->sizeNodes * + sizeof(xmlSchemaPSVIIDCNodePtr)); + if (parBind->nodeTable == NULL) { + xmlSchemaVErrMemory(NULL, + "re-allocating IDC list of node-table items", NULL); + goto internal_error; + } + } + parNodes = parBind->nodeTable; + /* + * Append the new node-table entry to the 'new node-table + * entries' section. + */ + parNodes[parBind->nbNodes++] = node; + } + + } + + } + } else { + /* + * No binding for the IDC was found: create a new one and + * copy all node-tables. + */ + parBind = xmlSchemaIDCNewBinding(bind->definition); + if (parBind == NULL) + goto internal_error; + + /* + * TODO: Hmm, how to optimize the initial number of + * allocated entries? + */ + if (bind->nbNodes != 0) { + /* + * Add all IDC node-table entries. + */ + if (! vctxt->psviExposeIDCNodeTables) { + /* + * Just move the entries. + * NOTE: this is quite save here, since + * all the keyref lookups have already been + * performed. + */ + parBind->nodeTable = bind->nodeTable; + bind->nodeTable = NULL; + parBind->sizeNodes = bind->sizeNodes; + bind->sizeNodes = 0; + parBind->nbNodes = bind->nbNodes; + bind->nbNodes = 0; + } else { + /* + * Copy the entries. + */ + parBind->nodeTable = (xmlSchemaPSVIIDCNodePtr *) + xmlMalloc(bind->nbNodes * + sizeof(xmlSchemaPSVIIDCNodePtr)); + if (parBind->nodeTable == NULL) { + xmlSchemaVErrMemory(NULL, + "allocating an array of IDC node-table " + "items", NULL); + xmlSchemaIDCFreeBinding(parBind); + goto internal_error; + } + parBind->sizeNodes = bind->nbNodes; + parBind->nbNodes = bind->nbNodes; + memcpy(parBind->nodeTable, bind->nodeTable, + bind->nbNodes * sizeof(xmlSchemaPSVIIDCNodePtr)); + } + } + if (bind->dupls) { + /* + * Move the duplicates. + */ + if (parBind->dupls != NULL) + xmlSchemaItemListFree(parBind->dupls); + parBind->dupls = bind->dupls; + bind->dupls = NULL; + } + if (parTable != NULL) { + if (*parTable == NULL) + *parTable = parBind; + else { + parBind->next = *parTable; + *parTable = parBind; + } + } + } + +next_binding: + bind = bind->next; + } + return (0); + +internal_error: + return(-1); +} + +/** + * xmlSchemaCheckCVCIDCKeyRef: + * @vctxt: the WXS validation context + * @elemDecl: the element declaration + * + * Check the cvc-idc-keyref constraints. + */ +static int +xmlSchemaCheckCVCIDCKeyRef(xmlSchemaValidCtxtPtr vctxt) +{ + xmlSchemaIDCMatcherPtr matcher; + xmlSchemaPSVIIDCBindingPtr bind; + + matcher = vctxt->inode->idcMatchers; + /* + * Find a keyref. + */ + while (matcher != NULL) { + if ((matcher->idcType == XML_SCHEMA_TYPE_IDC_KEYREF) && + matcher->targets && + matcher->targets->nbItems) + { + int i, j, k, res, nbFields, hasDupls; + xmlSchemaPSVIIDCKeyPtr *refKeys, *keys; + xmlSchemaPSVIIDCNodePtr refNode = NULL; + + nbFields = matcher->aidc->def->nbFields; + + /* + * Find the IDC node-table for the referenced IDC key/unique. + */ + bind = vctxt->inode->idcTable; + while (bind != NULL) { + if ((xmlSchemaIDCPtr) matcher->aidc->def->ref->item == + bind->definition) + break; + bind = bind->next; + } + hasDupls = (bind && bind->dupls && bind->dupls->nbItems) ? 1 : 0; + /* + * Search for a matching key-sequences. + */ + for (i = 0; i < matcher->targets->nbItems; i++) { + res = 0; + refNode = matcher->targets->items[i]; + if (bind != NULL) { + refKeys = refNode->keys; + for (j = 0; j < bind->nbNodes; j++) { + keys = bind->nodeTable[j]->keys; + for (k = 0; k < nbFields; k++) { + res = xmlSchemaAreValuesEqual(keys[k]->val, + refKeys[k]->val); + if (res == 0) + break; + else if (res == -1) { + return (-1); + } + } + if (res == 1) { + /* + * Match found. + */ + break; + } + } + if ((res == 0) && hasDupls) { + /* + * Search in duplicates + */ + for (j = 0; j < bind->dupls->nbItems; j++) { + keys = ((xmlSchemaPSVIIDCNodePtr) + bind->dupls->items[j])->keys; + for (k = 0; k < nbFields; k++) { + res = xmlSchemaAreValuesEqual(keys[k]->val, + refKeys[k]->val); + if (res == 0) + break; + else if (res == -1) { + return (-1); + } + } + if (res == 1) { + /* + * Match in duplicates found. + */ + xmlChar *str = NULL, *strB = NULL; + xmlSchemaKeyrefErr(vctxt, + XML_SCHEMAV_CVC_IDC, refNode, + (xmlSchemaTypePtr) matcher->aidc->def, + "More than one match found for " + "key-sequence %s of keyref '%s'", + xmlSchemaFormatIDCKeySequence(vctxt, &str, + refNode->keys, nbFields), + xmlSchemaGetComponentQName(&strB, + matcher->aidc->def)); + FREE_AND_NULL(str); + FREE_AND_NULL(strB); + break; + } + } + } + } + + if (res == 0) { + xmlChar *str = NULL, *strB = NULL; + xmlSchemaKeyrefErr(vctxt, + XML_SCHEMAV_CVC_IDC, refNode, + (xmlSchemaTypePtr) matcher->aidc->def, + "No match found for key-sequence %s of keyref '%s'", + xmlSchemaFormatIDCKeySequence(vctxt, &str, + refNode->keys, nbFields), + xmlSchemaGetComponentQName(&strB, matcher->aidc->def)); + FREE_AND_NULL(str); + FREE_AND_NULL(strB); + } + } + } + matcher = matcher->next; + } + /* TODO: Return an error if any error encountered. */ + return (0); +} + +/************************************************************************ + * * + * XML Reader validation code * + * * + ************************************************************************/ + +static xmlSchemaAttrInfoPtr +xmlSchemaGetFreshAttrInfo(xmlSchemaValidCtxtPtr vctxt) +{ + xmlSchemaAttrInfoPtr iattr; + /* + * Grow/create list of attribute infos. + */ + if (vctxt->attrInfos == NULL) { + vctxt->attrInfos = (xmlSchemaAttrInfoPtr *) + xmlMalloc(sizeof(xmlSchemaAttrInfoPtr)); + vctxt->sizeAttrInfos = 1; + if (vctxt->attrInfos == NULL) { + xmlSchemaVErrMemory(vctxt, + "allocating attribute info list", NULL); + return (NULL); + } + } else if (vctxt->sizeAttrInfos <= vctxt->nbAttrInfos) { + vctxt->sizeAttrInfos++; + vctxt->attrInfos = (xmlSchemaAttrInfoPtr *) + xmlRealloc(vctxt->attrInfos, + vctxt->sizeAttrInfos * sizeof(xmlSchemaAttrInfoPtr)); + if (vctxt->attrInfos == NULL) { + xmlSchemaVErrMemory(vctxt, + "re-allocating attribute info list", NULL); + return (NULL); + } + } else { + iattr = vctxt->attrInfos[vctxt->nbAttrInfos++]; + if (iattr->localName != NULL) { + VERROR_INT("xmlSchemaGetFreshAttrInfo", + "attr info not cleared"); + return (NULL); + } + iattr->nodeType = XML_ATTRIBUTE_NODE; + return (iattr); + } + /* + * Create an attribute info. + */ + iattr = (xmlSchemaAttrInfoPtr) + xmlMalloc(sizeof(xmlSchemaAttrInfo)); + if (iattr == NULL) { + xmlSchemaVErrMemory(vctxt, "creating new attribute info", NULL); + return (NULL); + } + memset(iattr, 0, sizeof(xmlSchemaAttrInfo)); + iattr->nodeType = XML_ATTRIBUTE_NODE; + vctxt->attrInfos[vctxt->nbAttrInfos++] = iattr; + + return (iattr); +} + +static int +xmlSchemaValidatorPushAttribute(xmlSchemaValidCtxtPtr vctxt, + xmlNodePtr attrNode, + int nodeLine, + const xmlChar *localName, + const xmlChar *nsName, + int ownedNames, + xmlChar *value, + int ownedValue) +{ + xmlSchemaAttrInfoPtr attr; + + attr = xmlSchemaGetFreshAttrInfo(vctxt); + if (attr == NULL) { + VERROR_INT("xmlSchemaPushAttribute", + "calling xmlSchemaGetFreshAttrInfo()"); + return (-1); + } + attr->node = attrNode; + attr->nodeLine = nodeLine; + attr->state = XML_SCHEMAS_ATTR_UNKNOWN; + attr->localName = localName; + attr->nsName = nsName; + if (ownedNames) + attr->flags |= XML_SCHEMA_NODE_INFO_FLAG_OWNED_NAMES; + /* + * Evaluate if it's an XSI attribute. + */ + if (nsName != NULL) { + if (xmlStrEqual(localName, BAD_CAST "nil")) { + if (xmlStrEqual(attr->nsName, xmlSchemaInstanceNs)) { + attr->metaType = XML_SCHEMA_ATTR_INFO_META_XSI_NIL; + } + } else if (xmlStrEqual(localName, BAD_CAST "type")) { + if (xmlStrEqual(attr->nsName, xmlSchemaInstanceNs)) { + attr->metaType = XML_SCHEMA_ATTR_INFO_META_XSI_TYPE; + } + } else if (xmlStrEqual(localName, BAD_CAST "schemaLocation")) { + if (xmlStrEqual(attr->nsName, xmlSchemaInstanceNs)) { + attr->metaType = XML_SCHEMA_ATTR_INFO_META_XSI_SCHEMA_LOC; + } + } else if (xmlStrEqual(localName, BAD_CAST "noNamespaceSchemaLocation")) { + if (xmlStrEqual(attr->nsName, xmlSchemaInstanceNs)) { + attr->metaType = XML_SCHEMA_ATTR_INFO_META_XSI_NO_NS_SCHEMA_LOC; + } + } else if (xmlStrEqual(attr->nsName, xmlNamespaceNs)) { + attr->metaType = XML_SCHEMA_ATTR_INFO_META_XMLNS; + } + } + attr->value = value; + if (ownedValue) + attr->flags |= XML_SCHEMA_NODE_INFO_FLAG_OWNED_VALUES; + if (attr->metaType != 0) + attr->state = XML_SCHEMAS_ATTR_META; + return (0); +} + +/** + * xmlSchemaClearElemInfo: + * @vctxt: the WXS validation context + * @ielem: the element information item + */ +static void +xmlSchemaClearElemInfo(xmlSchemaValidCtxtPtr vctxt, + xmlSchemaNodeInfoPtr ielem) +{ + ielem->hasKeyrefs = 0; + ielem->appliedXPath = 0; + if (ielem->flags & XML_SCHEMA_NODE_INFO_FLAG_OWNED_NAMES) { + FREE_AND_NULL(ielem->localName); + FREE_AND_NULL(ielem->nsName); + } else { + ielem->localName = NULL; + ielem->nsName = NULL; + } + if (ielem->flags & XML_SCHEMA_NODE_INFO_FLAG_OWNED_VALUES) { + FREE_AND_NULL(ielem->value); + } else { + ielem->value = NULL; + } + if (ielem->val != NULL) { + /* + * PSVI TODO: Be careful not to free it when the value is + * exposed via PSVI. + */ + xmlSchemaFreeValue(ielem->val); + ielem->val = NULL; + } + if (ielem->idcMatchers != NULL) { + /* + * REVISIT OPTIMIZE TODO: Use a pool of IDC matchers. + * Does it work? + */ + xmlSchemaIDCReleaseMatcherList(vctxt, ielem->idcMatchers); +#if 0 + xmlSchemaIDCFreeMatcherList(ielem->idcMatchers); +#endif + ielem->idcMatchers = NULL; + } + if (ielem->idcTable != NULL) { + /* + * OPTIMIZE TODO: Use a pool of IDC tables??. + */ + xmlSchemaIDCFreeIDCTable(ielem->idcTable); + ielem->idcTable = NULL; + } + if (ielem->regexCtxt != NULL) { + xmlRegFreeExecCtxt(ielem->regexCtxt); + ielem->regexCtxt = NULL; + } + if (ielem->nsBindings != NULL) { + xmlFree((xmlChar **)ielem->nsBindings); + ielem->nsBindings = NULL; + ielem->nbNsBindings = 0; + ielem->sizeNsBindings = 0; + } +} + +/** + * xmlSchemaGetFreshElemInfo: + * @vctxt: the schema validation context + * + * Creates/reuses and initializes the element info item for + * the currect tree depth. + * + * Returns the element info item or NULL on API or internal errors. + */ +static xmlSchemaNodeInfoPtr +xmlSchemaGetFreshElemInfo(xmlSchemaValidCtxtPtr vctxt) +{ + xmlSchemaNodeInfoPtr info = NULL; + + if (vctxt->depth > vctxt->sizeElemInfos) { + VERROR_INT("xmlSchemaGetFreshElemInfo", + "inconsistent depth encountered"); + return (NULL); + } + if (vctxt->elemInfos == NULL) { + vctxt->elemInfos = (xmlSchemaNodeInfoPtr *) + xmlMalloc(10 * sizeof(xmlSchemaNodeInfoPtr)); + if (vctxt->elemInfos == NULL) { + xmlSchemaVErrMemory(vctxt, + "allocating the element info array", NULL); + return (NULL); + } + memset(vctxt->elemInfos, 0, 10 * sizeof(xmlSchemaNodeInfoPtr)); + vctxt->sizeElemInfos = 10; + } else if (vctxt->sizeElemInfos <= vctxt->depth) { + int i = vctxt->sizeElemInfos; + + vctxt->sizeElemInfos *= 2; + vctxt->elemInfos = (xmlSchemaNodeInfoPtr *) + xmlRealloc(vctxt->elemInfos, vctxt->sizeElemInfos * + sizeof(xmlSchemaNodeInfoPtr)); + if (vctxt->elemInfos == NULL) { + xmlSchemaVErrMemory(vctxt, + "re-allocating the element info array", NULL); + return (NULL); + } + /* + * We need the new memory to be NULLed. + * TODO: Use memset instead? + */ + for (; i < vctxt->sizeElemInfos; i++) + vctxt->elemInfos[i] = NULL; + } else + info = vctxt->elemInfos[vctxt->depth]; + + if (info == NULL) { + info = (xmlSchemaNodeInfoPtr) + xmlMalloc(sizeof(xmlSchemaNodeInfo)); + if (info == NULL) { + xmlSchemaVErrMemory(vctxt, + "allocating an element info", NULL); + return (NULL); + } + vctxt->elemInfos[vctxt->depth] = info; + } else { + if (info->localName != NULL) { + VERROR_INT("xmlSchemaGetFreshElemInfo", + "elem info has not been cleared"); + return (NULL); + } + } + memset(info, 0, sizeof(xmlSchemaNodeInfo)); + info->nodeType = XML_ELEMENT_NODE; + info->depth = vctxt->depth; + + return (info); +} + +#define ACTIVATE_ATTRIBUTE(item) vctxt->inode = (xmlSchemaNodeInfoPtr) item; +#define ACTIVATE_ELEM vctxt->inode = vctxt->elemInfos[vctxt->depth]; +#define ACTIVATE_PARENT_ELEM vctxt->inode = vctxt->elemInfos[vctxt->depth -1]; + +static int +xmlSchemaValidateFacets(xmlSchemaAbstractCtxtPtr actxt, + xmlNodePtr node, + xmlSchemaTypePtr type, + xmlSchemaValType valType, + const xmlChar * value, + xmlSchemaValPtr val, + unsigned long length, + int fireErrors) +{ + int ret, error = 0; + + xmlSchemaTypePtr tmpType; + xmlSchemaFacetLinkPtr facetLink; + xmlSchemaFacetPtr facet; + unsigned long len = 0; + xmlSchemaWhitespaceValueType ws; + + /* + * In Libxml2, derived built-in types have currently no explicit facets. + */ + if (type->type == XML_SCHEMA_TYPE_BASIC) + return (0); + + /* + * NOTE: Do not jump away, if the facetSet of the given type is + * empty: until now, "pattern" and "enumeration" facets of the + * *base types* need to be checked as well. + */ + if (type->facetSet == NULL) + goto pattern_and_enum; + + if (! WXS_IS_ATOMIC(type)) { + if (WXS_IS_LIST(type)) + goto WXS_IS_LIST; + else + goto pattern_and_enum; + } + /* + * Whitespace handling is only of importance for string-based + * types. + */ + tmpType = xmlSchemaGetPrimitiveType(type); + if ((tmpType->builtInType == XML_SCHEMAS_STRING) || + WXS_IS_ANY_SIMPLE_TYPE(tmpType)) { + ws = xmlSchemaGetWhiteSpaceFacetValue(type); + } else + ws = XML_SCHEMA_WHITESPACE_COLLAPSE; + /* + * If the value was not computed (for string or + * anySimpleType based types), then use the provided + * type. + */ + if (val == NULL) + valType = valType; + else + valType = xmlSchemaGetValType(val); + + ret = 0; + for (facetLink = type->facetSet; facetLink != NULL; + facetLink = facetLink->next) { + /* + * Skip the pattern "whiteSpace": it is used to + * format the character content beforehand. + */ + switch (facetLink->facet->type) { + case XML_SCHEMA_FACET_WHITESPACE: + case XML_SCHEMA_FACET_PATTERN: + case XML_SCHEMA_FACET_ENUMERATION: + continue; + case XML_SCHEMA_FACET_LENGTH: + case XML_SCHEMA_FACET_MINLENGTH: + case XML_SCHEMA_FACET_MAXLENGTH: + ret = xmlSchemaValidateLengthFacetWhtsp(facetLink->facet, + valType, value, val, &len, ws); + break; + default: + ret = xmlSchemaValidateFacetWhtsp(facetLink->facet, ws, + valType, value, val, ws); + break; + } + if (ret < 0) { + AERROR_INT("xmlSchemaValidateFacets", + "validating against a atomic type facet"); + return (-1); + } else if (ret > 0) { + if (fireErrors) + xmlSchemaFacetErr(actxt, ret, node, + value, len, type, facetLink->facet, NULL, NULL, NULL); + else + return (ret); + if (error == 0) + error = ret; + } + ret = 0; + } + +WXS_IS_LIST: + if (! WXS_IS_LIST(type)) + goto pattern_and_enum; + /* + * "length", "minLength" and "maxLength" of list types. + */ + ret = 0; + for (facetLink = type->facetSet; facetLink != NULL; + facetLink = facetLink->next) { + + switch (facetLink->facet->type) { + case XML_SCHEMA_FACET_LENGTH: + case XML_SCHEMA_FACET_MINLENGTH: + case XML_SCHEMA_FACET_MAXLENGTH: + ret = xmlSchemaValidateListSimpleTypeFacet(facetLink->facet, + value, length, NULL); + break; + default: + continue; + } + if (ret < 0) { + AERROR_INT("xmlSchemaValidateFacets", + "validating against a list type facet"); + return (-1); + } else if (ret > 0) { + if (fireErrors) + xmlSchemaFacetErr(actxt, ret, node, + value, length, type, facetLink->facet, NULL, NULL, NULL); + else + return (ret); + if (error == 0) + error = ret; + } + ret = 0; + } + +pattern_and_enum: + if (error >= 0) { + int found = 0; + /* + * Process enumerations. Facet values are in the value space + * of the defining type's base type. This seems to be a bug in the + * XML Schema 1.0 spec. Use the whitespace type of the base type. + * Only the first set of enumerations in the ancestor-or-self axis + * is used for validation. + */ + ret = 0; + tmpType = type; + do { + for (facet = tmpType->facets; facet != NULL; facet = facet->next) { + if (facet->type != XML_SCHEMA_FACET_ENUMERATION) + continue; + found = 1; + ret = xmlSchemaAreValuesEqual(facet->val, val); + if (ret == 1) + break; + else if (ret < 0) { + AERROR_INT("xmlSchemaValidateFacets", + "validating against an enumeration facet"); + return (-1); + } + } + if (ret != 0) + break; + /* + * Break on the first set of enumerations. Any additional + * enumerations which might be existent on the ancestors + * of the current type are restricted by this set; thus + * *must* *not* be taken into account. + */ + if (found) + break; + tmpType = tmpType->baseType; + } while ((tmpType != NULL) && + (tmpType->type != XML_SCHEMA_TYPE_BASIC)); + if (found && (ret == 0)) { + ret = XML_SCHEMAV_CVC_ENUMERATION_VALID; + if (fireErrors) { + xmlSchemaFacetErr(actxt, ret, node, + value, 0, type, NULL, NULL, NULL, NULL); + } else + return (ret); + if (error == 0) + error = ret; + } + } + + if (error >= 0) { + int found; + /* + * Process patters. Pattern facets are ORed at type level + * and ANDed if derived. Walk the base type axis. + */ + tmpType = type; + facet = NULL; + do { + found = 0; + for (facetLink = tmpType->facetSet; facetLink != NULL; + facetLink = facetLink->next) { + if (facetLink->facet->type != XML_SCHEMA_FACET_PATTERN) + continue; + found = 1; + /* + * NOTE that for patterns, @value needs to be the + * normalized vaule. + */ + ret = xmlRegexpExec(facetLink->facet->regexp, value); + if (ret == 1) + break; + else if (ret < 0) { + AERROR_INT("xmlSchemaValidateFacets", + "validating against a pattern facet"); + return (-1); + } else { + /* + * Save the last non-validating facet. + */ + facet = facetLink->facet; + } + } + if (found && (ret != 1)) { + ret = XML_SCHEMAV_CVC_PATTERN_VALID; + if (fireErrors) { + xmlSchemaFacetErr(actxt, ret, node, + value, 0, type, facet, NULL, NULL, NULL); + } else + return (ret); + if (error == 0) + error = ret; + break; + } + tmpType = tmpType->baseType; + } while ((tmpType != NULL) && (tmpType->type != XML_SCHEMA_TYPE_BASIC)); + } + + return (error); +} + +static xmlChar * +xmlSchemaNormalizeValue(xmlSchemaTypePtr type, + const xmlChar *value) +{ + switch (xmlSchemaGetWhiteSpaceFacetValue(type)) { + case XML_SCHEMA_WHITESPACE_COLLAPSE: + return (xmlSchemaCollapseString(value)); + case XML_SCHEMA_WHITESPACE_REPLACE: + return (xmlSchemaWhiteSpaceReplace(value)); + default: + return (NULL); + } +} + +static int +xmlSchemaValidateQName(xmlSchemaValidCtxtPtr vctxt, + const xmlChar *value, + xmlSchemaValPtr *val, + int valNeeded) +{ + int ret; + const xmlChar *nsName; + xmlChar *local, *prefix = NULL; + + ret = xmlValidateQName(value, 1); + if (ret != 0) { + if (ret == -1) { + VERROR_INT("xmlSchemaValidateQName", + "calling xmlValidateQName()"); + return (-1); + } + return( XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_1); + } + /* + * NOTE: xmlSplitQName2 will always return a duplicated + * strings. + */ + local = xmlSplitQName2(value, &prefix); + if (local == NULL) + local = xmlStrdup(value); + /* + * OPTIMIZE TODO: Use flags for: + * - is there any namespace binding? + * - is there a default namespace? + */ + nsName = xmlSchemaLookupNamespace(vctxt, prefix); + + if (prefix != NULL) { + xmlFree(prefix); + /* + * A namespace must be found if the prefix is + * NOT NULL. + */ + if (nsName == NULL) { + ret = XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_1; + xmlSchemaCustomErr(ACTXT_CAST vctxt, ret, NULL, + WXS_BASIC_CAST xmlSchemaGetBuiltInType(XML_SCHEMAS_QNAME), + "The QName value '%s' has no " + "corresponding namespace declaration in " + "scope", value, NULL); + if (local != NULL) + xmlFree(local); + return (ret); + } + } + if (valNeeded && val) { + if (nsName != NULL) + *val = xmlSchemaNewQNameValue( + BAD_CAST xmlStrdup(nsName), BAD_CAST local); + else + *val = xmlSchemaNewQNameValue(NULL, + BAD_CAST local); + } else + xmlFree(local); + return (0); +} + +/* +* cvc-simple-type +*/ +static int +xmlSchemaVCheckCVCSimpleType(xmlSchemaAbstractCtxtPtr actxt, + xmlNodePtr node, + xmlSchemaTypePtr type, + const xmlChar *value, + xmlSchemaValPtr *retVal, + int fireErrors, + int normalize, + int isNormalized) +{ + int ret = 0, valNeeded = (retVal) ? 1 : 0; + xmlSchemaValPtr val = NULL; + /* xmlSchemaWhitespaceValueType ws; */ + xmlChar *normValue = NULL; + +#define NORMALIZE(atype) \ + if ((! isNormalized) && \ + (normalize || (type->flags & XML_SCHEMAS_TYPE_NORMVALUENEEDED))) { \ + normValue = xmlSchemaNormalizeValue(atype, value); \ + if (normValue != NULL) \ + value = normValue; \ + isNormalized = 1; \ + } + + if ((retVal != NULL) && (*retVal != NULL)) { + xmlSchemaFreeValue(*retVal); + *retVal = NULL; + } + /* + * 3.14.4 Simple Type Definition Validation Rules + * Validation Rule: String Valid + */ + /* + * 1 It is schema-valid with respect to that definition as defined + * by Datatype Valid in [XML Schemas: Datatypes]. + */ + /* + * 2.1 If The definition is ENTITY or is validly derived from ENTITY given + * the empty set, as defined in Type Derivation OK (Simple) (�3.14.6), then + * the string must be a �declared entity name�. + */ + /* + * 2.2 If The definition is ENTITIES or is validly derived from ENTITIES + * given the empty set, as defined in Type Derivation OK (Simple) (�3.14.6), + * then every whitespace-delimited substring of the string must be a �declared + * entity name�. + */ + /* + * 2.3 otherwise no further condition applies. + */ + if ((! valNeeded) && (type->flags & XML_SCHEMAS_TYPE_FACETSNEEDVALUE)) + valNeeded = 1; + if (value == NULL) + value = BAD_CAST ""; + if (WXS_IS_ANY_SIMPLE_TYPE(type) || WXS_IS_ATOMIC(type)) { + xmlSchemaTypePtr biType; /* The built-in type. */ + /* + * SPEC (1.2.1) "if {variety} is �atomic� then the string must �match� + * a literal in the �lexical space� of {base type definition}" + */ + /* + * Whitespace-normalize. + */ + NORMALIZE(type); + if (type->type != XML_SCHEMA_TYPE_BASIC) { + /* + * Get the built-in type. + */ + biType = type->baseType; + while ((biType != NULL) && + (biType->type != XML_SCHEMA_TYPE_BASIC)) + biType = biType->baseType; + + if (biType == NULL) { + AERROR_INT("xmlSchemaVCheckCVCSimpleType", + "could not get the built-in type"); + goto internal_error; + } + } else + biType = type; + /* + * NOTATIONs need to be processed here, since they need + * to lookup in the hashtable of NOTATION declarations of the schema. + */ + if (actxt->type == XML_SCHEMA_CTXT_VALIDATOR) { + switch (biType->builtInType) { + case XML_SCHEMAS_NOTATION: + ret = xmlSchemaValidateNotation( + (xmlSchemaValidCtxtPtr) actxt, + ((xmlSchemaValidCtxtPtr) actxt)->schema, + NULL, value, &val, valNeeded); + break; + case XML_SCHEMAS_QNAME: + ret = xmlSchemaValidateQName((xmlSchemaValidCtxtPtr) actxt, + value, &val, valNeeded); + break; + default: + /* ws = xmlSchemaGetWhiteSpaceFacetValue(type); */ + if (valNeeded) + ret = xmlSchemaValPredefTypeNodeNoNorm(biType, + value, &val, node); + else + ret = xmlSchemaValPredefTypeNodeNoNorm(biType, + value, NULL, node); + break; + } + } else if (actxt->type == XML_SCHEMA_CTXT_PARSER) { + switch (biType->builtInType) { + case XML_SCHEMAS_NOTATION: + ret = xmlSchemaValidateNotation(NULL, + ((xmlSchemaParserCtxtPtr) actxt)->schema, node, + value, &val, valNeeded); + break; + default: + /* ws = xmlSchemaGetWhiteSpaceFacetValue(type); */ + if (valNeeded) + ret = xmlSchemaValPredefTypeNodeNoNorm(biType, + value, &val, node); + else + ret = xmlSchemaValPredefTypeNodeNoNorm(biType, + value, NULL, node); + break; + } + } else { + /* + * Validation via a public API is not implemented yet. + */ + TODO + goto internal_error; + } + if (ret != 0) { + if (ret < 0) { + AERROR_INT("xmlSchemaVCheckCVCSimpleType", + "validating against a built-in type"); + goto internal_error; + } + if (WXS_IS_LIST(type)) + ret = XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_2; + else + ret = XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_1; + } + if ((ret == 0) && (type->flags & XML_SCHEMAS_TYPE_HAS_FACETS)) { + /* + * Check facets. + */ + ret = xmlSchemaValidateFacets(actxt, node, type, + (xmlSchemaValType) biType->builtInType, value, val, + 0, fireErrors); + if (ret != 0) { + if (ret < 0) { + AERROR_INT("xmlSchemaVCheckCVCSimpleType", + "validating facets of atomic simple type"); + goto internal_error; + } + if (WXS_IS_LIST(type)) + ret = XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_2; + else + ret = XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_1; + } + } + if (fireErrors && (ret > 0)) + xmlSchemaSimpleTypeErr(actxt, ret, node, value, type, 1); + } else if (WXS_IS_LIST(type)) { + + xmlSchemaTypePtr itemType; + const xmlChar *cur, *end; + xmlChar *tmpValue = NULL; + unsigned long len = 0; + xmlSchemaValPtr prevVal = NULL, curVal = NULL; + /* 1.2.2 if {variety} is �list� then the string must be a sequence + * of white space separated tokens, each of which �match�es a literal + * in the �lexical space� of {item type definition} + */ + /* + * Note that XML_SCHEMAS_TYPE_NORMVALUENEEDED will be set if + * the list type has an enum or pattern facet. + */ + NORMALIZE(type); + /* + * VAL TODO: Optimize validation of empty values. + * VAL TODO: We do not have computed values for lists. + */ + itemType = WXS_LIST_ITEMTYPE(type); + cur = value; + do { + while (IS_BLANK_CH(*cur)) + cur++; + end = cur; + while ((*end != 0) && (!(IS_BLANK_CH(*end)))) + end++; + if (end == cur) + break; + tmpValue = xmlStrndup(cur, end - cur); + len++; + + if (valNeeded) + ret = xmlSchemaVCheckCVCSimpleType(actxt, node, itemType, + tmpValue, &curVal, fireErrors, 0, 1); + else + ret = xmlSchemaVCheckCVCSimpleType(actxt, node, itemType, + tmpValue, NULL, fireErrors, 0, 1); + FREE_AND_NULL(tmpValue); + if (curVal != NULL) { + /* + * Add to list of computed values. + */ + if (val == NULL) + val = curVal; + else + xmlSchemaValueAppend(prevVal, curVal); + prevVal = curVal; + curVal = NULL; + } + if (ret != 0) { + if (ret < 0) { + AERROR_INT("xmlSchemaVCheckCVCSimpleType", + "validating an item of list simple type"); + goto internal_error; + } + ret = XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_2; + break; + } + cur = end; + } while (*cur != 0); + FREE_AND_NULL(tmpValue); + if ((ret == 0) && (type->flags & XML_SCHEMAS_TYPE_HAS_FACETS)) { + /* + * Apply facets (pattern, enumeration). + */ + ret = xmlSchemaValidateFacets(actxt, node, type, + XML_SCHEMAS_UNKNOWN, value, val, + len, fireErrors); + if (ret != 0) { + if (ret < 0) { + AERROR_INT("xmlSchemaVCheckCVCSimpleType", + "validating facets of list simple type"); + goto internal_error; + } + ret = XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_2; + } + } + if (fireErrors && (ret > 0)) { + /* + * Report the normalized value. + */ + normalize = 1; + NORMALIZE(type); + xmlSchemaSimpleTypeErr(actxt, ret, node, value, type, 1); + } + } else if (WXS_IS_UNION(type)) { + xmlSchemaTypeLinkPtr memberLink; + /* + * TODO: For all datatypes �derived� by �union� whiteSpace does + * not apply directly; however, the normalization behavior of �union� + * types is controlled by the value of whiteSpace on that one of the + * �memberTypes� against which the �union� is successfully validated. + * + * This means that the value is normalized by the first validating + * member type, then the facets of the union type are applied. This + * needs changing of the value! + */ + + /* + * 1.2.3 if {variety} is �union� then the string must �match� a + * literal in the �lexical space� of at least one member of + * {member type definitions} + */ + memberLink = xmlSchemaGetUnionSimpleTypeMemberTypes(type); + if (memberLink == NULL) { + AERROR_INT("xmlSchemaVCheckCVCSimpleType", + "union simple type has no member types"); + goto internal_error; + } + /* + * Always normalize union type values, since we currently + * cannot store the whitespace information with the value + * itself; otherwise a later value-comparison would be + * not possible. + */ + while (memberLink != NULL) { + if (valNeeded) + ret = xmlSchemaVCheckCVCSimpleType(actxt, node, + memberLink->type, value, &val, 0, 1, 0); + else + ret = xmlSchemaVCheckCVCSimpleType(actxt, node, + memberLink->type, value, NULL, 0, 1, 0); + if (ret <= 0) + break; + memberLink = memberLink->next; + } + if (ret != 0) { + if (ret < 0) { + AERROR_INT("xmlSchemaVCheckCVCSimpleType", + "validating members of union simple type"); + goto internal_error; + } + ret = XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_3; + } + /* + * Apply facets (pattern, enumeration). + */ + if ((ret == 0) && (type->flags & XML_SCHEMAS_TYPE_HAS_FACETS)) { + /* + * The normalization behavior of �union� types is controlled by + * the value of whiteSpace on that one of the �memberTypes� + * against which the �union� is successfully validated. + */ + NORMALIZE(memberLink->type); + ret = xmlSchemaValidateFacets(actxt, node, type, + XML_SCHEMAS_UNKNOWN, value, val, + 0, fireErrors); + if (ret != 0) { + if (ret < 0) { + AERROR_INT("xmlSchemaVCheckCVCSimpleType", + "validating facets of union simple type"); + goto internal_error; + } + ret = XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_3; + } + } + if (fireErrors && (ret > 0)) + xmlSchemaSimpleTypeErr(actxt, ret, node, value, type, 1); + } + + if (normValue != NULL) + xmlFree(normValue); + if (ret == 0) { + if (retVal != NULL) + *retVal = val; + else if (val != NULL) + xmlSchemaFreeValue(val); + } else if (val != NULL) + xmlSchemaFreeValue(val); + return (ret); +internal_error: + if (normValue != NULL) + xmlFree(normValue); + if (val != NULL) + xmlSchemaFreeValue(val); + return (-1); +} + +static int +xmlSchemaVExpandQName(xmlSchemaValidCtxtPtr vctxt, + const xmlChar *value, + const xmlChar **nsName, + const xmlChar **localName) +{ + int ret = 0; + + if ((nsName == NULL) || (localName == NULL)) + return (-1); + *nsName = NULL; + *localName = NULL; + + ret = xmlValidateQName(value, 1); + if (ret == -1) + return (-1); + if (ret > 0) { + xmlSchemaSimpleTypeErr(ACTXT_CAST vctxt, + XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_1, NULL, + value, xmlSchemaGetBuiltInType(XML_SCHEMAS_QNAME), 1); + return (1); + } + { + xmlChar *local = NULL; + xmlChar *prefix; + + /* + * NOTE: xmlSplitQName2 will return a duplicated + * string. + */ + local = xmlSplitQName2(value, &prefix); + if (local == NULL) + *localName = xmlDictLookup(vctxt->dict, value, -1); + else { + *localName = xmlDictLookup(vctxt->dict, local, -1); + xmlFree(local); + } + + *nsName = xmlSchemaLookupNamespace(vctxt, prefix); + + if (prefix != NULL) { + xmlFree(prefix); + /* + * A namespace must be found if the prefix is NOT NULL. + */ + if (*nsName == NULL) { + xmlSchemaCustomErr(ACTXT_CAST vctxt, + XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_1, NULL, + WXS_BASIC_CAST xmlSchemaGetBuiltInType(XML_SCHEMAS_QNAME), + "The QName value '%s' has no " + "corresponding namespace declaration in scope", + value, NULL); + return (2); + } + } + } + return (0); +} + +static int +xmlSchemaProcessXSIType(xmlSchemaValidCtxtPtr vctxt, + xmlSchemaAttrInfoPtr iattr, + xmlSchemaTypePtr *localType, + xmlSchemaElementPtr elemDecl) +{ + int ret = 0; + /* + * cvc-elt (3.3.4) : (4) + * AND + * Schema-Validity Assessment (Element) (cvc-assess-elt) + * (1.2.1.2.1) - (1.2.1.2.4) + * Handle 'xsi:type'. + */ + if (localType == NULL) + return (-1); + *localType = NULL; + if (iattr == NULL) + return (0); + else { + const xmlChar *nsName = NULL, *local = NULL; + /* + * TODO: We should report a *warning* that the type was overriden + * by the instance. + */ + ACTIVATE_ATTRIBUTE(iattr); + /* + * (cvc-elt) (3.3.4) : (4.1) + * (cvc-assess-elt) (1.2.1.2.2) + */ + ret = xmlSchemaVExpandQName(vctxt, iattr->value, + &nsName, &local); + if (ret != 0) { + if (ret < 0) { + VERROR_INT("xmlSchemaValidateElementByDeclaration", + "calling xmlSchemaQNameExpand() to validate the " + "attribute 'xsi:type'"); + goto internal_error; + } + goto exit; + } + /* + * (cvc-elt) (3.3.4) : (4.2) + * (cvc-assess-elt) (1.2.1.2.3) + */ + *localType = xmlSchemaGetType(vctxt->schema, local, nsName); + if (*localType == NULL) { + xmlChar *str = NULL; + + xmlSchemaCustomErr(ACTXT_CAST vctxt, + XML_SCHEMAV_CVC_ELT_4_2, NULL, + WXS_BASIC_CAST xmlSchemaGetBuiltInType(XML_SCHEMAS_QNAME), + "The QName value '%s' of the xsi:type attribute does not " + "resolve to a type definition", + xmlSchemaFormatQName(&str, nsName, local), NULL); + FREE_AND_NULL(str); + ret = vctxt->err; + goto exit; + } + if (elemDecl != NULL) { + int set = 0; + + /* + * SPEC cvc-elt (3.3.4) : (4.3) (Type Derivation OK) + * "The �local type definition� must be validly + * derived from the {type definition} given the union of + * the {disallowed substitutions} and the {type definition}'s + * {prohibited substitutions}, as defined in + * Type Derivation OK (Complex) (�3.4.6) + * (if it is a complex type definition), + * or given {disallowed substitutions} as defined in Type + * Derivation OK (Simple) (�3.14.6) (if it is a simple type + * definition)." + * + * {disallowed substitutions}: the "block" on the element decl. + * {prohibited substitutions}: the "block" on the type def. + */ + /* + * OPTIMIZE TODO: We could map types already evaluated + * to be validly derived from other types to avoid checking + * this over and over for the same types. + */ + if ((elemDecl->flags & XML_SCHEMAS_ELEM_BLOCK_EXTENSION) || + (elemDecl->subtypes->flags & + XML_SCHEMAS_TYPE_BLOCK_EXTENSION)) + set |= SUBSET_EXTENSION; + + if ((elemDecl->flags & XML_SCHEMAS_ELEM_BLOCK_RESTRICTION) || + (elemDecl->subtypes->flags & + XML_SCHEMAS_TYPE_BLOCK_RESTRICTION)) + set |= SUBSET_RESTRICTION; + + /* + * REMOVED and CHANGED since this produced a parser context + * which adds to the string dict of the schema. So this would + * change the schema and we don't want this. We don't need + * the parser context anymore. + * + * if ((vctxt->pctxt == NULL) && + * (xmlSchemaCreatePCtxtOnVCtxt(vctxt) == -1)) + * return (-1); + */ + + if (xmlSchemaCheckCOSDerivedOK(ACTXT_CAST vctxt, *localType, + elemDecl->subtypes, set) != 0) { + xmlChar *str = NULL; + + xmlSchemaCustomErr(ACTXT_CAST vctxt, + XML_SCHEMAV_CVC_ELT_4_3, NULL, NULL, + "The type definition '%s', specified by xsi:type, is " + "blocked or not validly derived from the type definition " + "of the element declaration", + xmlSchemaFormatQName(&str, + (*localType)->targetNamespace, + (*localType)->name), + NULL); + FREE_AND_NULL(str); + ret = vctxt->err; + *localType = NULL; + } + } + } +exit: + ACTIVATE_ELEM; + return (ret); +internal_error: + ACTIVATE_ELEM; + return (-1); +} + +static int +xmlSchemaValidateElemDecl(xmlSchemaValidCtxtPtr vctxt) +{ + xmlSchemaElementPtr elemDecl = vctxt->inode->decl; + xmlSchemaTypePtr actualType; + + /* + * cvc-elt (3.3.4) : 1 + */ + if (elemDecl == NULL) { + VERROR(XML_SCHEMAV_CVC_ELT_1, NULL, + "No matching declaration available"); + return (vctxt->err); + } + actualType = WXS_ELEM_TYPEDEF(elemDecl); + /* + * cvc-elt (3.3.4) : 2 + */ + if (elemDecl->flags & XML_SCHEMAS_ELEM_ABSTRACT) { + VERROR(XML_SCHEMAV_CVC_ELT_2, NULL, + "The element declaration is abstract"); + return (vctxt->err); + } + if (actualType == NULL) { + VERROR(XML_SCHEMAV_CVC_TYPE_1, NULL, + "The type definition is absent"); + return (XML_SCHEMAV_CVC_TYPE_1); + } + if (vctxt->nbAttrInfos != 0) { + int ret; + xmlSchemaAttrInfoPtr iattr; + /* + * cvc-elt (3.3.4) : 3 + * Handle 'xsi:nil'. + */ + iattr = xmlSchemaGetMetaAttrInfo(vctxt, + XML_SCHEMA_ATTR_INFO_META_XSI_NIL); + if (iattr) { + ACTIVATE_ATTRIBUTE(iattr); + /* + * Validate the value. + */ + ret = xmlSchemaVCheckCVCSimpleType( + ACTXT_CAST vctxt, NULL, + xmlSchemaGetBuiltInType(XML_SCHEMAS_BOOLEAN), + iattr->value, &(iattr->val), 1, 0, 0); + ACTIVATE_ELEM; + if (ret < 0) { + VERROR_INT("xmlSchemaValidateElemDecl", + "calling xmlSchemaVCheckCVCSimpleType() to " + "validate the attribute 'xsi:nil'"); + return (-1); + } + if (ret == 0) { + if ((elemDecl->flags & XML_SCHEMAS_ELEM_NILLABLE) == 0) { + /* + * cvc-elt (3.3.4) : 3.1 + */ + VERROR(XML_SCHEMAV_CVC_ELT_3_1, NULL, + "The element is not 'nillable'"); + /* Does not return an error on purpose. */ + } else { + if (xmlSchemaValueGetAsBoolean(iattr->val)) { + /* + * cvc-elt (3.3.4) : 3.2.2 + */ + if ((elemDecl->flags & XML_SCHEMAS_ELEM_FIXED) && + (elemDecl->value != NULL)) { + VERROR(XML_SCHEMAV_CVC_ELT_3_2_2, NULL, + "The element cannot be 'nilled' because " + "there is a fixed value constraint defined " + "for it"); + /* Does not return an error on purpose. */ + } else + vctxt->inode->flags |= + XML_SCHEMA_ELEM_INFO_NILLED; + } + } + } + } + /* + * cvc-elt (3.3.4) : 4 + * Handle 'xsi:type'. + */ + iattr = xmlSchemaGetMetaAttrInfo(vctxt, + XML_SCHEMA_ATTR_INFO_META_XSI_TYPE); + if (iattr) { + xmlSchemaTypePtr localType = NULL; + + ret = xmlSchemaProcessXSIType(vctxt, iattr, &localType, + elemDecl); + if (ret != 0) { + if (ret == -1) { + VERROR_INT("xmlSchemaValidateElemDecl", + "calling xmlSchemaProcessXSIType() to " + "process the attribute 'xsi:type'"); + return (-1); + } + /* Does not return an error on purpose. */ + } + if (localType != NULL) { + vctxt->inode->flags |= XML_SCHEMA_ELEM_INFO_LOCAL_TYPE; + actualType = localType; + } + } + } + /* + * IDC: Register identity-constraint XPath matchers. + */ + if ((elemDecl->idcs != NULL) && + (xmlSchemaIDCRegisterMatchers(vctxt, elemDecl) == -1)) + return (-1); + /* + * No actual type definition. + */ + if (actualType == NULL) { + VERROR(XML_SCHEMAV_CVC_TYPE_1, NULL, + "The type definition is absent"); + return (XML_SCHEMAV_CVC_TYPE_1); + } + /* + * Remember the actual type definition. + */ + vctxt->inode->typeDef = actualType; + + return (0); +} + +static int +xmlSchemaVAttributesSimple(xmlSchemaValidCtxtPtr vctxt) +{ + xmlSchemaAttrInfoPtr iattr; + int ret = 0, i; + + /* + * SPEC cvc-type (3.1.1) + * "The attributes of must be empty, excepting those whose namespace + * name is identical to http://www.w3.org/2001/XMLSchema-instance and + * whose local name is one of type, nil, schemaLocation or + * noNamespaceSchemaLocation." + */ + if (vctxt->nbAttrInfos == 0) + return (0); + for (i = 0; i < vctxt->nbAttrInfos; i++) { + iattr = vctxt->attrInfos[i]; + if (! iattr->metaType) { + ACTIVATE_ATTRIBUTE(iattr) + xmlSchemaIllegalAttrErr(ACTXT_CAST vctxt, + XML_SCHEMAV_CVC_TYPE_3_1_1, iattr, NULL); + ret = XML_SCHEMAV_CVC_TYPE_3_1_1; + } + } + ACTIVATE_ELEM + return (ret); +} + +/* +* Cleanup currently used attribute infos. +*/ +static void +xmlSchemaClearAttrInfos(xmlSchemaValidCtxtPtr vctxt) +{ + int i; + xmlSchemaAttrInfoPtr attr; + + if (vctxt->nbAttrInfos == 0) + return; + for (i = 0; i < vctxt->nbAttrInfos; i++) { + attr = vctxt->attrInfos[i]; + if (attr->flags & XML_SCHEMA_NODE_INFO_FLAG_OWNED_NAMES) { + if (attr->localName != NULL) + xmlFree((xmlChar *) attr->localName); + if (attr->nsName != NULL) + xmlFree((xmlChar *) attr->nsName); + } + if (attr->flags & XML_SCHEMA_NODE_INFO_FLAG_OWNED_VALUES) { + if (attr->value != NULL) + xmlFree((xmlChar *) attr->value); + } + if (attr->val != NULL) { + xmlSchemaFreeValue(attr->val); + attr->val = NULL; + } + memset(attr, 0, sizeof(xmlSchemaAttrInfo)); + } + vctxt->nbAttrInfos = 0; +} + +/* +* 3.4.4 Complex Type Definition Validation Rules +* Element Locally Valid (Complex Type) (cvc-complex-type) +* 3.2.4 Attribute Declaration Validation Rules +* Validation Rule: Attribute Locally Valid (cvc-attribute) +* Attribute Locally Valid (Use) (cvc-au) +* +* Only "assessed" attribute information items will be visible to +* IDCs. I.e. not "lax" (without declaration) and "skip" wild attributes. +*/ +static int +xmlSchemaVAttributesComplex(xmlSchemaValidCtxtPtr vctxt) +{ + xmlSchemaTypePtr type = vctxt->inode->typeDef; + xmlSchemaItemListPtr attrUseList; + xmlSchemaAttributeUsePtr attrUse = NULL; + xmlSchemaAttributePtr attrDecl = NULL; + xmlSchemaAttrInfoPtr iattr, tmpiattr; + int i, j, found, nbAttrs, nbUses; + int xpathRes = 0, res, wildIDs = 0, fixed; + xmlNodePtr defAttrOwnerElem = NULL; + + /* + * SPEC (cvc-attribute) + * (1) "The declaration must not be �absent� (see Missing + * Sub-components (�5.3) for how this can fail to be + * the case)." + * (2) "Its {type definition} must not be absent." + * + * NOTE (1) + (2): This is not handled here, since we currently do not + * allow validation against schemas which have missing sub-components. + * + * SPEC (cvc-complex-type) + * (3) "For each attribute information item in the element information + * item's [attributes] excepting those whose [namespace name] is + * identical to http://www.w3.org/2001/XMLSchema-instance and whose + * [local name] is one of type, nil, schemaLocation or + * noNamespaceSchemaLocation, the appropriate case among the following + * must be true: + * + */ + attrUseList = (xmlSchemaItemListPtr) type->attrUses; + /* + * @nbAttrs is the number of attributes present in the instance. + */ + nbAttrs = vctxt->nbAttrInfos; + if (attrUseList != NULL) + nbUses = attrUseList->nbItems; + else + nbUses = 0; + for (i = 0; i < nbUses; i++) { + found = 0; + attrUse = attrUseList->items[i]; + attrDecl = WXS_ATTRUSE_DECL(attrUse); + for (j = 0; j < nbAttrs; j++) { + iattr = vctxt->attrInfos[j]; + /* + * SPEC (cvc-complex-type) (3) + * Skip meta attributes. + */ + if (iattr->metaType) + continue; + if (iattr->localName[0] != attrDecl->name[0]) + continue; + if (!xmlStrEqual(iattr->localName, attrDecl->name)) + continue; + if (!xmlStrEqual(iattr->nsName, attrDecl->targetNamespace)) + continue; + found = 1; + /* + * SPEC (cvc-complex-type) + * (3.1) "If there is among the {attribute uses} an attribute + * use with an {attribute declaration} whose {name} matches + * the attribute information item's [local name] and whose + * {target namespace} is identical to the attribute information + * item's [namespace name] (where an �absent� {target namespace} + * is taken to be identical to a [namespace name] with no value), + * then the attribute information must be �valid� with respect + * to that attribute use as per Attribute Locally Valid (Use) + * (�3.5.4). In this case the {attribute declaration} of that + * attribute use is the �context-determined declaration� for the + * attribute information item with respect to Schema-Validity + * Assessment (Attribute) (�3.2.4) and + * Assessment Outcome (Attribute) (�3.2.5). + */ + iattr->state = XML_SCHEMAS_ATTR_ASSESSED; + iattr->use = attrUse; + /* + * Context-determined declaration. + */ + iattr->decl = attrDecl; + iattr->typeDef = attrDecl->subtypes; + break; + } + + if (found) + continue; + + if (attrUse->occurs == XML_SCHEMAS_ATTR_USE_REQUIRED) { + /* + * Handle non-existent, required attributes. + * + * SPEC (cvc-complex-type) + * (4) "The {attribute declaration} of each attribute use in + * the {attribute uses} whose {required} is true matches one + * of the attribute information items in the element information + * item's [attributes] as per clause 3.1 above." + */ + tmpiattr = xmlSchemaGetFreshAttrInfo(vctxt); + if (tmpiattr == NULL) { + VERROR_INT( + "xmlSchemaVAttributesComplex", + "calling xmlSchemaGetFreshAttrInfo()"); + return (-1); + } + tmpiattr->state = XML_SCHEMAS_ATTR_ERR_MISSING; + tmpiattr->use = attrUse; + tmpiattr->decl = attrDecl; + } else if ((attrUse->occurs == XML_SCHEMAS_ATTR_USE_OPTIONAL) && + ((attrUse->defValue != NULL) || + (attrDecl->defValue != NULL))) { + /* + * Handle non-existent, optional, default/fixed attributes. + */ + tmpiattr = xmlSchemaGetFreshAttrInfo(vctxt); + if (tmpiattr == NULL) { + VERROR_INT( + "xmlSchemaVAttributesComplex", + "calling xmlSchemaGetFreshAttrInfo()"); + return (-1); + } + tmpiattr->state = XML_SCHEMAS_ATTR_DEFAULT; + tmpiattr->use = attrUse; + tmpiattr->decl = attrDecl; + tmpiattr->typeDef = attrDecl->subtypes; + tmpiattr->localName = attrDecl->name; + tmpiattr->nsName = attrDecl->targetNamespace; + } + } + + if (vctxt->nbAttrInfos == 0) + return (0); + /* + * Validate against the wildcard. + */ + if (type->attributeWildcard != NULL) { + /* + * SPEC (cvc-complex-type) + * (3.2.1) "There must be an {attribute wildcard}." + */ + for (i = 0; i < nbAttrs; i++) { + iattr = vctxt->attrInfos[i]; + /* + * SPEC (cvc-complex-type) (3) + * Skip meta attributes. + */ + if (iattr->state != XML_SCHEMAS_ATTR_UNKNOWN) + continue; + /* + * SPEC (cvc-complex-type) + * (3.2.2) "The attribute information item must be �valid� with + * respect to it as defined in Item Valid (Wildcard) (�3.10.4)." + * + * SPEC Item Valid (Wildcard) (cvc-wildcard) + * "... its [namespace name] must be �valid� with respect to + * the wildcard constraint, as defined in Wildcard allows + * Namespace Name (�3.10.4)." + */ + if (xmlSchemaCheckCVCWildcardNamespace(type->attributeWildcard, + iattr->nsName) == 0) { + /* + * Handle processContents. + * + * SPEC (cvc-wildcard): + * processContents | context-determined declaration: + * "strict" "mustFind" + * "lax" "none" + * "skip" "skip" + */ + if (type->attributeWildcard->processContents == + XML_SCHEMAS_ANY_SKIP) { + /* + * context-determined declaration = "skip" + * + * SPEC PSVI Assessment Outcome (Attribute) + * [validity] = "notKnown" + * [validation attempted] = "none" + */ + iattr->state = XML_SCHEMAS_ATTR_WILD_SKIP; + continue; + } + /* + * Find an attribute declaration. + */ + iattr->decl = xmlSchemaGetAttributeDecl(vctxt->schema, + iattr->localName, iattr->nsName); + if (iattr->decl != NULL) { + iattr->state = XML_SCHEMAS_ATTR_ASSESSED; + /* + * SPEC (cvc-complex-type) + * (5) "Let [Definition:] the wild IDs be the set of + * all attribute information item to which clause 3.2 + * applied and whose �validation� resulted in a + * �context-determined declaration� of mustFind or no + * �context-determined declaration� at all, and whose + * [local name] and [namespace name] resolve (as + * defined by QName resolution (Instance) (�3.15.4)) to + * an attribute declaration whose {type definition} is + * or is derived from ID. Then all of the following + * must be true:" + */ + iattr->typeDef = WXS_ATTR_TYPEDEF(iattr->decl); + if (xmlSchemaIsDerivedFromBuiltInType( + iattr->typeDef, XML_SCHEMAS_ID)) { + /* + * SPEC (5.1) "There must be no more than one + * item in �wild IDs�." + */ + if (wildIDs != 0) { + /* VAL TODO */ + iattr->state = XML_SCHEMAS_ATTR_ERR_WILD_DUPLICATE_ID; + TODO + continue; + } + wildIDs++; + /* + * SPEC (cvc-complex-type) + * (5.2) "If �wild IDs� is non-empty, there must not + * be any attribute uses among the {attribute uses} + * whose {attribute declaration}'s {type definition} + * is or is derived from ID." + */ + if (attrUseList != NULL) { + for (j = 0; j < attrUseList->nbItems; j++) { + if (xmlSchemaIsDerivedFromBuiltInType( + WXS_ATTRUSE_TYPEDEF(attrUseList->items[j]), + XML_SCHEMAS_ID)) { + /* URGENT VAL TODO: implement */ + iattr->state = XML_SCHEMAS_ATTR_ERR_WILD_AND_USE_ID; + TODO + break; + } + } + } + } + } else if (type->attributeWildcard->processContents == + XML_SCHEMAS_ANY_LAX) { + iattr->state = XML_SCHEMAS_ATTR_WILD_LAX_NO_DECL; + /* + * SPEC PSVI Assessment Outcome (Attribute) + * [validity] = "notKnown" + * [validation attempted] = "none" + */ + } else { + iattr->state = XML_SCHEMAS_ATTR_ERR_WILD_STRICT_NO_DECL; + } + } + } + } + + if (vctxt->nbAttrInfos == 0) + return (0); + + /* + * Get the owner element; needed for creation of default attributes. + * This fixes bug #341337, reported by David Grohmann. + */ + if (vctxt->options & XML_SCHEMA_VAL_VC_I_CREATE) { + xmlSchemaNodeInfoPtr ielem = vctxt->elemInfos[vctxt->depth]; + if (ielem && ielem->node && ielem->node->doc) + defAttrOwnerElem = ielem->node; + } + /* + * Validate values, create default attributes, evaluate IDCs. + */ + for (i = 0; i < vctxt->nbAttrInfos; i++) { + iattr = vctxt->attrInfos[i]; + /* + * VAL TODO: Note that we won't try to resolve IDCs to + * "lax" and "skip" validated attributes. Check what to + * do in this case. + */ + if ((iattr->state != XML_SCHEMAS_ATTR_ASSESSED) && + (iattr->state != XML_SCHEMAS_ATTR_DEFAULT)) + continue; + /* + * VAL TODO: What to do if the type definition is missing? + */ + if (iattr->typeDef == NULL) { + iattr->state = XML_SCHEMAS_ATTR_ERR_NO_TYPE; + continue; + } + + ACTIVATE_ATTRIBUTE(iattr); + fixed = 0; + xpathRes = 0; + + if (vctxt->xpathStates != NULL) { + /* + * Evaluate IDCs. + */ + xpathRes = xmlSchemaXPathEvaluate(vctxt, + XML_ATTRIBUTE_NODE); + if (xpathRes == -1) { + VERROR_INT("xmlSchemaVAttributesComplex", + "calling xmlSchemaXPathEvaluate()"); + goto internal_error; + } + } + + if (iattr->state == XML_SCHEMAS_ATTR_DEFAULT) { + /* + * Default/fixed attributes. + * We need the value only if we need to resolve IDCs or + * will create default attributes. + */ + if ((xpathRes) || (defAttrOwnerElem)) { + if (iattr->use->defValue != NULL) { + iattr->value = (xmlChar *) iattr->use->defValue; + iattr->val = iattr->use->defVal; + } else { + iattr->value = (xmlChar *) iattr->decl->defValue; + iattr->val = iattr->decl->defVal; + } + /* + * IDCs will consume the precomputed default value, + * so we need to clone it. + */ + if (iattr->val == NULL) { + VERROR_INT("xmlSchemaVAttributesComplex", + "default/fixed value on an attribute use was " + "not precomputed"); + goto internal_error; + } + iattr->val = xmlSchemaCopyValue(iattr->val); + if (iattr->val == NULL) { + VERROR_INT("xmlSchemaVAttributesComplex", + "calling xmlSchemaCopyValue()"); + goto internal_error; + } + } + /* + * PSVI: Add the default attribute to the current element. + * VAL TODO: Should we use the *normalized* value? This currently + * uses the *initial* value. + */ + + if (defAttrOwnerElem) { + xmlChar *normValue; + const xmlChar *value; + + value = iattr->value; + /* + * Normalize the value. + */ + normValue = xmlSchemaNormalizeValue(iattr->typeDef, + iattr->value); + if (normValue != NULL) + value = BAD_CAST normValue; + + if (iattr->nsName == NULL) { + if (xmlNewProp(defAttrOwnerElem, + iattr->localName, value) == NULL) { + VERROR_INT("xmlSchemaVAttributesComplex", + "callling xmlNewProp()"); + if (normValue != NULL) + xmlFree(normValue); + goto internal_error; + } + } else { + xmlNsPtr ns; + + ns = xmlSearchNsByHref(defAttrOwnerElem->doc, + defAttrOwnerElem, iattr->nsName); + if (ns == NULL) { + xmlChar prefix[12]; + int counter = 0; + + /* + * Create a namespace declaration on the validation + * root node if no namespace declaration is in scope. + */ + do { + snprintf((char *) prefix, 12, "p%d", counter++); + ns = xmlSearchNs(defAttrOwnerElem->doc, + defAttrOwnerElem, BAD_CAST prefix); + if (counter > 1000) { + VERROR_INT( + "xmlSchemaVAttributesComplex", + "could not compute a ns prefix for a " + "default/fixed attribute"); + if (normValue != NULL) + xmlFree(normValue); + goto internal_error; + } + } while (ns != NULL); + ns = xmlNewNs(vctxt->validationRoot, + iattr->nsName, BAD_CAST prefix); + } + /* + * TODO: + * http://lists.w3.org/Archives/Public/www-xml-schema-comments/2005JulSep/0406.html + * If we have QNames: do we need to ensure there's a + * prefix defined for the QName? + */ + xmlNewNsProp(defAttrOwnerElem, ns, iattr->localName, value); + } + if (normValue != NULL) + xmlFree(normValue); + } + /* + * Go directly to IDC evaluation. + */ + goto eval_idcs; + } + /* + * Validate the value. + */ + if (vctxt->value != NULL) { + /* + * Free last computed value; just for safety reasons. + */ + xmlSchemaFreeValue(vctxt->value); + vctxt->value = NULL; + } + /* + * Note that the attribute *use* can be unavailable, if + * the attribute was a wild attribute. + */ + if ((iattr->decl->flags & XML_SCHEMAS_ATTR_FIXED) || + ((iattr->use != NULL) && + (iattr->use->flags & XML_SCHEMAS_ATTR_FIXED))) + fixed = 1; + else + fixed = 0; + /* + * SPEC (cvc-attribute) + * (3) "The item's �normalized value� must be locally �valid� + * with respect to that {type definition} as per + * String Valid (�3.14.4)." + * + * VAL TODO: Do we already have the + * "normalized attribute value" here? + */ + if (xpathRes || fixed) { + iattr->flags |= XML_SCHEMA_NODE_INFO_VALUE_NEEDED; + /* + * Request a computed value. + */ + res = xmlSchemaVCheckCVCSimpleType( + ACTXT_CAST vctxt, + iattr->node, iattr->typeDef, iattr->value, &(iattr->val), + 1, 1, 0); + } else { + res = xmlSchemaVCheckCVCSimpleType( + ACTXT_CAST vctxt, + iattr->node, iattr->typeDef, iattr->value, NULL, + 1, 0, 0); + } + + if (res != 0) { + if (res == -1) { + VERROR_INT("xmlSchemaVAttributesComplex", + "calling xmlSchemaStreamValidateSimpleTypeValue()"); + goto internal_error; + } + iattr->state = XML_SCHEMAS_ATTR_INVALID_VALUE; + /* + * SPEC PSVI Assessment Outcome (Attribute) + * [validity] = "invalid" + */ + goto eval_idcs; + } + + if (fixed) { + /* + * SPEC Attribute Locally Valid (Use) (cvc-au) + * "For an attribute information item to be�valid� + * with respect to an attribute use its *normalized* + * value� must match the *canonical* lexical + * representation of the attribute use's {value + * constraint}value, if it is present and fixed." + * + * VAL TODO: The requirement for the *canonical* value + * will be removed in XML Schema 1.1. + */ + /* + * SPEC Attribute Locally Valid (cvc-attribute) + * (4) "The item's *actual* value� must match the *value* of + * the {value constraint}, if it is present and fixed." + */ + 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; + /* + if (xmlSchemaCompareValuesWhtsp(attr->val, + (xmlSchemaWhitespaceValueType) ws, + attr->use->defVal, + (xmlSchemaWhitespaceValueType) ws) != 0) { + */ + if (! xmlSchemaAreValuesEqual(iattr->val, iattr->use->defVal)) + iattr->state = XML_SCHEMAS_ATTR_ERR_FIXED_VALUE; + } else { + if (iattr->decl->defVal == NULL) { + /* VAL TODO: A default value was not precomputed. */ + TODO + goto eval_idcs; + } + iattr->vcValue = iattr->decl->defValue; + /* + if (xmlSchemaCompareValuesWhtsp(attr->val, + (xmlSchemaWhitespaceValueType) ws, + attrDecl->defVal, + (xmlSchemaWhitespaceValueType) ws) != 0) { + */ + if (! xmlSchemaAreValuesEqual(iattr->val, iattr->decl->defVal)) + iattr->state = XML_SCHEMAS_ATTR_ERR_FIXED_VALUE; + } + /* + * [validity] = "valid" + */ + } +eval_idcs: + /* + * Evaluate IDCs. + */ + if (xpathRes) { + if (xmlSchemaXPathProcessHistory(vctxt, + vctxt->depth +1) == -1) { + VERROR_INT("xmlSchemaVAttributesComplex", + "calling xmlSchemaXPathEvaluate()"); + goto internal_error; + } + } else if (vctxt->xpathStates != NULL) + xmlSchemaXPathPop(vctxt); + } + + /* + * Report errors. + */ + for (i = 0; i < vctxt->nbAttrInfos; i++) { + iattr = vctxt->attrInfos[i]; + if ((iattr->state == XML_SCHEMAS_ATTR_META) || + (iattr->state == XML_SCHEMAS_ATTR_ASSESSED) || + (iattr->state == XML_SCHEMAS_ATTR_WILD_SKIP) || + (iattr->state == XML_SCHEMAS_ATTR_WILD_LAX_NO_DECL)) + continue; + ACTIVATE_ATTRIBUTE(iattr); + switch (iattr->state) { + case XML_SCHEMAS_ATTR_ERR_MISSING: { + xmlChar *str = NULL; + ACTIVATE_ELEM; + xmlSchemaCustomErr(ACTXT_CAST vctxt, + XML_SCHEMAV_CVC_COMPLEX_TYPE_4, NULL, NULL, + "The attribute '%s' is required but missing", + xmlSchemaFormatQName(&str, + iattr->decl->targetNamespace, + iattr->decl->name), + NULL); + FREE_AND_NULL(str) + break; + } + case XML_SCHEMAS_ATTR_ERR_NO_TYPE: + VERROR(XML_SCHEMAV_CVC_ATTRIBUTE_2, NULL, + "The type definition is absent"); + break; + case XML_SCHEMAS_ATTR_ERR_FIXED_VALUE: + xmlSchemaCustomErr(ACTXT_CAST vctxt, + XML_SCHEMAV_CVC_AU, NULL, NULL, + "The value '%s' does not match the fixed " + "value constraint '%s'", + iattr->value, iattr->vcValue); + break; + case XML_SCHEMAS_ATTR_ERR_WILD_STRICT_NO_DECL: + VERROR(XML_SCHEMAV_CVC_WILDCARD, NULL, + "No matching global attribute declaration available, but " + "demanded by the strict wildcard"); + break; + case XML_SCHEMAS_ATTR_UNKNOWN: + if (iattr->metaType) + break; + /* + * MAYBE VAL TODO: One might report different error messages + * for the following errors. + */ + if (type->attributeWildcard == NULL) { + xmlSchemaIllegalAttrErr(ACTXT_CAST vctxt, + XML_SCHEMAV_CVC_COMPLEX_TYPE_3_2_1, iattr, NULL); + } else { + xmlSchemaIllegalAttrErr(ACTXT_CAST vctxt, + XML_SCHEMAV_CVC_COMPLEX_TYPE_3_2_2, iattr, NULL); + } + break; + default: + break; + } + } + + ACTIVATE_ELEM; + return (0); +internal_error: + ACTIVATE_ELEM; + return (-1); +} + +static int +xmlSchemaValidateElemWildcard(xmlSchemaValidCtxtPtr vctxt, + int *skip) +{ + xmlSchemaWildcardPtr wild = (xmlSchemaWildcardPtr) vctxt->inode->decl; + /* + * The namespace of the element was already identified to be + * matching the wildcard. + */ + if ((skip == NULL) || (wild == NULL) || + (wild->type != XML_SCHEMA_TYPE_ANY)) { + VERROR_INT("xmlSchemaValidateElemWildcard", + "bad arguments"); + return (-1); + } + *skip = 0; + if (wild->processContents == XML_SCHEMAS_ANY_SKIP) { + /* + * URGENT VAL TODO: Either we need to position the stream to the + * next sibling, or walk the whole subtree. + */ + *skip = 1; + return (0); + } + { + xmlSchemaElementPtr decl = NULL; + + decl = xmlSchemaGetElem(vctxt->schema, + vctxt->inode->localName, vctxt->inode->nsName); + if (decl != NULL) { + vctxt->inode->decl = decl; + return (0); + } + } + if (wild->processContents == XML_SCHEMAS_ANY_STRICT) { + /* VAL TODO: Change to proper error code. */ + VERROR(XML_SCHEMAV_CVC_ELT_1, NULL, /* WXS_BASIC_CAST wild */ + "No matching global element declaration available, but " + "demanded by the strict wildcard"); + return (vctxt->err); + } + if (vctxt->nbAttrInfos != 0) { + xmlSchemaAttrInfoPtr iattr; + /* + * SPEC Validation Rule: Schema-Validity Assessment (Element) + * (1.2.1.2.1) - (1.2.1.2.3 ) + * + * Use the xsi:type attribute for the type definition. + */ + iattr = xmlSchemaGetMetaAttrInfo(vctxt, + XML_SCHEMA_ATTR_INFO_META_XSI_TYPE); + if (iattr != NULL) { + if (xmlSchemaProcessXSIType(vctxt, iattr, + &(vctxt->inode->typeDef), NULL) == -1) { + VERROR_INT("xmlSchemaValidateElemWildcard", + "calling xmlSchemaProcessXSIType() to " + "process the attribute 'xsi:nil'"); + return (-1); + } + /* + * Don't return an error on purpose. + */ + return (0); + } + } + /* + * SPEC Validation Rule: Schema-Validity Assessment (Element) + * + * Fallback to "anyType". + */ + vctxt->inode->typeDef = + xmlSchemaGetBuiltInType(XML_SCHEMAS_ANYTYPE); + return (0); +} + +/* +* xmlSchemaCheckCOSValidDefault: +* +* This will be called if: not nilled, no content and a default/fixed +* value is provided. +*/ + +static int +xmlSchemaCheckCOSValidDefault(xmlSchemaValidCtxtPtr vctxt, + const xmlChar *value, + xmlSchemaValPtr *val) +{ + int ret = 0; + xmlSchemaNodeInfoPtr inode = vctxt->inode; + + /* + * cos-valid-default: + * Schema Component Constraint: Element Default Valid (Immediate) + * For a string to be a valid default with respect to a type + * definition the appropriate case among the following must be true: + */ + if WXS_IS_COMPLEX(inode->typeDef) { + /* + * Complex type. + * + * SPEC (2.1) "its {content type} must be a simple type definition + * or mixed." + * SPEC (2.2.2) "If the {content type} is mixed, then the {content + * type}'s particle must be �emptiable� as defined by + * Particle Emptiable (�3.9.6)." + */ + if ((! WXS_HAS_SIMPLE_CONTENT(inode->typeDef)) && + ((! WXS_HAS_MIXED_CONTENT(inode->typeDef)) || + (! WXS_EMPTIABLE(inode->typeDef)))) { + ret = XML_SCHEMAP_COS_VALID_DEFAULT_2_1; + /* NOTE that this covers (2.2.2) as well. */ + VERROR(ret, NULL, + "For a string to be a valid default, the type definition " + "must be a simple type or a complex type with simple content " + "or mixed content and a particle emptiable"); + return(ret); + } + } + /* + * 1 If the type definition is a simple type definition, then the string + * must be �valid� with respect to that definition as defined by String + * Valid (�3.14.4). + * + * AND + * + * 2.2.1 If the {content type} is a simple type definition, then the + * string must be �valid� with respect to that simple type definition + * as defined by String Valid (�3.14.4). + */ + if (WXS_IS_SIMPLE(inode->typeDef)) { + + ret = xmlSchemaVCheckCVCSimpleType(ACTXT_CAST vctxt, + NULL, inode->typeDef, value, val, 1, 1, 0); + + } else if (WXS_HAS_SIMPLE_CONTENT(inode->typeDef)) { + + ret = xmlSchemaVCheckCVCSimpleType(ACTXT_CAST vctxt, + NULL, inode->typeDef->contentTypeDef, value, val, 1, 1, 0); + } + if (ret < 0) { + VERROR_INT("xmlSchemaCheckCOSValidDefault", + "calling xmlSchemaVCheckCVCSimpleType()"); + } + return (ret); +} + +static void +xmlSchemaVContentModelCallback(xmlSchemaValidCtxtPtr vctxt ATTRIBUTE_UNUSED, + const xmlChar * name ATTRIBUTE_UNUSED, + xmlSchemaElementPtr item, + xmlSchemaNodeInfoPtr inode) +{ + inode->decl = item; +#ifdef DEBUG_CONTENT + { + xmlChar *str = NULL; + + if (item->type == XML_SCHEMA_TYPE_ELEMENT) { + xmlGenericError(xmlGenericErrorContext, + "AUTOMATON callback for '%s' [declaration]\n", + xmlSchemaFormatQName(&str, + inode->localName, inode->nsName)); + } else { + xmlGenericError(xmlGenericErrorContext, + "AUTOMATON callback for '%s' [wildcard]\n", + xmlSchemaFormatQName(&str, + inode->localName, inode->nsName)); + + } + FREE_AND_NULL(str) + } +#endif +} + +static int +xmlSchemaValidatorPushElem(xmlSchemaValidCtxtPtr vctxt) +{ + vctxt->inode = xmlSchemaGetFreshElemInfo(vctxt); + if (vctxt->inode == NULL) { + VERROR_INT("xmlSchemaValidatorPushElem", + "calling xmlSchemaGetFreshElemInfo()"); + return (-1); + } + vctxt->nbAttrInfos = 0; + return (0); +} + +static int +xmlSchemaVCheckINodeDataType(xmlSchemaValidCtxtPtr vctxt, + xmlSchemaNodeInfoPtr inode, + xmlSchemaTypePtr type, + const xmlChar *value) +{ + if (inode->flags & XML_SCHEMA_NODE_INFO_VALUE_NEEDED) + return (xmlSchemaVCheckCVCSimpleType( + ACTXT_CAST vctxt, NULL, + type, value, &(inode->val), 1, 1, 0)); + else + return (xmlSchemaVCheckCVCSimpleType( + ACTXT_CAST vctxt, NULL, + type, value, NULL, 1, 0, 0)); +} + + + +/* +* Process END of element. +*/ +static int +xmlSchemaValidatorPopElem(xmlSchemaValidCtxtPtr vctxt) +{ + int ret = 0; + xmlSchemaNodeInfoPtr inode = vctxt->inode; + + if (vctxt->nbAttrInfos != 0) + xmlSchemaClearAttrInfos(vctxt); + if (inode->flags & XML_SCHEMA_NODE_INFO_ERR_NOT_EXPECTED) { + /* + * This element was not expected; + * we will not validate child elements of broken parents. + * Skip validation of all content of the parent. + */ + vctxt->skipDepth = vctxt->depth -1; + goto end_elem; + } + if ((inode->typeDef == NULL) || + (inode->flags & XML_SCHEMA_NODE_INFO_ERR_BAD_TYPE)) { + /* + * 1. the type definition might be missing if the element was + * error prone + * 2. it might be abstract. + */ + goto end_elem; + } + /* + * Check the content model. + */ + if ((inode->typeDef->contentType == XML_SCHEMA_CONTENT_MIXED) || + (inode->typeDef->contentType == XML_SCHEMA_CONTENT_ELEMENTS)) { + + /* + * Workaround for "anyType". + */ + if (inode->typeDef->builtInType == XML_SCHEMAS_ANYTYPE) + goto character_content; + + if ((inode->flags & XML_SCHEMA_ELEM_INFO_ERR_BAD_CONTENT) == 0) { + xmlChar *values[10]; + int terminal, nbval = 10, nbneg; + + if (inode->regexCtxt == NULL) { + /* + * Create the regex context. + */ + inode->regexCtxt = + xmlRegNewExecCtxt(inode->typeDef->contModel, + (xmlRegExecCallbacks) xmlSchemaVContentModelCallback, + vctxt); + if (inode->regexCtxt == NULL) { + VERROR_INT("xmlSchemaValidatorPopElem", + "failed to create a regex context"); + goto internal_error; + } +#ifdef DEBUG_AUTOMATA + xmlGenericError(xmlGenericErrorContext, + "AUTOMATON create on '%s'\n", inode->localName); +#endif + } + /* + * Get hold of the still expected content, since a further + * call to xmlRegExecPushString() will loose this information. + */ + xmlRegExecNextValues(inode->regexCtxt, + &nbval, &nbneg, &values[0], &terminal); + ret = xmlRegExecPushString(inode->regexCtxt, NULL, NULL); + if ((ret<0) || ((ret==0) && (!INODE_NILLED(inode)))) { + /* + * Still missing something. + */ + ret = 1; + inode->flags |= + XML_SCHEMA_ELEM_INFO_ERR_BAD_CONTENT; + xmlSchemaComplexTypeErr(ACTXT_CAST vctxt, + XML_SCHEMAV_ELEMENT_CONTENT, NULL, NULL, + "Missing child element(s)", + nbval, nbneg, values); +#ifdef DEBUG_AUTOMATA + xmlGenericError(xmlGenericErrorContext, + "AUTOMATON missing ERROR on '%s'\n", + inode->localName); +#endif + } else { + /* + * Content model is satisfied. + */ + ret = 0; +#ifdef DEBUG_AUTOMATA + xmlGenericError(xmlGenericErrorContext, + "AUTOMATON succeeded on '%s'\n", + inode->localName); +#endif + } + + } + } + if (inode->typeDef->contentType == XML_SCHEMA_CONTENT_ELEMENTS) + goto end_elem; + +character_content: + + if (vctxt->value != NULL) { + xmlSchemaFreeValue(vctxt->value); + vctxt->value = NULL; + } + /* + * Check character content. + */ + if (inode->decl == NULL) { + /* + * Speedup if no declaration exists. + */ + if (WXS_IS_SIMPLE(inode->typeDef)) { + ret = xmlSchemaVCheckINodeDataType(vctxt, + inode, inode->typeDef, inode->value); + } else if (WXS_HAS_SIMPLE_CONTENT(inode->typeDef)) { + ret = xmlSchemaVCheckINodeDataType(vctxt, + inode, inode->typeDef->contentTypeDef, + inode->value); + } + if (ret < 0) { + VERROR_INT("xmlSchemaValidatorPopElem", + "calling xmlSchemaVCheckCVCSimpleType()"); + goto internal_error; + } + goto end_elem; + } + /* + * cvc-elt (3.3.4) : 5 + * The appropriate case among the following must be true: + */ + /* + * cvc-elt (3.3.4) : 5.1 + * If the declaration has a {value constraint}, + * the item has neither element nor character [children] and + * clause 3.2 has not applied, then all of the following must be true: + */ + if ((inode->decl->value != NULL) && + (inode->flags & XML_SCHEMA_ELEM_INFO_EMPTY) && + (! INODE_NILLED(inode))) { + /* + * cvc-elt (3.3.4) : 5.1.1 + * If the �actual type definition� is a �local type definition� + * then the canonical lexical representation of the {value constraint} + * value must be a valid default for the �actual type definition� as + * defined in Element Default Valid (Immediate) (�3.3.6). + */ + /* + * NOTE: 'local' above means types acquired by xsi:type. + * NOTE: Although the *canonical* value is stated, it is not + * relevant if canonical or not. Additionally XML Schema 1.1 + * will removed this requirement as well. + */ + if (inode->flags & XML_SCHEMA_ELEM_INFO_LOCAL_TYPE) { + + ret = xmlSchemaCheckCOSValidDefault(vctxt, + inode->decl->value, &(inode->val)); + if (ret != 0) { + if (ret < 0) { + VERROR_INT("xmlSchemaValidatorPopElem", + "calling xmlSchemaCheckCOSValidDefault()"); + goto internal_error; + } + goto end_elem; + } + /* + * Stop here, to avoid redundant validation of the value + * (see following). + */ + goto default_psvi; + } + /* + * cvc-elt (3.3.4) : 5.1.2 + * The element information item with the canonical lexical + * representation of the {value constraint} value used as its + * �normalized value� must be �valid� with respect to the + * �actual type definition� as defined by Element Locally Valid (Type) + * (�3.3.4). + */ + if (WXS_IS_SIMPLE(inode->typeDef)) { + ret = xmlSchemaVCheckINodeDataType(vctxt, + inode, inode->typeDef, inode->decl->value); + } else if (WXS_HAS_SIMPLE_CONTENT(inode->typeDef)) { + ret = xmlSchemaVCheckINodeDataType(vctxt, + inode, inode->typeDef->contentTypeDef, + inode->decl->value); + } + if (ret != 0) { + if (ret < 0) { + VERROR_INT("xmlSchemaValidatorPopElem", + "calling xmlSchemaVCheckCVCSimpleType()"); + goto internal_error; + } + goto end_elem; + } + +default_psvi: + /* + * PSVI: Create a text node on the instance element. + */ + if ((vctxt->options & XML_SCHEMA_VAL_VC_I_CREATE) && + (inode->node != NULL)) { + xmlNodePtr textChild; + xmlChar *normValue; + /* + * VAL TODO: Normalize the value. + */ + normValue = xmlSchemaNormalizeValue(inode->typeDef, + inode->decl->value); + if (normValue != NULL) { + textChild = xmlNewText(BAD_CAST normValue); + xmlFree(normValue); + } else + textChild = xmlNewText(inode->decl->value); + if (textChild == NULL) { + VERROR_INT("xmlSchemaValidatorPopElem", + "calling xmlNewText()"); + goto internal_error; + } else + xmlAddChild(inode->node, textChild); + } + + } else if (! INODE_NILLED(inode)) { + /* + * 5.2.1 The element information item must be �valid� with respect + * to the �actual type definition� as defined by Element Locally + * Valid (Type) (�3.3.4). + */ + if (WXS_IS_SIMPLE(inode->typeDef)) { + /* + * SPEC (cvc-type) (3.1) + * "If the type definition is a simple type definition, ..." + * (3.1.3) "If clause 3.2 of Element Locally Valid + * (Element) (�3.3.4) did not apply, then the �normalized value� + * must be �valid� with respect to the type definition as defined + * by String Valid (�3.14.4). + */ + ret = xmlSchemaVCheckINodeDataType(vctxt, + inode, inode->typeDef, inode->value); + } else if (WXS_HAS_SIMPLE_CONTENT(inode->typeDef)) { + /* + * SPEC (cvc-type) (3.2) "If the type definition is a complex type + * definition, then the element information item must be + * �valid� with respect to the type definition as per + * Element Locally Valid (Complex Type) (�3.4.4);" + * + * SPEC (cvc-complex-type) (2.2) + * "If the {content type} is a simple type definition, ... + * the �normalized value� of the element information item is + * �valid� with respect to that simple type definition as + * defined by String Valid (�3.14.4)." + */ + ret = xmlSchemaVCheckINodeDataType(vctxt, + inode, inode->typeDef->contentTypeDef, inode->value); + } + if (ret != 0) { + if (ret < 0) { + VERROR_INT("xmlSchemaValidatorPopElem", + "calling xmlSchemaVCheckCVCSimpleType()"); + goto internal_error; + } + goto end_elem; + } + /* + * 5.2.2 If there is a fixed {value constraint} and clause 3.2 has + * not applied, all of the following must be true: + */ + if ((inode->decl->value != NULL) && + (inode->decl->flags & XML_SCHEMAS_ELEM_FIXED)) { + + /* + * TODO: We will need a computed value, when comparison is + * done on computed values. + */ + /* + * 5.2.2.1 The element information item must have no element + * information item [children]. + */ + if (inode->flags & + XML_SCHEMA_ELEM_INFO_HAS_ELEM_CONTENT) { + ret = XML_SCHEMAV_CVC_ELT_5_2_2_1; + VERROR(ret, NULL, + "The content must not containt element nodes since " + "there is a fixed value constraint"); + goto end_elem; + } else { + /* + * 5.2.2.2 The appropriate case among the following must + * be true: + */ + if (WXS_HAS_MIXED_CONTENT(inode->typeDef)) { + /* + * 5.2.2.2.1 If the {content type} of the �actual type + * definition� is mixed, then the *initial value* of the + * item must match the canonical lexical representation + * of the {value constraint} value. + * + * ... the *initial value* of an element information + * item is the string composed of, in order, the + * [character code] of each character information item in + * the [children] of that element information item. + */ + if (! xmlStrEqual(inode->value, inode->decl->value)){ + /* + * VAL TODO: Report invalid & expected values as well. + * VAL TODO: Implement the canonical stuff. + */ + ret = XML_SCHEMAV_CVC_ELT_5_2_2_2_1; + xmlSchemaCustomErr(ACTXT_CAST vctxt, + ret, NULL, NULL, + "The initial value '%s' does not match the fixed " + "value constraint '%s'", + inode->value, inode->decl->value); + goto end_elem; + } + } else if (WXS_HAS_SIMPLE_CONTENT(inode->typeDef)) { + /* + * 5.2.2.2.2 If the {content type} of the �actual type + * definition� is a simple type definition, then the + * *actual value* of the item must match the canonical + * lexical representation of the {value constraint} value. + */ + /* + * VAL TODO: *actual value* is the normalized value, impl. + * this. + * VAL TODO: Report invalid & expected values as well. + * VAL TODO: Implement a comparison with the computed values. + */ + if (! xmlStrEqual(inode->value, + inode->decl->value)) { + ret = XML_SCHEMAV_CVC_ELT_5_2_2_2_2; + xmlSchemaCustomErr(ACTXT_CAST vctxt, + ret, NULL, NULL, + "The actual value '%s' does not match the fixed " + "value constraint '%s'", + inode->value, + inode->decl->value); + goto end_elem; + } + } + } + } + } + +end_elem: + if (vctxt->depth < 0) { + /* TODO: raise error? */ + return (0); + } + if (vctxt->depth == vctxt->skipDepth) + vctxt->skipDepth = -1; + /* + * Evaluate the history of XPath state objects. + */ + if (inode->appliedXPath && + (xmlSchemaXPathProcessHistory(vctxt, vctxt->depth) == -1)) + goto internal_error; + /* + * MAYBE TODO: + * SPEC (6) "The element information item must be �valid� with + * respect to each of the {identity-constraint definitions} as per + * Identity-constraint Satisfied (�3.11.4)." + */ + /* + * PSVI TODO: If we expose IDC node-tables via PSVI then the tables + * need to be built in any case. + * We will currently build IDC node-tables and bubble them only if + * keyrefs do exist. + */ + + /* + * Add the current IDC target-nodes to the IDC node-tables. + */ + if ((inode->idcMatchers != NULL) && + (vctxt->hasKeyrefs || vctxt->createIDCNodeTables)) + { + if (xmlSchemaIDCFillNodeTables(vctxt, inode) == -1) + goto internal_error; + } + /* + * Validate IDC keyrefs. + */ + if (vctxt->inode->hasKeyrefs) + if (xmlSchemaCheckCVCIDCKeyRef(vctxt) == -1) + goto internal_error; + /* + * Merge/free the IDC table. + */ + if (inode->idcTable != NULL) { +#ifdef DEBUG_IDC_NODE_TABLE + xmlSchemaDebugDumpIDCTable(stdout, + inode->nsName, + inode->localName, + inode->idcTable); +#endif + if ((vctxt->depth > 0) && + (vctxt->hasKeyrefs || vctxt->createIDCNodeTables)) + { + /* + * Merge the IDC node table with the table of the parent node. + */ + if (xmlSchemaBubbleIDCNodeTables(vctxt) == -1) + goto internal_error; + } + } + /* + * Clear the current ielem. + * VAL TODO: Don't free the PSVI IDC tables if they are + * requested for the PSVI. + */ + xmlSchemaClearElemInfo(vctxt, inode); + /* + * Skip further processing if we are on the validation root. + */ + if (vctxt->depth == 0) { + vctxt->depth--; + vctxt->inode = NULL; + return (0); + } + /* + * Reset the keyrefDepth if needed. + */ + if (vctxt->aidcs != NULL) { + xmlSchemaIDCAugPtr aidc = vctxt->aidcs; + do { + if (aidc->keyrefDepth == vctxt->depth) { + /* + * A 'keyrefDepth' of a key/unique IDC matches the current + * depth, this means that we are leaving the scope of the + * top-most keyref IDC which refers to this IDC. + */ + aidc->keyrefDepth = -1; + } + aidc = aidc->next; + } while (aidc != NULL); + } + vctxt->depth--; + vctxt->inode = vctxt->elemInfos[vctxt->depth]; + /* + * VAL TODO: 7 If the element information item is the �validation root�, it must be + * �valid� per Validation Root Valid (ID/IDREF) (�3.3.4). + */ + return (ret); + +internal_error: + vctxt->err = -1; + return (-1); +} + +/* +* 3.4.4 Complex Type Definition Validation Rules +* Validation Rule: Element Locally Valid (Complex Type) (cvc-complex-type) +*/ +static int +xmlSchemaValidateChildElem(xmlSchemaValidCtxtPtr vctxt) +{ + xmlSchemaNodeInfoPtr pielem; + xmlSchemaTypePtr ptype; + int ret = 0; + + if (vctxt->depth <= 0) { + VERROR_INT("xmlSchemaValidateChildElem", + "not intended for the validation root"); + return (-1); + } + pielem = vctxt->elemInfos[vctxt->depth -1]; + if (pielem->flags & XML_SCHEMA_ELEM_INFO_EMPTY) + pielem->flags ^= XML_SCHEMA_ELEM_INFO_EMPTY; + /* + * Handle 'nilled' elements. + */ + if (INODE_NILLED(pielem)) { + /* + * SPEC (cvc-elt) (3.3.4) : (3.2.1) + */ + ACTIVATE_PARENT_ELEM; + ret = XML_SCHEMAV_CVC_ELT_3_2_1; + VERROR(ret, NULL, + "Neither character nor element content is allowed, " + "because the element was 'nilled'"); + ACTIVATE_ELEM; + goto unexpected_elem; + } + + ptype = pielem->typeDef; + + if (ptype->builtInType == XML_SCHEMAS_ANYTYPE) { + /* + * Workaround for "anyType": we have currently no content model + * assigned for "anyType", so handle it explicitely. + * "anyType" has an unbounded, lax "any" wildcard. + */ + vctxt->inode->decl = xmlSchemaGetElem(vctxt->schema, + vctxt->inode->localName, + vctxt->inode->nsName); + + if (vctxt->inode->decl == NULL) { + xmlSchemaAttrInfoPtr iattr; + /* + * Process "xsi:type". + * SPEC (cvc-assess-elt) (1.2.1.2.1) - (1.2.1.2.3) + */ + iattr = xmlSchemaGetMetaAttrInfo(vctxt, + XML_SCHEMA_ATTR_INFO_META_XSI_TYPE); + if (iattr != NULL) { + ret = xmlSchemaProcessXSIType(vctxt, iattr, + &(vctxt->inode->typeDef), NULL); + if (ret != 0) { + if (ret == -1) { + VERROR_INT("xmlSchemaValidateChildElem", + "calling xmlSchemaProcessXSIType() to " + "process the attribute 'xsi:nil'"); + return (-1); + } + return (ret); + } + } else { + /* + * Fallback to "anyType". + * + * SPEC (cvc-assess-elt) + * "If the item cannot be �strictly assessed�, [...] + * an element information item's schema validity may be laxly + * assessed if its �context-determined declaration� is not + * skip by �validating� with respect to the �ur-type + * definition� as per Element Locally Valid (Type) (�3.3.4)." + */ + vctxt->inode->typeDef = + xmlSchemaGetBuiltInType(XML_SCHEMAS_ANYTYPE); + } + } + return (0); + } + + switch (ptype->contentType) { + case XML_SCHEMA_CONTENT_EMPTY: + /* + * SPEC (2.1) "If the {content type} is empty, then the + * element information item has no character or element + * information item [children]." + */ + ACTIVATE_PARENT_ELEM + ret = XML_SCHEMAV_CVC_COMPLEX_TYPE_2_1; + VERROR(ret, NULL, + "Element content is not allowed, " + "because the content type is empty"); + ACTIVATE_ELEM + goto unexpected_elem; + break; + + case XML_SCHEMA_CONTENT_MIXED: + case XML_SCHEMA_CONTENT_ELEMENTS: { + xmlRegExecCtxtPtr regexCtxt; + xmlChar *values[10]; + int terminal, nbval = 10, nbneg; + + /* VAL TODO: Optimized "anyType" validation.*/ + + if (ptype->contModel == NULL) { + VERROR_INT("xmlSchemaValidateChildElem", + "type has elem content but no content model"); + return (-1); + } + /* + * Safety belf for evaluation if the cont. model was already + * examined to be invalid. + */ + if (pielem->flags & XML_SCHEMA_ELEM_INFO_ERR_BAD_CONTENT) { + VERROR_INT("xmlSchemaValidateChildElem", + "validating elem, but elem content is already invalid"); + return (-1); + } + + regexCtxt = pielem->regexCtxt; + if (regexCtxt == NULL) { + /* + * Create the regex context. + */ + regexCtxt = xmlRegNewExecCtxt(ptype->contModel, + (xmlRegExecCallbacks) xmlSchemaVContentModelCallback, + vctxt); + if (regexCtxt == NULL) { + VERROR_INT("xmlSchemaValidateChildElem", + "failed to create a regex context"); + return (-1); + } + pielem->regexCtxt = regexCtxt; +#ifdef DEBUG_AUTOMATA + xmlGenericError(xmlGenericErrorContext, "AUTOMATA create on '%s'\n", + pielem->localName); +#endif + } + + /* + * SPEC (2.4) "If the {content type} is element-only or mixed, + * then the sequence of the element information item's + * element information item [children], if any, taken in + * order, is �valid� with respect to the {content type}'s + * particle, as defined in Element Sequence Locally Valid + * (Particle) (�3.9.4)." + */ + ret = xmlRegExecPushString2(regexCtxt, + vctxt->inode->localName, + vctxt->inode->nsName, + vctxt->inode); +#ifdef DEBUG_AUTOMATA + if (ret < 0) + xmlGenericError(xmlGenericErrorContext, + "AUTOMATON push ERROR for '%s' on '%s'\n", + vctxt->inode->localName, pielem->localName); + else + xmlGenericError(xmlGenericErrorContext, + "AUTOMATON push OK for '%s' on '%s'\n", + vctxt->inode->localName, pielem->localName); +#endif + if (vctxt->err == XML_SCHEMAV_INTERNAL) { + VERROR_INT("xmlSchemaValidateChildElem", + "calling xmlRegExecPushString2()"); + return (-1); + } + if (ret < 0) { + xmlRegExecErrInfo(regexCtxt, NULL, &nbval, &nbneg, + &values[0], &terminal); + xmlSchemaComplexTypeErr(ACTXT_CAST vctxt, + XML_SCHEMAV_ELEMENT_CONTENT, NULL,NULL, + "This element is not expected", + nbval, nbneg, values); + ret = vctxt->err; + goto unexpected_elem; + } else + ret = 0; + } + break; + case XML_SCHEMA_CONTENT_SIMPLE: + case XML_SCHEMA_CONTENT_BASIC: + ACTIVATE_PARENT_ELEM + if (WXS_IS_COMPLEX(ptype)) { + /* + * SPEC (cvc-complex-type) (2.2) + * "If the {content type} is a simple type definition, then + * the element information item has no element information + * item [children], ..." + */ + ret = XML_SCHEMAV_CVC_COMPLEX_TYPE_2_2; + VERROR(ret, NULL, "Element content is not allowed, " + "because the content type is a simple type definition"); + } else { + /* + * SPEC (cvc-type) (3.1.2) "The element information item must + * have no element information item [children]." + */ + ret = XML_SCHEMAV_CVC_TYPE_3_1_2; + VERROR(ret, NULL, "Element content is not allowed, " + "because the type definition is simple"); + } + ACTIVATE_ELEM + ret = vctxt->err; + goto unexpected_elem; + break; + + default: + break; + } + return (ret); +unexpected_elem: + /* + * Pop this element and set the skipDepth to skip + * all further content of the parent element. + */ + vctxt->skipDepth = vctxt->depth; + vctxt->inode->flags |= XML_SCHEMA_NODE_INFO_ERR_NOT_EXPECTED; + pielem->flags |= XML_SCHEMA_ELEM_INFO_ERR_BAD_CONTENT; + return (ret); +} + +#define XML_SCHEMA_PUSH_TEXT_PERSIST 1 +#define XML_SCHEMA_PUSH_TEXT_CREATED 2 +#define XML_SCHEMA_PUSH_TEXT_VOLATILE 3 + +static int +xmlSchemaVPushText(xmlSchemaValidCtxtPtr vctxt, + int nodeType, const xmlChar *value, int len, + int mode, int *consumed) +{ + /* + * Unfortunately we have to duplicate the text sometimes. + * OPTIMIZE: Maybe we could skip it, if: + * 1. content type is simple + * 2. whitespace is "collapse" + * 3. it consists of whitespace only + * + * Process character content. + */ + if (consumed != NULL) + *consumed = 0; + if (INODE_NILLED(vctxt->inode)) { + /* + * SPEC cvc-elt (3.3.4 - 3.2.1) + * "The element information item must have no character or + * element information item [children]." + */ + VERROR(XML_SCHEMAV_CVC_ELT_3_2_1, NULL, + "Neither character nor element content is allowed " + "because the element is 'nilled'"); + return (vctxt->err); + } + /* + * SPEC (2.1) "If the {content type} is empty, then the + * element information item has no character or element + * information item [children]." + */ + if (vctxt->inode->typeDef->contentType == + XML_SCHEMA_CONTENT_EMPTY) { + VERROR(XML_SCHEMAV_CVC_COMPLEX_TYPE_2_1, NULL, + "Character content is not allowed, " + "because the content type is empty"); + return (vctxt->err); + } + + if (vctxt->inode->typeDef->contentType == + XML_SCHEMA_CONTENT_ELEMENTS) { + if ((nodeType != XML_TEXT_NODE) || + (! xmlSchemaIsBlank((xmlChar *) value, len))) { + /* + * SPEC cvc-complex-type (2.3) + * "If the {content type} is element-only, then the + * element information item has no character information + * item [children] other than those whose [character + * code] is defined as a white space in [XML 1.0 (Second + * Edition)]." + */ + VERROR(XML_SCHEMAV_CVC_COMPLEX_TYPE_2_3, NULL, + "Character content other than whitespace is not allowed " + "because the content type is 'element-only'"); + return (vctxt->err); + } + return (0); + } + + if ((value == NULL) || (value[0] == 0)) + return (0); + /* + * Save the value. + * NOTE that even if the content type is *mixed*, we need the + * *initial value* for default/fixed value constraints. + */ + if ((vctxt->inode->typeDef->contentType == XML_SCHEMA_CONTENT_MIXED) && + ((vctxt->inode->decl == NULL) || + (vctxt->inode->decl->value == NULL))) + return (0); + + if (vctxt->inode->value == NULL) { + /* + * Set the value. + */ + switch (mode) { + case XML_SCHEMA_PUSH_TEXT_PERSIST: + /* + * When working on a tree. + */ + vctxt->inode->value = value; + break; + case XML_SCHEMA_PUSH_TEXT_CREATED: + /* + * When working with the reader. + * The value will be freed by the element info. + */ + vctxt->inode->value = value; + if (consumed != NULL) + *consumed = 1; + vctxt->inode->flags |= + XML_SCHEMA_NODE_INFO_FLAG_OWNED_VALUES; + break; + case XML_SCHEMA_PUSH_TEXT_VOLATILE: + /* + * When working with SAX. + * The value will be freed by the element info. + */ + if (len != -1) + vctxt->inode->value = BAD_CAST xmlStrndup(value, len); + else + vctxt->inode->value = BAD_CAST xmlStrdup(value); + vctxt->inode->flags |= + XML_SCHEMA_NODE_INFO_FLAG_OWNED_VALUES; + break; + default: + break; + } + } else { + if (len < 0) + len = xmlStrlen(value); + /* + * Concat the value. + */ + if (vctxt->inode->flags & XML_SCHEMA_NODE_INFO_FLAG_OWNED_VALUES) { + vctxt->inode->value = BAD_CAST xmlStrncat( + (xmlChar *) vctxt->inode->value, value, len); + } else { + vctxt->inode->value = + BAD_CAST xmlStrncatNew(vctxt->inode->value, value, len); + vctxt->inode->flags |= XML_SCHEMA_NODE_INFO_FLAG_OWNED_VALUES; + } + } + + return (0); +} + +static int +xmlSchemaValidateElem(xmlSchemaValidCtxtPtr vctxt) +{ + int ret = 0; + + if ((vctxt->skipDepth != -1) && + (vctxt->depth >= vctxt->skipDepth)) { + VERROR_INT("xmlSchemaValidateElem", + "in skip-state"); + goto internal_error; + } + if (vctxt->xsiAssemble) { + /* + * We will stop validation if there was an error during + * dynamic schema construction. + * Note that we simply set @skipDepth to 0, this could + * mean that a streaming document via SAX would be + * still read to the end but it won't be validated any more. + * TODO: If we are sure how to stop the validation at once + * for all input scenarios, then this should be changed to + * instantly stop the validation. + */ + ret = xmlSchemaAssembleByXSI(vctxt); + if (ret != 0) { + if (ret == -1) + goto internal_error; + vctxt->skipDepth = 0; + return(ret); + } + /* + * Augment the IDC definitions for the main schema and all imported ones + * NOTE: main schema is the first in the imported list + */ + xmlHashScan(vctxt->schema->schemasImports,(xmlHashScanner)xmlSchemaAugmentImportedIDC, vctxt); + } + if (vctxt->depth > 0) { + /* + * Validate this element against the content model + * of the parent. + */ + ret = xmlSchemaValidateChildElem(vctxt); + if (ret != 0) { + if (ret < 0) { + VERROR_INT("xmlSchemaValidateElem", + "calling xmlSchemaStreamValidateChildElement()"); + goto internal_error; + } + goto exit; + } + if (vctxt->depth == vctxt->skipDepth) + goto exit; + if ((vctxt->inode->decl == NULL) && + (vctxt->inode->typeDef == NULL)) { + VERROR_INT("xmlSchemaValidateElem", + "the child element was valid but neither the " + "declaration nor the type was set"); + goto internal_error; + } + } else { + /* + * Get the declaration of the validation root. + */ + vctxt->inode->decl = xmlSchemaGetElem(vctxt->schema, + vctxt->inode->localName, + vctxt->inode->nsName); + if (vctxt->inode->decl == NULL) { + ret = XML_SCHEMAV_CVC_ELT_1; + VERROR(ret, NULL, + "No matching global declaration available " + "for the validation root"); + goto exit; + } + } + + if (vctxt->inode->decl == NULL) + goto type_validation; + + if (vctxt->inode->decl->type == XML_SCHEMA_TYPE_ANY) { + int skip; + /* + * Wildcards. + */ + ret = xmlSchemaValidateElemWildcard(vctxt, &skip); + if (ret != 0) { + if (ret < 0) { + VERROR_INT("xmlSchemaValidateElem", + "calling xmlSchemaValidateElemWildcard()"); + goto internal_error; + } + goto exit; + } + if (skip) { + vctxt->skipDepth = vctxt->depth; + goto exit; + } + /* + * The declaration might be set by the wildcard validation, + * when the processContents is "lax" or "strict". + */ + if (vctxt->inode->decl->type != XML_SCHEMA_TYPE_ELEMENT) { + /* + * Clear the "decl" field to not confuse further processing. + */ + vctxt->inode->decl = NULL; + goto type_validation; + } + } + /* + * Validate against the declaration. + */ + ret = xmlSchemaValidateElemDecl(vctxt); + if (ret != 0) { + if (ret < 0) { + VERROR_INT("xmlSchemaValidateElem", + "calling xmlSchemaValidateElemDecl()"); + goto internal_error; + } + goto exit; + } + /* + * Validate against the type definition. + */ +type_validation: + + if (vctxt->inode->typeDef == NULL) { + vctxt->inode->flags |= XML_SCHEMA_NODE_INFO_ERR_BAD_TYPE; + ret = XML_SCHEMAV_CVC_TYPE_1; + VERROR(ret, NULL, + "The type definition is absent"); + goto exit; + } + if (vctxt->inode->typeDef->flags & XML_SCHEMAS_TYPE_ABSTRACT) { + vctxt->inode->flags |= XML_SCHEMA_NODE_INFO_ERR_BAD_TYPE; + ret = XML_SCHEMAV_CVC_TYPE_2; + VERROR(ret, NULL, + "The type definition is abstract"); + goto exit; + } + /* + * Evaluate IDCs. Do it here, since new IDC matchers are registered + * during validation against the declaration. This must be done + * _before_ attribute validation. + */ + if (vctxt->xpathStates != NULL) { + ret = xmlSchemaXPathEvaluate(vctxt, XML_ELEMENT_NODE); + vctxt->inode->appliedXPath = 1; + if (ret == -1) { + VERROR_INT("xmlSchemaValidateElem", + "calling xmlSchemaXPathEvaluate()"); + goto internal_error; + } + } + /* + * Validate attributes. + */ + if (WXS_IS_COMPLEX(vctxt->inode->typeDef)) { + if ((vctxt->nbAttrInfos != 0) || + (vctxt->inode->typeDef->attrUses != NULL)) { + + ret = xmlSchemaVAttributesComplex(vctxt); + } + } else if (vctxt->nbAttrInfos != 0) { + + ret = xmlSchemaVAttributesSimple(vctxt); + } + /* + * Clear registered attributes. + */ + if (vctxt->nbAttrInfos != 0) + xmlSchemaClearAttrInfos(vctxt); + if (ret == -1) { + VERROR_INT("xmlSchemaValidateElem", + "calling attributes validation"); + goto internal_error; + } + /* + * Don't return an error if attributes are invalid on purpose. + */ + ret = 0; + +exit: + if (ret != 0) + vctxt->skipDepth = vctxt->depth; + return (ret); +internal_error: + return (-1); +} + +#ifdef XML_SCHEMA_READER_ENABLED +static int +xmlSchemaVReaderWalk(xmlSchemaValidCtxtPtr vctxt) +{ + const int WHTSP = 13, SIGN_WHTSP = 14, END_ELEM = 15; + int depth, nodeType, ret = 0, consumed; + xmlSchemaNodeInfoPtr ielem; + + vctxt->depth = -1; + ret = xmlTextReaderRead(vctxt->reader); + /* + * Move to the document element. + */ + while (ret == 1) { + nodeType = xmlTextReaderNodeType(vctxt->reader); + if (nodeType == XML_ELEMENT_NODE) + goto root_found; + ret = xmlTextReaderRead(vctxt->reader); + } + goto exit; + +root_found: + + do { + depth = xmlTextReaderDepth(vctxt->reader); + nodeType = xmlTextReaderNodeType(vctxt->reader); + + if (nodeType == XML_ELEMENT_NODE) { + + vctxt->depth++; + if (xmlSchemaValidatorPushElem(vctxt) == -1) { + VERROR_INT("xmlSchemaVReaderWalk", + "calling xmlSchemaValidatorPushElem()"); + goto internal_error; + } + ielem = vctxt->inode; + ielem->localName = xmlTextReaderLocalName(vctxt->reader); + ielem->nsName = xmlTextReaderNamespaceUri(vctxt->reader); + ielem->flags |= XML_SCHEMA_NODE_INFO_FLAG_OWNED_NAMES; + /* + * Is the element empty? + */ + ret = xmlTextReaderIsEmptyElement(vctxt->reader); + if (ret == -1) { + VERROR_INT("xmlSchemaVReaderWalk", + "calling xmlTextReaderIsEmptyElement()"); + goto internal_error; + } + if (ret) { + ielem->flags |= XML_SCHEMA_ELEM_INFO_EMPTY; + } + /* + * Register attributes. + */ + vctxt->nbAttrInfos = 0; + ret = xmlTextReaderMoveToFirstAttribute(vctxt->reader); + if (ret == -1) { + VERROR_INT("xmlSchemaVReaderWalk", + "calling xmlTextReaderMoveToFirstAttribute()"); + goto internal_error; + } + if (ret == 1) { + do { + /* + * VAL TODO: How do we know that the reader works on a + * node tree, to be able to pass a node here? + */ + if (xmlSchemaValidatorPushAttribute(vctxt, NULL, + (const xmlChar *) xmlTextReaderLocalName(vctxt->reader), + xmlTextReaderNamespaceUri(vctxt->reader), 1, + xmlTextReaderValue(vctxt->reader), 1) == -1) { + + VERROR_INT("xmlSchemaVReaderWalk", + "calling xmlSchemaValidatorPushAttribute()"); + goto internal_error; + } + ret = xmlTextReaderMoveToNextAttribute(vctxt->reader); + if (ret == -1) { + VERROR_INT("xmlSchemaVReaderWalk", + "calling xmlTextReaderMoveToFirstAttribute()"); + goto internal_error; + } + } while (ret == 1); + /* + * Back to element position. + */ + ret = xmlTextReaderMoveToElement(vctxt->reader); + if (ret == -1) { + VERROR_INT("xmlSchemaVReaderWalk", + "calling xmlTextReaderMoveToElement()"); + goto internal_error; + } + } + /* + * Validate the element. + */ + ret= xmlSchemaValidateElem(vctxt); + if (ret != 0) { + if (ret == -1) { + VERROR_INT("xmlSchemaVReaderWalk", + "calling xmlSchemaValidateElem()"); + goto internal_error; + } + goto exit; + } + if (vctxt->depth == vctxt->skipDepth) { + int curDepth; + /* + * Skip all content. + */ + if ((ielem->flags & XML_SCHEMA_ELEM_INFO_EMPTY) == 0) { + ret = xmlTextReaderRead(vctxt->reader); + curDepth = xmlTextReaderDepth(vctxt->reader); + while ((ret == 1) && (curDepth != depth)) { + ret = xmlTextReaderRead(vctxt->reader); + curDepth = xmlTextReaderDepth(vctxt->reader); + } + if (ret < 0) { + /* + * VAL TODO: A reader error occured; what to do here? + */ + ret = 1; + goto exit; + } + } + goto leave_elem; + } + /* + * READER VAL TODO: Is an END_ELEM really never called + * if the elem is empty? + */ + if (ielem->flags & XML_SCHEMA_ELEM_INFO_EMPTY) + goto leave_elem; + } else if (nodeType == END_ELEM) { + /* + * Process END of element. + */ +leave_elem: + ret = xmlSchemaValidatorPopElem(vctxt); + if (ret != 0) { + if (ret < 0) { + VERROR_INT("xmlSchemaVReaderWalk", + "calling xmlSchemaValidatorPopElem()"); + goto internal_error; + } + goto exit; + } + if (vctxt->depth >= 0) + ielem = vctxt->inode; + else + ielem = NULL; + } else if ((nodeType == XML_TEXT_NODE) || + (nodeType == XML_CDATA_SECTION_NODE) || + (nodeType == WHTSP) || + (nodeType == SIGN_WHTSP)) { + /* + * Process character content. + */ + xmlChar *value; + + if ((nodeType == WHTSP) || (nodeType == SIGN_WHTSP)) + nodeType = XML_TEXT_NODE; + + value = xmlTextReaderValue(vctxt->reader); + ret = xmlSchemaVPushText(vctxt, nodeType, BAD_CAST value, + -1, XML_SCHEMA_PUSH_TEXT_CREATED, &consumed); + if (! consumed) + xmlFree(value); + if (ret == -1) { + VERROR_INT("xmlSchemaVReaderWalk", + "calling xmlSchemaVPushText()"); + goto internal_error; + } + } else if ((nodeType == XML_ENTITY_NODE) || + (nodeType == XML_ENTITY_REF_NODE)) { + /* + * VAL TODO: What to do with entities? + */ + TODO + } + /* + * Read next node. + */ + ret = xmlTextReaderRead(vctxt->reader); + } while (ret == 1); + +exit: + return (ret); +internal_error: + return (-1); +} +#endif + +/************************************************************************ + * * + * SAX validation handlers * + * * + ************************************************************************/ + +/* +* Process text content. +*/ +static void +xmlSchemaSAXHandleText(void *ctx, + const xmlChar * ch, + int len) +{ + xmlSchemaValidCtxtPtr vctxt = (xmlSchemaValidCtxtPtr) ctx; + + if (vctxt->depth < 0) + return; + if ((vctxt->skipDepth != -1) && (vctxt->depth >= vctxt->skipDepth)) + return; + if (vctxt->inode->flags & XML_SCHEMA_ELEM_INFO_EMPTY) + vctxt->inode->flags ^= XML_SCHEMA_ELEM_INFO_EMPTY; + if (xmlSchemaVPushText(vctxt, XML_TEXT_NODE, ch, len, + XML_SCHEMA_PUSH_TEXT_VOLATILE, NULL) == -1) { + VERROR_INT("xmlSchemaSAXHandleCDataSection", + "calling xmlSchemaVPushText()"); + vctxt->err = -1; + xmlStopParser(vctxt->parserCtxt); + } +} + +/* +* Process CDATA content. +*/ +static void +xmlSchemaSAXHandleCDataSection(void *ctx, + const xmlChar * ch, + int len) +{ + xmlSchemaValidCtxtPtr vctxt = (xmlSchemaValidCtxtPtr) ctx; + + if (vctxt->depth < 0) + return; + if ((vctxt->skipDepth != -1) && (vctxt->depth >= vctxt->skipDepth)) + return; + if (vctxt->inode->flags & XML_SCHEMA_ELEM_INFO_EMPTY) + vctxt->inode->flags ^= XML_SCHEMA_ELEM_INFO_EMPTY; + if (xmlSchemaVPushText(vctxt, XML_CDATA_SECTION_NODE, ch, len, + XML_SCHEMA_PUSH_TEXT_VOLATILE, NULL) == -1) { + VERROR_INT("xmlSchemaSAXHandleCDataSection", + "calling xmlSchemaVPushText()"); + vctxt->err = -1; + xmlStopParser(vctxt->parserCtxt); + } +} + +static void +xmlSchemaSAXHandleReference(void *ctx ATTRIBUTE_UNUSED, + const xmlChar * name ATTRIBUTE_UNUSED) +{ + xmlSchemaValidCtxtPtr vctxt = (xmlSchemaValidCtxtPtr) ctx; + + if (vctxt->depth < 0) + return; + if ((vctxt->skipDepth != -1) && (vctxt->depth >= vctxt->skipDepth)) + return; + /* SAX VAL TODO: What to do here? */ + TODO +} + +static void +xmlSchemaSAXHandleStartElementNs(void *ctx, + const xmlChar * localname, + const xmlChar * prefix ATTRIBUTE_UNUSED, + const xmlChar * URI, + int nb_namespaces, + const xmlChar ** namespaces, + int nb_attributes, + int nb_defaulted ATTRIBUTE_UNUSED, + const xmlChar ** attributes) +{ + xmlSchemaValidCtxtPtr vctxt = (xmlSchemaValidCtxtPtr) ctx; + int ret; + xmlSchemaNodeInfoPtr ielem; + int i, j; + + /* + * SAX VAL TODO: What to do with nb_defaulted? + */ + /* + * Skip elements if inside a "skip" wildcard or invalid. + */ + vctxt->depth++; + if ((vctxt->skipDepth != -1) && (vctxt->depth >= vctxt->skipDepth)) + return; + /* + * Push the element. + */ + if (xmlSchemaValidatorPushElem(vctxt) == -1) { + VERROR_INT("xmlSchemaSAXHandleStartElementNs", + "calling xmlSchemaValidatorPushElem()"); + goto internal_error; + } + ielem = vctxt->inode; + /* + * TODO: Is this OK? + */ + ielem->nodeLine = xmlSAX2GetLineNumber(vctxt->parserCtxt); + ielem->localName = localname; + ielem->nsName = URI; + ielem->flags |= XML_SCHEMA_ELEM_INFO_EMPTY; + /* + * Register namespaces on the elem info. + */ + if (nb_namespaces != 0) { + /* + * Although the parser builds its own namespace list, + * we have no access to it, so we'll use an own one. + */ + for (i = 0, j = 0; i < nb_namespaces; i++, j += 2) { + /* + * Store prefix and namespace name. + */ + if (ielem->nsBindings == NULL) { + ielem->nsBindings = + (const xmlChar **) xmlMalloc(10 * + sizeof(const xmlChar *)); + if (ielem->nsBindings == NULL) { + xmlSchemaVErrMemory(vctxt, + "allocating namespace bindings for SAX validation", + NULL); + goto internal_error; + } + ielem->nbNsBindings = 0; + ielem->sizeNsBindings = 5; + } else if (ielem->sizeNsBindings <= ielem->nbNsBindings) { + ielem->sizeNsBindings *= 2; + ielem->nsBindings = + (const xmlChar **) xmlRealloc( + (void *) ielem->nsBindings, + ielem->sizeNsBindings * 2 * sizeof(const xmlChar *)); + if (ielem->nsBindings == NULL) { + xmlSchemaVErrMemory(vctxt, + "re-allocating namespace bindings for SAX validation", + NULL); + goto internal_error; + } + } + + ielem->nsBindings[ielem->nbNsBindings * 2] = namespaces[j]; + if (namespaces[j+1][0] == 0) { + /* + * Handle xmlns="". + */ + ielem->nsBindings[ielem->nbNsBindings * 2 + 1] = NULL; + } else + ielem->nsBindings[ielem->nbNsBindings * 2 + 1] = + namespaces[j+1]; + ielem->nbNsBindings++; + } + } + /* + * Register attributes. + * SAX VAL TODO: We are not adding namespace declaration + * attributes yet. + */ + if (nb_attributes != 0) { + xmlChar *value; + + for (j = 0, i = 0; i < nb_attributes; i++, j += 5) { + /* + * Duplicate the value. + */ + value = xmlStrndup(attributes[j+3], + attributes[j+4] - attributes[j+3]); + /* + * TODO: Set the node line. + */ + ret = xmlSchemaValidatorPushAttribute(vctxt, + NULL, ielem->nodeLine, attributes[j], attributes[j+2], 0, + value, 1); + if (ret == -1) { + VERROR_INT("xmlSchemaSAXHandleStartElementNs", + "calling xmlSchemaValidatorPushAttribute()"); + goto internal_error; + } + } + } + /* + * Validate the element. + */ + ret = xmlSchemaValidateElem(vctxt); + if (ret != 0) { + if (ret == -1) { + VERROR_INT("xmlSchemaSAXHandleStartElementNs", + "calling xmlSchemaValidateElem()"); + goto internal_error; + } + goto exit; + } + +exit: + return; +internal_error: + vctxt->err = -1; + xmlStopParser(vctxt->parserCtxt); + return; +} + +static void +xmlSchemaSAXHandleEndElementNs(void *ctx, + const xmlChar * localname ATTRIBUTE_UNUSED, + const xmlChar * prefix ATTRIBUTE_UNUSED, + const xmlChar * URI ATTRIBUTE_UNUSED) +{ + xmlSchemaValidCtxtPtr vctxt = (xmlSchemaValidCtxtPtr) ctx; + int res; + + /* + * Skip elements if inside a "skip" wildcard or if invalid. + */ + if (vctxt->skipDepth != -1) { + if (vctxt->depth > vctxt->skipDepth) { + vctxt->depth--; + return; + } else + vctxt->skipDepth = -1; + } + /* + * SAX VAL TODO: Just a temporary check. + */ + if ((!xmlStrEqual(vctxt->inode->localName, localname)) || + (!xmlStrEqual(vctxt->inode->nsName, URI))) { + VERROR_INT("xmlSchemaSAXHandleEndElementNs", + "elem pop mismatch"); + } + res = xmlSchemaValidatorPopElem(vctxt); + if (res != 0) { + if (res < 0) { + VERROR_INT("xmlSchemaSAXHandleEndElementNs", + "calling xmlSchemaValidatorPopElem()"); + goto internal_error; + } + goto exit; + } +exit: + return; +internal_error: + vctxt->err = -1; + xmlStopParser(vctxt->parserCtxt); + return; +} + +/************************************************************************ + * * + * Validation interfaces * + * * + ************************************************************************/ + +/** + * xmlSchemaNewValidCtxt: + * @schema: a precompiled XML Schemas + * + * Create an XML Schemas validation context based on the given schema. + * + * Returns the validation context or NULL in case of error + */ +xmlSchemaValidCtxtPtr +xmlSchemaNewValidCtxt(xmlSchemaPtr schema) +{ + xmlSchemaValidCtxtPtr ret; + + ret = (xmlSchemaValidCtxtPtr) xmlMalloc(sizeof(xmlSchemaValidCtxt)); + if (ret == NULL) { + xmlSchemaVErrMemory(NULL, "allocating validation context", NULL); + return (NULL); + } + memset(ret, 0, sizeof(xmlSchemaValidCtxt)); + ret->type = XML_SCHEMA_CTXT_VALIDATOR; + ret->dict = xmlDictCreate(); + ret->nodeQNames = xmlSchemaItemListCreate(); + ret->schema = schema; + return (ret); +} + +/** + * xmlSchemaClearValidCtxt: + * @ctxt: the schema validation context + * + * Free the resources associated to the schema validation context; + * leaves some fields alive intended for reuse of the context. + */ +static void +xmlSchemaClearValidCtxt(xmlSchemaValidCtxtPtr vctxt) +{ + if (vctxt == NULL) + return; + + /* + * TODO: Should we clear the flags? + * Might be problematic if one reuses the context + * and assumes that the options remain the same. + */ + vctxt->flags = 0; + vctxt->validationRoot = NULL; + vctxt->doc = NULL; +#ifdef LIBXML_READER_ENABLED + vctxt->reader = NULL; +#endif + vctxt->hasKeyrefs = 0; + + if (vctxt->value != NULL) { + xmlSchemaFreeValue(vctxt->value); + vctxt->value = NULL; + } + /* + * Augmented IDC information. + */ + if (vctxt->aidcs != NULL) { + xmlSchemaIDCAugPtr cur = vctxt->aidcs, next; + do { + next = cur->next; + xmlFree(cur); + cur = next; + } while (cur != NULL); + vctxt->aidcs = NULL; + } + if (vctxt->idcMatcherCache != NULL) { + xmlSchemaIDCMatcherPtr matcher = vctxt->idcMatcherCache, tmp; + + while (matcher) { + tmp = matcher; + matcher = matcher->nextCached; + xmlSchemaIDCFreeMatcherList(tmp); + } + vctxt->idcMatcherCache = NULL; + } + + + if (vctxt->idcNodes != NULL) { + int i; + xmlSchemaPSVIIDCNodePtr item; + + for (i = 0; i < vctxt->nbIdcNodes; i++) { + item = vctxt->idcNodes[i]; + xmlFree(item->keys); + xmlFree(item); + } + xmlFree(vctxt->idcNodes); + vctxt->idcNodes = NULL; + vctxt->nbIdcNodes = 0; + vctxt->sizeIdcNodes = 0; + } + /* + * Note that we won't delete the XPath state pool here. + */ + if (vctxt->xpathStates != NULL) { + xmlSchemaFreeIDCStateObjList(vctxt->xpathStates); + vctxt->xpathStates = NULL; + } + /* + * Attribute info. + */ + if (vctxt->nbAttrInfos != 0) { + xmlSchemaClearAttrInfos(vctxt); + } + /* + * Element info. + */ + if (vctxt->elemInfos != NULL) { + int i; + xmlSchemaNodeInfoPtr ei; + + for (i = 0; i < vctxt->sizeElemInfos; i++) { + ei = vctxt->elemInfos[i]; + if (ei == NULL) + break; + xmlSchemaClearElemInfo(vctxt, ei); + } + } + xmlSchemaItemListClear(vctxt->nodeQNames); + /* Recreate the dict. */ + xmlDictFree(vctxt->dict); + /* + * TODO: Is is save to recreate it? Do we have a scenario + * where the user provides the dict? + */ + vctxt->dict = xmlDictCreate(); +} + +/** + * xmlSchemaFreeValidCtxt: + * @ctxt: the schema validation context + * + * Free the resources associated to the schema validation context + */ +void +xmlSchemaFreeValidCtxt(xmlSchemaValidCtxtPtr ctxt) +{ + if (ctxt == NULL) + return; + if (ctxt->value != NULL) + xmlSchemaFreeValue(ctxt->value); + if (ctxt->pctxt != NULL) + xmlSchemaFreeParserCtxt(ctxt->pctxt); + if (ctxt->idcNodes != NULL) { + int i; + xmlSchemaPSVIIDCNodePtr item; + + for (i = 0; i < ctxt->nbIdcNodes; i++) { + item = ctxt->idcNodes[i]; + xmlFree(item->keys); + xmlFree(item); + } + xmlFree(ctxt->idcNodes); + } + if (ctxt->idcKeys != NULL) { + int i; + for (i = 0; i < ctxt->nbIdcKeys; i++) + xmlSchemaIDCFreeKey(ctxt->idcKeys[i]); + xmlFree(ctxt->idcKeys); + } + + if (ctxt->xpathStates != NULL) { + xmlSchemaFreeIDCStateObjList(ctxt->xpathStates); + ctxt->xpathStates = NULL; + } + if (ctxt->xpathStatePool != NULL) { + xmlSchemaFreeIDCStateObjList(ctxt->xpathStatePool); + ctxt->xpathStatePool = NULL; + } + + /* + * Augmented IDC information. + */ + if (ctxt->aidcs != NULL) { + xmlSchemaIDCAugPtr cur = ctxt->aidcs, next; + do { + next = cur->next; + xmlFree(cur); + cur = next; + } while (cur != NULL); + } + if (ctxt->attrInfos != NULL) { + int i; + xmlSchemaAttrInfoPtr attr; + + /* Just a paranoid call to the cleanup. */ + if (ctxt->nbAttrInfos != 0) + xmlSchemaClearAttrInfos(ctxt); + for (i = 0; i < ctxt->sizeAttrInfos; i++) { + attr = ctxt->attrInfos[i]; + xmlFree(attr); + } + xmlFree(ctxt->attrInfos); + } + if (ctxt->elemInfos != NULL) { + int i; + xmlSchemaNodeInfoPtr ei; + + for (i = 0; i < ctxt->sizeElemInfos; i++) { + ei = ctxt->elemInfos[i]; + if (ei == NULL) + break; + xmlSchemaClearElemInfo(ctxt, ei); + xmlFree(ei); + } + xmlFree(ctxt->elemInfos); + } + if (ctxt->nodeQNames != NULL) + xmlSchemaItemListFree(ctxt->nodeQNames); + if (ctxt->dict != NULL) + xmlDictFree(ctxt->dict); + xmlFree(ctxt); +} + +/** + * xmlSchemaIsValid: + * @ctxt: the schema validation context + * + * Check if any error was detected during validation. + * + * Returns 1 if valid so far, 0 if errors were detected, and -1 in case + * of internal error. + */ +int +xmlSchemaIsValid(xmlSchemaValidCtxtPtr ctxt) +{ + if (ctxt == NULL) + return(-1); + return(ctxt->err == 0); +} + +/** + * xmlSchemaSetValidErrors: + * @ctxt: a schema validation context + * @err: the error function + * @warn: the warning function + * @ctx: the functions context + * + * Set the error and warning callback informations + */ +void +xmlSchemaSetValidErrors(xmlSchemaValidCtxtPtr ctxt, + xmlSchemaValidityErrorFunc err, + xmlSchemaValidityWarningFunc warn, void *ctx) +{ + if (ctxt == NULL) + return; + ctxt->error = err; + ctxt->warning = warn; + ctxt->errCtxt = ctx; + if (ctxt->pctxt != NULL) + xmlSchemaSetParserErrors(ctxt->pctxt, err, warn, ctx); +} + +/** + * xmlSchemaSetValidStructuredErrors: + * @ctxt: a schema validation context + * @serror: the structured error function + * @ctx: the functions context + * + * Set the structured error callback + */ +void +xmlSchemaSetValidStructuredErrors(xmlSchemaValidCtxtPtr ctxt, + xmlStructuredErrorFunc serror, void *ctx) +{ + if (ctxt == NULL) + return; + ctxt->serror = serror; + ctxt->error = NULL; + ctxt->warning = NULL; + ctxt->errCtxt = ctx; + if (ctxt->pctxt != NULL) + xmlSchemaSetParserStructuredErrors(ctxt->pctxt, serror, ctx); +} + +/** + * xmlSchemaGetValidErrors: + * @ctxt: a XML-Schema validation context + * @err: the error function result + * @warn: the warning function result + * @ctx: the functions context result + * + * Get the error and warning callback informations + * + * Returns -1 in case of error and 0 otherwise + */ +int +xmlSchemaGetValidErrors(xmlSchemaValidCtxtPtr ctxt, + xmlSchemaValidityErrorFunc * err, + xmlSchemaValidityWarningFunc * warn, void **ctx) +{ + if (ctxt == NULL) + return (-1); + if (err != NULL) + *err = ctxt->error; + if (warn != NULL) + *warn = ctxt->warning; + if (ctx != NULL) + *ctx = ctxt->errCtxt; + return (0); +} + + +/** + * xmlSchemaSetValidOptions: + * @ctxt: a schema validation context + * @options: a combination of xmlSchemaValidOption + * + * Sets the options to be used during the validation. + * + * Returns 0 in case of success, -1 in case of an + * API error. + */ +int +xmlSchemaSetValidOptions(xmlSchemaValidCtxtPtr ctxt, + int options) + +{ + int i; + + if (ctxt == NULL) + return (-1); + /* + * WARNING: Change the start value if adding to the + * xmlSchemaValidOption. + * TODO: Is there an other, more easy to maintain, + * way? + */ + for (i = 1; i < (int) sizeof(int) * 8; i++) { + if (options & 1<options = options; + return (0); +} + +/** + * xmlSchemaValidCtxtGetOptions: + * @ctxt: a schema validation context + * + * Get the validation context options. + * + * Returns the option combination or -1 on error. + */ +int +xmlSchemaValidCtxtGetOptions(xmlSchemaValidCtxtPtr ctxt) + +{ + if (ctxt == NULL) + return (-1); + else + return (ctxt->options); +} + +static int +xmlSchemaVDocWalk(xmlSchemaValidCtxtPtr vctxt) +{ + xmlAttrPtr attr; + int ret = 0; + xmlSchemaNodeInfoPtr ielem = NULL; + xmlNodePtr node, valRoot; + const xmlChar *nsName; + + /* DOC VAL TODO: Move this to the start function. */ + valRoot = xmlDocGetRootElement(vctxt->doc); + if (valRoot == NULL) { + /* VAL TODO: Error code? */ + VERROR(1, NULL, "The document has no document element"); + return (1); + } + vctxt->depth = -1; + vctxt->validationRoot = valRoot; + node = valRoot; + while (node != NULL) { + if ((vctxt->skipDepth != -1) && (vctxt->depth >= vctxt->skipDepth)) + goto next_sibling; + if (node->type == XML_ELEMENT_NODE) { + + /* + * Init the node-info. + */ + vctxt->depth++; + if (xmlSchemaValidatorPushElem(vctxt) == -1) + goto internal_error; + ielem = vctxt->inode; + ielem->node = node; + ielem->nodeLine = node->line; + ielem->localName = node->name; + if (node->ns != NULL) + ielem->nsName = node->ns->href; + ielem->flags |= XML_SCHEMA_ELEM_INFO_EMPTY; + /* + * Register attributes. + * DOC VAL TODO: We do not register namespace declaration + * attributes yet. + */ + vctxt->nbAttrInfos = 0; + if (node->properties != NULL) { + attr = node->properties; + do { + if (attr->ns != NULL) + nsName = attr->ns->href; + else + nsName = NULL; + ret = xmlSchemaValidatorPushAttribute(vctxt, + (xmlNodePtr) attr, + /* + * Note that we give it the line number of the + * parent element. + */ + ielem->nodeLine, + attr->name, nsName, 0, + xmlNodeListGetString(attr->doc, attr->children, 1), 1); + if (ret == -1) { + VERROR_INT("xmlSchemaDocWalk", + "calling xmlSchemaValidatorPushAttribute()"); + goto internal_error; + } + attr = attr->next; + } while (attr); + } + /* + * Validate the element. + */ + ret = xmlSchemaValidateElem(vctxt); + if (ret != 0) { + if (ret == -1) { + VERROR_INT("xmlSchemaDocWalk", + "calling xmlSchemaValidateElem()"); + goto internal_error; + } + /* + * Don't stop validation; just skip the content + * of this element. + */ + goto leave_node; + } + if ((vctxt->skipDepth != -1) && + (vctxt->depth >= vctxt->skipDepth)) + goto leave_node; + } else if ((node->type == XML_TEXT_NODE) || + (node->type == XML_CDATA_SECTION_NODE)) { + /* + * Process character content. + */ + if ((ielem != NULL) && (ielem->flags & XML_SCHEMA_ELEM_INFO_EMPTY)) + ielem->flags ^= XML_SCHEMA_ELEM_INFO_EMPTY; + ret = xmlSchemaVPushText(vctxt, node->type, node->content, + -1, XML_SCHEMA_PUSH_TEXT_PERSIST, NULL); + if (ret < 0) { + VERROR_INT("xmlSchemaVDocWalk", + "calling xmlSchemaVPushText()"); + goto internal_error; + } + /* + * DOC VAL TODO: Should we skip further validation of the + * element content here? + */ + } else if ((node->type == XML_ENTITY_NODE) || + (node->type == XML_ENTITY_REF_NODE)) { + /* + * DOC VAL TODO: What to do with entities? + */ + VERROR_INT("xmlSchemaVDocWalk", + "there is at least one entity reference in the node-tree " + "currently being validated. Processing of entities with " + "this XML Schema processor is not supported (yet). Please " + "substitute entities before validation."); + goto internal_error; + } else { + goto leave_node; + /* + * DOC VAL TODO: XInclude nodes, etc. + */ + } + /* + * Walk the doc. + */ + if (node->children != NULL) { + node = node->children; + continue; + } +leave_node: + if (node->type == XML_ELEMENT_NODE) { + /* + * Leaving the scope of an element. + */ + if (node != vctxt->inode->node) { + VERROR_INT("xmlSchemaVDocWalk", + "element position mismatch"); + goto internal_error; + } + ret = xmlSchemaValidatorPopElem(vctxt); + if (ret != 0) { + if (ret < 0) { + VERROR_INT("xmlSchemaVDocWalk", + "calling xmlSchemaValidatorPopElem()"); + goto internal_error; + } + } + if (node == valRoot) + goto exit; + } +next_sibling: + if (node->next != NULL) + node = node->next; + else { + node = node->parent; + goto leave_node; + } + } + +exit: + return (ret); +internal_error: + return (-1); +} + +static int +xmlSchemaPreRun(xmlSchemaValidCtxtPtr vctxt) { + /* + * Some initialization. + */ + vctxt->err = 0; + vctxt->nberrors = 0; + vctxt->depth = -1; + vctxt->skipDepth = -1; + vctxt->xsiAssemble = 0; + vctxt->hasKeyrefs = 0; +#ifdef ENABLE_IDC_NODE_TABLES_TEST + vctxt->createIDCNodeTables = 1; +#else + vctxt->createIDCNodeTables = 0; +#endif + /* + * Create a schema + parser if necessary. + */ + if (vctxt->schema == NULL) { + xmlSchemaParserCtxtPtr pctxt; + + vctxt->xsiAssemble = 1; + /* + * If not schema was given then we will create a schema + * dynamically using XSI schema locations. + * + * Create the schema parser context. + */ + if ((vctxt->pctxt == NULL) && + (xmlSchemaCreatePCtxtOnVCtxt(vctxt) == -1)) + return (-1); + pctxt = vctxt->pctxt; + pctxt->xsiAssemble = 1; + /* + * Create the schema. + */ + vctxt->schema = xmlSchemaNewSchema(pctxt); + if (vctxt->schema == NULL) + return (-1); + /* + * Create the schema construction context. + */ + pctxt->constructor = xmlSchemaConstructionCtxtCreate(pctxt->dict); + if (pctxt->constructor == NULL) + return(-1); + pctxt->constructor->mainSchema = vctxt->schema; + /* + * Take ownership of the constructor to be able to free it. + */ + pctxt->ownsConstructor = 1; + } + /* + * Augment the IDC definitions for the main schema and all imported ones + * NOTE: main schema if the first in the imported list + */ + xmlHashScan(vctxt->schema->schemasImports,(xmlHashScanner)xmlSchemaAugmentImportedIDC, vctxt); + + return(0); +} + +static void +xmlSchemaPostRun(xmlSchemaValidCtxtPtr vctxt) { + if (vctxt->xsiAssemble) { + if (vctxt->schema != NULL) { + xmlSchemaFree(vctxt->schema); + vctxt->schema = NULL; + } + } + xmlSchemaClearValidCtxt(vctxt); +} + +static int +xmlSchemaVStart(xmlSchemaValidCtxtPtr vctxt) +{ + int ret = 0; + + if (xmlSchemaPreRun(vctxt) < 0) + return(-1); + + if (vctxt->doc != NULL) { + /* + * Tree validation. + */ + ret = xmlSchemaVDocWalk(vctxt); +#ifdef LIBXML_READER_ENABLED + } else if (vctxt->reader != NULL) { + /* + * XML Reader validation. + */ +#ifdef XML_SCHEMA_READER_ENABLED + ret = xmlSchemaVReaderWalk(vctxt); +#endif +#endif + } else if ((vctxt->sax != NULL) && (vctxt->parserCtxt != NULL)) { + /* + * SAX validation. + */ + ret = xmlParseDocument(vctxt->parserCtxt); + } else { + VERROR_INT("xmlSchemaVStart", + "no instance to validate"); + ret = -1; + } + + xmlSchemaPostRun(vctxt); + if (ret == 0) + ret = vctxt->err; + return (ret); +} + +/** + * xmlSchemaValidateOneElement: + * @ctxt: a schema validation context + * @elem: an element node + * + * Validate a branch of a tree, starting with the given @elem. + * + * Returns 0 if the element and its subtree is valid, a positive error + * code number otherwise and -1 in case of an internal or API error. + */ +int +xmlSchemaValidateOneElement(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem) +{ + if ((ctxt == NULL) || (elem == NULL) || (elem->type != XML_ELEMENT_NODE)) + return (-1); + + if (ctxt->schema == NULL) + return (-1); + + ctxt->doc = elem->doc; + ctxt->node = elem; + ctxt->validationRoot = elem; + return(xmlSchemaVStart(ctxt)); +} + +/** + * xmlSchemaValidateDoc: + * @ctxt: a schema validation context + * @doc: a parsed document tree + * + * Validate a document tree in memory. + * + * Returns 0 if the document is schemas valid, a positive error code + * number otherwise and -1 in case of internal or API error. + */ +int +xmlSchemaValidateDoc(xmlSchemaValidCtxtPtr ctxt, xmlDocPtr doc) +{ + if ((ctxt == NULL) || (doc == NULL)) + return (-1); + + ctxt->doc = doc; + ctxt->node = xmlDocGetRootElement(doc); + if (ctxt->node == NULL) { + xmlSchemaCustomErr(ACTXT_CAST ctxt, + XML_SCHEMAV_DOCUMENT_ELEMENT_MISSING, + (xmlNodePtr) doc, NULL, + "The document has no document element", NULL, NULL); + return (ctxt->err); + } + ctxt->validationRoot = ctxt->node; + return (xmlSchemaVStart(ctxt)); +} + + +/************************************************************************ + * * + * Function and data for SAX streaming API * + * * + ************************************************************************/ +typedef struct _xmlSchemaSplitSAXData xmlSchemaSplitSAXData; +typedef xmlSchemaSplitSAXData *xmlSchemaSplitSAXDataPtr; + +struct _xmlSchemaSplitSAXData { + xmlSAXHandlerPtr user_sax; + void *user_data; + xmlSchemaValidCtxtPtr ctxt; + xmlSAXHandlerPtr schemas_sax; +}; + +#define XML_SAX_PLUG_MAGIC 0xdc43ba21 + +struct _xmlSchemaSAXPlug { + unsigned int magic; + + /* the original callbacks informations */ + xmlSAXHandlerPtr *user_sax_ptr; + xmlSAXHandlerPtr user_sax; + void **user_data_ptr; + void *user_data; + + /* the block plugged back and validation informations */ + xmlSAXHandler schemas_sax; + xmlSchemaValidCtxtPtr ctxt; +}; + +/* All those functions just bounces to the user provided SAX handlers */ +static void +internalSubsetSplit(void *ctx, const xmlChar *name, + const xmlChar *ExternalID, const xmlChar *SystemID) +{ + xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx; + if ((ctxt != NULL) && (ctxt->user_sax != NULL) && + (ctxt->user_sax->internalSubset != NULL)) + ctxt->user_sax->internalSubset(ctxt->user_data, name, ExternalID, + SystemID); +} + +static int +isStandaloneSplit(void *ctx) +{ + xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx; + if ((ctxt != NULL) && (ctxt->user_sax != NULL) && + (ctxt->user_sax->isStandalone != NULL)) + return(ctxt->user_sax->isStandalone(ctxt->user_data)); + return(0); +} + +static int +hasInternalSubsetSplit(void *ctx) +{ + xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx; + if ((ctxt != NULL) && (ctxt->user_sax != NULL) && + (ctxt->user_sax->hasInternalSubset != NULL)) + return(ctxt->user_sax->hasInternalSubset(ctxt->user_data)); + return(0); +} + +static int +hasExternalSubsetSplit(void *ctx) +{ + xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx; + if ((ctxt != NULL) && (ctxt->user_sax != NULL) && + (ctxt->user_sax->hasExternalSubset != NULL)) + return(ctxt->user_sax->hasExternalSubset(ctxt->user_data)); + return(0); +} + +static void +externalSubsetSplit(void *ctx, const xmlChar *name, + const xmlChar *ExternalID, const xmlChar *SystemID) +{ + xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx; + if ((ctxt != NULL) && (ctxt->user_sax != NULL) && + (ctxt->user_sax->externalSubset != NULL)) + ctxt->user_sax->externalSubset(ctxt->user_data, name, ExternalID, + SystemID); +} + +static xmlParserInputPtr +resolveEntitySplit(void *ctx, const xmlChar *publicId, const xmlChar *systemId) +{ + xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx; + if ((ctxt != NULL) && (ctxt->user_sax != NULL) && + (ctxt->user_sax->resolveEntity != NULL)) + return(ctxt->user_sax->resolveEntity(ctxt->user_data, publicId, + systemId)); + return(NULL); +} + +static xmlEntityPtr +getEntitySplit(void *ctx, const xmlChar *name) +{ + xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx; + if ((ctxt != NULL) && (ctxt->user_sax != NULL) && + (ctxt->user_sax->getEntity != NULL)) + return(ctxt->user_sax->getEntity(ctxt->user_data, name)); + return(NULL); +} + +static xmlEntityPtr +getParameterEntitySplit(void *ctx, const xmlChar *name) +{ + xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx; + if ((ctxt != NULL) && (ctxt->user_sax != NULL) && + (ctxt->user_sax->getParameterEntity != NULL)) + return(ctxt->user_sax->getParameterEntity(ctxt->user_data, name)); + return(NULL); +} + + +static void +entityDeclSplit(void *ctx, const xmlChar *name, int type, + const xmlChar *publicId, const xmlChar *systemId, xmlChar *content) +{ + xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx; + if ((ctxt != NULL) && (ctxt->user_sax != NULL) && + (ctxt->user_sax->entityDecl != NULL)) + ctxt->user_sax->entityDecl(ctxt->user_data, name, type, publicId, + systemId, content); +} + +static void +attributeDeclSplit(void *ctx, const xmlChar * elem, + const xmlChar * name, int type, int def, + const xmlChar * defaultValue, xmlEnumerationPtr tree) +{ + xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx; + if ((ctxt != NULL) && (ctxt->user_sax != NULL) && + (ctxt->user_sax->attributeDecl != NULL)) { + ctxt->user_sax->attributeDecl(ctxt->user_data, elem, name, type, + def, defaultValue, tree); + } else { + xmlFreeEnumeration(tree); + } +} + +static void +elementDeclSplit(void *ctx, const xmlChar *name, int type, + xmlElementContentPtr content) +{ + xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx; + if ((ctxt != NULL) && (ctxt->user_sax != NULL) && + (ctxt->user_sax->elementDecl != NULL)) + ctxt->user_sax->elementDecl(ctxt->user_data, name, type, content); +} + +static void +notationDeclSplit(void *ctx, const xmlChar *name, + const xmlChar *publicId, const xmlChar *systemId) +{ + xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx; + if ((ctxt != NULL) && (ctxt->user_sax != NULL) && + (ctxt->user_sax->notationDecl != NULL)) + ctxt->user_sax->notationDecl(ctxt->user_data, name, publicId, + systemId); +} + +static void +unparsedEntityDeclSplit(void *ctx, const xmlChar *name, + const xmlChar *publicId, const xmlChar *systemId, + const xmlChar *notationName) +{ + xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx; + if ((ctxt != NULL) && (ctxt->user_sax != NULL) && + (ctxt->user_sax->unparsedEntityDecl != NULL)) + ctxt->user_sax->unparsedEntityDecl(ctxt->user_data, name, publicId, + systemId, notationName); +} + +static void +setDocumentLocatorSplit(void *ctx, xmlSAXLocatorPtr loc) +{ + xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx; + if ((ctxt != NULL) && (ctxt->user_sax != NULL) && + (ctxt->user_sax->setDocumentLocator != NULL)) + ctxt->user_sax->setDocumentLocator(ctxt->user_data, loc); +} + +static void +startDocumentSplit(void *ctx) +{ + xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx; + if ((ctxt != NULL) && (ctxt->user_sax != NULL) && + (ctxt->user_sax->startDocument != NULL)) + ctxt->user_sax->startDocument(ctxt->user_data); +} + +static void +endDocumentSplit(void *ctx) +{ + xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx; + if ((ctxt != NULL) && (ctxt->user_sax != NULL) && + (ctxt->user_sax->endDocument != NULL)) + ctxt->user_sax->endDocument(ctxt->user_data); +} + +static void +processingInstructionSplit(void *ctx, const xmlChar *target, + const xmlChar *data) +{ + xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx; + if ((ctxt != NULL) && (ctxt->user_sax != NULL) && + (ctxt->user_sax->processingInstruction != NULL)) + ctxt->user_sax->processingInstruction(ctxt->user_data, target, data); +} + +static void +commentSplit(void *ctx, const xmlChar *value) +{ + xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx; + if ((ctxt != NULL) && (ctxt->user_sax != NULL) && + (ctxt->user_sax->comment != NULL)) + ctxt->user_sax->comment(ctxt->user_data, value); +} + +/* + * Varargs error callbacks to the user application, harder ... + */ + +static void XMLCDECL +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 + } +} +static void XMLCDECL +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 + } +} +static void XMLCDECL +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 + } +} + +/* + * Those are function where both the user handler and the schemas handler + * need to be called. + */ +static void +charactersSplit(void *ctx, const xmlChar *ch, int len) +{ + xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx; + if (ctxt == NULL) + return; + if ((ctxt->user_sax != NULL) && (ctxt->user_sax->characters != NULL)) + ctxt->user_sax->characters(ctxt->user_data, ch, len); + if (ctxt->ctxt != NULL) + xmlSchemaSAXHandleText(ctxt->ctxt, ch, len); +} + +static void +ignorableWhitespaceSplit(void *ctx, const xmlChar *ch, int len) +{ + xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx; + if (ctxt == NULL) + return; + if ((ctxt->user_sax != NULL) && + (ctxt->user_sax->ignorableWhitespace != NULL)) + ctxt->user_sax->ignorableWhitespace(ctxt->user_data, ch, len); + if (ctxt->ctxt != NULL) + xmlSchemaSAXHandleText(ctxt->ctxt, ch, len); +} + +static void +cdataBlockSplit(void *ctx, const xmlChar *value, int len) +{ + xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx; + if (ctxt == NULL) + return; + if ((ctxt->user_sax != NULL) && + (ctxt->user_sax->cdataBlock != NULL)) + ctxt->user_sax->cdataBlock(ctxt->user_data, value, len); + if (ctxt->ctxt != NULL) + xmlSchemaSAXHandleCDataSection(ctxt->ctxt, value, len); +} + +static void +referenceSplit(void *ctx, const xmlChar *name) +{ + xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx; + if (ctxt == NULL) + return; + if ((ctxt != NULL) && (ctxt->user_sax != NULL) && + (ctxt->user_sax->reference != NULL)) + ctxt->user_sax->reference(ctxt->user_data, name); + if (ctxt->ctxt != NULL) + xmlSchemaSAXHandleReference(ctxt->user_data, name); +} + +static void +startElementNsSplit(void *ctx, const xmlChar * localname, + const xmlChar * prefix, const xmlChar * URI, + int nb_namespaces, const xmlChar ** namespaces, + int nb_attributes, int nb_defaulted, + const xmlChar ** attributes) { + xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx; + if (ctxt == NULL) + return; + if ((ctxt->user_sax != NULL) && + (ctxt->user_sax->startElementNs != NULL)) + ctxt->user_sax->startElementNs(ctxt->user_data, localname, prefix, + URI, nb_namespaces, namespaces, + nb_attributes, nb_defaulted, + attributes); + if (ctxt->ctxt != NULL) + xmlSchemaSAXHandleStartElementNs(ctxt->ctxt, localname, prefix, + URI, nb_namespaces, namespaces, + nb_attributes, nb_defaulted, + attributes); +} + +static void +endElementNsSplit(void *ctx, const xmlChar * localname, + const xmlChar * prefix, const xmlChar * URI) { + xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx; + if (ctxt == NULL) + return; + if ((ctxt->user_sax != NULL) && + (ctxt->user_sax->endElementNs != NULL)) + ctxt->user_sax->endElementNs(ctxt->user_data, localname, prefix, URI); + if (ctxt->ctxt != NULL) + xmlSchemaSAXHandleEndElementNs(ctxt->ctxt, localname, prefix, URI); +} + +/** + * xmlSchemaSAXPlug: + * @ctxt: a schema validation context + * @sax: a pointer to the original xmlSAXHandlerPtr + * @user_data: a pointer to the original SAX user data pointer + * + * Plug a SAX based validation layer in a SAX parsing event flow. + * The original @saxptr and @dataptr data are replaced by new pointers + * but the calls to the original will be maintained. + * + * Returns a pointer to a data structure needed to unplug the validation layer + * or NULL in case of errors. + */ +xmlSchemaSAXPlugPtr +xmlSchemaSAXPlug(xmlSchemaValidCtxtPtr ctxt, + xmlSAXHandlerPtr *sax, void **user_data) +{ + xmlSchemaSAXPlugPtr ret; + xmlSAXHandlerPtr old_sax; + + if ((ctxt == NULL) || (sax == NULL) || (user_data == NULL)) + return(NULL); + + /* + * We only allow to plug into SAX2 event streams + */ + old_sax = *sax; + if ((old_sax != NULL) && (old_sax->initialized != XML_SAX2_MAGIC)) + return(NULL); + if ((old_sax != NULL) && + (old_sax->startElementNs == NULL) && (old_sax->endElementNs == NULL) && + ((old_sax->startElement != NULL) || (old_sax->endElement != NULL))) + return(NULL); + + /* + * everything seems right allocate the local data needed for that layer + */ + ret = (xmlSchemaSAXPlugPtr) xmlMalloc(sizeof(xmlSchemaSAXPlugStruct)); + if (ret == NULL) { + return(NULL); + } + memset(ret, 0, sizeof(xmlSchemaSAXPlugStruct)); + ret->magic = XML_SAX_PLUG_MAGIC; + ret->schemas_sax.initialized = XML_SAX2_MAGIC; + ret->ctxt = ctxt; + ret->user_sax_ptr = sax; + ret->user_sax = old_sax; + if (old_sax == NULL) { + /* + * go direct, no need for the split block and functions. + */ + ret->schemas_sax.startElementNs = xmlSchemaSAXHandleStartElementNs; + ret->schemas_sax.endElementNs = xmlSchemaSAXHandleEndElementNs; + /* + * Note that we use the same text-function for both, to prevent + * the parser from testing for ignorable whitespace. + */ + ret->schemas_sax.ignorableWhitespace = xmlSchemaSAXHandleText; + ret->schemas_sax.characters = xmlSchemaSAXHandleText; + + ret->schemas_sax.cdataBlock = xmlSchemaSAXHandleCDataSection; + ret->schemas_sax.reference = xmlSchemaSAXHandleReference; + + ret->user_data = ctxt; + *user_data = ctxt; + } else { + /* + * for each callback unused by Schemas initialize it to the Split + * routine only if non NULL in the user block, this can speed up + * things at the SAX level. + */ + if (old_sax->internalSubset != NULL) + ret->schemas_sax.internalSubset = internalSubsetSplit; + if (old_sax->isStandalone != NULL) + ret->schemas_sax.isStandalone = isStandaloneSplit; + if (old_sax->hasInternalSubset != NULL) + ret->schemas_sax.hasInternalSubset = hasInternalSubsetSplit; + if (old_sax->hasExternalSubset != NULL) + ret->schemas_sax.hasExternalSubset = hasExternalSubsetSplit; + if (old_sax->resolveEntity != NULL) + ret->schemas_sax.resolveEntity = resolveEntitySplit; + if (old_sax->getEntity != NULL) + ret->schemas_sax.getEntity = getEntitySplit; + if (old_sax->entityDecl != NULL) + ret->schemas_sax.entityDecl = entityDeclSplit; + if (old_sax->notationDecl != NULL) + ret->schemas_sax.notationDecl = notationDeclSplit; + if (old_sax->attributeDecl != NULL) + ret->schemas_sax.attributeDecl = attributeDeclSplit; + if (old_sax->elementDecl != NULL) + ret->schemas_sax.elementDecl = elementDeclSplit; + if (old_sax->unparsedEntityDecl != NULL) + ret->schemas_sax.unparsedEntityDecl = unparsedEntityDeclSplit; + if (old_sax->setDocumentLocator != NULL) + ret->schemas_sax.setDocumentLocator = setDocumentLocatorSplit; + if (old_sax->startDocument != NULL) + ret->schemas_sax.startDocument = startDocumentSplit; + if (old_sax->endDocument != NULL) + ret->schemas_sax.endDocument = endDocumentSplit; + if (old_sax->processingInstruction != NULL) + ret->schemas_sax.processingInstruction = processingInstructionSplit; + if (old_sax->comment != NULL) + ret->schemas_sax.comment = commentSplit; + if (old_sax->warning != NULL) + ret->schemas_sax.warning = warningSplit; + if (old_sax->error != NULL) + ret->schemas_sax.error = errorSplit; + if (old_sax->fatalError != NULL) + ret->schemas_sax.fatalError = fatalErrorSplit; + if (old_sax->getParameterEntity != NULL) + ret->schemas_sax.getParameterEntity = getParameterEntitySplit; + if (old_sax->externalSubset != NULL) + ret->schemas_sax.externalSubset = externalSubsetSplit; + + /* + * the 6 schemas callback have to go to the splitter functions + * Note that we use the same text-function for ignorableWhitespace + * if possible, to prevent the parser from testing for ignorable + * whitespace. + */ + ret->schemas_sax.characters = charactersSplit; + if ((old_sax->ignorableWhitespace != NULL) && + (old_sax->ignorableWhitespace != old_sax->characters)) + ret->schemas_sax.ignorableWhitespace = ignorableWhitespaceSplit; + else + ret->schemas_sax.ignorableWhitespace = charactersSplit; + ret->schemas_sax.cdataBlock = cdataBlockSplit; + ret->schemas_sax.reference = referenceSplit; + ret->schemas_sax.startElementNs = startElementNsSplit; + ret->schemas_sax.endElementNs = endElementNsSplit; + + ret->user_data_ptr = user_data; + ret->user_data = *user_data; + *user_data = ret; + } + + /* + * plug the pointers back. + */ + *sax = &(ret->schemas_sax); + ctxt->sax = *sax; + ctxt->flags |= XML_SCHEMA_VALID_CTXT_FLAG_STREAM; + xmlSchemaPreRun(ctxt); + return(ret); +} + +/** + * xmlSchemaSAXUnplug: + * @plug: a data structure returned by xmlSchemaSAXPlug + * + * Unplug a SAX based validation layer in a SAX parsing event flow. + * The original pointers used in the call are restored. + * + * Returns 0 in case of success and -1 in case of failure. + */ +int +xmlSchemaSAXUnplug(xmlSchemaSAXPlugPtr plug) +{ + xmlSAXHandlerPtr *sax; + void **user_data; + + if ((plug == NULL) || (plug->magic != XML_SAX_PLUG_MAGIC)) + return(-1); + plug->magic = 0; + + xmlSchemaPostRun(plug->ctxt); + /* restore the data */ + sax = plug->user_sax_ptr; + *sax = plug->user_sax; + if (plug->user_sax != NULL) { + user_data = plug->user_data_ptr; + *user_data = plug->user_data; + } + + /* free and return */ + xmlFree(plug); + return(0); +} + +/** + * xmlSchemaValidateStream: + * @ctxt: a schema validation context + * @input: the input to use for reading the data + * @enc: an optional encoding information + * @sax: a SAX handler for the resulting events + * @user_data: the context to provide to the SAX handler. + * + * Validate an input based on a flow of SAX event from the parser + * and forward the events to the @sax handler with the provided @user_data + * the user provided @sax handler must be a SAX2 one. + * + * Returns 0 if the document is schemas valid, a positive error code + * number otherwise and -1 in case of internal or API error. + */ +int +xmlSchemaValidateStream(xmlSchemaValidCtxtPtr ctxt, + xmlParserInputBufferPtr input, xmlCharEncoding enc, + xmlSAXHandlerPtr sax, void *user_data) +{ + xmlSchemaSAXPlugPtr plug = NULL; + xmlSAXHandlerPtr old_sax = NULL; + xmlParserCtxtPtr pctxt = NULL; + xmlParserInputPtr inputStream = NULL; + int ret; + + if ((ctxt == NULL) || (input == NULL)) + return (-1); + + /* + * prepare the parser + */ + pctxt = xmlNewParserCtxt(); + if (pctxt == NULL) + return (-1); + old_sax = pctxt->sax; + pctxt->sax = sax; + pctxt->userData = user_data; +#if 0 + if (options) + xmlCtxtUseOptions(pctxt, options); +#endif + pctxt->linenumbers = 1; + + inputStream = xmlNewIOInputStream(pctxt, input, enc);; + if (inputStream == NULL) { + ret = -1; + goto done; + } + inputPush(pctxt, inputStream); + ctxt->parserCtxt = pctxt; + ctxt->input = input; + + /* + * Plug the validation and launch the parsing + */ + plug = xmlSchemaSAXPlug(ctxt, &(pctxt->sax), &(pctxt->userData)); + if (plug == NULL) { + ret = -1; + goto done; + } + ctxt->input = input; + ctxt->enc = enc; + ctxt->sax = pctxt->sax; + ctxt->flags |= XML_SCHEMA_VALID_CTXT_FLAG_STREAM; + ret = xmlSchemaVStart(ctxt); + + if ((ret == 0) && (! ctxt->parserCtxt->wellFormed)) { + ret = ctxt->parserCtxt->errNo; + if (ret == 0) + ret = 1; + } + +done: + ctxt->parserCtxt = NULL; + ctxt->sax = NULL; + ctxt->input = NULL; + if (plug != NULL) { + xmlSchemaSAXUnplug(plug); + } + /* cleanup */ + if (pctxt != NULL) { + pctxt->sax = old_sax; + xmlFreeParserCtxt(pctxt); + } + return (ret); +} + +/** + * xmlSchemaValidateFile: + * @ctxt: a schema validation context + * @filename: the URI of the instance + * @options: a future set of options, currently unused + * + * Do a schemas validation of the given resource, it will use the + * SAX streamable validation internally. + * + * Returns 0 if the document is valid, a positive error code + * number otherwise and -1 in case of an internal or API error. + */ +int +xmlSchemaValidateFile(xmlSchemaValidCtxtPtr ctxt, + const char * filename, + int options ATTRIBUTE_UNUSED) +{ + int ret; + xmlParserInputBufferPtr input; + + if ((ctxt == NULL) || (filename == NULL)) + return (-1); + + input = xmlParserInputBufferCreateFilename(filename, + XML_CHAR_ENCODING_NONE); + if (input == NULL) + return (-1); + ret = xmlSchemaValidateStream(ctxt, input, XML_CHAR_ENCODING_NONE, + NULL, NULL); + return (ret); +} + +/** + * xmlSchemaValidCtxtGetParserCtxt: + * @ctxt: a schema validation context + * + * allow access to the parser context of the schema validation context + * + * Returns the parser context of the schema validation context or NULL + * in case of error. + */ +xmlParserCtxtPtr +xmlSchemaValidCtxtGetParserCtxt(xmlSchemaValidCtxtPtr ctxt) +{ + if (ctxt == NULL) + return(NULL); + return (ctxt->parserCtxt); +} + +#define bottom_xmlschemas +#include "elfgcchack.h" +#endif /* LIBXML_SCHEMAS_ENABLED */ diff --git a/android/native/libxml2/xmlschemastypes.c b/android/native/libxml2/xmlschemastypes.c new file mode 100644 index 0000000000..834b2613ab --- /dev/null +++ b/android/native/libxml2/xmlschemastypes.c @@ -0,0 +1,6134 @@ +/* + * schemastypes.c : implementation of the XML Schema Datatypes + * definition and validity checking + * + * See Copyright for the status of this software. + * + * Daniel Veillard + */ + +#define IN_LIBXML +#include "libxml.h" + +#ifdef LIBXML_SCHEMAS_ENABLED + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifdef HAVE_MATH_H +#include +#endif +#ifdef HAVE_FLOAT_H +#include +#endif + +#define DEBUG + +#ifndef LIBXML_XPATH_ENABLED +extern double xmlXPathNAN; +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" + +#define IS_WSP_REPLACE_CH(c) ((((c) == 0x9) || ((c) == 0xa)) || \ + ((c) == 0xd)) + +#define IS_WSP_SPACE_CH(c) ((c) == 0x20) + +#define IS_WSP_BLANK_CH(c) IS_BLANK_CH(c) + +/* Date value */ +typedef struct _xmlSchemaValDate xmlSchemaValDate; +typedef xmlSchemaValDate *xmlSchemaValDatePtr; +struct _xmlSchemaValDate { + long year; + unsigned int mon :4; /* 1 <= mon <= 12 */ + unsigned int day :5; /* 1 <= day <= 31 */ + unsigned int hour :5; /* 0 <= hour <= 23 */ + unsigned int min :6; /* 0 <= min <= 59 */ + double sec; + unsigned int tz_flag :1; /* is tzo explicitely set? */ + signed int tzo :12; /* -1440 <= tzo <= 1440; + currently only -840 to +840 are needed */ +}; + +/* Duration value */ +typedef struct _xmlSchemaValDuration xmlSchemaValDuration; +typedef xmlSchemaValDuration *xmlSchemaValDurationPtr; +struct _xmlSchemaValDuration { + long mon; /* mon stores years also */ + long day; + double sec; /* sec stores min and hour also */ +}; + +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; +}; + +typedef struct _xmlSchemaValQName xmlSchemaValQName; +typedef xmlSchemaValQName *xmlSchemaValQNamePtr; +struct _xmlSchemaValQName { + xmlChar *name; + xmlChar *uri; +}; + +typedef struct _xmlSchemaValHex xmlSchemaValHex; +typedef xmlSchemaValHex *xmlSchemaValHexPtr; +struct _xmlSchemaValHex { + xmlChar *str; + unsigned int total; +}; + +typedef struct _xmlSchemaValBase64 xmlSchemaValBase64; +typedef xmlSchemaValBase64 *xmlSchemaValBase64Ptr; +struct _xmlSchemaValBase64 { + xmlChar *str; + unsigned int total; +}; + +struct _xmlSchemaVal { + xmlSchemaValType type; + struct _xmlSchemaVal *next; + union { + xmlSchemaValDecimal decimal; + xmlSchemaValDate date; + xmlSchemaValDuration dur; + xmlSchemaValQName qname; + xmlSchemaValHex hex; + xmlSchemaValBase64 base64; + float f; + double d; + int b; + xmlChar *str; + } value; +}; + +static int xmlSchemaTypesInitialized = 0; +static xmlHashTablePtr xmlSchemaTypesBank = NULL; + +/* + * Basic types + */ +static xmlSchemaTypePtr xmlSchemaTypeStringDef = NULL; +static xmlSchemaTypePtr xmlSchemaTypeAnyTypeDef = NULL; +static xmlSchemaTypePtr xmlSchemaTypeAnySimpleTypeDef = NULL; +static xmlSchemaTypePtr xmlSchemaTypeDecimalDef = NULL; +static xmlSchemaTypePtr xmlSchemaTypeDatetimeDef = NULL; +static xmlSchemaTypePtr xmlSchemaTypeDateDef = NULL; +static xmlSchemaTypePtr xmlSchemaTypeTimeDef = NULL; +static xmlSchemaTypePtr xmlSchemaTypeGYearDef = NULL; +static xmlSchemaTypePtr xmlSchemaTypeGYearMonthDef = NULL; +static xmlSchemaTypePtr xmlSchemaTypeGDayDef = NULL; +static xmlSchemaTypePtr xmlSchemaTypeGMonthDayDef = NULL; +static xmlSchemaTypePtr xmlSchemaTypeGMonthDef = NULL; +static xmlSchemaTypePtr xmlSchemaTypeDurationDef = NULL; +static xmlSchemaTypePtr xmlSchemaTypeFloatDef = NULL; +static xmlSchemaTypePtr xmlSchemaTypeBooleanDef = NULL; +static xmlSchemaTypePtr xmlSchemaTypeDoubleDef = NULL; +static xmlSchemaTypePtr xmlSchemaTypeHexBinaryDef = NULL; +static xmlSchemaTypePtr xmlSchemaTypeBase64BinaryDef = NULL; +static xmlSchemaTypePtr xmlSchemaTypeAnyURIDef = NULL; + +/* + * Derived types + */ +static xmlSchemaTypePtr xmlSchemaTypePositiveIntegerDef = NULL; +static xmlSchemaTypePtr xmlSchemaTypeNonPositiveIntegerDef = NULL; +static xmlSchemaTypePtr xmlSchemaTypeNegativeIntegerDef = NULL; +static xmlSchemaTypePtr xmlSchemaTypeNonNegativeIntegerDef = NULL; +static xmlSchemaTypePtr xmlSchemaTypeIntegerDef = NULL; +static xmlSchemaTypePtr xmlSchemaTypeLongDef = NULL; +static xmlSchemaTypePtr xmlSchemaTypeIntDef = NULL; +static xmlSchemaTypePtr xmlSchemaTypeShortDef = NULL; +static xmlSchemaTypePtr xmlSchemaTypeByteDef = NULL; +static xmlSchemaTypePtr xmlSchemaTypeUnsignedLongDef = NULL; +static xmlSchemaTypePtr xmlSchemaTypeUnsignedIntDef = NULL; +static xmlSchemaTypePtr xmlSchemaTypeUnsignedShortDef = NULL; +static xmlSchemaTypePtr xmlSchemaTypeUnsignedByteDef = NULL; +static xmlSchemaTypePtr xmlSchemaTypeNormStringDef = NULL; +static xmlSchemaTypePtr xmlSchemaTypeTokenDef = NULL; +static xmlSchemaTypePtr xmlSchemaTypeLanguageDef = NULL; +static xmlSchemaTypePtr xmlSchemaTypeNameDef = NULL; +static xmlSchemaTypePtr xmlSchemaTypeQNameDef = NULL; +static xmlSchemaTypePtr xmlSchemaTypeNCNameDef = NULL; +static xmlSchemaTypePtr xmlSchemaTypeIdDef = NULL; +static xmlSchemaTypePtr xmlSchemaTypeIdrefDef = NULL; +static xmlSchemaTypePtr xmlSchemaTypeIdrefsDef = NULL; +static xmlSchemaTypePtr xmlSchemaTypeEntityDef = NULL; +static xmlSchemaTypePtr xmlSchemaTypeEntitiesDef = NULL; +static xmlSchemaTypePtr xmlSchemaTypeNotationDef = NULL; +static xmlSchemaTypePtr xmlSchemaTypeNmtokenDef = NULL; +static xmlSchemaTypePtr xmlSchemaTypeNmtokensDef = NULL; + +/************************************************************************ + * * + * Datatype error handlers * + * * + ************************************************************************/ +/** + * xmlSchemaTypeErrMemory: + * @extra: extra informations + * + * Handle an out of memory condition + */ +static void +xmlSchemaTypeErrMemory(xmlNodePtr node, const char *extra) +{ + __xmlSimpleError(XML_FROM_DATATYPE, XML_ERR_NO_MEMORY, node, NULL, extra); +} + +/************************************************************************ + * * + * Base types support * + * * + ************************************************************************/ + +/** + * xmlSchemaNewValue: + * @type: the value type + * + * Allocate a new simple type value + * + * Returns a pointer to the new value or NULL in case of error + */ +static xmlSchemaValPtr +xmlSchemaNewValue(xmlSchemaValType type) { + xmlSchemaValPtr value; + + value = (xmlSchemaValPtr) xmlMalloc(sizeof(xmlSchemaVal)); + if (value == NULL) { + return(NULL); + } + memset(value, 0, sizeof(xmlSchemaVal)); + value->type = type; + return(value); +} + +static xmlSchemaFacetPtr +xmlSchemaNewMinLengthFacet(int value) +{ + xmlSchemaFacetPtr ret; + + ret = xmlSchemaNewFacet(); + if (ret == NULL) { + return(NULL); + } + ret->type = XML_SCHEMA_FACET_MINLENGTH; + ret->val = xmlSchemaNewValue(XML_SCHEMAS_NNINTEGER); + ret->val->value.decimal.lo = value; + return (ret); +} + +/* + * xmlSchemaInitBasicType: + * @name: the type name + * @type: the value type associated + * + * Initialize one primitive built-in type + */ +static xmlSchemaTypePtr +xmlSchemaInitBasicType(const char *name, xmlSchemaValType type, + xmlSchemaTypePtr baseType) { + xmlSchemaTypePtr ret; + + ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType)); + if (ret == NULL) { + xmlSchemaTypeErrMemory(NULL, "could not initialize basic types"); + return(NULL); + } + memset(ret, 0, sizeof(xmlSchemaType)); + ret->name = (const xmlChar *)name; + ret->targetNamespace = XML_SCHEMAS_NAMESPACE_NAME; + ret->type = XML_SCHEMA_TYPE_BASIC; + ret->baseType = baseType; + ret->contentType = XML_SCHEMA_CONTENT_BASIC; + /* + * Primitive types. + */ + switch (type) { + case XML_SCHEMAS_STRING: + case XML_SCHEMAS_DECIMAL: + case XML_SCHEMAS_DATE: + case XML_SCHEMAS_DATETIME: + case XML_SCHEMAS_TIME: + case XML_SCHEMAS_GYEAR: + case XML_SCHEMAS_GYEARMONTH: + case XML_SCHEMAS_GMONTH: + case XML_SCHEMAS_GMONTHDAY: + case XML_SCHEMAS_GDAY: + case XML_SCHEMAS_DURATION: + case XML_SCHEMAS_FLOAT: + case XML_SCHEMAS_DOUBLE: + case XML_SCHEMAS_BOOLEAN: + case XML_SCHEMAS_ANYURI: + case XML_SCHEMAS_HEXBINARY: + case XML_SCHEMAS_BASE64BINARY: + case XML_SCHEMAS_QNAME: + case XML_SCHEMAS_NOTATION: + ret->flags |= XML_SCHEMAS_TYPE_BUILTIN_PRIMITIVE; + break; + default: + break; + } + /* + * Set variety. + */ + switch (type) { + case XML_SCHEMAS_ANYTYPE: + case XML_SCHEMAS_ANYSIMPLETYPE: + break; + case XML_SCHEMAS_IDREFS: + case XML_SCHEMAS_NMTOKENS: + case XML_SCHEMAS_ENTITIES: + ret->flags |= XML_SCHEMAS_TYPE_VARIETY_LIST; + ret->facets = xmlSchemaNewMinLengthFacet(1); + ret->flags |= XML_SCHEMAS_TYPE_HAS_FACETS; + break; + default: + ret->flags |= XML_SCHEMAS_TYPE_VARIETY_ATOMIC; + break; + } + xmlHashAddEntry2(xmlSchemaTypesBank, ret->name, + XML_SCHEMAS_NAMESPACE_NAME, ret); + ret->builtInType = type; + return(ret); +} + +/* +* WARNING: Those type reside normally in xmlschemas.c but are +* redefined here locally in oder of being able to use them for xs:anyType- +* TODO: Remove those definition if we move the types to a header file. +* TODO: Always keep those structs up-to-date with the originals. +*/ +#define UNBOUNDED (1 << 30) + +typedef struct _xmlSchemaTreeItem xmlSchemaTreeItem; +typedef xmlSchemaTreeItem *xmlSchemaTreeItemPtr; +struct _xmlSchemaTreeItem { + xmlSchemaTypeType type; + xmlSchemaAnnotPtr annot; + xmlSchemaTreeItemPtr next; + xmlSchemaTreeItemPtr children; +}; + +typedef struct _xmlSchemaParticle xmlSchemaParticle; +typedef xmlSchemaParticle *xmlSchemaParticlePtr; +struct _xmlSchemaParticle { + xmlSchemaTypeType type; + xmlSchemaAnnotPtr annot; + xmlSchemaTreeItemPtr next; + xmlSchemaTreeItemPtr children; + int minOccurs; + int maxOccurs; + xmlNodePtr node; +}; + +typedef struct _xmlSchemaModelGroup xmlSchemaModelGroup; +typedef xmlSchemaModelGroup *xmlSchemaModelGroupPtr; +struct _xmlSchemaModelGroup { + xmlSchemaTypeType type; + xmlSchemaAnnotPtr annot; + xmlSchemaTreeItemPtr next; + xmlSchemaTreeItemPtr children; + xmlNodePtr node; +}; + +static xmlSchemaParticlePtr +xmlSchemaAddParticle(void) +{ + xmlSchemaParticlePtr ret = NULL; + + ret = (xmlSchemaParticlePtr) + xmlMalloc(sizeof(xmlSchemaParticle)); + if (ret == NULL) { + xmlSchemaTypeErrMemory(NULL, "allocating particle component"); + return (NULL); + } + memset(ret, 0, sizeof(xmlSchemaParticle)); + ret->type = XML_SCHEMA_TYPE_PARTICLE; + ret->minOccurs = 1; + ret->maxOccurs = 1; + return (ret); +} + +/* + * xmlSchemaInitTypes: + * + * Initialize the default XML Schemas type library + */ +void +xmlSchemaInitTypes(void) +{ + if (xmlSchemaTypesInitialized != 0) + return; + xmlSchemaTypesBank = xmlHashCreate(40); + + + /* + * 3.4.7 Built-in Complex Type Definition + */ + xmlSchemaTypeAnyTypeDef = xmlSchemaInitBasicType("anyType", + XML_SCHEMAS_ANYTYPE, + NULL); + xmlSchemaTypeAnyTypeDef->baseType = xmlSchemaTypeAnyTypeDef; + xmlSchemaTypeAnyTypeDef->contentType = XML_SCHEMA_CONTENT_MIXED; + /* + * Init the content type. + */ + xmlSchemaTypeAnyTypeDef->contentType = XML_SCHEMA_CONTENT_MIXED; + { + xmlSchemaParticlePtr particle; + xmlSchemaModelGroupPtr sequence; + xmlSchemaWildcardPtr wild; + /* First particle. */ + particle = xmlSchemaAddParticle(); + if (particle == NULL) + return; + xmlSchemaTypeAnyTypeDef->subtypes = (xmlSchemaTypePtr) particle; + /* Sequence model group. */ + sequence = (xmlSchemaModelGroupPtr) + xmlMalloc(sizeof(xmlSchemaModelGroup)); + if (sequence == NULL) { + xmlSchemaTypeErrMemory(NULL, "allocating model group component"); + return; + } + memset(sequence, 0, sizeof(xmlSchemaModelGroup)); + sequence->type = XML_SCHEMA_TYPE_SEQUENCE; + particle->children = (xmlSchemaTreeItemPtr) sequence; + /* Second particle. */ + particle = xmlSchemaAddParticle(); + if (particle == NULL) + return; + particle->minOccurs = 0; + particle->maxOccurs = UNBOUNDED; + sequence->children = (xmlSchemaTreeItemPtr) particle; + /* The wildcard */ + wild = (xmlSchemaWildcardPtr) xmlMalloc(sizeof(xmlSchemaWildcard)); + if (wild == NULL) { + xmlSchemaTypeErrMemory(NULL, "allocating wildcard component"); + return; + } + memset(wild, 0, sizeof(xmlSchemaWildcard)); + wild->type = XML_SCHEMA_TYPE_ANY; + wild->any = 1; + wild->processContents = XML_SCHEMAS_ANY_LAX; + particle->children = (xmlSchemaTreeItemPtr) wild; + /* + * Create the attribute wildcard. + */ + wild = (xmlSchemaWildcardPtr) xmlMalloc(sizeof(xmlSchemaWildcard)); + if (wild == NULL) { + xmlSchemaTypeErrMemory(NULL, "could not create an attribute " + "wildcard on anyType"); + return; + } + memset(wild, 0, sizeof(xmlSchemaWildcard)); + wild->any = 1; + wild->processContents = XML_SCHEMAS_ANY_LAX; + xmlSchemaTypeAnyTypeDef->attributeWildcard = wild; + } + xmlSchemaTypeAnySimpleTypeDef = xmlSchemaInitBasicType("anySimpleType", + XML_SCHEMAS_ANYSIMPLETYPE, + xmlSchemaTypeAnyTypeDef); + /* + * primitive datatypes + */ + xmlSchemaTypeStringDef = xmlSchemaInitBasicType("string", + XML_SCHEMAS_STRING, + xmlSchemaTypeAnySimpleTypeDef); + xmlSchemaTypeDecimalDef = xmlSchemaInitBasicType("decimal", + XML_SCHEMAS_DECIMAL, + xmlSchemaTypeAnySimpleTypeDef); + xmlSchemaTypeDateDef = xmlSchemaInitBasicType("date", + XML_SCHEMAS_DATE, + xmlSchemaTypeAnySimpleTypeDef); + xmlSchemaTypeDatetimeDef = xmlSchemaInitBasicType("dateTime", + XML_SCHEMAS_DATETIME, + xmlSchemaTypeAnySimpleTypeDef); + xmlSchemaTypeTimeDef = xmlSchemaInitBasicType("time", + XML_SCHEMAS_TIME, + xmlSchemaTypeAnySimpleTypeDef); + xmlSchemaTypeGYearDef = xmlSchemaInitBasicType("gYear", + XML_SCHEMAS_GYEAR, + xmlSchemaTypeAnySimpleTypeDef); + xmlSchemaTypeGYearMonthDef = xmlSchemaInitBasicType("gYearMonth", + XML_SCHEMAS_GYEARMONTH, + xmlSchemaTypeAnySimpleTypeDef); + xmlSchemaTypeGMonthDef = xmlSchemaInitBasicType("gMonth", + XML_SCHEMAS_GMONTH, + xmlSchemaTypeAnySimpleTypeDef); + xmlSchemaTypeGMonthDayDef = xmlSchemaInitBasicType("gMonthDay", + XML_SCHEMAS_GMONTHDAY, + xmlSchemaTypeAnySimpleTypeDef); + xmlSchemaTypeGDayDef = xmlSchemaInitBasicType("gDay", + XML_SCHEMAS_GDAY, + xmlSchemaTypeAnySimpleTypeDef); + xmlSchemaTypeDurationDef = xmlSchemaInitBasicType("duration", + XML_SCHEMAS_DURATION, + xmlSchemaTypeAnySimpleTypeDef); + xmlSchemaTypeFloatDef = xmlSchemaInitBasicType("float", + XML_SCHEMAS_FLOAT, + xmlSchemaTypeAnySimpleTypeDef); + xmlSchemaTypeDoubleDef = xmlSchemaInitBasicType("double", + XML_SCHEMAS_DOUBLE, + xmlSchemaTypeAnySimpleTypeDef); + xmlSchemaTypeBooleanDef = xmlSchemaInitBasicType("boolean", + XML_SCHEMAS_BOOLEAN, + xmlSchemaTypeAnySimpleTypeDef); + xmlSchemaTypeAnyURIDef = xmlSchemaInitBasicType("anyURI", + XML_SCHEMAS_ANYURI, + xmlSchemaTypeAnySimpleTypeDef); + xmlSchemaTypeHexBinaryDef = xmlSchemaInitBasicType("hexBinary", + XML_SCHEMAS_HEXBINARY, + xmlSchemaTypeAnySimpleTypeDef); + xmlSchemaTypeBase64BinaryDef + = xmlSchemaInitBasicType("base64Binary", XML_SCHEMAS_BASE64BINARY, + xmlSchemaTypeAnySimpleTypeDef); + xmlSchemaTypeNotationDef = xmlSchemaInitBasicType("NOTATION", + XML_SCHEMAS_NOTATION, + xmlSchemaTypeAnySimpleTypeDef); + xmlSchemaTypeQNameDef = xmlSchemaInitBasicType("QName", + XML_SCHEMAS_QNAME, + xmlSchemaTypeAnySimpleTypeDef); + + /* + * derived datatypes + */ + xmlSchemaTypeIntegerDef = xmlSchemaInitBasicType("integer", + XML_SCHEMAS_INTEGER, + xmlSchemaTypeDecimalDef); + xmlSchemaTypeNonPositiveIntegerDef = + xmlSchemaInitBasicType("nonPositiveInteger", + XML_SCHEMAS_NPINTEGER, + xmlSchemaTypeIntegerDef); + xmlSchemaTypeNegativeIntegerDef = + xmlSchemaInitBasicType("negativeInteger", XML_SCHEMAS_NINTEGER, + xmlSchemaTypeNonPositiveIntegerDef); + xmlSchemaTypeLongDef = + xmlSchemaInitBasicType("long", XML_SCHEMAS_LONG, + xmlSchemaTypeIntegerDef); + xmlSchemaTypeIntDef = xmlSchemaInitBasicType("int", XML_SCHEMAS_INT, + xmlSchemaTypeLongDef); + xmlSchemaTypeShortDef = xmlSchemaInitBasicType("short", + XML_SCHEMAS_SHORT, + xmlSchemaTypeIntDef); + xmlSchemaTypeByteDef = xmlSchemaInitBasicType("byte", + XML_SCHEMAS_BYTE, + xmlSchemaTypeShortDef); + xmlSchemaTypeNonNegativeIntegerDef = + xmlSchemaInitBasicType("nonNegativeInteger", + XML_SCHEMAS_NNINTEGER, + xmlSchemaTypeIntegerDef); + xmlSchemaTypeUnsignedLongDef = + xmlSchemaInitBasicType("unsignedLong", XML_SCHEMAS_ULONG, + xmlSchemaTypeNonNegativeIntegerDef); + xmlSchemaTypeUnsignedIntDef = + xmlSchemaInitBasicType("unsignedInt", XML_SCHEMAS_UINT, + xmlSchemaTypeUnsignedLongDef); + xmlSchemaTypeUnsignedShortDef = + xmlSchemaInitBasicType("unsignedShort", XML_SCHEMAS_USHORT, + xmlSchemaTypeUnsignedIntDef); + xmlSchemaTypeUnsignedByteDef = + xmlSchemaInitBasicType("unsignedByte", XML_SCHEMAS_UBYTE, + xmlSchemaTypeUnsignedShortDef); + xmlSchemaTypePositiveIntegerDef = + xmlSchemaInitBasicType("positiveInteger", XML_SCHEMAS_PINTEGER, + xmlSchemaTypeNonNegativeIntegerDef); + xmlSchemaTypeNormStringDef = xmlSchemaInitBasicType("normalizedString", + XML_SCHEMAS_NORMSTRING, + xmlSchemaTypeStringDef); + xmlSchemaTypeTokenDef = xmlSchemaInitBasicType("token", + XML_SCHEMAS_TOKEN, + xmlSchemaTypeNormStringDef); + xmlSchemaTypeLanguageDef = xmlSchemaInitBasicType("language", + XML_SCHEMAS_LANGUAGE, + xmlSchemaTypeTokenDef); + xmlSchemaTypeNameDef = xmlSchemaInitBasicType("Name", + XML_SCHEMAS_NAME, + xmlSchemaTypeTokenDef); + xmlSchemaTypeNmtokenDef = xmlSchemaInitBasicType("NMTOKEN", + XML_SCHEMAS_NMTOKEN, + xmlSchemaTypeTokenDef); + xmlSchemaTypeNCNameDef = xmlSchemaInitBasicType("NCName", + XML_SCHEMAS_NCNAME, + xmlSchemaTypeNameDef); + xmlSchemaTypeIdDef = xmlSchemaInitBasicType("ID", XML_SCHEMAS_ID, + xmlSchemaTypeNCNameDef); + xmlSchemaTypeIdrefDef = xmlSchemaInitBasicType("IDREF", + XML_SCHEMAS_IDREF, + xmlSchemaTypeNCNameDef); + xmlSchemaTypeEntityDef = xmlSchemaInitBasicType("ENTITY", + XML_SCHEMAS_ENTITY, + xmlSchemaTypeNCNameDef); + /* + * Derived list types. + */ + /* ENTITIES */ + xmlSchemaTypeEntitiesDef = xmlSchemaInitBasicType("ENTITIES", + XML_SCHEMAS_ENTITIES, + xmlSchemaTypeAnySimpleTypeDef); + xmlSchemaTypeEntitiesDef->subtypes = xmlSchemaTypeEntityDef; + /* IDREFS */ + xmlSchemaTypeIdrefsDef = xmlSchemaInitBasicType("IDREFS", + XML_SCHEMAS_IDREFS, + xmlSchemaTypeAnySimpleTypeDef); + xmlSchemaTypeIdrefsDef->subtypes = xmlSchemaTypeIdrefDef; + + /* NMTOKENS */ + xmlSchemaTypeNmtokensDef = xmlSchemaInitBasicType("NMTOKENS", + XML_SCHEMAS_NMTOKENS, + xmlSchemaTypeAnySimpleTypeDef); + xmlSchemaTypeNmtokensDef->subtypes = xmlSchemaTypeNmtokenDef; + + xmlSchemaTypesInitialized = 1; +} + +/** + * xmlSchemaCleanupTypes: + * + * Cleanup the default XML Schemas type library + */ +void +xmlSchemaCleanupTypes(void) { + if (xmlSchemaTypesInitialized == 0) + return; + /* + * Free xs:anyType. + */ + { + xmlSchemaParticlePtr particle; + /* Attribute wildcard. */ + xmlSchemaFreeWildcard(xmlSchemaTypeAnyTypeDef->attributeWildcard); + /* Content type. */ + particle = (xmlSchemaParticlePtr) xmlSchemaTypeAnyTypeDef->subtypes; + /* Wildcard. */ + xmlSchemaFreeWildcard((xmlSchemaWildcardPtr) + particle->children->children->children); + xmlFree((xmlSchemaParticlePtr) particle->children->children); + /* Sequence model group. */ + xmlFree((xmlSchemaModelGroupPtr) particle->children); + xmlFree((xmlSchemaParticlePtr) particle); + xmlSchemaTypeAnyTypeDef->subtypes = NULL; + } + xmlHashFree(xmlSchemaTypesBank, (xmlHashDeallocator) xmlSchemaFreeType); + xmlSchemaTypesInitialized = 0; +} + +/** + * xmlSchemaIsBuiltInTypeFacet: + * @type: the built-in type + * @facetType: the facet type + * + * Evaluates if a specific facet can be + * used in conjunction with a type. + * + * Returns 1 if the facet can be used with the given built-in type, + * 0 otherwise and -1 in case the type is not a built-in type. + */ +int +xmlSchemaIsBuiltInTypeFacet(xmlSchemaTypePtr type, int facetType) +{ + if (type == NULL) + return (-1); + if (type->type != XML_SCHEMA_TYPE_BASIC) + return (-1); + switch (type->builtInType) { + case XML_SCHEMAS_BOOLEAN: + if ((facetType == XML_SCHEMA_FACET_PATTERN) || + (facetType == XML_SCHEMA_FACET_WHITESPACE)) + return (1); + else + return (0); + case XML_SCHEMAS_STRING: + case XML_SCHEMAS_NOTATION: + case XML_SCHEMAS_QNAME: + case XML_SCHEMAS_ANYURI: + case XML_SCHEMAS_BASE64BINARY: + case XML_SCHEMAS_HEXBINARY: + if ((facetType == XML_SCHEMA_FACET_LENGTH) || + (facetType == XML_SCHEMA_FACET_MINLENGTH) || + (facetType == XML_SCHEMA_FACET_MAXLENGTH) || + (facetType == XML_SCHEMA_FACET_PATTERN) || + (facetType == XML_SCHEMA_FACET_ENUMERATION) || + (facetType == XML_SCHEMA_FACET_WHITESPACE)) + return (1); + else + return (0); + case XML_SCHEMAS_DECIMAL: + if ((facetType == XML_SCHEMA_FACET_TOTALDIGITS) || + (facetType == XML_SCHEMA_FACET_FRACTIONDIGITS) || + (facetType == XML_SCHEMA_FACET_PATTERN) || + (facetType == XML_SCHEMA_FACET_WHITESPACE) || + (facetType == XML_SCHEMA_FACET_ENUMERATION) || + (facetType == XML_SCHEMA_FACET_MAXINCLUSIVE) || + (facetType == XML_SCHEMA_FACET_MAXEXCLUSIVE) || + (facetType == XML_SCHEMA_FACET_MININCLUSIVE) || + (facetType == XML_SCHEMA_FACET_MINEXCLUSIVE)) + return (1); + else + return (0); + case XML_SCHEMAS_TIME: + case XML_SCHEMAS_GDAY: + case XML_SCHEMAS_GMONTH: + case XML_SCHEMAS_GMONTHDAY: + case XML_SCHEMAS_GYEAR: + case XML_SCHEMAS_GYEARMONTH: + case XML_SCHEMAS_DATE: + case XML_SCHEMAS_DATETIME: + case XML_SCHEMAS_DURATION: + case XML_SCHEMAS_FLOAT: + case XML_SCHEMAS_DOUBLE: + if ((facetType == XML_SCHEMA_FACET_PATTERN) || + (facetType == XML_SCHEMA_FACET_ENUMERATION) || + (facetType == XML_SCHEMA_FACET_WHITESPACE) || + (facetType == XML_SCHEMA_FACET_MAXINCLUSIVE) || + (facetType == XML_SCHEMA_FACET_MAXEXCLUSIVE) || + (facetType == XML_SCHEMA_FACET_MININCLUSIVE) || + (facetType == XML_SCHEMA_FACET_MINEXCLUSIVE)) + return (1); + else + return (0); + default: + break; + } + return (0); +} + +/** + * xmlSchemaGetBuiltInType: + * @type: the type of the built in type + * + * Gives you the type struct for a built-in + * type by its type id. + * + * Returns the type if found, NULL otherwise. + */ +xmlSchemaTypePtr +xmlSchemaGetBuiltInType(xmlSchemaValType type) +{ + if (xmlSchemaTypesInitialized == 0) + xmlSchemaInitTypes(); + switch (type) { + + case XML_SCHEMAS_ANYSIMPLETYPE: + return (xmlSchemaTypeAnySimpleTypeDef); + case XML_SCHEMAS_STRING: + return (xmlSchemaTypeStringDef); + case XML_SCHEMAS_NORMSTRING: + return (xmlSchemaTypeNormStringDef); + case XML_SCHEMAS_DECIMAL: + return (xmlSchemaTypeDecimalDef); + case XML_SCHEMAS_TIME: + return (xmlSchemaTypeTimeDef); + case XML_SCHEMAS_GDAY: + return (xmlSchemaTypeGDayDef); + case XML_SCHEMAS_GMONTH: + return (xmlSchemaTypeGMonthDef); + case XML_SCHEMAS_GMONTHDAY: + return (xmlSchemaTypeGMonthDayDef); + case XML_SCHEMAS_GYEAR: + return (xmlSchemaTypeGYearDef); + case XML_SCHEMAS_GYEARMONTH: + return (xmlSchemaTypeGYearMonthDef); + case XML_SCHEMAS_DATE: + return (xmlSchemaTypeDateDef); + case XML_SCHEMAS_DATETIME: + return (xmlSchemaTypeDatetimeDef); + case XML_SCHEMAS_DURATION: + return (xmlSchemaTypeDurationDef); + case XML_SCHEMAS_FLOAT: + return (xmlSchemaTypeFloatDef); + case XML_SCHEMAS_DOUBLE: + return (xmlSchemaTypeDoubleDef); + case XML_SCHEMAS_BOOLEAN: + return (xmlSchemaTypeBooleanDef); + case XML_SCHEMAS_TOKEN: + return (xmlSchemaTypeTokenDef); + case XML_SCHEMAS_LANGUAGE: + return (xmlSchemaTypeLanguageDef); + case XML_SCHEMAS_NMTOKEN: + return (xmlSchemaTypeNmtokenDef); + case XML_SCHEMAS_NMTOKENS: + return (xmlSchemaTypeNmtokensDef); + case XML_SCHEMAS_NAME: + return (xmlSchemaTypeNameDef); + case XML_SCHEMAS_QNAME: + return (xmlSchemaTypeQNameDef); + case XML_SCHEMAS_NCNAME: + return (xmlSchemaTypeNCNameDef); + case XML_SCHEMAS_ID: + return (xmlSchemaTypeIdDef); + case XML_SCHEMAS_IDREF: + return (xmlSchemaTypeIdrefDef); + case XML_SCHEMAS_IDREFS: + return (xmlSchemaTypeIdrefsDef); + case XML_SCHEMAS_ENTITY: + return (xmlSchemaTypeEntityDef); + case XML_SCHEMAS_ENTITIES: + return (xmlSchemaTypeEntitiesDef); + case XML_SCHEMAS_NOTATION: + return (xmlSchemaTypeNotationDef); + case XML_SCHEMAS_ANYURI: + return (xmlSchemaTypeAnyURIDef); + case XML_SCHEMAS_INTEGER: + return (xmlSchemaTypeIntegerDef); + case XML_SCHEMAS_NPINTEGER: + return (xmlSchemaTypeNonPositiveIntegerDef); + case XML_SCHEMAS_NINTEGER: + return (xmlSchemaTypeNegativeIntegerDef); + case XML_SCHEMAS_NNINTEGER: + return (xmlSchemaTypeNonNegativeIntegerDef); + case XML_SCHEMAS_PINTEGER: + return (xmlSchemaTypePositiveIntegerDef); + case XML_SCHEMAS_INT: + return (xmlSchemaTypeIntDef); + case XML_SCHEMAS_UINT: + return (xmlSchemaTypeUnsignedIntDef); + case XML_SCHEMAS_LONG: + return (xmlSchemaTypeLongDef); + case XML_SCHEMAS_ULONG: + return (xmlSchemaTypeUnsignedLongDef); + case XML_SCHEMAS_SHORT: + return (xmlSchemaTypeShortDef); + case XML_SCHEMAS_USHORT: + return (xmlSchemaTypeUnsignedShortDef); + case XML_SCHEMAS_BYTE: + return (xmlSchemaTypeByteDef); + case XML_SCHEMAS_UBYTE: + return (xmlSchemaTypeUnsignedByteDef); + case XML_SCHEMAS_HEXBINARY: + return (xmlSchemaTypeHexBinaryDef); + case XML_SCHEMAS_BASE64BINARY: + return (xmlSchemaTypeBase64BinaryDef); + case XML_SCHEMAS_ANYTYPE: + return (xmlSchemaTypeAnyTypeDef); + default: + return (NULL); + } +} + +/** + * xmlSchemaValueAppend: + * @prev: the value + * @cur: the value to be appended + * + * Appends a next sibling to a list of computed values. + * + * Returns 0 if succeeded and -1 on API errors. + */ +int +xmlSchemaValueAppend(xmlSchemaValPtr prev, xmlSchemaValPtr cur) { + + if ((prev == NULL) || (cur == NULL)) + return (-1); + prev->next = cur; + return (0); +} + +/** + * xmlSchemaValueGetNext: + * @cur: the value + * + * Accessor for the next sibling of a list of computed values. + * + * Returns the next value or NULL if there was none, or on + * API errors. + */ +xmlSchemaValPtr +xmlSchemaValueGetNext(xmlSchemaValPtr cur) { + + if (cur == NULL) + return (NULL); + return (cur->next); +} + +/** + * xmlSchemaValueGetAsString: + * @val: the value + * + * Accessor for the string value of a computed value. + * + * Returns the string value or NULL if there was none, or on + * API errors. + */ +const xmlChar * +xmlSchemaValueGetAsString(xmlSchemaValPtr val) +{ + if (val == NULL) + return (NULL); + switch (val->type) { + case XML_SCHEMAS_STRING: + case XML_SCHEMAS_NORMSTRING: + case XML_SCHEMAS_ANYSIMPLETYPE: + case XML_SCHEMAS_TOKEN: + case XML_SCHEMAS_LANGUAGE: + case XML_SCHEMAS_NMTOKEN: + case XML_SCHEMAS_NAME: + case XML_SCHEMAS_NCNAME: + case XML_SCHEMAS_ID: + case XML_SCHEMAS_IDREF: + case XML_SCHEMAS_ENTITY: + case XML_SCHEMAS_ANYURI: + return (BAD_CAST val->value.str); + default: + break; + } + return (NULL); +} + +/** + * xmlSchemaValueGetAsBoolean: + * @val: the value + * + * Accessor for the boolean value of a computed value. + * + * Returns 1 if true and 0 if false, or in case of an error. Hmm. + */ +int +xmlSchemaValueGetAsBoolean(xmlSchemaValPtr val) +{ + if ((val == NULL) || (val->type != XML_SCHEMAS_BOOLEAN)) + return (0); + return (val->value.b); +} + +/** + * xmlSchemaNewStringValue: + * @type: the value type + * @value: the value + * + * Allocate a new simple type value. The type can be + * of XML_SCHEMAS_STRING. + * WARNING: This one is intended to be expanded for other + * string based types. We need this for anySimpleType as well. + * The given value is consumed and freed with the struct. + * + * Returns a pointer to the new value or NULL in case of error + */ +xmlSchemaValPtr +xmlSchemaNewStringValue(xmlSchemaValType type, + const xmlChar *value) +{ + xmlSchemaValPtr val; + + if (type != XML_SCHEMAS_STRING) + return(NULL); + val = (xmlSchemaValPtr) xmlMalloc(sizeof(xmlSchemaVal)); + if (val == NULL) { + return(NULL); + } + memset(val, 0, sizeof(xmlSchemaVal)); + val->type = type; + val->value.str = (xmlChar *) value; + return(val); +} + +/** + * xmlSchemaNewNOTATIONValue: + * @name: the notation name + * @ns: the notation namespace name or NULL + * + * Allocate a new NOTATION value. + * The given values are consumed and freed with the struct. + * + * Returns a pointer to the new value or NULL in case of error + */ +xmlSchemaValPtr +xmlSchemaNewNOTATIONValue(const xmlChar *name, + const xmlChar *ns) +{ + xmlSchemaValPtr val; + + val = xmlSchemaNewValue(XML_SCHEMAS_NOTATION); + if (val == NULL) + return (NULL); + + val->value.qname.name = (xmlChar *)name; + if (ns != NULL) + val->value.qname.uri = (xmlChar *)ns; + return(val); +} + +/** + * xmlSchemaNewQNameValue: + * @namespaceName: the namespace name + * @localName: the local name + * + * Allocate a new QName value. + * The given values are consumed and freed with the struct. + * + * Returns a pointer to the new value or NULL in case of an error. + */ +xmlSchemaValPtr +xmlSchemaNewQNameValue(const xmlChar *namespaceName, + const xmlChar *localName) +{ + xmlSchemaValPtr val; + + val = xmlSchemaNewValue(XML_SCHEMAS_QNAME); + if (val == NULL) + return (NULL); + + val->value.qname.name = (xmlChar *) localName; + val->value.qname.uri = (xmlChar *) namespaceName; + return(val); +} + +/** + * xmlSchemaFreeValue: + * @value: the value to free + * + * Cleanup the default XML Schemas type library + */ +void +xmlSchemaFreeValue(xmlSchemaValPtr value) { + xmlSchemaValPtr prev; + + while (value != NULL) { + switch (value->type) { + case XML_SCHEMAS_STRING: + case XML_SCHEMAS_NORMSTRING: + case XML_SCHEMAS_TOKEN: + case XML_SCHEMAS_LANGUAGE: + case XML_SCHEMAS_NMTOKEN: + case XML_SCHEMAS_NMTOKENS: + case XML_SCHEMAS_NAME: + case XML_SCHEMAS_NCNAME: + case XML_SCHEMAS_ID: + case XML_SCHEMAS_IDREF: + case XML_SCHEMAS_IDREFS: + case XML_SCHEMAS_ENTITY: + case XML_SCHEMAS_ENTITIES: + case XML_SCHEMAS_ANYURI: + case XML_SCHEMAS_ANYSIMPLETYPE: + if (value->value.str != NULL) + xmlFree(value->value.str); + break; + case XML_SCHEMAS_NOTATION: + case XML_SCHEMAS_QNAME: + if (value->value.qname.uri != NULL) + xmlFree(value->value.qname.uri); + if (value->value.qname.name != NULL) + xmlFree(value->value.qname.name); + break; + case XML_SCHEMAS_HEXBINARY: + if (value->value.hex.str != NULL) + xmlFree(value->value.hex.str); + break; + case XML_SCHEMAS_BASE64BINARY: + if (value->value.base64.str != NULL) + xmlFree(value->value.base64.str); + break; + default: + break; + } + prev = value; + value = value->next; + xmlFree(prev); + } +} + +/** + * xmlSchemaGetPredefinedType: + * @name: the type name + * @ns: the URI of the namespace usually "http://www.w3.org/2001/XMLSchema" + * + * Lookup a type in the default XML Schemas type library + * + * Returns the type if found, NULL otherwise + */ +xmlSchemaTypePtr +xmlSchemaGetPredefinedType(const xmlChar *name, const xmlChar *ns) { + if (xmlSchemaTypesInitialized == 0) + xmlSchemaInitTypes(); + if (name == NULL) + return(NULL); + return((xmlSchemaTypePtr) xmlHashLookup2(xmlSchemaTypesBank, name, ns)); +} + +/** + * xmlSchemaGetBuiltInListSimpleTypeItemType: + * @type: the built-in simple type. + * + * Lookup function + * + * Returns the item type of @type as defined by the built-in datatype + * hierarchy of XML Schema Part 2: Datatypes, or NULL in case of an error. + */ +xmlSchemaTypePtr +xmlSchemaGetBuiltInListSimpleTypeItemType(xmlSchemaTypePtr type) +{ + if ((type == NULL) || (type->type != XML_SCHEMA_TYPE_BASIC)) + return (NULL); + switch (type->builtInType) { + case XML_SCHEMAS_NMTOKENS: + return (xmlSchemaTypeNmtokenDef ); + case XML_SCHEMAS_IDREFS: + return (xmlSchemaTypeIdrefDef); + case XML_SCHEMAS_ENTITIES: + return (xmlSchemaTypeEntityDef); + default: + return (NULL); + } +} + +/**************************************************************** + * * + * Convenience macros and functions * + * * + ****************************************************************/ + +#define IS_TZO_CHAR(c) \ + ((c == 0) || (c == 'Z') || (c == '+') || (c == '-')) + +#define VALID_YEAR(yr) (yr != 0) +#define VALID_MONTH(mon) ((mon >= 1) && (mon <= 12)) +/* VALID_DAY should only be used when month is unknown */ +#define VALID_DAY(day) ((day >= 1) && (day <= 31)) +#define VALID_HOUR(hr) ((hr >= 0) && (hr <= 23)) +#define VALID_MIN(min) ((min >= 0) && (min <= 59)) +#define VALID_SEC(sec) ((sec >= 0) && (sec < 60)) +#define VALID_TZO(tzo) ((tzo > -840) && (tzo < 840)) +#define IS_LEAP(y) \ + (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0)) + +static const unsigned int daysInMonth[12] = + { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; +static const unsigned int daysInMonthLeap[12] = + { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + +#define MAX_DAYINMONTH(yr,mon) \ + (IS_LEAP(yr) ? daysInMonthLeap[mon - 1] : daysInMonth[mon - 1]) + +#define VALID_MDAY(dt) \ + (IS_LEAP(dt->year) ? \ + (dt->day <= daysInMonthLeap[dt->mon - 1]) : \ + (dt->day <= daysInMonth[dt->mon - 1])) + +#define VALID_DATE(dt) \ + (VALID_YEAR(dt->year) && VALID_MONTH(dt->mon) && VALID_MDAY(dt)) + +#define VALID_TIME(dt) \ + (VALID_HOUR(dt->hour) && VALID_MIN(dt->min) && \ + VALID_SEC(dt->sec) && VALID_TZO(dt->tzo)) + +#define VALID_DATETIME(dt) \ + (VALID_DATE(dt) && VALID_TIME(dt)) + +#define SECS_PER_MIN (60) +#define SECS_PER_HOUR (60 * SECS_PER_MIN) +#define SECS_PER_DAY (24 * SECS_PER_HOUR) + +static const long dayInYearByMonth[12] = + { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; +static const long dayInLeapYearByMonth[12] = + { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 }; + +#define DAY_IN_YEAR(day, month, year) \ + ((IS_LEAP(year) ? \ + dayInLeapYearByMonth[month - 1] : \ + dayInYearByMonth[month - 1]) + day) + +#ifdef DEBUG +#define DEBUG_DATE(dt) \ + xmlGenericError(xmlGenericErrorContext, \ + "type=%o %04ld-%02u-%02uT%02u:%02u:%03f", \ + dt->type,dt->value.date.year,dt->value.date.mon, \ + dt->value.date.day,dt->value.date.hour,dt->value.date.min, \ + dt->value.date.sec); \ + if (dt->value.date.tz_flag) \ + if (dt->value.date.tzo != 0) \ + xmlGenericError(xmlGenericErrorContext, \ + "%+05d\n",dt->value.date.tzo); \ + else \ + xmlGenericError(xmlGenericErrorContext, "Z\n"); \ + else \ + xmlGenericError(xmlGenericErrorContext,"\n") +#else +#define DEBUG_DATE(dt) +#endif + +/** + * _xmlSchemaParseGYear: + * @dt: pointer to a date structure + * @str: pointer to the string to analyze + * + * Parses a xs:gYear without time zone and fills in the appropriate + * field of the @dt structure. @str is updated to point just after the + * xs:gYear. It is supposed that @dt->year is big enough to contain + * the year. + * + * Returns 0 or the error code + */ +static int +_xmlSchemaParseGYear (xmlSchemaValDatePtr dt, const xmlChar **str) { + const xmlChar *cur = *str, *firstChar; + int isneg = 0, digcnt = 0; + + if (((*cur < '0') || (*cur > '9')) && + (*cur != '-') && (*cur != '+')) + return -1; + + if (*cur == '-') { + isneg = 1; + cur++; + } + + firstChar = cur; + + while ((*cur >= '0') && (*cur <= '9')) { + dt->year = dt->year * 10 + (*cur - '0'); + cur++; + digcnt++; + } + + /* year must be at least 4 digits (CCYY); over 4 + * digits cannot have a leading zero. */ + if ((digcnt < 4) || ((digcnt > 4) && (*firstChar == '0'))) + return 1; + + if (isneg) + dt->year = - dt->year; + + if (!VALID_YEAR(dt->year)) + return 2; + + *str = cur; + return 0; +} + +/** + * PARSE_2_DIGITS: + * @num: the integer to fill in + * @cur: an #xmlChar * + * @invalid: an integer + * + * Parses a 2-digits integer and updates @num with the value. @cur is + * updated to point just after the integer. + * In case of error, @invalid is set to %TRUE, values of @num and + * @cur are undefined. + */ +#define PARSE_2_DIGITS(num, cur, invalid) \ + if ((cur[0] < '0') || (cur[0] > '9') || \ + (cur[1] < '0') || (cur[1] > '9')) \ + invalid = 1; \ + else \ + num = (cur[0] - '0') * 10 + (cur[1] - '0'); \ + cur += 2; + +/** + * PARSE_FLOAT: + * @num: the double to fill in + * @cur: an #xmlChar * + * @invalid: an integer + * + * Parses a float and updates @num with the value. @cur is + * updated to point just after the float. The float must have a + * 2-digits integer part and may or may not have a decimal part. + * In case of error, @invalid is set to %TRUE, values of @num and + * @cur are undefined. + */ +#define PARSE_FLOAT(num, cur, invalid) \ + PARSE_2_DIGITS(num, cur, invalid); \ + if (!invalid && (*cur == '.')) { \ + double mult = 1; \ + cur++; \ + if ((*cur < '0') || (*cur > '9')) \ + invalid = 1; \ + while ((*cur >= '0') && (*cur <= '9')) { \ + mult /= 10; \ + num += (*cur - '0') * mult; \ + cur++; \ + } \ + } + +/** + * _xmlSchemaParseGMonth: + * @dt: pointer to a date structure + * @str: pointer to the string to analyze + * + * Parses a xs:gMonth without time zone and fills in the appropriate + * field of the @dt structure. @str is updated to point just after the + * xs:gMonth. + * + * Returns 0 or the error code + */ +static int +_xmlSchemaParseGMonth (xmlSchemaValDatePtr dt, const xmlChar **str) { + const xmlChar *cur = *str; + int ret = 0; + unsigned int value = 0; + + PARSE_2_DIGITS(value, cur, ret); + if (ret != 0) + return ret; + + if (!VALID_MONTH(value)) + return 2; + + dt->mon = value; + + *str = cur; + return 0; +} + +/** + * _xmlSchemaParseGDay: + * @dt: pointer to a date structure + * @str: pointer to the string to analyze + * + * Parses a xs:gDay without time zone and fills in the appropriate + * field of the @dt structure. @str is updated to point just after the + * xs:gDay. + * + * Returns 0 or the error code + */ +static int +_xmlSchemaParseGDay (xmlSchemaValDatePtr dt, const xmlChar **str) { + const xmlChar *cur = *str; + int ret = 0; + unsigned int value = 0; + + PARSE_2_DIGITS(value, cur, ret); + if (ret != 0) + return ret; + + if (!VALID_DAY(value)) + return 2; + + dt->day = value; + *str = cur; + return 0; +} + +/** + * _xmlSchemaParseTime: + * @dt: pointer to a date structure + * @str: pointer to the string to analyze + * + * Parses a xs:time without time zone and fills in the appropriate + * fields of the @dt structure. @str is updated to point just after the + * xs:time. + * In case of error, values of @dt fields are undefined. + * + * Returns 0 or the error code + */ +static int +_xmlSchemaParseTime (xmlSchemaValDatePtr dt, const xmlChar **str) { + const xmlChar *cur = *str; + int ret = 0; + int value = 0; + + PARSE_2_DIGITS(value, cur, ret); + if (ret != 0) + return ret; + if (*cur != ':') + return 1; + if (!VALID_HOUR(value)) + return 2; + cur++; + + /* the ':' insures this string is xs:time */ + dt->hour = value; + + PARSE_2_DIGITS(value, cur, ret); + if (ret != 0) + return ret; + if (!VALID_MIN(value)) + return 2; + dt->min = value; + + if (*cur != ':') + return 1; + cur++; + + PARSE_FLOAT(dt->sec, cur, ret); + if (ret != 0) + return ret; + + if ((!VALID_SEC(dt->sec)) || (!VALID_TZO(dt->tzo))) + return 2; + + *str = cur; + return 0; +} + +/** + * _xmlSchemaParseTimeZone: + * @dt: pointer to a date structure + * @str: pointer to the string to analyze + * + * Parses a time zone without time zone and fills in the appropriate + * field of the @dt structure. @str is updated to point just after the + * time zone. + * + * Returns 0 or the error code + */ +static int +_xmlSchemaParseTimeZone (xmlSchemaValDatePtr dt, const xmlChar **str) { + const xmlChar *cur; + int ret = 0; + + if (str == NULL) + return -1; + cur = *str; + + switch (*cur) { + case 0: + dt->tz_flag = 0; + dt->tzo = 0; + break; + + case 'Z': + dt->tz_flag = 1; + dt->tzo = 0; + cur++; + break; + + case '+': + case '-': { + int isneg = 0, tmp = 0; + isneg = (*cur == '-'); + + cur++; + + PARSE_2_DIGITS(tmp, cur, ret); + if (ret != 0) + return ret; + if (!VALID_HOUR(tmp)) + return 2; + + if (*cur != ':') + return 1; + cur++; + + dt->tzo = tmp * 60; + + PARSE_2_DIGITS(tmp, cur, ret); + if (ret != 0) + return ret; + if (!VALID_MIN(tmp)) + return 2; + + dt->tzo += tmp; + if (isneg) + dt->tzo = - dt->tzo; + + if (!VALID_TZO(dt->tzo)) + return 2; + + dt->tz_flag = 1; + break; + } + default: + return 1; + } + + *str = cur; + return 0; +} + +/** + * _xmlSchemaBase64Decode: + * @ch: a character + * + * Converts a base64 encoded character to its base 64 value. + * + * Returns 0-63 (value), 64 (pad), or -1 (not recognized) + */ +static int +_xmlSchemaBase64Decode (const xmlChar ch) { + if (('A' <= ch) && (ch <= 'Z')) return ch - 'A'; + if (('a' <= ch) && (ch <= 'z')) return ch - 'a' + 26; + if (('0' <= ch) && (ch <= '9')) return ch - '0' + 52; + if ('+' == ch) return 62; + if ('/' == ch) return 63; + if ('=' == ch) return 64; + return -1; +} + +/**************************************************************** + * * + * XML Schema Dates/Times Datatypes Handling * + * * + ****************************************************************/ + +/** + * PARSE_DIGITS: + * @num: the integer to fill in + * @cur: an #xmlChar * + * @num_type: an integer flag + * + * Parses a digits integer and updates @num with the value. @cur is + * updated to point just after the integer. + * In case of error, @num_type is set to -1, values of @num and + * @cur are undefined. + */ +#define PARSE_DIGITS(num, cur, num_type) \ + if ((*cur < '0') || (*cur > '9')) \ + num_type = -1; \ + else \ + while ((*cur >= '0') && (*cur <= '9')) { \ + num = num * 10 + (*cur - '0'); \ + cur++; \ + } + +/** + * PARSE_NUM: + * @num: the double to fill in + * @cur: an #xmlChar * + * @num_type: an integer flag + * + * Parses a float or integer and updates @num with the value. @cur is + * updated to point just after the number. If the number is a float, + * then it must have an integer part and a decimal part; @num_type will + * be set to 1. If there is no decimal part, @num_type is set to zero. + * In case of error, @num_type is set to -1, values of @num and + * @cur are undefined. + */ +#define PARSE_NUM(num, cur, num_type) \ + num = 0; \ + PARSE_DIGITS(num, cur, num_type); \ + if (!num_type && (*cur == '.')) { \ + double mult = 1; \ + cur++; \ + if ((*cur < '0') || (*cur > '9')) \ + num_type = -1; \ + else \ + num_type = 1; \ + while ((*cur >= '0') && (*cur <= '9')) { \ + mult /= 10; \ + num += (*cur - '0') * mult; \ + cur++; \ + } \ + } + +/** + * xmlSchemaValidateDates: + * @type: the expected type or XML_SCHEMAS_UNKNOWN + * @dateTime: string to analyze + * @val: the return computed value + * + * Check that @dateTime conforms to the lexical space of one of the date types. + * if true a value is computed and returned in @val. + * + * Returns 0 if this validates, a positive error code number otherwise + * and -1 in case of internal or API error. + */ +static int +xmlSchemaValidateDates (xmlSchemaValType type, + const xmlChar *dateTime, xmlSchemaValPtr *val, + int collapse) { + xmlSchemaValPtr dt; + int ret; + const xmlChar *cur = dateTime; + +#define RETURN_TYPE_IF_VALID(t) \ + if (IS_TZO_CHAR(*cur)) { \ + ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur); \ + if (ret == 0) { \ + if (*cur != 0) \ + goto error; \ + dt->type = t; \ + goto done; \ + } \ + } + + if (dateTime == NULL) + return -1; + + if (collapse) + while IS_WSP_BLANK_CH(*cur) cur++; + + if ((*cur != '-') && (*cur < '0') && (*cur > '9')) + return 1; + + dt = xmlSchemaNewValue(XML_SCHEMAS_UNKNOWN); + if (dt == NULL) + return -1; + + if ((cur[0] == '-') && (cur[1] == '-')) { + /* + * It's an incomplete date (xs:gMonthDay, xs:gMonth or + * xs:gDay) + */ + cur += 2; + + /* is it an xs:gDay? */ + if (*cur == '-') { + if (type == XML_SCHEMAS_GMONTH) + goto error; + ++cur; + ret = _xmlSchemaParseGDay(&(dt->value.date), &cur); + if (ret != 0) + goto error; + + RETURN_TYPE_IF_VALID(XML_SCHEMAS_GDAY); + + goto error; + } + + /* + * it should be an xs:gMonthDay or xs:gMonth + */ + ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur); + if (ret != 0) + goto error; + + /* + * a '-' char could indicate this type is xs:gMonthDay or + * a negative time zone offset. Check for xs:gMonthDay first. + * Also the first three char's of a negative tzo (-MM:SS) can + * appear to be a valid day; so even if the day portion + * of the xs:gMonthDay verifies, we must insure it was not + * a tzo. + */ + if (*cur == '-') { + const xmlChar *rewnd = cur; + cur++; + + ret = _xmlSchemaParseGDay(&(dt->value.date), &cur); + if ((ret == 0) && ((*cur == 0) || (*cur != ':'))) { + + /* + * we can use the VALID_MDAY macro to validate the month + * and day because the leap year test will flag year zero + * as a leap year (even though zero is an invalid year). + * FUTURE TODO: Zero will become valid in XML Schema 1.1 + * probably. + */ + if (VALID_MDAY((&(dt->value.date)))) { + + RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTHDAY); + + goto error; + } + } + + /* + * not xs:gMonthDay so rewind and check if just xs:gMonth + * with an optional time zone. + */ + cur = rewnd; + } + + RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTH); + + goto error; + } + + /* + * It's a right-truncated date or an xs:time. + * Try to parse an xs:time then fallback on right-truncated dates. + */ + if ((*cur >= '0') && (*cur <= '9')) { + ret = _xmlSchemaParseTime(&(dt->value.date), &cur); + if (ret == 0) { + /* it's an xs:time */ + RETURN_TYPE_IF_VALID(XML_SCHEMAS_TIME); + } + } + + /* fallback on date parsing */ + cur = dateTime; + + ret = _xmlSchemaParseGYear(&(dt->value.date), &cur); + if (ret != 0) + goto error; + + /* is it an xs:gYear? */ + RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEAR); + + if (*cur != '-') + goto error; + cur++; + + ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur); + if (ret != 0) + goto error; + + /* is it an xs:gYearMonth? */ + RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEARMONTH); + + if (*cur != '-') + goto error; + cur++; + + ret = _xmlSchemaParseGDay(&(dt->value.date), &cur); + if ((ret != 0) || !VALID_DATE((&(dt->value.date)))) + goto error; + + /* is it an xs:date? */ + RETURN_TYPE_IF_VALID(XML_SCHEMAS_DATE); + + if (*cur != 'T') + goto error; + cur++; + + /* it should be an xs:dateTime */ + ret = _xmlSchemaParseTime(&(dt->value.date), &cur); + if (ret != 0) + goto error; + + ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur); + if (collapse) + while IS_WSP_BLANK_CH(*cur) cur++; + if ((ret != 0) || (*cur != 0) || (!(VALID_DATETIME((&(dt->value.date)))))) + goto error; + + + dt->type = XML_SCHEMAS_DATETIME; + +done: +#if 1 + if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type)) + goto error; +#else + /* + * insure the parsed type is equal to or less significant (right + * truncated) than the desired type. + */ + if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type)) { + + /* time only matches time */ + if ((type == XML_SCHEMAS_TIME) && (dt->type == XML_SCHEMAS_TIME)) + goto error; + + if ((type == XML_SCHEMAS_DATETIME) && + ((dt->type != XML_SCHEMAS_DATE) || + (dt->type != XML_SCHEMAS_GYEARMONTH) || + (dt->type != XML_SCHEMAS_GYEAR))) + goto error; + + if ((type == XML_SCHEMAS_DATE) && + ((dt->type != XML_SCHEMAS_GYEAR) || + (dt->type != XML_SCHEMAS_GYEARMONTH))) + goto error; + + if ((type == XML_SCHEMAS_GYEARMONTH) && (dt->type != XML_SCHEMAS_GYEAR)) + goto error; + + if ((type == XML_SCHEMAS_GMONTHDAY) && (dt->type != XML_SCHEMAS_GMONTH)) + goto error; + } +#endif + + if (val != NULL) + *val = dt; + else + xmlSchemaFreeValue(dt); + + return 0; + +error: + if (dt != NULL) + xmlSchemaFreeValue(dt); + return 1; +} + +/** + * xmlSchemaValidateDuration: + * @type: the predefined type + * @duration: string to analyze + * @val: the return computed value + * + * Check that @duration conforms to the lexical space of the duration type. + * if true a value is computed and returned in @val. + * + * Returns 0 if this validates, a positive error code number otherwise + * and -1 in case of internal or API error. + */ +static int +xmlSchemaValidateDuration (xmlSchemaTypePtr type ATTRIBUTE_UNUSED, + const xmlChar *duration, xmlSchemaValPtr *val, + int collapse) { + const xmlChar *cur = duration; + xmlSchemaValPtr dur; + int isneg = 0; + unsigned int seq = 0; + double num; + int num_type = 0; /* -1 = invalid, 0 = int, 1 = floating */ + const xmlChar desig[] = {'Y', 'M', 'D', 'H', 'M', 'S'}; + const double multi[] = { 0.0, 0.0, 86400.0, 3600.0, 60.0, 1.0, 0.0}; + + if (duration == NULL) + return -1; + + if (collapse) + while IS_WSP_BLANK_CH(*cur) cur++; + + if (*cur == '-') { + isneg = 1; + cur++; + } + + /* duration must start with 'P' (after sign) */ + if (*cur++ != 'P') + return 1; + + if (*cur == 0) + return 1; + + dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION); + if (dur == NULL) + return -1; + + while (*cur != 0) { + + /* input string should be empty or invalid date/time item */ + if (seq >= sizeof(desig)) + goto error; + + /* T designator must be present for time items */ + if (*cur == 'T') { + if (seq <= 3) { + seq = 3; + cur++; + } else + return 1; + } else if (seq == 3) + goto error; + + /* parse the number portion of the item */ + PARSE_NUM(num, cur, num_type); + + if ((num_type == -1) || (*cur == 0)) + goto error; + + /* update duration based on item type */ + while (seq < sizeof(desig)) { + if (*cur == desig[seq]) { + + /* verify numeric type; only seconds can be float */ + if ((num_type != 0) && (seq < (sizeof(desig)-1))) + goto error; + + switch (seq) { + case 0: + dur->value.dur.mon = (long)num * 12; + break; + case 1: + dur->value.dur.mon += (long)num; + break; + default: + /* convert to seconds using multiplier */ + dur->value.dur.sec += num * multi[seq]; + seq++; + break; + } + + break; /* exit loop */ + } + /* no date designators found? */ + if ((++seq == 3) || (seq == 6)) + goto error; + } + cur++; + if (collapse) + while IS_WSP_BLANK_CH(*cur) cur++; + } + + if (isneg) { + dur->value.dur.mon = -dur->value.dur.mon; + dur->value.dur.day = -dur->value.dur.day; + dur->value.dur.sec = -dur->value.dur.sec; + } + + if (val != NULL) + *val = dur; + else + xmlSchemaFreeValue(dur); + + return 0; + +error: + if (dur != NULL) + xmlSchemaFreeValue(dur); + return 1; +} + +/** + * xmlSchemaStrip: + * @value: a value + * + * Removes the leading and ending spaces of a string + * + * Returns the new string or NULL if no change was required. + */ +static xmlChar * +xmlSchemaStrip(const xmlChar *value) { + const xmlChar *start = value, *end, *f; + + if (value == NULL) return(NULL); + while ((*start != 0) && (IS_BLANK_CH(*start))) start++; + end = start; + while (*end != 0) end++; + f = end; + end--; + while ((end > start) && (IS_BLANK_CH(*end))) end--; + end++; + if ((start == value) && (f == end)) return(NULL); + return(xmlStrndup(start, end - start)); +} + +/** + * xmlSchemaWhiteSpaceReplace: + * @value: a value + * + * Replaces 0xd, 0x9 and 0xa with a space. + * + * Returns the new string or NULL if no change was required. + */ +xmlChar * +xmlSchemaWhiteSpaceReplace(const xmlChar *value) { + const xmlChar *cur = value; + xmlChar *ret = NULL, *mcur; + + if (value == NULL) + return(NULL); + + while ((*cur != 0) && + (((*cur) != 0xd) && ((*cur) != 0x9) && ((*cur) != 0xa))) { + cur++; + } + if (*cur == 0) + return (NULL); + ret = xmlStrdup(value); + /* TODO FIXME: I guess gcc will bark at this. */ + mcur = (xmlChar *) (ret + (cur - value)); + do { + if ( ((*mcur) == 0xd) || ((*mcur) == 0x9) || ((*mcur) == 0xa) ) + *mcur = ' '; + mcur++; + } while (*mcur != 0); + return(ret); +} + +/** + * xmlSchemaCollapseString: + * @value: a value + * + * Removes and normalize white spaces in the string + * + * Returns the new string or NULL if no change was required. + */ +xmlChar * +xmlSchemaCollapseString(const xmlChar *value) { + const xmlChar *start = value, *end, *f; + xmlChar *g; + int col = 0; + + if (value == NULL) return(NULL); + while ((*start != 0) && (IS_BLANK_CH(*start))) start++; + end = start; + while (*end != 0) { + if ((*end == ' ') && (IS_BLANK_CH(end[1]))) { + col = end - start; + break; + } else if ((*end == 0xa) || (*end == 0x9) || (*end == 0xd)) { + col = end - start; + break; + } + end++; + } + if (col == 0) { + f = end; + end--; + while ((end > start) && (IS_BLANK_CH(*end))) end--; + end++; + if ((start == value) && (f == end)) return(NULL); + return(xmlStrndup(start, end - start)); + } + start = xmlStrdup(start); + if (start == NULL) return(NULL); + g = (xmlChar *) (start + col); + end = g; + while (*end != 0) { + if (IS_BLANK_CH(*end)) { + end++; + while (IS_BLANK_CH(*end)) end++; + if (*end != 0) + *g++ = ' '; + } else + *g++ = *end++; + } + *g = 0; + return((xmlChar *) start); +} + +/** + * xmlSchemaValAtomicListNode: + * @type: the predefined atomic type for a token in the list + * @value: the list value to check + * @ret: the return computed value + * @node: the node containing the value + * + * Check that a value conforms to the lexical space of the predefined + * list type. if true a value is computed and returned in @ret. + * + * Returns the number of items if this validates, a negative error code + * number otherwise + */ +static int +xmlSchemaValAtomicListNode(xmlSchemaTypePtr type, const xmlChar *value, + xmlSchemaValPtr *ret, xmlNodePtr node) { + xmlChar *val, *cur, *endval; + int nb_values = 0; + int tmp = 0; + + if (value == NULL) { + return(-1); + } + val = xmlStrdup(value); + if (val == NULL) { + return(-1); + } + if (ret != NULL) { + *ret = NULL; + } + cur = val; + /* + * Split the list + */ + while (IS_BLANK_CH(*cur)) *cur++ = 0; + while (*cur != 0) { + if (IS_BLANK_CH(*cur)) { + *cur = 0; + cur++; + while (IS_BLANK_CH(*cur)) *cur++ = 0; + } else { + nb_values++; + cur++; + while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++; + } + } + if (nb_values == 0) { + xmlFree(val); + return(nb_values); + } + endval = cur; + cur = val; + while ((*cur == 0) && (cur != endval)) cur++; + while (cur != endval) { + tmp = xmlSchemaValPredefTypeNode(type, cur, NULL, node); + if (tmp != 0) + break; + while (*cur != 0) cur++; + while ((*cur == 0) && (cur != endval)) cur++; + } + /* TODO what return value ? c.f. bug #158628 + if (ret != NULL) { + TODO + } */ + xmlFree(val); + if (tmp == 0) + return(nb_values); + return(-1); +} + +/** + * 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 + * + * Parse an unsigned long into 3 fields. + * + * 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; + + if (!((*cur >= '0') && (*cur <= '9'))) + return(-2); + + while (*cur == '0') { /* ignore leading zeroes */ + 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--; + } + + *str = cur; + *llo = lo; + *lmi = mi; + *lhi = hi; + return(ret); +} + +/** + * xmlSchemaValAtomicType: + * @type: the predefined type + * @value: the value to check + * @val: the return computed value + * @node: the node containing the value + * flags: flags to control the vlidation + * + * Check that a value conforms to the lexical space of the atomic type. + * if true a value is computed and returned in @val. + * This checks the value space for list types as well (IDREFS, NMTOKENS). + * + * Returns 0 if this validates, a positive error code number otherwise + * and -1 in case of internal or API error. + */ +static int +xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value, + xmlSchemaValPtr * val, xmlNodePtr node, int flags, + xmlSchemaWhitespaceValueType ws, + int normOnTheFly, int applyNorm, int createStringValue) +{ + xmlSchemaValPtr v; + xmlChar *norm = NULL; + int ret = 0; + + if (xmlSchemaTypesInitialized == 0) + xmlSchemaInitTypes(); + if (type == NULL) + return (-1); + + /* + * validating a non existant text node is similar to validating + * an empty one. + */ + if (value == NULL) + value = BAD_CAST ""; + + if (val != NULL) + *val = NULL; + if ((flags == 0) && (value != NULL)) { + + if ((type->builtInType != XML_SCHEMAS_STRING) && + (type->builtInType != XML_SCHEMAS_ANYTYPE) && + (type->builtInType != XML_SCHEMAS_ANYSIMPLETYPE)) { + if (type->builtInType == XML_SCHEMAS_NORMSTRING) + norm = xmlSchemaWhiteSpaceReplace(value); + else + norm = xmlSchemaCollapseString(value); + if (norm != NULL) + value = norm; + } + } + + switch (type->builtInType) { + case XML_SCHEMAS_UNKNOWN: + goto error; + case XML_SCHEMAS_ANYTYPE: + case XML_SCHEMAS_ANYSIMPLETYPE: + if ((createStringValue) && (val != NULL)) { + v = xmlSchemaNewValue(XML_SCHEMAS_ANYSIMPLETYPE); + if (v != NULL) { + v->value.str = xmlStrdup(value); + *val = v; + } else { + goto error; + } + } + goto return0; + case XML_SCHEMAS_STRING: + if (! normOnTheFly) { + const xmlChar *cur = value; + + if (ws == XML_SCHEMA_WHITESPACE_REPLACE) { + while (*cur != 0) { + if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) { + goto return1; + } else { + cur++; + } + } + } else if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE) { + while (*cur != 0) { + if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) { + goto return1; + } else if IS_WSP_SPACE_CH(*cur) { + cur++; + if IS_WSP_SPACE_CH(*cur) + goto return1; + } else { + cur++; + } + } + } + } + if (createStringValue && (val != NULL)) { + if (applyNorm) { + if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE) + norm = xmlSchemaCollapseString(value); + else if (ws == XML_SCHEMA_WHITESPACE_REPLACE) + norm = xmlSchemaWhiteSpaceReplace(value); + if (norm != NULL) + value = norm; + } + v = xmlSchemaNewValue(XML_SCHEMAS_STRING); + if (v != NULL) { + v->value.str = xmlStrdup(value); + *val = v; + } else { + goto error; + } + } + goto return0; + case XML_SCHEMAS_NORMSTRING:{ + if (normOnTheFly) { + if (applyNorm) { + if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE) + norm = xmlSchemaCollapseString(value); + else + norm = xmlSchemaWhiteSpaceReplace(value); + if (norm != NULL) + value = norm; + } + } else { + const xmlChar *cur = value; + while (*cur != 0) { + if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) { + goto return1; + } else { + cur++; + } + } + } + if (val != NULL) { + v = xmlSchemaNewValue(XML_SCHEMAS_NORMSTRING); + if (v != NULL) { + v->value.str = xmlStrdup(value); + *val = v; + } else { + goto error; + } + } + goto return0; + } + case XML_SCHEMAS_DECIMAL:{ + const xmlChar *cur = value; + unsigned int len, neg, integ, hasLeadingZeroes; + xmlChar cval[25]; + xmlChar *cptr = cval; + + if ((cur == NULL) || (*cur == 0)) + goto return1; + + /* + * xs:decimal has a whitespace-facet value of 'collapse'. + */ + if (normOnTheFly) + while IS_WSP_BLANK_CH(*cur) cur++; + + /* + * First we handle an optional sign. + */ + neg = 0; + if (*cur == '-') { + neg = 1; + cur++; + } else if (*cur == '+') + cur++; + /* + * Disallow: "", "-", "- " + */ + 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); + } + if (normOnTheFly) + while IS_WSP_BLANK_CH(*cur) cur++; + if (*cur != 0) + goto return1; /* error if any extraneous chars */ + 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; + } + *val = v; + } + } + goto return0; + } + case XML_SCHEMAS_TIME: + case XML_SCHEMAS_GDAY: + case XML_SCHEMAS_GMONTH: + case XML_SCHEMAS_GMONTHDAY: + case XML_SCHEMAS_GYEAR: + case XML_SCHEMAS_GYEARMONTH: + case XML_SCHEMAS_DATE: + case XML_SCHEMAS_DATETIME: + ret = xmlSchemaValidateDates(type->builtInType, value, val, + normOnTheFly); + break; + case XML_SCHEMAS_DURATION: + ret = xmlSchemaValidateDuration(type, value, val, + normOnTheFly); + break; + case XML_SCHEMAS_FLOAT: + case XML_SCHEMAS_DOUBLE: { + const xmlChar *cur = value; + int neg = 0; + int digits_before = 0; + int digits_after = 0; + + if (normOnTheFly) + while IS_WSP_BLANK_CH(*cur) cur++; + + if ((cur[0] == 'N') && (cur[1] == 'a') && (cur[2] == 'N')) { + cur += 3; + if (*cur != 0) + goto return1; + if (val != NULL) { + if (type == xmlSchemaTypeFloatDef) { + v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT); + if (v != NULL) { + v->value.f = (float) xmlXPathNAN; + } else { + xmlSchemaFreeValue(v); + goto error; + } + } else { + v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE); + if (v != NULL) { + v->value.d = xmlXPathNAN; + } else { + xmlSchemaFreeValue(v); + goto error; + } + } + *val = v; + } + goto return0; + } + if (*cur == '-') { + neg = 1; + cur++; + } + if ((cur[0] == 'I') && (cur[1] == 'N') && (cur[2] == 'F')) { + cur += 3; + if (*cur != 0) + goto return1; + if (val != NULL) { + if (type == xmlSchemaTypeFloatDef) { + v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT); + if (v != NULL) { + if (neg) + v->value.f = (float) xmlXPathNINF; + else + v->value.f = (float) xmlXPathPINF; + } else { + xmlSchemaFreeValue(v); + goto error; + } + } else { + v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE); + if (v != NULL) { + if (neg) + v->value.d = xmlXPathNINF; + else + v->value.d = xmlXPathPINF; + } else { + xmlSchemaFreeValue(v); + goto error; + } + } + *val = v; + } + goto return0; + } + if ((neg == 0) && (*cur == '+')) + cur++; + if ((cur[0] == 0) || (cur[0] == '+') || (cur[0] == '-')) + goto return1; + while ((*cur >= '0') && (*cur <= '9')) { + cur++; + digits_before++; + } + if (*cur == '.') { + cur++; + while ((*cur >= '0') && (*cur <= '9')) { + cur++; + digits_after++; + } + } + if ((digits_before == 0) && (digits_after == 0)) + goto return1; + if ((*cur == 'e') || (*cur == 'E')) { + cur++; + if ((*cur == '-') || (*cur == '+')) + cur++; + while ((*cur >= '0') && (*cur <= '9')) + cur++; + } + if (normOnTheFly) + while IS_WSP_BLANK_CH(*cur) cur++; + + if (*cur != 0) + goto return1; + if (val != NULL) { + if (type == xmlSchemaTypeFloatDef) { + v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT); + if (v != NULL) { + /* + * TODO: sscanf seems not to give the correct + * value for extremely high/low values. + * E.g. "1E-149" results in zero. + */ + if (sscanf((const char *) value, "%f", + &(v->value.f)) == 1) { + *val = v; + } else { + xmlSchemaFreeValue(v); + goto return1; + } + } else { + goto error; + } + } else { + v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE); + if (v != NULL) { + /* + * TODO: sscanf seems not to give the correct + * value for extremely high/low values. + */ + if (sscanf((const char *) value, "%lf", + &(v->value.d)) == 1) { + *val = v; + } else { + xmlSchemaFreeValue(v); + goto return1; + } + } else { + goto error; + } + } + } + goto return0; + } + case XML_SCHEMAS_BOOLEAN:{ + const xmlChar *cur = value; + + if (normOnTheFly) { + while IS_WSP_BLANK_CH(*cur) cur++; + if (*cur == '0') { + ret = 0; + cur++; + } else if (*cur == '1') { + ret = 1; + cur++; + } else if (*cur == 't') { + cur++; + if ((*cur++ == 'r') && (*cur++ == 'u') && + (*cur++ == 'e')) { + ret = 1; + } else + goto return1; + } else if (*cur == 'f') { + cur++; + if ((*cur++ == 'a') && (*cur++ == 'l') && + (*cur++ == 's') && (*cur++ == 'e')) { + ret = 0; + } else + goto return1; + } else + goto return1; + if (*cur != 0) { + while IS_WSP_BLANK_CH(*cur) cur++; + if (*cur != 0) + goto return1; + } + } else { + if ((cur[0] == '0') && (cur[1] == 0)) + ret = 0; + else if ((cur[0] == '1') && (cur[1] == 0)) + ret = 1; + else if ((cur[0] == 't') && (cur[1] == 'r') + && (cur[2] == 'u') && (cur[3] == 'e') + && (cur[4] == 0)) + ret = 1; + else if ((cur[0] == 'f') && (cur[1] == 'a') + && (cur[2] == 'l') && (cur[3] == 's') + && (cur[4] == 'e') && (cur[5] == 0)) + ret = 0; + else + goto return1; + } + if (val != NULL) { + v = xmlSchemaNewValue(XML_SCHEMAS_BOOLEAN); + if (v != NULL) { + v->value.b = ret; + *val = v; + } else { + goto error; + } + } + goto return0; + } + case XML_SCHEMAS_TOKEN:{ + const xmlChar *cur = value; + + if (! normOnTheFly) { + while (*cur != 0) { + if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) { + goto return1; + } else if (*cur == ' ') { + cur++; + if (*cur == 0) + goto return1; + if (*cur == ' ') + goto return1; + } else { + cur++; + } + } + } + if (val != NULL) { + v = xmlSchemaNewValue(XML_SCHEMAS_TOKEN); + if (v != NULL) { + v->value.str = xmlStrdup(value); + *val = v; + } else { + goto error; + } + } + goto return0; + } + case XML_SCHEMAS_LANGUAGE: + if (normOnTheFly) { + norm = xmlSchemaCollapseString(value); + if (norm != NULL) + value = norm; + } + if (xmlCheckLanguageID(value) == 1) { + if (val != NULL) { + v = xmlSchemaNewValue(XML_SCHEMAS_LANGUAGE); + if (v != NULL) { + v->value.str = xmlStrdup(value); + *val = v; + } else { + goto error; + } + } + goto return0; + } + goto return1; + case XML_SCHEMAS_NMTOKEN: + if (xmlValidateNMToken(value, 1) == 0) { + if (val != NULL) { + v = xmlSchemaNewValue(XML_SCHEMAS_NMTOKEN); + if (v != NULL) { + v->value.str = xmlStrdup(value); + *val = v; + } else { + goto error; + } + } + goto return0; + } + goto return1; + case XML_SCHEMAS_NMTOKENS: + ret = xmlSchemaValAtomicListNode(xmlSchemaTypeNmtokenDef, + value, val, node); + if (ret > 0) + ret = 0; + else + ret = 1; + goto done; + case XML_SCHEMAS_NAME: + ret = xmlValidateName(value, 1); + if ((ret == 0) && (val != NULL) && (value != NULL)) { + v = xmlSchemaNewValue(XML_SCHEMAS_NAME); + if (v != NULL) { + const xmlChar *start = value, *end; + while (IS_BLANK_CH(*start)) start++; + end = start; + while ((*end != 0) && (!IS_BLANK_CH(*end))) end++; + v->value.str = xmlStrndup(start, end - start); + *val = v; + } else { + goto error; + } + } + goto done; + case XML_SCHEMAS_QNAME:{ + const xmlChar *uri = NULL; + xmlChar *local = NULL; + + ret = xmlValidateQName(value, 1); + if (ret != 0) + goto done; + if (node != NULL) { + xmlChar *prefix; + xmlNsPtr ns; + + local = xmlSplitQName2(value, &prefix); + ns = xmlSearchNs(node->doc, node, prefix); + if ((ns == NULL) && (prefix != NULL)) { + xmlFree(prefix); + if (local != NULL) + xmlFree(local); + goto return1; + } + if (ns != NULL) + uri = ns->href; + if (prefix != NULL) + xmlFree(prefix); + } + if (val != NULL) { + v = xmlSchemaNewValue(XML_SCHEMAS_QNAME); + if (v == NULL) { + if (local != NULL) + xmlFree(local); + goto error; + } + if (local != NULL) + v->value.qname.name = local; + else + v->value.qname.name = xmlStrdup(value); + if (uri != NULL) + v->value.qname.uri = xmlStrdup(uri); + *val = v; + } else + if (local != NULL) + xmlFree(local); + goto done; + } + case XML_SCHEMAS_NCNAME: + ret = xmlValidateNCName(value, 1); + if ((ret == 0) && (val != NULL)) { + v = xmlSchemaNewValue(XML_SCHEMAS_NCNAME); + if (v != NULL) { + v->value.str = xmlStrdup(value); + *val = v; + } else { + goto error; + } + } + goto done; + case XML_SCHEMAS_ID: + ret = xmlValidateNCName(value, 1); + if ((ret == 0) && (val != NULL)) { + v = xmlSchemaNewValue(XML_SCHEMAS_ID); + if (v != NULL) { + v->value.str = xmlStrdup(value); + *val = v; + } else { + goto error; + } + } + if ((ret == 0) && (node != NULL) && + (node->type == XML_ATTRIBUTE_NODE)) { + xmlAttrPtr attr = (xmlAttrPtr) node; + + /* + * NOTE: the IDness might have already be declared in the DTD + */ + if (attr->atype != XML_ATTRIBUTE_ID) { + xmlIDPtr res; + xmlChar *strip; + + strip = xmlSchemaStrip(value); + if (strip != NULL) { + res = xmlAddID(NULL, node->doc, strip, attr); + xmlFree(strip); + } else + res = xmlAddID(NULL, node->doc, value, attr); + if (res == NULL) { + ret = 2; + } else { + attr->atype = XML_ATTRIBUTE_ID; + } + } + } + goto done; + case XML_SCHEMAS_IDREF: + ret = xmlValidateNCName(value, 1); + if ((ret == 0) && (val != NULL)) { + v = xmlSchemaNewValue(XML_SCHEMAS_IDREF); + if (v == NULL) + goto error; + v->value.str = xmlStrdup(value); + *val = v; + } + if ((ret == 0) && (node != NULL) && + (node->type == XML_ATTRIBUTE_NODE)) { + xmlAttrPtr attr = (xmlAttrPtr) node; + xmlChar *strip; + + strip = xmlSchemaStrip(value); + if (strip != NULL) { + xmlAddRef(NULL, node->doc, strip, attr); + xmlFree(strip); + } else + xmlAddRef(NULL, node->doc, value, attr); + attr->atype = XML_ATTRIBUTE_IDREF; + } + goto done; + case XML_SCHEMAS_IDREFS: + ret = xmlSchemaValAtomicListNode(xmlSchemaTypeIdrefDef, + value, val, node); + if (ret < 0) + ret = 2; + else + ret = 0; + if ((ret == 0) && (node != NULL) && + (node->type == XML_ATTRIBUTE_NODE)) { + xmlAttrPtr attr = (xmlAttrPtr) node; + + attr->atype = XML_ATTRIBUTE_IDREFS; + } + goto done; + case XML_SCHEMAS_ENTITY:{ + xmlChar *strip; + + ret = xmlValidateNCName(value, 1); + if ((node == NULL) || (node->doc == NULL)) + ret = 3; + if (ret == 0) { + xmlEntityPtr ent; + + strip = xmlSchemaStrip(value); + if (strip != NULL) { + ent = xmlGetDocEntity(node->doc, strip); + xmlFree(strip); + } else { + ent = xmlGetDocEntity(node->doc, value); + } + if ((ent == NULL) || + (ent->etype != + XML_EXTERNAL_GENERAL_UNPARSED_ENTITY)) + ret = 4; + } + if ((ret == 0) && (val != NULL)) { + TODO; + } + if ((ret == 0) && (node != NULL) && + (node->type == XML_ATTRIBUTE_NODE)) { + xmlAttrPtr attr = (xmlAttrPtr) node; + + attr->atype = XML_ATTRIBUTE_ENTITY; + } + goto done; + } + case XML_SCHEMAS_ENTITIES: + if ((node == NULL) || (node->doc == NULL)) + goto return3; + ret = xmlSchemaValAtomicListNode(xmlSchemaTypeEntityDef, + value, val, node); + if (ret <= 0) + ret = 1; + else + ret = 0; + if ((ret == 0) && (node != NULL) && + (node->type == XML_ATTRIBUTE_NODE)) { + xmlAttrPtr attr = (xmlAttrPtr) node; + + attr->atype = XML_ATTRIBUTE_ENTITIES; + } + goto done; + case XML_SCHEMAS_NOTATION:{ + xmlChar *uri = NULL; + xmlChar *local = NULL; + + ret = xmlValidateQName(value, 1); + if ((ret == 0) && (node != NULL)) { + xmlChar *prefix; + + local = xmlSplitQName2(value, &prefix); + if (prefix != NULL) { + xmlNsPtr ns; + + ns = xmlSearchNs(node->doc, node, prefix); + if (ns == NULL) + ret = 1; + else if (val != NULL) + uri = xmlStrdup(ns->href); + } + if ((local != NULL) && ((val == NULL) || (ret != 0))) + xmlFree(local); + if (prefix != NULL) + xmlFree(prefix); + } + if ((node == NULL) || (node->doc == NULL)) + ret = 3; + if (ret == 0) { + ret = xmlValidateNotationUse(NULL, node->doc, value); + if (ret == 1) + ret = 0; + else + ret = 1; + } + if ((ret == 0) && (val != NULL)) { + v = xmlSchemaNewValue(XML_SCHEMAS_NOTATION); + if (v != NULL) { + if (local != NULL) + v->value.qname.name = local; + else + v->value.qname.name = xmlStrdup(value); + if (uri != NULL) + v->value.qname.uri = uri; + + *val = v; + } else { + if (local != NULL) + xmlFree(local); + if (uri != NULL) + xmlFree(uri); + goto error; + } + } + goto done; + } + case XML_SCHEMAS_ANYURI:{ + if (*value != 0) { + xmlURIPtr uri; + xmlChar *tmpval, *cur; + if (normOnTheFly) { + norm = xmlSchemaCollapseString(value); + if (norm != NULL) + value = norm; + } + tmpval = xmlStrdup(value); + for (cur = tmpval; *cur; ++cur) { + if (*cur < 32 || *cur >= 127 || *cur == ' ' || + *cur == '<' || *cur == '>' || *cur == '"' || + *cur == '{' || *cur == '}' || *cur == '|' || + *cur == '\\' || *cur == '^' || *cur == '`' || + *cur == '\'') + *cur = '_'; + } + uri = xmlParseURI((const char *) tmpval); + xmlFree(tmpval); + if (uri == NULL) + goto return1; + xmlFreeURI(uri); + } + + if (val != NULL) { + v = xmlSchemaNewValue(XML_SCHEMAS_ANYURI); + if (v == NULL) + goto error; + v->value.str = xmlStrdup(value); + *val = v; + } + goto return0; + } + case XML_SCHEMAS_HEXBINARY:{ + const xmlChar *cur = value, *start; + xmlChar *base; + int total, i = 0; + + if (cur == NULL) + goto return1; + + if (normOnTheFly) + while IS_WSP_BLANK_CH(*cur) cur++; + + start = cur; + while (((*cur >= '0') && (*cur <= '9')) || + ((*cur >= 'A') && (*cur <= 'F')) || + ((*cur >= 'a') && (*cur <= 'f'))) { + i++; + cur++; + } + if (normOnTheFly) + while IS_WSP_BLANK_CH(*cur) cur++; + + if (*cur != 0) + goto return1; + if ((i % 2) != 0) + goto return1; + + if (val != NULL) { + + v = xmlSchemaNewValue(XML_SCHEMAS_HEXBINARY); + if (v == NULL) + goto error; + /* + * Copy only the normalized piece. + * CRITICAL TODO: Check this. + */ + cur = xmlStrndup(start, i); + if (cur == NULL) { + xmlSchemaTypeErrMemory(node, "allocating hexbin data"); + xmlFree(v); + goto return1; + } + + total = i / 2; /* number of octets */ + + base = (xmlChar *) cur; + while (i-- > 0) { + if (*base >= 'a') + *base = *base - ('a' - 'A'); + base++; + } + + v->value.hex.str = (xmlChar *) cur; + v->value.hex.total = total; + *val = v; + } + goto return0; + } + case XML_SCHEMAS_BASE64BINARY:{ + /* ISSUE: + * + * Ignore all stray characters? (yes, currently) + * Worry about long lines? (no, currently) + * + * rfc2045.txt: + * + * "The encoded output stream must be represented in lines of + * no more than 76 characters each. All line breaks or other + * characters not found in Table 1 must be ignored by decoding + * software. In base64 data, characters other than those in + * Table 1, line breaks, and other white space probably + * indicate a transmission error, about which a warning + * message or even a message rejection might be appropriate + * under some circumstances." */ + const xmlChar *cur = value; + xmlChar *base; + int total, i = 0, pad = 0; + + if (cur == NULL) + goto return1; + + for (; *cur; ++cur) { + int decc; + + decc = _xmlSchemaBase64Decode(*cur); + if (decc < 0) ; + else if (decc < 64) + i++; + else + break; + } + for (; *cur; ++cur) { + int decc; + + decc = _xmlSchemaBase64Decode(*cur); + if (decc < 0) ; + else if (decc < 64) + goto return1; + if (decc == 64) + pad++; + } + + /* rfc2045.txt: "Special processing is performed if fewer than + * 24 bits are available at the end of the data being encoded. + * A full encoding quantum is always completed at the end of a + * body. When fewer than 24 input bits are available in an + * input group, zero bits are added (on the right) to form an + * integral number of 6-bit groups. Padding at the end of the + * data is performed using the "=" character. Since all + * base64 input is an integral number of octets, only the + * following cases can arise: (1) the final quantum of + * encoding input is an integral multiple of 24 bits; here, + * the final unit of encoded output will be an integral + * multiple ofindent: Standard input:701: Warning:old style + * assignment ambiguity in "=*". Assuming "= *" 4 characters + * with no "=" padding, (2) the final + * quantum of encoding input is exactly 8 bits; here, the + * final unit of encoded output will be two characters + * followed by two "=" padding characters, or (3) the final + * quantum of encoding input is exactly 16 bits; here, the + * final unit of encoded output will be three characters + * followed by one "=" padding character." */ + + total = 3 * (i / 4); + if (pad == 0) { + if (i % 4 != 0) + goto return1; + } else if (pad == 1) { + int decc; + + if (i % 4 != 3) + goto return1; + for (decc = _xmlSchemaBase64Decode(*cur); + (decc < 0) || (decc > 63); + decc = _xmlSchemaBase64Decode(*cur)) + --cur; + /* 16bits in 24bits means 2 pad bits: nnnnnn nnmmmm mmmm00*/ + /* 00111100 -> 0x3c */ + if (decc & ~0x3c) + goto return1; + total += 2; + } else if (pad == 2) { + int decc; + + if (i % 4 != 2) + goto return1; + for (decc = _xmlSchemaBase64Decode(*cur); + (decc < 0) || (decc > 63); + decc = _xmlSchemaBase64Decode(*cur)) + --cur; + /* 8bits in 12bits means 4 pad bits: nnnnnn nn0000 */ + /* 00110000 -> 0x30 */ + if (decc & ~0x30) + goto return1; + total += 1; + } else + goto return1; + + if (val != NULL) { + v = xmlSchemaNewValue(XML_SCHEMAS_BASE64BINARY); + if (v == NULL) + goto error; + base = + (xmlChar *) xmlMallocAtomic((i + pad + 1) * + sizeof(xmlChar)); + if (base == NULL) { + xmlSchemaTypeErrMemory(node, "allocating base64 data"); + xmlFree(v); + goto return1; + } + v->value.base64.str = base; + for (cur = value; *cur; ++cur) + if (_xmlSchemaBase64Decode(*cur) >= 0) { + *base = *cur; + ++base; + } + *base = 0; + v->value.base64.total = total; + *val = v; + } + goto return0; + } + case XML_SCHEMAS_INTEGER: + 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_LONG: + case XML_SCHEMAS_BYTE: + case XML_SCHEMAS_SHORT: + case XML_SCHEMAS_INT:{ + const xmlChar *cur = value; + unsigned long lo, mi, hi; + int sign = 0; + + if (cur == NULL) + goto return1; + if (*cur == '-') { + sign = 1; + cur++; + } else if (*cur == '+') + cur++; + ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi); + if (ret < 0) + goto return1; + 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; + } + 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; + } + } + 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; + ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi); + if (ret < 0) + goto return1; + 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; + } + 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; + *val = v; + } + } + goto return0; + } + } + + done: + if (norm != NULL) + xmlFree(norm); + return (ret); + return3: + if (norm != NULL) + xmlFree(norm); + return (3); + return1: + if (norm != NULL) + xmlFree(norm); + return (1); + return0: + if (norm != NULL) + xmlFree(norm); + return (0); + error: + if (norm != NULL) + xmlFree(norm); + return (-1); +} + +/** + * xmlSchemaValPredefTypeNode: + * @type: the predefined type + * @value: the value to check + * @val: the return computed value + * @node: the node containing the value + * + * Check that a value conforms to the lexical space of the predefined type. + * if true a value is computed and returned in @val. + * + * Returns 0 if this validates, a positive error code number otherwise + * and -1 in case of internal or API error. + */ +int +xmlSchemaValPredefTypeNode(xmlSchemaTypePtr type, const xmlChar *value, + xmlSchemaValPtr *val, xmlNodePtr node) { + return(xmlSchemaValAtomicType(type, value, val, node, 0, + XML_SCHEMA_WHITESPACE_UNKNOWN, 1, 1, 0)); +} + +/** + * xmlSchemaValPredefTypeNodeNoNorm: + * @type: the predefined type + * @value: the value to check + * @val: the return computed value + * @node: the node containing the value + * + * Check that a value conforms to the lexical space of the predefined type. + * if true a value is computed and returned in @val. + * This one does apply any normalization to the value. + * + * Returns 0 if this validates, a positive error code number otherwise + * and -1 in case of internal or API error. + */ +int +xmlSchemaValPredefTypeNodeNoNorm(xmlSchemaTypePtr type, const xmlChar *value, + xmlSchemaValPtr *val, xmlNodePtr node) { + return(xmlSchemaValAtomicType(type, value, val, node, 1, + XML_SCHEMA_WHITESPACE_UNKNOWN, 1, 0, 1)); +} + +/** + * xmlSchemaValidatePredefinedType: + * @type: the predefined type + * @value: the value to check + * @val: the return computed value + * + * Check that a value conforms to the lexical space of the predefined type. + * if true a value is computed and returned in @val. + * + * Returns 0 if this validates, a positive error code number otherwise + * and -1 in case of internal or API error. + */ +int +xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value, + xmlSchemaValPtr *val) { + return(xmlSchemaValPredefTypeNode(type, value, val, NULL)); +} + +/** + * xmlSchemaCompareDecimals: + * @x: a first decimal value + * @y: a second decimal value + * + * Compare 2 decimals + * + * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error + */ +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--; + } + 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; + } + } + } + } + return -order; +} + +/** + * xmlSchemaCompareDurations: + * @x: a first duration value + * @y: a second duration value + * + * Compare 2 durations + * + * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in + * case of error + */ +static int +xmlSchemaCompareDurations(xmlSchemaValPtr x, xmlSchemaValPtr y) +{ + long carry, mon, day; + double sec; + int invert = 1; + long xmon, xday, myear, minday, maxday; + static const long dayRange [2][12] = { + { 0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334, }, + { 0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337} }; + + if ((x == NULL) || (y == NULL)) + return -2; + + /* months */ + mon = x->value.dur.mon - y->value.dur.mon; + + /* seconds */ + sec = x->value.dur.sec - y->value.dur.sec; + carry = (long)(sec / SECS_PER_DAY); + sec -= ((double)carry) * SECS_PER_DAY; + + /* days */ + day = x->value.dur.day - y->value.dur.day + carry; + + /* easy test */ + if (mon == 0) { + if (day == 0) + if (sec == 0.0) + return 0; + else if (sec < 0.0) + return -1; + else + return 1; + else if (day < 0) + return -1; + else + return 1; + } + + if (mon > 0) { + if ((day >= 0) && (sec >= 0.0)) + return 1; + else { + xmon = mon; + xday = -day; + } + } else if ((day <= 0) && (sec <= 0.0)) { + return -1; + } else { + invert = -1; + xmon = -mon; + xday = day; + } + + myear = xmon / 12; + if (myear == 0) { + minday = 0; + maxday = 0; + } else { + maxday = 366 * ((myear + 3) / 4) + + 365 * ((myear - 1) % 4); + minday = maxday - 1; + } + + xmon = xmon % 12; + minday += dayRange[0][xmon]; + maxday += dayRange[1][xmon]; + + if ((maxday == minday) && (maxday == xday)) + return(0); /* can this really happen ? */ + if (maxday < xday) + return(-invert); + if (minday > xday) + return(invert); + + /* indeterminate */ + return 2; +} + +/* + * macros for adding date/times and durations + */ +#define FQUOTIENT(a,b) (floor(((double)a/(double)b))) +#define MODULO(a,b) (a - FQUOTIENT(a,b) * b) +#define FQUOTIENT_RANGE(a,low,high) (FQUOTIENT((a-low),(high-low))) +#define MODULO_RANGE(a,low,high) ((MODULO((a-low),(high-low)))+low) + +/** + * xmlSchemaDupVal: + * @v: the #xmlSchemaValPtr value to duplicate + * + * Makes a copy of @v. The calling program is responsible for freeing + * the returned value. + * + * returns a pointer to a duplicated #xmlSchemaValPtr or NULL if error. + */ +static xmlSchemaValPtr +xmlSchemaDupVal (xmlSchemaValPtr v) +{ + xmlSchemaValPtr ret = xmlSchemaNewValue(v->type); + if (ret == NULL) + return NULL; + + memcpy(ret, v, sizeof(xmlSchemaVal)); + ret->next = NULL; + return ret; +} + +/** + * xmlSchemaCopyValue: + * @val: the precomputed value to be copied + * + * Copies the precomputed value. This duplicates any string within. + * + * Returns the copy or NULL if a copy for a data-type is not implemented. + */ +xmlSchemaValPtr +xmlSchemaCopyValue(xmlSchemaValPtr val) +{ + xmlSchemaValPtr ret = NULL, prev = NULL, cur; + + /* + * Copy the string values. + */ + while (val != NULL) { + switch (val->type) { + case XML_SCHEMAS_ANYTYPE: + case XML_SCHEMAS_IDREFS: + case XML_SCHEMAS_ENTITIES: + case XML_SCHEMAS_NMTOKENS: + xmlSchemaFreeValue(ret); + return (NULL); + case XML_SCHEMAS_ANYSIMPLETYPE: + case XML_SCHEMAS_STRING: + case XML_SCHEMAS_NORMSTRING: + case XML_SCHEMAS_TOKEN: + case XML_SCHEMAS_LANGUAGE: + case XML_SCHEMAS_NAME: + case XML_SCHEMAS_NCNAME: + case XML_SCHEMAS_ID: + case XML_SCHEMAS_IDREF: + case XML_SCHEMAS_ENTITY: + case XML_SCHEMAS_NMTOKEN: + case XML_SCHEMAS_ANYURI: + cur = xmlSchemaDupVal(val); + if (val->value.str != NULL) + cur->value.str = xmlStrdup(BAD_CAST val->value.str); + break; + case XML_SCHEMAS_QNAME: + case XML_SCHEMAS_NOTATION: + cur = xmlSchemaDupVal(val); + if (val->value.qname.name != NULL) + cur->value.qname.name = + xmlStrdup(BAD_CAST val->value.qname.name); + if (val->value.qname.uri != NULL) + cur->value.qname.uri = + xmlStrdup(BAD_CAST val->value.qname.uri); + break; + case XML_SCHEMAS_HEXBINARY: + cur = xmlSchemaDupVal(val); + if (val->value.hex.str != NULL) + cur->value.hex.str = xmlStrdup(BAD_CAST val->value.hex.str); + break; + case XML_SCHEMAS_BASE64BINARY: + cur = xmlSchemaDupVal(val); + if (val->value.base64.str != NULL) + cur->value.base64.str = + xmlStrdup(BAD_CAST val->value.base64.str); + break; + default: + cur = xmlSchemaDupVal(val); + break; + } + if (ret == NULL) + ret = cur; + else + prev->next = cur; + prev = cur; + val = val->next; + } + return (ret); +} + +/** + * _xmlSchemaDateAdd: + * @dt: an #xmlSchemaValPtr + * @dur: an #xmlSchemaValPtr of type #XS_DURATION + * + * Compute a new date/time from @dt and @dur. This function assumes @dt + * is either #XML_SCHEMAS_DATETIME, #XML_SCHEMAS_DATE, #XML_SCHEMAS_GYEARMONTH, + * or #XML_SCHEMAS_GYEAR. The returned #xmlSchemaVal is the same type as + * @dt. The calling program is responsible for freeing the returned value. + * + * Returns a pointer to a new #xmlSchemaVal or NULL if error. + */ +static xmlSchemaValPtr +_xmlSchemaDateAdd (xmlSchemaValPtr dt, xmlSchemaValPtr dur) +{ + xmlSchemaValPtr ret, tmp; + long carry, tempdays, temp; + xmlSchemaValDatePtr r, d; + xmlSchemaValDurationPtr u; + + if ((dt == NULL) || (dur == NULL)) + return NULL; + + ret = xmlSchemaNewValue(dt->type); + if (ret == NULL) + return NULL; + + /* make a copy so we don't alter the original value */ + tmp = xmlSchemaDupVal(dt); + if (tmp == NULL) { + xmlSchemaFreeValue(ret); + return NULL; + } + + r = &(ret->value.date); + d = &(tmp->value.date); + u = &(dur->value.dur); + + /* normalization */ + if (d->mon == 0) + d->mon = 1; + + /* normalize for time zone offset */ + u->sec -= (d->tzo * 60); + d->tzo = 0; + + /* normalization */ + if (d->day == 0) + d->day = 1; + + /* month */ + carry = d->mon + u->mon; + r->mon = (unsigned int) MODULO_RANGE(carry, 1, 13); + carry = (long) FQUOTIENT_RANGE(carry, 1, 13); + + /* year (may be modified later) */ + r->year = d->year + carry; + if (r->year == 0) { + if (d->year > 0) + r->year--; + else + r->year++; + } + + /* time zone */ + r->tzo = d->tzo; + r->tz_flag = d->tz_flag; + + /* seconds */ + r->sec = d->sec + u->sec; + carry = (long) FQUOTIENT((long)r->sec, 60); + if (r->sec != 0.0) { + r->sec = MODULO(r->sec, 60.0); + } + + /* minute */ + carry += d->min; + r->min = (unsigned int) MODULO(carry, 60); + carry = (long) FQUOTIENT(carry, 60); + + /* hours */ + carry += d->hour; + r->hour = (unsigned int) MODULO(carry, 24); + carry = (long)FQUOTIENT(carry, 24); + + /* + * days + * Note we use tempdays because the temporary values may need more + * than 5 bits + */ + if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) && + (d->day > MAX_DAYINMONTH(r->year, r->mon))) + tempdays = MAX_DAYINMONTH(r->year, r->mon); + else if (d->day < 1) + tempdays = 1; + else + tempdays = d->day; + + tempdays += u->day + carry; + + while (1) { + if (tempdays < 1) { + long tmon = (long) MODULO_RANGE((int)r->mon-1, 1, 13); + long tyr = r->year + (long)FQUOTIENT_RANGE((int)r->mon-1, 1, 13); + if (tyr == 0) + tyr--; + /* + * Coverity detected an overrun in daysInMonth + * of size 12 at position 12 with index variable "((r)->mon - 1)" + */ + if (tmon < 0) + tmon = 0; + if (tmon > 12) + tmon = 12; + tempdays += MAX_DAYINMONTH(tyr, tmon); + carry = -1; + } else if (tempdays > (long) MAX_DAYINMONTH(r->year, r->mon)) { + tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon); + carry = 1; + } else + break; + + temp = r->mon + carry; + r->mon = (unsigned int) MODULO_RANGE(temp, 1, 13); + r->year = r->year + (unsigned int) FQUOTIENT_RANGE(temp, 1, 13); + if (r->year == 0) { + if (temp < 1) + r->year--; + else + r->year++; + } + } + + r->day = tempdays; + + /* + * adjust the date/time type to the date values + */ + if (ret->type != XML_SCHEMAS_DATETIME) { + if ((r->hour) || (r->min) || (r->sec)) + ret->type = XML_SCHEMAS_DATETIME; + else if (ret->type != XML_SCHEMAS_DATE) { + if ((r->mon != 1) && (r->day != 1)) + ret->type = XML_SCHEMAS_DATE; + else if ((ret->type != XML_SCHEMAS_GYEARMONTH) && (r->mon != 1)) + ret->type = XML_SCHEMAS_GYEARMONTH; + } + } + + xmlSchemaFreeValue(tmp); + + return ret; +} + +/** + * xmlSchemaDateNormalize: + * @dt: an #xmlSchemaValPtr of a date/time type value. + * @offset: number of seconds to adjust @dt by. + * + * Normalize @dt to GMT time. The @offset parameter is subtracted from + * the return value is a time-zone offset is present on @dt. + * + * Returns a normalized copy of @dt or NULL if error. + */ +static xmlSchemaValPtr +xmlSchemaDateNormalize (xmlSchemaValPtr dt, double offset) +{ + xmlSchemaValPtr dur, ret; + + if (dt == NULL) + return NULL; + + if (((dt->type != XML_SCHEMAS_TIME) && + (dt->type != XML_SCHEMAS_DATETIME) && + (dt->type != XML_SCHEMAS_DATE)) || (dt->value.date.tzo == 0)) + return xmlSchemaDupVal(dt); + + dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION); + if (dur == NULL) + return NULL; + + dur->value.date.sec -= offset; + + ret = _xmlSchemaDateAdd(dt, dur); + if (ret == NULL) + return NULL; + + xmlSchemaFreeValue(dur); + + /* ret->value.date.tzo = 0; */ + return ret; +} + +/** + * _xmlSchemaDateCastYMToDays: + * @dt: an #xmlSchemaValPtr + * + * Convert mon and year of @dt to total number of days. Take the + * number of years since (or before) 1 AD and add the number of leap + * years. This is a function because negative + * years must be handled a little differently and there is no zero year. + * + * Returns number of days. + */ +static long +_xmlSchemaDateCastYMToDays (const xmlSchemaValPtr dt) +{ + long ret; + int mon; + + mon = dt->value.date.mon; + if (mon <= 0) mon = 1; /* normalization */ + + if (dt->value.date.year <= 0) + ret = (dt->value.date.year * 365) + + (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+ + ((dt->value.date.year+1)/400)) + + DAY_IN_YEAR(0, mon, dt->value.date.year); + else + ret = ((dt->value.date.year-1) * 365) + + (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+ + ((dt->value.date.year-1)/400)) + + DAY_IN_YEAR(0, mon, dt->value.date.year); + + return ret; +} + +/** + * TIME_TO_NUMBER: + * @dt: an #xmlSchemaValPtr + * + * Calculates the number of seconds in the time portion of @dt. + * + * Returns seconds. + */ +#define TIME_TO_NUMBER(dt) \ + ((double)((dt->value.date.hour * SECS_PER_HOUR) + \ + (dt->value.date.min * SECS_PER_MIN) + \ + (dt->value.date.tzo * SECS_PER_MIN)) + \ + dt->value.date.sec) + +/** + * xmlSchemaCompareDates: + * @x: a first date/time value + * @y: a second date/time value + * + * Compare 2 date/times + * + * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in + * case of error + */ +static int +xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y) +{ + unsigned char xmask, ymask, xor_mask, and_mask; + xmlSchemaValPtr p1, p2, q1, q2; + long p1d, p2d, q1d, q2d; + + if ((x == NULL) || (y == NULL)) + return -2; + + if (x->value.date.tz_flag) { + + if (!y->value.date.tz_flag) { + p1 = xmlSchemaDateNormalize(x, 0); + p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day; + /* normalize y + 14:00 */ + q1 = xmlSchemaDateNormalize(y, (14 * SECS_PER_HOUR)); + + q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day; + if (p1d < q1d) { + xmlSchemaFreeValue(p1); + xmlSchemaFreeValue(q1); + return -1; + } else if (p1d == q1d) { + double sec; + + sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1); + if (sec < 0.0) { + xmlSchemaFreeValue(p1); + xmlSchemaFreeValue(q1); + return -1; + } else { + int ret = 0; + /* normalize y - 14:00 */ + q2 = xmlSchemaDateNormalize(y, -(14 * SECS_PER_HOUR)); + q2d = _xmlSchemaDateCastYMToDays(q2) + q2->value.date.day; + if (p1d > q2d) + ret = 1; + else if (p1d == q2d) { + sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q2); + if (sec > 0.0) + ret = 1; + else + ret = 2; /* indeterminate */ + } + xmlSchemaFreeValue(p1); + xmlSchemaFreeValue(q1); + xmlSchemaFreeValue(q2); + if (ret != 0) + return(ret); + } + } else { + xmlSchemaFreeValue(p1); + xmlSchemaFreeValue(q1); + } + } + } else if (y->value.date.tz_flag) { + q1 = xmlSchemaDateNormalize(y, 0); + q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day; + + /* normalize x - 14:00 */ + p1 = xmlSchemaDateNormalize(x, -(14 * SECS_PER_HOUR)); + p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day; + + if (p1d < q1d) { + xmlSchemaFreeValue(p1); + xmlSchemaFreeValue(q1); + return -1; + } else if (p1d == q1d) { + double sec; + + sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1); + if (sec < 0.0) { + xmlSchemaFreeValue(p1); + xmlSchemaFreeValue(q1); + return -1; + } else { + int ret = 0; + /* normalize x + 14:00 */ + p2 = xmlSchemaDateNormalize(x, (14 * SECS_PER_HOUR)); + p2d = _xmlSchemaDateCastYMToDays(p2) + p2->value.date.day; + + if (p2d > q1d) { + ret = 1; + } else if (p2d == q1d) { + sec = TIME_TO_NUMBER(p2) - TIME_TO_NUMBER(q1); + if (sec > 0.0) + ret = 1; + else + ret = 2; /* indeterminate */ + } + xmlSchemaFreeValue(p1); + xmlSchemaFreeValue(q1); + xmlSchemaFreeValue(p2); + if (ret != 0) + return(ret); + } + } else { + xmlSchemaFreeValue(p1); + xmlSchemaFreeValue(q1); + } + } + + /* + * if the same type then calculate the difference + */ + if (x->type == y->type) { + int ret = 0; + q1 = xmlSchemaDateNormalize(y, 0); + q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day; + + p1 = xmlSchemaDateNormalize(x, 0); + p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day; + + if (p1d < q1d) { + ret = -1; + } else if (p1d > q1d) { + ret = 1; + } else { + double sec; + + sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1); + if (sec < 0.0) + ret = -1; + else if (sec > 0.0) + ret = 1; + + } + xmlSchemaFreeValue(p1); + xmlSchemaFreeValue(q1); + return(ret); + } + + switch (x->type) { + case XML_SCHEMAS_DATETIME: + xmask = 0xf; + break; + case XML_SCHEMAS_DATE: + xmask = 0x7; + break; + case XML_SCHEMAS_GYEAR: + xmask = 0x1; + break; + case XML_SCHEMAS_GMONTH: + xmask = 0x2; + break; + case XML_SCHEMAS_GDAY: + xmask = 0x3; + break; + case XML_SCHEMAS_GYEARMONTH: + xmask = 0x3; + break; + case XML_SCHEMAS_GMONTHDAY: + xmask = 0x6; + break; + case XML_SCHEMAS_TIME: + xmask = 0x8; + break; + default: + xmask = 0; + break; + } + + switch (y->type) { + case XML_SCHEMAS_DATETIME: + ymask = 0xf; + break; + case XML_SCHEMAS_DATE: + ymask = 0x7; + break; + case XML_SCHEMAS_GYEAR: + ymask = 0x1; + break; + case XML_SCHEMAS_GMONTH: + ymask = 0x2; + break; + case XML_SCHEMAS_GDAY: + ymask = 0x3; + break; + case XML_SCHEMAS_GYEARMONTH: + ymask = 0x3; + break; + case XML_SCHEMAS_GMONTHDAY: + ymask = 0x6; + break; + case XML_SCHEMAS_TIME: + ymask = 0x8; + break; + default: + ymask = 0; + break; + } + + xor_mask = xmask ^ ymask; /* mark type differences */ + and_mask = xmask & ymask; /* mark field specification */ + + /* year */ + if (xor_mask & 1) + return 2; /* indeterminate */ + else if (and_mask & 1) { + if (x->value.date.year < y->value.date.year) + return -1; + else if (x->value.date.year > y->value.date.year) + return 1; + } + + /* month */ + if (xor_mask & 2) + return 2; /* indeterminate */ + else if (and_mask & 2) { + if (x->value.date.mon < y->value.date.mon) + return -1; + else if (x->value.date.mon > y->value.date.mon) + return 1; + } + + /* day */ + if (xor_mask & 4) + return 2; /* indeterminate */ + else if (and_mask & 4) { + if (x->value.date.day < y->value.date.day) + return -1; + else if (x->value.date.day > y->value.date.day) + return 1; + } + + /* time */ + if (xor_mask & 8) + return 2; /* indeterminate */ + else if (and_mask & 8) { + if (x->value.date.hour < y->value.date.hour) + return -1; + else if (x->value.date.hour > y->value.date.hour) + return 1; + else if (x->value.date.min < y->value.date.min) + return -1; + else if (x->value.date.min > y->value.date.min) + return 1; + else if (x->value.date.sec < y->value.date.sec) + return -1; + else if (x->value.date.sec > y->value.date.sec) + return 1; + } + + return 0; +} + +/** + * xmlSchemaComparePreserveReplaceStrings: + * @x: a first string value + * @y: a second string value + * @invert: inverts the result if x < y or x > y. + * + * Compare 2 string for their normalized values. + * @x is a string with whitespace of "preserve", @y is + * a string with a whitespace of "replace". I.e. @x could + * be an "xsd:string" and @y an "xsd:normalizedString". + * + * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in + * case of error + */ +static int +xmlSchemaComparePreserveReplaceStrings(const xmlChar *x, + const xmlChar *y, + int invert) +{ + int tmp; + + while ((*x != 0) && (*y != 0)) { + if (IS_WSP_REPLACE_CH(*y)) { + if (! IS_WSP_SPACE_CH(*x)) { + if ((*x - 0x20) < 0) { + if (invert) + return(1); + else + return(-1); + } else { + if (invert) + return(-1); + else + return(1); + } + } + } else { + tmp = *x - *y; + if (tmp < 0) { + if (invert) + return(1); + else + return(-1); + } + if (tmp > 0) { + if (invert) + return(-1); + else + return(1); + } + } + x++; + y++; + } + if (*x != 0) { + if (invert) + return(-1); + else + return(1); + } + if (*y != 0) { + if (invert) + return(1); + else + return(-1); + } + return(0); +} + +/** + * xmlSchemaComparePreserveCollapseStrings: + * @x: a first string value + * @y: a second string value + * + * Compare 2 string for their normalized values. + * @x is a string with whitespace of "preserve", @y is + * a string with a whitespace of "collapse". I.e. @x could + * be an "xsd:string" and @y an "xsd:normalizedString". + * + * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in + * case of error + */ +static int +xmlSchemaComparePreserveCollapseStrings(const xmlChar *x, + const xmlChar *y, + int invert) +{ + int tmp; + + /* + * Skip leading blank chars of the collapsed string. + */ + while IS_WSP_BLANK_CH(*y) + y++; + + while ((*x != 0) && (*y != 0)) { + if IS_WSP_BLANK_CH(*y) { + if (! IS_WSP_SPACE_CH(*x)) { + /* + * The yv character would have been replaced to 0x20. + */ + if ((*x - 0x20) < 0) { + if (invert) + return(1); + else + return(-1); + } else { + if (invert) + return(-1); + else + return(1); + } + } + x++; + y++; + /* + * Skip contiguous blank chars of the collapsed string. + */ + while IS_WSP_BLANK_CH(*y) + y++; + } else { + tmp = *x++ - *y++; + if (tmp < 0) { + if (invert) + return(1); + else + return(-1); + } + if (tmp > 0) { + if (invert) + return(-1); + else + return(1); + } + } + } + if (*x != 0) { + if (invert) + return(-1); + else + return(1); + } + if (*y != 0) { + /* + * Skip trailing blank chars of the collapsed string. + */ + while IS_WSP_BLANK_CH(*y) + y++; + if (*y != 0) { + if (invert) + return(1); + else + return(-1); + } + } + return(0); +} + +/** + * xmlSchemaComparePreserveCollapseStrings: + * @x: a first string value + * @y: a second string value + * + * Compare 2 string for their normalized values. + * @x is a string with whitespace of "preserve", @y is + * a string with a whitespace of "collapse". I.e. @x could + * be an "xsd:string" and @y an "xsd:normalizedString". + * + * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in + * case of error + */ +static int +xmlSchemaCompareReplaceCollapseStrings(const xmlChar *x, + const xmlChar *y, + int invert) +{ + int tmp; + + /* + * Skip leading blank chars of the collapsed string. + */ + while IS_WSP_BLANK_CH(*y) + y++; + + while ((*x != 0) && (*y != 0)) { + if IS_WSP_BLANK_CH(*y) { + if (! IS_WSP_BLANK_CH(*x)) { + /* + * The yv character would have been replaced to 0x20. + */ + if ((*x - 0x20) < 0) { + if (invert) + return(1); + else + return(-1); + } else { + if (invert) + return(-1); + else + return(1); + } + } + x++; + y++; + /* + * Skip contiguous blank chars of the collapsed string. + */ + while IS_WSP_BLANK_CH(*y) + y++; + } else { + if IS_WSP_BLANK_CH(*x) { + /* + * The xv character would have been replaced to 0x20. + */ + if ((0x20 - *y) < 0) { + if (invert) + return(1); + else + return(-1); + } else { + if (invert) + return(-1); + else + return(1); + } + } + tmp = *x++ - *y++; + if (tmp < 0) + return(-1); + if (tmp > 0) + return(1); + } + } + if (*x != 0) { + if (invert) + return(-1); + else + return(1); + } + if (*y != 0) { + /* + * Skip trailing blank chars of the collapsed string. + */ + while IS_WSP_BLANK_CH(*y) + y++; + if (*y != 0) { + if (invert) + return(1); + else + return(-1); + } + } + return(0); +} + + +/** + * xmlSchemaCompareReplacedStrings: + * @x: a first string value + * @y: a second string value + * + * Compare 2 string for their normalized values. + * + * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in + * case of error + */ +static int +xmlSchemaCompareReplacedStrings(const xmlChar *x, + const xmlChar *y) +{ + int tmp; + + while ((*x != 0) && (*y != 0)) { + if IS_WSP_BLANK_CH(*y) { + if (! IS_WSP_BLANK_CH(*x)) { + if ((*x - 0x20) < 0) + return(-1); + else + return(1); + } + } else { + if IS_WSP_BLANK_CH(*x) { + if ((0x20 - *y) < 0) + return(-1); + else + return(1); + } + tmp = *x - *y; + if (tmp < 0) + return(-1); + if (tmp > 0) + return(1); + } + x++; + y++; + } + if (*x != 0) + return(1); + if (*y != 0) + return(-1); + return(0); +} + +/** + * xmlSchemaCompareNormStrings: + * @x: a first string value + * @y: a second string value + * + * Compare 2 string for their normalized values. + * + * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in + * case of error + */ +static int +xmlSchemaCompareNormStrings(const xmlChar *x, + const xmlChar *y) { + int tmp; + + while (IS_BLANK_CH(*x)) x++; + while (IS_BLANK_CH(*y)) y++; + while ((*x != 0) && (*y != 0)) { + if (IS_BLANK_CH(*x)) { + if (!IS_BLANK_CH(*y)) { + tmp = *x - *y; + return(tmp); + } + while (IS_BLANK_CH(*x)) x++; + while (IS_BLANK_CH(*y)) y++; + } else { + tmp = *x++ - *y++; + if (tmp < 0) + return(-1); + if (tmp > 0) + return(1); + } + } + if (*x != 0) { + while (IS_BLANK_CH(*x)) x++; + if (*x != 0) + return(1); + } + if (*y != 0) { + while (IS_BLANK_CH(*y)) y++; + if (*y != 0) + return(-1); + } + return(0); +} + +/** + * xmlSchemaCompareFloats: + * @x: a first float or double value + * @y: a second float or double value + * + * Compare 2 values + * + * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in + * case of error + */ +static int +xmlSchemaCompareFloats(xmlSchemaValPtr x, xmlSchemaValPtr y) { + double d1, d2; + + if ((x == NULL) || (y == NULL)) + return(-2); + + /* + * Cast everything to doubles. + */ + if (x->type == XML_SCHEMAS_DOUBLE) + d1 = x->value.d; + else if (x->type == XML_SCHEMAS_FLOAT) + d1 = x->value.f; + else + return(-2); + + if (y->type == XML_SCHEMAS_DOUBLE) + d2 = y->value.d; + else if (y->type == XML_SCHEMAS_FLOAT) + d2 = y->value.f; + else + return(-2); + + /* + * Check for special cases. + */ + if (xmlXPathIsNaN(d1)) { + if (xmlXPathIsNaN(d2)) + return(0); + return(1); + } + if (xmlXPathIsNaN(d2)) + return(-1); + if (d1 == xmlXPathPINF) { + if (d2 == xmlXPathPINF) + return(0); + return(1); + } + if (d2 == xmlXPathPINF) + return(-1); + if (d1 == xmlXPathNINF) { + if (d2 == xmlXPathNINF) + return(0); + return(-1); + } + if (d2 == xmlXPathNINF) + return(1); + + /* + * basic tests, the last one we should have equality, but + * portability is more important than speed and handling + * NaN or Inf in a portable way is always a challenge, so ... + */ + if (d1 < d2) + return(-1); + if (d1 > d2) + return(1); + if (d1 == d2) + return(0); + return(2); +} + +/** + * xmlSchemaCompareValues: + * @x: a first value + * @xvalue: the first value as a string (optional) + * @xwtsp: the whitespace type + * @y: a second value + * @xvalue: the second value as a string (optional) + * @ywtsp: the whitespace type + * + * Compare 2 values + * + * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, 3 if not + * comparable and -2 in case of error + */ +static int +xmlSchemaCompareValuesInternal(xmlSchemaValType xtype, + xmlSchemaValPtr x, + const xmlChar *xvalue, + xmlSchemaWhitespaceValueType xws, + xmlSchemaValType ytype, + xmlSchemaValPtr y, + const xmlChar *yvalue, + xmlSchemaWhitespaceValueType yws) +{ + switch (xtype) { + case XML_SCHEMAS_UNKNOWN: + case XML_SCHEMAS_ANYTYPE: + return(-2); + case XML_SCHEMAS_INTEGER: + case XML_SCHEMAS_NPINTEGER: + case XML_SCHEMAS_NINTEGER: + case XML_SCHEMAS_NNINTEGER: + case XML_SCHEMAS_PINTEGER: + 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: + case XML_SCHEMAS_DECIMAL: + if ((x == NULL) || (y == NULL)) + return(-2); + if (ytype == xtype) + return(xmlSchemaCompareDecimals(x, y)); + if ((ytype == XML_SCHEMAS_DECIMAL) || + (ytype == XML_SCHEMAS_INTEGER) || + (ytype == XML_SCHEMAS_NPINTEGER) || + (ytype == XML_SCHEMAS_NINTEGER) || + (ytype == XML_SCHEMAS_NNINTEGER) || + (ytype == XML_SCHEMAS_PINTEGER) || + (ytype == XML_SCHEMAS_INT) || + (ytype == XML_SCHEMAS_UINT) || + (ytype == XML_SCHEMAS_LONG) || + (ytype == XML_SCHEMAS_ULONG) || + (ytype == XML_SCHEMAS_SHORT) || + (ytype == XML_SCHEMAS_USHORT) || + (ytype == XML_SCHEMAS_BYTE) || + (ytype == XML_SCHEMAS_UBYTE)) + return(xmlSchemaCompareDecimals(x, y)); + return(-2); + case XML_SCHEMAS_DURATION: + if ((x == NULL) || (y == NULL)) + return(-2); + if (ytype == XML_SCHEMAS_DURATION) + return(xmlSchemaCompareDurations(x, y)); + return(-2); + case XML_SCHEMAS_TIME: + case XML_SCHEMAS_GDAY: + case XML_SCHEMAS_GMONTH: + case XML_SCHEMAS_GMONTHDAY: + case XML_SCHEMAS_GYEAR: + case XML_SCHEMAS_GYEARMONTH: + case XML_SCHEMAS_DATE: + case XML_SCHEMAS_DATETIME: + if ((x == NULL) || (y == NULL)) + return(-2); + if ((ytype == XML_SCHEMAS_DATETIME) || + (ytype == XML_SCHEMAS_TIME) || + (ytype == XML_SCHEMAS_GDAY) || + (ytype == XML_SCHEMAS_GMONTH) || + (ytype == XML_SCHEMAS_GMONTHDAY) || + (ytype == XML_SCHEMAS_GYEAR) || + (ytype == XML_SCHEMAS_DATE) || + (ytype == XML_SCHEMAS_GYEARMONTH)) + return (xmlSchemaCompareDates(x, y)); + return (-2); + /* + * Note that we will support comparison of string types against + * anySimpleType as well. + */ + case XML_SCHEMAS_ANYSIMPLETYPE: + case XML_SCHEMAS_STRING: + case XML_SCHEMAS_NORMSTRING: + case XML_SCHEMAS_TOKEN: + case XML_SCHEMAS_LANGUAGE: + case XML_SCHEMAS_NMTOKEN: + case XML_SCHEMAS_NAME: + case XML_SCHEMAS_NCNAME: + case XML_SCHEMAS_ID: + case XML_SCHEMAS_IDREF: + case XML_SCHEMAS_ENTITY: + case XML_SCHEMAS_ANYURI: + { + const xmlChar *xv, *yv; + + if (x == NULL) + xv = xvalue; + else + xv = x->value.str; + if (y == NULL) + yv = yvalue; + else + yv = y->value.str; + /* + * TODO: Compare those against QName. + */ + if (ytype == XML_SCHEMAS_QNAME) { + TODO + if (y == NULL) + return(-2); + return (-2); + } + if ((ytype == XML_SCHEMAS_ANYSIMPLETYPE) || + (ytype == XML_SCHEMAS_STRING) || + (ytype == XML_SCHEMAS_NORMSTRING) || + (ytype == XML_SCHEMAS_TOKEN) || + (ytype == XML_SCHEMAS_LANGUAGE) || + (ytype == XML_SCHEMAS_NMTOKEN) || + (ytype == XML_SCHEMAS_NAME) || + (ytype == XML_SCHEMAS_NCNAME) || + (ytype == XML_SCHEMAS_ID) || + (ytype == XML_SCHEMAS_IDREF) || + (ytype == XML_SCHEMAS_ENTITY) || + (ytype == XML_SCHEMAS_ANYURI)) { + + if (xws == XML_SCHEMA_WHITESPACE_PRESERVE) { + + if (yws == XML_SCHEMA_WHITESPACE_PRESERVE) { + /* TODO: What about x < y or x > y. */ + if (xmlStrEqual(xv, yv)) + return (0); + else + return (2); + } else if (yws == XML_SCHEMA_WHITESPACE_REPLACE) + return (xmlSchemaComparePreserveReplaceStrings(xv, yv, 0)); + else if (yws == XML_SCHEMA_WHITESPACE_COLLAPSE) + return (xmlSchemaComparePreserveCollapseStrings(xv, yv, 0)); + + } else if (xws == XML_SCHEMA_WHITESPACE_REPLACE) { + + if (yws == XML_SCHEMA_WHITESPACE_PRESERVE) + return (xmlSchemaComparePreserveReplaceStrings(yv, xv, 1)); + if (yws == XML_SCHEMA_WHITESPACE_REPLACE) + return (xmlSchemaCompareReplacedStrings(xv, yv)); + if (yws == XML_SCHEMA_WHITESPACE_COLLAPSE) + return (xmlSchemaCompareReplaceCollapseStrings(xv, yv, 0)); + + } else if (xws == XML_SCHEMA_WHITESPACE_COLLAPSE) { + + if (yws == XML_SCHEMA_WHITESPACE_PRESERVE) + return (xmlSchemaComparePreserveCollapseStrings(yv, xv, 1)); + if (yws == XML_SCHEMA_WHITESPACE_REPLACE) + return (xmlSchemaCompareReplaceCollapseStrings(yv, xv, 1)); + if (yws == XML_SCHEMA_WHITESPACE_COLLAPSE) + return (xmlSchemaCompareNormStrings(xv, yv)); + } else + return (-2); + + } + return (-2); + } + case XML_SCHEMAS_QNAME: + case XML_SCHEMAS_NOTATION: + if ((x == NULL) || (y == NULL)) + return(-2); + if ((ytype == XML_SCHEMAS_QNAME) || + (ytype == XML_SCHEMAS_NOTATION)) { + if ((xmlStrEqual(x->value.qname.name, y->value.qname.name)) && + (xmlStrEqual(x->value.qname.uri, y->value.qname.uri))) + return(0); + return(2); + } + return (-2); + case XML_SCHEMAS_FLOAT: + case XML_SCHEMAS_DOUBLE: + if ((x == NULL) || (y == NULL)) + return(-2); + if ((ytype == XML_SCHEMAS_FLOAT) || + (ytype == XML_SCHEMAS_DOUBLE)) + return (xmlSchemaCompareFloats(x, y)); + return (-2); + case XML_SCHEMAS_BOOLEAN: + if ((x == NULL) || (y == NULL)) + return(-2); + if (ytype == XML_SCHEMAS_BOOLEAN) { + if (x->value.b == y->value.b) + return(0); + if (x->value.b == 0) + return(-1); + return(1); + } + return (-2); + case XML_SCHEMAS_HEXBINARY: + if ((x == NULL) || (y == NULL)) + return(-2); + if (ytype == XML_SCHEMAS_HEXBINARY) { + if (x->value.hex.total == y->value.hex.total) { + int ret = xmlStrcmp(x->value.hex.str, y->value.hex.str); + if (ret > 0) + return(1); + else if (ret == 0) + return(0); + } + else if (x->value.hex.total > y->value.hex.total) + return(1); + + return(-1); + } + return (-2); + case XML_SCHEMAS_BASE64BINARY: + if ((x == NULL) || (y == NULL)) + return(-2); + if (ytype == XML_SCHEMAS_BASE64BINARY) { + if (x->value.base64.total == y->value.base64.total) { + int ret = xmlStrcmp(x->value.base64.str, + y->value.base64.str); + if (ret > 0) + return(1); + else if (ret == 0) + return(0); + else + return(-1); + } + else if (x->value.base64.total > y->value.base64.total) + return(1); + else + return(-1); + } + return (-2); + case XML_SCHEMAS_IDREFS: + case XML_SCHEMAS_ENTITIES: + case XML_SCHEMAS_NMTOKENS: + TODO + break; + } + return -2; +} + +/** + * xmlSchemaCompareValues: + * @x: a first value + * @y: a second value + * + * Compare 2 values + * + * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in + * case of error + */ +int +xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) { + xmlSchemaWhitespaceValueType xws, yws; + + if ((x == NULL) || (y == NULL)) + return(-2); + if (x->type == XML_SCHEMAS_STRING) + xws = XML_SCHEMA_WHITESPACE_PRESERVE; + else if (x->type == XML_SCHEMAS_NORMSTRING) + xws = XML_SCHEMA_WHITESPACE_REPLACE; + else + xws = XML_SCHEMA_WHITESPACE_COLLAPSE; + + if (y->type == XML_SCHEMAS_STRING) + yws = XML_SCHEMA_WHITESPACE_PRESERVE; + else if (x->type == XML_SCHEMAS_NORMSTRING) + yws = XML_SCHEMA_WHITESPACE_REPLACE; + else + yws = XML_SCHEMA_WHITESPACE_COLLAPSE; + + return(xmlSchemaCompareValuesInternal(x->type, x, NULL, xws, y->type, + y, NULL, yws)); +} + +/** + * xmlSchemaCompareValuesWhtsp: + * @x: a first value + * @xws: the whitespace value of x + * @y: a second value + * @yws: the whitespace value of y + * + * Compare 2 values + * + * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in + * case of error + */ +int +xmlSchemaCompareValuesWhtsp(xmlSchemaValPtr x, + xmlSchemaWhitespaceValueType xws, + xmlSchemaValPtr y, + xmlSchemaWhitespaceValueType yws) +{ + if ((x == NULL) || (y == NULL)) + return(-2); + return(xmlSchemaCompareValuesInternal(x->type, x, NULL, xws, y->type, + y, NULL, yws)); +} + +/** + * xmlSchemaCompareValuesWhtspExt: + * @x: a first value + * @xws: the whitespace value of x + * @y: a second value + * @yws: the whitespace value of y + * + * Compare 2 values + * + * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in + * case of error + */ +static int +xmlSchemaCompareValuesWhtspExt(xmlSchemaValType xtype, + xmlSchemaValPtr x, + const xmlChar *xvalue, + xmlSchemaWhitespaceValueType xws, + xmlSchemaValType ytype, + xmlSchemaValPtr y, + const xmlChar *yvalue, + xmlSchemaWhitespaceValueType yws) +{ + return(xmlSchemaCompareValuesInternal(xtype, x, xvalue, xws, ytype, y, + yvalue, yws)); +} + +/** + * xmlSchemaNormLen: + * @value: a string + * + * Computes the UTF8 length of the normalized value of the string + * + * Returns the length or -1 in case of error. + */ +static int +xmlSchemaNormLen(const xmlChar *value) { + const xmlChar *utf; + int ret = 0; + + if (value == NULL) + return(-1); + utf = value; + while (IS_BLANK_CH(*utf)) utf++; + while (*utf != 0) { + if (utf[0] & 0x80) { + if ((utf[1] & 0xc0) != 0x80) + return(-1); + if ((utf[0] & 0xe0) == 0xe0) { + if ((utf[2] & 0xc0) != 0x80) + return(-1); + if ((utf[0] & 0xf0) == 0xf0) { + if ((utf[0] & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80) + return(-1); + utf += 4; + } else { + utf += 3; + } + } else { + utf += 2; + } + } else if (IS_BLANK_CH(*utf)) { + while (IS_BLANK_CH(*utf)) utf++; + if (*utf == 0) + break; + } else { + utf++; + } + ret++; + } + return(ret); +} + +/** + * xmlSchemaGetFacetValueAsULong: + * @facet: an schemas type facet + * + * Extract the value of a facet + * + * Returns the value as a long + */ +unsigned long +xmlSchemaGetFacetValueAsULong(xmlSchemaFacetPtr facet) +{ + /* + * TODO: Check if this is a decimal. + */ + if (facet == NULL) + return 0; + return ((unsigned long) facet->val->value.decimal.lo); +} + +/** + * xmlSchemaValidateListSimpleTypeFacet: + * @facet: the facet to check + * @value: the lexical repr of the value to validate + * @actualLen: the number of list items + * @expectedLen: the resulting expected number of list items + * + * Checks the value of a list simple type against a facet. + * + * Returns 0 if the value is valid, a positive error code + * number otherwise and -1 in case of an internal error. + */ +int +xmlSchemaValidateListSimpleTypeFacet(xmlSchemaFacetPtr facet, + const xmlChar *value, + unsigned long actualLen, + unsigned long *expectedLen) +{ + if (facet == NULL) + return(-1); + /* + * TODO: Check if this will work with large numbers. + * (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 (expectedLen != NULL) + *expectedLen = facet->val->value.decimal.lo; + return (XML_SCHEMAV_CVC_LENGTH_VALID); + } + } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) { + if (actualLen < facet->val->value.decimal.lo) { + if (expectedLen != NULL) + *expectedLen = facet->val->value.decimal.lo; + return (XML_SCHEMAV_CVC_MINLENGTH_VALID); + } + } else if (facet->type == XML_SCHEMA_FACET_MAXLENGTH) { + if (actualLen > facet->val->value.decimal.lo) { + if (expectedLen != NULL) + *expectedLen = facet->val->value.decimal.lo; + return (XML_SCHEMAV_CVC_MAXLENGTH_VALID); + } + } else + /* + * NOTE: That we can pass NULL as xmlSchemaValPtr to + * xmlSchemaValidateFacet, since the remaining facet types + * are: XML_SCHEMA_FACET_PATTERN, XML_SCHEMA_FACET_ENUMERATION. + */ + return(xmlSchemaValidateFacet(NULL, facet, value, NULL)); + return (0); +} + +/** + * xmlSchemaValidateLengthFacet: + * @type: the built-in type + * @facet: the facet to check + * @value: the lexical repr. of the value to be validated + * @val: the precomputed value + * @ws: the whitespace type of the value + * @length: the actual length of the value + * + * Checka a value against a "length", "minLength" and "maxLength" + * facet; sets @length to the computed length of @value. + * + * Returns 0 if the value is valid, a positive error code + * otherwise and -1 in case of an internal or API error. + */ +static int +xmlSchemaValidateLengthFacetInternal(xmlSchemaFacetPtr facet, + xmlSchemaTypeType valType, + const xmlChar *value, + xmlSchemaValPtr val, + unsigned long *length, + xmlSchemaWhitespaceValueType ws) +{ + unsigned int len = 0; + + if ((length == NULL) || (facet == NULL)) + return (-1); + *length = 0; + if ((facet->type != XML_SCHEMA_FACET_LENGTH) && + (facet->type != XML_SCHEMA_FACET_MAXLENGTH) && + (facet->type != XML_SCHEMA_FACET_MINLENGTH)) + return (-1); + + /* + * TODO: length, maxLength and minLength must be of type + * nonNegativeInteger only. Check if decimal is used somehow. + */ + if ((facet->val == NULL) || + ((facet->val->type != XML_SCHEMAS_DECIMAL) && + (facet->val->type != XML_SCHEMAS_NNINTEGER)) || + (facet->val->value.decimal.frac != 0)) { + return(-1); + } + if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY)) + len = val->value.hex.total; + else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY)) + len = val->value.base64.total; + else { + switch (valType) { + case XML_SCHEMAS_STRING: + case XML_SCHEMAS_NORMSTRING: + if (ws == XML_SCHEMA_WHITESPACE_UNKNOWN) { + /* + * This is to ensure API compatibility with the old + * xmlSchemaValidateLengthFacet(). Anyway, this was and + * is not the correct handling. + * TODO: Get rid of this case somehow. + */ + if (valType == XML_SCHEMAS_STRING) + len = xmlUTF8Strlen(value); + else + len = xmlSchemaNormLen(value); + } else if (value != NULL) { + if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE) + len = xmlSchemaNormLen(value); + else + /* + * Should be OK for "preserve" as well. + */ + len = xmlUTF8Strlen(value); + } + break; + case XML_SCHEMAS_IDREF: + case XML_SCHEMAS_TOKEN: + case XML_SCHEMAS_LANGUAGE: + case XML_SCHEMAS_NMTOKEN: + case XML_SCHEMAS_NAME: + case XML_SCHEMAS_NCNAME: + case XML_SCHEMAS_ID: + /* + * FIXME: What exactly to do with anyURI? + */ + case XML_SCHEMAS_ANYURI: + if (value != NULL) + len = xmlSchemaNormLen(value); + break; + case XML_SCHEMAS_QNAME: + case XML_SCHEMAS_NOTATION: + /* + * For QName and NOTATION, those facets are + * deprecated and should be ignored. + */ + return (0); + default: + TODO + } + } + *length = (unsigned long) len; + /* + * TODO: Return the whole expected value, i.e. "lo", "mi" and "hi". + */ + if (facet->type == XML_SCHEMA_FACET_LENGTH) { + if (len != facet->val->value.decimal.lo) + return(XML_SCHEMAV_CVC_LENGTH_VALID); + } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) { + if (len < facet->val->value.decimal.lo) + return(XML_SCHEMAV_CVC_MINLENGTH_VALID); + } else { + if (len > facet->val->value.decimal.lo) + return(XML_SCHEMAV_CVC_MAXLENGTH_VALID); + } + + return (0); +} + +/** + * xmlSchemaValidateLengthFacet: + * @type: the built-in type + * @facet: the facet to check + * @value: the lexical repr. of the value to be validated + * @val: the precomputed value + * @length: the actual length of the value + * + * Checka a value against a "length", "minLength" and "maxLength" + * facet; sets @length to the computed length of @value. + * + * Returns 0 if the value is valid, a positive error code + * otherwise and -1 in case of an internal or API error. + */ +int +xmlSchemaValidateLengthFacet(xmlSchemaTypePtr type, + xmlSchemaFacetPtr facet, + const xmlChar *value, + xmlSchemaValPtr val, + unsigned long *length) +{ + if (type == NULL) + return(-1); + return (xmlSchemaValidateLengthFacetInternal(facet, + type->builtInType, value, val, length, + XML_SCHEMA_WHITESPACE_UNKNOWN)); +} + +/** + * xmlSchemaValidateLengthFacetWhtsp: + * @facet: the facet to check + * @valType: the built-in type + * @value: the lexical repr. of the value to be validated + * @val: the precomputed value + * @ws: the whitespace type of the value + * @length: the actual length of the value + * + * Checka a value against a "length", "minLength" and "maxLength" + * facet; sets @length to the computed length of @value. + * + * Returns 0 if the value is valid, a positive error code + * otherwise and -1 in case of an internal or API error. + */ +int +xmlSchemaValidateLengthFacetWhtsp(xmlSchemaFacetPtr facet, + xmlSchemaValType valType, + const xmlChar *value, + xmlSchemaValPtr val, + unsigned long *length, + xmlSchemaWhitespaceValueType ws) +{ + return (xmlSchemaValidateLengthFacetInternal(facet, valType, value, val, + length, ws)); +} + +/** + * xmlSchemaValidateFacetInternal: + * @facet: the facet to check + * @fws: the whitespace type of the facet's value + * @valType: the built-in type of the value + * @value: the lexical repr of the value to validate + * @val: the precomputed value + * @ws: the whitespace type of the value + * + * Check a value against a facet condition + * + * Returns 0 if the element is schemas valid, a positive error code + * number otherwise and -1 in case of internal or API error. + */ +static int +xmlSchemaValidateFacetInternal(xmlSchemaFacetPtr facet, + xmlSchemaWhitespaceValueType fws, + xmlSchemaValType valType, + const xmlChar *value, + xmlSchemaValPtr val, + xmlSchemaWhitespaceValueType ws) +{ + int ret; + + if (facet == NULL) + return(-1); + + switch (facet->type) { + case XML_SCHEMA_FACET_PATTERN: + /* + * NOTE that for patterns, the @value needs to be the normalized + * value, *not* the lexical initial value or the canonical value. + */ + if (value == NULL) + return(-1); + ret = xmlRegexpExec(facet->regexp, value); + if (ret == 1) + return(0); + if (ret == 0) + return(XML_SCHEMAV_CVC_PATTERN_VALID); + return(ret); + case XML_SCHEMA_FACET_MAXEXCLUSIVE: + ret = xmlSchemaCompareValues(val, facet->val); + if (ret == -2) + return(-1); + if (ret == -1) + return(0); + return(XML_SCHEMAV_CVC_MAXEXCLUSIVE_VALID); + case XML_SCHEMA_FACET_MAXINCLUSIVE: + ret = xmlSchemaCompareValues(val, facet->val); + if (ret == -2) + return(-1); + if ((ret == -1) || (ret == 0)) + return(0); + return(XML_SCHEMAV_CVC_MAXINCLUSIVE_VALID); + case XML_SCHEMA_FACET_MINEXCLUSIVE: + ret = xmlSchemaCompareValues(val, facet->val); + if (ret == -2) + return(-1); + if (ret == 1) + return(0); + return(XML_SCHEMAV_CVC_MINEXCLUSIVE_VALID); + case XML_SCHEMA_FACET_MININCLUSIVE: + ret = xmlSchemaCompareValues(val, facet->val); + if (ret == -2) + return(-1); + if ((ret == 1) || (ret == 0)) + return(0); + return(XML_SCHEMAV_CVC_MININCLUSIVE_VALID); + case XML_SCHEMA_FACET_WHITESPACE: + /* TODO whitespaces */ + /* + * NOTE: Whitespace should be handled to normalize + * the value to be validated against a the facets; + * not to normalize the value in-between. + */ + return(0); + case XML_SCHEMA_FACET_ENUMERATION: + if (ws == XML_SCHEMA_WHITESPACE_UNKNOWN) { + /* + * This is to ensure API compatibility with the old + * xmlSchemaValidateFacet(). + * TODO: Get rid of this case. + */ + if ((facet->value != NULL) && + (xmlStrEqual(facet->value, value))) + return(0); + } else { + ret = xmlSchemaCompareValuesWhtspExt(facet->val->type, + facet->val, facet->value, fws, valType, val, + value, ws); + if (ret == -2) + return(-1); + if (ret == 0) + return(0); + } + return(XML_SCHEMAV_CVC_ENUMERATION_VALID); + case XML_SCHEMA_FACET_LENGTH: + /* + * SPEC (1.3) "if {primitive type definition} is QName or NOTATION, + * then any {value} is facet-valid." + */ + if ((valType == XML_SCHEMAS_QNAME) || + (valType == XML_SCHEMAS_NOTATION)) + return (0); + /* No break on purpose. */ + case XML_SCHEMA_FACET_MAXLENGTH: + case XML_SCHEMA_FACET_MINLENGTH: { + unsigned int len = 0; + + if ((valType == XML_SCHEMAS_QNAME) || + (valType == XML_SCHEMAS_NOTATION)) + return (0); + /* + * TODO: length, maxLength and minLength must be of type + * nonNegativeInteger only. Check if decimal is used somehow. + */ + if ((facet->val == NULL) || + ((facet->val->type != XML_SCHEMAS_DECIMAL) && + (facet->val->type != XML_SCHEMAS_NNINTEGER)) || + (facet->val->value.decimal.frac != 0)) { + return(-1); + } + if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY)) + len = val->value.hex.total; + else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY)) + len = val->value.base64.total; + else { + switch (valType) { + case XML_SCHEMAS_STRING: + case XML_SCHEMAS_NORMSTRING: + if (ws == XML_SCHEMA_WHITESPACE_UNKNOWN) { + /* + * This is to ensure API compatibility with the old + * xmlSchemaValidateFacet(). Anyway, this was and + * is not the correct handling. + * TODO: Get rid of this case somehow. + */ + if (valType == XML_SCHEMAS_STRING) + len = xmlUTF8Strlen(value); + else + len = xmlSchemaNormLen(value); + } else if (value != NULL) { + if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE) + len = xmlSchemaNormLen(value); + else + /* + * Should be OK for "preserve" as well. + */ + len = xmlUTF8Strlen(value); + } + break; + case XML_SCHEMAS_IDREF: + case XML_SCHEMAS_TOKEN: + case XML_SCHEMAS_LANGUAGE: + case XML_SCHEMAS_NMTOKEN: + case XML_SCHEMAS_NAME: + case XML_SCHEMAS_NCNAME: + case XML_SCHEMAS_ID: + case XML_SCHEMAS_ANYURI: + if (value != NULL) + len = xmlSchemaNormLen(value); + break; + default: + TODO + } + } + if (facet->type == XML_SCHEMA_FACET_LENGTH) { + if (len != facet->val->value.decimal.lo) + return(XML_SCHEMAV_CVC_LENGTH_VALID); + } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) { + if (len < facet->val->value.decimal.lo) + return(XML_SCHEMAV_CVC_MINLENGTH_VALID); + } else { + if (len > facet->val->value.decimal.lo) + return(XML_SCHEMAV_CVC_MAXLENGTH_VALID); + } + break; + } + case XML_SCHEMA_FACET_TOTALDIGITS: + case XML_SCHEMA_FACET_FRACTIONDIGITS: + + if ((facet->val == NULL) || + ((facet->val->type != XML_SCHEMAS_PINTEGER) && + (facet->val->type != XML_SCHEMAS_NNINTEGER)) || + (facet->val->value.decimal.frac != 0)) { + return(-1); + } + if ((val == NULL) || + ((val->type != XML_SCHEMAS_DECIMAL) && + (val->type != XML_SCHEMAS_INTEGER) && + (val->type != XML_SCHEMAS_NPINTEGER) && + (val->type != XML_SCHEMAS_NINTEGER) && + (val->type != XML_SCHEMAS_NNINTEGER) && + (val->type != XML_SCHEMAS_PINTEGER) && + (val->type != XML_SCHEMAS_INT) && + (val->type != XML_SCHEMAS_UINT) && + (val->type != XML_SCHEMAS_LONG) && + (val->type != XML_SCHEMAS_ULONG) && + (val->type != XML_SCHEMAS_SHORT) && + (val->type != XML_SCHEMAS_USHORT) && + (val->type != XML_SCHEMAS_BYTE) && + (val->type != XML_SCHEMAS_UBYTE))) { + return(-1); + } + if (facet->type == XML_SCHEMA_FACET_TOTALDIGITS) { + if (val->value.decimal.total > facet->val->value.decimal.lo) + return(XML_SCHEMAV_CVC_TOTALDIGITS_VALID); + + } else if (facet->type == XML_SCHEMA_FACET_FRACTIONDIGITS) { + if (val->value.decimal.frac > facet->val->value.decimal.lo) + return(XML_SCHEMAV_CVC_FRACTIONDIGITS_VALID); + } + break; + default: + TODO + } + return(0); + +} + +/** + * xmlSchemaValidateFacet: + * @base: the base type + * @facet: the facet to check + * @value: the lexical repr of the value to validate + * @val: the precomputed value + * + * Check a value against a facet condition + * + * Returns 0 if the element is schemas valid, a positive error code + * number otherwise and -1 in case of internal or API error. + */ +int +xmlSchemaValidateFacet(xmlSchemaTypePtr base, + xmlSchemaFacetPtr facet, + const xmlChar *value, + xmlSchemaValPtr val) +{ + /* + * This tries to ensure API compatibility regarding the old + * xmlSchemaValidateFacet() and the new xmlSchemaValidateFacetInternal() and + * xmlSchemaValidateFacetWhtsp(). + */ + if (val != NULL) + return(xmlSchemaValidateFacetInternal(facet, + XML_SCHEMA_WHITESPACE_UNKNOWN, val->type, value, val, + XML_SCHEMA_WHITESPACE_UNKNOWN)); + else if (base != NULL) + return(xmlSchemaValidateFacetInternal(facet, + XML_SCHEMA_WHITESPACE_UNKNOWN, base->builtInType, value, val, + XML_SCHEMA_WHITESPACE_UNKNOWN)); + return(-1); +} + +/** + * xmlSchemaValidateFacetWhtsp: + * @facet: the facet to check + * @fws: the whitespace type of the facet's value + * @valType: the built-in type of the value + * @value: the lexical (or normalized for pattern) repr of the value to validate + * @val: the precomputed value + * @ws: the whitespace type of the value + * + * Check a value against a facet condition. This takes value normalization + * according to the specified whitespace types into account. + * Note that @value needs to be the *normalized* value if the facet + * is of type "pattern". + * + * Returns 0 if the element is schemas valid, a positive error code + * number otherwise and -1 in case of internal or API error. + */ +int +xmlSchemaValidateFacetWhtsp(xmlSchemaFacetPtr facet, + xmlSchemaWhitespaceValueType fws, + xmlSchemaValType valType, + const xmlChar *value, + xmlSchemaValPtr val, + xmlSchemaWhitespaceValueType ws) +{ + return(xmlSchemaValidateFacetInternal(facet, fws, valType, + value, val, ws)); +} + +#if 0 +#ifndef DBL_DIG +#define DBL_DIG 16 +#endif +#ifndef DBL_EPSILON +#define DBL_EPSILON 1E-9 +#endif + +#define INTEGER_DIGITS DBL_DIG +#define FRACTION_DIGITS (DBL_DIG + 1) +#define EXPONENT_DIGITS (3 + 2) + +/** + * xmlXPathFormatNumber: + * @number: number to format + * @buffer: output buffer + * @buffersize: size of output buffer + * + * Convert the number into a string representation. + */ +static void +xmlSchemaFormatFloat(double number, char buffer[], int buffersize) +{ + switch (xmlXPathIsInf(number)) { + case 1: + if (buffersize > (int)sizeof("INF")) + snprintf(buffer, buffersize, "INF"); + break; + case -1: + if (buffersize > (int)sizeof("-INF")) + snprintf(buffer, buffersize, "-INF"); + break; + default: + if (xmlXPathIsNaN(number)) { + if (buffersize > (int)sizeof("NaN")) + snprintf(buffer, buffersize, "NaN"); + } else if (number == 0) { + snprintf(buffer, buffersize, "0.0E0"); + } else { + /* 3 is sign, decimal point, and terminating zero */ + char work[DBL_DIG + EXPONENT_DIGITS + 3]; + int integer_place, fraction_place; + char *ptr; + char *after_fraction; + double absolute_value; + int size; + + absolute_value = fabs(number); + + /* + * Result is in work, and after_fraction points + * just past the fractional part. + * Use scientific notation + */ + integer_place = DBL_DIG + EXPONENT_DIGITS + 1; + fraction_place = DBL_DIG - 1; + snprintf(work, sizeof(work),"%*.*e", + integer_place, fraction_place, number); + after_fraction = strchr(work + DBL_DIG, 'e'); + /* Remove fractional trailing zeroes */ + ptr = after_fraction; + while (*(--ptr) == '0') + ; + if (*ptr != '.') + ptr++; + while ((*ptr++ = *after_fraction++) != 0); + + /* Finally copy result back to caller */ + size = strlen(work) + 1; + if (size > buffersize) { + work[buffersize - 1] = 0; + size = buffersize; + } + memmove(buffer, work, size); + } + break; + } +} +#endif + +/** + * xmlSchemaGetCanonValue: + * @val: the precomputed value + * @retValue: the returned value + * + * Get a the cononical lexical representation of the value. + * The caller has to FREE the returned retValue. + * + * WARNING: Some value types are not supported yet, resulting + * in a @retValue of "???". + * + * TODO: XML Schema 1.0 does not define canonical representations + * for: duration, gYearMonth, gYear, gMonthDay, gMonth, gDay, + * anyURI, QName, NOTATION. This will be fixed in XML Schema 1.1. + * + * + * Returns 0 if the value could be built, 1 if the value type is + * not supported yet and -1 in case of API errors. + */ +int +xmlSchemaGetCanonValue(xmlSchemaValPtr val, const xmlChar **retValue) +{ + if ((retValue == NULL) || (val == NULL)) + return (-1); + *retValue = NULL; + switch (val->type) { + case XML_SCHEMAS_STRING: + if (val->value.str == NULL) + *retValue = BAD_CAST xmlStrdup(BAD_CAST ""); + else + *retValue = + BAD_CAST xmlStrdup((const xmlChar *) val->value.str); + break; + case XML_SCHEMAS_NORMSTRING: + if (val->value.str == NULL) + *retValue = BAD_CAST xmlStrdup(BAD_CAST ""); + else { + *retValue = xmlSchemaWhiteSpaceReplace( + (const xmlChar *) val->value.str); + if ((*retValue) == NULL) + *retValue = BAD_CAST xmlStrdup( + (const xmlChar *) val->value.str); + } + break; + case XML_SCHEMAS_TOKEN: + case XML_SCHEMAS_LANGUAGE: + case XML_SCHEMAS_NMTOKEN: + case XML_SCHEMAS_NAME: + case XML_SCHEMAS_NCNAME: + case XML_SCHEMAS_ID: + case XML_SCHEMAS_IDREF: + case XML_SCHEMAS_ENTITY: + case XML_SCHEMAS_NOTATION: /* Unclear */ + case XML_SCHEMAS_ANYURI: /* Unclear */ + if (val->value.str == NULL) + return (-1); + *retValue = + BAD_CAST xmlSchemaCollapseString(BAD_CAST val->value.str); + if (*retValue == NULL) + *retValue = + BAD_CAST xmlStrdup((const xmlChar *) val->value.str); + break; + case XML_SCHEMAS_QNAME: + /* TODO: Unclear in XML Schema 1.0. */ + if (val->value.qname.uri == NULL) { + *retValue = BAD_CAST xmlStrdup(BAD_CAST val->value.qname.name); + return (0); + } else { + *retValue = BAD_CAST xmlStrdup(BAD_CAST "{"); + *retValue = BAD_CAST xmlStrcat((xmlChar *) (*retValue), + BAD_CAST val->value.qname.uri); + *retValue = BAD_CAST xmlStrcat((xmlChar *) (*retValue), + BAD_CAST "}"); + *retValue = BAD_CAST xmlStrcat((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; + } + break; + 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: + 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); + } + } + break; + case XML_SCHEMAS_BOOLEAN: + if (val->value.b) + *retValue = BAD_CAST xmlStrdup(BAD_CAST "true"); + else + *retValue = BAD_CAST xmlStrdup(BAD_CAST "false"); + break; + case XML_SCHEMAS_DURATION: { + char buf[100]; + unsigned long year; + unsigned long mon, day, hour = 0, min = 0; + double sec = 0, left; + + /* TODO: Unclear in XML Schema 1.0 */ + /* + * TODO: This results in a normalized output of the value + * - which is NOT conformant to the spec - + * since the exact values of each property are not + * recoverable. Think about extending the structure to + * provide a field for every property. + */ + year = (unsigned long) FQUOTIENT(labs(val->value.dur.mon), 12); + mon = labs(val->value.dur.mon) - 12 * year; + + day = (unsigned long) FQUOTIENT(fabs(val->value.dur.sec), 86400); + left = fabs(val->value.dur.sec) - day * 86400; + if (left > 0) { + hour = (unsigned long) FQUOTIENT(left, 3600); + left = left - (hour * 3600); + if (left > 0) { + min = (unsigned long) FQUOTIENT(left, 60); + sec = left - (min * 60); + } + } + if ((val->value.dur.mon < 0) || (val->value.dur.sec < 0)) + snprintf(buf, 100, "P%luY%luM%luDT%luH%luM%.14gS", + year, mon, day, hour, min, sec); + else + snprintf(buf, 100, "-P%luY%luM%luDT%luH%luM%.14gS", + year, mon, day, hour, min, sec); + *retValue = BAD_CAST xmlStrdup(BAD_CAST buf); + } + break; + case XML_SCHEMAS_GYEAR: { + char buf[30]; + /* TODO: Unclear in XML Schema 1.0 */ + /* TODO: What to do with the timezone? */ + snprintf(buf, 30, "%04ld", val->value.date.year); + *retValue = BAD_CAST xmlStrdup(BAD_CAST buf); + } + break; + case XML_SCHEMAS_GMONTH: { + /* TODO: Unclear in XML Schema 1.0 */ + /* TODO: What to do with the timezone? */ + *retValue = xmlMalloc(6); + if (*retValue == NULL) + return(-1); + snprintf((char *) *retValue, 6, "--%02u", + val->value.date.mon); + } + break; + case XML_SCHEMAS_GDAY: { + /* TODO: Unclear in XML Schema 1.0 */ + /* TODO: What to do with the timezone? */ + *retValue = xmlMalloc(6); + if (*retValue == NULL) + return(-1); + snprintf((char *) *retValue, 6, "---%02u", + val->value.date.day); + } + break; + case XML_SCHEMAS_GMONTHDAY: { + /* TODO: Unclear in XML Schema 1.0 */ + /* TODO: What to do with the timezone? */ + *retValue = xmlMalloc(8); + if (*retValue == NULL) + return(-1); + snprintf((char *) *retValue, 8, "--%02u-%02u", + val->value.date.mon, val->value.date.day); + } + break; + case XML_SCHEMAS_GYEARMONTH: { + char buf[35]; + /* TODO: Unclear in XML Schema 1.0 */ + /* TODO: What to do with the timezone? */ + if (val->value.date.year < 0) + snprintf(buf, 35, "-%04ld-%02u", + labs(val->value.date.year), + val->value.date.mon); + else + snprintf(buf, 35, "%04ld-%02u", + val->value.date.year, val->value.date.mon); + *retValue = BAD_CAST xmlStrdup(BAD_CAST buf); + } + break; + case XML_SCHEMAS_TIME: + { + char buf[30]; + + if (val->value.date.tz_flag) { + xmlSchemaValPtr norm; + + norm = xmlSchemaDateNormalize(val, 0); + if (norm == NULL) + return (-1); + /* + * TODO: Check if "%.14g" is portable. + */ + snprintf(buf, 30, + "%02u:%02u:%02.14gZ", + norm->value.date.hour, + norm->value.date.min, + norm->value.date.sec); + xmlSchemaFreeValue(norm); + } else { + snprintf(buf, 30, + "%02u:%02u:%02.14g", + val->value.date.hour, + val->value.date.min, + val->value.date.sec); + } + *retValue = BAD_CAST xmlStrdup(BAD_CAST buf); + } + break; + case XML_SCHEMAS_DATE: + { + char buf[30]; + + if (val->value.date.tz_flag) { + xmlSchemaValPtr norm; + + norm = xmlSchemaDateNormalize(val, 0); + if (norm == NULL) + return (-1); + /* + * TODO: Append the canonical value of the + * recoverable timezone and not "Z". + */ + snprintf(buf, 30, + "%04ld:%02u:%02uZ", + norm->value.date.year, norm->value.date.mon, + norm->value.date.day); + xmlSchemaFreeValue(norm); + } else { + snprintf(buf, 30, + "%04ld:%02u:%02u", + val->value.date.year, val->value.date.mon, + val->value.date.day); + } + *retValue = BAD_CAST xmlStrdup(BAD_CAST buf); + } + break; + case XML_SCHEMAS_DATETIME: + { + char buf[50]; + + if (val->value.date.tz_flag) { + xmlSchemaValPtr norm; + + norm = xmlSchemaDateNormalize(val, 0); + if (norm == NULL) + return (-1); + /* + * TODO: Check if "%.14g" is portable. + */ + snprintf(buf, 50, + "%04ld:%02u:%02uT%02u:%02u:%02.14gZ", + norm->value.date.year, norm->value.date.mon, + norm->value.date.day, norm->value.date.hour, + norm->value.date.min, norm->value.date.sec); + xmlSchemaFreeValue(norm); + } else { + snprintf(buf, 50, + "%04ld:%02u:%02uT%02u:%02u:%02.14g", + val->value.date.year, val->value.date.mon, + val->value.date.day, val->value.date.hour, + val->value.date.min, val->value.date.sec); + } + *retValue = BAD_CAST xmlStrdup(BAD_CAST buf); + } + break; + case XML_SCHEMAS_HEXBINARY: + *retValue = BAD_CAST xmlStrdup(BAD_CAST val->value.hex.str); + break; + case XML_SCHEMAS_BASE64BINARY: + /* + * TODO: Is the following spec piece implemented?: + * SPEC: "Note: For some values the canonical form defined + * above does not conform to [RFC 2045], which requires breaking + * with linefeeds at appropriate intervals." + */ + *retValue = BAD_CAST xmlStrdup(BAD_CAST val->value.base64.str); + break; + case XML_SCHEMAS_FLOAT: { + char buf[30]; + /* + * |m| < 16777216, -149 <= e <= 104. + * TODO: Handle, NaN, INF, -INF. The format is not + * yet conformant. The c type float does not cover + * the whole range. + */ + snprintf(buf, 30, "%01.14e", val->value.f); + *retValue = BAD_CAST xmlStrdup(BAD_CAST buf); + } + break; + case XML_SCHEMAS_DOUBLE: { + char buf[40]; + /* |m| < 9007199254740992, -1075 <= e <= 970 */ + /* + * TODO: Handle, NaN, INF, -INF. The format is not + * yet conformant. The c type float does not cover + * the whole range. + */ + snprintf(buf, 40, "%01.14e", val->value.d); + *retValue = BAD_CAST xmlStrdup(BAD_CAST buf); + } + break; + default: + *retValue = BAD_CAST xmlStrdup(BAD_CAST "???"); + return (1); + } + if (*retValue == NULL) + return(-1); + return (0); +} + +/** + * xmlSchemaGetCanonValueWhtsp: + * @val: the precomputed value + * @retValue: the returned value + * @ws: the whitespace type of the value + * + * Get a the cononical representation of the value. + * The caller has to free the returned @retValue. + * + * Returns 0 if the value could be built, 1 if the value type is + * not supported yet and -1 in case of API errors. + */ +int +xmlSchemaGetCanonValueWhtsp(xmlSchemaValPtr val, + const xmlChar **retValue, + xmlSchemaWhitespaceValueType ws) +{ + if ((retValue == NULL) || (val == NULL)) + return (-1); + if ((ws == XML_SCHEMA_WHITESPACE_UNKNOWN) || + (ws > XML_SCHEMA_WHITESPACE_COLLAPSE)) + return (-1); + + *retValue = NULL; + switch (val->type) { + case XML_SCHEMAS_STRING: + if (val->value.str == NULL) + *retValue = BAD_CAST xmlStrdup(BAD_CAST ""); + else if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE) + *retValue = xmlSchemaCollapseString(val->value.str); + else if (ws == XML_SCHEMA_WHITESPACE_REPLACE) + *retValue = xmlSchemaWhiteSpaceReplace(val->value.str); + if ((*retValue) == NULL) + *retValue = BAD_CAST xmlStrdup(val->value.str); + break; + case XML_SCHEMAS_NORMSTRING: + if (val->value.str == NULL) + *retValue = BAD_CAST xmlStrdup(BAD_CAST ""); + else { + if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE) + *retValue = xmlSchemaCollapseString(val->value.str); + else + *retValue = xmlSchemaWhiteSpaceReplace(val->value.str); + if ((*retValue) == NULL) + *retValue = BAD_CAST xmlStrdup(val->value.str); + } + break; + default: + return (xmlSchemaGetCanonValue(val, retValue)); + } + return (0); +} + +/** + * xmlSchemaGetValType: + * @val: a schemas value + * + * Accessor for the type of a value + * + * Returns the xmlSchemaValType of the value + */ +xmlSchemaValType +xmlSchemaGetValType(xmlSchemaValPtr val) +{ + if (val == NULL) + return(XML_SCHEMAS_UNKNOWN); + return (val->type); +} + +#define bottom_xmlschemastypes +#include "elfgcchack.h" +#endif /* LIBXML_SCHEMAS_ENABLED */ diff --git a/android/native/libxml2/xmlstring.c b/android/native/libxml2/xmlstring.c new file mode 100644 index 0000000000..910f244485 --- /dev/null +++ b/android/native/libxml2/xmlstring.c @@ -0,0 +1,984 @@ +/* + * string.c : an XML string utilities module + * + * This module provides various utility functions for manipulating + * the xmlChar* type. All functions named xmlStr* have been moved here + * from the parser.c file (their original home). + * + * See Copyright for the status of this software. + * + * UTF8 string routines from: + * William Brack + * + * daniel@veillard.com + */ + +#define IN_LIBXML +#include "libxml.h" + +#include +#include +#include +#include +#include + +/************************************************************************ + * * + * Commodity functions to handle xmlChars * + * * + ************************************************************************/ + +/** + * xmlStrndup: + * @cur: the input xmlChar * + * @len: the len of @cur + * + * a strndup for array of xmlChar's + * + * Returns a new xmlChar * or NULL + */ +xmlChar * +xmlStrndup(const xmlChar *cur, int len) { + xmlChar *ret; + + if ((cur == NULL) || (len < 0)) return(NULL); + ret = (xmlChar *) xmlMallocAtomic((len + 1) * sizeof(xmlChar)); + if (ret == NULL) { + xmlErrMemory(NULL, NULL); + return(NULL); + } + memcpy(ret, cur, len * sizeof(xmlChar)); + ret[len] = 0; + return(ret); +} + +/** + * xmlStrdup: + * @cur: the input xmlChar * + * + * a strdup for array of xmlChar's. Since they are supposed to be + * encoded in UTF-8 or an encoding with 8bit based chars, we assume + * a termination mark of '0'. + * + * Returns a new xmlChar * or NULL + */ +xmlChar * +xmlStrdup(const xmlChar *cur) { + const xmlChar *p = cur; + + if (cur == NULL) return(NULL); + while (*p != 0) p++; /* non input consuming */ + return(xmlStrndup(cur, p - cur)); +} + +/** + * xmlCharStrndup: + * @cur: the input char * + * @len: the len of @cur + * + * a strndup for char's to xmlChar's + * + * Returns a new xmlChar * or NULL + */ + +xmlChar * +xmlCharStrndup(const char *cur, int len) { + int i; + xmlChar *ret; + + if ((cur == NULL) || (len < 0)) return(NULL); + ret = (xmlChar *) xmlMallocAtomic((len + 1) * sizeof(xmlChar)); + if (ret == NULL) { + xmlErrMemory(NULL, NULL); + return(NULL); + } + for (i = 0;i < len;i++) { + ret[i] = (xmlChar) cur[i]; + if (ret[i] == 0) return(ret); + } + ret[len] = 0; + return(ret); +} + +/** + * xmlCharStrdup: + * @cur: the input char * + * + * a strdup for char's to xmlChar's + * + * Returns a new xmlChar * or NULL + */ + +xmlChar * +xmlCharStrdup(const char *cur) { + const char *p = cur; + + if (cur == NULL) return(NULL); + while (*p != '\0') p++; /* non input consuming */ + return(xmlCharStrndup(cur, p - cur)); +} + +/** + * xmlStrcmp: + * @str1: the first xmlChar * + * @str2: the second xmlChar * + * + * a strcmp for xmlChar's + * + * Returns the integer result of the comparison + */ + +int +xmlStrcmp(const xmlChar *str1, const xmlChar *str2) { + register int tmp; + + if (str1 == str2) return(0); + if (str1 == NULL) return(-1); + if (str2 == NULL) return(1); + do { + tmp = *str1++ - *str2; + if (tmp != 0) return(tmp); + } while (*str2++ != 0); + return 0; +} + +/** + * xmlStrEqual: + * @str1: the first xmlChar * + * @str2: the second xmlChar * + * + * Check if both strings are equal of have same content. + * Should be a bit more readable and faster than xmlStrcmp() + * + * Returns 1 if they are equal, 0 if they are different + */ + +int +xmlStrEqual(const xmlChar *str1, const xmlChar *str2) { + if (str1 == str2) return(1); + if (str1 == NULL) return(0); + if (str2 == NULL) return(0); + do { + if (*str1++ != *str2) return(0); + } while (*str2++); + return(1); +} + +/** + * xmlStrQEqual: + * @pref: the prefix of the QName + * @name: the localname of the QName + * @str: the second xmlChar * + * + * Check if a QName is Equal to a given string + * + * Returns 1 if they are equal, 0 if they are different + */ + +int +xmlStrQEqual(const xmlChar *pref, const xmlChar *name, const xmlChar *str) { + if (pref == NULL) return(xmlStrEqual(name, str)); + if (name == NULL) return(0); + if (str == NULL) return(0); + + do { + if (*pref++ != *str) return(0); + } while ((*str++) && (*pref)); + if (*str++ != ':') return(0); + do { + if (*name++ != *str) return(0); + } while (*str++); + return(1); +} + +/** + * xmlStrncmp: + * @str1: the first xmlChar * + * @str2: the second xmlChar * + * @len: the max comparison length + * + * a strncmp for xmlChar's + * + * Returns the integer result of the comparison + */ + +int +xmlStrncmp(const xmlChar *str1, const xmlChar *str2, int len) { + register int tmp; + + if (len <= 0) return(0); + if (str1 == str2) return(0); + if (str1 == NULL) return(-1); + if (str2 == NULL) return(1); +#ifdef __GNUC__ + tmp = strncmp((const char *)str1, (const char *)str2, len); + return tmp; +#else + do { + tmp = *str1++ - *str2; + if (tmp != 0 || --len == 0) return(tmp); + } while (*str2++ != 0); + return 0; +#endif +} + +static const xmlChar casemap[256] = { + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F, + 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27, + 0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F, + 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37, + 0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F, + 0x40,0x61,0x62,0x63,0x64,0x65,0x66,0x67, + 0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F, + 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77, + 0x78,0x79,0x7A,0x7B,0x5C,0x5D,0x5E,0x5F, + 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67, + 0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F, + 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77, + 0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F, + 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87, + 0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97, + 0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, + 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7, + 0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7, + 0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7, + 0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7, + 0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7, + 0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7, + 0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF +}; + +/** + * xmlStrcasecmp: + * @str1: the first xmlChar * + * @str2: the second xmlChar * + * + * a strcasecmp for xmlChar's + * + * Returns the integer result of the comparison + */ + +int +xmlStrcasecmp(const xmlChar *str1, const xmlChar *str2) { + register int tmp; + + if (str1 == str2) return(0); + if (str1 == NULL) return(-1); + if (str2 == NULL) return(1); + do { + tmp = casemap[*str1++] - casemap[*str2]; + if (tmp != 0) return(tmp); + } while (*str2++ != 0); + return 0; +} + +/** + * xmlStrncasecmp: + * @str1: the first xmlChar * + * @str2: the second xmlChar * + * @len: the max comparison length + * + * a strncasecmp for xmlChar's + * + * Returns the integer result of the comparison + */ + +int +xmlStrncasecmp(const xmlChar *str1, const xmlChar *str2, int len) { + register int tmp; + + if (len <= 0) return(0); + if (str1 == str2) return(0); + if (str1 == NULL) return(-1); + if (str2 == NULL) return(1); + do { + tmp = casemap[*str1++] - casemap[*str2]; + if (tmp != 0 || --len == 0) return(tmp); + } while (*str2++ != 0); + return 0; +} + +/** + * xmlStrchr: + * @str: the xmlChar * array + * @val: the xmlChar to search + * + * a strchr for xmlChar's + * + * Returns the xmlChar * for the first occurrence or NULL. + */ + +const xmlChar * +xmlStrchr(const xmlChar *str, xmlChar val) { + if (str == NULL) return(NULL); + while (*str != 0) { /* non input consuming */ + if (*str == val) return((xmlChar *) str); + str++; + } + return(NULL); +} + +/** + * xmlStrstr: + * @str: the xmlChar * array (haystack) + * @val: the xmlChar to search (needle) + * + * a strstr for xmlChar's + * + * Returns the xmlChar * for the first occurrence or NULL. + */ + +const xmlChar * +xmlStrstr(const xmlChar *str, const xmlChar *val) { + int n; + + if (str == NULL) return(NULL); + if (val == NULL) return(NULL); + n = xmlStrlen(val); + + if (n == 0) return(str); + while (*str != 0) { /* non input consuming */ + if (*str == *val) { + if (!xmlStrncmp(str, val, n)) return((const xmlChar *) str); + } + str++; + } + return(NULL); +} + +/** + * xmlStrcasestr: + * @str: the xmlChar * array (haystack) + * @val: the xmlChar to search (needle) + * + * a case-ignoring strstr for xmlChar's + * + * Returns the xmlChar * for the first occurrence or NULL. + */ + +const xmlChar * +xmlStrcasestr(const xmlChar *str, const xmlChar *val) { + int n; + + if (str == NULL) return(NULL); + if (val == NULL) return(NULL); + n = xmlStrlen(val); + + if (n == 0) return(str); + while (*str != 0) { /* non input consuming */ + if (casemap[*str] == casemap[*val]) + if (!xmlStrncasecmp(str, val, n)) return(str); + str++; + } + return(NULL); +} + +/** + * xmlStrsub: + * @str: the xmlChar * array (haystack) + * @start: the index of the first char (zero based) + * @len: the length of the substring + * + * Extract a substring of a given string + * + * Returns the xmlChar * for the first occurrence or NULL. + */ + +xmlChar * +xmlStrsub(const xmlChar *str, int start, int len) { + int i; + + if (str == NULL) return(NULL); + if (start < 0) return(NULL); + if (len < 0) return(NULL); + + for (i = 0;i < start;i++) { + if (*str == 0) return(NULL); + str++; + } + if (*str == 0) return(NULL); + return(xmlStrndup(str, len)); +} + +/** + * xmlStrlen: + * @str: the xmlChar * array + * + * length of a xmlChar's string + * + * Returns the number of xmlChar contained in the ARRAY. + */ + +int +xmlStrlen(const xmlChar *str) { + int len = 0; + + if (str == NULL) return(0); + while (*str != 0) { /* non input consuming */ + str++; + len++; + } + return(len); +} + +/** + * xmlStrncat: + * @cur: the original xmlChar * array + * @add: the xmlChar * array added + * @len: the length of @add + * + * a strncat for array of xmlChar's, it will extend @cur with the len + * first bytes of @add. Note that if @len < 0 then this is an API error + * and NULL will be returned. + * + * Returns a new xmlChar *, the original @cur is reallocated if needed + * and should not be freed + */ + +xmlChar * +xmlStrncat(xmlChar *cur, const xmlChar *add, int len) { + int size; + xmlChar *ret; + + if ((add == NULL) || (len == 0)) + return(cur); + if (len < 0) + return(NULL); + if (cur == NULL) + return(xmlStrndup(add, len)); + + size = xmlStrlen(cur); + ret = (xmlChar *) xmlRealloc(cur, (size + len + 1) * sizeof(xmlChar)); + if (ret == NULL) { + xmlErrMemory(NULL, NULL); + return(cur); + } + memcpy(&ret[size], add, len * sizeof(xmlChar)); + ret[size + len] = 0; + return(ret); +} + +/** + * xmlStrncatNew: + * @str1: first xmlChar string + * @str2: second xmlChar string + * @len: the len of @str2 or < 0 + * + * same as xmlStrncat, but creates a new string. The original + * two strings are not freed. If @len is < 0 then the length + * will be calculated automatically. + * + * Returns a new xmlChar * or NULL + */ +xmlChar * +xmlStrncatNew(const xmlChar *str1, const xmlChar *str2, int len) { + int size; + xmlChar *ret; + + if (len < 0) + len = xmlStrlen(str2); + if ((str2 == NULL) || (len == 0)) + return(xmlStrdup(str1)); + if (str1 == NULL) + return(xmlStrndup(str2, len)); + + size = xmlStrlen(str1); + ret = (xmlChar *) xmlMalloc((size + len + 1) * sizeof(xmlChar)); + if (ret == NULL) { + xmlErrMemory(NULL, NULL); + return(xmlStrndup(str1, size)); + } + memcpy(ret, str1, size * sizeof(xmlChar)); + memcpy(&ret[size], str2, len * sizeof(xmlChar)); + ret[size + len] = 0; + return(ret); +} + +/** + * xmlStrcat: + * @cur: the original xmlChar * array + * @add: the xmlChar * array added + * + * a strcat for array of xmlChar's. Since they are supposed to be + * encoded in UTF-8 or an encoding with 8bit based chars, we assume + * a termination mark of '0'. + * + * Returns a new xmlChar * containing the concatenated string. + */ +xmlChar * +xmlStrcat(xmlChar *cur, const xmlChar *add) { + const xmlChar *p = add; + + if (add == NULL) return(cur); + if (cur == NULL) + return(xmlStrdup(add)); + + while (*p != 0) p++; /* non input consuming */ + return(xmlStrncat(cur, add, p - add)); +} + +/** + * xmlStrPrintf: + * @buf: the result buffer. + * @len: the result buffer length. + * @msg: the message with printf formatting. + * @...: extra parameters for the message. + * + * Formats @msg and places result into @buf. + * + * Returns the number of characters written to @buf or -1 if an error occurs. + */ +int XMLCDECL +xmlStrPrintf(xmlChar *buf, int len, const xmlChar *msg, ...) { + va_list args; + int ret; + + if((buf == NULL) || (msg == NULL)) { + return(-1); + } + + va_start(args, msg); + ret = vsnprintf((char *) buf, len, (const char *) msg, args); + va_end(args); + buf[len - 1] = 0; /* be safe ! */ + + return(ret); +} + +/** + * xmlStrVPrintf: + * @buf: the result buffer. + * @len: the result buffer length. + * @msg: the message with printf formatting. + * @ap: extra parameters for the message. + * + * Formats @msg and places result into @buf. + * + * Returns the number of characters written to @buf or -1 if an error occurs. + */ +int +xmlStrVPrintf(xmlChar *buf, int len, const xmlChar *msg, va_list ap) { + int ret; + + if((buf == NULL) || (msg == NULL)) { + return(-1); + } + + ret = vsnprintf((char *) buf, len, (const char *) msg, ap); + buf[len - 1] = 0; /* be safe ! */ + + return(ret); +} + +/************************************************************************ + * * + * Generic UTF8 handling routines * + * * + * From rfc2044: encoding of the Unicode values on UTF-8: * + * * + * UCS-4 range (hex.) UTF-8 octet sequence (binary) * + * 0000 0000-0000 007F 0xxxxxxx * + * 0000 0080-0000 07FF 110xxxxx 10xxxxxx * + * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx * + * * + * I hope we won't use values > 0xFFFF anytime soon ! * + * * + ************************************************************************/ + + +/** + * xmlUTF8Size: + * @utf: pointer to the UTF8 character + * + * calculates the internal size of a UTF8 character + * + * returns the numbers of bytes in the character, -1 on format error + */ +int +xmlUTF8Size(const xmlChar *utf) { + xmlChar mask; + int len; + + if (utf == NULL) + return -1; + if (*utf < 0x80) + return 1; + /* check valid UTF8 character */ + if (!(*utf & 0x40)) + return -1; + /* determine number of bytes in char */ + len = 2; + for (mask=0x20; mask != 0; mask>>=1) { + if (!(*utf & mask)) + return len; + len++; + } + return -1; +} + +/** + * xmlUTF8Charcmp: + * @utf1: pointer to first UTF8 char + * @utf2: pointer to second UTF8 char + * + * compares the two UCS4 values + * + * returns result of the compare as with xmlStrncmp + */ +int +xmlUTF8Charcmp(const xmlChar *utf1, const xmlChar *utf2) { + + if (utf1 == NULL ) { + if (utf2 == NULL) + return 0; + return -1; + } + return xmlStrncmp(utf1, utf2, xmlUTF8Size(utf1)); +} + +/** + * xmlUTF8Strlen: + * @utf: a sequence of UTF-8 encoded bytes + * + * compute the length of an UTF8 string, it doesn't do a full UTF8 + * checking of the content of the string. + * + * Returns the number of characters in the string or -1 in case of error + */ +int +xmlUTF8Strlen(const xmlChar *utf) { + int ret = 0; + + if (utf == NULL) + return(-1); + + while (*utf != 0) { + if (utf[0] & 0x80) { + if ((utf[1] & 0xc0) != 0x80) + return(-1); + if ((utf[0] & 0xe0) == 0xe0) { + if ((utf[2] & 0xc0) != 0x80) + return(-1); + if ((utf[0] & 0xf0) == 0xf0) { + if ((utf[0] & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80) + return(-1); + utf += 4; + } else { + utf += 3; + } + } else { + utf += 2; + } + } else { + utf++; + } + ret++; + } + return(ret); +} + +/** + * xmlGetUTF8Char: + * @utf: a sequence of UTF-8 encoded bytes + * @len: a pointer to the minimum number of bytes present in + * the sequence. This is used to assure the next character + * is completely contained within the sequence. + * + * Read the first UTF8 character from @utf + * + * Returns the char value or -1 in case of error, and sets *len to + * the actual number of bytes consumed (0 in case of error) + */ +int +xmlGetUTF8Char(const unsigned char *utf, int *len) { + unsigned int c; + + if (utf == NULL) + goto error; + if (len == NULL) + goto error; + if (*len < 1) + goto error; + + c = utf[0]; + if (c & 0x80) { + if (*len < 2) + goto error; + if ((utf[1] & 0xc0) != 0x80) + goto error; + if ((c & 0xe0) == 0xe0) { + if (*len < 3) + goto error; + if ((utf[2] & 0xc0) != 0x80) + goto error; + if ((c & 0xf0) == 0xf0) { + if (*len < 4) + goto error; + if ((c & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80) + goto error; + *len = 4; + /* 4-byte code */ + c = (utf[0] & 0x7) << 18; + c |= (utf[1] & 0x3f) << 12; + c |= (utf[2] & 0x3f) << 6; + c |= utf[3] & 0x3f; + } else { + /* 3-byte code */ + *len = 3; + c = (utf[0] & 0xf) << 12; + c |= (utf[1] & 0x3f) << 6; + c |= utf[2] & 0x3f; + } + } else { + /* 2-byte code */ + *len = 2; + c = (utf[0] & 0x1f) << 6; + c |= utf[1] & 0x3f; + } + } else { + /* 1-byte code */ + *len = 1; + } + return(c); + +error: + if (len != NULL) + *len = 0; + return(-1); +} + +/** + * xmlCheckUTF8: + * @utf: Pointer to putative UTF-8 encoded string. + * + * Checks @utf for being valid UTF-8. @utf is assumed to be + * null-terminated. This function is not super-strict, as it will + * allow longer UTF-8 sequences than necessary. Note that Java is + * capable of producing these sequences if provoked. Also note, this + * routine checks for the 4-byte maximum size, but does not check for + * 0x10ffff maximum value. + * + * Return value: true if @utf is valid. + **/ +int +xmlCheckUTF8(const unsigned char *utf) +{ + int ix; + unsigned char c; + + if (utf == NULL) + return(0); + /* + * utf is a string of 1, 2, 3 or 4 bytes. The valid strings + * are as follows (in "bit format"): + * 0xxxxxxx valid 1-byte + * 110xxxxx 10xxxxxx valid 2-byte + * 1110xxxx 10xxxxxx 10xxxxxx valid 3-byte + * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx valid 4-byte + */ + for (ix = 0; (c = utf[ix]);) { /* string is 0-terminated */ + if ((c & 0x80) == 0x00) { /* 1-byte code, starts with 10 */ + ix++; + } else if ((c & 0xe0) == 0xc0) {/* 2-byte code, starts with 110 */ + if ((utf[ix+1] & 0xc0 ) != 0x80) + return 0; + ix += 2; + } else if ((c & 0xf0) == 0xe0) {/* 3-byte code, starts with 1110 */ + if (((utf[ix+1] & 0xc0) != 0x80) || + ((utf[ix+2] & 0xc0) != 0x80)) + return 0; + ix += 3; + } else if ((c & 0xf8) == 0xf0) {/* 4-byte code, starts with 11110 */ + if (((utf[ix+1] & 0xc0) != 0x80) || + ((utf[ix+2] & 0xc0) != 0x80) || + ((utf[ix+3] & 0xc0) != 0x80)) + return 0; + ix += 4; + } else /* unknown encoding */ + return 0; + } + return(1); +} + +/** + * xmlUTF8Strsize: + * @utf: a sequence of UTF-8 encoded bytes + * @len: the number of characters in the array + * + * storage size of an UTF8 string + * the behaviour is not garanteed if the input string is not UTF-8 + * + * Returns the storage size of + * the first 'len' characters of ARRAY + */ + +int +xmlUTF8Strsize(const xmlChar *utf, int len) { + const xmlChar *ptr=utf; + xmlChar ch; + + if (utf == NULL) + return(0); + + if (len <= 0) + return(0); + + while ( len-- > 0) { + if ( !*ptr ) + break; + if ( (ch = *ptr++) & 0x80) + while ((ch<<=1) & 0x80 ) { + ptr++; + if (*ptr == 0) break; + } + } + return (ptr - utf); +} + + +/** + * xmlUTF8Strndup: + * @utf: the input UTF8 * + * @len: the len of @utf (in chars) + * + * a strndup for array of UTF8's + * + * Returns a new UTF8 * or NULL + */ +xmlChar * +xmlUTF8Strndup(const xmlChar *utf, int len) { + xmlChar *ret; + int i; + + if ((utf == NULL) || (len < 0)) return(NULL); + i = xmlUTF8Strsize(utf, len); + ret = (xmlChar *) xmlMallocAtomic((i + 1) * sizeof(xmlChar)); + if (ret == NULL) { + xmlGenericError(xmlGenericErrorContext, + "malloc of %ld byte failed\n", + (len + 1) * (long)sizeof(xmlChar)); + return(NULL); + } + memcpy(ret, utf, i * sizeof(xmlChar)); + ret[i] = 0; + return(ret); +} + +/** + * xmlUTF8Strpos: + * @utf: the input UTF8 * + * @pos: the position of the desired UTF8 char (in chars) + * + * a function to provide the equivalent of fetching a + * character from a string array + * + * Returns a pointer to the UTF8 character or NULL + */ +const xmlChar * +xmlUTF8Strpos(const xmlChar *utf, int pos) { + xmlChar ch; + + if (utf == NULL) return(NULL); + if (pos < 0) + return(NULL); + while (pos--) { + 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 ) + return(NULL); + } + } + return((xmlChar *)utf); +} + +/** + * xmlUTF8Strloc: + * @utf: the input UTF8 * + * @utfchar: the UTF8 character to be found + * + * a function to provide the relative location of a UTF8 char + * + * Returns the relative character position of the desired char + * or -1 if not found + */ +int +xmlUTF8Strloc(const xmlChar *utf, const xmlChar *utfchar) { + int i, size; + xmlChar ch; + + if (utf==NULL || utfchar==NULL) return -1; + size = xmlUTF8Strsize(utfchar, 1); + for(i=0; (ch=*utf) != 0; i++) { + if (xmlStrncmp(utf, utfchar, size)==0) + return(i); + utf++; + if ( ch & 0x80 ) { + /* if not simple ascii, verify proper format */ + if ( (ch & 0xc0) != 0xc0 ) + return(-1); + /* then skip over remaining bytes for this char */ + while ( (ch <<= 1) & 0x80 ) + if ( (*utf++ & 0xc0) != 0x80 ) + return(-1); + } + } + + return(-1); +} +/** + * xmlUTF8Strsub: + * @utf: a sequence of UTF-8 encoded bytes + * @start: relative pos of first char + * @len: total number to copy + * + * 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 + */ + +xmlChar * +xmlUTF8Strsub(const xmlChar *utf, int start, int len) { + int i; + xmlChar ch; + + if (utf == NULL) return(NULL); + if (start < 0) return(NULL); + if (len < 0) return(NULL); + + /* + * 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 ) + return(NULL); + } + } + + return(xmlUTF8Strndup(utf, len)); +} + +#define bottom_xmlstring +#include "elfgcchack.h" diff --git a/android/native/libxml2/xmlunicode.c b/android/native/libxml2/xmlunicode.c new file mode 100644 index 0000000000..450d0f0937 --- /dev/null +++ b/android/native/libxml2/xmlunicode.c @@ -0,0 +1,3179 @@ +/* + * xmlunicode.c: this module implements the Unicode character APIs + * + * This file is automatically generated from the + * UCS description files of the Unicode Character Database + * 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 + * Sources: Blocks-4.0.1.txt UnicodeData-4.0.1.txt + * Daniel Veillard + */ + +#define IN_LIBXML +#include "libxml.h" + +#ifdef LIBXML_UNICODE_ENABLED + +#include +#include +#include +#include + +typedef int (xmlIntFunc)(int); /* just to keep one's mind untwisted */ + +typedef struct { + const char *rangename; + xmlIntFunc *func; +} xmlUnicodeRange; + +typedef struct { + xmlUnicodeRange *table; + int numentries; +} xmlUnicodeNameTable; + + +static xmlIntFunc *xmlUnicodeLookup(xmlUnicodeNameTable *tptr, const char *tname); + +static xmlUnicodeRange xmlUnicodeBlocks[] = { + {"AegeanNumbers", xmlUCSIsAegeanNumbers}, + {"AlphabeticPresentationForms", xmlUCSIsAlphabeticPresentationForms}, + {"Arabic", xmlUCSIsArabic}, + {"ArabicPresentationForms-A", xmlUCSIsArabicPresentationFormsA}, + {"ArabicPresentationForms-B", xmlUCSIsArabicPresentationFormsB}, + {"Armenian", xmlUCSIsArmenian}, + {"Arrows", xmlUCSIsArrows}, + {"BasicLatin", xmlUCSIsBasicLatin}, + {"Bengali", xmlUCSIsBengali}, + {"BlockElements", xmlUCSIsBlockElements}, + {"Bopomofo", xmlUCSIsBopomofo}, + {"BopomofoExtended", xmlUCSIsBopomofoExtended}, + {"BoxDrawing", xmlUCSIsBoxDrawing}, + {"BraillePatterns", xmlUCSIsBraillePatterns}, + {"Buhid", xmlUCSIsBuhid}, + {"ByzantineMusicalSymbols", xmlUCSIsByzantineMusicalSymbols}, + {"CJKCompatibility", xmlUCSIsCJKCompatibility}, + {"CJKCompatibilityForms", xmlUCSIsCJKCompatibilityForms}, + {"CJKCompatibilityIdeographs", xmlUCSIsCJKCompatibilityIdeographs}, + {"CJKCompatibilityIdeographsSupplement", xmlUCSIsCJKCompatibilityIdeographsSupplement}, + {"CJKRadicalsSupplement", xmlUCSIsCJKRadicalsSupplement}, + {"CJKSymbolsandPunctuation", xmlUCSIsCJKSymbolsandPunctuation}, + {"CJKUnifiedIdeographs", xmlUCSIsCJKUnifiedIdeographs}, + {"CJKUnifiedIdeographsExtensionA", xmlUCSIsCJKUnifiedIdeographsExtensionA}, + {"CJKUnifiedIdeographsExtensionB", xmlUCSIsCJKUnifiedIdeographsExtensionB}, + {"Cherokee", xmlUCSIsCherokee}, + {"CombiningDiacriticalMarks", xmlUCSIsCombiningDiacriticalMarks}, + {"CombiningDiacriticalMarksforSymbols", xmlUCSIsCombiningDiacriticalMarksforSymbols}, + {"CombiningHalfMarks", xmlUCSIsCombiningHalfMarks}, + {"CombiningMarksforSymbols", xmlUCSIsCombiningMarksforSymbols}, + {"ControlPictures", xmlUCSIsControlPictures}, + {"CurrencySymbols", xmlUCSIsCurrencySymbols}, + {"CypriotSyllabary", xmlUCSIsCypriotSyllabary}, + {"Cyrillic", xmlUCSIsCyrillic}, + {"CyrillicSupplement", xmlUCSIsCyrillicSupplement}, + {"Deseret", xmlUCSIsDeseret}, + {"Devanagari", xmlUCSIsDevanagari}, + {"Dingbats", xmlUCSIsDingbats}, + {"EnclosedAlphanumerics", xmlUCSIsEnclosedAlphanumerics}, + {"EnclosedCJKLettersandMonths", xmlUCSIsEnclosedCJKLettersandMonths}, + {"Ethiopic", xmlUCSIsEthiopic}, + {"GeneralPunctuation", xmlUCSIsGeneralPunctuation}, + {"GeometricShapes", xmlUCSIsGeometricShapes}, + {"Georgian", xmlUCSIsGeorgian}, + {"Gothic", xmlUCSIsGothic}, + {"Greek", xmlUCSIsGreek}, + {"GreekExtended", xmlUCSIsGreekExtended}, + {"GreekandCoptic", xmlUCSIsGreekandCoptic}, + {"Gujarati", xmlUCSIsGujarati}, + {"Gurmukhi", xmlUCSIsGurmukhi}, + {"HalfwidthandFullwidthForms", xmlUCSIsHalfwidthandFullwidthForms}, + {"HangulCompatibilityJamo", xmlUCSIsHangulCompatibilityJamo}, + {"HangulJamo", xmlUCSIsHangulJamo}, + {"HangulSyllables", xmlUCSIsHangulSyllables}, + {"Hanunoo", xmlUCSIsHanunoo}, + {"Hebrew", xmlUCSIsHebrew}, + {"HighPrivateUseSurrogates", xmlUCSIsHighPrivateUseSurrogates}, + {"HighSurrogates", xmlUCSIsHighSurrogates}, + {"Hiragana", xmlUCSIsHiragana}, + {"IPAExtensions", xmlUCSIsIPAExtensions}, + {"IdeographicDescriptionCharacters", xmlUCSIsIdeographicDescriptionCharacters}, + {"Kanbun", xmlUCSIsKanbun}, + {"KangxiRadicals", xmlUCSIsKangxiRadicals}, + {"Kannada", xmlUCSIsKannada}, + {"Katakana", xmlUCSIsKatakana}, + {"KatakanaPhoneticExtensions", xmlUCSIsKatakanaPhoneticExtensions}, + {"Khmer", xmlUCSIsKhmer}, + {"KhmerSymbols", xmlUCSIsKhmerSymbols}, + {"Lao", xmlUCSIsLao}, + {"Latin-1Supplement", xmlUCSIsLatin1Supplement}, + {"LatinExtended-A", xmlUCSIsLatinExtendedA}, + {"LatinExtended-B", xmlUCSIsLatinExtendedB}, + {"LatinExtendedAdditional", xmlUCSIsLatinExtendedAdditional}, + {"LetterlikeSymbols", xmlUCSIsLetterlikeSymbols}, + {"Limbu", xmlUCSIsLimbu}, + {"LinearBIdeograms", xmlUCSIsLinearBIdeograms}, + {"LinearBSyllabary", xmlUCSIsLinearBSyllabary}, + {"LowSurrogates", xmlUCSIsLowSurrogates}, + {"Malayalam", xmlUCSIsMalayalam}, + {"MathematicalAlphanumericSymbols", xmlUCSIsMathematicalAlphanumericSymbols}, + {"MathematicalOperators", xmlUCSIsMathematicalOperators}, + {"MiscellaneousMathematicalSymbols-A", xmlUCSIsMiscellaneousMathematicalSymbolsA}, + {"MiscellaneousMathematicalSymbols-B", xmlUCSIsMiscellaneousMathematicalSymbolsB}, + {"MiscellaneousSymbols", xmlUCSIsMiscellaneousSymbols}, + {"MiscellaneousSymbolsandArrows", xmlUCSIsMiscellaneousSymbolsandArrows}, + {"MiscellaneousTechnical", xmlUCSIsMiscellaneousTechnical}, + {"Mongolian", xmlUCSIsMongolian}, + {"MusicalSymbols", xmlUCSIsMusicalSymbols}, + {"Myanmar", xmlUCSIsMyanmar}, + {"NumberForms", xmlUCSIsNumberForms}, + {"Ogham", xmlUCSIsOgham}, + {"OldItalic", xmlUCSIsOldItalic}, + {"OpticalCharacterRecognition", xmlUCSIsOpticalCharacterRecognition}, + {"Oriya", xmlUCSIsOriya}, + {"Osmanya", xmlUCSIsOsmanya}, + {"PhoneticExtensions", xmlUCSIsPhoneticExtensions}, + {"PrivateUse", xmlUCSIsPrivateUse}, + {"PrivateUseArea", xmlUCSIsPrivateUseArea}, + {"Runic", xmlUCSIsRunic}, + {"Shavian", xmlUCSIsShavian}, + {"Sinhala", xmlUCSIsSinhala}, + {"SmallFormVariants", xmlUCSIsSmallFormVariants}, + {"SpacingModifierLetters", xmlUCSIsSpacingModifierLetters}, + {"Specials", xmlUCSIsSpecials}, + {"SuperscriptsandSubscripts", xmlUCSIsSuperscriptsandSubscripts}, + {"SupplementalArrows-A", xmlUCSIsSupplementalArrowsA}, + {"SupplementalArrows-B", xmlUCSIsSupplementalArrowsB}, + {"SupplementalMathematicalOperators", xmlUCSIsSupplementalMathematicalOperators}, + {"SupplementaryPrivateUseArea-A", xmlUCSIsSupplementaryPrivateUseAreaA}, + {"SupplementaryPrivateUseArea-B", xmlUCSIsSupplementaryPrivateUseAreaB}, + {"Syriac", xmlUCSIsSyriac}, + {"Tagalog", xmlUCSIsTagalog}, + {"Tagbanwa", xmlUCSIsTagbanwa}, + {"Tags", xmlUCSIsTags}, + {"TaiLe", xmlUCSIsTaiLe}, + {"TaiXuanJingSymbols", xmlUCSIsTaiXuanJingSymbols}, + {"Tamil", xmlUCSIsTamil}, + {"Telugu", xmlUCSIsTelugu}, + {"Thaana", xmlUCSIsThaana}, + {"Thai", xmlUCSIsThai}, + {"Tibetan", xmlUCSIsTibetan}, + {"Ugaritic", xmlUCSIsUgaritic}, + {"UnifiedCanadianAboriginalSyllabics", xmlUCSIsUnifiedCanadianAboriginalSyllabics}, + {"VariationSelectors", xmlUCSIsVariationSelectors}, + {"VariationSelectorsSupplement", xmlUCSIsVariationSelectorsSupplement}, + {"YiRadicals", xmlUCSIsYiRadicals}, + {"YiSyllables", xmlUCSIsYiSyllables}, + {"YijingHexagramSymbols", xmlUCSIsYijingHexagramSymbols}}; + +static xmlUnicodeRange xmlUnicodeCats[] = { + {"C", xmlUCSIsCatC}, + {"Cc", xmlUCSIsCatCc}, + {"Cf", xmlUCSIsCatCf}, + {"Co", xmlUCSIsCatCo}, + {"Cs", xmlUCSIsCatCs}, + {"L", xmlUCSIsCatL}, + {"Ll", xmlUCSIsCatLl}, + {"Lm", xmlUCSIsCatLm}, + {"Lo", xmlUCSIsCatLo}, + {"Lt", xmlUCSIsCatLt}, + {"Lu", xmlUCSIsCatLu}, + {"M", xmlUCSIsCatM}, + {"Mc", xmlUCSIsCatMc}, + {"Me", xmlUCSIsCatMe}, + {"Mn", xmlUCSIsCatMn}, + {"N", xmlUCSIsCatN}, + {"Nd", xmlUCSIsCatNd}, + {"Nl", xmlUCSIsCatNl}, + {"No", xmlUCSIsCatNo}, + {"P", xmlUCSIsCatP}, + {"Pc", xmlUCSIsCatPc}, + {"Pd", xmlUCSIsCatPd}, + {"Pe", xmlUCSIsCatPe}, + {"Pf", xmlUCSIsCatPf}, + {"Pi", xmlUCSIsCatPi}, + {"Po", xmlUCSIsCatPo}, + {"Ps", xmlUCSIsCatPs}, + {"S", xmlUCSIsCatS}, + {"Sc", xmlUCSIsCatSc}, + {"Sk", xmlUCSIsCatSk}, + {"Sm", xmlUCSIsCatSm}, + {"So", xmlUCSIsCatSo}, + {"Z", xmlUCSIsCatZ}, + {"Zl", xmlUCSIsCatZl}, + {"Zp", xmlUCSIsCatZp}, + {"Zs", xmlUCSIsCatZs}}; + +static const xmlChSRange xmlCS[] = {{0x0, 0x1f}, {0x7f, 0x9f}, + {0xad, 0xad}, {0x600, 0x603}, {0x6dd, 0x6dd}, {0x70f, 0x70f}, + {0x17b4, 0x17b5}, {0x200b, 0x200f}, {0x202a, 0x202e}, {0x2060, 0x2063}, + {0x206a, 0x206f}, {0xd800, 0xd800}, {0xdb7f, 0xdb80}, {0xdbff, 0xdc00}, + {0xdfff, 0xe000}, {0xf8ff, 0xf8ff}, {0xfeff, 0xfeff}, {0xfff9, 0xfffb} }; +static const xmlChLRange xmlCL[] = {{0x1d173, 0x1d17a}, {0xe0001, 0xe0001}, + {0xe0020, 0xe007f}, {0xf0000, 0xf0000}, {0xffffd, 0xffffd}, + {0x100000, 0x100000}, {0x10fffd, 0x10fffd} }; +static xmlChRangeGroup xmlCG = {18,7,xmlCS,xmlCL}; + +static const xmlChSRange xmlCfS[] = {{0xad, 0xad}, {0x600, 0x603}, + {0x6dd, 0x6dd}, {0x70f, 0x70f}, {0x17b4, 0x17b5}, {0x200b, 0x200f}, + {0x202a, 0x202e}, {0x2060, 0x2063}, {0x206a, 0x206f}, {0xfeff, 0xfeff}, + {0xfff9, 0xfffb} }; +static const xmlChLRange xmlCfL[] = {{0x1d173, 0x1d17a}, {0xe0001, 0xe0001}, + {0xe0020, 0xe007f} }; +static xmlChRangeGroup xmlCfG = {11,3,xmlCfS,xmlCfL}; + +static const xmlChSRange xmlLS[] = {{0x41, 0x5a}, {0x61, 0x7a}, + {0xaa, 0xaa}, {0xb5, 0xb5}, {0xba, 0xba}, {0xc0, 0xd6}, {0xd8, 0xf6}, + {0xf8, 0x236}, {0x250, 0x2c1}, {0x2c6, 0x2d1}, {0x2e0, 0x2e4}, + {0x2ee, 0x2ee}, {0x37a, 0x37a}, {0x386, 0x386}, {0x388, 0x38a}, + {0x38c, 0x38c}, {0x38e, 0x3a1}, {0x3a3, 0x3ce}, {0x3d0, 0x3f5}, + {0x3f7, 0x3fb}, {0x400, 0x481}, {0x48a, 0x4ce}, {0x4d0, 0x4f5}, + {0x4f8, 0x4f9}, {0x500, 0x50f}, {0x531, 0x556}, {0x559, 0x559}, + {0x561, 0x587}, {0x5d0, 0x5ea}, {0x5f0, 0x5f2}, {0x621, 0x63a}, + {0x640, 0x64a}, {0x66e, 0x66f}, {0x671, 0x6d3}, {0x6d5, 0x6d5}, + {0x6e5, 0x6e6}, {0x6ee, 0x6ef}, {0x6fa, 0x6fc}, {0x6ff, 0x6ff}, + {0x710, 0x710}, {0x712, 0x72f}, {0x74d, 0x74f}, {0x780, 0x7a5}, + {0x7b1, 0x7b1}, {0x904, 0x939}, {0x93d, 0x93d}, {0x950, 0x950}, + {0x958, 0x961}, {0x985, 0x98c}, {0x98f, 0x990}, {0x993, 0x9a8}, + {0x9aa, 0x9b0}, {0x9b2, 0x9b2}, {0x9b6, 0x9b9}, {0x9bd, 0x9bd}, + {0x9dc, 0x9dd}, {0x9df, 0x9e1}, {0x9f0, 0x9f1}, {0xa05, 0xa0a}, + {0xa0f, 0xa10}, {0xa13, 0xa28}, {0xa2a, 0xa30}, {0xa32, 0xa33}, + {0xa35, 0xa36}, {0xa38, 0xa39}, {0xa59, 0xa5c}, {0xa5e, 0xa5e}, + {0xa72, 0xa74}, {0xa85, 0xa8d}, {0xa8f, 0xa91}, {0xa93, 0xaa8}, + {0xaaa, 0xab0}, {0xab2, 0xab3}, {0xab5, 0xab9}, {0xabd, 0xabd}, + {0xad0, 0xad0}, {0xae0, 0xae1}, {0xb05, 0xb0c}, {0xb0f, 0xb10}, + {0xb13, 0xb28}, {0xb2a, 0xb30}, {0xb32, 0xb33}, {0xb35, 0xb39}, + {0xb3d, 0xb3d}, {0xb5c, 0xb5d}, {0xb5f, 0xb61}, {0xb71, 0xb71}, + {0xb83, 0xb83}, {0xb85, 0xb8a}, {0xb8e, 0xb90}, {0xb92, 0xb95}, + {0xb99, 0xb9a}, {0xb9c, 0xb9c}, {0xb9e, 0xb9f}, {0xba3, 0xba4}, + {0xba8, 0xbaa}, {0xbae, 0xbb5}, {0xbb7, 0xbb9}, {0xc05, 0xc0c}, + {0xc0e, 0xc10}, {0xc12, 0xc28}, {0xc2a, 0xc33}, {0xc35, 0xc39}, + {0xc60, 0xc61}, {0xc85, 0xc8c}, {0xc8e, 0xc90}, {0xc92, 0xca8}, + {0xcaa, 0xcb3}, {0xcb5, 0xcb9}, {0xcbd, 0xcbd}, {0xcde, 0xcde}, + {0xce0, 0xce1}, {0xd05, 0xd0c}, {0xd0e, 0xd10}, {0xd12, 0xd28}, + {0xd2a, 0xd39}, {0xd60, 0xd61}, {0xd85, 0xd96}, {0xd9a, 0xdb1}, + {0xdb3, 0xdbb}, {0xdbd, 0xdbd}, {0xdc0, 0xdc6}, {0xe01, 0xe30}, + {0xe32, 0xe33}, {0xe40, 0xe46}, {0xe81, 0xe82}, {0xe84, 0xe84}, + {0xe87, 0xe88}, {0xe8a, 0xe8a}, {0xe8d, 0xe8d}, {0xe94, 0xe97}, + {0xe99, 0xe9f}, {0xea1, 0xea3}, {0xea5, 0xea5}, {0xea7, 0xea7}, + {0xeaa, 0xeab}, {0xead, 0xeb0}, {0xeb2, 0xeb3}, {0xebd, 0xebd}, + {0xec0, 0xec4}, {0xec6, 0xec6}, {0xedc, 0xedd}, {0xf00, 0xf00}, + {0xf40, 0xf47}, {0xf49, 0xf6a}, {0xf88, 0xf8b}, {0x1000, 0x1021}, + {0x1023, 0x1027}, {0x1029, 0x102a}, {0x1050, 0x1055}, {0x10a0, 0x10c5}, + {0x10d0, 0x10f8}, {0x1100, 0x1159}, {0x115f, 0x11a2}, {0x11a8, 0x11f9}, + {0x1200, 0x1206}, {0x1208, 0x1246}, {0x1248, 0x1248}, {0x124a, 0x124d}, + {0x1250, 0x1256}, {0x1258, 0x1258}, {0x125a, 0x125d}, {0x1260, 0x1286}, + {0x1288, 0x1288}, {0x128a, 0x128d}, {0x1290, 0x12ae}, {0x12b0, 0x12b0}, + {0x12b2, 0x12b5}, {0x12b8, 0x12be}, {0x12c0, 0x12c0}, {0x12c2, 0x12c5}, + {0x12c8, 0x12ce}, {0x12d0, 0x12d6}, {0x12d8, 0x12ee}, {0x12f0, 0x130e}, + {0x1310, 0x1310}, {0x1312, 0x1315}, {0x1318, 0x131e}, {0x1320, 0x1346}, + {0x1348, 0x135a}, {0x13a0, 0x13f4}, {0x1401, 0x166c}, {0x166f, 0x1676}, + {0x1681, 0x169a}, {0x16a0, 0x16ea}, {0x1700, 0x170c}, {0x170e, 0x1711}, + {0x1720, 0x1731}, {0x1740, 0x1751}, {0x1760, 0x176c}, {0x176e, 0x1770}, + {0x1780, 0x17b3}, {0x17d7, 0x17d7}, {0x17dc, 0x17dc}, {0x1820, 0x1877}, + {0x1880, 0x18a8}, {0x1900, 0x191c}, {0x1950, 0x196d}, {0x1970, 0x1974}, + {0x1d00, 0x1d6b}, {0x1e00, 0x1e9b}, {0x1ea0, 0x1ef9}, {0x1f00, 0x1f15}, + {0x1f18, 0x1f1d}, {0x1f20, 0x1f45}, {0x1f48, 0x1f4d}, {0x1f50, 0x1f57}, + {0x1f59, 0x1f59}, {0x1f5b, 0x1f5b}, {0x1f5d, 0x1f5d}, {0x1f5f, 0x1f7d}, + {0x1f80, 0x1fb4}, {0x1fb6, 0x1fbc}, {0x1fbe, 0x1fbe}, {0x1fc2, 0x1fc4}, + {0x1fc6, 0x1fcc}, {0x1fd0, 0x1fd3}, {0x1fd6, 0x1fdb}, {0x1fe0, 0x1fec}, + {0x1ff2, 0x1ff4}, {0x1ff6, 0x1ffc}, {0x2071, 0x2071}, {0x207f, 0x207f}, + {0x2102, 0x2102}, {0x2107, 0x2107}, {0x210a, 0x2113}, {0x2115, 0x2115}, + {0x2119, 0x211d}, {0x2124, 0x2124}, {0x2126, 0x2126}, {0x2128, 0x2128}, + {0x212a, 0x212d}, {0x212f, 0x2131}, {0x2133, 0x2139}, {0x213d, 0x213f}, + {0x2145, 0x2149}, {0x3005, 0x3006}, {0x3031, 0x3035}, {0x303b, 0x303c}, + {0x3041, 0x3096}, {0x309d, 0x309f}, {0x30a1, 0x30fa}, {0x30fc, 0x30ff}, + {0x3105, 0x312c}, {0x3131, 0x318e}, {0x31a0, 0x31b7}, {0x31f0, 0x31ff}, + {0x3400, 0x3400}, {0x4db5, 0x4db5}, {0x4e00, 0x4e00}, {0x9fa5, 0x9fa5}, + {0xa000, 0xa48c}, {0xac00, 0xac00}, {0xd7a3, 0xd7a3}, {0xf900, 0xfa2d}, + {0xfa30, 0xfa6a}, {0xfb00, 0xfb06}, {0xfb13, 0xfb17}, {0xfb1d, 0xfb1d}, + {0xfb1f, 0xfb28}, {0xfb2a, 0xfb36}, {0xfb38, 0xfb3c}, {0xfb3e, 0xfb3e}, + {0xfb40, 0xfb41}, {0xfb43, 0xfb44}, {0xfb46, 0xfbb1}, {0xfbd3, 0xfd3d}, + {0xfd50, 0xfd8f}, {0xfd92, 0xfdc7}, {0xfdf0, 0xfdfb}, {0xfe70, 0xfe74}, + {0xfe76, 0xfefc}, {0xff21, 0xff3a}, {0xff41, 0xff5a}, {0xff66, 0xffbe}, + {0xffc2, 0xffc7}, {0xffca, 0xffcf}, {0xffd2, 0xffd7}, {0xffda, 0xffdc} }; +static const xmlChLRange xmlLL[] = {{0x10000, 0x1000b}, {0x1000d, 0x10026}, + {0x10028, 0x1003a}, {0x1003c, 0x1003d}, {0x1003f, 0x1004d}, + {0x10050, 0x1005d}, {0x10080, 0x100fa}, {0x10300, 0x1031e}, + {0x10330, 0x10349}, {0x10380, 0x1039d}, {0x10400, 0x1049d}, + {0x10800, 0x10805}, {0x10808, 0x10808}, {0x1080a, 0x10835}, + {0x10837, 0x10838}, {0x1083c, 0x1083c}, {0x1083f, 0x1083f}, + {0x1d400, 0x1d454}, {0x1d456, 0x1d49c}, {0x1d49e, 0x1d49f}, + {0x1d4a2, 0x1d4a2}, {0x1d4a5, 0x1d4a6}, {0x1d4a9, 0x1d4ac}, + {0x1d4ae, 0x1d4b9}, {0x1d4bb, 0x1d4bb}, {0x1d4bd, 0x1d4c3}, + {0x1d4c5, 0x1d505}, {0x1d507, 0x1d50a}, {0x1d50d, 0x1d514}, + {0x1d516, 0x1d51c}, {0x1d51e, 0x1d539}, {0x1d53b, 0x1d53e}, + {0x1d540, 0x1d544}, {0x1d546, 0x1d546}, {0x1d54a, 0x1d550}, + {0x1d552, 0x1d6a3}, {0x1d6a8, 0x1d6c0}, {0x1d6c2, 0x1d6da}, + {0x1d6dc, 0x1d6fa}, {0x1d6fc, 0x1d714}, {0x1d716, 0x1d734}, + {0x1d736, 0x1d74e}, {0x1d750, 0x1d76e}, {0x1d770, 0x1d788}, + {0x1d78a, 0x1d7a8}, {0x1d7aa, 0x1d7c2}, {0x1d7c4, 0x1d7c9}, + {0x20000, 0x20000}, {0x2a6d6, 0x2a6d6}, {0x2f800, 0x2fa1d} }; +static xmlChRangeGroup xmlLG = {279,50,xmlLS,xmlLL}; + +static const xmlChSRange xmlLlS[] = {{0x61, 0x7a}, {0xaa, 0xaa}, + {0xb5, 0xb5}, {0xba, 0xba}, {0xdf, 0xf6}, {0xf8, 0xff}, {0x101, 0x101}, + {0x103, 0x103}, {0x105, 0x105}, {0x107, 0x107}, {0x109, 0x109}, + {0x10b, 0x10b}, {0x10d, 0x10d}, {0x10f, 0x10f}, {0x111, 0x111}, + {0x113, 0x113}, {0x115, 0x115}, {0x117, 0x117}, {0x119, 0x119}, + {0x11b, 0x11b}, {0x11d, 0x11d}, {0x11f, 0x11f}, {0x121, 0x121}, + {0x123, 0x123}, {0x125, 0x125}, {0x127, 0x127}, {0x129, 0x129}, + {0x12b, 0x12b}, {0x12d, 0x12d}, {0x12f, 0x12f}, {0x131, 0x131}, + {0x133, 0x133}, {0x135, 0x135}, {0x137, 0x138}, {0x13a, 0x13a}, + {0x13c, 0x13c}, {0x13e, 0x13e}, {0x140, 0x140}, {0x142, 0x142}, + {0x144, 0x144}, {0x146, 0x146}, {0x148, 0x149}, {0x14b, 0x14b}, + {0x14d, 0x14d}, {0x14f, 0x14f}, {0x151, 0x151}, {0x153, 0x153}, + {0x155, 0x155}, {0x157, 0x157}, {0x159, 0x159}, {0x15b, 0x15b}, + {0x15d, 0x15d}, {0x15f, 0x15f}, {0x161, 0x161}, {0x163, 0x163}, + {0x165, 0x165}, {0x167, 0x167}, {0x169, 0x169}, {0x16b, 0x16b}, + {0x16d, 0x16d}, {0x16f, 0x16f}, {0x171, 0x171}, {0x173, 0x173}, + {0x175, 0x175}, {0x177, 0x177}, {0x17a, 0x17a}, {0x17c, 0x17c}, + {0x17e, 0x180}, {0x183, 0x183}, {0x185, 0x185}, {0x188, 0x188}, + {0x18c, 0x18d}, {0x192, 0x192}, {0x195, 0x195}, {0x199, 0x19b}, + {0x19e, 0x19e}, {0x1a1, 0x1a1}, {0x1a3, 0x1a3}, {0x1a5, 0x1a5}, + {0x1a8, 0x1a8}, {0x1aa, 0x1ab}, {0x1ad, 0x1ad}, {0x1b0, 0x1b0}, + {0x1b4, 0x1b4}, {0x1b6, 0x1b6}, {0x1b9, 0x1ba}, {0x1bd, 0x1bf}, + {0x1c6, 0x1c6}, {0x1c9, 0x1c9}, {0x1cc, 0x1cc}, {0x1ce, 0x1ce}, + {0x1d0, 0x1d0}, {0x1d2, 0x1d2}, {0x1d4, 0x1d4}, {0x1d6, 0x1d6}, + {0x1d8, 0x1d8}, {0x1da, 0x1da}, {0x1dc, 0x1dd}, {0x1df, 0x1df}, + {0x1e1, 0x1e1}, {0x1e3, 0x1e3}, {0x1e5, 0x1e5}, {0x1e7, 0x1e7}, + {0x1e9, 0x1e9}, {0x1eb, 0x1eb}, {0x1ed, 0x1ed}, {0x1ef, 0x1f0}, + {0x1f3, 0x1f3}, {0x1f5, 0x1f5}, {0x1f9, 0x1f9}, {0x1fb, 0x1fb}, + {0x1fd, 0x1fd}, {0x1ff, 0x1ff}, {0x201, 0x201}, {0x203, 0x203}, + {0x205, 0x205}, {0x207, 0x207}, {0x209, 0x209}, {0x20b, 0x20b}, + {0x20d, 0x20d}, {0x20f, 0x20f}, {0x211, 0x211}, {0x213, 0x213}, + {0x215, 0x215}, {0x217, 0x217}, {0x219, 0x219}, {0x21b, 0x21b}, + {0x21d, 0x21d}, {0x21f, 0x21f}, {0x221, 0x221}, {0x223, 0x223}, + {0x225, 0x225}, {0x227, 0x227}, {0x229, 0x229}, {0x22b, 0x22b}, + {0x22d, 0x22d}, {0x22f, 0x22f}, {0x231, 0x231}, {0x233, 0x236}, + {0x250, 0x2af}, {0x390, 0x390}, {0x3ac, 0x3ce}, {0x3d0, 0x3d1}, + {0x3d5, 0x3d7}, {0x3d9, 0x3d9}, {0x3db, 0x3db}, {0x3dd, 0x3dd}, + {0x3df, 0x3df}, {0x3e1, 0x3e1}, {0x3e3, 0x3e3}, {0x3e5, 0x3e5}, + {0x3e7, 0x3e7}, {0x3e9, 0x3e9}, {0x3eb, 0x3eb}, {0x3ed, 0x3ed}, + {0x3ef, 0x3f3}, {0x3f5, 0x3f5}, {0x3f8, 0x3f8}, {0x3fb, 0x3fb}, + {0x430, 0x45f}, {0x461, 0x461}, {0x463, 0x463}, {0x465, 0x465}, + {0x467, 0x467}, {0x469, 0x469}, {0x46b, 0x46b}, {0x46d, 0x46d}, + {0x46f, 0x46f}, {0x471, 0x471}, {0x473, 0x473}, {0x475, 0x475}, + {0x477, 0x477}, {0x479, 0x479}, {0x47b, 0x47b}, {0x47d, 0x47d}, + {0x47f, 0x47f}, {0x481, 0x481}, {0x48b, 0x48b}, {0x48d, 0x48d}, + {0x48f, 0x48f}, {0x491, 0x491}, {0x493, 0x493}, {0x495, 0x495}, + {0x497, 0x497}, {0x499, 0x499}, {0x49b, 0x49b}, {0x49d, 0x49d}, + {0x49f, 0x49f}, {0x4a1, 0x4a1}, {0x4a3, 0x4a3}, {0x4a5, 0x4a5}, + {0x4a7, 0x4a7}, {0x4a9, 0x4a9}, {0x4ab, 0x4ab}, {0x4ad, 0x4ad}, + {0x4af, 0x4af}, {0x4b1, 0x4b1}, {0x4b3, 0x4b3}, {0x4b5, 0x4b5}, + {0x4b7, 0x4b7}, {0x4b9, 0x4b9}, {0x4bb, 0x4bb}, {0x4bd, 0x4bd}, + {0x4bf, 0x4bf}, {0x4c2, 0x4c2}, {0x4c4, 0x4c4}, {0x4c6, 0x4c6}, + {0x4c8, 0x4c8}, {0x4ca, 0x4ca}, {0x4cc, 0x4cc}, {0x4ce, 0x4ce}, + {0x4d1, 0x4d1}, {0x4d3, 0x4d3}, {0x4d5, 0x4d5}, {0x4d7, 0x4d7}, + {0x4d9, 0x4d9}, {0x4db, 0x4db}, {0x4dd, 0x4dd}, {0x4df, 0x4df}, + {0x4e1, 0x4e1}, {0x4e3, 0x4e3}, {0x4e5, 0x4e5}, {0x4e7, 0x4e7}, + {0x4e9, 0x4e9}, {0x4eb, 0x4eb}, {0x4ed, 0x4ed}, {0x4ef, 0x4ef}, + {0x4f1, 0x4f1}, {0x4f3, 0x4f3}, {0x4f5, 0x4f5}, {0x4f9, 0x4f9}, + {0x501, 0x501}, {0x503, 0x503}, {0x505, 0x505}, {0x507, 0x507}, + {0x509, 0x509}, {0x50b, 0x50b}, {0x50d, 0x50d}, {0x50f, 0x50f}, + {0x561, 0x587}, {0x1d00, 0x1d2b}, {0x1d62, 0x1d6b}, {0x1e01, 0x1e01}, + {0x1e03, 0x1e03}, {0x1e05, 0x1e05}, {0x1e07, 0x1e07}, {0x1e09, 0x1e09}, + {0x1e0b, 0x1e0b}, {0x1e0d, 0x1e0d}, {0x1e0f, 0x1e0f}, {0x1e11, 0x1e11}, + {0x1e13, 0x1e13}, {0x1e15, 0x1e15}, {0x1e17, 0x1e17}, {0x1e19, 0x1e19}, + {0x1e1b, 0x1e1b}, {0x1e1d, 0x1e1d}, {0x1e1f, 0x1e1f}, {0x1e21, 0x1e21}, + {0x1e23, 0x1e23}, {0x1e25, 0x1e25}, {0x1e27, 0x1e27}, {0x1e29, 0x1e29}, + {0x1e2b, 0x1e2b}, {0x1e2d, 0x1e2d}, {0x1e2f, 0x1e2f}, {0x1e31, 0x1e31}, + {0x1e33, 0x1e33}, {0x1e35, 0x1e35}, {0x1e37, 0x1e37}, {0x1e39, 0x1e39}, + {0x1e3b, 0x1e3b}, {0x1e3d, 0x1e3d}, {0x1e3f, 0x1e3f}, {0x1e41, 0x1e41}, + {0x1e43, 0x1e43}, {0x1e45, 0x1e45}, {0x1e47, 0x1e47}, {0x1e49, 0x1e49}, + {0x1e4b, 0x1e4b}, {0x1e4d, 0x1e4d}, {0x1e4f, 0x1e4f}, {0x1e51, 0x1e51}, + {0x1e53, 0x1e53}, {0x1e55, 0x1e55}, {0x1e57, 0x1e57}, {0x1e59, 0x1e59}, + {0x1e5b, 0x1e5b}, {0x1e5d, 0x1e5d}, {0x1e5f, 0x1e5f}, {0x1e61, 0x1e61}, + {0x1e63, 0x1e63}, {0x1e65, 0x1e65}, {0x1e67, 0x1e67}, {0x1e69, 0x1e69}, + {0x1e6b, 0x1e6b}, {0x1e6d, 0x1e6d}, {0x1e6f, 0x1e6f}, {0x1e71, 0x1e71}, + {0x1e73, 0x1e73}, {0x1e75, 0x1e75}, {0x1e77, 0x1e77}, {0x1e79, 0x1e79}, + {0x1e7b, 0x1e7b}, {0x1e7d, 0x1e7d}, {0x1e7f, 0x1e7f}, {0x1e81, 0x1e81}, + {0x1e83, 0x1e83}, {0x1e85, 0x1e85}, {0x1e87, 0x1e87}, {0x1e89, 0x1e89}, + {0x1e8b, 0x1e8b}, {0x1e8d, 0x1e8d}, {0x1e8f, 0x1e8f}, {0x1e91, 0x1e91}, + {0x1e93, 0x1e93}, {0x1e95, 0x1e9b}, {0x1ea1, 0x1ea1}, {0x1ea3, 0x1ea3}, + {0x1ea5, 0x1ea5}, {0x1ea7, 0x1ea7}, {0x1ea9, 0x1ea9}, {0x1eab, 0x1eab}, + {0x1ead, 0x1ead}, {0x1eaf, 0x1eaf}, {0x1eb1, 0x1eb1}, {0x1eb3, 0x1eb3}, + {0x1eb5, 0x1eb5}, {0x1eb7, 0x1eb7}, {0x1eb9, 0x1eb9}, {0x1ebb, 0x1ebb}, + {0x1ebd, 0x1ebd}, {0x1ebf, 0x1ebf}, {0x1ec1, 0x1ec1}, {0x1ec3, 0x1ec3}, + {0x1ec5, 0x1ec5}, {0x1ec7, 0x1ec7}, {0x1ec9, 0x1ec9}, {0x1ecb, 0x1ecb}, + {0x1ecd, 0x1ecd}, {0x1ecf, 0x1ecf}, {0x1ed1, 0x1ed1}, {0x1ed3, 0x1ed3}, + {0x1ed5, 0x1ed5}, {0x1ed7, 0x1ed7}, {0x1ed9, 0x1ed9}, {0x1edb, 0x1edb}, + {0x1edd, 0x1edd}, {0x1edf, 0x1edf}, {0x1ee1, 0x1ee1}, {0x1ee3, 0x1ee3}, + {0x1ee5, 0x1ee5}, {0x1ee7, 0x1ee7}, {0x1ee9, 0x1ee9}, {0x1eeb, 0x1eeb}, + {0x1eed, 0x1eed}, {0x1eef, 0x1eef}, {0x1ef1, 0x1ef1}, {0x1ef3, 0x1ef3}, + {0x1ef5, 0x1ef5}, {0x1ef7, 0x1ef7}, {0x1ef9, 0x1ef9}, {0x1f00, 0x1f07}, + {0x1f10, 0x1f15}, {0x1f20, 0x1f27}, {0x1f30, 0x1f37}, {0x1f40, 0x1f45}, + {0x1f50, 0x1f57}, {0x1f60, 0x1f67}, {0x1f70, 0x1f7d}, {0x1f80, 0x1f87}, + {0x1f90, 0x1f97}, {0x1fa0, 0x1fa7}, {0x1fb0, 0x1fb4}, {0x1fb6, 0x1fb7}, + {0x1fbe, 0x1fbe}, {0x1fc2, 0x1fc4}, {0x1fc6, 0x1fc7}, {0x1fd0, 0x1fd3}, + {0x1fd6, 0x1fd7}, {0x1fe0, 0x1fe7}, {0x1ff2, 0x1ff4}, {0x1ff6, 0x1ff7}, + {0x2071, 0x2071}, {0x207f, 0x207f}, {0x210a, 0x210a}, {0x210e, 0x210f}, + {0x2113, 0x2113}, {0x212f, 0x212f}, {0x2134, 0x2134}, {0x2139, 0x2139}, + {0x213d, 0x213d}, {0x2146, 0x2149}, {0xfb00, 0xfb06}, {0xfb13, 0xfb17}, + {0xff41, 0xff5a} }; +static const xmlChLRange xmlLlL[] = {{0x10428, 0x1044f}, {0x1d41a, 0x1d433}, + {0x1d44e, 0x1d454}, {0x1d456, 0x1d467}, {0x1d482, 0x1d49b}, + {0x1d4b6, 0x1d4b9}, {0x1d4bb, 0x1d4bb}, {0x1d4bd, 0x1d4c3}, + {0x1d4c5, 0x1d4cf}, {0x1d4ea, 0x1d503}, {0x1d51e, 0x1d537}, + {0x1d552, 0x1d56b}, {0x1d586, 0x1d59f}, {0x1d5ba, 0x1d5d3}, + {0x1d5ee, 0x1d607}, {0x1d622, 0x1d63b}, {0x1d656, 0x1d66f}, + {0x1d68a, 0x1d6a3}, {0x1d6c2, 0x1d6da}, {0x1d6dc, 0x1d6e1}, + {0x1d6fc, 0x1d714}, {0x1d716, 0x1d71b}, {0x1d736, 0x1d74e}, + {0x1d750, 0x1d755}, {0x1d770, 0x1d788}, {0x1d78a, 0x1d78f}, + {0x1d7aa, 0x1d7c2}, {0x1d7c4, 0x1d7c9} }; +static xmlChRangeGroup xmlLlG = {396,28,xmlLlS,xmlLlL}; + +static const xmlChSRange xmlLmS[] = {{0x2b0, 0x2c1}, {0x2c6, 0x2d1}, + {0x2e0, 0x2e4}, {0x2ee, 0x2ee}, {0x37a, 0x37a}, {0x559, 0x559}, + {0x640, 0x640}, {0x6e5, 0x6e6}, {0xe46, 0xe46}, {0xec6, 0xec6}, + {0x17d7, 0x17d7}, {0x1843, 0x1843}, {0x1d2c, 0x1d61}, {0x3005, 0x3005}, + {0x3031, 0x3035}, {0x303b, 0x303b}, {0x309d, 0x309e}, {0x30fc, 0x30fe}, + {0xff70, 0xff70}, {0xff9e, 0xff9f} }; +static xmlChRangeGroup xmlLmG = {20,0,xmlLmS,NULL}; + +static const xmlChSRange xmlLoS[] = {{0x1bb, 0x1bb}, {0x1c0, 0x1c3}, + {0x5d0, 0x5ea}, {0x5f0, 0x5f2}, {0x621, 0x63a}, {0x641, 0x64a}, + {0x66e, 0x66f}, {0x671, 0x6d3}, {0x6d5, 0x6d5}, {0x6ee, 0x6ef}, + {0x6fa, 0x6fc}, {0x6ff, 0x6ff}, {0x710, 0x710}, {0x712, 0x72f}, + {0x74d, 0x74f}, {0x780, 0x7a5}, {0x7b1, 0x7b1}, {0x904, 0x939}, + {0x93d, 0x93d}, {0x950, 0x950}, {0x958, 0x961}, {0x985, 0x98c}, + {0x98f, 0x990}, {0x993, 0x9a8}, {0x9aa, 0x9b0}, {0x9b2, 0x9b2}, + {0x9b6, 0x9b9}, {0x9bd, 0x9bd}, {0x9dc, 0x9dd}, {0x9df, 0x9e1}, + {0x9f0, 0x9f1}, {0xa05, 0xa0a}, {0xa0f, 0xa10}, {0xa13, 0xa28}, + {0xa2a, 0xa30}, {0xa32, 0xa33}, {0xa35, 0xa36}, {0xa38, 0xa39}, + {0xa59, 0xa5c}, {0xa5e, 0xa5e}, {0xa72, 0xa74}, {0xa85, 0xa8d}, + {0xa8f, 0xa91}, {0xa93, 0xaa8}, {0xaaa, 0xab0}, {0xab2, 0xab3}, + {0xab5, 0xab9}, {0xabd, 0xabd}, {0xad0, 0xad0}, {0xae0, 0xae1}, + {0xb05, 0xb0c}, {0xb0f, 0xb10}, {0xb13, 0xb28}, {0xb2a, 0xb30}, + {0xb32, 0xb33}, {0xb35, 0xb39}, {0xb3d, 0xb3d}, {0xb5c, 0xb5d}, + {0xb5f, 0xb61}, {0xb71, 0xb71}, {0xb83, 0xb83}, {0xb85, 0xb8a}, + {0xb8e, 0xb90}, {0xb92, 0xb95}, {0xb99, 0xb9a}, {0xb9c, 0xb9c}, + {0xb9e, 0xb9f}, {0xba3, 0xba4}, {0xba8, 0xbaa}, {0xbae, 0xbb5}, + {0xbb7, 0xbb9}, {0xc05, 0xc0c}, {0xc0e, 0xc10}, {0xc12, 0xc28}, + {0xc2a, 0xc33}, {0xc35, 0xc39}, {0xc60, 0xc61}, {0xc85, 0xc8c}, + {0xc8e, 0xc90}, {0xc92, 0xca8}, {0xcaa, 0xcb3}, {0xcb5, 0xcb9}, + {0xcbd, 0xcbd}, {0xcde, 0xcde}, {0xce0, 0xce1}, {0xd05, 0xd0c}, + {0xd0e, 0xd10}, {0xd12, 0xd28}, {0xd2a, 0xd39}, {0xd60, 0xd61}, + {0xd85, 0xd96}, {0xd9a, 0xdb1}, {0xdb3, 0xdbb}, {0xdbd, 0xdbd}, + {0xdc0, 0xdc6}, {0xe01, 0xe30}, {0xe32, 0xe33}, {0xe40, 0xe45}, + {0xe81, 0xe82}, {0xe84, 0xe84}, {0xe87, 0xe88}, {0xe8a, 0xe8a}, + {0xe8d, 0xe8d}, {0xe94, 0xe97}, {0xe99, 0xe9f}, {0xea1, 0xea3}, + {0xea5, 0xea5}, {0xea7, 0xea7}, {0xeaa, 0xeab}, {0xead, 0xeb0}, + {0xeb2, 0xeb3}, {0xebd, 0xebd}, {0xec0, 0xec4}, {0xedc, 0xedd}, + {0xf00, 0xf00}, {0xf40, 0xf47}, {0xf49, 0xf6a}, {0xf88, 0xf8b}, + {0x1000, 0x1021}, {0x1023, 0x1027}, {0x1029, 0x102a}, {0x1050, 0x1055}, + {0x10d0, 0x10f8}, {0x1100, 0x1159}, {0x115f, 0x11a2}, {0x11a8, 0x11f9}, + {0x1200, 0x1206}, {0x1208, 0x1246}, {0x1248, 0x1248}, {0x124a, 0x124d}, + {0x1250, 0x1256}, {0x1258, 0x1258}, {0x125a, 0x125d}, {0x1260, 0x1286}, + {0x1288, 0x1288}, {0x128a, 0x128d}, {0x1290, 0x12ae}, {0x12b0, 0x12b0}, + {0x12b2, 0x12b5}, {0x12b8, 0x12be}, {0x12c0, 0x12c0}, {0x12c2, 0x12c5}, + {0x12c8, 0x12ce}, {0x12d0, 0x12d6}, {0x12d8, 0x12ee}, {0x12f0, 0x130e}, + {0x1310, 0x1310}, {0x1312, 0x1315}, {0x1318, 0x131e}, {0x1320, 0x1346}, + {0x1348, 0x135a}, {0x13a0, 0x13f4}, {0x1401, 0x166c}, {0x166f, 0x1676}, + {0x1681, 0x169a}, {0x16a0, 0x16ea}, {0x1700, 0x170c}, {0x170e, 0x1711}, + {0x1720, 0x1731}, {0x1740, 0x1751}, {0x1760, 0x176c}, {0x176e, 0x1770}, + {0x1780, 0x17b3}, {0x17dc, 0x17dc}, {0x1820, 0x1842}, {0x1844, 0x1877}, + {0x1880, 0x18a8}, {0x1900, 0x191c}, {0x1950, 0x196d}, {0x1970, 0x1974}, + {0x2135, 0x2138}, {0x3006, 0x3006}, {0x303c, 0x303c}, {0x3041, 0x3096}, + {0x309f, 0x309f}, {0x30a1, 0x30fa}, {0x30ff, 0x30ff}, {0x3105, 0x312c}, + {0x3131, 0x318e}, {0x31a0, 0x31b7}, {0x31f0, 0x31ff}, {0x3400, 0x3400}, + {0x4db5, 0x4db5}, {0x4e00, 0x4e00}, {0x9fa5, 0x9fa5}, {0xa000, 0xa48c}, + {0xac00, 0xac00}, {0xd7a3, 0xd7a3}, {0xf900, 0xfa2d}, {0xfa30, 0xfa6a}, + {0xfb1d, 0xfb1d}, {0xfb1f, 0xfb28}, {0xfb2a, 0xfb36}, {0xfb38, 0xfb3c}, + {0xfb3e, 0xfb3e}, {0xfb40, 0xfb41}, {0xfb43, 0xfb44}, {0xfb46, 0xfbb1}, + {0xfbd3, 0xfd3d}, {0xfd50, 0xfd8f}, {0xfd92, 0xfdc7}, {0xfdf0, 0xfdfb}, + {0xfe70, 0xfe74}, {0xfe76, 0xfefc}, {0xff66, 0xff6f}, {0xff71, 0xff9d}, + {0xffa0, 0xffbe}, {0xffc2, 0xffc7}, {0xffca, 0xffcf}, {0xffd2, 0xffd7}, + {0xffda, 0xffdc} }; +static const xmlChLRange xmlLoL[] = {{0x10000, 0x1000b}, {0x1000d, 0x10026}, + {0x10028, 0x1003a}, {0x1003c, 0x1003d}, {0x1003f, 0x1004d}, + {0x10050, 0x1005d}, {0x10080, 0x100fa}, {0x10300, 0x1031e}, + {0x10330, 0x10349}, {0x10380, 0x1039d}, {0x10450, 0x1049d}, + {0x10800, 0x10805}, {0x10808, 0x10808}, {0x1080a, 0x10835}, + {0x10837, 0x10838}, {0x1083c, 0x1083c}, {0x1083f, 0x1083f}, + {0x20000, 0x20000}, {0x2a6d6, 0x2a6d6}, {0x2f800, 0x2fa1d} }; +static xmlChRangeGroup xmlLoG = {211,20,xmlLoS,xmlLoL}; + +static const xmlChSRange xmlLtS[] = {{0x1c5, 0x1c5}, {0x1c8, 0x1c8}, + {0x1cb, 0x1cb}, {0x1f2, 0x1f2}, {0x1f88, 0x1f8f}, {0x1f98, 0x1f9f}, + {0x1fa8, 0x1faf}, {0x1fbc, 0x1fbc}, {0x1fcc, 0x1fcc}, {0x1ffc, 0x1ffc} }; +static xmlChRangeGroup xmlLtG = {10,0,xmlLtS,NULL}; + +static const xmlChSRange xmlLuS[] = {{0x41, 0x5a}, {0xc0, 0xd6}, + {0xd8, 0xde}, {0x100, 0x100}, {0x102, 0x102}, {0x104, 0x104}, + {0x106, 0x106}, {0x108, 0x108}, {0x10a, 0x10a}, {0x10c, 0x10c}, + {0x10e, 0x10e}, {0x110, 0x110}, {0x112, 0x112}, {0x114, 0x114}, + {0x116, 0x116}, {0x118, 0x118}, {0x11a, 0x11a}, {0x11c, 0x11c}, + {0x11e, 0x11e}, {0x120, 0x120}, {0x122, 0x122}, {0x124, 0x124}, + {0x126, 0x126}, {0x128, 0x128}, {0x12a, 0x12a}, {0x12c, 0x12c}, + {0x12e, 0x12e}, {0x130, 0x130}, {0x132, 0x132}, {0x134, 0x134}, + {0x136, 0x136}, {0x139, 0x139}, {0x13b, 0x13b}, {0x13d, 0x13d}, + {0x13f, 0x13f}, {0x141, 0x141}, {0x143, 0x143}, {0x145, 0x145}, + {0x147, 0x147}, {0x14a, 0x14a}, {0x14c, 0x14c}, {0x14e, 0x14e}, + {0x150, 0x150}, {0x152, 0x152}, {0x154, 0x154}, {0x156, 0x156}, + {0x158, 0x158}, {0x15a, 0x15a}, {0x15c, 0x15c}, {0x15e, 0x15e}, + {0x160, 0x160}, {0x162, 0x162}, {0x164, 0x164}, {0x166, 0x166}, + {0x168, 0x168}, {0x16a, 0x16a}, {0x16c, 0x16c}, {0x16e, 0x16e}, + {0x170, 0x170}, {0x172, 0x172}, {0x174, 0x174}, {0x176, 0x176}, + {0x178, 0x179}, {0x17b, 0x17b}, {0x17d, 0x17d}, {0x181, 0x182}, + {0x184, 0x184}, {0x186, 0x187}, {0x189, 0x18b}, {0x18e, 0x191}, + {0x193, 0x194}, {0x196, 0x198}, {0x19c, 0x19d}, {0x19f, 0x1a0}, + {0x1a2, 0x1a2}, {0x1a4, 0x1a4}, {0x1a6, 0x1a7}, {0x1a9, 0x1a9}, + {0x1ac, 0x1ac}, {0x1ae, 0x1af}, {0x1b1, 0x1b3}, {0x1b5, 0x1b5}, + {0x1b7, 0x1b8}, {0x1bc, 0x1bc}, {0x1c4, 0x1c4}, {0x1c7, 0x1c7}, + {0x1ca, 0x1ca}, {0x1cd, 0x1cd}, {0x1cf, 0x1cf}, {0x1d1, 0x1d1}, + {0x1d3, 0x1d3}, {0x1d5, 0x1d5}, {0x1d7, 0x1d7}, {0x1d9, 0x1d9}, + {0x1db, 0x1db}, {0x1de, 0x1de}, {0x1e0, 0x1e0}, {0x1e2, 0x1e2}, + {0x1e4, 0x1e4}, {0x1e6, 0x1e6}, {0x1e8, 0x1e8}, {0x1ea, 0x1ea}, + {0x1ec, 0x1ec}, {0x1ee, 0x1ee}, {0x1f1, 0x1f1}, {0x1f4, 0x1f4}, + {0x1f6, 0x1f8}, {0x1fa, 0x1fa}, {0x1fc, 0x1fc}, {0x1fe, 0x1fe}, + {0x200, 0x200}, {0x202, 0x202}, {0x204, 0x204}, {0x206, 0x206}, + {0x208, 0x208}, {0x20a, 0x20a}, {0x20c, 0x20c}, {0x20e, 0x20e}, + {0x210, 0x210}, {0x212, 0x212}, {0x214, 0x214}, {0x216, 0x216}, + {0x218, 0x218}, {0x21a, 0x21a}, {0x21c, 0x21c}, {0x21e, 0x21e}, + {0x220, 0x220}, {0x222, 0x222}, {0x224, 0x224}, {0x226, 0x226}, + {0x228, 0x228}, {0x22a, 0x22a}, {0x22c, 0x22c}, {0x22e, 0x22e}, + {0x230, 0x230}, {0x232, 0x232}, {0x386, 0x386}, {0x388, 0x38a}, + {0x38c, 0x38c}, {0x38e, 0x38f}, {0x391, 0x3a1}, {0x3a3, 0x3ab}, + {0x3d2, 0x3d4}, {0x3d8, 0x3d8}, {0x3da, 0x3da}, {0x3dc, 0x3dc}, + {0x3de, 0x3de}, {0x3e0, 0x3e0}, {0x3e2, 0x3e2}, {0x3e4, 0x3e4}, + {0x3e6, 0x3e6}, {0x3e8, 0x3e8}, {0x3ea, 0x3ea}, {0x3ec, 0x3ec}, + {0x3ee, 0x3ee}, {0x3f4, 0x3f4}, {0x3f7, 0x3f7}, {0x3f9, 0x3fa}, + {0x400, 0x42f}, {0x460, 0x460}, {0x462, 0x462}, {0x464, 0x464}, + {0x466, 0x466}, {0x468, 0x468}, {0x46a, 0x46a}, {0x46c, 0x46c}, + {0x46e, 0x46e}, {0x470, 0x470}, {0x472, 0x472}, {0x474, 0x474}, + {0x476, 0x476}, {0x478, 0x478}, {0x47a, 0x47a}, {0x47c, 0x47c}, + {0x47e, 0x47e}, {0x480, 0x480}, {0x48a, 0x48a}, {0x48c, 0x48c}, + {0x48e, 0x48e}, {0x490, 0x490}, {0x492, 0x492}, {0x494, 0x494}, + {0x496, 0x496}, {0x498, 0x498}, {0x49a, 0x49a}, {0x49c, 0x49c}, + {0x49e, 0x49e}, {0x4a0, 0x4a0}, {0x4a2, 0x4a2}, {0x4a4, 0x4a4}, + {0x4a6, 0x4a6}, {0x4a8, 0x4a8}, {0x4aa, 0x4aa}, {0x4ac, 0x4ac}, + {0x4ae, 0x4ae}, {0x4b0, 0x4b0}, {0x4b2, 0x4b2}, {0x4b4, 0x4b4}, + {0x4b6, 0x4b6}, {0x4b8, 0x4b8}, {0x4ba, 0x4ba}, {0x4bc, 0x4bc}, + {0x4be, 0x4be}, {0x4c0, 0x4c1}, {0x4c3, 0x4c3}, {0x4c5, 0x4c5}, + {0x4c7, 0x4c7}, {0x4c9, 0x4c9}, {0x4cb, 0x4cb}, {0x4cd, 0x4cd}, + {0x4d0, 0x4d0}, {0x4d2, 0x4d2}, {0x4d4, 0x4d4}, {0x4d6, 0x4d6}, + {0x4d8, 0x4d8}, {0x4da, 0x4da}, {0x4dc, 0x4dc}, {0x4de, 0x4de}, + {0x4e0, 0x4e0}, {0x4e2, 0x4e2}, {0x4e4, 0x4e4}, {0x4e6, 0x4e6}, + {0x4e8, 0x4e8}, {0x4ea, 0x4ea}, {0x4ec, 0x4ec}, {0x4ee, 0x4ee}, + {0x4f0, 0x4f0}, {0x4f2, 0x4f2}, {0x4f4, 0x4f4}, {0x4f8, 0x4f8}, + {0x500, 0x500}, {0x502, 0x502}, {0x504, 0x504}, {0x506, 0x506}, + {0x508, 0x508}, {0x50a, 0x50a}, {0x50c, 0x50c}, {0x50e, 0x50e}, + {0x531, 0x556}, {0x10a0, 0x10c5}, {0x1e00, 0x1e00}, {0x1e02, 0x1e02}, + {0x1e04, 0x1e04}, {0x1e06, 0x1e06}, {0x1e08, 0x1e08}, {0x1e0a, 0x1e0a}, + {0x1e0c, 0x1e0c}, {0x1e0e, 0x1e0e}, {0x1e10, 0x1e10}, {0x1e12, 0x1e12}, + {0x1e14, 0x1e14}, {0x1e16, 0x1e16}, {0x1e18, 0x1e18}, {0x1e1a, 0x1e1a}, + {0x1e1c, 0x1e1c}, {0x1e1e, 0x1e1e}, {0x1e20, 0x1e20}, {0x1e22, 0x1e22}, + {0x1e24, 0x1e24}, {0x1e26, 0x1e26}, {0x1e28, 0x1e28}, {0x1e2a, 0x1e2a}, + {0x1e2c, 0x1e2c}, {0x1e2e, 0x1e2e}, {0x1e30, 0x1e30}, {0x1e32, 0x1e32}, + {0x1e34, 0x1e34}, {0x1e36, 0x1e36}, {0x1e38, 0x1e38}, {0x1e3a, 0x1e3a}, + {0x1e3c, 0x1e3c}, {0x1e3e, 0x1e3e}, {0x1e40, 0x1e40}, {0x1e42, 0x1e42}, + {0x1e44, 0x1e44}, {0x1e46, 0x1e46}, {0x1e48, 0x1e48}, {0x1e4a, 0x1e4a}, + {0x1e4c, 0x1e4c}, {0x1e4e, 0x1e4e}, {0x1e50, 0x1e50}, {0x1e52, 0x1e52}, + {0x1e54, 0x1e54}, {0x1e56, 0x1e56}, {0x1e58, 0x1e58}, {0x1e5a, 0x1e5a}, + {0x1e5c, 0x1e5c}, {0x1e5e, 0x1e5e}, {0x1e60, 0x1e60}, {0x1e62, 0x1e62}, + {0x1e64, 0x1e64}, {0x1e66, 0x1e66}, {0x1e68, 0x1e68}, {0x1e6a, 0x1e6a}, + {0x1e6c, 0x1e6c}, {0x1e6e, 0x1e6e}, {0x1e70, 0x1e70}, {0x1e72, 0x1e72}, + {0x1e74, 0x1e74}, {0x1e76, 0x1e76}, {0x1e78, 0x1e78}, {0x1e7a, 0x1e7a}, + {0x1e7c, 0x1e7c}, {0x1e7e, 0x1e7e}, {0x1e80, 0x1e80}, {0x1e82, 0x1e82}, + {0x1e84, 0x1e84}, {0x1e86, 0x1e86}, {0x1e88, 0x1e88}, {0x1e8a, 0x1e8a}, + {0x1e8c, 0x1e8c}, {0x1e8e, 0x1e8e}, {0x1e90, 0x1e90}, {0x1e92, 0x1e92}, + {0x1e94, 0x1e94}, {0x1ea0, 0x1ea0}, {0x1ea2, 0x1ea2}, {0x1ea4, 0x1ea4}, + {0x1ea6, 0x1ea6}, {0x1ea8, 0x1ea8}, {0x1eaa, 0x1eaa}, {0x1eac, 0x1eac}, + {0x1eae, 0x1eae}, {0x1eb0, 0x1eb0}, {0x1eb2, 0x1eb2}, {0x1eb4, 0x1eb4}, + {0x1eb6, 0x1eb6}, {0x1eb8, 0x1eb8}, {0x1eba, 0x1eba}, {0x1ebc, 0x1ebc}, + {0x1ebe, 0x1ebe}, {0x1ec0, 0x1ec0}, {0x1ec2, 0x1ec2}, {0x1ec4, 0x1ec4}, + {0x1ec6, 0x1ec6}, {0x1ec8, 0x1ec8}, {0x1eca, 0x1eca}, {0x1ecc, 0x1ecc}, + {0x1ece, 0x1ece}, {0x1ed0, 0x1ed0}, {0x1ed2, 0x1ed2}, {0x1ed4, 0x1ed4}, + {0x1ed6, 0x1ed6}, {0x1ed8, 0x1ed8}, {0x1eda, 0x1eda}, {0x1edc, 0x1edc}, + {0x1ede, 0x1ede}, {0x1ee0, 0x1ee0}, {0x1ee2, 0x1ee2}, {0x1ee4, 0x1ee4}, + {0x1ee6, 0x1ee6}, {0x1ee8, 0x1ee8}, {0x1eea, 0x1eea}, {0x1eec, 0x1eec}, + {0x1eee, 0x1eee}, {0x1ef0, 0x1ef0}, {0x1ef2, 0x1ef2}, {0x1ef4, 0x1ef4}, + {0x1ef6, 0x1ef6}, {0x1ef8, 0x1ef8}, {0x1f08, 0x1f0f}, {0x1f18, 0x1f1d}, + {0x1f28, 0x1f2f}, {0x1f38, 0x1f3f}, {0x1f48, 0x1f4d}, {0x1f59, 0x1f59}, + {0x1f5b, 0x1f5b}, {0x1f5d, 0x1f5d}, {0x1f5f, 0x1f5f}, {0x1f68, 0x1f6f}, + {0x1fb8, 0x1fbb}, {0x1fc8, 0x1fcb}, {0x1fd8, 0x1fdb}, {0x1fe8, 0x1fec}, + {0x1ff8, 0x1ffb}, {0x2102, 0x2102}, {0x2107, 0x2107}, {0x210b, 0x210d}, + {0x2110, 0x2112}, {0x2115, 0x2115}, {0x2119, 0x211d}, {0x2124, 0x2124}, + {0x2126, 0x2126}, {0x2128, 0x2128}, {0x212a, 0x212d}, {0x2130, 0x2131}, + {0x2133, 0x2133}, {0x213e, 0x213f}, {0x2145, 0x2145}, {0xff21, 0xff3a} }; +static const xmlChLRange xmlLuL[] = {{0x10400, 0x10427}, {0x1d400, 0x1d419}, + {0x1d434, 0x1d44d}, {0x1d468, 0x1d481}, {0x1d49c, 0x1d49c}, + {0x1d49e, 0x1d49f}, {0x1d4a2, 0x1d4a2}, {0x1d4a5, 0x1d4a6}, + {0x1d4a9, 0x1d4ac}, {0x1d4ae, 0x1d4b5}, {0x1d4d0, 0x1d4e9}, + {0x1d504, 0x1d505}, {0x1d507, 0x1d50a}, {0x1d50d, 0x1d514}, + {0x1d516, 0x1d51c}, {0x1d538, 0x1d539}, {0x1d53b, 0x1d53e}, + {0x1d540, 0x1d544}, {0x1d546, 0x1d546}, {0x1d54a, 0x1d550}, + {0x1d56c, 0x1d585}, {0x1d5a0, 0x1d5b9}, {0x1d5d4, 0x1d5ed}, + {0x1d608, 0x1d621}, {0x1d63c, 0x1d655}, {0x1d670, 0x1d689}, + {0x1d6a8, 0x1d6c0}, {0x1d6e2, 0x1d6fa}, {0x1d71c, 0x1d734}, + {0x1d756, 0x1d76e}, {0x1d790, 0x1d7a8} }; +static xmlChRangeGroup xmlLuG = {390,31,xmlLuS,xmlLuL}; + +static const xmlChSRange xmlMS[] = {{0x300, 0x357}, {0x35d, 0x36f}, + {0x483, 0x486}, {0x488, 0x489}, {0x591, 0x5a1}, {0x5a3, 0x5b9}, + {0x5bb, 0x5bd}, {0x5bf, 0x5bf}, {0x5c1, 0x5c2}, {0x5c4, 0x5c4}, + {0x610, 0x615}, {0x64b, 0x658}, {0x670, 0x670}, {0x6d6, 0x6dc}, + {0x6de, 0x6e4}, {0x6e7, 0x6e8}, {0x6ea, 0x6ed}, {0x711, 0x711}, + {0x730, 0x74a}, {0x7a6, 0x7b0}, {0x901, 0x903}, {0x93c, 0x93c}, + {0x93e, 0x94d}, {0x951, 0x954}, {0x962, 0x963}, {0x981, 0x983}, + {0x9bc, 0x9bc}, {0x9be, 0x9c4}, {0x9c7, 0x9c8}, {0x9cb, 0x9cd}, + {0x9d7, 0x9d7}, {0x9e2, 0x9e3}, {0xa01, 0xa03}, {0xa3c, 0xa3c}, + {0xa3e, 0xa42}, {0xa47, 0xa48}, {0xa4b, 0xa4d}, {0xa70, 0xa71}, + {0xa81, 0xa83}, {0xabc, 0xabc}, {0xabe, 0xac5}, {0xac7, 0xac9}, + {0xacb, 0xacd}, {0xae2, 0xae3}, {0xb01, 0xb03}, {0xb3c, 0xb3c}, + {0xb3e, 0xb43}, {0xb47, 0xb48}, {0xb4b, 0xb4d}, {0xb56, 0xb57}, + {0xb82, 0xb82}, {0xbbe, 0xbc2}, {0xbc6, 0xbc8}, {0xbca, 0xbcd}, + {0xbd7, 0xbd7}, {0xc01, 0xc03}, {0xc3e, 0xc44}, {0xc46, 0xc48}, + {0xc4a, 0xc4d}, {0xc55, 0xc56}, {0xc82, 0xc83}, {0xcbc, 0xcbc}, + {0xcbe, 0xcc4}, {0xcc6, 0xcc8}, {0xcca, 0xccd}, {0xcd5, 0xcd6}, + {0xd02, 0xd03}, {0xd3e, 0xd43}, {0xd46, 0xd48}, {0xd4a, 0xd4d}, + {0xd57, 0xd57}, {0xd82, 0xd83}, {0xdca, 0xdca}, {0xdcf, 0xdd4}, + {0xdd6, 0xdd6}, {0xdd8, 0xddf}, {0xdf2, 0xdf3}, {0xe31, 0xe31}, + {0xe34, 0xe3a}, {0xe47, 0xe4e}, {0xeb1, 0xeb1}, {0xeb4, 0xeb9}, + {0xebb, 0xebc}, {0xec8, 0xecd}, {0xf18, 0xf19}, {0xf35, 0xf35}, + {0xf37, 0xf37}, {0xf39, 0xf39}, {0xf3e, 0xf3f}, {0xf71, 0xf84}, + {0xf86, 0xf87}, {0xf90, 0xf97}, {0xf99, 0xfbc}, {0xfc6, 0xfc6}, + {0x102c, 0x1032}, {0x1036, 0x1039}, {0x1056, 0x1059}, {0x1712, 0x1714}, + {0x1732, 0x1734}, {0x1752, 0x1753}, {0x1772, 0x1773}, {0x17b6, 0x17d3}, + {0x17dd, 0x17dd}, {0x180b, 0x180d}, {0x18a9, 0x18a9}, {0x1920, 0x192b}, + {0x1930, 0x193b}, {0x20d0, 0x20ea}, {0x302a, 0x302f}, {0x3099, 0x309a}, + {0xfb1e, 0xfb1e}, {0xfe00, 0xfe0f}, {0xfe20, 0xfe23} }; +static const xmlChLRange xmlML[] = {{0x1d165, 0x1d169}, {0x1d16d, 0x1d172}, + {0x1d17b, 0x1d182}, {0x1d185, 0x1d18b}, {0x1d1aa, 0x1d1ad}, + {0xe0100, 0xe01ef} }; +static xmlChRangeGroup xmlMG = {113,6,xmlMS,xmlML}; + +static const xmlChSRange xmlMcS[] = {{0x903, 0x903}, {0x93e, 0x940}, + {0x949, 0x94c}, {0x982, 0x983}, {0x9be, 0x9c0}, {0x9c7, 0x9c8}, + {0x9cb, 0x9cc}, {0x9d7, 0x9d7}, {0xa03, 0xa03}, {0xa3e, 0xa40}, + {0xa83, 0xa83}, {0xabe, 0xac0}, {0xac9, 0xac9}, {0xacb, 0xacc}, + {0xb02, 0xb03}, {0xb3e, 0xb3e}, {0xb40, 0xb40}, {0xb47, 0xb48}, + {0xb4b, 0xb4c}, {0xb57, 0xb57}, {0xbbe, 0xbbf}, {0xbc1, 0xbc2}, + {0xbc6, 0xbc8}, {0xbca, 0xbcc}, {0xbd7, 0xbd7}, {0xc01, 0xc03}, + {0xc41, 0xc44}, {0xc82, 0xc83}, {0xcbe, 0xcbe}, {0xcc0, 0xcc4}, + {0xcc7, 0xcc8}, {0xcca, 0xccb}, {0xcd5, 0xcd6}, {0xd02, 0xd03}, + {0xd3e, 0xd40}, {0xd46, 0xd48}, {0xd4a, 0xd4c}, {0xd57, 0xd57}, + {0xd82, 0xd83}, {0xdcf, 0xdd1}, {0xdd8, 0xddf}, {0xdf2, 0xdf3}, + {0xf3e, 0xf3f}, {0xf7f, 0xf7f}, {0x102c, 0x102c}, {0x1031, 0x1031}, + {0x1038, 0x1038}, {0x1056, 0x1057}, {0x17b6, 0x17b6}, {0x17be, 0x17c5}, + {0x17c7, 0x17c8}, {0x1923, 0x1926}, {0x1929, 0x192b}, {0x1930, 0x1931}, + {0x1933, 0x1938} }; +static const xmlChLRange xmlMcL[] = {{0x1d165, 0x1d166}, {0x1d16d, 0x1d172} }; +static xmlChRangeGroup xmlMcG = {55,2,xmlMcS,xmlMcL}; + +static const xmlChSRange xmlMnS[] = {{0x300, 0x357}, {0x35d, 0x36f}, + {0x483, 0x486}, {0x591, 0x5a1}, {0x5a3, 0x5b9}, {0x5bb, 0x5bd}, + {0x5bf, 0x5bf}, {0x5c1, 0x5c2}, {0x5c4, 0x5c4}, {0x610, 0x615}, + {0x64b, 0x658}, {0x670, 0x670}, {0x6d6, 0x6dc}, {0x6df, 0x6e4}, + {0x6e7, 0x6e8}, {0x6ea, 0x6ed}, {0x711, 0x711}, {0x730, 0x74a}, + {0x7a6, 0x7b0}, {0x901, 0x902}, {0x93c, 0x93c}, {0x941, 0x948}, + {0x94d, 0x94d}, {0x951, 0x954}, {0x962, 0x963}, {0x981, 0x981}, + {0x9bc, 0x9bc}, {0x9c1, 0x9c4}, {0x9cd, 0x9cd}, {0x9e2, 0x9e3}, + {0xa01, 0xa02}, {0xa3c, 0xa3c}, {0xa41, 0xa42}, {0xa47, 0xa48}, + {0xa4b, 0xa4d}, {0xa70, 0xa71}, {0xa81, 0xa82}, {0xabc, 0xabc}, + {0xac1, 0xac5}, {0xac7, 0xac8}, {0xacd, 0xacd}, {0xae2, 0xae3}, + {0xb01, 0xb01}, {0xb3c, 0xb3c}, {0xb3f, 0xb3f}, {0xb41, 0xb43}, + {0xb4d, 0xb4d}, {0xb56, 0xb56}, {0xb82, 0xb82}, {0xbc0, 0xbc0}, + {0xbcd, 0xbcd}, {0xc3e, 0xc40}, {0xc46, 0xc48}, {0xc4a, 0xc4d}, + {0xc55, 0xc56}, {0xcbc, 0xcbc}, {0xcbf, 0xcbf}, {0xcc6, 0xcc6}, + {0xccc, 0xccd}, {0xd41, 0xd43}, {0xd4d, 0xd4d}, {0xdca, 0xdca}, + {0xdd2, 0xdd4}, {0xdd6, 0xdd6}, {0xe31, 0xe31}, {0xe34, 0xe3a}, + {0xe47, 0xe4e}, {0xeb1, 0xeb1}, {0xeb4, 0xeb9}, {0xebb, 0xebc}, + {0xec8, 0xecd}, {0xf18, 0xf19}, {0xf35, 0xf35}, {0xf37, 0xf37}, + {0xf39, 0xf39}, {0xf71, 0xf7e}, {0xf80, 0xf84}, {0xf86, 0xf87}, + {0xf90, 0xf97}, {0xf99, 0xfbc}, {0xfc6, 0xfc6}, {0x102d, 0x1030}, + {0x1032, 0x1032}, {0x1036, 0x1037}, {0x1039, 0x1039}, {0x1058, 0x1059}, + {0x1712, 0x1714}, {0x1732, 0x1734}, {0x1752, 0x1753}, {0x1772, 0x1773}, + {0x17b7, 0x17bd}, {0x17c6, 0x17c6}, {0x17c9, 0x17d3}, {0x17dd, 0x17dd}, + {0x180b, 0x180d}, {0x18a9, 0x18a9}, {0x1920, 0x1922}, {0x1927, 0x1928}, + {0x1932, 0x1932}, {0x1939, 0x193b}, {0x20d0, 0x20dc}, {0x20e1, 0x20e1}, + {0x20e5, 0x20ea}, {0x302a, 0x302f}, {0x3099, 0x309a}, {0xfb1e, 0xfb1e}, + {0xfe00, 0xfe0f}, {0xfe20, 0xfe23} }; +static const xmlChLRange xmlMnL[] = {{0x1d167, 0x1d169}, {0x1d17b, 0x1d182}, + {0x1d185, 0x1d18b}, {0x1d1aa, 0x1d1ad}, {0xe0100, 0xe01ef} }; +static xmlChRangeGroup xmlMnG = {108,5,xmlMnS,xmlMnL}; + +static const xmlChSRange xmlNS[] = {{0x30, 0x39}, {0xb2, 0xb3}, + {0xb9, 0xb9}, {0xbc, 0xbe}, {0x660, 0x669}, {0x6f0, 0x6f9}, + {0x966, 0x96f}, {0x9e6, 0x9ef}, {0x9f4, 0x9f9}, {0xa66, 0xa6f}, + {0xae6, 0xaef}, {0xb66, 0xb6f}, {0xbe7, 0xbf2}, {0xc66, 0xc6f}, + {0xce6, 0xcef}, {0xd66, 0xd6f}, {0xe50, 0xe59}, {0xed0, 0xed9}, + {0xf20, 0xf33}, {0x1040, 0x1049}, {0x1369, 0x137c}, {0x16ee, 0x16f0}, + {0x17e0, 0x17e9}, {0x17f0, 0x17f9}, {0x1810, 0x1819}, {0x1946, 0x194f}, + {0x2070, 0x2070}, {0x2074, 0x2079}, {0x2080, 0x2089}, {0x2153, 0x2183}, + {0x2460, 0x249b}, {0x24ea, 0x24ff}, {0x2776, 0x2793}, {0x3007, 0x3007}, + {0x3021, 0x3029}, {0x3038, 0x303a}, {0x3192, 0x3195}, {0x3220, 0x3229}, + {0x3251, 0x325f}, {0x3280, 0x3289}, {0x32b1, 0x32bf}, {0xff10, 0xff19} }; +static const xmlChLRange xmlNL[] = {{0x10107, 0x10133}, {0x10320, 0x10323}, + {0x1034a, 0x1034a}, {0x104a0, 0x104a9}, {0x1d7ce, 0x1d7ff} }; +static xmlChRangeGroup xmlNG = {42,5,xmlNS,xmlNL}; + +static const xmlChSRange xmlNdS[] = {{0x30, 0x39}, {0x660, 0x669}, + {0x6f0, 0x6f9}, {0x966, 0x96f}, {0x9e6, 0x9ef}, {0xa66, 0xa6f}, + {0xae6, 0xaef}, {0xb66, 0xb6f}, {0xbe7, 0xbef}, {0xc66, 0xc6f}, + {0xce6, 0xcef}, {0xd66, 0xd6f}, {0xe50, 0xe59}, {0xed0, 0xed9}, + {0xf20, 0xf29}, {0x1040, 0x1049}, {0x1369, 0x1371}, {0x17e0, 0x17e9}, + {0x1810, 0x1819}, {0x1946, 0x194f}, {0xff10, 0xff19} }; +static const xmlChLRange xmlNdL[] = {{0x104a0, 0x104a9}, {0x1d7ce, 0x1d7ff} }; +static xmlChRangeGroup xmlNdG = {21,2,xmlNdS,xmlNdL}; + +static const xmlChSRange xmlNoS[] = {{0xb2, 0xb3}, {0xb9, 0xb9}, + {0xbc, 0xbe}, {0x9f4, 0x9f9}, {0xbf0, 0xbf2}, {0xf2a, 0xf33}, + {0x1372, 0x137c}, {0x17f0, 0x17f9}, {0x2070, 0x2070}, {0x2074, 0x2079}, + {0x2080, 0x2089}, {0x2153, 0x215f}, {0x2460, 0x249b}, {0x24ea, 0x24ff}, + {0x2776, 0x2793}, {0x3192, 0x3195}, {0x3220, 0x3229}, {0x3251, 0x325f}, + {0x3280, 0x3289}, {0x32b1, 0x32bf} }; +static const xmlChLRange xmlNoL[] = {{0x10107, 0x10133}, {0x10320, 0x10323} }; +static xmlChRangeGroup xmlNoG = {20,2,xmlNoS,xmlNoL}; + +static const xmlChSRange xmlPS[] = {{0x21, 0x23}, {0x25, 0x2a}, + {0x2c, 0x2f}, {0x3a, 0x3b}, {0x3f, 0x40}, {0x5b, 0x5d}, {0x5f, 0x5f}, + {0x7b, 0x7b}, {0x7d, 0x7d}, {0xa1, 0xa1}, {0xab, 0xab}, {0xb7, 0xb7}, + {0xbb, 0xbb}, {0xbf, 0xbf}, {0x37e, 0x37e}, {0x387, 0x387}, + {0x55a, 0x55f}, {0x589, 0x58a}, {0x5be, 0x5be}, {0x5c0, 0x5c0}, + {0x5c3, 0x5c3}, {0x5f3, 0x5f4}, {0x60c, 0x60d}, {0x61b, 0x61b}, + {0x61f, 0x61f}, {0x66a, 0x66d}, {0x6d4, 0x6d4}, {0x700, 0x70d}, + {0x964, 0x965}, {0x970, 0x970}, {0xdf4, 0xdf4}, {0xe4f, 0xe4f}, + {0xe5a, 0xe5b}, {0xf04, 0xf12}, {0xf3a, 0xf3d}, {0xf85, 0xf85}, + {0x104a, 0x104f}, {0x10fb, 0x10fb}, {0x1361, 0x1368}, {0x166d, 0x166e}, + {0x169b, 0x169c}, {0x16eb, 0x16ed}, {0x1735, 0x1736}, {0x17d4, 0x17d6}, + {0x17d8, 0x17da}, {0x1800, 0x180a}, {0x1944, 0x1945}, {0x2010, 0x2027}, + {0x2030, 0x2043}, {0x2045, 0x2051}, {0x2053, 0x2054}, {0x2057, 0x2057}, + {0x207d, 0x207e}, {0x208d, 0x208e}, {0x2329, 0x232a}, {0x23b4, 0x23b6}, + {0x2768, 0x2775}, {0x27e6, 0x27eb}, {0x2983, 0x2998}, {0x29d8, 0x29db}, + {0x29fc, 0x29fd}, {0x3001, 0x3003}, {0x3008, 0x3011}, {0x3014, 0x301f}, + {0x3030, 0x3030}, {0x303d, 0x303d}, {0x30a0, 0x30a0}, {0x30fb, 0x30fb}, + {0xfd3e, 0xfd3f}, {0xfe30, 0xfe52}, {0xfe54, 0xfe61}, {0xfe63, 0xfe63}, + {0xfe68, 0xfe68}, {0xfe6a, 0xfe6b}, {0xff01, 0xff03}, {0xff05, 0xff0a}, + {0xff0c, 0xff0f}, {0xff1a, 0xff1b}, {0xff1f, 0xff20}, {0xff3b, 0xff3d}, + {0xff3f, 0xff3f}, {0xff5b, 0xff5b}, {0xff5d, 0xff5d}, {0xff5f, 0xff65} }; +static const xmlChLRange xmlPL[] = {{0x10100, 0x10101}, {0x1039f, 0x1039f} }; +static xmlChRangeGroup xmlPG = {84,2,xmlPS,xmlPL}; + +static const xmlChSRange xmlPdS[] = {{0x2d, 0x2d}, {0x58a, 0x58a}, + {0x1806, 0x1806}, {0x2010, 0x2015}, {0x301c, 0x301c}, {0x3030, 0x3030}, + {0x30a0, 0x30a0}, {0xfe31, 0xfe32}, {0xfe58, 0xfe58}, {0xfe63, 0xfe63}, + {0xff0d, 0xff0d} }; +static xmlChRangeGroup xmlPdG = {11,0,xmlPdS,NULL}; + +static const xmlChSRange xmlPeS[] = {{0x29, 0x29}, {0x5d, 0x5d}, + {0x7d, 0x7d}, {0xf3b, 0xf3b}, {0xf3d, 0xf3d}, {0x169c, 0x169c}, + {0x2046, 0x2046}, {0x207e, 0x207e}, {0x208e, 0x208e}, {0x232a, 0x232a}, + {0x23b5, 0x23b5}, {0x2769, 0x2769}, {0x276b, 0x276b}, {0x276d, 0x276d}, + {0x276f, 0x276f}, {0x2771, 0x2771}, {0x2773, 0x2773}, {0x2775, 0x2775}, + {0x27e7, 0x27e7}, {0x27e9, 0x27e9}, {0x27eb, 0x27eb}, {0x2984, 0x2984}, + {0x2986, 0x2986}, {0x2988, 0x2988}, {0x298a, 0x298a}, {0x298c, 0x298c}, + {0x298e, 0x298e}, {0x2990, 0x2990}, {0x2992, 0x2992}, {0x2994, 0x2994}, + {0x2996, 0x2996}, {0x2998, 0x2998}, {0x29d9, 0x29d9}, {0x29db, 0x29db}, + {0x29fd, 0x29fd}, {0x3009, 0x3009}, {0x300b, 0x300b}, {0x300d, 0x300d}, + {0x300f, 0x300f}, {0x3011, 0x3011}, {0x3015, 0x3015}, {0x3017, 0x3017}, + {0x3019, 0x3019}, {0x301b, 0x301b}, {0x301e, 0x301f}, {0xfd3f, 0xfd3f}, + {0xfe36, 0xfe36}, {0xfe38, 0xfe38}, {0xfe3a, 0xfe3a}, {0xfe3c, 0xfe3c}, + {0xfe3e, 0xfe3e}, {0xfe40, 0xfe40}, {0xfe42, 0xfe42}, {0xfe44, 0xfe44}, + {0xfe48, 0xfe48}, {0xfe5a, 0xfe5a}, {0xfe5c, 0xfe5c}, {0xfe5e, 0xfe5e}, + {0xff09, 0xff09}, {0xff3d, 0xff3d}, {0xff5d, 0xff5d}, {0xff60, 0xff60}, + {0xff63, 0xff63} }; +static xmlChRangeGroup xmlPeG = {63,0,xmlPeS,NULL}; + +static const xmlChSRange xmlPoS[] = {{0x21, 0x23}, {0x25, 0x27}, + {0x2a, 0x2a}, {0x2c, 0x2c}, {0x2e, 0x2f}, {0x3a, 0x3b}, {0x3f, 0x40}, + {0x5c, 0x5c}, {0xa1, 0xa1}, {0xb7, 0xb7}, {0xbf, 0xbf}, {0x37e, 0x37e}, + {0x387, 0x387}, {0x55a, 0x55f}, {0x589, 0x589}, {0x5be, 0x5be}, + {0x5c0, 0x5c0}, {0x5c3, 0x5c3}, {0x5f3, 0x5f4}, {0x60c, 0x60d}, + {0x61b, 0x61b}, {0x61f, 0x61f}, {0x66a, 0x66d}, {0x6d4, 0x6d4}, + {0x700, 0x70d}, {0x964, 0x965}, {0x970, 0x970}, {0xdf4, 0xdf4}, + {0xe4f, 0xe4f}, {0xe5a, 0xe5b}, {0xf04, 0xf12}, {0xf85, 0xf85}, + {0x104a, 0x104f}, {0x10fb, 0x10fb}, {0x1361, 0x1368}, {0x166d, 0x166e}, + {0x16eb, 0x16ed}, {0x1735, 0x1736}, {0x17d4, 0x17d6}, {0x17d8, 0x17da}, + {0x1800, 0x1805}, {0x1807, 0x180a}, {0x1944, 0x1945}, {0x2016, 0x2017}, + {0x2020, 0x2027}, {0x2030, 0x2038}, {0x203b, 0x203e}, {0x2041, 0x2043}, + {0x2047, 0x2051}, {0x2053, 0x2053}, {0x2057, 0x2057}, {0x23b6, 0x23b6}, + {0x3001, 0x3003}, {0x303d, 0x303d}, {0xfe30, 0xfe30}, {0xfe45, 0xfe46}, + {0xfe49, 0xfe4c}, {0xfe50, 0xfe52}, {0xfe54, 0xfe57}, {0xfe5f, 0xfe61}, + {0xfe68, 0xfe68}, {0xfe6a, 0xfe6b}, {0xff01, 0xff03}, {0xff05, 0xff07}, + {0xff0a, 0xff0a}, {0xff0c, 0xff0c}, {0xff0e, 0xff0f}, {0xff1a, 0xff1b}, + {0xff1f, 0xff20}, {0xff3c, 0xff3c}, {0xff61, 0xff61}, {0xff64, 0xff64} }; +static const xmlChLRange xmlPoL[] = {{0x10100, 0x10101}, {0x1039f, 0x1039f} }; +static xmlChRangeGroup xmlPoG = {72,2,xmlPoS,xmlPoL}; + +static const xmlChSRange xmlPsS[] = {{0x28, 0x28}, {0x5b, 0x5b}, + {0x7b, 0x7b}, {0xf3a, 0xf3a}, {0xf3c, 0xf3c}, {0x169b, 0x169b}, + {0x201a, 0x201a}, {0x201e, 0x201e}, {0x2045, 0x2045}, {0x207d, 0x207d}, + {0x208d, 0x208d}, {0x2329, 0x2329}, {0x23b4, 0x23b4}, {0x2768, 0x2768}, + {0x276a, 0x276a}, {0x276c, 0x276c}, {0x276e, 0x276e}, {0x2770, 0x2770}, + {0x2772, 0x2772}, {0x2774, 0x2774}, {0x27e6, 0x27e6}, {0x27e8, 0x27e8}, + {0x27ea, 0x27ea}, {0x2983, 0x2983}, {0x2985, 0x2985}, {0x2987, 0x2987}, + {0x2989, 0x2989}, {0x298b, 0x298b}, {0x298d, 0x298d}, {0x298f, 0x298f}, + {0x2991, 0x2991}, {0x2993, 0x2993}, {0x2995, 0x2995}, {0x2997, 0x2997}, + {0x29d8, 0x29d8}, {0x29da, 0x29da}, {0x29fc, 0x29fc}, {0x3008, 0x3008}, + {0x300a, 0x300a}, {0x300c, 0x300c}, {0x300e, 0x300e}, {0x3010, 0x3010}, + {0x3014, 0x3014}, {0x3016, 0x3016}, {0x3018, 0x3018}, {0x301a, 0x301a}, + {0x301d, 0x301d}, {0xfd3e, 0xfd3e}, {0xfe35, 0xfe35}, {0xfe37, 0xfe37}, + {0xfe39, 0xfe39}, {0xfe3b, 0xfe3b}, {0xfe3d, 0xfe3d}, {0xfe3f, 0xfe3f}, + {0xfe41, 0xfe41}, {0xfe43, 0xfe43}, {0xfe47, 0xfe47}, {0xfe59, 0xfe59}, + {0xfe5b, 0xfe5b}, {0xfe5d, 0xfe5d}, {0xff08, 0xff08}, {0xff3b, 0xff3b}, + {0xff5b, 0xff5b}, {0xff5f, 0xff5f}, {0xff62, 0xff62} }; +static xmlChRangeGroup xmlPsG = {65,0,xmlPsS,NULL}; + +static const xmlChSRange xmlSS[] = {{0x24, 0x24}, {0x2b, 0x2b}, + {0x3c, 0x3e}, {0x5e, 0x5e}, {0x60, 0x60}, {0x7c, 0x7c}, {0x7e, 0x7e}, + {0xa2, 0xa9}, {0xac, 0xac}, {0xae, 0xb1}, {0xb4, 0xb4}, {0xb6, 0xb6}, + {0xb8, 0xb8}, {0xd7, 0xd7}, {0xf7, 0xf7}, {0x2c2, 0x2c5}, + {0x2d2, 0x2df}, {0x2e5, 0x2ed}, {0x2ef, 0x2ff}, {0x374, 0x375}, + {0x384, 0x385}, {0x3f6, 0x3f6}, {0x482, 0x482}, {0x60e, 0x60f}, + {0x6e9, 0x6e9}, {0x6fd, 0x6fe}, {0x9f2, 0x9f3}, {0x9fa, 0x9fa}, + {0xaf1, 0xaf1}, {0xb70, 0xb70}, {0xbf3, 0xbfa}, {0xe3f, 0xe3f}, + {0xf01, 0xf03}, {0xf13, 0xf17}, {0xf1a, 0xf1f}, {0xf34, 0xf34}, + {0xf36, 0xf36}, {0xf38, 0xf38}, {0xfbe, 0xfc5}, {0xfc7, 0xfcc}, + {0xfcf, 0xfcf}, {0x17db, 0x17db}, {0x1940, 0x1940}, {0x19e0, 0x19ff}, + {0x1fbd, 0x1fbd}, {0x1fbf, 0x1fc1}, {0x1fcd, 0x1fcf}, {0x1fdd, 0x1fdf}, + {0x1fed, 0x1fef}, {0x1ffd, 0x1ffe}, {0x2044, 0x2044}, {0x2052, 0x2052}, + {0x207a, 0x207c}, {0x208a, 0x208c}, {0x20a0, 0x20b1}, {0x2100, 0x2101}, + {0x2103, 0x2106}, {0x2108, 0x2109}, {0x2114, 0x2114}, {0x2116, 0x2118}, + {0x211e, 0x2123}, {0x2125, 0x2125}, {0x2127, 0x2127}, {0x2129, 0x2129}, + {0x212e, 0x212e}, {0x2132, 0x2132}, {0x213a, 0x213b}, {0x2140, 0x2144}, + {0x214a, 0x214b}, {0x2190, 0x2328}, {0x232b, 0x23b3}, {0x23b7, 0x23d0}, + {0x2400, 0x2426}, {0x2440, 0x244a}, {0x249c, 0x24e9}, {0x2500, 0x2617}, + {0x2619, 0x267d}, {0x2680, 0x2691}, {0x26a0, 0x26a1}, {0x2701, 0x2704}, + {0x2706, 0x2709}, {0x270c, 0x2727}, {0x2729, 0x274b}, {0x274d, 0x274d}, + {0x274f, 0x2752}, {0x2756, 0x2756}, {0x2758, 0x275e}, {0x2761, 0x2767}, + {0x2794, 0x2794}, {0x2798, 0x27af}, {0x27b1, 0x27be}, {0x27d0, 0x27e5}, + {0x27f0, 0x2982}, {0x2999, 0x29d7}, {0x29dc, 0x29fb}, {0x29fe, 0x2b0d}, + {0x2e80, 0x2e99}, {0x2e9b, 0x2ef3}, {0x2f00, 0x2fd5}, {0x2ff0, 0x2ffb}, + {0x3004, 0x3004}, {0x3012, 0x3013}, {0x3020, 0x3020}, {0x3036, 0x3037}, + {0x303e, 0x303f}, {0x309b, 0x309c}, {0x3190, 0x3191}, {0x3196, 0x319f}, + {0x3200, 0x321e}, {0x322a, 0x3243}, {0x3250, 0x3250}, {0x3260, 0x327d}, + {0x327f, 0x327f}, {0x328a, 0x32b0}, {0x32c0, 0x32fe}, {0x3300, 0x33ff}, + {0x4dc0, 0x4dff}, {0xa490, 0xa4c6}, {0xfb29, 0xfb29}, {0xfdfc, 0xfdfd}, + {0xfe62, 0xfe62}, {0xfe64, 0xfe66}, {0xfe69, 0xfe69}, {0xff04, 0xff04}, + {0xff0b, 0xff0b}, {0xff1c, 0xff1e}, {0xff3e, 0xff3e}, {0xff40, 0xff40}, + {0xff5c, 0xff5c}, {0xff5e, 0xff5e}, {0xffe0, 0xffe6}, {0xffe8, 0xffee}, + {0xfffc, 0xfffd} }; +static const xmlChLRange xmlSL[] = {{0x10102, 0x10102}, {0x10137, 0x1013f}, + {0x1d000, 0x1d0f5}, {0x1d100, 0x1d126}, {0x1d12a, 0x1d164}, + {0x1d16a, 0x1d16c}, {0x1d183, 0x1d184}, {0x1d18c, 0x1d1a9}, + {0x1d1ae, 0x1d1dd}, {0x1d300, 0x1d356}, {0x1d6c1, 0x1d6c1}, + {0x1d6db, 0x1d6db}, {0x1d6fb, 0x1d6fb}, {0x1d715, 0x1d715}, + {0x1d735, 0x1d735}, {0x1d74f, 0x1d74f}, {0x1d76f, 0x1d76f}, + {0x1d789, 0x1d789}, {0x1d7a9, 0x1d7a9}, {0x1d7c3, 0x1d7c3} }; +static xmlChRangeGroup xmlSG = {133,20,xmlSS,xmlSL}; + +static const xmlChSRange xmlScS[] = {{0x24, 0x24}, {0xa2, 0xa5}, + {0x9f2, 0x9f3}, {0xaf1, 0xaf1}, {0xbf9, 0xbf9}, {0xe3f, 0xe3f}, + {0x17db, 0x17db}, {0x20a0, 0x20b1}, {0xfdfc, 0xfdfc}, {0xfe69, 0xfe69}, + {0xff04, 0xff04}, {0xffe0, 0xffe1}, {0xffe5, 0xffe6} }; +static xmlChRangeGroup xmlScG = {13,0,xmlScS,NULL}; + +static const xmlChSRange xmlSkS[] = {{0x5e, 0x5e}, {0x60, 0x60}, + {0xa8, 0xa8}, {0xaf, 0xaf}, {0xb4, 0xb4}, {0xb8, 0xb8}, {0x2c2, 0x2c5}, + {0x2d2, 0x2df}, {0x2e5, 0x2ed}, {0x2ef, 0x2ff}, {0x374, 0x375}, + {0x384, 0x385}, {0x1fbd, 0x1fbd}, {0x1fbf, 0x1fc1}, {0x1fcd, 0x1fcf}, + {0x1fdd, 0x1fdf}, {0x1fed, 0x1fef}, {0x1ffd, 0x1ffe}, {0x309b, 0x309c}, + {0xff3e, 0xff3e}, {0xff40, 0xff40}, {0xffe3, 0xffe3} }; +static xmlChRangeGroup xmlSkG = {22,0,xmlSkS,NULL}; + +static const xmlChSRange xmlSmS[] = {{0x2b, 0x2b}, {0x3c, 0x3e}, + {0x7c, 0x7c}, {0x7e, 0x7e}, {0xac, 0xac}, {0xb1, 0xb1}, {0xd7, 0xd7}, + {0xf7, 0xf7}, {0x3f6, 0x3f6}, {0x2044, 0x2044}, {0x2052, 0x2052}, + {0x207a, 0x207c}, {0x208a, 0x208c}, {0x2140, 0x2144}, {0x214b, 0x214b}, + {0x2190, 0x2194}, {0x219a, 0x219b}, {0x21a0, 0x21a0}, {0x21a3, 0x21a3}, + {0x21a6, 0x21a6}, {0x21ae, 0x21ae}, {0x21ce, 0x21cf}, {0x21d2, 0x21d2}, + {0x21d4, 0x21d4}, {0x21f4, 0x22ff}, {0x2308, 0x230b}, {0x2320, 0x2321}, + {0x237c, 0x237c}, {0x239b, 0x23b3}, {0x25b7, 0x25b7}, {0x25c1, 0x25c1}, + {0x25f8, 0x25ff}, {0x266f, 0x266f}, {0x27d0, 0x27e5}, {0x27f0, 0x27ff}, + {0x2900, 0x2982}, {0x2999, 0x29d7}, {0x29dc, 0x29fb}, {0x29fe, 0x2aff}, + {0xfb29, 0xfb29}, {0xfe62, 0xfe62}, {0xfe64, 0xfe66}, {0xff0b, 0xff0b}, + {0xff1c, 0xff1e}, {0xff5c, 0xff5c}, {0xff5e, 0xff5e}, {0xffe2, 0xffe2}, + {0xffe9, 0xffec} }; +static const xmlChLRange xmlSmL[] = {{0x1d6c1, 0x1d6c1}, {0x1d6db, 0x1d6db}, + {0x1d6fb, 0x1d6fb}, {0x1d715, 0x1d715}, {0x1d735, 0x1d735}, + {0x1d74f, 0x1d74f}, {0x1d76f, 0x1d76f}, {0x1d789, 0x1d789}, + {0x1d7a9, 0x1d7a9}, {0x1d7c3, 0x1d7c3} }; +static xmlChRangeGroup xmlSmG = {48,10,xmlSmS,xmlSmL}; + +static const xmlChSRange xmlSoS[] = {{0xa6, 0xa7}, {0xa9, 0xa9}, + {0xae, 0xae}, {0xb0, 0xb0}, {0xb6, 0xb6}, {0x482, 0x482}, + {0x60e, 0x60f}, {0x6e9, 0x6e9}, {0x6fd, 0x6fe}, {0x9fa, 0x9fa}, + {0xb70, 0xb70}, {0xbf3, 0xbf8}, {0xbfa, 0xbfa}, {0xf01, 0xf03}, + {0xf13, 0xf17}, {0xf1a, 0xf1f}, {0xf34, 0xf34}, {0xf36, 0xf36}, + {0xf38, 0xf38}, {0xfbe, 0xfc5}, {0xfc7, 0xfcc}, {0xfcf, 0xfcf}, + {0x1940, 0x1940}, {0x19e0, 0x19ff}, {0x2100, 0x2101}, {0x2103, 0x2106}, + {0x2108, 0x2109}, {0x2114, 0x2114}, {0x2116, 0x2118}, {0x211e, 0x2123}, + {0x2125, 0x2125}, {0x2127, 0x2127}, {0x2129, 0x2129}, {0x212e, 0x212e}, + {0x2132, 0x2132}, {0x213a, 0x213b}, {0x214a, 0x214a}, {0x2195, 0x2199}, + {0x219c, 0x219f}, {0x21a1, 0x21a2}, {0x21a4, 0x21a5}, {0x21a7, 0x21ad}, + {0x21af, 0x21cd}, {0x21d0, 0x21d1}, {0x21d3, 0x21d3}, {0x21d5, 0x21f3}, + {0x2300, 0x2307}, {0x230c, 0x231f}, {0x2322, 0x2328}, {0x232b, 0x237b}, + {0x237d, 0x239a}, {0x23b7, 0x23d0}, {0x2400, 0x2426}, {0x2440, 0x244a}, + {0x249c, 0x24e9}, {0x2500, 0x25b6}, {0x25b8, 0x25c0}, {0x25c2, 0x25f7}, + {0x2600, 0x2617}, {0x2619, 0x266e}, {0x2670, 0x267d}, {0x2680, 0x2691}, + {0x26a0, 0x26a1}, {0x2701, 0x2704}, {0x2706, 0x2709}, {0x270c, 0x2727}, + {0x2729, 0x274b}, {0x274d, 0x274d}, {0x274f, 0x2752}, {0x2756, 0x2756}, + {0x2758, 0x275e}, {0x2761, 0x2767}, {0x2794, 0x2794}, {0x2798, 0x27af}, + {0x27b1, 0x27be}, {0x2800, 0x28ff}, {0x2b00, 0x2b0d}, {0x2e80, 0x2e99}, + {0x2e9b, 0x2ef3}, {0x2f00, 0x2fd5}, {0x2ff0, 0x2ffb}, {0x3004, 0x3004}, + {0x3012, 0x3013}, {0x3020, 0x3020}, {0x3036, 0x3037}, {0x303e, 0x303f}, + {0x3190, 0x3191}, {0x3196, 0x319f}, {0x3200, 0x321e}, {0x322a, 0x3243}, + {0x3250, 0x3250}, {0x3260, 0x327d}, {0x327f, 0x327f}, {0x328a, 0x32b0}, + {0x32c0, 0x32fe}, {0x3300, 0x33ff}, {0x4dc0, 0x4dff}, {0xa490, 0xa4c6}, + {0xfdfd, 0xfdfd}, {0xffe4, 0xffe4}, {0xffe8, 0xffe8}, {0xffed, 0xffee}, + {0xfffc, 0xfffd} }; +static const xmlChLRange xmlSoL[] = {{0x10102, 0x10102}, {0x10137, 0x1013f}, + {0x1d000, 0x1d0f5}, {0x1d100, 0x1d126}, {0x1d12a, 0x1d164}, + {0x1d16a, 0x1d16c}, {0x1d183, 0x1d184}, {0x1d18c, 0x1d1a9}, + {0x1d1ae, 0x1d1dd}, {0x1d300, 0x1d356} }; +static xmlChRangeGroup xmlSoG = {103,10,xmlSoS,xmlSoL}; + +static const xmlChSRange xmlZS[] = {{0x20, 0x20}, {0xa0, 0xa0}, + {0x1680, 0x1680}, {0x180e, 0x180e}, {0x2000, 0x200a}, {0x2028, 0x2029}, + {0x202f, 0x202f}, {0x205f, 0x205f}, {0x3000, 0x3000} }; +static xmlChRangeGroup xmlZG = {9,0,xmlZS,NULL}; + +static xmlUnicodeNameTable xmlUnicodeBlockTbl = {xmlUnicodeBlocks, 128}; +static xmlUnicodeNameTable xmlUnicodeCatTbl = {xmlUnicodeCats, 36}; + +/** + * xmlUnicodeLookup: + * @tptr: pointer to the name table + * @name: name to be found + * + * binary table lookup for user-supplied name + * + * Returns pointer to range function if found, otherwise NULL + */ +static xmlIntFunc +*xmlUnicodeLookup(xmlUnicodeNameTable *tptr, const char *tname) { + int low, high, mid, cmp; + xmlUnicodeRange *sptr; + + if ((tptr == NULL) || (tname == NULL)) return(NULL); + + low = 0; + high = tptr->numentries - 1; + sptr = tptr->table; + while (low <= high) { + mid = (low + high) / 2; + if ((cmp=strcmp(tname, sptr[mid].rangename)) == 0) + return (sptr[mid].func); + if (cmp < 0) + high = mid - 1; + else + low = mid + 1; + } + return (NULL); +} + +/** + * xmlUCSIsAegeanNumbers: + * @code: UCS code point + * + * Check whether the character is part of AegeanNumbers UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsAegeanNumbers(int code) { + return(((code >= 0x10100) && (code <= 0x1013F))); +} + +/** + * xmlUCSIsAlphabeticPresentationForms: + * @code: UCS code point + * + * Check whether the character is part of AlphabeticPresentationForms UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsAlphabeticPresentationForms(int code) { + return(((code >= 0xFB00) && (code <= 0xFB4F))); +} + +/** + * xmlUCSIsArabic: + * @code: UCS code point + * + * Check whether the character is part of Arabic UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsArabic(int code) { + return(((code >= 0x0600) && (code <= 0x06FF))); +} + +/** + * xmlUCSIsArabicPresentationFormsA: + * @code: UCS code point + * + * Check whether the character is part of ArabicPresentationForms-A UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsArabicPresentationFormsA(int code) { + return(((code >= 0xFB50) && (code <= 0xFDFF))); +} + +/** + * xmlUCSIsArabicPresentationFormsB: + * @code: UCS code point + * + * Check whether the character is part of ArabicPresentationForms-B UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsArabicPresentationFormsB(int code) { + return(((code >= 0xFE70) && (code <= 0xFEFF))); +} + +/** + * xmlUCSIsArmenian: + * @code: UCS code point + * + * Check whether the character is part of Armenian UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsArmenian(int code) { + return(((code >= 0x0530) && (code <= 0x058F))); +} + +/** + * xmlUCSIsArrows: + * @code: UCS code point + * + * Check whether the character is part of Arrows UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsArrows(int code) { + return(((code >= 0x2190) && (code <= 0x21FF))); +} + +/** + * xmlUCSIsBasicLatin: + * @code: UCS code point + * + * Check whether the character is part of BasicLatin UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsBasicLatin(int code) { + return(((code >= 0x0000) && (code <= 0x007F))); +} + +/** + * xmlUCSIsBengali: + * @code: UCS code point + * + * Check whether the character is part of Bengali UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsBengali(int code) { + return(((code >= 0x0980) && (code <= 0x09FF))); +} + +/** + * xmlUCSIsBlockElements: + * @code: UCS code point + * + * Check whether the character is part of BlockElements UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsBlockElements(int code) { + return(((code >= 0x2580) && (code <= 0x259F))); +} + +/** + * xmlUCSIsBopomofo: + * @code: UCS code point + * + * Check whether the character is part of Bopomofo UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsBopomofo(int code) { + return(((code >= 0x3100) && (code <= 0x312F))); +} + +/** + * xmlUCSIsBopomofoExtended: + * @code: UCS code point + * + * Check whether the character is part of BopomofoExtended UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsBopomofoExtended(int code) { + return(((code >= 0x31A0) && (code <= 0x31BF))); +} + +/** + * xmlUCSIsBoxDrawing: + * @code: UCS code point + * + * Check whether the character is part of BoxDrawing UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsBoxDrawing(int code) { + return(((code >= 0x2500) && (code <= 0x257F))); +} + +/** + * xmlUCSIsBraillePatterns: + * @code: UCS code point + * + * Check whether the character is part of BraillePatterns UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsBraillePatterns(int code) { + return(((code >= 0x2800) && (code <= 0x28FF))); +} + +/** + * xmlUCSIsBuhid: + * @code: UCS code point + * + * Check whether the character is part of Buhid UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsBuhid(int code) { + return(((code >= 0x1740) && (code <= 0x175F))); +} + +/** + * xmlUCSIsByzantineMusicalSymbols: + * @code: UCS code point + * + * Check whether the character is part of ByzantineMusicalSymbols UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsByzantineMusicalSymbols(int code) { + return(((code >= 0x1D000) && (code <= 0x1D0FF))); +} + +/** + * xmlUCSIsCJKCompatibility: + * @code: UCS code point + * + * Check whether the character is part of CJKCompatibility UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCJKCompatibility(int code) { + return(((code >= 0x3300) && (code <= 0x33FF))); +} + +/** + * xmlUCSIsCJKCompatibilityForms: + * @code: UCS code point + * + * Check whether the character is part of CJKCompatibilityForms UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCJKCompatibilityForms(int code) { + return(((code >= 0xFE30) && (code <= 0xFE4F))); +} + +/** + * xmlUCSIsCJKCompatibilityIdeographs: + * @code: UCS code point + * + * Check whether the character is part of CJKCompatibilityIdeographs UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCJKCompatibilityIdeographs(int code) { + return(((code >= 0xF900) && (code <= 0xFAFF))); +} + +/** + * xmlUCSIsCJKCompatibilityIdeographsSupplement: + * @code: UCS code point + * + * Check whether the character is part of CJKCompatibilityIdeographsSupplement UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCJKCompatibilityIdeographsSupplement(int code) { + return(((code >= 0x2F800) && (code <= 0x2FA1F))); +} + +/** + * xmlUCSIsCJKRadicalsSupplement: + * @code: UCS code point + * + * Check whether the character is part of CJKRadicalsSupplement UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCJKRadicalsSupplement(int code) { + return(((code >= 0x2E80) && (code <= 0x2EFF))); +} + +/** + * xmlUCSIsCJKSymbolsandPunctuation: + * @code: UCS code point + * + * Check whether the character is part of CJKSymbolsandPunctuation UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCJKSymbolsandPunctuation(int code) { + return(((code >= 0x3000) && (code <= 0x303F))); +} + +/** + * xmlUCSIsCJKUnifiedIdeographs: + * @code: UCS code point + * + * Check whether the character is part of CJKUnifiedIdeographs UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCJKUnifiedIdeographs(int code) { + return(((code >= 0x4E00) && (code <= 0x9FFF))); +} + +/** + * xmlUCSIsCJKUnifiedIdeographsExtensionA: + * @code: UCS code point + * + * Check whether the character is part of CJKUnifiedIdeographsExtensionA UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCJKUnifiedIdeographsExtensionA(int code) { + return(((code >= 0x3400) && (code <= 0x4DBF))); +} + +/** + * xmlUCSIsCJKUnifiedIdeographsExtensionB: + * @code: UCS code point + * + * Check whether the character is part of CJKUnifiedIdeographsExtensionB UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCJKUnifiedIdeographsExtensionB(int code) { + return(((code >= 0x20000) && (code <= 0x2A6DF))); +} + +/** + * xmlUCSIsCherokee: + * @code: UCS code point + * + * Check whether the character is part of Cherokee UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCherokee(int code) { + return(((code >= 0x13A0) && (code <= 0x13FF))); +} + +/** + * xmlUCSIsCombiningDiacriticalMarks: + * @code: UCS code point + * + * Check whether the character is part of CombiningDiacriticalMarks UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCombiningDiacriticalMarks(int code) { + return(((code >= 0x0300) && (code <= 0x036F))); +} + +/** + * xmlUCSIsCombiningDiacriticalMarksforSymbols: + * @code: UCS code point + * + * Check whether the character is part of CombiningDiacriticalMarksforSymbols UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCombiningDiacriticalMarksforSymbols(int code) { + return(((code >= 0x20D0) && (code <= 0x20FF))); +} + +/** + * xmlUCSIsCombiningHalfMarks: + * @code: UCS code point + * + * Check whether the character is part of CombiningHalfMarks UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCombiningHalfMarks(int code) { + return(((code >= 0xFE20) && (code <= 0xFE2F))); +} + +/** + * xmlUCSIsCombiningMarksforSymbols: + * @code: UCS code point + * + * Check whether the character is part of CombiningMarksforSymbols UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCombiningMarksforSymbols(int code) { + return(((code >= 0x20D0) && (code <= 0x20FF))); +} + +/** + * xmlUCSIsControlPictures: + * @code: UCS code point + * + * Check whether the character is part of ControlPictures UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsControlPictures(int code) { + return(((code >= 0x2400) && (code <= 0x243F))); +} + +/** + * xmlUCSIsCurrencySymbols: + * @code: UCS code point + * + * Check whether the character is part of CurrencySymbols UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCurrencySymbols(int code) { + return(((code >= 0x20A0) && (code <= 0x20CF))); +} + +/** + * xmlUCSIsCypriotSyllabary: + * @code: UCS code point + * + * Check whether the character is part of CypriotSyllabary UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCypriotSyllabary(int code) { + return(((code >= 0x10800) && (code <= 0x1083F))); +} + +/** + * xmlUCSIsCyrillic: + * @code: UCS code point + * + * Check whether the character is part of Cyrillic UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCyrillic(int code) { + return(((code >= 0x0400) && (code <= 0x04FF))); +} + +/** + * xmlUCSIsCyrillicSupplement: + * @code: UCS code point + * + * Check whether the character is part of CyrillicSupplement UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCyrillicSupplement(int code) { + return(((code >= 0x0500) && (code <= 0x052F))); +} + +/** + * xmlUCSIsDeseret: + * @code: UCS code point + * + * Check whether the character is part of Deseret UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsDeseret(int code) { + return(((code >= 0x10400) && (code <= 0x1044F))); +} + +/** + * xmlUCSIsDevanagari: + * @code: UCS code point + * + * Check whether the character is part of Devanagari UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsDevanagari(int code) { + return(((code >= 0x0900) && (code <= 0x097F))); +} + +/** + * xmlUCSIsDingbats: + * @code: UCS code point + * + * Check whether the character is part of Dingbats UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsDingbats(int code) { + return(((code >= 0x2700) && (code <= 0x27BF))); +} + +/** + * xmlUCSIsEnclosedAlphanumerics: + * @code: UCS code point + * + * Check whether the character is part of EnclosedAlphanumerics UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsEnclosedAlphanumerics(int code) { + return(((code >= 0x2460) && (code <= 0x24FF))); +} + +/** + * xmlUCSIsEnclosedCJKLettersandMonths: + * @code: UCS code point + * + * Check whether the character is part of EnclosedCJKLettersandMonths UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsEnclosedCJKLettersandMonths(int code) { + return(((code >= 0x3200) && (code <= 0x32FF))); +} + +/** + * xmlUCSIsEthiopic: + * @code: UCS code point + * + * Check whether the character is part of Ethiopic UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsEthiopic(int code) { + return(((code >= 0x1200) && (code <= 0x137F))); +} + +/** + * xmlUCSIsGeneralPunctuation: + * @code: UCS code point + * + * Check whether the character is part of GeneralPunctuation UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsGeneralPunctuation(int code) { + return(((code >= 0x2000) && (code <= 0x206F))); +} + +/** + * xmlUCSIsGeometricShapes: + * @code: UCS code point + * + * Check whether the character is part of GeometricShapes UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsGeometricShapes(int code) { + return(((code >= 0x25A0) && (code <= 0x25FF))); +} + +/** + * xmlUCSIsGeorgian: + * @code: UCS code point + * + * Check whether the character is part of Georgian UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsGeorgian(int code) { + return(((code >= 0x10A0) && (code <= 0x10FF))); +} + +/** + * xmlUCSIsGothic: + * @code: UCS code point + * + * Check whether the character is part of Gothic UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsGothic(int code) { + return(((code >= 0x10330) && (code <= 0x1034F))); +} + +/** + * xmlUCSIsGreek: + * @code: UCS code point + * + * Check whether the character is part of Greek UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsGreek(int code) { + return(((code >= 0x0370) && (code <= 0x03FF))); +} + +/** + * xmlUCSIsGreekExtended: + * @code: UCS code point + * + * Check whether the character is part of GreekExtended UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsGreekExtended(int code) { + return(((code >= 0x1F00) && (code <= 0x1FFF))); +} + +/** + * xmlUCSIsGreekandCoptic: + * @code: UCS code point + * + * Check whether the character is part of GreekandCoptic UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsGreekandCoptic(int code) { + return(((code >= 0x0370) && (code <= 0x03FF))); +} + +/** + * xmlUCSIsGujarati: + * @code: UCS code point + * + * Check whether the character is part of Gujarati UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsGujarati(int code) { + return(((code >= 0x0A80) && (code <= 0x0AFF))); +} + +/** + * xmlUCSIsGurmukhi: + * @code: UCS code point + * + * Check whether the character is part of Gurmukhi UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsGurmukhi(int code) { + return(((code >= 0x0A00) && (code <= 0x0A7F))); +} + +/** + * xmlUCSIsHalfwidthandFullwidthForms: + * @code: UCS code point + * + * Check whether the character is part of HalfwidthandFullwidthForms UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsHalfwidthandFullwidthForms(int code) { + return(((code >= 0xFF00) && (code <= 0xFFEF))); +} + +/** + * xmlUCSIsHangulCompatibilityJamo: + * @code: UCS code point + * + * Check whether the character is part of HangulCompatibilityJamo UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsHangulCompatibilityJamo(int code) { + return(((code >= 0x3130) && (code <= 0x318F))); +} + +/** + * xmlUCSIsHangulJamo: + * @code: UCS code point + * + * Check whether the character is part of HangulJamo UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsHangulJamo(int code) { + return(((code >= 0x1100) && (code <= 0x11FF))); +} + +/** + * xmlUCSIsHangulSyllables: + * @code: UCS code point + * + * Check whether the character is part of HangulSyllables UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsHangulSyllables(int code) { + return(((code >= 0xAC00) && (code <= 0xD7AF))); +} + +/** + * xmlUCSIsHanunoo: + * @code: UCS code point + * + * Check whether the character is part of Hanunoo UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsHanunoo(int code) { + return(((code >= 0x1720) && (code <= 0x173F))); +} + +/** + * xmlUCSIsHebrew: + * @code: UCS code point + * + * Check whether the character is part of Hebrew UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsHebrew(int code) { + return(((code >= 0x0590) && (code <= 0x05FF))); +} + +/** + * xmlUCSIsHighPrivateUseSurrogates: + * @code: UCS code point + * + * Check whether the character is part of HighPrivateUseSurrogates UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsHighPrivateUseSurrogates(int code) { + return(((code >= 0xDB80) && (code <= 0xDBFF))); +} + +/** + * xmlUCSIsHighSurrogates: + * @code: UCS code point + * + * Check whether the character is part of HighSurrogates UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsHighSurrogates(int code) { + return(((code >= 0xD800) && (code <= 0xDB7F))); +} + +/** + * xmlUCSIsHiragana: + * @code: UCS code point + * + * Check whether the character is part of Hiragana UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsHiragana(int code) { + return(((code >= 0x3040) && (code <= 0x309F))); +} + +/** + * xmlUCSIsIPAExtensions: + * @code: UCS code point + * + * Check whether the character is part of IPAExtensions UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsIPAExtensions(int code) { + return(((code >= 0x0250) && (code <= 0x02AF))); +} + +/** + * xmlUCSIsIdeographicDescriptionCharacters: + * @code: UCS code point + * + * Check whether the character is part of IdeographicDescriptionCharacters UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsIdeographicDescriptionCharacters(int code) { + return(((code >= 0x2FF0) && (code <= 0x2FFF))); +} + +/** + * xmlUCSIsKanbun: + * @code: UCS code point + * + * Check whether the character is part of Kanbun UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsKanbun(int code) { + return(((code >= 0x3190) && (code <= 0x319F))); +} + +/** + * xmlUCSIsKangxiRadicals: + * @code: UCS code point + * + * Check whether the character is part of KangxiRadicals UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsKangxiRadicals(int code) { + return(((code >= 0x2F00) && (code <= 0x2FDF))); +} + +/** + * xmlUCSIsKannada: + * @code: UCS code point + * + * Check whether the character is part of Kannada UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsKannada(int code) { + return(((code >= 0x0C80) && (code <= 0x0CFF))); +} + +/** + * xmlUCSIsKatakana: + * @code: UCS code point + * + * Check whether the character is part of Katakana UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsKatakana(int code) { + return(((code >= 0x30A0) && (code <= 0x30FF))); +} + +/** + * xmlUCSIsKatakanaPhoneticExtensions: + * @code: UCS code point + * + * Check whether the character is part of KatakanaPhoneticExtensions UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsKatakanaPhoneticExtensions(int code) { + return(((code >= 0x31F0) && (code <= 0x31FF))); +} + +/** + * xmlUCSIsKhmer: + * @code: UCS code point + * + * Check whether the character is part of Khmer UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsKhmer(int code) { + return(((code >= 0x1780) && (code <= 0x17FF))); +} + +/** + * xmlUCSIsKhmerSymbols: + * @code: UCS code point + * + * Check whether the character is part of KhmerSymbols UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsKhmerSymbols(int code) { + return(((code >= 0x19E0) && (code <= 0x19FF))); +} + +/** + * xmlUCSIsLao: + * @code: UCS code point + * + * Check whether the character is part of Lao UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsLao(int code) { + return(((code >= 0x0E80) && (code <= 0x0EFF))); +} + +/** + * xmlUCSIsLatin1Supplement: + * @code: UCS code point + * + * Check whether the character is part of Latin-1Supplement UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsLatin1Supplement(int code) { + return(((code >= 0x0080) && (code <= 0x00FF))); +} + +/** + * xmlUCSIsLatinExtendedA: + * @code: UCS code point + * + * Check whether the character is part of LatinExtended-A UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsLatinExtendedA(int code) { + return(((code >= 0x0100) && (code <= 0x017F))); +} + +/** + * xmlUCSIsLatinExtendedB: + * @code: UCS code point + * + * Check whether the character is part of LatinExtended-B UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsLatinExtendedB(int code) { + return(((code >= 0x0180) && (code <= 0x024F))); +} + +/** + * xmlUCSIsLatinExtendedAdditional: + * @code: UCS code point + * + * Check whether the character is part of LatinExtendedAdditional UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsLatinExtendedAdditional(int code) { + return(((code >= 0x1E00) && (code <= 0x1EFF))); +} + +/** + * xmlUCSIsLetterlikeSymbols: + * @code: UCS code point + * + * Check whether the character is part of LetterlikeSymbols UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsLetterlikeSymbols(int code) { + return(((code >= 0x2100) && (code <= 0x214F))); +} + +/** + * xmlUCSIsLimbu: + * @code: UCS code point + * + * Check whether the character is part of Limbu UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsLimbu(int code) { + return(((code >= 0x1900) && (code <= 0x194F))); +} + +/** + * xmlUCSIsLinearBIdeograms: + * @code: UCS code point + * + * Check whether the character is part of LinearBIdeograms UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsLinearBIdeograms(int code) { + return(((code >= 0x10080) && (code <= 0x100FF))); +} + +/** + * xmlUCSIsLinearBSyllabary: + * @code: UCS code point + * + * Check whether the character is part of LinearBSyllabary UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsLinearBSyllabary(int code) { + return(((code >= 0x10000) && (code <= 0x1007F))); +} + +/** + * xmlUCSIsLowSurrogates: + * @code: UCS code point + * + * Check whether the character is part of LowSurrogates UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsLowSurrogates(int code) { + return(((code >= 0xDC00) && (code <= 0xDFFF))); +} + +/** + * xmlUCSIsMalayalam: + * @code: UCS code point + * + * Check whether the character is part of Malayalam UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsMalayalam(int code) { + return(((code >= 0x0D00) && (code <= 0x0D7F))); +} + +/** + * xmlUCSIsMathematicalAlphanumericSymbols: + * @code: UCS code point + * + * Check whether the character is part of MathematicalAlphanumericSymbols UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsMathematicalAlphanumericSymbols(int code) { + return(((code >= 0x1D400) && (code <= 0x1D7FF))); +} + +/** + * xmlUCSIsMathematicalOperators: + * @code: UCS code point + * + * Check whether the character is part of MathematicalOperators UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsMathematicalOperators(int code) { + return(((code >= 0x2200) && (code <= 0x22FF))); +} + +/** + * xmlUCSIsMiscellaneousMathematicalSymbolsA: + * @code: UCS code point + * + * Check whether the character is part of MiscellaneousMathematicalSymbols-A UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsMiscellaneousMathematicalSymbolsA(int code) { + return(((code >= 0x27C0) && (code <= 0x27EF))); +} + +/** + * xmlUCSIsMiscellaneousMathematicalSymbolsB: + * @code: UCS code point + * + * Check whether the character is part of MiscellaneousMathematicalSymbols-B UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsMiscellaneousMathematicalSymbolsB(int code) { + return(((code >= 0x2980) && (code <= 0x29FF))); +} + +/** + * xmlUCSIsMiscellaneousSymbols: + * @code: UCS code point + * + * Check whether the character is part of MiscellaneousSymbols UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsMiscellaneousSymbols(int code) { + return(((code >= 0x2600) && (code <= 0x26FF))); +} + +/** + * xmlUCSIsMiscellaneousSymbolsandArrows: + * @code: UCS code point + * + * Check whether the character is part of MiscellaneousSymbolsandArrows UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsMiscellaneousSymbolsandArrows(int code) { + return(((code >= 0x2B00) && (code <= 0x2BFF))); +} + +/** + * xmlUCSIsMiscellaneousTechnical: + * @code: UCS code point + * + * Check whether the character is part of MiscellaneousTechnical UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsMiscellaneousTechnical(int code) { + return(((code >= 0x2300) && (code <= 0x23FF))); +} + +/** + * xmlUCSIsMongolian: + * @code: UCS code point + * + * Check whether the character is part of Mongolian UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsMongolian(int code) { + return(((code >= 0x1800) && (code <= 0x18AF))); +} + +/** + * xmlUCSIsMusicalSymbols: + * @code: UCS code point + * + * Check whether the character is part of MusicalSymbols UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsMusicalSymbols(int code) { + return(((code >= 0x1D100) && (code <= 0x1D1FF))); +} + +/** + * xmlUCSIsMyanmar: + * @code: UCS code point + * + * Check whether the character is part of Myanmar UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsMyanmar(int code) { + return(((code >= 0x1000) && (code <= 0x109F))); +} + +/** + * xmlUCSIsNumberForms: + * @code: UCS code point + * + * Check whether the character is part of NumberForms UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsNumberForms(int code) { + return(((code >= 0x2150) && (code <= 0x218F))); +} + +/** + * xmlUCSIsOgham: + * @code: UCS code point + * + * Check whether the character is part of Ogham UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsOgham(int code) { + return(((code >= 0x1680) && (code <= 0x169F))); +} + +/** + * xmlUCSIsOldItalic: + * @code: UCS code point + * + * Check whether the character is part of OldItalic UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsOldItalic(int code) { + return(((code >= 0x10300) && (code <= 0x1032F))); +} + +/** + * xmlUCSIsOpticalCharacterRecognition: + * @code: UCS code point + * + * Check whether the character is part of OpticalCharacterRecognition UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsOpticalCharacterRecognition(int code) { + return(((code >= 0x2440) && (code <= 0x245F))); +} + +/** + * xmlUCSIsOriya: + * @code: UCS code point + * + * Check whether the character is part of Oriya UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsOriya(int code) { + return(((code >= 0x0B00) && (code <= 0x0B7F))); +} + +/** + * xmlUCSIsOsmanya: + * @code: UCS code point + * + * Check whether the character is part of Osmanya UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsOsmanya(int code) { + return(((code >= 0x10480) && (code <= 0x104AF))); +} + +/** + * xmlUCSIsPhoneticExtensions: + * @code: UCS code point + * + * Check whether the character is part of PhoneticExtensions UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsPhoneticExtensions(int code) { + return(((code >= 0x1D00) && (code <= 0x1D7F))); +} + +/** + * xmlUCSIsPrivateUse: + * @code: UCS code point + * + * Check whether the character is part of PrivateUse UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsPrivateUse(int code) { + return(((code >= 0xE000) && (code <= 0xF8FF)) || + ((code >= 0xF0000) && (code <= 0xFFFFF)) || + ((code >= 0x100000) && (code <= 0x10FFFF))); +} + +/** + * xmlUCSIsPrivateUseArea: + * @code: UCS code point + * + * Check whether the character is part of PrivateUseArea UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsPrivateUseArea(int code) { + return(((code >= 0xE000) && (code <= 0xF8FF))); +} + +/** + * xmlUCSIsRunic: + * @code: UCS code point + * + * Check whether the character is part of Runic UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsRunic(int code) { + return(((code >= 0x16A0) && (code <= 0x16FF))); +} + +/** + * xmlUCSIsShavian: + * @code: UCS code point + * + * Check whether the character is part of Shavian UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsShavian(int code) { + return(((code >= 0x10450) && (code <= 0x1047F))); +} + +/** + * xmlUCSIsSinhala: + * @code: UCS code point + * + * Check whether the character is part of Sinhala UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsSinhala(int code) { + return(((code >= 0x0D80) && (code <= 0x0DFF))); +} + +/** + * xmlUCSIsSmallFormVariants: + * @code: UCS code point + * + * Check whether the character is part of SmallFormVariants UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsSmallFormVariants(int code) { + return(((code >= 0xFE50) && (code <= 0xFE6F))); +} + +/** + * xmlUCSIsSpacingModifierLetters: + * @code: UCS code point + * + * Check whether the character is part of SpacingModifierLetters UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsSpacingModifierLetters(int code) { + return(((code >= 0x02B0) && (code <= 0x02FF))); +} + +/** + * xmlUCSIsSpecials: + * @code: UCS code point + * + * Check whether the character is part of Specials UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsSpecials(int code) { + return(((code >= 0xFFF0) && (code <= 0xFFFF))); +} + +/** + * xmlUCSIsSuperscriptsandSubscripts: + * @code: UCS code point + * + * Check whether the character is part of SuperscriptsandSubscripts UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsSuperscriptsandSubscripts(int code) { + return(((code >= 0x2070) && (code <= 0x209F))); +} + +/** + * xmlUCSIsSupplementalArrowsA: + * @code: UCS code point + * + * Check whether the character is part of SupplementalArrows-A UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsSupplementalArrowsA(int code) { + return(((code >= 0x27F0) && (code <= 0x27FF))); +} + +/** + * xmlUCSIsSupplementalArrowsB: + * @code: UCS code point + * + * Check whether the character is part of SupplementalArrows-B UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsSupplementalArrowsB(int code) { + return(((code >= 0x2900) && (code <= 0x297F))); +} + +/** + * xmlUCSIsSupplementalMathematicalOperators: + * @code: UCS code point + * + * Check whether the character is part of SupplementalMathematicalOperators UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsSupplementalMathematicalOperators(int code) { + return(((code >= 0x2A00) && (code <= 0x2AFF))); +} + +/** + * xmlUCSIsSupplementaryPrivateUseAreaA: + * @code: UCS code point + * + * Check whether the character is part of SupplementaryPrivateUseArea-A UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsSupplementaryPrivateUseAreaA(int code) { + return(((code >= 0xF0000) && (code <= 0xFFFFF))); +} + +/** + * xmlUCSIsSupplementaryPrivateUseAreaB: + * @code: UCS code point + * + * Check whether the character is part of SupplementaryPrivateUseArea-B UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsSupplementaryPrivateUseAreaB(int code) { + return(((code >= 0x100000) && (code <= 0x10FFFF))); +} + +/** + * xmlUCSIsSyriac: + * @code: UCS code point + * + * Check whether the character is part of Syriac UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsSyriac(int code) { + return(((code >= 0x0700) && (code <= 0x074F))); +} + +/** + * xmlUCSIsTagalog: + * @code: UCS code point + * + * Check whether the character is part of Tagalog UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsTagalog(int code) { + return(((code >= 0x1700) && (code <= 0x171F))); +} + +/** + * xmlUCSIsTagbanwa: + * @code: UCS code point + * + * Check whether the character is part of Tagbanwa UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsTagbanwa(int code) { + return(((code >= 0x1760) && (code <= 0x177F))); +} + +/** + * xmlUCSIsTags: + * @code: UCS code point + * + * Check whether the character is part of Tags UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsTags(int code) { + return(((code >= 0xE0000) && (code <= 0xE007F))); +} + +/** + * xmlUCSIsTaiLe: + * @code: UCS code point + * + * Check whether the character is part of TaiLe UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsTaiLe(int code) { + return(((code >= 0x1950) && (code <= 0x197F))); +} + +/** + * xmlUCSIsTaiXuanJingSymbols: + * @code: UCS code point + * + * Check whether the character is part of TaiXuanJingSymbols UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsTaiXuanJingSymbols(int code) { + return(((code >= 0x1D300) && (code <= 0x1D35F))); +} + +/** + * xmlUCSIsTamil: + * @code: UCS code point + * + * Check whether the character is part of Tamil UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsTamil(int code) { + return(((code >= 0x0B80) && (code <= 0x0BFF))); +} + +/** + * xmlUCSIsTelugu: + * @code: UCS code point + * + * Check whether the character is part of Telugu UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsTelugu(int code) { + return(((code >= 0x0C00) && (code <= 0x0C7F))); +} + +/** + * xmlUCSIsThaana: + * @code: UCS code point + * + * Check whether the character is part of Thaana UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsThaana(int code) { + return(((code >= 0x0780) && (code <= 0x07BF))); +} + +/** + * xmlUCSIsThai: + * @code: UCS code point + * + * Check whether the character is part of Thai UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsThai(int code) { + return(((code >= 0x0E00) && (code <= 0x0E7F))); +} + +/** + * xmlUCSIsTibetan: + * @code: UCS code point + * + * Check whether the character is part of Tibetan UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsTibetan(int code) { + return(((code >= 0x0F00) && (code <= 0x0FFF))); +} + +/** + * xmlUCSIsUgaritic: + * @code: UCS code point + * + * Check whether the character is part of Ugaritic UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsUgaritic(int code) { + return(((code >= 0x10380) && (code <= 0x1039F))); +} + +/** + * xmlUCSIsUnifiedCanadianAboriginalSyllabics: + * @code: UCS code point + * + * Check whether the character is part of UnifiedCanadianAboriginalSyllabics UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsUnifiedCanadianAboriginalSyllabics(int code) { + return(((code >= 0x1400) && (code <= 0x167F))); +} + +/** + * xmlUCSIsVariationSelectors: + * @code: UCS code point + * + * Check whether the character is part of VariationSelectors UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsVariationSelectors(int code) { + return(((code >= 0xFE00) && (code <= 0xFE0F))); +} + +/** + * xmlUCSIsVariationSelectorsSupplement: + * @code: UCS code point + * + * Check whether the character is part of VariationSelectorsSupplement UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsVariationSelectorsSupplement(int code) { + return(((code >= 0xE0100) && (code <= 0xE01EF))); +} + +/** + * xmlUCSIsYiRadicals: + * @code: UCS code point + * + * Check whether the character is part of YiRadicals UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsYiRadicals(int code) { + return(((code >= 0xA490) && (code <= 0xA4CF))); +} + +/** + * xmlUCSIsYiSyllables: + * @code: UCS code point + * + * Check whether the character is part of YiSyllables UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsYiSyllables(int code) { + return(((code >= 0xA000) && (code <= 0xA48F))); +} + +/** + * xmlUCSIsYijingHexagramSymbols: + * @code: UCS code point + * + * Check whether the character is part of YijingHexagramSymbols UCS Block + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsYijingHexagramSymbols(int code) { + return(((code >= 0x4DC0) && (code <= 0x4DFF))); +} + +/** + * xmlUCSIsBlock: + * @code: UCS code point + * @block: UCS block name + * + * Check whether the character is part of the UCS Block + * + * Returns 1 if true, 0 if false and -1 on unknown block + */ +int +xmlUCSIsBlock(int code, const char *block) { + xmlIntFunc *func; + + func = xmlUnicodeLookup(&xmlUnicodeBlockTbl, block); + if (func == NULL) + return (-1); + return (func(code)); +} + +/** + * xmlUCSIsCatC: + * @code: UCS code point + * + * Check whether the character is part of C UCS Category + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCatC(int code) { + return(xmlCharInRange((unsigned int)code, &xmlCG)); +} + +/** + * xmlUCSIsCatCc: + * @code: UCS code point + * + * Check whether the character is part of Cc UCS Category + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCatCc(int code) { + return(((code >= 0x0) && (code <= 0x1f)) || + ((code >= 0x7f) && (code <= 0x9f))); +} + +/** + * xmlUCSIsCatCf: + * @code: UCS code point + * + * Check whether the character is part of Cf UCS Category + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCatCf(int code) { + return(xmlCharInRange((unsigned int)code, &xmlCfG)); +} + +/** + * xmlUCSIsCatCo: + * @code: UCS code point + * + * Check whether the character is part of Co UCS Category + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCatCo(int code) { + return((code == 0xe000) || + (code == 0xf8ff) || + (code == 0xf0000) || + (code == 0xffffd) || + (code == 0x100000) || + (code == 0x10fffd)); +} + +/** + * xmlUCSIsCatCs: + * @code: UCS code point + * + * Check whether the character is part of Cs UCS Category + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCatCs(int code) { + return((code == 0xd800) || + ((code >= 0xdb7f) && (code <= 0xdb80)) || + ((code >= 0xdbff) && (code <= 0xdc00)) || + (code == 0xdfff)); +} + +/** + * xmlUCSIsCatL: + * @code: UCS code point + * + * Check whether the character is part of L UCS Category + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCatL(int code) { + return(xmlCharInRange((unsigned int)code, &xmlLG)); +} + +/** + * xmlUCSIsCatLl: + * @code: UCS code point + * + * Check whether the character is part of Ll UCS Category + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCatLl(int code) { + return(xmlCharInRange((unsigned int)code, &xmlLlG)); +} + +/** + * xmlUCSIsCatLm: + * @code: UCS code point + * + * Check whether the character is part of Lm UCS Category + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCatLm(int code) { + return(xmlCharInRange((unsigned int)code, &xmlLmG)); +} + +/** + * xmlUCSIsCatLo: + * @code: UCS code point + * + * Check whether the character is part of Lo UCS Category + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCatLo(int code) { + return(xmlCharInRange((unsigned int)code, &xmlLoG)); +} + +/** + * xmlUCSIsCatLt: + * @code: UCS code point + * + * Check whether the character is part of Lt UCS Category + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCatLt(int code) { + return(xmlCharInRange((unsigned int)code, &xmlLtG)); +} + +/** + * xmlUCSIsCatLu: + * @code: UCS code point + * + * Check whether the character is part of Lu UCS Category + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCatLu(int code) { + return(xmlCharInRange((unsigned int)code, &xmlLuG)); +} + +/** + * xmlUCSIsCatM: + * @code: UCS code point + * + * Check whether the character is part of M UCS Category + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCatM(int code) { + return(xmlCharInRange((unsigned int)code, &xmlMG)); +} + +/** + * xmlUCSIsCatMc: + * @code: UCS code point + * + * Check whether the character is part of Mc UCS Category + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCatMc(int code) { + return(xmlCharInRange((unsigned int)code, &xmlMcG)); +} + +/** + * xmlUCSIsCatMe: + * @code: UCS code point + * + * Check whether the character is part of Me UCS Category + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCatMe(int code) { + return(((code >= 0x488) && (code <= 0x489)) || + (code == 0x6de) || + ((code >= 0x20dd) && (code <= 0x20e0)) || + ((code >= 0x20e2) && (code <= 0x20e4))); +} + +/** + * xmlUCSIsCatMn: + * @code: UCS code point + * + * Check whether the character is part of Mn UCS Category + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCatMn(int code) { + return(xmlCharInRange((unsigned int)code, &xmlMnG)); +} + +/** + * xmlUCSIsCatN: + * @code: UCS code point + * + * Check whether the character is part of N UCS Category + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCatN(int code) { + return(xmlCharInRange((unsigned int)code, &xmlNG)); +} + +/** + * xmlUCSIsCatNd: + * @code: UCS code point + * + * Check whether the character is part of Nd UCS Category + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCatNd(int code) { + return(xmlCharInRange((unsigned int)code, &xmlNdG)); +} + +/** + * xmlUCSIsCatNl: + * @code: UCS code point + * + * Check whether the character is part of Nl UCS Category + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCatNl(int code) { + return(((code >= 0x16ee) && (code <= 0x16f0)) || + ((code >= 0x2160) && (code <= 0x2183)) || + (code == 0x3007) || + ((code >= 0x3021) && (code <= 0x3029)) || + ((code >= 0x3038) && (code <= 0x303a)) || + (code == 0x1034a)); +} + +/** + * xmlUCSIsCatNo: + * @code: UCS code point + * + * Check whether the character is part of No UCS Category + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCatNo(int code) { + return(xmlCharInRange((unsigned int)code, &xmlNoG)); +} + +/** + * xmlUCSIsCatP: + * @code: UCS code point + * + * Check whether the character is part of P UCS Category + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCatP(int code) { + return(xmlCharInRange((unsigned int)code, &xmlPG)); +} + +/** + * xmlUCSIsCatPc: + * @code: UCS code point + * + * Check whether the character is part of Pc UCS Category + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCatPc(int code) { + return((code == 0x5f) || + ((code >= 0x203f) && (code <= 0x2040)) || + (code == 0x2054) || + (code == 0x30fb) || + ((code >= 0xfe33) && (code <= 0xfe34)) || + ((code >= 0xfe4d) && (code <= 0xfe4f)) || + (code == 0xff3f) || + (code == 0xff65)); +} + +/** + * xmlUCSIsCatPd: + * @code: UCS code point + * + * Check whether the character is part of Pd UCS Category + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCatPd(int code) { + return(xmlCharInRange((unsigned int)code, &xmlPdG)); +} + +/** + * xmlUCSIsCatPe: + * @code: UCS code point + * + * Check whether the character is part of Pe UCS Category + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCatPe(int code) { + return(xmlCharInRange((unsigned int)code, &xmlPeG)); +} + +/** + * xmlUCSIsCatPf: + * @code: UCS code point + * + * Check whether the character is part of Pf UCS Category + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCatPf(int code) { + return((code == 0xbb) || + (code == 0x2019) || + (code == 0x201d) || + (code == 0x203a)); +} + +/** + * xmlUCSIsCatPi: + * @code: UCS code point + * + * Check whether the character is part of Pi UCS Category + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCatPi(int code) { + return((code == 0xab) || + (code == 0x2018) || + ((code >= 0x201b) && (code <= 0x201c)) || + (code == 0x201f) || + (code == 0x2039)); +} + +/** + * xmlUCSIsCatPo: + * @code: UCS code point + * + * Check whether the character is part of Po UCS Category + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCatPo(int code) { + return(xmlCharInRange((unsigned int)code, &xmlPoG)); +} + +/** + * xmlUCSIsCatPs: + * @code: UCS code point + * + * Check whether the character is part of Ps UCS Category + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCatPs(int code) { + return(xmlCharInRange((unsigned int)code, &xmlPsG)); +} + +/** + * xmlUCSIsCatS: + * @code: UCS code point + * + * Check whether the character is part of S UCS Category + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCatS(int code) { + return(xmlCharInRange((unsigned int)code, &xmlSG)); +} + +/** + * xmlUCSIsCatSc: + * @code: UCS code point + * + * Check whether the character is part of Sc UCS Category + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCatSc(int code) { + return(xmlCharInRange((unsigned int)code, &xmlScG)); +} + +/** + * xmlUCSIsCatSk: + * @code: UCS code point + * + * Check whether the character is part of Sk UCS Category + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCatSk(int code) { + return(xmlCharInRange((unsigned int)code, &xmlSkG)); +} + +/** + * xmlUCSIsCatSm: + * @code: UCS code point + * + * Check whether the character is part of Sm UCS Category + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCatSm(int code) { + return(xmlCharInRange((unsigned int)code, &xmlSmG)); +} + +/** + * xmlUCSIsCatSo: + * @code: UCS code point + * + * Check whether the character is part of So UCS Category + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCatSo(int code) { + return(xmlCharInRange((unsigned int)code, &xmlSoG)); +} + +/** + * xmlUCSIsCatZ: + * @code: UCS code point + * + * Check whether the character is part of Z UCS Category + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCatZ(int code) { + return(xmlCharInRange((unsigned int)code, &xmlZG)); +} + +/** + * xmlUCSIsCatZl: + * @code: UCS code point + * + * Check whether the character is part of Zl UCS Category + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCatZl(int code) { + return((code == 0x2028)); +} + +/** + * xmlUCSIsCatZp: + * @code: UCS code point + * + * Check whether the character is part of Zp UCS Category + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCatZp(int code) { + return((code == 0x2029)); +} + +/** + * xmlUCSIsCatZs: + * @code: UCS code point + * + * Check whether the character is part of Zs UCS Category + * + * Returns 1 if true 0 otherwise + */ +int +xmlUCSIsCatZs(int code) { + return((code == 0x20) || + (code == 0xa0) || + (code == 0x1680) || + (code == 0x180e) || + ((code >= 0x2000) && (code <= 0x200a)) || + (code == 0x202f) || + (code == 0x205f) || + (code == 0x3000)); +} + +/** + * xmlUCSIsCat: + * @code: UCS code point + * @cat: UCS Category name + * + * Check whether the character is part of the UCS Category + * + * Returns 1 if true, 0 if false and -1 on unknown category + */ +int +xmlUCSIsCat(int code, const char *cat) { + xmlIntFunc *func; + + func = xmlUnicodeLookup(&xmlUnicodeCatTbl, cat); + if (func == NULL) + return (-1); + return (func(code)); +} + +#define bottom_xmlunicode +#include "elfgcchack.h" +#endif /* LIBXML_UNICODE_ENABLED */ diff --git a/android/native/libxml2/xmlwriter.c b/android/native/libxml2/xmlwriter.c new file mode 100644 index 0000000000..0103aa2113 --- /dev/null +++ b/android/native/libxml2/xmlwriter.c @@ -0,0 +1,4699 @@ + +/* + * xmlwriter.c: XML text writer implementation + * + * For license and disclaimer see the license and disclaimer of + * libxml2. + * + * alfred@mickautsch.de + */ + +#define IN_LIBXML +#include "libxml.h" +#include + +#include +#include +#include +#include + +#ifdef LIBXML_WRITER_ENABLED + +#include + +#define B64LINELEN 72 +#define B64CRLF "\r\n" + +/* + * 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 (i.e. it may need + * something involving a memcpy) but (hopefully) will be + * sufficient for libxml2. + */ +#ifndef VA_COPY + #ifdef HAVE_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 + #define VA_COPY(dest,src) (dest) = (src) + #endif + #endif +#endif + +/* + * Types are kept private + */ +typedef enum { + XML_TEXTWRITER_NONE = 0, + XML_TEXTWRITER_NAME, + XML_TEXTWRITER_ATTRIBUTE, + XML_TEXTWRITER_TEXT, + XML_TEXTWRITER_PI, + XML_TEXTWRITER_PI_TEXT, + XML_TEXTWRITER_CDATA, + XML_TEXTWRITER_DTD, + XML_TEXTWRITER_DTD_TEXT, + XML_TEXTWRITER_DTD_ELEM, + XML_TEXTWRITER_DTD_ELEM_TEXT, + XML_TEXTWRITER_DTD_ATTL, + XML_TEXTWRITER_DTD_ATTL_TEXT, + XML_TEXTWRITER_DTD_ENTY, /* entity */ + XML_TEXTWRITER_DTD_ENTY_TEXT, + XML_TEXTWRITER_DTD_PENT, /* parameter entity */ + XML_TEXTWRITER_COMMENT +} xmlTextWriterState; + +typedef struct _xmlTextWriterStackEntry xmlTextWriterStackEntry; + +struct _xmlTextWriterStackEntry { + xmlChar *name; + xmlTextWriterState state; +}; + +typedef struct _xmlTextWriterNsStackEntry xmlTextWriterNsStackEntry; +struct _xmlTextWriterNsStackEntry { + xmlChar *prefix; + xmlChar *uri; + xmlLinkPtr elem; +}; + +struct _xmlTextWriter { + xmlOutputBufferPtr out; /* output buffer */ + xmlListPtr nodes; /* element name stack */ + xmlListPtr nsstack; /* name spaces stack */ + int level; + int indent; /* enable indent */ + int doindent; /* internal indent flag */ + xmlChar *ichar; /* indent character */ + char qchar; /* character used for quoting attribute values */ + xmlParserCtxtPtr ctxt; + int no_doc_free; + xmlDocPtr doc; +}; + +static void xmlFreeTextWriterStackEntry(xmlLinkPtr lk); +static int xmlCmpTextWriterStackEntry(const void *data0, + const void *data1); +static int xmlTextWriterOutputNSDecl(xmlTextWriterPtr writer); +static void xmlFreeTextWriterNsStackEntry(xmlLinkPtr lk); +static int xmlCmpTextWriterNsStackEntry(const void *data0, + const void *data1); +static int xmlTextWriterWriteDocCallback(void *context, + const xmlChar * str, int len); +static int xmlTextWriterCloseDocCallback(void *context); + +static xmlChar *xmlTextWriterVSprintf(const char *format, va_list argptr); +static int xmlOutputBufferWriteBase64(xmlOutputBufferPtr out, int len, + const unsigned char *data); +static void xmlTextWriterStartDocumentCallback(void *ctx); +static int xmlTextWriterWriteIndent(xmlTextWriterPtr writer); +static int + xmlTextWriterHandleStateDependencies(xmlTextWriterPtr writer, + xmlTextWriterStackEntry * p); + +/** + * xmlWriterErrMsg: + * @ctxt: a writer context + * @error: the error number + * @msg: the error message + * + * Handle a writer error + */ +static void +xmlWriterErrMsg(xmlTextWriterPtr ctxt, xmlParserErrors error, + const char *msg) +{ + if (ctxt != NULL) { + __xmlRaiseError(NULL, NULL, NULL, ctxt->ctxt, + NULL, XML_FROM_WRITER, error, XML_ERR_FATAL, + NULL, 0, NULL, NULL, NULL, 0, 0, "%s", msg); + } else { + __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_WRITER, error, + XML_ERR_FATAL, NULL, 0, NULL, NULL, NULL, 0, 0, "%s", msg); + } +} + +/** + * xmlWriterErrMsgInt: + * @ctxt: a writer context + * @error: the error number + * @msg: the error message + * @val: an int + * + * Handle a writer error + */ +static void +xmlWriterErrMsgInt(xmlTextWriterPtr ctxt, xmlParserErrors error, + const char *msg, int val) +{ + if (ctxt != NULL) { + __xmlRaiseError(NULL, NULL, NULL, ctxt->ctxt, + NULL, XML_FROM_WRITER, error, XML_ERR_FATAL, + NULL, 0, NULL, NULL, NULL, val, 0, msg, val); + } else { + __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_WRITER, error, + XML_ERR_FATAL, NULL, 0, NULL, NULL, NULL, val, 0, msg, val); + } +} + +/** + * xmlNewTextWriter: + * @out: an xmlOutputBufferPtr + * + * Create a new xmlNewTextWriter structure using an xmlOutputBufferPtr + * NOTE: the @out parameter will be deallocated when the writer is closed + * (if the call succeed.) + * + * Returns the new xmlTextWriterPtr or NULL in case of error + */ +xmlTextWriterPtr +xmlNewTextWriter(xmlOutputBufferPtr out) +{ + xmlTextWriterPtr ret; + + ret = (xmlTextWriterPtr) xmlMalloc(sizeof(xmlTextWriter)); + if (ret == NULL) { + xmlWriterErrMsg(NULL, XML_ERR_NO_MEMORY, + "xmlNewTextWriter : out of memory!\n"); + return NULL; + } + memset(ret, 0, (size_t) sizeof(xmlTextWriter)); + + ret->nodes = xmlListCreate((xmlListDeallocator) + xmlFreeTextWriterStackEntry, + (xmlListDataCompare) + xmlCmpTextWriterStackEntry); + if (ret->nodes == NULL) { + xmlWriterErrMsg(NULL, XML_ERR_NO_MEMORY, + "xmlNewTextWriter : out of memory!\n"); + xmlFree(ret); + return NULL; + } + + ret->nsstack = xmlListCreate((xmlListDeallocator) + xmlFreeTextWriterNsStackEntry, + (xmlListDataCompare) + xmlCmpTextWriterNsStackEntry); + if (ret->nsstack == NULL) { + xmlWriterErrMsg(NULL, XML_ERR_NO_MEMORY, + "xmlNewTextWriter : out of memory!\n"); + xmlListDelete(ret->nodes); + xmlFree(ret); + return NULL; + } + + ret->out = out; + ret->ichar = xmlStrdup(BAD_CAST " "); + ret->qchar = '"'; + + if (!ret->ichar) { + xmlListDelete(ret->nodes); + xmlListDelete(ret->nsstack); + xmlFree(ret); + xmlWriterErrMsg(NULL, XML_ERR_NO_MEMORY, + "xmlNewTextWriter : out of memory!\n"); + return NULL; + } + + ret->doc = xmlNewDoc(NULL); + + ret->no_doc_free = 0; + + return ret; +} + +/** + * xmlNewTextWriterFilename: + * @uri: the URI of the resource for the output + * @compression: compress the output? + * + * Create a new xmlNewTextWriter structure with @uri as output + * + * Returns the new xmlTextWriterPtr or NULL in case of error + */ +xmlTextWriterPtr +xmlNewTextWriterFilename(const char *uri, int compression) +{ + xmlTextWriterPtr ret; + xmlOutputBufferPtr out; + + out = xmlOutputBufferCreateFilename(uri, NULL, compression); + if (out == NULL) { + xmlWriterErrMsg(NULL, XML_IO_EIO, + "xmlNewTextWriterFilename : cannot open uri\n"); + return NULL; + } + + ret = xmlNewTextWriter(out); + if (ret == NULL) { + xmlWriterErrMsg(NULL, XML_ERR_NO_MEMORY, + "xmlNewTextWriterFilename : out of memory!\n"); + xmlOutputBufferClose(out); + return NULL; + } + + ret->indent = 0; + ret->doindent = 0; + return ret; +} + +/** + * xmlNewTextWriterMemory: + * @buf: xmlBufferPtr + * @compression: compress the output? + * + * Create a new xmlNewTextWriter structure with @buf as output + * TODO: handle compression + * + * Returns the new xmlTextWriterPtr or NULL in case of error + */ +xmlTextWriterPtr +xmlNewTextWriterMemory(xmlBufferPtr buf, int compression ATTRIBUTE_UNUSED) +{ + xmlTextWriterPtr ret; + xmlOutputBufferPtr out; + +/*::todo handle compression */ + out = xmlOutputBufferCreateBuffer(buf, NULL); + + if (out == NULL) { + xmlWriterErrMsg(NULL, XML_ERR_NO_MEMORY, + "xmlNewTextWriterMemory : out of memory!\n"); + return NULL; + } + + ret = xmlNewTextWriter(out); + if (ret == NULL) { + xmlWriterErrMsg(NULL, XML_ERR_NO_MEMORY, + "xmlNewTextWriterMemory : out of memory!\n"); + xmlOutputBufferClose(out); + return NULL; + } + + return ret; +} + +/** + * xmlNewTextWriterPushParser: + * @ctxt: xmlParserCtxtPtr to hold the new XML document tree + * @compression: compress the output? + * + * Create a new xmlNewTextWriter structure with @ctxt as output + * NOTE: the @ctxt context will be freed with the resulting writer + * (if the call succeeds). + * TODO: handle compression + * + * Returns the new xmlTextWriterPtr or NULL in case of error + */ +xmlTextWriterPtr +xmlNewTextWriterPushParser(xmlParserCtxtPtr ctxt, + int compression ATTRIBUTE_UNUSED) +{ + xmlTextWriterPtr ret; + xmlOutputBufferPtr out; + + if (ctxt == NULL) { + xmlWriterErrMsg(NULL, XML_ERR_INTERNAL_ERROR, + "xmlNewTextWriterPushParser : invalid context!\n"); + return NULL; + } + + out = xmlOutputBufferCreateIO((xmlOutputWriteCallback) + xmlTextWriterWriteDocCallback, + (xmlOutputCloseCallback) + xmlTextWriterCloseDocCallback, + (void *) ctxt, NULL); + if (out == NULL) { + xmlWriterErrMsg(NULL, XML_ERR_INTERNAL_ERROR, + "xmlNewTextWriterPushParser : error at xmlOutputBufferCreateIO!\n"); + return NULL; + } + + ret = xmlNewTextWriter(out); + if (ret == NULL) { + xmlWriterErrMsg(NULL, XML_ERR_INTERNAL_ERROR, + "xmlNewTextWriterPushParser : error at xmlNewTextWriter!\n"); + xmlOutputBufferClose(out); + return NULL; + } + + ret->ctxt = ctxt; + + return ret; +} + +/** + * xmlNewTextWriterDoc: + * @doc: address of a xmlDocPtr to hold the new XML document tree + * @compression: compress the output? + * + * Create a new xmlNewTextWriter structure with @*doc as output + * + * Returns the new xmlTextWriterPtr or NULL in case of error + */ +xmlTextWriterPtr +xmlNewTextWriterDoc(xmlDocPtr * doc, int compression) +{ + xmlTextWriterPtr ret; + xmlSAXHandler saxHandler; + xmlParserCtxtPtr ctxt; + + memset(&saxHandler, '\0', sizeof(saxHandler)); + xmlSAX2InitDefaultSAXHandler(&saxHandler, 1); + saxHandler.startDocument = xmlTextWriterStartDocumentCallback; + saxHandler.startElement = xmlSAX2StartElement; + saxHandler.endElement = xmlSAX2EndElement; + + ctxt = xmlCreatePushParserCtxt(&saxHandler, NULL, NULL, 0, NULL); + if (ctxt == NULL) { + xmlWriterErrMsg(NULL, XML_ERR_INTERNAL_ERROR, + "xmlNewTextWriterDoc : error at xmlCreatePushParserCtxt!\n"); + return NULL; + } + /* + * For some reason this seems to completely break if node names + * are interned. + */ + ctxt->dictNames = 0; + + ctxt->myDoc = xmlNewDoc(BAD_CAST XML_DEFAULT_VERSION); + if (ctxt->myDoc == NULL) { + xmlFreeParserCtxt(ctxt); + xmlWriterErrMsg(NULL, XML_ERR_INTERNAL_ERROR, + "xmlNewTextWriterDoc : error at xmlNewDoc!\n"); + return NULL; + } + + ret = xmlNewTextWriterPushParser(ctxt, compression); + if (ret == NULL) { + xmlFreeDoc(ctxt->myDoc); + xmlFreeParserCtxt(ctxt); + xmlWriterErrMsg(NULL, XML_ERR_INTERNAL_ERROR, + "xmlNewTextWriterDoc : error at xmlNewTextWriterPushParser!\n"); + return NULL; + } + + xmlSetDocCompressMode(ctxt->myDoc, compression); + + if (doc != NULL) { + *doc = ctxt->myDoc; + ret->no_doc_free = 1; + } + + return ret; +} + +/** + * xmlNewTextWriterTree: + * @doc: xmlDocPtr + * @node: xmlNodePtr or NULL for doc->children + * @compression: compress the output? + * + * Create a new xmlNewTextWriter structure with @doc as output + * starting at @node + * + * Returns the new xmlTextWriterPtr or NULL in case of error + */ +xmlTextWriterPtr +xmlNewTextWriterTree(xmlDocPtr doc, xmlNodePtr node, int compression) +{ + xmlTextWriterPtr ret; + xmlSAXHandler saxHandler; + xmlParserCtxtPtr ctxt; + + if (doc == NULL) { + xmlWriterErrMsg(NULL, XML_ERR_INTERNAL_ERROR, + "xmlNewTextWriterTree : invalid document tree!\n"); + return NULL; + } + + memset(&saxHandler, '\0', sizeof(saxHandler)); + xmlSAX2InitDefaultSAXHandler(&saxHandler, 1); + saxHandler.startDocument = xmlTextWriterStartDocumentCallback; + saxHandler.startElement = xmlSAX2StartElement; + saxHandler.endElement = xmlSAX2EndElement; + + ctxt = xmlCreatePushParserCtxt(&saxHandler, NULL, NULL, 0, NULL); + if (ctxt == NULL) { + xmlWriterErrMsg(NULL, XML_ERR_INTERNAL_ERROR, + "xmlNewTextWriterDoc : error at xmlCreatePushParserCtxt!\n"); + return NULL; + } + /* + * For some reason this seems to completely break if node names + * are interned. + */ + ctxt->dictNames = 0; + + ret = xmlNewTextWriterPushParser(ctxt, compression); + if (ret == NULL) { + xmlFreeParserCtxt(ctxt); + xmlWriterErrMsg(NULL, XML_ERR_INTERNAL_ERROR, + "xmlNewTextWriterDoc : error at xmlNewTextWriterPushParser!\n"); + return NULL; + } + + ctxt->myDoc = doc; + ctxt->node = node; + ret->no_doc_free = 1; + + xmlSetDocCompressMode(doc, compression); + + return ret; +} + +/** + * xmlFreeTextWriter: + * @writer: the xmlTextWriterPtr + * + * Deallocate all the resources associated to the writer + */ +void +xmlFreeTextWriter(xmlTextWriterPtr writer) +{ + if (writer == NULL) + return; + + if (writer->out != NULL) + xmlOutputBufferClose(writer->out); + + if (writer->nodes != NULL) + xmlListDelete(writer->nodes); + + if (writer->nsstack != NULL) + xmlListDelete(writer->nsstack); + + if (writer->ctxt != NULL) { + if ((writer->ctxt->myDoc != NULL) && (writer->no_doc_free == 0)) { + xmlFreeDoc(writer->ctxt->myDoc); + writer->ctxt->myDoc = NULL; + } + xmlFreeParserCtxt(writer->ctxt); + } + + if (writer->doc != NULL) + xmlFreeDoc(writer->doc); + + if (writer->ichar != NULL) + xmlFree(writer->ichar); + xmlFree(writer); +} + +/** + * xmlTextWriterStartDocument: + * @writer: the xmlTextWriterPtr + * @version: the xml version ("1.0") or NULL for default ("1.0") + * @encoding: the encoding or NULL for default + * @standalone: "yes" or "no" or NULL for default + * + * Start a new xml document + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterStartDocument(xmlTextWriterPtr writer, const char *version, + const char *encoding, const char *standalone) +{ + int count; + int sum; + xmlLinkPtr lk; + xmlCharEncodingHandlerPtr encoder; + + if ((writer == NULL) || (writer->out == NULL)) { + xmlWriterErrMsg(writer, XML_ERR_INTERNAL_ERROR, + "xmlTextWriterStartDocument : invalid writer!\n"); + return -1; + } + + lk = xmlListFront(writer->nodes); + if ((lk != NULL) && (xmlLinkGetData(lk) != NULL)) { + xmlWriterErrMsg(writer, XML_ERR_INTERNAL_ERROR, + "xmlTextWriterStartDocument : not allowed in this context!\n"); + return -1; + } + + encoder = NULL; + if (encoding != NULL) { + encoder = xmlFindCharEncodingHandler(encoding); + if (encoder == NULL) { + xmlWriterErrMsg(writer, XML_ERR_NO_MEMORY, + "xmlTextWriterStartDocument : out of memory!\n"); + return -1; + } + } + + writer->out->encoder = encoder; + if (encoder != NULL) { + if (writer->out->conv == NULL) { + writer->out->conv = xmlBufferCreateSize(4000); + } + xmlCharEncOutFunc(encoder, writer->out->conv, NULL); + if ((writer->doc != NULL) && (writer->doc->encoding == NULL)) + writer->doc->encoding = xmlStrdup((xmlChar *)writer->out->encoder->name); + } else + writer->out->conv = NULL; + + sum = 0; + count = xmlOutputBufferWriteString(writer->out, "out, 1, &writer->qchar); + if (count < 0) + return -1; + sum += count; + if (version != 0) + count = xmlOutputBufferWriteString(writer->out, version); + else + count = xmlOutputBufferWriteString(writer->out, "1.0"); + if (count < 0) + return -1; + sum += count; + count = xmlOutputBufferWrite(writer->out, 1, &writer->qchar); + if (count < 0) + return -1; + sum += count; + if (writer->out->encoder != 0) { + count = xmlOutputBufferWriteString(writer->out, " encoding="); + if (count < 0) + return -1; + sum += count; + count = xmlOutputBufferWrite(writer->out, 1, &writer->qchar); + if (count < 0) + return -1; + sum += count; + count = + xmlOutputBufferWriteString(writer->out, + writer->out->encoder->name); + if (count < 0) + return -1; + sum += count; + count = xmlOutputBufferWrite(writer->out, 1, &writer->qchar); + if (count < 0) + return -1; + sum += count; + } + + if (standalone != 0) { + count = xmlOutputBufferWriteString(writer->out, " standalone="); + if (count < 0) + return -1; + sum += count; + count = xmlOutputBufferWrite(writer->out, 1, &writer->qchar); + if (count < 0) + return -1; + sum += count; + count = xmlOutputBufferWriteString(writer->out, standalone); + if (count < 0) + return -1; + sum += count; + count = xmlOutputBufferWrite(writer->out, 1, &writer->qchar); + if (count < 0) + return -1; + sum += count; + } + + count = xmlOutputBufferWriteString(writer->out, "?>\n"); + if (count < 0) + return -1; + sum += count; + + return sum; +} + +/** + * xmlTextWriterEndDocument: + * @writer: the xmlTextWriterPtr + * + * End an xml document. All open elements are closed, and + * the content is flushed to the output. + * + * Returns the bytes written or -1 in case of error + */ +int +xmlTextWriterEndDocument(xmlTextWriterPtr writer) +{ + int count; + int sum; + xmlLinkPtr lk; + xmlTextWriterStackEntry *p; + + if (writer == NULL) { + xmlWriterErrMsg(writer, XML_ERR_INTERNAL_ERROR, + "xmlTextWriterEndDocument : invalid writer!\n"); + return -1; + } + + sum = 0; + while ((lk = xmlListFront(writer->nodes)) != NULL) { + p = (xmlTextWriterStackEntry *) xmlLinkGetData(lk); + if (p == 0) + break; + switch (p->state) { + case XML_TEXTWRITER_NAME: + case XML_TEXTWRITER_ATTRIBUTE: + case XML_TEXTWRITER_TEXT: + count = xmlTextWriterEndElement(writer); + if (count < 0) + return -1; + sum += count; + break; + case XML_TEXTWRITER_PI: + case XML_TEXTWRITER_PI_TEXT: + count = xmlTextWriterEndPI(writer); + if (count < 0) + return -1; + sum += count; + break; + case XML_TEXTWRITER_CDATA: + count = xmlTextWriterEndCDATA(writer); + if (count < 0) + return -1; + sum += count; + break; + case XML_TEXTWRITER_DTD: + case XML_TEXTWRITER_DTD_TEXT: + case XML_TEXTWRITER_DTD_ELEM: + case XML_TEXTWRITER_DTD_ELEM_TEXT: + case XML_TEXTWRITER_DTD_ATTL: + case XML_TEXTWRITER_DTD_ATTL_TEXT: + case XML_TEXTWRITER_DTD_ENTY: + case XML_TEXTWRITER_DTD_ENTY_TEXT: + case XML_TEXTWRITER_DTD_PENT: + count = xmlTextWriterEndDTD(writer); + if (count < 0) + return -1; + sum += count; + break; + case XML_TEXTWRITER_COMMENT: + count = xmlTextWriterEndComment(writer); + if (count < 0) + return -1; + sum += count; + break; + default: + break; + } + } + + if (!writer->indent) { + count = xmlOutputBufferWriteString(writer->out, "\n"); + if (count < 0) + return -1; + sum += count; + } + + sum += xmlTextWriterFlush(writer); + + return sum; +} + +/** + * xmlTextWriterStartComment: + * @writer: the xmlTextWriterPtr + * + * Start an xml comment. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterStartComment(xmlTextWriterPtr writer) +{ + int count; + int sum; + xmlLinkPtr lk; + xmlTextWriterStackEntry *p; + + if (writer == NULL) { + xmlWriterErrMsg(writer, XML_ERR_INTERNAL_ERROR, + "xmlTextWriterStartComment : invalid writer!\n"); + return -1; + } + + sum = 0; + lk = xmlListFront(writer->nodes); + if (lk != 0) { + p = (xmlTextWriterStackEntry *) xmlLinkGetData(lk); + if (p != 0) { + switch (p->state) { + case XML_TEXTWRITER_TEXT: + case XML_TEXTWRITER_NONE: + break; + case XML_TEXTWRITER_NAME: + /* Output namespace declarations */ + count = xmlTextWriterOutputNSDecl(writer); + if (count < 0) + return -1; + sum += count; + count = xmlOutputBufferWriteString(writer->out, ">"); + if (count < 0) + return -1; + sum += count; + if (writer->indent) { + count = + xmlOutputBufferWriteString(writer->out, "\n"); + if (count < 0) + return -1; + sum += count; + } + p->state = XML_TEXTWRITER_TEXT; + break; + default: + return -1; + } + } + } + + p = (xmlTextWriterStackEntry *) + xmlMalloc(sizeof(xmlTextWriterStackEntry)); + if (p == 0) { + xmlWriterErrMsg(writer, XML_ERR_NO_MEMORY, + "xmlTextWriterStartElement : out of memory!\n"); + return -1; + } + + p->name = NULL; + p->state = XML_TEXTWRITER_COMMENT; + + xmlListPushFront(writer->nodes, p); + + if (writer->indent) { + count = xmlTextWriterWriteIndent(writer); + if (count < 0) + return -1; + sum += count; + } + + count = xmlOutputBufferWriteString(writer->out, ""); + if (count < 0) + return -1; + sum += count; + break; + default: + return -1; + } + + if (writer->indent) { + count = xmlOutputBufferWriteString(writer->out, "\n"); + if (count < 0) + return -1; + sum += count; + } + + xmlListPopFront(writer->nodes); + return sum; +} + +/** + * xmlTextWriterWriteFormatComment: + * @writer: the xmlTextWriterPtr + * @format: format string (see printf) + * @...: extra parameters for the format + * + * Write an xml comment. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int XMLCDECL +xmlTextWriterWriteFormatComment(xmlTextWriterPtr writer, + const char *format, ...) +{ + int rc; + va_list ap; + + va_start(ap, format); + + rc = xmlTextWriterWriteVFormatComment(writer, format, ap); + + va_end(ap); + return rc; +} + +/** + * xmlTextWriterWriteVFormatComment: + * @writer: the xmlTextWriterPtr + * @format: format string (see printf) + * @argptr: pointer to the first member of the variable argument list. + * + * Write an xml comment. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterWriteVFormatComment(xmlTextWriterPtr writer, + const char *format, va_list argptr) +{ + int rc; + xmlChar *buf; + + if (writer == NULL) { + xmlWriterErrMsg(writer, XML_ERR_INTERNAL_ERROR, + "xmlTextWriterWriteVFormatComment : invalid writer!\n"); + return -1; + } + + buf = xmlTextWriterVSprintf(format, argptr); + if (buf == NULL) + return -1; + + rc = xmlTextWriterWriteComment(writer, buf); + + xmlFree(buf); + return rc; +} + +/** + * xmlTextWriterWriteComment: + * @writer: the xmlTextWriterPtr + * @content: comment string + * + * Write an xml comment. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterWriteComment(xmlTextWriterPtr writer, const xmlChar * content) +{ + int count; + int sum; + + sum = 0; + count = xmlTextWriterStartComment(writer); + if (count < 0) + return -1; + sum += count; + count = xmlTextWriterWriteString(writer, content); + if (count < 0) + return -1; + sum += count; + count = xmlTextWriterEndComment(writer); + if (count < 0) + return -1; + sum += count; + + return sum; +} + +/** + * xmlTextWriterStartElement: + * @writer: the xmlTextWriterPtr + * @name: element name + * + * Start an xml element. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterStartElement(xmlTextWriterPtr writer, const xmlChar * name) +{ + int count; + int sum; + xmlLinkPtr lk; + xmlTextWriterStackEntry *p; + + if ((writer == NULL) || (name == NULL) || (*name == '\0')) + return -1; + + sum = 0; + lk = xmlListFront(writer->nodes); + if (lk != 0) { + p = (xmlTextWriterStackEntry *) xmlLinkGetData(lk); + if (p != 0) { + switch (p->state) { + case XML_TEXTWRITER_PI: + case XML_TEXTWRITER_PI_TEXT: + return -1; + case XML_TEXTWRITER_NONE: + break; + case XML_TEXTWRITER_ATTRIBUTE: + count = xmlTextWriterEndAttribute(writer); + if (count < 0) + return -1; + sum += count; + /* fallthrough */ + case XML_TEXTWRITER_NAME: + /* Output namespace declarations */ + count = xmlTextWriterOutputNSDecl(writer); + if (count < 0) + return -1; + sum += count; + count = xmlOutputBufferWriteString(writer->out, ">"); + if (count < 0) + return -1; + sum += count; + if (writer->indent) + count = + xmlOutputBufferWriteString(writer->out, "\n"); + p->state = XML_TEXTWRITER_TEXT; + break; + default: + break; + } + } + } + + p = (xmlTextWriterStackEntry *) + xmlMalloc(sizeof(xmlTextWriterStackEntry)); + if (p == 0) { + xmlWriterErrMsg(writer, XML_ERR_NO_MEMORY, + "xmlTextWriterStartElement : out of memory!\n"); + return -1; + } + + p->name = xmlStrdup(name); + if (p->name == 0) { + xmlWriterErrMsg(writer, XML_ERR_NO_MEMORY, + "xmlTextWriterStartElement : out of memory!\n"); + xmlFree(p); + return -1; + } + p->state = XML_TEXTWRITER_NAME; + + xmlListPushFront(writer->nodes, p); + + if (writer->indent) { + count = xmlTextWriterWriteIndent(writer); + sum += count; + } + + count = xmlOutputBufferWriteString(writer->out, "<"); + if (count < 0) + return -1; + sum += count; + count = + xmlOutputBufferWriteString(writer->out, (const char *) p->name); + if (count < 0) + return -1; + sum += count; + + return sum; +} + +/** + * xmlTextWriterStartElementNS: + * @writer: the xmlTextWriterPtr + * @prefix: namespace prefix or NULL + * @name: element local name + * @namespaceURI: namespace URI or NULL + * + * Start an xml element with namespace support. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterStartElementNS(xmlTextWriterPtr writer, + const xmlChar * prefix, const xmlChar * name, + const xmlChar * namespaceURI) +{ + int count; + int sum; + xmlChar *buf; + + if ((writer == NULL) || (name == NULL) || (*name == '\0')) + return -1; + + buf = NULL; + if (prefix != 0) { + buf = xmlStrdup(prefix); + buf = xmlStrcat(buf, BAD_CAST ":"); + } + buf = xmlStrcat(buf, name); + + sum = 0; + count = xmlTextWriterStartElement(writer, buf); + xmlFree(buf); + if (count < 0) + return -1; + sum += count; + + if (namespaceURI != 0) { + xmlTextWriterNsStackEntry *p = (xmlTextWriterNsStackEntry *) + xmlMalloc(sizeof(xmlTextWriterNsStackEntry)); + if (p == 0) { + xmlWriterErrMsg(writer, XML_ERR_NO_MEMORY, + "xmlTextWriterStartElementNS : out of memory!\n"); + return -1; + } + + buf = xmlStrdup(BAD_CAST "xmlns"); + if (prefix != 0) { + buf = xmlStrcat(buf, BAD_CAST ":"); + buf = xmlStrcat(buf, prefix); + } + + p->prefix = buf; + p->uri = xmlStrdup(namespaceURI); + if (p->uri == 0) { + xmlWriterErrMsg(writer, XML_ERR_NO_MEMORY, + "xmlTextWriterStartElementNS : out of memory!\n"); + xmlFree(p); + return -1; + } + p->elem = xmlListFront(writer->nodes); + + xmlListPushFront(writer->nsstack, p); + } + + return sum; +} + +/** + * xmlTextWriterEndElement: + * @writer: the xmlTextWriterPtr + * + * End the current xml element. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterEndElement(xmlTextWriterPtr writer) +{ + int count; + int sum; + xmlLinkPtr lk; + xmlTextWriterStackEntry *p; + + if (writer == NULL) + return -1; + + lk = xmlListFront(writer->nodes); + if (lk == 0) { + xmlListDelete(writer->nsstack); + writer->nsstack = NULL; + return -1; + } + + p = (xmlTextWriterStackEntry *) xmlLinkGetData(lk); + if (p == 0) { + xmlListDelete(writer->nsstack); + writer->nsstack = NULL; + return -1; + } + + sum = 0; + switch (p->state) { + case XML_TEXTWRITER_ATTRIBUTE: + count = xmlTextWriterEndAttribute(writer); + if (count < 0) { + xmlListDelete(writer->nsstack); + writer->nsstack = NULL; + return -1; + } + sum += count; + /* fallthrough */ + case XML_TEXTWRITER_NAME: + /* Output namespace declarations */ + count = xmlTextWriterOutputNSDecl(writer); + if (count < 0) + return -1; + sum += count; + + if (writer->indent) /* next element needs indent */ + writer->doindent = 1; + count = xmlOutputBufferWriteString(writer->out, "/>"); + if (count < 0) + return -1; + sum += count; + break; + case XML_TEXTWRITER_TEXT: + if ((writer->indent) && (writer->doindent)) { + count = xmlTextWriterWriteIndent(writer); + sum += count; + writer->doindent = 1; + } else + writer->doindent = 1; + count = xmlOutputBufferWriteString(writer->out, "out, + (const char *) p->name); + if (count < 0) + return -1; + sum += count; + count = xmlOutputBufferWriteString(writer->out, ">"); + if (count < 0) + return -1; + sum += count; + break; + default: + return -1; + } + + if (writer->indent) { + count = xmlOutputBufferWriteString(writer->out, "\n"); + sum += count; + } + + xmlListPopFront(writer->nodes); + return sum; +} + +/** + * xmlTextWriterFullEndElement: + * @writer: the xmlTextWriterPtr + * + * End the current xml element. Writes an end tag even if the element is empty + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterFullEndElement(xmlTextWriterPtr writer) +{ + int count; + int sum; + xmlLinkPtr lk; + xmlTextWriterStackEntry *p; + + if (writer == NULL) + return -1; + + lk = xmlListFront(writer->nodes); + if (lk == 0) + return -1; + + p = (xmlTextWriterStackEntry *) xmlLinkGetData(lk); + if (p == 0) + return -1; + + sum = 0; + switch (p->state) { + case XML_TEXTWRITER_ATTRIBUTE: + count = xmlTextWriterEndAttribute(writer); + if (count < 0) + return -1; + sum += count; + /* fallthrough */ + case XML_TEXTWRITER_NAME: + /* Output namespace declarations */ + count = xmlTextWriterOutputNSDecl(writer); + if (count < 0) + return -1; + sum += count; + + count = xmlOutputBufferWriteString(writer->out, ">"); + if (count < 0) + return -1; + sum += count; + if (writer->indent) + writer->doindent = 0; + /* fallthrough */ + case XML_TEXTWRITER_TEXT: + if ((writer->indent) && (writer->doindent)) { + count = xmlTextWriterWriteIndent(writer); + sum += count; + writer->doindent = 1; + } else + writer->doindent = 1; + count = xmlOutputBufferWriteString(writer->out, "out, + (const char *) p->name); + if (count < 0) + return -1; + sum += count; + count = xmlOutputBufferWriteString(writer->out, ">"); + if (count < 0) + return -1; + sum += count; + break; + default: + return -1; + } + + if (writer->indent) { + count = xmlOutputBufferWriteString(writer->out, "\n"); + sum += count; + } + + xmlListPopFront(writer->nodes); + return sum; +} + +/** + * xmlTextWriterWriteFormatRaw: + * @writer: the xmlTextWriterPtr + * @format: format string (see printf) + * @...: extra parameters for the format + * + * Write a formatted raw xml text. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int XMLCDECL +xmlTextWriterWriteFormatRaw(xmlTextWriterPtr writer, const char *format, + ...) +{ + int rc; + va_list ap; + + va_start(ap, format); + + rc = xmlTextWriterWriteVFormatRaw(writer, format, ap); + + va_end(ap); + return rc; +} + +/** + * xmlTextWriterWriteVFormatRaw: + * @writer: the xmlTextWriterPtr + * @format: format string (see printf) + * @argptr: pointer to the first member of the variable argument list. + * + * Write a formatted raw xml text. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterWriteVFormatRaw(xmlTextWriterPtr writer, const char *format, + va_list argptr) +{ + int rc; + xmlChar *buf; + + if (writer == NULL) + return -1; + + buf = xmlTextWriterVSprintf(format, argptr); + if (buf == NULL) + return -1; + + rc = xmlTextWriterWriteRaw(writer, buf); + + xmlFree(buf); + return rc; +} + +/** + * xmlTextWriterWriteRawLen: + * @writer: the xmlTextWriterPtr + * @content: text string + * @len: length of the text string + * + * Write an xml text. + * TODO: what about entities and special chars?? + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterWriteRawLen(xmlTextWriterPtr writer, const xmlChar * content, + int len) +{ + int count; + int sum; + xmlLinkPtr lk; + xmlTextWriterStackEntry *p; + + if (writer == NULL) { + xmlWriterErrMsg(writer, XML_ERR_INTERNAL_ERROR, + "xmlTextWriterWriteRawLen : invalid writer!\n"); + return -1; + } + + if ((content == NULL) || (len < 0)) { + xmlWriterErrMsg(writer, XML_ERR_INTERNAL_ERROR, + "xmlTextWriterWriteRawLen : invalid content!\n"); + return -1; + } + + sum = 0; + lk = xmlListFront(writer->nodes); + if (lk != 0) { + p = (xmlTextWriterStackEntry *) xmlLinkGetData(lk); + count = xmlTextWriterHandleStateDependencies(writer, p); + if (count < 0) + return -1; + sum += count; + } + + if (writer->indent) + writer->doindent = 0; + + if (content != NULL) { + count = + xmlOutputBufferWrite(writer->out, len, (const char *) content); + if (count < 0) + return -1; + sum += count; + } + + return sum; +} + +/** + * xmlTextWriterWriteRaw: + * @writer: the xmlTextWriterPtr + * @content: text string + * + * Write a raw xml text. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterWriteRaw(xmlTextWriterPtr writer, const xmlChar * content) +{ + return xmlTextWriterWriteRawLen(writer, content, xmlStrlen(content)); +} + +/** + * xmlTextWriterWriteFormatString: + * @writer: the xmlTextWriterPtr + * @format: format string (see printf) + * @...: extra parameters for the format + * + * Write a formatted xml text. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int XMLCDECL +xmlTextWriterWriteFormatString(xmlTextWriterPtr writer, const char *format, + ...) +{ + int rc; + va_list ap; + + if ((writer == NULL) || (format == NULL)) + return -1; + + va_start(ap, format); + + rc = xmlTextWriterWriteVFormatString(writer, format, ap); + + va_end(ap); + return rc; +} + +/** + * xmlTextWriterWriteVFormatString: + * @writer: the xmlTextWriterPtr + * @format: format string (see printf) + * @argptr: pointer to the first member of the variable argument list. + * + * Write a formatted xml text. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterWriteVFormatString(xmlTextWriterPtr writer, + const char *format, va_list argptr) +{ + int rc; + xmlChar *buf; + + if ((writer == NULL) || (format == NULL)) + return -1; + + buf = xmlTextWriterVSprintf(format, argptr); + if (buf == NULL) + return -1; + + rc = xmlTextWriterWriteString(writer, buf); + + xmlFree(buf); + return rc; +} + +/** + * xmlTextWriterWriteString: + * @writer: the xmlTextWriterPtr + * @content: text string + * + * Write an xml text. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterWriteString(xmlTextWriterPtr writer, const xmlChar * content) +{ + int count; + int sum; + xmlLinkPtr lk; + xmlTextWriterStackEntry *p; + xmlChar *buf; + + if ((writer == NULL) || (content == NULL)) + return -1; + + sum = 0; + buf = (xmlChar *) content; + lk = xmlListFront(writer->nodes); + if (lk != 0) { + p = (xmlTextWriterStackEntry *) xmlLinkGetData(lk); + if (p != 0) { + switch (p->state) { + case XML_TEXTWRITER_NAME: + case XML_TEXTWRITER_TEXT: +#if 0 + buf = NULL; + xmlOutputBufferWriteEscape(writer->out, content, NULL); +#endif + buf = xmlEncodeSpecialChars(NULL, content); + break; + case XML_TEXTWRITER_ATTRIBUTE: + buf = NULL; + xmlAttrSerializeTxtContent(writer->out->buffer, writer->doc, + NULL, content); + break; + default: + break; + } + } + } + + if (buf != NULL) { + count = xmlTextWriterWriteRaw(writer, buf); + + if (buf != content) /* buf was allocated by us, so free it */ + xmlFree(buf); + + if (count < 0) + return -1; + sum += count; + } + + return sum; +} + +/** + * xmlOutputBufferWriteBase64: + * @out: the xmlOutputBufferPtr + * @data: binary data + * @len: the number of bytes to encode + * + * Write base64 encoded data to an xmlOutputBuffer. + * Adapted from John Walker's base64.c (http://www.fourmilab.ch/). + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +static int +xmlOutputBufferWriteBase64(xmlOutputBufferPtr out, int len, + const unsigned char *data) +{ + static unsigned char dtable[64] = + {'A','B','C','D','E','F','G','H','I','J','K','L','M', + 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z', + 'a','b','c','d','e','f','g','h','i','j','k','l','m', + 'n','o','p','q','r','s','t','u','v','w','x','y','z', + '0','1','2','3','4','5','6','7','8','9','+','/'}; + + int i; + int linelen; + int count; + int sum; + + if ((out == NULL) || (len < 0) || (data == NULL)) + return(-1); + + linelen = 0; + sum = 0; + + i = 0; + while (1) { + unsigned char igroup[3]; + unsigned char ogroup[4]; + int c; + int n; + + igroup[0] = igroup[1] = igroup[2] = 0; + for (n = 0; n < 3 && i < len; n++, i++) { + c = data[i]; + igroup[n] = (unsigned char) c; + } + + if (n > 0) { + ogroup[0] = dtable[igroup[0] >> 2]; + ogroup[1] = dtable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)]; + ogroup[2] = + dtable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)]; + ogroup[3] = dtable[igroup[2] & 0x3F]; + + if (n < 3) { + ogroup[3] = '='; + if (n < 2) { + ogroup[2] = '='; + } + } + + if (linelen >= B64LINELEN) { + count = xmlOutputBufferWrite(out, 2, B64CRLF); + if (count == -1) + return -1; + sum += count; + linelen = 0; + } + count = xmlOutputBufferWrite(out, 4, (const char *) ogroup); + if (count == -1) + return -1; + sum += count; + + linelen += 4; + } + + if (i >= len) + break; + } + + return sum; +} + +/** + * xmlTextWriterWriteBase64: + * @writer: the xmlTextWriterPtr + * @data: binary data + * @start: the position within the data of the first byte to encode + * @len: the number of bytes to encode + * + * Write an base64 encoded xml text. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterWriteBase64(xmlTextWriterPtr writer, const char *data, + int start, int len) +{ + int count; + int sum; + xmlLinkPtr lk; + xmlTextWriterStackEntry *p; + + if ((writer == NULL) || (data == NULL) || (start < 0) || (len < 0)) + return -1; + + sum = 0; + lk = xmlListFront(writer->nodes); + if (lk != 0) { + p = (xmlTextWriterStackEntry *) xmlLinkGetData(lk); + if (p != 0) { + count = xmlTextWriterHandleStateDependencies(writer, p); + if (count < 0) + return -1; + sum += count; + } + } + + if (writer->indent) + writer->doindent = 0; + + count = + xmlOutputBufferWriteBase64(writer->out, len, + (unsigned char *) data + start); + if (count < 0) + return -1; + sum += count; + + return sum; +} + +/** + * xmlOutputBufferWriteBinHex: + * @out: the xmlOutputBufferPtr + * @data: binary data + * @len: the number of bytes to encode + * + * Write hqx encoded data to an xmlOutputBuffer. + * ::todo + * + * Returns the bytes written (may be 0 because of buffering) + * or -1 in case of error + */ +static int +xmlOutputBufferWriteBinHex(xmlOutputBufferPtr out, + int len, const unsigned char *data) +{ + int count; + int sum; + static char hex[16] = + {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; + int i; + + if ((out == NULL) || (data == NULL) || (len < 0)) { + return -1; + } + + sum = 0; + for (i = 0; i < len; i++) { + count = + xmlOutputBufferWrite(out, 1, + (const char *) &hex[data[i] >> 4]); + if (count == -1) + return -1; + sum += count; + count = + xmlOutputBufferWrite(out, 1, + (const char *) &hex[data[i] & 0xF]); + if (count == -1) + return -1; + sum += count; + } + + return sum; +} + +/** + * xmlTextWriterWriteBinHex: + * @writer: the xmlTextWriterPtr + * @data: binary data + * @start: the position within the data of the first byte to encode + * @len: the number of bytes to encode + * + * Write a BinHex encoded xml text. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterWriteBinHex(xmlTextWriterPtr writer, const char *data, + int start, int len) +{ + int count; + int sum; + xmlLinkPtr lk; + xmlTextWriterStackEntry *p; + + if ((writer == NULL) || (data == NULL) || (start < 0) || (len < 0)) + return -1; + + sum = 0; + lk = xmlListFront(writer->nodes); + if (lk != 0) { + p = (xmlTextWriterStackEntry *) xmlLinkGetData(lk); + if (p != 0) { + count = xmlTextWriterHandleStateDependencies(writer, p); + if (count < 0) + return -1; + sum += count; + } + } + + if (writer->indent) + writer->doindent = 0; + + count = + xmlOutputBufferWriteBinHex(writer->out, len, + (unsigned char *) data + start); + if (count < 0) + return -1; + sum += count; + + return sum; +} + +/** + * xmlTextWriterStartAttribute: + * @writer: the xmlTextWriterPtr + * @name: element name + * + * Start an xml attribute. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterStartAttribute(xmlTextWriterPtr writer, const xmlChar * name) +{ + int count; + int sum; + xmlLinkPtr lk; + xmlTextWriterStackEntry *p; + + if ((writer == NULL) || (name == NULL) || (*name == '\0')) + return -1; + + sum = 0; + lk = xmlListFront(writer->nodes); + if (lk == 0) + return -1; + + p = (xmlTextWriterStackEntry *) xmlLinkGetData(lk); + if (p == 0) + return -1; + + switch (p->state) { + case XML_TEXTWRITER_ATTRIBUTE: + count = xmlTextWriterEndAttribute(writer); + if (count < 0) + return -1; + sum += count; + /* fallthrough */ + case XML_TEXTWRITER_NAME: + count = xmlOutputBufferWriteString(writer->out, " "); + if (count < 0) + return -1; + sum += count; + count = + xmlOutputBufferWriteString(writer->out, + (const char *) name); + if (count < 0) + return -1; + sum += count; + count = xmlOutputBufferWriteString(writer->out, "="); + if (count < 0) + return -1; + sum += count; + count = xmlOutputBufferWrite(writer->out, 1, &writer->qchar); + if (count < 0) + return -1; + sum += count; + p->state = XML_TEXTWRITER_ATTRIBUTE; + break; + default: + return -1; + } + + return sum; +} + +/** + * xmlTextWriterStartAttributeNS: + * @writer: the xmlTextWriterPtr + * @prefix: namespace prefix or NULL + * @name: element local name + * @namespaceURI: namespace URI or NULL + * + * Start an xml attribute with namespace support. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterStartAttributeNS(xmlTextWriterPtr writer, + const xmlChar * prefix, const xmlChar * name, + const xmlChar * namespaceURI) +{ + int count; + int sum; + xmlChar *buf; + xmlTextWriterNsStackEntry *p; + + if ((writer == NULL) || (name == NULL) || (*name == '\0')) + return -1; + + /* Handle namespace first in case of error */ + if (namespaceURI != 0) { + xmlTextWriterNsStackEntry nsentry, *curns; + + buf = xmlStrdup(BAD_CAST "xmlns"); + if (prefix != 0) { + buf = xmlStrcat(buf, BAD_CAST ":"); + buf = xmlStrcat(buf, prefix); + } + + nsentry.prefix = buf; + nsentry.uri = (xmlChar *)namespaceURI; + nsentry.elem = xmlListFront(writer->nodes); + + curns = (xmlTextWriterNsStackEntry *)xmlListSearch(writer->nsstack, + (void *)&nsentry); + if ((curns != NULL)) { + xmlFree(buf); + if (xmlStrcmp(curns->uri, namespaceURI) == 0) { + /* Namespace already defined on element skip */ + buf = NULL; + } else { + /* Prefix mismatch so error out */ + return -1; + } + } + + /* Do not add namespace decl to list - it is already there */ + if (buf != NULL) { + p = (xmlTextWriterNsStackEntry *) + xmlMalloc(sizeof(xmlTextWriterNsStackEntry)); + if (p == 0) { + xmlWriterErrMsg(writer, XML_ERR_NO_MEMORY, + "xmlTextWriterStartAttributeNS : out of memory!\n"); + return -1; + } + + p->prefix = buf; + p->uri = xmlStrdup(namespaceURI); + if (p->uri == 0) { + xmlWriterErrMsg(writer, XML_ERR_NO_MEMORY, + "xmlTextWriterStartAttributeNS : out of memory!\n"); + xmlFree(p); + return -1; + } + p->elem = xmlListFront(writer->nodes); + + xmlListPushFront(writer->nsstack, p); + } + } + + buf = NULL; + if (prefix != 0) { + buf = xmlStrdup(prefix); + buf = xmlStrcat(buf, BAD_CAST ":"); + } + buf = xmlStrcat(buf, name); + + sum = 0; + count = xmlTextWriterStartAttribute(writer, buf); + xmlFree(buf); + if (count < 0) + return -1; + sum += count; + + return sum; +} + +/** + * xmlTextWriterEndAttribute: + * @writer: the xmlTextWriterPtr + * + * End the current xml element. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterEndAttribute(xmlTextWriterPtr writer) +{ + int count; + int sum; + xmlLinkPtr lk; + xmlTextWriterStackEntry *p; + + if (writer == NULL) + return -1; + + lk = xmlListFront(writer->nodes); + if (lk == 0) { + return -1; + } + + p = (xmlTextWriterStackEntry *) xmlLinkGetData(lk); + if (p == 0) { + return -1; + } + + sum = 0; + switch (p->state) { + case XML_TEXTWRITER_ATTRIBUTE: + p->state = XML_TEXTWRITER_NAME; + + count = xmlOutputBufferWrite(writer->out, 1, &writer->qchar); + if (count < 0) { + return -1; + } + sum += count; + break; + default: + return -1; + } + + return sum; +} + +/** + * xmlTextWriterWriteFormatAttribute: + * @writer: the xmlTextWriterPtr + * @name: attribute name + * @format: format string (see printf) + * @...: extra parameters for the format + * + * Write a formatted xml attribute. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int XMLCDECL +xmlTextWriterWriteFormatAttribute(xmlTextWriterPtr writer, + const xmlChar * name, const char *format, + ...) +{ + int rc; + va_list ap; + + va_start(ap, format); + + rc = xmlTextWriterWriteVFormatAttribute(writer, name, format, ap); + + va_end(ap); + return rc; +} + +/** + * xmlTextWriterWriteVFormatAttribute: + * @writer: the xmlTextWriterPtr + * @name: attribute name + * @format: format string (see printf) + * @argptr: pointer to the first member of the variable argument list. + * + * Write a formatted xml attribute. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterWriteVFormatAttribute(xmlTextWriterPtr writer, + const xmlChar * name, + const char *format, va_list argptr) +{ + int rc; + xmlChar *buf; + + if (writer == NULL) + return -1; + + buf = xmlTextWriterVSprintf(format, argptr); + if (buf == NULL) + return -1; + + rc = xmlTextWriterWriteAttribute(writer, name, buf); + + xmlFree(buf); + return rc; +} + +/** + * xmlTextWriterWriteAttribute: + * @writer: the xmlTextWriterPtr + * @name: attribute name + * @content: attribute content + * + * Write an xml attribute. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterWriteAttribute(xmlTextWriterPtr writer, const xmlChar * name, + const xmlChar * content) +{ + int count; + int sum; + + sum = 0; + count = xmlTextWriterStartAttribute(writer, name); + if (count < 0) + return -1; + sum += count; + count = xmlTextWriterWriteString(writer, content); + if (count < 0) + return -1; + sum += count; + count = xmlTextWriterEndAttribute(writer); + if (count < 0) + return -1; + sum += count; + + return sum; +} + +/** + * xmlTextWriterWriteFormatAttributeNS: + * @writer: the xmlTextWriterPtr + * @prefix: namespace prefix + * @name: attribute local name + * @namespaceURI: namespace URI + * @format: format string (see printf) + * @...: extra parameters for the format + * + * Write a formatted xml attribute.with namespace support + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int XMLCDECL +xmlTextWriterWriteFormatAttributeNS(xmlTextWriterPtr writer, + const xmlChar * prefix, + const xmlChar * name, + const xmlChar * namespaceURI, + const char *format, ...) +{ + int rc; + va_list ap; + + va_start(ap, format); + + rc = xmlTextWriterWriteVFormatAttributeNS(writer, prefix, name, + namespaceURI, format, ap); + + va_end(ap); + return rc; +} + +/** + * xmlTextWriterWriteVFormatAttributeNS: + * @writer: the xmlTextWriterPtr + * @prefix: namespace prefix + * @name: attribute local name + * @namespaceURI: namespace URI + * @format: format string (see printf) + * @argptr: pointer to the first member of the variable argument list. + * + * Write a formatted xml attribute.with namespace support + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterWriteVFormatAttributeNS(xmlTextWriterPtr writer, + const xmlChar * prefix, + const xmlChar * name, + const xmlChar * namespaceURI, + const char *format, va_list argptr) +{ + int rc; + xmlChar *buf; + + if (writer == NULL) + return -1; + + buf = xmlTextWriterVSprintf(format, argptr); + if (buf == NULL) + return -1; + + rc = xmlTextWriterWriteAttributeNS(writer, prefix, name, namespaceURI, + buf); + + xmlFree(buf); + return rc; +} + +/** + * xmlTextWriterWriteAttributeNS: + * @writer: the xmlTextWriterPtr + * @prefix: namespace prefix + * @name: attribute local name + * @namespaceURI: namespace URI + * @content: attribute content + * + * Write an xml attribute. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterWriteAttributeNS(xmlTextWriterPtr writer, + const xmlChar * prefix, const xmlChar * name, + const xmlChar * namespaceURI, + const xmlChar * content) +{ + int count; + int sum; + + if ((writer == NULL) || (name == NULL) || (*name == '\0')) + return -1; + + sum = 0; + count = xmlTextWriterStartAttributeNS(writer, prefix, name, namespaceURI); + if (count < 0) + return -1; + sum += count; + count = xmlTextWriterWriteString(writer, content); + if (count < 0) + return -1; + sum += count; + count = xmlTextWriterEndAttribute(writer); + if (count < 0) + return -1; + sum += count; + + return sum; +} + +/** + * xmlTextWriterWriteFormatElement: + * @writer: the xmlTextWriterPtr + * @name: element name + * @format: format string (see printf) + * @...: extra parameters for the format + * + * Write a formatted xml element. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int XMLCDECL +xmlTextWriterWriteFormatElement(xmlTextWriterPtr writer, + const xmlChar * name, const char *format, + ...) +{ + int rc; + va_list ap; + + va_start(ap, format); + + rc = xmlTextWriterWriteVFormatElement(writer, name, format, ap); + + va_end(ap); + return rc; +} + +/** + * xmlTextWriterWriteVFormatElement: + * @writer: the xmlTextWriterPtr + * @name: element name + * @format: format string (see printf) + * @argptr: pointer to the first member of the variable argument list. + * + * Write a formatted xml element. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterWriteVFormatElement(xmlTextWriterPtr writer, + const xmlChar * name, const char *format, + va_list argptr) +{ + int rc; + xmlChar *buf; + + if (writer == NULL) + return -1; + + buf = xmlTextWriterVSprintf(format, argptr); + if (buf == NULL) + return -1; + + rc = xmlTextWriterWriteElement(writer, name, buf); + + xmlFree(buf); + return rc; +} + +/** + * xmlTextWriterWriteElement: + * @writer: the xmlTextWriterPtr + * @name: element name + * @content: element content + * + * Write an xml element. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterWriteElement(xmlTextWriterPtr writer, const xmlChar * name, + const xmlChar * content) +{ + int count; + int sum; + + sum = 0; + count = xmlTextWriterStartElement(writer, name); + if (count == -1) + return -1; + sum += count; + count = xmlTextWriterWriteString(writer, content); + if (count == -1) + return -1; + sum += count; + count = xmlTextWriterEndElement(writer); + if (count == -1) + return -1; + sum += count; + + return sum; +} + +/** + * xmlTextWriterWriteFormatElementNS: + * @writer: the xmlTextWriterPtr + * @prefix: namespace prefix + * @name: element local name + * @namespaceURI: namespace URI + * @format: format string (see printf) + * @...: extra parameters for the format + * + * Write a formatted xml element with namespace support. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int XMLCDECL +xmlTextWriterWriteFormatElementNS(xmlTextWriterPtr writer, + const xmlChar * prefix, + const xmlChar * name, + const xmlChar * namespaceURI, + const char *format, ...) +{ + int rc; + va_list ap; + + va_start(ap, format); + + rc = xmlTextWriterWriteVFormatElementNS(writer, prefix, name, + namespaceURI, format, ap); + + va_end(ap); + return rc; +} + +/** + * xmlTextWriterWriteVFormatElementNS: + * @writer: the xmlTextWriterPtr + * @prefix: namespace prefix + * @name: element local name + * @namespaceURI: namespace URI + * @format: format string (see printf) + * @argptr: pointer to the first member of the variable argument list. + * + * Write a formatted xml element with namespace support. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterWriteVFormatElementNS(xmlTextWriterPtr writer, + const xmlChar * prefix, + const xmlChar * name, + const xmlChar * namespaceURI, + const char *format, va_list argptr) +{ + int rc; + xmlChar *buf; + + if (writer == NULL) + return -1; + + buf = xmlTextWriterVSprintf(format, argptr); + if (buf == NULL) + return -1; + + rc = xmlTextWriterWriteElementNS(writer, prefix, name, namespaceURI, + buf); + + xmlFree(buf); + return rc; +} + +/** + * xmlTextWriterWriteElementNS: + * @writer: the xmlTextWriterPtr + * @prefix: namespace prefix + * @name: element local name + * @namespaceURI: namespace URI + * @content: element content + * + * Write an xml element with namespace support. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterWriteElementNS(xmlTextWriterPtr writer, + const xmlChar * prefix, const xmlChar * name, + const xmlChar * namespaceURI, + const xmlChar * content) +{ + int count; + int sum; + + if ((writer == NULL) || (name == NULL) || (*name == '\0')) + return -1; + + sum = 0; + count = + xmlTextWriterStartElementNS(writer, prefix, name, namespaceURI); + if (count < 0) + return -1; + sum += count; + count = xmlTextWriterWriteString(writer, content); + if (count == -1) + return -1; + sum += count; + count = xmlTextWriterEndElement(writer); + if (count == -1) + return -1; + sum += count; + + return sum; +} + +/** + * xmlTextWriterStartPI: + * @writer: the xmlTextWriterPtr + * @target: PI target + * + * Start an xml PI. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterStartPI(xmlTextWriterPtr writer, const xmlChar * target) +{ + int count; + int sum; + xmlLinkPtr lk; + xmlTextWriterStackEntry *p; + + if ((writer == NULL) || (target == NULL) || (*target == '\0')) + return -1; + + if (xmlStrcasecmp(target, (const xmlChar *) "xml") == 0) { + xmlWriterErrMsg(writer, XML_ERR_INTERNAL_ERROR, + "xmlTextWriterStartPI : target name [Xx][Mm][Ll] is reserved for xml standardization!\n"); + return -1; + } + + sum = 0; + lk = xmlListFront(writer->nodes); + if (lk != 0) { + p = (xmlTextWriterStackEntry *) xmlLinkGetData(lk); + if (p != 0) { + switch (p->state) { + case XML_TEXTWRITER_ATTRIBUTE: + count = xmlTextWriterEndAttribute(writer); + if (count < 0) + return -1; + sum += count; + /* fallthrough */ + case XML_TEXTWRITER_NAME: + /* Output namespace declarations */ + count = xmlTextWriterOutputNSDecl(writer); + if (count < 0) + return -1; + sum += count; + count = xmlOutputBufferWriteString(writer->out, ">"); + if (count < 0) + return -1; + sum += count; + p->state = XML_TEXTWRITER_TEXT; + break; + case XML_TEXTWRITER_NONE: + case XML_TEXTWRITER_TEXT: + case XML_TEXTWRITER_DTD: + break; + case XML_TEXTWRITER_PI: + case XML_TEXTWRITER_PI_TEXT: + xmlWriterErrMsg(writer, XML_ERR_INTERNAL_ERROR, + "xmlTextWriterStartPI : nested PI!\n"); + return -1; + default: + return -1; + } + } + } + + p = (xmlTextWriterStackEntry *) + xmlMalloc(sizeof(xmlTextWriterStackEntry)); + if (p == 0) { + xmlWriterErrMsg(writer, XML_ERR_NO_MEMORY, + "xmlTextWriterStartPI : out of memory!\n"); + return -1; + } + + p->name = xmlStrdup(target); + if (p->name == 0) { + xmlWriterErrMsg(writer, XML_ERR_NO_MEMORY, + "xmlTextWriterStartPI : out of memory!\n"); + xmlFree(p); + return -1; + } + p->state = XML_TEXTWRITER_PI; + + xmlListPushFront(writer->nodes, p); + + count = xmlOutputBufferWriteString(writer->out, "out, (const char *) p->name); + if (count < 0) + return -1; + sum += count; + + return sum; +} + +/** + * xmlTextWriterEndPI: + * @writer: the xmlTextWriterPtr + * + * End the current xml PI. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterEndPI(xmlTextWriterPtr writer) +{ + int count; + int sum; + xmlLinkPtr lk; + xmlTextWriterStackEntry *p; + + if (writer == NULL) + return -1; + + lk = xmlListFront(writer->nodes); + if (lk == 0) + return 0; + + p = (xmlTextWriterStackEntry *) xmlLinkGetData(lk); + if (p == 0) + return 0; + + sum = 0; + switch (p->state) { + case XML_TEXTWRITER_PI: + case XML_TEXTWRITER_PI_TEXT: + count = xmlOutputBufferWriteString(writer->out, "?>"); + if (count < 0) + return -1; + sum += count; + break; + default: + return -1; + } + + if (writer->indent) { + count = xmlOutputBufferWriteString(writer->out, "\n"); + if (count < 0) + return -1; + sum += count; + } + + xmlListPopFront(writer->nodes); + return sum; +} + +/** + * xmlTextWriterWriteFormatPI: + * @writer: the xmlTextWriterPtr + * @target: PI target + * @format: format string (see printf) + * @...: extra parameters for the format + * + * Write a formatted PI. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int XMLCDECL +xmlTextWriterWriteFormatPI(xmlTextWriterPtr writer, const xmlChar * target, + const char *format, ...) +{ + int rc; + va_list ap; + + va_start(ap, format); + + rc = xmlTextWriterWriteVFormatPI(writer, target, format, ap); + + va_end(ap); + return rc; +} + +/** + * xmlTextWriterWriteVFormatPI: + * @writer: the xmlTextWriterPtr + * @target: PI target + * @format: format string (see printf) + * @argptr: pointer to the first member of the variable argument list. + * + * Write a formatted xml PI. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterWriteVFormatPI(xmlTextWriterPtr writer, + const xmlChar * target, const char *format, + va_list argptr) +{ + int rc; + xmlChar *buf; + + if (writer == NULL) + return -1; + + buf = xmlTextWriterVSprintf(format, argptr); + if (buf == NULL) + return -1; + + rc = xmlTextWriterWritePI(writer, target, buf); + + xmlFree(buf); + return rc; +} + +/** + * xmlTextWriterWritePI: + * @writer: the xmlTextWriterPtr + * @target: PI target + * @content: PI content + * + * Write an xml PI. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterWritePI(xmlTextWriterPtr writer, const xmlChar * target, + const xmlChar * content) +{ + int count; + int sum; + + sum = 0; + count = xmlTextWriterStartPI(writer, target); + if (count == -1) + return -1; + sum += count; + if (content != 0) { + count = xmlTextWriterWriteString(writer, content); + if (count == -1) + return -1; + sum += count; + } + count = xmlTextWriterEndPI(writer); + if (count == -1) + return -1; + sum += count; + + return sum; +} + +/** + * xmlTextWriterStartCDATA: + * @writer: the xmlTextWriterPtr + * + * Start an xml CDATA section. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterStartCDATA(xmlTextWriterPtr writer) +{ + int count; + int sum; + xmlLinkPtr lk; + xmlTextWriterStackEntry *p; + + if (writer == NULL) + return -1; + + sum = 0; + lk = xmlListFront(writer->nodes); + if (lk != 0) { + p = (xmlTextWriterStackEntry *) xmlLinkGetData(lk); + if (p != 0) { + switch (p->state) { + case XML_TEXTWRITER_NONE: + case XML_TEXTWRITER_TEXT: + case XML_TEXTWRITER_PI: + case XML_TEXTWRITER_PI_TEXT: + break; + case XML_TEXTWRITER_ATTRIBUTE: + count = xmlTextWriterEndAttribute(writer); + if (count < 0) + return -1; + sum += count; + /* fallthrough */ + case XML_TEXTWRITER_NAME: + /* Output namespace declarations */ + count = xmlTextWriterOutputNSDecl(writer); + if (count < 0) + return -1; + sum += count; + count = xmlOutputBufferWriteString(writer->out, ">"); + if (count < 0) + return -1; + sum += count; + p->state = XML_TEXTWRITER_TEXT; + break; + case XML_TEXTWRITER_CDATA: + xmlWriterErrMsg(writer, XML_ERR_INTERNAL_ERROR, + "xmlTextWriterStartCDATA : CDATA not allowed in this context!\n"); + return -1; + default: + return -1; + } + } + } + + p = (xmlTextWriterStackEntry *) + xmlMalloc(sizeof(xmlTextWriterStackEntry)); + if (p == 0) { + xmlWriterErrMsg(writer, XML_ERR_NO_MEMORY, + "xmlTextWriterStartCDATA : out of memory!\n"); + return -1; + } + + p->name = NULL; + p->state = XML_TEXTWRITER_CDATA; + + xmlListPushFront(writer->nodes, p); + + count = xmlOutputBufferWriteString(writer->out, "nodes); + if (lk == 0) + return -1; + + p = (xmlTextWriterStackEntry *) xmlLinkGetData(lk); + if (p == 0) + return -1; + + sum = 0; + switch (p->state) { + case XML_TEXTWRITER_CDATA: + count = xmlOutputBufferWriteString(writer->out, "]]>"); + if (count < 0) + return -1; + sum += count; + break; + default: + return -1; + } + + xmlListPopFront(writer->nodes); + return sum; +} + +/** + * xmlTextWriterWriteFormatCDATA: + * @writer: the xmlTextWriterPtr + * @format: format string (see printf) + * @...: extra parameters for the format + * + * Write a formatted xml CDATA. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int XMLCDECL +xmlTextWriterWriteFormatCDATA(xmlTextWriterPtr writer, const char *format, + ...) +{ + int rc; + va_list ap; + + va_start(ap, format); + + rc = xmlTextWriterWriteVFormatCDATA(writer, format, ap); + + va_end(ap); + return rc; +} + +/** + * xmlTextWriterWriteVFormatCDATA: + * @writer: the xmlTextWriterPtr + * @format: format string (see printf) + * @argptr: pointer to the first member of the variable argument list. + * + * Write a formatted xml CDATA. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterWriteVFormatCDATA(xmlTextWriterPtr writer, const char *format, + va_list argptr) +{ + int rc; + xmlChar *buf; + + if (writer == NULL) + return -1; + + buf = xmlTextWriterVSprintf(format, argptr); + if (buf == NULL) + return -1; + + rc = xmlTextWriterWriteCDATA(writer, buf); + + xmlFree(buf); + return rc; +} + +/** + * xmlTextWriterWriteCDATA: + * @writer: the xmlTextWriterPtr + * @content: CDATA content + * + * Write an xml CDATA. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterWriteCDATA(xmlTextWriterPtr writer, const xmlChar * content) +{ + int count; + int sum; + + sum = 0; + count = xmlTextWriterStartCDATA(writer); + if (count == -1) + return -1; + sum += count; + if (content != 0) { + count = xmlTextWriterWriteString(writer, content); + if (count == -1) + return -1; + sum += count; + } + count = xmlTextWriterEndCDATA(writer); + if (count == -1) + return -1; + sum += count; + + return sum; +} + +/** + * xmlTextWriterStartDTD: + * @writer: the xmlTextWriterPtr + * @name: the name of the DTD + * @pubid: the public identifier, which is an alternative to the system identifier + * @sysid: the system identifier, which is the URI of the DTD + * + * Start an xml DTD. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterStartDTD(xmlTextWriterPtr writer, + const xmlChar * name, + const xmlChar * pubid, const xmlChar * sysid) +{ + int count; + int sum; + xmlLinkPtr lk; + xmlTextWriterStackEntry *p; + + if (writer == NULL || name == NULL || *name == '\0') + return -1; + + sum = 0; + lk = xmlListFront(writer->nodes); + if ((lk != NULL) && (xmlLinkGetData(lk) != NULL)) { + xmlWriterErrMsg(writer, XML_ERR_INTERNAL_ERROR, + "xmlTextWriterStartDTD : DTD allowed only in prolog!\n"); + return -1; + } + + p = (xmlTextWriterStackEntry *) + xmlMalloc(sizeof(xmlTextWriterStackEntry)); + if (p == 0) { + xmlWriterErrMsg(writer, XML_ERR_NO_MEMORY, + "xmlTextWriterStartDTD : out of memory!\n"); + return -1; + } + + p->name = xmlStrdup(name); + if (p->name == 0) { + xmlWriterErrMsg(writer, XML_ERR_NO_MEMORY, + "xmlTextWriterStartDTD : out of memory!\n"); + xmlFree(p); + return -1; + } + p->state = XML_TEXTWRITER_DTD; + + xmlListPushFront(writer->nodes, p); + + count = xmlOutputBufferWriteString(writer->out, "out, (const char *) name); + if (count < 0) + return -1; + sum += count; + + if (pubid != 0) { + if (sysid == 0) { + xmlWriterErrMsg(writer, XML_ERR_INTERNAL_ERROR, + "xmlTextWriterStartDTD : system identifier needed!\n"); + return -1; + } + + if (writer->indent) + count = xmlOutputBufferWrite(writer->out, 1, "\n"); + else + count = xmlOutputBufferWrite(writer->out, 1, " "); + if (count < 0) + return -1; + sum += count; + + count = xmlOutputBufferWriteString(writer->out, "PUBLIC "); + if (count < 0) + return -1; + sum += count; + + count = xmlOutputBufferWrite(writer->out, 1, &writer->qchar); + if (count < 0) + return -1; + sum += count; + + count = + xmlOutputBufferWriteString(writer->out, (const char *) pubid); + if (count < 0) + return -1; + sum += count; + + count = xmlOutputBufferWrite(writer->out, 1, &writer->qchar); + if (count < 0) + return -1; + sum += count; + } + + if (sysid != 0) { + if (pubid == 0) { + if (writer->indent) + count = xmlOutputBufferWrite(writer->out, 1, "\n"); + else + count = xmlOutputBufferWrite(writer->out, 1, " "); + if (count < 0) + return -1; + sum += count; + count = xmlOutputBufferWriteString(writer->out, "SYSTEM "); + if (count < 0) + return -1; + sum += count; + } else { + if (writer->indent) + count = xmlOutputBufferWriteString(writer->out, "\n "); + else + count = xmlOutputBufferWrite(writer->out, 1, " "); + if (count < 0) + return -1; + sum += count; + } + + count = xmlOutputBufferWrite(writer->out, 1, &writer->qchar); + if (count < 0) + return -1; + sum += count; + + count = + xmlOutputBufferWriteString(writer->out, (const char *) sysid); + if (count < 0) + return -1; + sum += count; + + count = xmlOutputBufferWrite(writer->out, 1, &writer->qchar); + if (count < 0) + return -1; + sum += count; + } + + return sum; +} + +/** + * xmlTextWriterEndDTD: + * @writer: the xmlTextWriterPtr + * + * End an xml DTD. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterEndDTD(xmlTextWriterPtr writer) +{ + int loop; + int count; + int sum; + xmlLinkPtr lk; + xmlTextWriterStackEntry *p; + + if (writer == NULL) + return -1; + + sum = 0; + loop = 1; + while (loop) { + lk = xmlListFront(writer->nodes); + if (lk == NULL) + break; + p = (xmlTextWriterStackEntry *) xmlLinkGetData(lk); + if (p == 0) + break; + switch (p->state) { + case XML_TEXTWRITER_DTD_TEXT: + count = xmlOutputBufferWriteString(writer->out, "]"); + if (count < 0) + return -1; + sum += count; + /* fallthrough */ + case XML_TEXTWRITER_DTD: + count = xmlOutputBufferWriteString(writer->out, ">"); + + if (writer->indent) { + if (count < 0) + return -1; + sum += count; + count = xmlOutputBufferWriteString(writer->out, "\n"); + } + + xmlListPopFront(writer->nodes); + break; + case XML_TEXTWRITER_DTD_ELEM: + case XML_TEXTWRITER_DTD_ELEM_TEXT: + count = xmlTextWriterEndDTDElement(writer); + break; + case XML_TEXTWRITER_DTD_ATTL: + case XML_TEXTWRITER_DTD_ATTL_TEXT: + count = xmlTextWriterEndDTDAttlist(writer); + break; + case XML_TEXTWRITER_DTD_ENTY: + case XML_TEXTWRITER_DTD_PENT: + case XML_TEXTWRITER_DTD_ENTY_TEXT: + count = xmlTextWriterEndDTDEntity(writer); + break; + case XML_TEXTWRITER_COMMENT: + count = xmlTextWriterEndComment(writer); + break; + default: + loop = 0; + continue; + } + + if (count < 0) + return -1; + sum += count; + } + + return sum; +} + +/** + * xmlTextWriterWriteFormatDTD: + * @writer: the xmlTextWriterPtr + * @name: the name of the DTD + * @pubid: the public identifier, which is an alternative to the system identifier + * @sysid: the system identifier, which is the URI of the DTD + * @format: format string (see printf) + * @...: extra parameters for the format + * + * Write a DTD with a formatted markup declarations part. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int XMLCDECL +xmlTextWriterWriteFormatDTD(xmlTextWriterPtr writer, + const xmlChar * name, + const xmlChar * pubid, + const xmlChar * sysid, const char *format, ...) +{ + int rc; + va_list ap; + + va_start(ap, format); + + rc = xmlTextWriterWriteVFormatDTD(writer, name, pubid, sysid, format, + ap); + + va_end(ap); + return rc; +} + +/** + * xmlTextWriterWriteVFormatDTD: + * @writer: the xmlTextWriterPtr + * @name: the name of the DTD + * @pubid: the public identifier, which is an alternative to the system identifier + * @sysid: the system identifier, which is the URI of the DTD + * @format: format string (see printf) + * @argptr: pointer to the first member of the variable argument list. + * + * Write a DTD with a formatted markup declarations part. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterWriteVFormatDTD(xmlTextWriterPtr writer, + const xmlChar * name, + const xmlChar * pubid, + const xmlChar * sysid, + const char *format, va_list argptr) +{ + int rc; + xmlChar *buf; + + if (writer == NULL) + return -1; + + buf = xmlTextWriterVSprintf(format, argptr); + if (buf == NULL) + return -1; + + rc = xmlTextWriterWriteDTD(writer, name, pubid, sysid, buf); + + xmlFree(buf); + return rc; +} + +/** + * xmlTextWriterWriteDTD: + * @writer: the xmlTextWriterPtr + * @name: the name of the DTD + * @pubid: the public identifier, which is an alternative to the system identifier + * @sysid: the system identifier, which is the URI of the DTD + * @subset: string content of the DTD + * + * Write a DTD. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterWriteDTD(xmlTextWriterPtr writer, + const xmlChar * name, + const xmlChar * pubid, + const xmlChar * sysid, const xmlChar * subset) +{ + int count; + int sum; + + sum = 0; + count = xmlTextWriterStartDTD(writer, name, pubid, sysid); + if (count == -1) + return -1; + sum += count; + if (subset != 0) { + count = xmlTextWriterWriteString(writer, subset); + if (count == -1) + return -1; + sum += count; + } + count = xmlTextWriterEndDTD(writer); + if (count == -1) + return -1; + sum += count; + + return sum; +} + +/** + * xmlTextWriterStartDTDElement: + * @writer: the xmlTextWriterPtr + * @name: the name of the DTD element + * + * Start an xml DTD element. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterStartDTDElement(xmlTextWriterPtr writer, const xmlChar * name) +{ + int count; + int sum; + xmlLinkPtr lk; + xmlTextWriterStackEntry *p; + + if (writer == NULL || name == NULL || *name == '\0') + return -1; + + sum = 0; + lk = xmlListFront(writer->nodes); + if (lk == 0) { + return -1; + } + + p = (xmlTextWriterStackEntry *) xmlLinkGetData(lk); + if (p != 0) { + switch (p->state) { + case XML_TEXTWRITER_DTD: + count = xmlOutputBufferWriteString(writer->out, " ["); + if (count < 0) + return -1; + sum += count; + if (writer->indent) { + count = xmlOutputBufferWriteString(writer->out, "\n"); + if (count < 0) + return -1; + sum += count; + } + p->state = XML_TEXTWRITER_DTD_TEXT; + /* fallthrough */ + case XML_TEXTWRITER_DTD_TEXT: + case XML_TEXTWRITER_NONE: + break; + default: + return -1; + } + } + + p = (xmlTextWriterStackEntry *) + xmlMalloc(sizeof(xmlTextWriterStackEntry)); + if (p == 0) { + xmlWriterErrMsg(writer, XML_ERR_NO_MEMORY, + "xmlTextWriterStartDTDElement : out of memory!\n"); + return -1; + } + + p->name = xmlStrdup(name); + if (p->name == 0) { + xmlWriterErrMsg(writer, XML_ERR_NO_MEMORY, + "xmlTextWriterStartDTDElement : out of memory!\n"); + xmlFree(p); + return -1; + } + p->state = XML_TEXTWRITER_DTD_ELEM; + + xmlListPushFront(writer->nodes, p); + + if (writer->indent) { + count = xmlTextWriterWriteIndent(writer); + if (count < 0) + return -1; + sum += count; + } + + count = xmlOutputBufferWriteString(writer->out, "out, (const char *) name); + if (count < 0) + return -1; + sum += count; + + return sum; +} + +/** + * xmlTextWriterEndDTDElement: + * @writer: the xmlTextWriterPtr + * + * End an xml DTD element. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterEndDTDElement(xmlTextWriterPtr writer) +{ + int count; + int sum; + xmlLinkPtr lk; + xmlTextWriterStackEntry *p; + + if (writer == NULL) + return -1; + + sum = 0; + lk = xmlListFront(writer->nodes); + if (lk == 0) + return -1; + + p = (xmlTextWriterStackEntry *) xmlLinkGetData(lk); + if (p == 0) + return -1; + + switch (p->state) { + case XML_TEXTWRITER_DTD_ELEM: + case XML_TEXTWRITER_DTD_ELEM_TEXT: + count = xmlOutputBufferWriteString(writer->out, ">"); + if (count < 0) + return -1; + sum += count; + break; + default: + return -1; + } + + if (writer->indent) { + count = xmlOutputBufferWriteString(writer->out, "\n"); + if (count < 0) + return -1; + sum += count; + } + + xmlListPopFront(writer->nodes); + return sum; +} + +/** + * xmlTextWriterWriteFormatDTDElement: + * @writer: the xmlTextWriterPtr + * @name: the name of the DTD element + * @format: format string (see printf) + * @...: extra parameters for the format + * + * Write a formatted DTD element. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int XMLCDECL +xmlTextWriterWriteFormatDTDElement(xmlTextWriterPtr writer, + const xmlChar * name, + const char *format, ...) +{ + int rc; + va_list ap; + + va_start(ap, format); + + rc = xmlTextWriterWriteVFormatDTDElement(writer, name, format, ap); + + va_end(ap); + return rc; +} + +/** + * xmlTextWriterWriteVFormatDTDElement: + * @writer: the xmlTextWriterPtr + * @name: the name of the DTD element + * @format: format string (see printf) + * @argptr: pointer to the first member of the variable argument list. + * + * Write a formatted DTD element. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterWriteVFormatDTDElement(xmlTextWriterPtr writer, + const xmlChar * name, + const char *format, va_list argptr) +{ + int rc; + xmlChar *buf; + + if (writer == NULL) + return -1; + + buf = xmlTextWriterVSprintf(format, argptr); + if (buf == NULL) + return -1; + + rc = xmlTextWriterWriteDTDElement(writer, name, buf); + + xmlFree(buf); + return rc; +} + +/** + * xmlTextWriterWriteDTDElement: + * @writer: the xmlTextWriterPtr + * @name: the name of the DTD element + * @content: content of the element + * + * Write a DTD element. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterWriteDTDElement(xmlTextWriterPtr writer, + const xmlChar * name, const xmlChar * content) +{ + int count; + int sum; + + if (content == NULL) + return -1; + + sum = 0; + count = xmlTextWriterStartDTDElement(writer, name); + if (count == -1) + return -1; + sum += count; + + count = xmlTextWriterWriteString(writer, content); + if (count == -1) + return -1; + sum += count; + + count = xmlTextWriterEndDTDElement(writer); + if (count == -1) + return -1; + sum += count; + + return sum; +} + +/** + * xmlTextWriterStartDTDAttlist: + * @writer: the xmlTextWriterPtr + * @name: the name of the DTD ATTLIST + * + * Start an xml DTD ATTLIST. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterStartDTDAttlist(xmlTextWriterPtr writer, const xmlChar * name) +{ + int count; + int sum; + xmlLinkPtr lk; + xmlTextWriterStackEntry *p; + + if (writer == NULL || name == NULL || *name == '\0') + return -1; + + sum = 0; + lk = xmlListFront(writer->nodes); + if (lk == 0) { + return -1; + } + + p = (xmlTextWriterStackEntry *) xmlLinkGetData(lk); + if (p != 0) { + switch (p->state) { + case XML_TEXTWRITER_DTD: + count = xmlOutputBufferWriteString(writer->out, " ["); + if (count < 0) + return -1; + sum += count; + if (writer->indent) { + count = xmlOutputBufferWriteString(writer->out, "\n"); + if (count < 0) + return -1; + sum += count; + } + p->state = XML_TEXTWRITER_DTD_TEXT; + /* fallthrough */ + case XML_TEXTWRITER_DTD_TEXT: + case XML_TEXTWRITER_NONE: + break; + default: + return -1; + } + } + + p = (xmlTextWriterStackEntry *) + xmlMalloc(sizeof(xmlTextWriterStackEntry)); + if (p == 0) { + xmlWriterErrMsg(writer, XML_ERR_NO_MEMORY, + "xmlTextWriterStartDTDAttlist : out of memory!\n"); + return -1; + } + + p->name = xmlStrdup(name); + if (p->name == 0) { + xmlWriterErrMsg(writer, XML_ERR_NO_MEMORY, + "xmlTextWriterStartDTDAttlist : out of memory!\n"); + xmlFree(p); + return -1; + } + p->state = XML_TEXTWRITER_DTD_ATTL; + + xmlListPushFront(writer->nodes, p); + + if (writer->indent) { + count = xmlTextWriterWriteIndent(writer); + if (count < 0) + return -1; + sum += count; + } + + count = xmlOutputBufferWriteString(writer->out, "out, (const char *) name); + if (count < 0) + return -1; + sum += count; + + return sum; +} + +/** + * xmlTextWriterEndDTDAttlist: + * @writer: the xmlTextWriterPtr + * + * End an xml DTD attribute list. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterEndDTDAttlist(xmlTextWriterPtr writer) +{ + int count; + int sum; + xmlLinkPtr lk; + xmlTextWriterStackEntry *p; + + if (writer == NULL) + return -1; + + sum = 0; + lk = xmlListFront(writer->nodes); + if (lk == 0) + return -1; + + p = (xmlTextWriterStackEntry *) xmlLinkGetData(lk); + if (p == 0) + return -1; + + switch (p->state) { + case XML_TEXTWRITER_DTD_ATTL: + case XML_TEXTWRITER_DTD_ATTL_TEXT: + count = xmlOutputBufferWriteString(writer->out, ">"); + if (count < 0) + return -1; + sum += count; + break; + default: + return -1; + } + + if (writer->indent) { + count = xmlOutputBufferWriteString(writer->out, "\n"); + if (count < 0) + return -1; + sum += count; + } + + xmlListPopFront(writer->nodes); + return sum; +} + +/** + * xmlTextWriterWriteFormatDTDAttlist: + * @writer: the xmlTextWriterPtr + * @name: the name of the DTD ATTLIST + * @format: format string (see printf) + * @...: extra parameters for the format + * + * Write a formatted DTD ATTLIST. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int XMLCDECL +xmlTextWriterWriteFormatDTDAttlist(xmlTextWriterPtr writer, + const xmlChar * name, + const char *format, ...) +{ + int rc; + va_list ap; + + va_start(ap, format); + + rc = xmlTextWriterWriteVFormatDTDAttlist(writer, name, format, ap); + + va_end(ap); + return rc; +} + +/** + * xmlTextWriterWriteVFormatDTDAttlist: + * @writer: the xmlTextWriterPtr + * @name: the name of the DTD ATTLIST + * @format: format string (see printf) + * @argptr: pointer to the first member of the variable argument list. + * + * Write a formatted DTD ATTLIST. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterWriteVFormatDTDAttlist(xmlTextWriterPtr writer, + const xmlChar * name, + const char *format, va_list argptr) +{ + int rc; + xmlChar *buf; + + if (writer == NULL) + return -1; + + buf = xmlTextWriterVSprintf(format, argptr); + if (buf == NULL) + return -1; + + rc = xmlTextWriterWriteDTDAttlist(writer, name, buf); + + xmlFree(buf); + return rc; +} + +/** + * xmlTextWriterWriteDTDAttlist: + * @writer: the xmlTextWriterPtr + * @name: the name of the DTD ATTLIST + * @content: content of the ATTLIST + * + * Write a DTD ATTLIST. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterWriteDTDAttlist(xmlTextWriterPtr writer, + const xmlChar * name, const xmlChar * content) +{ + int count; + int sum; + + if (content == NULL) + return -1; + + sum = 0; + count = xmlTextWriterStartDTDAttlist(writer, name); + if (count == -1) + return -1; + sum += count; + + count = xmlTextWriterWriteString(writer, content); + if (count == -1) + return -1; + sum += count; + + count = xmlTextWriterEndDTDAttlist(writer); + if (count == -1) + return -1; + sum += count; + + return sum; +} + +/** + * xmlTextWriterStartDTDEntity: + * @writer: the xmlTextWriterPtr + * @pe: TRUE if this is a parameter entity, FALSE if not + * @name: the name of the DTD ATTLIST + * + * Start an xml DTD ATTLIST. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterStartDTDEntity(xmlTextWriterPtr writer, + int pe, const xmlChar * name) +{ + int count; + int sum; + xmlLinkPtr lk; + xmlTextWriterStackEntry *p; + + if (writer == NULL || name == NULL || *name == '\0') + return -1; + + sum = 0; + lk = xmlListFront(writer->nodes); + if (lk != 0) { + + p = (xmlTextWriterStackEntry *) xmlLinkGetData(lk); + if (p != 0) { + switch (p->state) { + case XML_TEXTWRITER_DTD: + count = xmlOutputBufferWriteString(writer->out, " ["); + if (count < 0) + return -1; + sum += count; + if (writer->indent) { + count = + xmlOutputBufferWriteString(writer->out, "\n"); + if (count < 0) + return -1; + sum += count; + } + p->state = XML_TEXTWRITER_DTD_TEXT; + /* fallthrough */ + case XML_TEXTWRITER_DTD_TEXT: + case XML_TEXTWRITER_NONE: + break; + default: + return -1; + } + } + } + + p = (xmlTextWriterStackEntry *) + xmlMalloc(sizeof(xmlTextWriterStackEntry)); + if (p == 0) { + xmlWriterErrMsg(writer, XML_ERR_NO_MEMORY, + "xmlTextWriterStartDTDElement : out of memory!\n"); + return -1; + } + + p->name = xmlStrdup(name); + if (p->name == 0) { + xmlWriterErrMsg(writer, XML_ERR_NO_MEMORY, + "xmlTextWriterStartDTDElement : out of memory!\n"); + xmlFree(p); + return -1; + } + + if (pe != 0) + p->state = XML_TEXTWRITER_DTD_PENT; + else + p->state = XML_TEXTWRITER_DTD_ENTY; + + xmlListPushFront(writer->nodes, p); + + if (writer->indent) { + count = xmlTextWriterWriteIndent(writer); + if (count < 0) + return -1; + sum += count; + } + + count = xmlOutputBufferWriteString(writer->out, "out, "% "); + if (count < 0) + return -1; + sum += count; + } + + count = xmlOutputBufferWriteString(writer->out, (const char *) name); + if (count < 0) + return -1; + sum += count; + + return sum; +} + +/** + * xmlTextWriterEndDTDEntity: + * @writer: the xmlTextWriterPtr + * + * End an xml DTD entity. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterEndDTDEntity(xmlTextWriterPtr writer) +{ + int count; + int sum; + xmlLinkPtr lk; + xmlTextWriterStackEntry *p; + + if (writer == NULL) + return -1; + + sum = 0; + lk = xmlListFront(writer->nodes); + if (lk == 0) + return -1; + + p = (xmlTextWriterStackEntry *) xmlLinkGetData(lk); + if (p == 0) + return -1; + + switch (p->state) { + case XML_TEXTWRITER_DTD_ENTY_TEXT: + count = xmlOutputBufferWrite(writer->out, 1, &writer->qchar); + if (count < 0) + return -1; + sum += count; + case XML_TEXTWRITER_DTD_ENTY: + case XML_TEXTWRITER_DTD_PENT: + count = xmlOutputBufferWriteString(writer->out, ">"); + if (count < 0) + return -1; + sum += count; + break; + default: + return -1; + } + + if (writer->indent) { + count = xmlOutputBufferWriteString(writer->out, "\n"); + if (count < 0) + return -1; + sum += count; + } + + xmlListPopFront(writer->nodes); + return sum; +} + +/** + * xmlTextWriterWriteFormatDTDInternalEntity: + * @writer: the xmlTextWriterPtr + * @pe: TRUE if this is a parameter entity, FALSE if not + * @name: the name of the DTD entity + * @format: format string (see printf) + * @...: extra parameters for the format + * + * Write a formatted DTD internal entity. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int XMLCDECL +xmlTextWriterWriteFormatDTDInternalEntity(xmlTextWriterPtr writer, + int pe, + const xmlChar * name, + const char *format, ...) +{ + int rc; + va_list ap; + + va_start(ap, format); + + rc = xmlTextWriterWriteVFormatDTDInternalEntity(writer, pe, name, + format, ap); + + va_end(ap); + return rc; +} + +/** + * xmlTextWriterWriteVFormatDTDInternalEntity: + * @writer: the xmlTextWriterPtr + * @pe: TRUE if this is a parameter entity, FALSE if not + * @name: the name of the DTD entity + * @format: format string (see printf) + * @argptr: pointer to the first member of the variable argument list. + * + * Write a formatted DTD internal entity. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterWriteVFormatDTDInternalEntity(xmlTextWriterPtr writer, + int pe, + const xmlChar * name, + const char *format, + va_list argptr) +{ + int rc; + xmlChar *buf; + + if (writer == NULL) + return -1; + + buf = xmlTextWriterVSprintf(format, argptr); + if (buf == NULL) + return -1; + + rc = xmlTextWriterWriteDTDInternalEntity(writer, pe, name, buf); + + xmlFree(buf); + return rc; +} + +/** + * xmlTextWriterWriteDTDEntity: + * @writer: the xmlTextWriterPtr + * @pe: TRUE if this is a parameter entity, FALSE if not + * @name: the name of the DTD entity + * @pubid: the public identifier, which is an alternative to the system identifier + * @sysid: the system identifier, which is the URI of the DTD + * @ndataid: the xml notation name. + * @content: content of the entity + * + * Write a DTD entity. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterWriteDTDEntity(xmlTextWriterPtr writer, + int pe, + const xmlChar * name, + const xmlChar * pubid, + const xmlChar * sysid, + const xmlChar * ndataid, + const xmlChar * content) +{ + if ((content == NULL) && (pubid == NULL) && (sysid == NULL)) + return -1; + if ((pe != 0) && (ndataid != NULL)) + return -1; + + if ((pubid == NULL) && (sysid == NULL)) + return xmlTextWriterWriteDTDInternalEntity(writer, pe, name, + content); + + return xmlTextWriterWriteDTDExternalEntity(writer, pe, name, pubid, + sysid, ndataid); +} + +/** + * xmlTextWriterWriteDTDInternalEntity: + * @writer: the xmlTextWriterPtr + * @pe: TRUE if this is a parameter entity, FALSE if not + * @name: the name of the DTD entity + * @content: content of the entity + * + * Write a DTD internal entity. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterWriteDTDInternalEntity(xmlTextWriterPtr writer, + int pe, + const xmlChar * name, + const xmlChar * content) +{ + int count; + int sum; + + if ((name == NULL) || (*name == '\0') || (content == NULL)) + return -1; + + sum = 0; + count = xmlTextWriterStartDTDEntity(writer, pe, name); + if (count == -1) + return -1; + sum += count; + + count = xmlTextWriterWriteString(writer, content); + if (count == -1) + return -1; + sum += count; + + count = xmlTextWriterEndDTDEntity(writer); + if (count == -1) + return -1; + sum += count; + + return sum; +} + +/** + * xmlTextWriterWriteDTDExternalEntity: + * @writer: the xmlTextWriterPtr + * @pe: TRUE if this is a parameter entity, FALSE if not + * @name: the name of the DTD entity + * @pubid: the public identifier, which is an alternative to the system identifier + * @sysid: the system identifier, which is the URI of the DTD + * @ndataid: the xml notation name. + * + * Write a DTD external entity. The entity must have been started with xmlTextWriterStartDTDEntity + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterWriteDTDExternalEntity(xmlTextWriterPtr writer, + int pe, + const xmlChar * name, + const xmlChar * pubid, + const xmlChar * sysid, + const xmlChar * ndataid) +{ + int count; + int sum; + + if (((pubid == NULL) && (sysid == NULL))) + return -1; + if ((pe != 0) && (ndataid != NULL)) + return -1; + + sum = 0; + count = xmlTextWriterStartDTDEntity(writer, pe, name); + if (count == -1) + return -1; + sum += count; + + count = + xmlTextWriterWriteDTDExternalEntityContents(writer, pubid, sysid, + ndataid); + if (count < 0) + return -1; + sum += count; + + count = xmlTextWriterEndDTDEntity(writer); + if (count == -1) + return -1; + sum += count; + + return sum; +} + +/** + * xmlTextWriterWriteDTDExternalEntityContents: + * @writer: the xmlTextWriterPtr + * @pubid: the public identifier, which is an alternative to the system identifier + * @sysid: the system identifier, which is the URI of the DTD + * @ndataid: the xml notation name. + * + * Write the contents of a DTD external entity. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterWriteDTDExternalEntityContents(xmlTextWriterPtr writer, + const xmlChar * pubid, + const xmlChar * sysid, + const xmlChar * ndataid) +{ + int count; + int sum; + xmlLinkPtr lk; + xmlTextWriterStackEntry *p; + + if (writer == NULL) { + xmlWriterErrMsg(writer, XML_ERR_INTERNAL_ERROR, + "xmlTextWriterWriteDTDExternalEntityContents: xmlTextWriterPtr invalid!\n"); + return -1; + } + + sum = 0; + lk = xmlListFront(writer->nodes); + if (lk == 0) { + xmlWriterErrMsg(writer, XML_ERR_INTERNAL_ERROR, + "xmlTextWriterWriteDTDExternalEntityContents: you must call xmlTextWriterStartDTDEntity before the call to this function!\n"); + return -1; + } + + p = (xmlTextWriterStackEntry *) xmlLinkGetData(lk); + if (p == 0) + return -1; + + switch (p->state) { + case XML_TEXTWRITER_DTD_ENTY: + break; + case XML_TEXTWRITER_DTD_PENT: + if (ndataid != NULL) { + xmlWriterErrMsg(writer, XML_ERR_INTERNAL_ERROR, + "xmlTextWriterWriteDTDExternalEntityContents: notation not allowed with parameter entities!\n"); + return -1; + } + break; + default: + xmlWriterErrMsg(writer, XML_ERR_INTERNAL_ERROR, + "xmlTextWriterWriteDTDExternalEntityContents: you must call xmlTextWriterStartDTDEntity before the call to this function!\n"); + return -1; + } + + if (pubid != 0) { + if (sysid == 0) { + xmlWriterErrMsg(writer, XML_ERR_INTERNAL_ERROR, + "xmlTextWriterWriteDTDExternalEntityContents: system identifier needed!\n"); + return -1; + } + + count = xmlOutputBufferWriteString(writer->out, " PUBLIC "); + if (count < 0) + return -1; + sum += count; + + count = xmlOutputBufferWrite(writer->out, 1, &writer->qchar); + if (count < 0) + return -1; + sum += count; + + count = + xmlOutputBufferWriteString(writer->out, (const char *) pubid); + if (count < 0) + return -1; + sum += count; + + count = xmlOutputBufferWrite(writer->out, 1, &writer->qchar); + if (count < 0) + return -1; + sum += count; + } + + if (sysid != 0) { + if (pubid == 0) { + count = xmlOutputBufferWriteString(writer->out, " SYSTEM"); + if (count < 0) + return -1; + sum += count; + } + + count = xmlOutputBufferWriteString(writer->out, " "); + if (count < 0) + return -1; + sum += count; + + count = xmlOutputBufferWrite(writer->out, 1, &writer->qchar); + if (count < 0) + return -1; + sum += count; + + count = + xmlOutputBufferWriteString(writer->out, (const char *) sysid); + if (count < 0) + return -1; + sum += count; + + count = xmlOutputBufferWrite(writer->out, 1, &writer->qchar); + if (count < 0) + return -1; + sum += count; + } + + if (ndataid != NULL) { + count = xmlOutputBufferWriteString(writer->out, " NDATA "); + if (count < 0) + return -1; + sum += count; + + count = + xmlOutputBufferWriteString(writer->out, + (const char *) ndataid); + if (count < 0) + return -1; + sum += count; + } + + return sum; +} + +/** + * xmlTextWriterWriteDTDNotation: + * @writer: the xmlTextWriterPtr + * @name: the name of the xml notation + * @pubid: the public identifier, which is an alternative to the system identifier + * @sysid: the system identifier, which is the URI of the DTD + * + * Write a DTD entity. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterWriteDTDNotation(xmlTextWriterPtr writer, + const xmlChar * name, + const xmlChar * pubid, const xmlChar * sysid) +{ + int count; + int sum; + xmlLinkPtr lk; + xmlTextWriterStackEntry *p; + + if (writer == NULL || name == NULL || *name == '\0') + return -1; + + sum = 0; + lk = xmlListFront(writer->nodes); + if (lk == 0) { + return -1; + } + + p = (xmlTextWriterStackEntry *) xmlLinkGetData(lk); + if (p != 0) { + switch (p->state) { + case XML_TEXTWRITER_DTD: + count = xmlOutputBufferWriteString(writer->out, " ["); + if (count < 0) + return -1; + sum += count; + if (writer->indent) { + count = xmlOutputBufferWriteString(writer->out, "\n"); + if (count < 0) + return -1; + sum += count; + } + p->state = XML_TEXTWRITER_DTD_TEXT; + /* fallthrough */ + case XML_TEXTWRITER_DTD_TEXT: + break; + default: + return -1; + } + } + + if (writer->indent) { + count = xmlTextWriterWriteIndent(writer); + if (count < 0) + return -1; + sum += count; + } + + count = xmlOutputBufferWriteString(writer->out, "out, (const char *) name); + if (count < 0) + return -1; + sum += count; + + if (pubid != 0) { + count = xmlOutputBufferWriteString(writer->out, " PUBLIC "); + if (count < 0) + return -1; + sum += count; + count = xmlOutputBufferWrite(writer->out, 1, &writer->qchar); + if (count < 0) + return -1; + sum += count; + count = + xmlOutputBufferWriteString(writer->out, (const char *) pubid); + if (count < 0) + return -1; + sum += count; + count = xmlOutputBufferWrite(writer->out, 1, &writer->qchar); + if (count < 0) + return -1; + sum += count; + } + + if (sysid != 0) { + if (pubid == 0) { + count = xmlOutputBufferWriteString(writer->out, " SYSTEM"); + if (count < 0) + return -1; + sum += count; + } + count = xmlOutputBufferWriteString(writer->out, " "); + if (count < 0) + return -1; + sum += count; + count = xmlOutputBufferWrite(writer->out, 1, &writer->qchar); + if (count < 0) + return -1; + sum += count; + count = + xmlOutputBufferWriteString(writer->out, (const char *) sysid); + if (count < 0) + return -1; + sum += count; + count = xmlOutputBufferWrite(writer->out, 1, &writer->qchar); + if (count < 0) + return -1; + sum += count; + } + + count = xmlOutputBufferWriteString(writer->out, ">"); + if (count < 0) + return -1; + sum += count; + + return sum; +} + +/** + * xmlTextWriterFlush: + * @writer: the xmlTextWriterPtr + * + * Flush the output buffer. + * + * Returns the bytes written (may be 0 because of buffering) or -1 in case of error + */ +int +xmlTextWriterFlush(xmlTextWriterPtr writer) +{ + int count; + + if (writer == NULL) + return -1; + + if (writer->out == NULL) + count = 0; + else + count = xmlOutputBufferFlush(writer->out); + + return count; +} + +/** + * misc + */ + +/** + * xmlFreeTextWriterStackEntry: + * @lk: the xmlLinkPtr + * + * Free callback for the xmlList. + */ +static void +xmlFreeTextWriterStackEntry(xmlLinkPtr lk) +{ + xmlTextWriterStackEntry *p; + + p = (xmlTextWriterStackEntry *) xmlLinkGetData(lk); + if (p == 0) + return; + + if (p->name != 0) + xmlFree(p->name); + xmlFree(p); +} + +/** + * xmlCmpTextWriterStackEntry: + * @data0: the first data + * @data1: the second data + * + * Compare callback for the xmlList. + * + * Returns -1, 0, 1 + */ +static int +xmlCmpTextWriterStackEntry(const void *data0, const void *data1) +{ + xmlTextWriterStackEntry *p0; + xmlTextWriterStackEntry *p1; + + if (data0 == data1) + return 0; + + if (data0 == 0) + return -1; + + if (data1 == 0) + return 1; + + p0 = (xmlTextWriterStackEntry *) data0; + p1 = (xmlTextWriterStackEntry *) data1; + + return xmlStrcmp(p0->name, p1->name); +} + +/** + * misc + */ + +/** + * xmlTextWriterOutputNSDecl: + * @writer: the xmlTextWriterPtr + * + * Output the current namespace declarations. + */ +static int +xmlTextWriterOutputNSDecl(xmlTextWriterPtr writer) +{ + xmlLinkPtr lk; + xmlTextWriterNsStackEntry *np; + int count; + int sum; + + sum = 0; + while (!xmlListEmpty(writer->nsstack)) { + xmlChar *namespaceURI = NULL; + xmlChar *prefix = NULL; + + lk = xmlListFront(writer->nsstack); + np = (xmlTextWriterNsStackEntry *) xmlLinkGetData(lk); + + if (np != 0) { + namespaceURI = xmlStrdup(np->uri); + prefix = xmlStrdup(np->prefix); + } + + xmlListPopFront(writer->nsstack); + + if (np != 0) { + count = xmlTextWriterWriteAttribute(writer, prefix, namespaceURI); + xmlFree(namespaceURI); + xmlFree(prefix); + + if (count < 0) { + xmlListDelete(writer->nsstack); + writer->nsstack = NULL; + return -1; + } + sum += count; + } + } + return sum; +} + +/** + * xmlFreeTextWriterNsStackEntry: + * @lk: the xmlLinkPtr + * + * Free callback for the xmlList. + */ +static void +xmlFreeTextWriterNsStackEntry(xmlLinkPtr lk) +{ + xmlTextWriterNsStackEntry *p; + + p = (xmlTextWriterNsStackEntry *) xmlLinkGetData(lk); + if (p == 0) + return; + + if (p->prefix != 0) + xmlFree(p->prefix); + if (p->uri != 0) + xmlFree(p->uri); + + xmlFree(p); +} + +/** + * xmlCmpTextWriterNsStackEntry: + * @data0: the first data + * @data1: the second data + * + * Compare callback for the xmlList. + * + * Returns -1, 0, 1 + */ +static int +xmlCmpTextWriterNsStackEntry(const void *data0, const void *data1) +{ + xmlTextWriterNsStackEntry *p0; + xmlTextWriterNsStackEntry *p1; + int rc; + + if (data0 == data1) + return 0; + + if (data0 == 0) + return -1; + + if (data1 == 0) + return 1; + + p0 = (xmlTextWriterNsStackEntry *) data0; + p1 = (xmlTextWriterNsStackEntry *) data1; + + rc = xmlStrcmp(p0->prefix, p1->prefix); + + if ((rc != 0) || (p0->elem != p1->elem)) + rc = -1; + + return rc; +} + +/** + * xmlTextWriterWriteDocCallback: + * @context: the xmlBufferPtr + * @str: the data to write + * @len: the length of the data + * + * Write callback for the xmlOutputBuffer with target xmlBuffer + * + * Returns -1, 0, 1 + */ +static int +xmlTextWriterWriteDocCallback(void *context, const xmlChar * str, int len) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) context; + int rc; + + if ((rc = xmlParseChunk(ctxt, (const char *) str, len, 0)) != 0) { + xmlWriterErrMsgInt(NULL, XML_ERR_INTERNAL_ERROR, + "xmlTextWriterWriteDocCallback : XML error %d !\n", + rc); + return -1; + } + + return len; +} + +/** + * xmlTextWriterCloseDocCallback: + * @context: the xmlBufferPtr + * + * Close callback for the xmlOutputBuffer with target xmlBuffer + * + * Returns -1, 0, 1 + */ +static int +xmlTextWriterCloseDocCallback(void *context) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) context; + int rc; + + if ((rc = xmlParseChunk(ctxt, NULL, 0, 1)) != 0) { + xmlWriterErrMsgInt(NULL, XML_ERR_INTERNAL_ERROR, + "xmlTextWriterWriteDocCallback : XML error %d !\n", + rc); + return -1; + } + + return 0; +} + +/** + * xmlTextWriterVSprintf: + * @format: see printf + * @argptr: pointer to the first member of the variable argument list. + * + * Utility function for formatted output + * + * Returns a new xmlChar buffer with the data or NULL on error. This buffer must be freed. + */ +static xmlChar * +xmlTextWriterVSprintf(const char *format, va_list argptr) +{ + int size; + int count; + xmlChar *buf; + va_list locarg; + + size = BUFSIZ; + buf = (xmlChar *) xmlMalloc(size); + if (buf == NULL) { + xmlWriterErrMsg(NULL, XML_ERR_NO_MEMORY, + "xmlTextWriterVSprintf : out of memory!\n"); + return NULL; + } + + VA_COPY(locarg, argptr); + while (((count = vsnprintf((char *) buf, size, format, locarg)) < 0) + || (count == size - 1) || (count == size) || (count > size)) { + va_end(locarg); + xmlFree(buf); + size += BUFSIZ; + buf = (xmlChar *) xmlMalloc(size); + if (buf == NULL) { + xmlWriterErrMsg(NULL, XML_ERR_NO_MEMORY, + "xmlTextWriterVSprintf : out of memory!\n"); + return NULL; + } + VA_COPY(locarg, argptr); + } + va_end(locarg); + + return buf; +} + +/** + * xmlTextWriterStartDocumentCallback: + * @ctx: the user data (XML parser context) + * + * called at the start of document processing. + */ +static void +xmlTextWriterStartDocumentCallback(void *ctx) +{ + xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; + xmlDocPtr doc; + + if (ctxt->html) { + xmlWriterErrMsg(NULL, XML_ERR_INTERNAL_ERROR, + "libxml2 built without HTML support\n"); + ctxt->errNo = XML_ERR_INTERNAL_ERROR; + ctxt->instate = XML_PARSER_EOF; + ctxt->disableSAX = 1; + return; + } else { + doc = ctxt->myDoc; + if (doc == NULL) + doc = ctxt->myDoc = xmlNewDoc(ctxt->version); + if (doc != NULL) { + if (doc->children == NULL) { + if (ctxt->encoding != NULL) + doc->encoding = xmlStrdup(ctxt->encoding); + else + doc->encoding = NULL; + doc->standalone = ctxt->standalone; + } + } else { + if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL)) + ctxt->sax->error(ctxt->userData, + "SAX.startDocument(): out of memory\n"); + ctxt->errNo = XML_ERR_NO_MEMORY; + ctxt->instate = XML_PARSER_EOF; + ctxt->disableSAX = 1; + return; + } + } + if ((ctxt->myDoc != NULL) && (ctxt->myDoc->URL == NULL) && + (ctxt->input != NULL) && (ctxt->input->filename != NULL)) { + ctxt->myDoc->URL = + xmlCanonicPath((const xmlChar *) ctxt->input->filename); + if (ctxt->myDoc->URL == NULL) + ctxt->myDoc->URL = + xmlStrdup((const xmlChar *) ctxt->input->filename); + } +} + +/** + * xmlTextWriterSetIndent: + * @writer: the xmlTextWriterPtr + * @indent: do indentation? + * + * Set indentation output. indent = 0 do not indentation. indent > 0 do indentation. + * + * Returns -1 on error or 0 otherwise. + */ +int +xmlTextWriterSetIndent(xmlTextWriterPtr writer, int indent) +{ + if ((writer == NULL) || (indent < 0)) + return -1; + + writer->indent = indent; + writer->doindent = 1; + + return 0; +} + +/** + * xmlTextWriterSetIndentString: + * @writer: the xmlTextWriterPtr + * @str: the xmlChar string + * + * Set string indentation. + * + * Returns -1 on error or 0 otherwise. + */ +int +xmlTextWriterSetIndentString(xmlTextWriterPtr writer, const xmlChar * str) +{ + if ((writer == NULL) || (!str)) + return -1; + + if (writer->ichar != NULL) + xmlFree(writer->ichar); + writer->ichar = xmlStrdup(str); + + if (!writer->ichar) + return -1; + else + return 0; +} + +/** + * xmlTextWriterWriteIndent: + * @writer: the xmlTextWriterPtr + * + * Write indent string. + * + * Returns -1 on error or the number of strings written. + */ +static int +xmlTextWriterWriteIndent(xmlTextWriterPtr writer) +{ + int lksize; + int i; + int ret; + + lksize = xmlListSize(writer->nodes); + if (lksize < 1) + return (-1); /* list is empty */ + for (i = 0; i < (lksize - 1); i++) { + ret = xmlOutputBufferWriteString(writer->out, + (const char *) writer->ichar); + if (ret == -1) + return (-1); + } + + return (lksize - 1); +} + +/** + * xmlTextWriterHandleStateDependencies: + * @writer: the xmlTextWriterPtr + * @p: the xmlTextWriterStackEntry + * + * Write state dependent strings. + * + * Returns -1 on error or the number of characters written. + */ +static int +xmlTextWriterHandleStateDependencies(xmlTextWriterPtr writer, + xmlTextWriterStackEntry * p) +{ + int count; + int sum; + char extra[3]; + + if (writer == NULL) + return -1; + + if (p == NULL) + return 0; + + sum = 0; + extra[0] = extra[1] = extra[2] = '\0'; + if (p != 0) { + sum = 0; + switch (p->state) { + case XML_TEXTWRITER_NAME: + /* Output namespace declarations */ + count = xmlTextWriterOutputNSDecl(writer); + if (count < 0) + return -1; + sum += count; + extra[0] = '>'; + p->state = XML_TEXTWRITER_TEXT; + break; + case XML_TEXTWRITER_PI: + extra[0] = ' '; + p->state = XML_TEXTWRITER_PI_TEXT; + break; + case XML_TEXTWRITER_DTD: + extra[0] = ' '; + extra[1] = '['; + p->state = XML_TEXTWRITER_DTD_TEXT; + break; + case XML_TEXTWRITER_DTD_ELEM: + extra[0] = ' '; + p->state = XML_TEXTWRITER_DTD_ELEM_TEXT; + break; + case XML_TEXTWRITER_DTD_ATTL: + extra[0] = ' '; + p->state = XML_TEXTWRITER_DTD_ATTL_TEXT; + break; + case XML_TEXTWRITER_DTD_ENTY: + case XML_TEXTWRITER_DTD_PENT: + extra[0] = ' '; + extra[1] = writer->qchar; + p->state = XML_TEXTWRITER_DTD_ENTY_TEXT; + break; + default: + break; + } + } + + if (*extra != '\0') { + count = xmlOutputBufferWriteString(writer->out, extra); + if (count < 0) + return -1; + sum += count; + } + + return sum; +} + +#define bottom_xmlwriter +#include "elfgcchack.h" +#endif diff --git a/android/native/libxml2/xpath.c b/android/native/libxml2/xpath.c new file mode 100644 index 0000000000..8900313563 --- /dev/null +++ b/android/native/libxml2/xpath.c @@ -0,0 +1,15228 @@ +/* + * xpath.c: XML Path Language implementation + * XPath is a language for addressing parts of an XML document, + * designed to be used by both XSLT and XPointer + *f + * Reference: W3C Recommendation 16 November 1999 + * http://www.w3.org/TR/1999/REC-xpath-19991116 + * Public reference: + * http://www.w3.org/TR/xpath + * + * See Copyright for the status of this software + * + * Author: daniel@veillard.com + * + */ + +#define IN_LIBXML +#include "libxml.h" + +#include + +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_MATH_H +#include +#endif +#ifdef HAVE_FLOAT_H +#include +#endif +#ifdef HAVE_CTYPE_H +#include +#endif +#ifdef HAVE_SIGNAL_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#ifdef LIBXML_XPTR_ENABLED +#include +#endif +#ifdef LIBXML_DEBUG_ENABLED +#include +#endif +#include +#include +#include +#ifdef LIBXML_PATTERN_ENABLED +#include +#endif + +#ifdef LIBXML_PATTERN_ENABLED +#define XPATH_STREAMING +#endif + +#define TODO \ + xmlGenericError(xmlGenericErrorContext, \ + "Unimplemented block at %s:%d\n", \ + __FILE__, __LINE__); + +/* +* XP_OPTIMIZED_NON_ELEM_COMPARISON: +* If defined, this will use xmlXPathCmpNodesExt() instead of +* xmlXPathCmpNodes(). The new function is optimized comparison of +* non-element nodes; actually it will speed up comparison only if +* xmlXPathOrderDocElems() was called in order to index the elements of +* a tree in document order; Libxslt does such an indexing, thus it will +* benefit from this optimization. +*/ +#define XP_OPTIMIZED_NON_ELEM_COMPARISON + +/* +* XP_OPTIMIZED_FILTER_FIRST: +* If defined, this will optimize expressions like "key('foo', 'val')[b][1]" +* in a way, that it stop evaluation at the first node. +*/ +#define XP_OPTIMIZED_FILTER_FIRST + +/* +* XP_DEBUG_OBJ_USAGE: +* Internal flag to enable tracking of how much XPath objects have been +* created. +*/ +/* #define XP_DEBUG_OBJ_USAGE */ + +/* + * TODO: + * There are a few spots where some tests are done which depend upon ascii + * data. These should be enhanced for full UTF8 support (see particularly + * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT) + */ + +#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED) + +/************************************************************************ + * * + * Floating point stuff * + * * + ************************************************************************/ + +#ifndef TRIO_REPLACE_STDIO +#define TRIO_PUBLIC static +#endif +#include "trionan.c" + +/* + * The lack of portability of this section of the libc is annoying ! + */ +double xmlXPathNAN = 0; +double xmlXPathPINF = 1; +double xmlXPathNINF = -1; +static double xmlXPathNZERO = 0; /* not exported from headers */ +static int xmlXPathInitialized = 0; + +/** + * xmlXPathInit: + * + * Initialize the XPath environment + */ +void +xmlXPathInit(void) { + if (xmlXPathInitialized) return; + + xmlXPathPINF = trio_pinf(); + xmlXPathNINF = trio_ninf(); + xmlXPathNAN = trio_nan(); + xmlXPathNZERO = trio_nzero(); + + xmlXPathInitialized = 1; +} + +/** + * xmlXPathIsNaN: + * @val: a double value + * + * Provides a portable isnan() function to detect whether a double + * is a NotaNumber. Based on trio code + * http://sourceforge.net/projects/ctrio/ + * + * Returns 1 if the value is a NaN, 0 otherwise + */ +int +xmlXPathIsNaN(double val) { + return(trio_isnan(val)); +} + +/** + * xmlXPathIsInf: + * @val: a double value + * + * Provides a portable isinf() function to detect whether a double + * is a +Infinite or -Infinite. Based on trio code + * http://sourceforge.net/projects/ctrio/ + * + * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise + */ +int +xmlXPathIsInf(double val) { + return(trio_isinf(val)); +} + +#endif /* SCHEMAS or XPATH */ +#ifdef LIBXML_XPATH_ENABLED +/** + * xmlXPathGetSign: + * @val: a double value + * + * Provides a portable function to detect the sign of a double + * Modified from trio code + * http://sourceforge.net/projects/ctrio/ + * + * Returns 1 if the value is Negative, 0 if positive + */ +static int +xmlXPathGetSign(double val) { + return(trio_signbit(val)); +} + + +/* + * TODO: when compatibility allows remove all "fake node libxslt" strings + * the test should just be name[0] = ' ' + */ +#ifdef DEBUG_XPATH_EXPRESSION +#define DEBUG_STEP +#define DEBUG_EXPR +#define DEBUG_EVAL_COUNTS +#endif + +static xmlNs xmlXPathXMLNamespaceStruct = { + NULL, + XML_NAMESPACE_DECL, + XML_XML_NAMESPACE, + BAD_CAST "xml", + NULL, + NULL +}; +static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct; +#ifndef LIBXML_THREAD_ENABLED +/* + * Optimizer is disabled only when threaded apps are detected while + * the library ain't compiled for thread safety. + */ +static int xmlXPathDisableOptimizer = 0; +#endif + +/************************************************************************ + * * + * Error handling routines * + * * + ************************************************************************/ + +/** + * XP_ERRORNULL: + * @X: the error code + * + * Macro to raise an XPath error and return NULL. + */ +#define XP_ERRORNULL(X) \ + { xmlXPathErr(ctxt, X); return(NULL); } + +/* + * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError + */ +static const char *xmlXPathErrorMessages[] = { + "Ok\n", + "Number encoding\n", + "Unfinished literal\n", + "Start of literal\n", + "Expected $ for variable reference\n", + "Undefined variable\n", + "Invalid predicate\n", + "Invalid expression\n", + "Missing closing curly brace\n", + "Unregistered function\n", + "Invalid operand\n", + "Invalid type\n", + "Invalid number of arguments\n", + "Invalid context size\n", + "Invalid context position\n", + "Memory allocation error\n", + "Syntax error\n", + "Resource error\n", + "Sub resource error\n", + "Undefined namespace prefix\n", + "Encoding error\n", + "Char out of XML range\n", + "Invalid or incomplete context\n", + "Stack usage errror\n", + "?? Unknown error ??\n" /* Must be last in the list! */ +}; +#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \ + sizeof(xmlXPathErrorMessages[0])) - 1) +/** + * xmlXPathErrMemory: + * @ctxt: an XPath context + * @extra: extra informations + * + * Handle a redefinition of attribute error + */ +static void +xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra) +{ + if (ctxt != NULL) { + if (extra) { + xmlChar buf[200]; + + xmlStrPrintf(buf, 200, + BAD_CAST "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"); + } +} + +/** + * xmlXPathPErrMemory: + * @ctxt: an XPath parser context + * @extra: extra informations + * + * Handle a redefinition of attribute error + */ +static void +xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra) +{ + if (ctxt == NULL) + xmlXPathErrMemory(NULL, extra); + else { + ctxt->error = XPATH_MEMORY_ERROR; + xmlXPathErrMemory(ctxt->context, extra); + } +} + +/** + * xmlXPathErr: + * @ctxt: a XPath parser context + * @error: the error code + * + * Handle an XPath error + */ +void +xmlXPathErr(xmlXPathParserContextPtr ctxt, int error) +{ + 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; + } + 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->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]); + } + +} + +/** + * xmlXPatherror: + * @ctxt: the XPath Parser context + * @file: the file name + * @line: the line number + * @no: the error number + * + * Formats an error message. + */ +void +xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED, + int line ATTRIBUTE_UNUSED, int no) { + xmlXPathErr(ctxt, no); +} + +/************************************************************************ + * * + * 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->items == NULL) { + if (initialSize <= 0) + initialSize = 1; + list->items = (void **) xmlMalloc( + initialSize * sizeof(void *)); + if (list->items == NULL) { + xmlXPathErrMemory(NULL, + "xmlPointerListCreate: allocating item\n"); + return(-1); + } + list->number = 0; + list->size = initialSize; + } else if (list->size <= list->number) { + list->size *= 2; + list->items = (void **) xmlRealloc(list->items, + list->size * sizeof(void *)); + if (list->items == NULL) { + xmlXPathErrMemory(NULL, + "xmlPointerListCreate: re-allocating item\n"); + list->size = 0; + return(-1); + } + } + 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 * + * * + ************************************************************************/ + +/* + * Types are private: + */ + +typedef enum { + XPATH_OP_END=0, + XPATH_OP_AND, + XPATH_OP_OR, + XPATH_OP_EQUAL, + XPATH_OP_CMP, + XPATH_OP_PLUS, + XPATH_OP_MULT, + XPATH_OP_UNION, + XPATH_OP_ROOT, + XPATH_OP_NODE, + XPATH_OP_RESET, /* 10 */ + XPATH_OP_COLLECT, + XPATH_OP_VALUE, /* 12 */ + XPATH_OP_VARIABLE, + XPATH_OP_FUNCTION, + XPATH_OP_ARG, + XPATH_OP_PREDICATE, + XPATH_OP_FILTER, /* 17 */ + XPATH_OP_SORT /* 18 */ +#ifdef LIBXML_XPTR_ENABLED + ,XPATH_OP_RANGETO +#endif +} xmlXPathOp; + +typedef enum { + AXIS_ANCESTOR = 1, + AXIS_ANCESTOR_OR_SELF, + AXIS_ATTRIBUTE, + AXIS_CHILD, + AXIS_DESCENDANT, + AXIS_DESCENDANT_OR_SELF, + AXIS_FOLLOWING, + AXIS_FOLLOWING_SIBLING, + AXIS_NAMESPACE, + AXIS_PARENT, + AXIS_PRECEDING, + AXIS_PRECEDING_SIBLING, + AXIS_SELF +} xmlXPathAxisVal; + +typedef enum { + NODE_TEST_NONE = 0, + NODE_TEST_TYPE = 1, + NODE_TEST_PI = 2, + NODE_TEST_ALL = 3, + NODE_TEST_NS = 4, + NODE_TEST_NAME = 5 +} xmlXPathTestVal; + +typedef enum { + NODE_TYPE_NODE = 0, + NODE_TYPE_COMMENT = XML_COMMENT_NODE, + NODE_TYPE_TEXT = XML_TEXT_NODE, + NODE_TYPE_PI = XML_PI_NODE +} xmlXPathTypeVal; + +#define XP_REWRITE_DOS_CHILD_ELEM 1 + +typedef struct _xmlXPathStepOp xmlXPathStepOp; +typedef xmlXPathStepOp *xmlXPathStepOpPtr; +struct _xmlXPathStepOp { + xmlXPathOp op; /* The identifier of the operation */ + int ch1; /* First child */ + int ch2; /* Second child */ + int value; + int value2; + int value3; + void *value4; + void *value5; + void *cache; + void *cacheURI; + int rewriteType; +}; + +struct _xmlXPathCompExpr { + int nbStep; /* Number of steps in this expression */ + int maxStep; /* Maximum number of steps allocated */ + xmlXPathStepOp *steps; /* ops for computation of this expression */ + int last; /* index of last step in expression */ + xmlChar *expr; /* the expression being computed */ + xmlDictPtr dict; /* the dictionnary to use if any */ +#ifdef DEBUG_EVAL_COUNTS + int nb; + xmlChar *string; +#endif +#ifdef XPATH_STREAMING + xmlPatternPtr stream; +#endif +}; + +/************************************************************************ + * * + * Forward declarations * + * * + ************************************************************************/ +static void +xmlXPathFreeValueTree(xmlNodeSetPtr obj); +static void +xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj); +static int +xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt, + xmlXPathStepOpPtr op, xmlNodePtr *first); +static int +xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt, + xmlXPathStepOpPtr op, + int isPredicate); + +/************************************************************************ + * * + * Parser Type functions * + * * + ************************************************************************/ + +/** + * xmlXPathNewCompExpr: + * + * Create a new Xpath component + * + * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error + */ +static xmlXPathCompExprPtr +xmlXPathNewCompExpr(void) { + xmlXPathCompExprPtr cur; + + cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr)); + if (cur == NULL) { + xmlXPathErrMemory(NULL, "allocating component\n"); + 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); + } + memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp)); + cur->last = -1; +#ifdef DEBUG_EVAL_COUNTS + cur->nb = 0; +#endif + return(cur); +} + +/** + * xmlXPathFreeCompExpr: + * @comp: an XPATH comp + * + * Free up the memory allocated by @comp + */ +void +xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp) +{ + xmlXPathStepOpPtr op; + int i; + + if (comp == NULL) + return; + if (comp->dict == NULL) { + for (i = 0; i < comp->nbStep; i++) { + op = &comp->steps[i]; + if (op->value4 != NULL) { + if (op->op == XPATH_OP_VALUE) + xmlXPathFreeObject(op->value4); + else + xmlFree(op->value4); + } + if (op->value5 != NULL) + xmlFree(op->value5); + } + } else { + for (i = 0; i < comp->nbStep; i++) { + op = &comp->steps[i]; + if (op->value4 != NULL) { + if (op->op == XPATH_OP_VALUE) + xmlXPathFreeObject(op->value4); + } + } + xmlDictFree(comp->dict); + } + if (comp->steps != NULL) { + xmlFree(comp->steps); + } +#ifdef DEBUG_EVAL_COUNTS + if (comp->string != NULL) { + xmlFree(comp->string); + } +#endif +#ifdef XPATH_STREAMING + if (comp->stream != NULL) { + xmlFreePatternList(comp->stream); + } +#endif + if (comp->expr != NULL) { + xmlFree(comp->expr); + } + + xmlFree(comp); +} + +/** + * xmlXPathCompExprAdd: + * @comp: the compiled expression + * @ch1: first child index + * @ch2: second child index + * @op: an op + * @value: the first int value + * @value2: the second int value + * @value3: the third int value + * @value4: the first string value + * @value5: the second string value + * + * Add a step to an XPath Compiled Expression + * + * Returns -1 in case of failure, the index otherwise + */ +static int +xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2, + xmlXPathOp op, int value, + int value2, int value3, void *value4, void *value5) { + if (comp->nbStep >= comp->maxStep) { + xmlXPathStepOp *real; + + comp->maxStep *= 2; + real = (xmlXPathStepOp *) xmlRealloc(comp->steps, + comp->maxStep * sizeof(xmlXPathStepOp)); + if (real == NULL) { + comp->maxStep /= 2; + xmlXPathErrMemory(NULL, "adding step\n"); + return(-1); + } + comp->steps = real; + } + comp->last = comp->nbStep; + comp->steps[comp->nbStep].rewriteType = 0; + comp->steps[comp->nbStep].ch1 = ch1; + comp->steps[comp->nbStep].ch2 = ch2; + comp->steps[comp->nbStep].op = op; + comp->steps[comp->nbStep].value = value; + comp->steps[comp->nbStep].value2 = value2; + comp->steps[comp->nbStep].value3 = value3; + if ((comp->dict != NULL) && + ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) || + (op == XPATH_OP_COLLECT))) { + if (value4 != NULL) { + comp->steps[comp->nbStep].value4 = (xmlChar *) + (void *)xmlDictLookup(comp->dict, value4, -1); + xmlFree(value4); + } else + comp->steps[comp->nbStep].value4 = NULL; + if (value5 != NULL) { + comp->steps[comp->nbStep].value5 = (xmlChar *) + (void *)xmlDictLookup(comp->dict, value5, -1); + xmlFree(value5); + } else + comp->steps[comp->nbStep].value5 = NULL; + } else { + comp->steps[comp->nbStep].value4 = value4; + comp->steps[comp->nbStep].value5 = value5; + } + comp->steps[comp->nbStep].cache = NULL; + return(comp->nbStep++); +} + +/** + * xmlXPathCompSwap: + * @comp: the compiled expression + * @op: operation index + * + * Swaps 2 operations in the compiled expression + */ +static void +xmlXPathCompSwap(xmlXPathStepOpPtr op) { + int tmp; + +#ifndef LIBXML_THREAD_ENABLED + /* + * Since this manipulates possibly shared variables, this is + * disabled if one detects that the library is used in a multithreaded + * application + */ + if (xmlXPathDisableOptimizer) + return; +#endif + + tmp = op->ch1; + op->ch1 = op->ch2; + op->ch2 = tmp; +} + +#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \ + xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \ + (op), (val), (val2), (val3), (val4), (val5)) +#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \ + xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \ + (op), (val), (val2), (val3), (val4), (val5)) + +#define PUSH_LEAVE_EXPR(op, val, val2) \ +xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL) + +#define PUSH_UNARY_EXPR(op, ch, val, val2) \ +xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL) + +#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \ +xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \ + (val), (val2), 0 ,NULL ,NULL) + +/************************************************************************ + * * + * XPath object cache structures * + * * + ************************************************************************/ + +/* #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 */ + int maxNodeset; + int maxString; + int maxBoolean; + int maxNumber; + int maxMisc; +#ifdef XP_DEBUG_OBJ_USAGE + int dbgCachedAll; + int dbgCachedNodeset; + int dbgCachedString; + int dbgCachedBool; + int dbgCachedNumber; + int dbgCachedPoint; + int dbgCachedRange; + int dbgCachedLocset; + int dbgCachedUsers; + int dbgCachedXSLTTree; + int dbgCachedUndefined; + + + int dbgReusedAll; + int dbgReusedNodeset; + int dbgReusedString; + int dbgReusedBool; + int dbgReusedNumber; + int dbgReusedPoint; + int dbgReusedRange; + int dbgReusedLocset; + int dbgReusedUsers; + int dbgReusedXSLTTree; + int dbgReusedUndefined; + +#endif +}; + +/************************************************************************ + * * + * Debugging related functions * + * * + ************************************************************************/ + +#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) { + int i; + char shift[100]; + + for (i = 0;((i < depth) && (i < 25));i++) + shift[2 * i] = shift[2 * i + 1] = ' '; + shift[2 * i] = shift[2 * i + 1] = 0; + if (cur == NULL) { + fprintf(output, "%s", shift); + fprintf(output, "Node is NULL !\n"); + return; + + } + + if ((cur->type == XML_DOCUMENT_NODE) || + (cur->type == XML_HTML_DOCUMENT_NODE)) { + fprintf(output, "%s", shift); + fprintf(output, " /\n"); + } else if (cur->type == XML_ATTRIBUTE_NODE) + xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth); + else + xmlDebugDumpOneNode(output, cur, depth); +} +static void +xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) { + xmlNodePtr tmp; + int i; + char shift[100]; + + for (i = 0;((i < depth) && (i < 25));i++) + shift[2 * i] = shift[2 * i + 1] = ' '; + shift[2 * i] = shift[2 * i + 1] = 0; + if (cur == NULL) { + fprintf(output, "%s", shift); + fprintf(output, "Node is NULL !\n"); + return; + + } + + while (cur != NULL) { + tmp = cur; + cur = cur->next; + xmlDebugDumpOneNode(output, tmp, depth); + } +} + +static void +xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) { + int i; + char shift[100]; + + for (i = 0;((i < depth) && (i < 25));i++) + shift[2 * i] = shift[2 * i + 1] = ' '; + shift[2 * i] = shift[2 * i + 1] = 0; + + if (cur == NULL) { + fprintf(output, "%s", shift); + fprintf(output, "NodeSet is NULL !\n"); + return; + + } + + if (cur != NULL) { + fprintf(output, "Set contains %d nodes:\n", cur->nodeNr); + for (i = 0;i < cur->nodeNr;i++) { + fprintf(output, "%s", shift); + fprintf(output, "%d", i + 1); + xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1); + } + } +} + +static void +xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) { + int i; + char shift[100]; + + for (i = 0;((i < depth) && (i < 25));i++) + shift[2 * i] = shift[2 * i + 1] = ' '; + shift[2 * i] = shift[2 * i + 1] = 0; + + if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) { + fprintf(output, "%s", shift); + fprintf(output, "Value Tree is NULL !\n"); + return; + + } + + fprintf(output, "%s", shift); + fprintf(output, "%d", i + 1); + xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1); +} +#if defined(LIBXML_XPTR_ENABLED) +static void +xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) { + int i; + char shift[100]; + + for (i = 0;((i < depth) && (i < 25));i++) + shift[2 * i] = shift[2 * i + 1] = ' '; + shift[2 * i] = shift[2 * i + 1] = 0; + + if (cur == NULL) { + fprintf(output, "%s", shift); + fprintf(output, "LocationSet is NULL !\n"); + return; + + } + + for (i = 0;i < cur->locNr;i++) { + fprintf(output, "%s", shift); + fprintf(output, "%d : ", i + 1); + xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1); + } +} +#endif /* LIBXML_XPTR_ENABLED */ + +/** + * xmlXPathDebugDumpObject: + * @output: the FILE * to dump the output + * @cur: the object to inspect + * @depth: indentation level + * + * Dump the content of the object for debugging purposes + */ +void +xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) { + int i; + char shift[100]; + + if (output == NULL) return; + + for (i = 0;((i < depth) && (i < 25));i++) + shift[2 * i] = shift[2 * i + 1] = ' '; + shift[2 * i] = shift[2 * i + 1] = 0; + + + fprintf(output, "%s", shift); + + if (cur == NULL) { + fprintf(output, "Object is empty (NULL)\n"); + return; + } + switch(cur->type) { + case XPATH_UNDEFINED: + fprintf(output, "Object is uninitialized\n"); + break; + case XPATH_NODESET: + fprintf(output, "Object is a Node Set :\n"); + xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth); + break; + case XPATH_XSLT_TREE: + fprintf(output, "Object is an XSLT value tree :\n"); + xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth); + break; + case XPATH_BOOLEAN: + fprintf(output, "Object is a Boolean : "); + if (cur->boolval) fprintf(output, "true\n"); + else fprintf(output, "false\n"); + break; + case XPATH_NUMBER: + switch (xmlXPathIsInf(cur->floatval)) { + case 1: + fprintf(output, "Object is a number : Infinity\n"); + break; + case -1: + fprintf(output, "Object is a number : -Infinity\n"); + break; + default: + if (xmlXPathIsNaN(cur->floatval)) { + fprintf(output, "Object is a number : NaN\n"); + } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) { + fprintf(output, "Object is a number : 0\n"); + } else { + fprintf(output, "Object is a number : %0g\n", cur->floatval); + } + } + break; + case XPATH_STRING: + fprintf(output, "Object is a string : "); + xmlDebugDumpString(output, cur->stringval); + fprintf(output, "\n"); + break; + case XPATH_POINT: + fprintf(output, "Object is a point : index %d in node", cur->index); + xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1); + fprintf(output, "\n"); + break; + case XPATH_RANGE: + if ((cur->user2 == NULL) || + ((cur->user2 == cur->user) && (cur->index == cur->index2))) { + fprintf(output, "Object is a collapsed range :\n"); + fprintf(output, "%s", shift); + if (cur->index >= 0) + fprintf(output, "index %d in ", cur->index); + fprintf(output, "node\n"); + xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, + depth + 1); + } else { + fprintf(output, "Object is a range :\n"); + fprintf(output, "%s", shift); + fprintf(output, "From "); + if (cur->index >= 0) + fprintf(output, "index %d in ", cur->index); + fprintf(output, "node\n"); + xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, + depth + 1); + fprintf(output, "%s", shift); + fprintf(output, "To "); + if (cur->index2 >= 0) + fprintf(output, "index %d in ", cur->index2); + fprintf(output, "node\n"); + xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2, + depth + 1); + fprintf(output, "\n"); + } + break; + case XPATH_LOCATIONSET: +#if defined(LIBXML_XPTR_ENABLED) + fprintf(output, "Object is a Location Set:\n"); + xmlXPathDebugDumpLocationSet(output, + (xmlLocationSetPtr) cur->user, depth); +#endif + break; + case XPATH_USERS: + fprintf(output, "Object is user defined\n"); + break; + } +} + +static void +xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp, + xmlXPathStepOpPtr op, int depth) { + int i; + char shift[100]; + + for (i = 0;((i < depth) && (i < 25));i++) + shift[2 * i] = shift[2 * i + 1] = ' '; + shift[2 * i] = shift[2 * i + 1] = 0; + + fprintf(output, "%s", shift); + if (op == NULL) { + fprintf(output, "Step is NULL\n"); + return; + } + switch (op->op) { + case XPATH_OP_END: + fprintf(output, "END"); break; + case XPATH_OP_AND: + fprintf(output, "AND"); break; + case XPATH_OP_OR: + fprintf(output, "OR"); break; + case XPATH_OP_EQUAL: + if (op->value) + fprintf(output, "EQUAL ="); + else + fprintf(output, "EQUAL !="); + break; + case XPATH_OP_CMP: + if (op->value) + fprintf(output, "CMP <"); + else + fprintf(output, "CMP >"); + if (!op->value2) + fprintf(output, "="); + break; + case XPATH_OP_PLUS: + if (op->value == 0) + fprintf(output, "PLUS -"); + else if (op->value == 1) + fprintf(output, "PLUS +"); + else if (op->value == 2) + fprintf(output, "PLUS unary -"); + else if (op->value == 3) + fprintf(output, "PLUS unary - -"); + break; + case XPATH_OP_MULT: + if (op->value == 0) + fprintf(output, "MULT *"); + else if (op->value == 1) + fprintf(output, "MULT div"); + else + fprintf(output, "MULT mod"); + break; + case XPATH_OP_UNION: + fprintf(output, "UNION"); break; + case XPATH_OP_ROOT: + fprintf(output, "ROOT"); break; + case XPATH_OP_NODE: + fprintf(output, "NODE"); break; + case XPATH_OP_RESET: + fprintf(output, "RESET"); break; + case XPATH_OP_SORT: + fprintf(output, "SORT"); break; + case XPATH_OP_COLLECT: { + xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value; + xmlXPathTestVal test = (xmlXPathTestVal)op->value2; + xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3; + const xmlChar *prefix = op->value4; + const xmlChar *name = op->value5; + + fprintf(output, "COLLECT "); + switch (axis) { + case AXIS_ANCESTOR: + fprintf(output, " 'ancestors' "); break; + case AXIS_ANCESTOR_OR_SELF: + fprintf(output, " 'ancestors-or-self' "); break; + case AXIS_ATTRIBUTE: + fprintf(output, " 'attributes' "); break; + case AXIS_CHILD: + fprintf(output, " 'child' "); break; + case AXIS_DESCENDANT: + fprintf(output, " 'descendant' "); break; + case AXIS_DESCENDANT_OR_SELF: + fprintf(output, " 'descendant-or-self' "); break; + case AXIS_FOLLOWING: + fprintf(output, " 'following' "); break; + case AXIS_FOLLOWING_SIBLING: + fprintf(output, " 'following-siblings' "); break; + case AXIS_NAMESPACE: + fprintf(output, " 'namespace' "); break; + case AXIS_PARENT: + fprintf(output, " 'parent' "); break; + case AXIS_PRECEDING: + fprintf(output, " 'preceding' "); break; + case AXIS_PRECEDING_SIBLING: + fprintf(output, " 'preceding-sibling' "); break; + case AXIS_SELF: + fprintf(output, " 'self' "); break; + } + switch (test) { + case NODE_TEST_NONE: + fprintf(output, "'none' "); break; + case NODE_TEST_TYPE: + fprintf(output, "'type' "); break; + case NODE_TEST_PI: + fprintf(output, "'PI' "); break; + case NODE_TEST_ALL: + fprintf(output, "'all' "); break; + case NODE_TEST_NS: + fprintf(output, "'namespace' "); break; + case NODE_TEST_NAME: + fprintf(output, "'name' "); break; + } + switch (type) { + case NODE_TYPE_NODE: + fprintf(output, "'node' "); break; + case NODE_TYPE_COMMENT: + fprintf(output, "'comment' "); break; + case NODE_TYPE_TEXT: + fprintf(output, "'text' "); break; + case NODE_TYPE_PI: + fprintf(output, "'PI' "); break; + } + if (prefix != NULL) + fprintf(output, "%s:", prefix); + if (name != NULL) + fprintf(output, "%s", (const char *) name); + break; + + } + case XPATH_OP_VALUE: { + xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4; + + fprintf(output, "ELEM "); + xmlXPathDebugDumpObject(output, object, 0); + goto finish; + } + case XPATH_OP_VARIABLE: { + const xmlChar *prefix = op->value5; + const xmlChar *name = op->value4; + + if (prefix != NULL) + fprintf(output, "VARIABLE %s:%s", prefix, name); + else + fprintf(output, "VARIABLE %s", name); + break; + } + case XPATH_OP_FUNCTION: { + int nbargs = op->value; + const xmlChar *prefix = op->value5; + const xmlChar *name = op->value4; + + if (prefix != NULL) + fprintf(output, "FUNCTION %s:%s(%d args)", + prefix, name, nbargs); + else + fprintf(output, "FUNCTION %s(%d args)", name, nbargs); + break; + } + case XPATH_OP_ARG: fprintf(output, "ARG"); break; + case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break; + case XPATH_OP_FILTER: fprintf(output, "FILTER"); break; +#ifdef LIBXML_XPTR_ENABLED + case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break; +#endif + default: + fprintf(output, "UNKNOWN %d\n", op->op); return; + } + fprintf(output, "\n"); +finish: + if (op->ch1 >= 0) + xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1); + if (op->ch2 >= 0) + xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1); +} + +/** + * xmlXPathDebugDumpCompExpr: + * @output: the FILE * for the output + * @comp: the precompiled XPath expression + * @depth: the indentation level. + * + * Dumps the tree of the compiled XPath expression. + */ +void +xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp, + int depth) { + int i; + char shift[100]; + + if ((output == NULL) || (comp == NULL)) return; + + for (i = 0;((i < depth) && (i < 25));i++) + shift[2 * i] = shift[2 * i + 1] = ' '; + shift[2 * i] = shift[2 * i + 1] = 0; + + fprintf(output, "%s", shift); + + fprintf(output, "Compiled Expression : %d elements\n", + comp->nbStep); + i = comp->last; + xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1); +} + +#ifdef XP_DEBUG_OBJ_USAGE + +/* +* XPath object usage related debugging variables. +*/ +static int xmlXPathDebugObjCounterUndefined = 0; +static int xmlXPathDebugObjCounterNodeset = 0; +static int xmlXPathDebugObjCounterBool = 0; +static int xmlXPathDebugObjCounterNumber = 0; +static int xmlXPathDebugObjCounterString = 0; +static int xmlXPathDebugObjCounterPoint = 0; +static int xmlXPathDebugObjCounterRange = 0; +static int xmlXPathDebugObjCounterLocset = 0; +static int xmlXPathDebugObjCounterUsers = 0; +static int xmlXPathDebugObjCounterXSLTTree = 0; +static int xmlXPathDebugObjCounterAll = 0; + +static int xmlXPathDebugObjTotalUndefined = 0; +static int xmlXPathDebugObjTotalNodeset = 0; +static int xmlXPathDebugObjTotalBool = 0; +static int xmlXPathDebugObjTotalNumber = 0; +static int xmlXPathDebugObjTotalString = 0; +static int xmlXPathDebugObjTotalPoint = 0; +static int xmlXPathDebugObjTotalRange = 0; +static int xmlXPathDebugObjTotalLocset = 0; +static int xmlXPathDebugObjTotalUsers = 0; +static int xmlXPathDebugObjTotalXSLTTree = 0; +static int xmlXPathDebugObjTotalAll = 0; + +static int xmlXPathDebugObjMaxUndefined = 0; +static int xmlXPathDebugObjMaxNodeset = 0; +static int xmlXPathDebugObjMaxBool = 0; +static int xmlXPathDebugObjMaxNumber = 0; +static int xmlXPathDebugObjMaxString = 0; +static int xmlXPathDebugObjMaxPoint = 0; +static int xmlXPathDebugObjMaxRange = 0; +static int xmlXPathDebugObjMaxLocset = 0; +static int xmlXPathDebugObjMaxUsers = 0; +static int xmlXPathDebugObjMaxXSLTTree = 0; +static int xmlXPathDebugObjMaxAll = 0; + +/* REVISIT TODO: Make this static when committing */ +static void +xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt) +{ + if (ctxt != NULL) { + if (ctxt->cache != NULL) { + xmlXPathContextCachePtr cache = + (xmlXPathContextCachePtr) ctxt->cache; + + cache->dbgCachedAll = 0; + cache->dbgCachedNodeset = 0; + cache->dbgCachedString = 0; + cache->dbgCachedBool = 0; + cache->dbgCachedNumber = 0; + cache->dbgCachedPoint = 0; + cache->dbgCachedRange = 0; + cache->dbgCachedLocset = 0; + cache->dbgCachedUsers = 0; + cache->dbgCachedXSLTTree = 0; + cache->dbgCachedUndefined = 0; + + cache->dbgReusedAll = 0; + cache->dbgReusedNodeset = 0; + cache->dbgReusedString = 0; + cache->dbgReusedBool = 0; + cache->dbgReusedNumber = 0; + cache->dbgReusedPoint = 0; + cache->dbgReusedRange = 0; + cache->dbgReusedLocset = 0; + cache->dbgReusedUsers = 0; + cache->dbgReusedXSLTTree = 0; + cache->dbgReusedUndefined = 0; + } + } + + xmlXPathDebugObjCounterUndefined = 0; + xmlXPathDebugObjCounterNodeset = 0; + xmlXPathDebugObjCounterBool = 0; + xmlXPathDebugObjCounterNumber = 0; + xmlXPathDebugObjCounterString = 0; + xmlXPathDebugObjCounterPoint = 0; + xmlXPathDebugObjCounterRange = 0; + xmlXPathDebugObjCounterLocset = 0; + xmlXPathDebugObjCounterUsers = 0; + xmlXPathDebugObjCounterXSLTTree = 0; + xmlXPathDebugObjCounterAll = 0; + + xmlXPathDebugObjTotalUndefined = 0; + xmlXPathDebugObjTotalNodeset = 0; + xmlXPathDebugObjTotalBool = 0; + xmlXPathDebugObjTotalNumber = 0; + xmlXPathDebugObjTotalString = 0; + xmlXPathDebugObjTotalPoint = 0; + xmlXPathDebugObjTotalRange = 0; + xmlXPathDebugObjTotalLocset = 0; + xmlXPathDebugObjTotalUsers = 0; + xmlXPathDebugObjTotalXSLTTree = 0; + xmlXPathDebugObjTotalAll = 0; + + xmlXPathDebugObjMaxUndefined = 0; + xmlXPathDebugObjMaxNodeset = 0; + xmlXPathDebugObjMaxBool = 0; + xmlXPathDebugObjMaxNumber = 0; + xmlXPathDebugObjMaxString = 0; + xmlXPathDebugObjMaxPoint = 0; + xmlXPathDebugObjMaxRange = 0; + xmlXPathDebugObjMaxLocset = 0; + xmlXPathDebugObjMaxUsers = 0; + xmlXPathDebugObjMaxXSLTTree = 0; + xmlXPathDebugObjMaxAll = 0; + +} + +static void +xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt, + xmlXPathObjectType objType) +{ + int isCached = 0; + + if (ctxt != NULL) { + if (ctxt->cache != NULL) { + xmlXPathContextCachePtr cache = + (xmlXPathContextCachePtr) ctxt->cache; + + isCached = 1; + + cache->dbgReusedAll++; + switch (objType) { + case XPATH_UNDEFINED: + cache->dbgReusedUndefined++; + break; + case XPATH_NODESET: + cache->dbgReusedNodeset++; + break; + case XPATH_BOOLEAN: + cache->dbgReusedBool++; + break; + case XPATH_NUMBER: + cache->dbgReusedNumber++; + break; + case XPATH_STRING: + cache->dbgReusedString++; + break; + case XPATH_POINT: + cache->dbgReusedPoint++; + break; + case XPATH_RANGE: + cache->dbgReusedRange++; + break; + case XPATH_LOCATIONSET: + cache->dbgReusedLocset++; + break; + case XPATH_USERS: + cache->dbgReusedUsers++; + break; + case XPATH_XSLT_TREE: + cache->dbgReusedXSLTTree++; + break; + default: + break; + } + } + } + + switch (objType) { + case XPATH_UNDEFINED: + if (! isCached) + xmlXPathDebugObjTotalUndefined++; + xmlXPathDebugObjCounterUndefined++; + if (xmlXPathDebugObjCounterUndefined > + xmlXPathDebugObjMaxUndefined) + xmlXPathDebugObjMaxUndefined = + xmlXPathDebugObjCounterUndefined; + break; + case XPATH_NODESET: + if (! isCached) + xmlXPathDebugObjTotalNodeset++; + xmlXPathDebugObjCounterNodeset++; + if (xmlXPathDebugObjCounterNodeset > + xmlXPathDebugObjMaxNodeset) + xmlXPathDebugObjMaxNodeset = + xmlXPathDebugObjCounterNodeset; + break; + case XPATH_BOOLEAN: + if (! isCached) + xmlXPathDebugObjTotalBool++; + xmlXPathDebugObjCounterBool++; + if (xmlXPathDebugObjCounterBool > + xmlXPathDebugObjMaxBool) + xmlXPathDebugObjMaxBool = + xmlXPathDebugObjCounterBool; + break; + case XPATH_NUMBER: + if (! isCached) + xmlXPathDebugObjTotalNumber++; + xmlXPathDebugObjCounterNumber++; + if (xmlXPathDebugObjCounterNumber > + xmlXPathDebugObjMaxNumber) + xmlXPathDebugObjMaxNumber = + xmlXPathDebugObjCounterNumber; + break; + case XPATH_STRING: + if (! isCached) + xmlXPathDebugObjTotalString++; + xmlXPathDebugObjCounterString++; + if (xmlXPathDebugObjCounterString > + xmlXPathDebugObjMaxString) + xmlXPathDebugObjMaxString = + xmlXPathDebugObjCounterString; + break; + case XPATH_POINT: + if (! isCached) + xmlXPathDebugObjTotalPoint++; + xmlXPathDebugObjCounterPoint++; + if (xmlXPathDebugObjCounterPoint > + xmlXPathDebugObjMaxPoint) + xmlXPathDebugObjMaxPoint = + xmlXPathDebugObjCounterPoint; + break; + case XPATH_RANGE: + if (! isCached) + xmlXPathDebugObjTotalRange++; + xmlXPathDebugObjCounterRange++; + if (xmlXPathDebugObjCounterRange > + xmlXPathDebugObjMaxRange) + xmlXPathDebugObjMaxRange = + xmlXPathDebugObjCounterRange; + break; + case XPATH_LOCATIONSET: + if (! isCached) + xmlXPathDebugObjTotalLocset++; + xmlXPathDebugObjCounterLocset++; + if (xmlXPathDebugObjCounterLocset > + xmlXPathDebugObjMaxLocset) + xmlXPathDebugObjMaxLocset = + xmlXPathDebugObjCounterLocset; + break; + case XPATH_USERS: + if (! isCached) + xmlXPathDebugObjTotalUsers++; + xmlXPathDebugObjCounterUsers++; + if (xmlXPathDebugObjCounterUsers > + xmlXPathDebugObjMaxUsers) + xmlXPathDebugObjMaxUsers = + xmlXPathDebugObjCounterUsers; + break; + case XPATH_XSLT_TREE: + if (! isCached) + xmlXPathDebugObjTotalXSLTTree++; + xmlXPathDebugObjCounterXSLTTree++; + if (xmlXPathDebugObjCounterXSLTTree > + xmlXPathDebugObjMaxXSLTTree) + xmlXPathDebugObjMaxXSLTTree = + xmlXPathDebugObjCounterXSLTTree; + break; + default: + break; + } + if (! isCached) + xmlXPathDebugObjTotalAll++; + xmlXPathDebugObjCounterAll++; + if (xmlXPathDebugObjCounterAll > + xmlXPathDebugObjMaxAll) + xmlXPathDebugObjMaxAll = + xmlXPathDebugObjCounterAll; +} + +static void +xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt, + xmlXPathObjectType objType) +{ + int isCached = 0; + + if (ctxt != NULL) { + if (ctxt->cache != NULL) { + xmlXPathContextCachePtr cache = + (xmlXPathContextCachePtr) ctxt->cache; + + isCached = 1; + + cache->dbgCachedAll++; + switch (objType) { + case XPATH_UNDEFINED: + cache->dbgCachedUndefined++; + break; + case XPATH_NODESET: + cache->dbgCachedNodeset++; + break; + case XPATH_BOOLEAN: + cache->dbgCachedBool++; + break; + case XPATH_NUMBER: + cache->dbgCachedNumber++; + break; + case XPATH_STRING: + cache->dbgCachedString++; + break; + case XPATH_POINT: + cache->dbgCachedPoint++; + break; + case XPATH_RANGE: + cache->dbgCachedRange++; + break; + case XPATH_LOCATIONSET: + cache->dbgCachedLocset++; + break; + case XPATH_USERS: + cache->dbgCachedUsers++; + break; + case XPATH_XSLT_TREE: + cache->dbgCachedXSLTTree++; + break; + default: + break; + } + + } + } + switch (objType) { + case XPATH_UNDEFINED: + xmlXPathDebugObjCounterUndefined--; + break; + case XPATH_NODESET: + xmlXPathDebugObjCounterNodeset--; + break; + case XPATH_BOOLEAN: + xmlXPathDebugObjCounterBool--; + break; + case XPATH_NUMBER: + xmlXPathDebugObjCounterNumber--; + break; + case XPATH_STRING: + xmlXPathDebugObjCounterString--; + break; + case XPATH_POINT: + xmlXPathDebugObjCounterPoint--; + break; + case XPATH_RANGE: + xmlXPathDebugObjCounterRange--; + break; + case XPATH_LOCATIONSET: + xmlXPathDebugObjCounterLocset--; + break; + case XPATH_USERS: + xmlXPathDebugObjCounterUsers--; + break; + case XPATH_XSLT_TREE: + xmlXPathDebugObjCounterXSLTTree--; + break; + default: + break; + } + xmlXPathDebugObjCounterAll--; +} + +/* REVISIT TODO: Make this static when committing */ +static void +xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt) +{ + int reqAll, reqNodeset, reqString, reqBool, reqNumber, + reqXSLTTree, reqUndefined; + int caAll = 0, caNodeset = 0, caString = 0, caBool = 0, + caNumber = 0, caXSLTTree = 0, caUndefined = 0; + int reAll = 0, reNodeset = 0, reString = 0, reBool = 0, + reNumber = 0, reXSLTTree = 0, reUndefined = 0; + int leftObjs = xmlXPathDebugObjCounterAll; + + reqAll = xmlXPathDebugObjTotalAll; + reqNodeset = xmlXPathDebugObjTotalNodeset; + reqString = xmlXPathDebugObjTotalString; + reqBool = xmlXPathDebugObjTotalBool; + reqNumber = xmlXPathDebugObjTotalNumber; + reqXSLTTree = xmlXPathDebugObjTotalXSLTTree; + reqUndefined = xmlXPathDebugObjTotalUndefined; + + printf("# XPath object usage:\n"); + + if (ctxt != NULL) { + if (ctxt->cache != NULL) { + xmlXPathContextCachePtr cache = + (xmlXPathContextCachePtr) ctxt->cache; + + reAll = cache->dbgReusedAll; + reqAll += reAll; + reNodeset = cache->dbgReusedNodeset; + reqNodeset += reNodeset; + reString = cache->dbgReusedString; + reqString += reString; + reBool = cache->dbgReusedBool; + reqBool += reBool; + reNumber = cache->dbgReusedNumber; + reqNumber += reNumber; + reXSLTTree = cache->dbgReusedXSLTTree; + reqXSLTTree += reXSLTTree; + reUndefined = cache->dbgReusedUndefined; + reqUndefined += reUndefined; + + caAll = cache->dbgCachedAll; + caBool = cache->dbgCachedBool; + caNodeset = cache->dbgCachedNodeset; + caString = cache->dbgCachedString; + caNumber = cache->dbgCachedNumber; + caXSLTTree = cache->dbgCachedXSLTTree; + caUndefined = cache->dbgCachedUndefined; + + if (cache->nodesetObjs) + leftObjs -= cache->nodesetObjs->number; + if (cache->stringObjs) + leftObjs -= cache->stringObjs->number; + if (cache->booleanObjs) + leftObjs -= cache->booleanObjs->number; + if (cache->numberObjs) + leftObjs -= cache->numberObjs->number; + if (cache->miscObjs) + leftObjs -= cache->miscObjs->number; + } + } + + printf("# all\n"); + printf("# total : %d\n", reqAll); + printf("# left : %d\n", leftObjs); + printf("# created: %d\n", xmlXPathDebugObjTotalAll); + printf("# reused : %d\n", reAll); + printf("# max : %d\n", xmlXPathDebugObjMaxAll); + + printf("# node-sets\n"); + printf("# total : %d\n", reqNodeset); + printf("# created: %d\n", xmlXPathDebugObjTotalNodeset); + printf("# reused : %d\n", reNodeset); + printf("# max : %d\n", xmlXPathDebugObjMaxNodeset); + + printf("# strings\n"); + printf("# total : %d\n", reqString); + printf("# created: %d\n", xmlXPathDebugObjTotalString); + printf("# reused : %d\n", reString); + printf("# max : %d\n", xmlXPathDebugObjMaxString); + + printf("# booleans\n"); + printf("# total : %d\n", reqBool); + printf("# created: %d\n", xmlXPathDebugObjTotalBool); + printf("# reused : %d\n", reBool); + printf("# max : %d\n", xmlXPathDebugObjMaxBool); + + printf("# numbers\n"); + printf("# total : %d\n", reqNumber); + printf("# created: %d\n", xmlXPathDebugObjTotalNumber); + printf("# reused : %d\n", reNumber); + printf("# max : %d\n", xmlXPathDebugObjMaxNumber); + + printf("# XSLT result tree fragments\n"); + printf("# total : %d\n", reqXSLTTree); + printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree); + printf("# reused : %d\n", reXSLTTree); + printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree); + + printf("# undefined\n"); + printf("# total : %d\n", reqUndefined); + printf("# created: %d\n", xmlXPathDebugObjTotalUndefined); + printf("# reused : %d\n", reUndefined); + printf("# max : %d\n", xmlXPathDebugObjMaxUndefined); + +} + +#endif /* XP_DEBUG_OBJ_USAGE */ + +#endif /* LIBXML_DEBUG_ENABLED */ + +/************************************************************************ + * * + * XPath object caching * + * * + ************************************************************************/ + +/** + * xmlXPathNewCache: + * + * Create a new object cache + * + * Returns the xmlXPathCache just allocated. + */ +static xmlXPathContextCachePtr +xmlXPathNewCache(void) +{ + xmlXPathContextCachePtr ret; + + ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache)); + if (ret == NULL) { + xmlXPathErrMemory(NULL, "creating object cache\n"); + return(NULL); + } + memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache)); + ret->maxNodeset = 100; + ret->maxString = 100; + ret->maxBoolean = 100; + ret->maxNumber = 100; + ret->maxMisc = 100; + return(ret); +} + +static void +xmlXPathCacheFreeObjectList(xmlPointerListPtr list) +{ + int i; + xmlXPathObjectPtr obj; + + if (list == NULL) + return; + + 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); + } + xmlFree(obj); +#ifdef XP_DEBUG_OBJ_USAGE + xmlXPathDebugObjCounterAll--; +#endif + } + xmlPointerListFree(list); +} + +static void +xmlXPathFreeCache(xmlXPathContextCachePtr cache) +{ + if (cache == NULL) + 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); +} + +/** + * xmlXPathContextSetCache: + * + * @ctxt: the XPath context + * @active: enables/disables (creates/frees) the cache + * @value: a value with semantics dependant on @options + * @options: options (currently only the value 0 is used) + * + * Creates/frees an object cache on the XPath context. + * If activates XPath objects (xmlXPathObject) will be cached internally + * to be reused. + * @options: + * 0: This will set the XPath object caching: + * @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). + * Other values for @options have currently no effect. + * + * Returns 0 if the setting succeeded, and -1 on API or internal errors. + */ +int +xmlXPathContextSetCache(xmlXPathContextPtr ctxt, + int active, + int value, + int options) +{ + if (ctxt == NULL) + return(-1); + if (active) { + xmlXPathContextCachePtr cache; + + if (ctxt->cache == NULL) { + ctxt->cache = xmlXPathNewCache(); + if (ctxt->cache == NULL) + 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) { + xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache); + ctxt->cache = NULL; + } + return(0); +} + +/** + * xmlXPathCacheWrapNodeSet: + * @ctxt: the XPath context + * @val: the NodePtr value + * + * This is the cached version of xmlXPathWrapNodeSet(). + * Wrap the Nodeset @val in a new xmlXPathObjectPtr + * + * Returns the created or reused object. + */ +static xmlXPathObjectPtr +xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val) +{ + 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]; + ret->type = XPATH_NODESET; + ret->nodesetval = val; +#ifdef XP_DEBUG_OBJ_USAGE + xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); +#endif + return(ret); + } + } + + return(xmlXPathWrapNodeSet(val)); + +} + +/** + * xmlXPathCacheWrapString: + * @ctxt: the XPath context + * @val: the xmlChar * value + * + * This is the cached version of xmlXPathWrapString(). + * Wraps the @val string into an XPath object. + * + * Returns the created or reused object. + */ +static xmlXPathObjectPtr +xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val) +{ + 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; +#ifdef XP_DEBUG_OBJ_USAGE + xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); +#endif + 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]; + + ret->type = XPATH_STRING; + ret->stringval = val; +#ifdef XP_DEBUG_OBJ_USAGE + xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); +#endif + return(ret); + } + } + return(xmlXPathWrapString(val)); +} + +/** + * xmlXPathCacheNewNodeSet: + * @ctxt: the XPath context + * @val: the NodePtr value + * + * This is the cached version of xmlXPathNewNodeSet(). + * Acquire an xmlXPathObjectPtr of type NodeSet and initialize + * it with the single Node @val + * + * Returns the created or reused object. + */ +static xmlXPathObjectPtr +xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val) +{ + if ((ctxt != NULL) && (ctxt->cache)) { + xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache; + + if ((cache->nodesetObjs != NULL) && + (cache->nodesetObjs->number != 0)) + { + xmlXPathObjectPtr ret; + /* + * Use the nodset-cache. + */ + ret = (xmlXPathObjectPtr) + cache->nodesetObjs->items[--cache->nodesetObjs->number]; + ret->type = XPATH_NODESET; + ret->boolval = 0; + if (val) { + if ((ret->nodesetval->nodeMax == 0) || + (val->type == XML_NAMESPACE_DECL)) + { + xmlXPathNodeSetAddUnique(ret->nodesetval, val); + } else { + ret->nodesetval->nodeTab[0] = val; + ret->nodesetval->nodeNr = 1; + } + } +#ifdef XP_DEBUG_OBJ_USAGE + xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); +#endif + 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]; + + ret->type = XPATH_NODESET; + ret->boolval = 0; + ret->nodesetval = xmlXPathNodeSetCreate(val); +#ifdef XP_DEBUG_OBJ_USAGE + xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET); +#endif + return(ret); + } + } + return(xmlXPathNewNodeSet(val)); +} + +/** + * xmlXPathCacheNewCString: + * @ctxt: the XPath context + * @val: the char * value + * + * This is the cached version of xmlXPathNewCString(). + * Acquire an xmlXPathObjectPtr of type string and of value @val + * + * Returns the created or reused object. + */ +static xmlXPathObjectPtr +xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val) +{ + if ((ctxt != NULL) && (ctxt->cache)) { + 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 = xmlStrdup(BAD_CAST val); +#ifdef XP_DEBUG_OBJ_USAGE + xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); +#endif + return(ret); + } else if ((cache->miscObjs != NULL) && + (cache->miscObjs->number != 0)) + { + xmlXPathObjectPtr ret; + + ret = (xmlXPathObjectPtr) + cache->miscObjs->items[--cache->miscObjs->number]; + + ret->type = XPATH_STRING; + ret->stringval = xmlStrdup(BAD_CAST val); +#ifdef XP_DEBUG_OBJ_USAGE + xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); +#endif + return(ret); + } + } + return(xmlXPathNewCString(val)); +} + +/** + * xmlXPathCacheNewString: + * @ctxt: the XPath context + * @val: the xmlChar * value + * + * This is the cached version of xmlXPathNewString(). + * Acquire an xmlXPathObjectPtr of type string and of value @val + * + * Returns the created or reused object. + */ +static xmlXPathObjectPtr +xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val) +{ + if ((ctxt != NULL) && (ctxt->cache)) { + 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; + if (val != NULL) + ret->stringval = xmlStrdup(val); + else + ret->stringval = xmlStrdup((const xmlChar *)""); +#ifdef XP_DEBUG_OBJ_USAGE + xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); +#endif + return(ret); + } else if ((cache->miscObjs != NULL) && + (cache->miscObjs->number != 0)) + { + xmlXPathObjectPtr ret; + + ret = (xmlXPathObjectPtr) + cache->miscObjs->items[--cache->miscObjs->number]; + + ret->type = XPATH_STRING; + if (val != NULL) + ret->stringval = xmlStrdup(val); + else + ret->stringval = xmlStrdup((const xmlChar *)""); +#ifdef XP_DEBUG_OBJ_USAGE + xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING); +#endif + return(ret); + } + } + return(xmlXPathNewString(val)); +} + +/** + * xmlXPathCacheNewBoolean: + * @ctxt: the XPath context + * @val: the boolean value + * + * This is the cached version of xmlXPathNewBoolean(). + * Acquires an xmlXPathObjectPtr of type boolean and of value @val + * + * Returns the created or reused object. + */ +static xmlXPathObjectPtr +xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, 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); +#ifdef XP_DEBUG_OBJ_USAGE + xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN); +#endif + return(ret); + } else if ((cache->miscObjs != NULL) && + (cache->miscObjs->number != 0)) + { + xmlXPathObjectPtr ret; + + ret = (xmlXPathObjectPtr) + cache->miscObjs->items[--cache->miscObjs->number]; + + ret->type = XPATH_BOOLEAN; + ret->boolval = (val != 0); +#ifdef XP_DEBUG_OBJ_USAGE + xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN); +#endif + return(ret); + } + } + return(xmlXPathNewBoolean(val)); +} + +/** + * xmlXPathCacheNewFloat: + * @ctxt: the XPath context + * @val: the double value + * + * This is the cached version of xmlXPathNewFloat(). + * Acquires an xmlXPathObjectPtr of type double and of value @val + * + * Returns the created or reused object. + */ +static xmlXPathObjectPtr +xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, 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; +#ifdef XP_DEBUG_OBJ_USAGE + xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER); +#endif + return(ret); + } else if ((cache->miscObjs != NULL) && + (cache->miscObjs->number != 0)) + { + xmlXPathObjectPtr ret; + + ret = (xmlXPathObjectPtr) + cache->miscObjs->items[--cache->miscObjs->number]; + + ret->type = XPATH_NUMBER; + ret->floatval = val; +#ifdef XP_DEBUG_OBJ_USAGE + xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER); +#endif + 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: +#ifdef DEBUG_EXPR + xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n"); +#endif + 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: + case XPATH_POINT: + case XPATH_RANGE: + case XPATH_LOCATIONSET: + TODO; + break; + } + xmlXPathReleaseObject(ctxt, val); + if (res == NULL) + return(xmlXPathCacheNewCString(ctxt, "")); + return(xmlXPathCacheWrapString(ctxt, res)); +} + +/** + * xmlXPathCacheObjectCopy: + * @ctxt: the XPath context + * @val: the original object + * + * This is the cached version of xmlXPathObjectCopy(). + * Acquire a copy of a given object + * + * Returns a created or reused created object. + */ +static xmlXPathObjectPtr +xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) +{ + if (val == NULL) + return(NULL); + + if (XP_HAS_CACHE(ctxt)) { + switch (val->type) { + case XPATH_NODESET: + return(xmlXPathCacheWrapNodeSet(ctxt, + xmlXPathNodeSetMerge(NULL, val->nodesetval))); + case XPATH_STRING: + return(xmlXPathCacheNewString(ctxt, val->stringval)); + case XPATH_BOOLEAN: + return(xmlXPathCacheNewBoolean(ctxt, val->boolval)); + case XPATH_NUMBER: + return(xmlXPathCacheNewFloat(ctxt, 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); + return(ret); +} + +/** + * xmlXPathCacheConvertNumber: + * @ctxt: the XPath context + * @val: an XPath object + * + * This is the cached version of xmlXPathConvertNumber(). + * Converts an existing object to its number() equivalent + * + * Returns a created or reused object, the old one is freed (or the operation + * is done directly on @val) + */ +static xmlXPathObjectPtr +xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { + xmlXPathObjectPtr ret; + + if (val == NULL) + return(xmlXPathCacheNewFloat(ctxt, 0.0)); + if (val->type == XPATH_NUMBER) + return(val); + ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val)); + xmlXPathReleaseObject(ctxt, val); + return(ret); +} + +/************************************************************************ + * * + * Parser stacks related functions and macros * + * * + ************************************************************************/ + +/** + * xmlXPathSetFrame: + * @ctxt: an XPath parser context + * + * Set the callee evaluation frame + * + * Returns the previous frame value to be restored once done + */ +static int +xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) { + int ret; + + if (ctxt == NULL) + return(0); + ret = ctxt->valueFrame; + ctxt->valueFrame = ctxt->valueNr; + return(ret); +} + +/** + * xmlXPathPopFrame: + * @ctxt: an XPath parser context + * @frame: the previous frame value + * + * Remove the callee evaluation frame + */ +static void +xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) { + if (ctxt == NULL) + return; + if (ctxt->valueNr < ctxt->valueFrame) { + xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR); + } + ctxt->valueFrame = frame; +} + +/** + * valuePop: + * @ctxt: an XPath evaluation context + * + * Pops the top XPath object from the value stack + * + * Returns the XPath object just removed + */ +xmlXPathObjectPtr +valuePop(xmlXPathParserContextPtr ctxt) +{ + xmlXPathObjectPtr ret; + + if ((ctxt == NULL) || (ctxt->valueNr <= 0)) + return (NULL); + + if (ctxt->valueNr <= ctxt->valueFrame) { + xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR); + return (NULL); + } + + ctxt->valueNr--; + if (ctxt->valueNr > 0) + ctxt->value = ctxt->valueTab[ctxt->valueNr - 1]; + else + ctxt->value = NULL; + ret = ctxt->valueTab[ctxt->valueNr]; + ctxt->valueTab[ctxt->valueNr] = NULL; + return (ret); +} +/** + * valuePush: + * @ctxt: an XPath evaluation context + * @value: the XPath object + * + * Pushes a new XPath object on top of the value stack + * + * returns the number of items on the value stack + */ +int +valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value) +{ + if ((ctxt == NULL) || (value == NULL)) return(-1); + if (ctxt->valueNr >= ctxt->valueMax) { + xmlXPathObjectPtr *tmp; + + tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab, + 2 * ctxt->valueMax * + sizeof(ctxt->valueTab[0])); + if (tmp == NULL) { + xmlGenericError(xmlGenericErrorContext, "realloc failed !\n"); + ctxt->error = XPATH_MEMORY_ERROR; + return (0); + } + ctxt->valueMax *= 2; + ctxt->valueTab = tmp; + } + ctxt->valueTab[ctxt->valueNr] = value; + ctxt->value = value; + return (ctxt->valueNr++); +} + +/** + * xmlXPathPopBoolean: + * @ctxt: an XPath parser context + * + * Pops a boolean from the stack, handling conversion if needed. + * Check error with #xmlXPathCheckError. + * + * Returns the boolean + */ +int +xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) { + xmlXPathObjectPtr obj; + int ret; + + obj = valuePop(ctxt); + if (obj == NULL) { + xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); + return(0); + } + if (obj->type != XPATH_BOOLEAN) + ret = xmlXPathCastToBoolean(obj); + else + ret = obj->boolval; + xmlXPathReleaseObject(ctxt->context, obj); + return(ret); +} + +/** + * xmlXPathPopNumber: + * @ctxt: an XPath parser context + * + * Pops a number from the stack, handling conversion if needed. + * Check error with #xmlXPathCheckError. + * + * Returns the number + */ +double +xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) { + xmlXPathObjectPtr obj; + double ret; + + obj = valuePop(ctxt); + if (obj == NULL) { + xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); + return(0); + } + if (obj->type != XPATH_NUMBER) + ret = xmlXPathCastToNumber(obj); + else + ret = obj->floatval; + xmlXPathReleaseObject(ctxt->context, obj); + return(ret); +} + +/** + * xmlXPathPopString: + * @ctxt: an XPath parser context + * + * Pops a string from the stack, handling conversion if needed. + * Check error with #xmlXPathCheckError. + * + * Returns the string + */ +xmlChar * +xmlXPathPopString (xmlXPathParserContextPtr ctxt) { + xmlXPathObjectPtr obj; + xmlChar * ret; + + obj = valuePop(ctxt); + if (obj == NULL) { + 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; + xmlXPathReleaseObject(ctxt->context, obj); + return(ret); +} + +/** + * xmlXPathPopNodeSet: + * @ctxt: an XPath parser context + * + * Pops a node-set from the stack, handling conversion if needed. + * Check error with #xmlXPathCheckError. + * + * Returns the node-set + */ +xmlNodeSetPtr +xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) { + xmlXPathObjectPtr obj; + xmlNodeSetPtr ret; + + if (ctxt == NULL) return(NULL); + if (ctxt->value == NULL) { + xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); + return(NULL); + } + if (!xmlXPathStackIsNodeSet(ctxt)) { + xmlXPathSetTypeError(ctxt); + return(NULL); + } + obj = valuePop(ctxt); + ret = obj->nodesetval; +#if 0 + /* to fix memory leak of not clearing obj->user */ + if (obj->boolval && obj->user != NULL) + xmlFreeNodeList((xmlNodePtr) obj->user); +#endif + obj->nodesetval = NULL; + xmlXPathReleaseObject(ctxt->context, obj); + return(ret); +} + +/** + * xmlXPathPopExternal: + * @ctxt: an XPath parser context + * + * Pops an external object from the stack, handling conversion if needed. + * Check error with #xmlXPathCheckError. + * + * Returns the object + */ +void * +xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) { + xmlXPathObjectPtr obj; + void * ret; + + if ((ctxt == NULL) || (ctxt->value == NULL)) { + xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); + return(NULL); + } + if (ctxt->value->type != XPATH_USERS) { + xmlXPathSetTypeError(ctxt); + return(NULL); + } + obj = valuePop(ctxt); + ret = obj->user; + obj->user = NULL; + xmlXPathReleaseObject(ctxt->context, obj); + return(ret); +} + +/* + * Macros for accessing the content. Those should be used only by the parser, + * and not exported. + * + * Dirty macros, i.e. one need to make assumption on the context to use them + * + * CUR_PTR return the current pointer to the xmlChar to be parsed. + * CUR returns the current xmlChar value, i.e. a 8 bit value + * in ISO-Latin or UTF-8. + * This should be used internally by the parser + * only to compare to ASCII values otherwise it would break when + * running with UTF-8 encoding. + * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only + * to compare on ASCII based substring. + * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined + * strings within the parser. + * CURRENT Returns the current char value, with the full decoding of + * UTF-8 if we are using this mode. It returns an int. + * NEXT Skip to the next character, this does the proper decoding + * in UTF-8 mode. It also pop-up unfinished entities on the fly. + * It returns the pointer to the current xmlChar. + */ + +#define CUR (*ctxt->cur) +#define SKIP(val) ctxt->cur += (val) +#define NXT(val) ctxt->cur[(val)] +#define CUR_PTR ctxt->cur +#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l) + +#define COPY_BUF(l,b,i,v) \ + if (l == 1) b[i++] = (xmlChar) v; \ + else i += xmlCopyChar(l,&b[i],v) + +#define NEXTL(l) ctxt->cur += l + +#define SKIP_BLANKS \ + while (IS_BLANK_CH(*(ctxt->cur))) NEXT + +#define CURRENT (*ctxt->cur) +#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur) + + +#ifndef DBL_DIG +#define DBL_DIG 16 +#endif +#ifndef DBL_EPSILON +#define DBL_EPSILON 1E-9 +#endif + +#define UPPER_DOUBLE 1E9 +#define LOWER_DOUBLE 1E-5 +#define LOWER_DOUBLE_EXP 5 + +#define INTEGER_DIGITS DBL_DIG +#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP)) +#define EXPONENT_DIGITS (3 + 2) + +/** + * xmlXPathFormatNumber: + * @number: number to format + * @buffer: output buffer + * @buffersize: size of output buffer + * + * Convert the number into a string representation. + */ +static void +xmlXPathFormatNumber(double number, char buffer[], int buffersize) +{ + switch (xmlXPathIsInf(number)) { + case 1: + if (buffersize > (int)sizeof("Infinity")) + snprintf(buffer, buffersize, "Infinity"); + break; + case -1: + if (buffersize > (int)sizeof("-Infinity")) + snprintf(buffer, buffersize, "-Infinity"); + break; + default: + if (xmlXPathIsNaN(number)) { + if (buffersize > (int)sizeof("NaN")) + snprintf(buffer, buffersize, "NaN"); + } else if (number == 0 && xmlXPathGetSign(number) != 0) { + snprintf(buffer, buffersize, "0"); + } else if (number == ((int) number)) { + char work[30]; + char *ptr, *cur; + int value = (int) number; + + ptr = &buffer[0]; + if (value == 0) { + *ptr++ = '0'; + } else { + snprintf(work, 29, "%d", value); + cur = &work[0]; + while ((*cur) && (ptr - buffer < buffersize)) { + *ptr++ = *cur++; + } + } + if (ptr - buffer < buffersize) { + *ptr = 0; + } else if (buffersize > 0) { + ptr--; + *ptr = 0; + } + } else { + /* + For the dimension of work, + DBL_DIG is number of significant digits + EXPONENT is only needed for "scientific notation" + 3 is sign, decimal point, and terminating zero + LOWER_DOUBLE_EXP is max number of leading zeroes in fraction + Note that this dimension is slightly (a few characters) + larger than actually necessary. + */ + char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP]; + int integer_place, fraction_place; + char *ptr; + char *after_fraction; + double absolute_value; + int size; + + absolute_value = fabs(number); + + /* + * First choose format - scientific or regular floating point. + * In either case, result is in work, and after_fraction points + * just past the fractional part. + */ + if ( ((absolute_value > UPPER_DOUBLE) || + (absolute_value < LOWER_DOUBLE)) && + (absolute_value != 0.0) ) { + /* Use scientific notation */ + integer_place = DBL_DIG + EXPONENT_DIGITS + 1; + fraction_place = DBL_DIG - 1; + size = snprintf(work, sizeof(work),"%*.*e", + integer_place, fraction_place, number); + while ((size > 0) && (work[size] != 'e')) size--; + + } + else { + /* Use regular notation */ + if (absolute_value > 0.0) { + integer_place = (int)log10(absolute_value); + if (integer_place > 0) + fraction_place = DBL_DIG - integer_place - 1; + else + fraction_place = DBL_DIG - integer_place; + } else { + fraction_place = 1; + } + size = snprintf(work, sizeof(work), "%0.*f", + fraction_place, number); + } + + /* Remove fractional trailing zeroes */ + after_fraction = work + size; + ptr = after_fraction; + while (*(--ptr) == '0') + ; + if (*ptr != '.') + ptr++; + while ((*ptr++ = *after_fraction++) != 0); + + /* Finally copy result back to caller */ + size = strlen(work) + 1; + if (size > buffersize && buffersize <= (int)sizeof(work)) { + work[buffersize - 1] = 0; + size = buffersize; + } + memmove(buffer, work, size); + } + break; + } +} + + +/************************************************************************ + * * + * Routines to handle NodeSets * + * * + ************************************************************************/ + +/** + * xmlXPathOrderDocElems: + * @doc: an input document + * + * Call this routine to speed up XPath computation on static documents. + * This stamps all the element nodes with the document order + * Like for line information, the order is kept in the element->content + * field, the value stored is actually - the node number (starting at -1) + * to be able to differentiate from line numbers. + * + * Returns the number of elements found in the document or -1 in case + * of error. + */ +long +xmlXPathOrderDocElems(xmlDocPtr doc) { + long count = 0; + xmlNodePtr cur; + + if (doc == NULL) + return(-1); + cur = doc->children; + while (cur != NULL) { + if (cur->type == XML_ELEMENT_NODE) { + cur->content = (void *) (-(++count)); + if (cur->children != NULL) { + cur = cur->children; + continue; + } + } + if (cur->next != NULL) { + cur = cur->next; + continue; + } + do { + cur = cur->parent; + if (cur == NULL) + break; + if (cur == (xmlNodePtr) doc) { + cur = NULL; + break; + } + if (cur->next != NULL) { + cur = cur->next; + break; + } + } while (cur != NULL); + } + return(count); +} + +/** + * xmlXPathCmpNodes: + * @node1: the first node + * @node2: the second node + * + * Compare two nodes w.r.t document order + * + * Returns -2 in case of error 1 if first point < second point, 0 if + * it's the same node, -1 otherwise + */ +int +xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) { + int depth1, depth2; + int attr1 = 0, attr2 = 0; + xmlNodePtr attrNode1 = NULL, attrNode2 = NULL; + xmlNodePtr cur, root; + + if ((node1 == NULL) || (node2 == NULL)) + return(-2); + /* + * a couple of optimizations which will avoid computations in most cases + */ + if (node1 == node2) /* trivial case */ + return(0); + if (node1->type == XML_ATTRIBUTE_NODE) { + attr1 = 1; + attrNode1 = node1; + node1 = node1->parent; + } + if (node2->type == XML_ATTRIBUTE_NODE) { + attr2 = 1; + attrNode2 = node2; + node2 = node2->parent; + } + if (node1 == node2) { + if (attr1 == attr2) { + /* not required, but we keep attributes in order */ + if (attr1 != 0) { + cur = attrNode2->prev; + while (cur != NULL) { + if (cur == attrNode1) + return (1); + cur = cur->prev; + } + return (-1); + } + return(0); + } + if (attr2 == 1) + return(1); + return(-1); + } + if ((node1->type == XML_NAMESPACE_DECL) || + (node2->type == XML_NAMESPACE_DECL)) + return(1); + if (node1 == node2->prev) + return(1); + if (node1 == node2->next) + return(-1); + + /* + * Speedup using document order if availble. + */ + if ((node1->type == XML_ELEMENT_NODE) && + (node2->type == XML_ELEMENT_NODE) && + (0 > (long) node1->content) && + (0 > (long) node2->content) && + (node1->doc == node2->doc)) { + long l1, l2; + + l1 = -((long) node1->content); + l2 = -((long) node2->content); + if (l1 < l2) + return(1); + if (l1 > l2) + return(-1); + } + + /* + * compute depth to root + */ + for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) { + if (cur == node1) + return(1); + depth2++; + } + root = cur; + for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) { + if (cur == node2) + return(-1); + depth1++; + } + /* + * Distinct document (or distinct entities :-( ) case. + */ + if (root != cur) { + return(-2); + } + /* + * get the nearest common ancestor. + */ + while (depth1 > depth2) { + depth1--; + node1 = node1->parent; + } + while (depth2 > depth1) { + depth2--; + node2 = node2->parent; + } + while (node1->parent != node2->parent) { + node1 = node1->parent; + node2 = node2->parent; + /* should not happen but just in case ... */ + if ((node1 == NULL) || (node2 == NULL)) + return(-2); + } + /* + * Find who's first. + */ + if (node1 == node2->prev) + return(1); + if (node1 == node2->next) + return(-1); + /* + * Speedup using document order if availble. + */ + if ((node1->type == XML_ELEMENT_NODE) && + (node2->type == XML_ELEMENT_NODE) && + (0 > (long) node1->content) && + (0 > (long) node2->content) && + (node1->doc == node2->doc)) { + long l1, l2; + + l1 = -((long) node1->content); + l2 = -((long) node2->content); + if (l1 < l2) + return(1); + if (l1 > l2) + return(-1); + } + + for (cur = node1->next;cur != NULL;cur = cur->next) + if (cur == node2) + return(1); + return(-1); /* assume there is no sibling list corruption */ +} + +#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON +/** + * xmlXPathCmpNodesExt: + * @node1: the first node + * @node2: the second node + * + * Compare two nodes w.r.t document order. + * This one is optimized for handling of non-element nodes. + * + * Returns -2 in case of error 1 if first point < second point, 0 if + * it's the same node, -1 otherwise + */ +static int +xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) { + int depth1, depth2; + int misc = 0, precedence1 = 0, precedence2 = 0; + xmlNodePtr miscNode1 = NULL, miscNode2 = NULL; + xmlNodePtr cur, root; + long l1, l2; + + if ((node1 == NULL) || (node2 == NULL)) + return(-2); + + if (node1 == node2) + return(0); + + /* + * a couple of optimizations which will avoid computations in most cases + */ + switch (node1->type) { + case XML_ELEMENT_NODE: + if (node2->type == XML_ELEMENT_NODE) { + if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */ + (0 > (long) node2->content) && + (node1->doc == node2->doc)) + { + l1 = -((long) node1->content); + l2 = -((long) node2->content); + if (l1 < l2) + return(1); + if (l1 > l2) + return(-1); + } else + goto turtle_comparison; + } + break; + case XML_ATTRIBUTE_NODE: + precedence1 = 1; /* element is owner */ + miscNode1 = node1; + node1 = node1->parent; + misc = 1; + break; + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: + case XML_COMMENT_NODE: + case XML_PI_NODE: { + miscNode1 = node1; + /* + * Find nearest element node. + */ + if (node1->prev != NULL) { + do { + node1 = node1->prev; + if (node1->type == XML_ELEMENT_NODE) { + precedence1 = 3; /* element in prev-sibl axis */ + break; + } + if (node1->prev == NULL) { + precedence1 = 2; /* element is parent */ + /* + * URGENT TODO: Are there any cases, where the + * parent of such a node is not an element node? + */ + node1 = node1->parent; + break; + } + } while (1); + } else { + precedence1 = 2; /* element is parent */ + node1 = node1->parent; + } + if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) || + (0 <= (long) node1->content)) { + /* + * Fallback for whatever case. + */ + node1 = miscNode1; + precedence1 = 0; + } else + misc = 1; + } + break; + case XML_NAMESPACE_DECL: + /* + * TODO: why do we return 1 for namespace nodes? + */ + return(1); + default: + break; + } + switch (node2->type) { + case XML_ELEMENT_NODE: + break; + case XML_ATTRIBUTE_NODE: + precedence2 = 1; /* element is owner */ + miscNode2 = node2; + node2 = node2->parent; + misc = 1; + break; + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: + case XML_COMMENT_NODE: + case XML_PI_NODE: { + miscNode2 = node2; + if (node2->prev != NULL) { + do { + node2 = node2->prev; + if (node2->type == XML_ELEMENT_NODE) { + precedence2 = 3; /* element in prev-sibl axis */ + break; + } + if (node2->prev == NULL) { + precedence2 = 2; /* element is parent */ + node2 = node2->parent; + break; + } + } while (1); + } else { + precedence2 = 2; /* element is parent */ + node2 = node2->parent; + } + if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) || + (0 <= (long) node1->content)) + { + node2 = miscNode2; + precedence2 = 0; + } else + misc = 1; + } + break; + case XML_NAMESPACE_DECL: + return(1); + default: + break; + } + if (misc) { + if (node1 == node2) { + if (precedence1 == precedence2) { + /* + * The ugly case; but normally there aren't many + * adjacent non-element nodes around. + */ + cur = miscNode2->prev; + while (cur != NULL) { + if (cur == miscNode1) + return(1); + if (cur->type == XML_ELEMENT_NODE) + return(-1); + cur = cur->prev; + } + return (-1); + } else { + /* + * Evaluate based on higher precedence wrt to the element. + * TODO: This assumes attributes are sorted before content. + * Is this 100% correct? + */ + if (precedence1 < precedence2) + return(1); + else + return(-1); + } + } + /* + * Special case: One of the helper-elements is contained by the other. + * + * + * Text-1(precedence1 == 2) + * + * Text-6(precedence2 == 3) + * + */ + if ((precedence2 == 3) && (precedence1 > 1)) { + cur = node1->parent; + while (cur) { + if (cur == node2) + return(1); + cur = cur->parent; + } + } + if ((precedence1 == 3) && (precedence2 > 1)) { + cur = node2->parent; + while (cur) { + if (cur == node1) + return(-1); + cur = cur->parent; + } + } + } + + /* + * Speedup using document order if availble. + */ + if ((node1->type == XML_ELEMENT_NODE) && + (node2->type == XML_ELEMENT_NODE) && + (0 > (long) node1->content) && + (0 > (long) node2->content) && + (node1->doc == node2->doc)) { + + l1 = -((long) node1->content); + l2 = -((long) node2->content); + if (l1 < l2) + return(1); + if (l1 > l2) + return(-1); + } + +turtle_comparison: + + if (node1 == node2->prev) + return(1); + if (node1 == node2->next) + return(-1); + /* + * compute depth to root + */ + for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) { + if (cur == node1) + return(1); + depth2++; + } + root = cur; + for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) { + if (cur == node2) + return(-1); + depth1++; + } + /* + * Distinct document (or distinct entities :-( ) case. + */ + if (root != cur) { + return(-2); + } + /* + * get the nearest common ancestor. + */ + while (depth1 > depth2) { + depth1--; + node1 = node1->parent; + } + while (depth2 > depth1) { + depth2--; + node2 = node2->parent; + } + while (node1->parent != node2->parent) { + node1 = node1->parent; + node2 = node2->parent; + /* should not happen but just in case ... */ + if ((node1 == NULL) || (node2 == NULL)) + return(-2); + } + /* + * Find who's first. + */ + if (node1 == node2->prev) + return(1); + if (node1 == node2->next) + return(-1); + /* + * Speedup using document order if availble. + */ + if ((node1->type == XML_ELEMENT_NODE) && + (node2->type == XML_ELEMENT_NODE) && + (0 > (long) node1->content) && + (0 > (long) node2->content) && + (node1->doc == node2->doc)) { + + l1 = -((long) node1->content); + l2 = -((long) node2->content); + if (l1 < l2) + return(1); + if (l1 > l2) + return(-1); + } + + for (cur = node1->next;cur != NULL;cur = cur->next) + if (cur == node2) + return(1); + return(-1); /* assume there is no sibling list corruption */ +} +#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */ + +/** + * xmlXPathNodeSetSort: + * @set: the node set + * + * Sort the node set in document order + */ +void +xmlXPathNodeSetSort(xmlNodeSetPtr set) { + int i, j, incr, len; + xmlNodePtr tmp; + + if (set == NULL) + return; + + /* Use Shell's sort to sort the node-set */ + len = set->nodeNr; + for (incr = len / 2; incr > 0; incr /= 2) { + for (i = incr; i < len; i++) { + j = i - incr; + while (j >= 0) { +#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON + if (xmlXPathCmpNodesExt(set->nodeTab[j], + set->nodeTab[j + incr]) == -1) +#else + if (xmlXPathCmpNodes(set->nodeTab[j], + set->nodeTab[j + incr]) == -1) +#endif + { + tmp = set->nodeTab[j]; + set->nodeTab[j] = set->nodeTab[j + incr]; + set->nodeTab[j + incr] = tmp; + j -= incr; + } else + break; + } + } + } +} + +#define XML_NODESET_DEFAULT 10 +/** + * xmlXPathNodeSetDupNs: + * @node: the parent node of the namespace XPath node + * @ns: the libxml namespace declaration node. + * + * Namespace node in libxml don't match the XPath semantic. In a node set + * the namespace nodes are duplicated and the next pointer is set to the + * parent node in the XPath semantic. + * + * Returns the newly created object. + */ +static xmlNodePtr +xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) { + xmlNsPtr cur; + + if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) + return(NULL); + if ((node == NULL) || (node->type == XML_NAMESPACE_DECL)) + return((xmlNodePtr) ns); + + /* + * Allocate a new Namespace and fill the fields. + */ + cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); + if (cur == NULL) { + xmlXPathErrMemory(NULL, "duplicating namespace\n"); + return(NULL); + } + memset(cur, 0, sizeof(xmlNs)); + cur->type = XML_NAMESPACE_DECL; + if (ns->href != NULL) + cur->href = xmlStrdup(ns->href); + if (ns->prefix != NULL) + cur->prefix = xmlStrdup(ns->prefix); + cur->next = (xmlNsPtr) node; + return((xmlNodePtr) cur); +} + +/** + * xmlXPathNodeSetFreeNs: + * @ns: the XPath namespace node found in a nodeset. + * + * Namespace nodes in libxml don't match the XPath semantic. In a node set + * the namespace nodes are duplicated and the next pointer is set to the + * parent node in the XPath semantic. Check if such a node needs to be freed + */ +void +xmlXPathNodeSetFreeNs(xmlNsPtr ns) { + if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) + return; + + if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) { + if (ns->href != NULL) + xmlFree((xmlChar *)ns->href); + if (ns->prefix != NULL) + xmlFree((xmlChar *)ns->prefix); + xmlFree(ns); + } +} + +/** + * xmlXPathNodeSetCreate: + * @val: an initial xmlNodePtr, or NULL + * + * Create a new xmlNodeSetPtr of type double and of value @val + * + * Returns the newly created object. + */ +xmlNodeSetPtr +xmlXPathNodeSetCreate(xmlNodePtr val) { + xmlNodeSetPtr ret; + + ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet)); + if (ret == NULL) { + xmlXPathErrMemory(NULL, "creating nodeset\n"); + return(NULL); + } + memset(ret, 0 , (size_t) 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); + } + memset(ret->nodeTab, 0 , + XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); + ret->nodeMax = XML_NODESET_DEFAULT; + if (val->type == XML_NAMESPACE_DECL) { + xmlNsPtr ns = (xmlNsPtr) val; + + ret->nodeTab[ret->nodeNr++] = + xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); + } else + ret->nodeTab[ret->nodeNr++] = val; + } + return(ret); +} + +/** + * xmlXPathNodeSetCreateSize: + * @size: the initial size of the set + * + * Create a new xmlNodeSetPtr of type double and of value @val + * + * Returns the newly created object. + */ +static xmlNodeSetPtr +xmlXPathNodeSetCreateSize(int size) { + xmlNodeSetPtr ret; + + ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet)); + if (ret == NULL) { + xmlXPathErrMemory(NULL, "creating nodeset\n"); + return(NULL); + } + memset(ret, 0 , (size_t) sizeof(xmlNodeSet)); + if (size < XML_NODESET_DEFAULT) + size = XML_NODESET_DEFAULT; + ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr)); + if (ret->nodeTab == NULL) { + xmlXPathErrMemory(NULL, "creating nodeset\n"); + xmlFree(ret); + return(NULL); + } + memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr)); + ret->nodeMax = size; + return(ret); +} + +/** + * xmlXPathNodeSetContains: + * @cur: the node-set + * @val: the node + * + * checks whether @cur contains @val + * + * Returns true (1) if @cur contains @val, false (0) otherwise + */ +int +xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) { + int i; + + if ((cur == NULL) || (val == NULL)) return(0); + if (val->type == XML_NAMESPACE_DECL) { + for (i = 0; i < cur->nodeNr; i++) { + if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) { + xmlNsPtr ns1, ns2; + + ns1 = (xmlNsPtr) val; + ns2 = (xmlNsPtr) cur->nodeTab[i]; + if (ns1 == ns2) + return(1); + if ((ns1->next != NULL) && (ns2->next == ns1->next) && + (xmlStrEqual(ns1->prefix, ns2->prefix))) + return(1); + } + } + } else { + for (i = 0; i < cur->nodeNr; i++) { + if (cur->nodeTab[i] == val) + return(1); + } + } + return(0); +} + +/** + * xmlXPathNodeSetAddNs: + * @cur: the initial node set + * @node: the hosting node + * @ns: a the namespace node + * + * add a new namespace node to an existing NodeSet + */ +void +xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) { + int i; + + + if ((cur == NULL) || (ns == NULL) || (node == NULL) || + (ns->type != XML_NAMESPACE_DECL) || + (node->type != XML_ELEMENT_NODE)) + return; + + /* @@ with_ns to check whether namespace nodes should be looked at @@ */ + /* + * prevent duplicates + */ + for (i = 0;i < cur->nodeNr;i++) { + if ((cur->nodeTab[i] != NULL) && + (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) && + (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) && + (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix))) + return; + } + + /* + * grow the nodeTab if needed + */ + if (cur->nodeMax == 0) { + cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * + sizeof(xmlNodePtr)); + if (cur->nodeTab == NULL) { + xmlXPathErrMemory(NULL, "growing nodeset\n"); + return; + } + memset(cur->nodeTab, 0 , + XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); + cur->nodeMax = XML_NODESET_DEFAULT; + } else if (cur->nodeNr == cur->nodeMax) { + xmlNodePtr *temp; + + temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 * + sizeof(xmlNodePtr)); + if (temp == NULL) { + xmlXPathErrMemory(NULL, "growing nodeset\n"); + return; + } + cur->nodeMax *= 2; + cur->nodeTab = temp; + } + cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns); +} + +/** + * xmlXPathNodeSetAdd: + * @cur: the initial node set + * @val: a new xmlNodePtr + * + * add a new xmlNodePtr to an existing NodeSet + */ +void +xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) { + int i; + + if ((cur == NULL) || (val == NULL)) return; + +#if 0 + if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' ')) + return; /* an XSLT fake node */ +#endif + + /* @@ with_ns to check whether namespace nodes should be looked at @@ */ + /* + * prevent duplcates + */ + for (i = 0;i < cur->nodeNr;i++) + if (cur->nodeTab[i] == val) return; + + /* + * grow the nodeTab if needed + */ + if (cur->nodeMax == 0) { + cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * + sizeof(xmlNodePtr)); + if (cur->nodeTab == NULL) { + xmlXPathErrMemory(NULL, "growing nodeset\n"); + return; + } + memset(cur->nodeTab, 0 , + XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); + cur->nodeMax = XML_NODESET_DEFAULT; + } else if (cur->nodeNr == cur->nodeMax) { + xmlNodePtr *temp; + + temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 * + sizeof(xmlNodePtr)); + if (temp == NULL) { + xmlXPathErrMemory(NULL, "growing nodeset\n"); + return; + } + cur->nodeMax *= 2; + cur->nodeTab = temp; + } + if (val->type == XML_NAMESPACE_DECL) { + xmlNsPtr ns = (xmlNsPtr) val; + + cur->nodeTab[cur->nodeNr++] = + xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); + } else + cur->nodeTab[cur->nodeNr++] = val; +} + +/** + * xmlXPathNodeSetAddUnique: + * @cur: the initial node set + * @val: a new xmlNodePtr + * + * add a new xmlNodePtr to an existing NodeSet, optimized version + * when we are sure the node is not already in the set. + */ +void +xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) { + if ((cur == NULL) || (val == NULL)) return; + +#if 0 + if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' ')) + return; /* an XSLT fake node */ +#endif + + /* @@ with_ns to check whether namespace nodes should be looked at @@ */ + /* + * grow the nodeTab if needed + */ + if (cur->nodeMax == 0) { + cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * + sizeof(xmlNodePtr)); + if (cur->nodeTab == NULL) { + xmlXPathErrMemory(NULL, "growing nodeset\n"); + return; + } + memset(cur->nodeTab, 0 , + XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); + cur->nodeMax = XML_NODESET_DEFAULT; + } else if (cur->nodeNr == cur->nodeMax) { + xmlNodePtr *temp; + + temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 * + sizeof(xmlNodePtr)); + if (temp == NULL) { + xmlXPathErrMemory(NULL, "growing nodeset\n"); + return; + } + cur->nodeTab = temp; + cur->nodeMax *= 2; + } + if (val->type == XML_NAMESPACE_DECL) { + xmlNsPtr ns = (xmlNsPtr) val; + + cur->nodeTab[cur->nodeNr++] = + xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); + } else + cur->nodeTab[cur->nodeNr++] = val; +} + +/** + * xmlXPathNodeSetMerge: + * @val1: the first NodeSet or NULL + * @val2: the second NodeSet + * + * Merges two nodesets, all nodes from @val2 are added to @val1 + * if @val1 is NULL, a new set is created and copied from @val2 + * + * Returns @val1 once extended or NULL in case of error. + */ +xmlNodeSetPtr +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 0 + /* + * TODO: The optimization won't work in every case, since + * those nasty namespace nodes need to be added with + * xmlXPathNodeSetDupNs() to the set; thus a pure + * memcpy is not possible. + * If there was a flag on the nodesetval, indicating that + * some temporary nodes are in, that would be helpfull. + */ + /* + * Optimization: Create an equally sized node-set + * and memcpy the content. + */ + val1 = xmlXPathNodeSetCreateSize(val2->nodeNr); + if (val1 == NULL) + return(NULL); + if (val2->nodeNr != 0) { + if (val2->nodeNr == 1) + *(val1->nodeTab) = *(val2->nodeTab); + else { + memcpy(val1->nodeTab, val2->nodeTab, + val2->nodeNr * sizeof(xmlNodePtr)); + } + val1->nodeNr = val2->nodeNr; + } + return(val1); +#endif + } + + /* @@ with_ns to check whether namespace nodes should be looked at @@ */ + initNr = val1->nodeNr; + + for (i = 0;i < val2->nodeNr;i++) { + n2 = val2->nodeTab[i]; + /* + * check against duplicates + */ + skip = 0; + for (j = 0; j < initNr; j++) { + n1 = val1->nodeTab[j]; + if (n1 == n2) { + skip = 1; + break; + } else if ((n1->type == XML_NAMESPACE_DECL) && + (n2->type == XML_NAMESPACE_DECL)) { + if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) && + (xmlStrEqual(((xmlNsPtr) n1)->prefix, + ((xmlNsPtr) n2)->prefix))) + { + skip = 1; + break; + } + } + } + if (skip) + continue; + + /* + * grow the nodeTab if needed + */ + if (val1->nodeMax == 0) { + val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * + sizeof(xmlNodePtr)); + if (val1->nodeTab == NULL) { + xmlXPathErrMemory(NULL, "merging nodeset\n"); + return(NULL); + } + memset(val1->nodeTab, 0 , + XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); + val1->nodeMax = XML_NODESET_DEFAULT; + } else if (val1->nodeNr == val1->nodeMax) { + xmlNodePtr *temp; + + temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 * + sizeof(xmlNodePtr)); + if (temp == NULL) { + xmlXPathErrMemory(NULL, "merging nodeset\n"); + return(NULL); + } + val1->nodeTab = temp; + val1->nodeMax *= 2; + } + if (n2->type == XML_NAMESPACE_DECL) { + xmlNsPtr ns = (xmlNsPtr) n2; + + val1->nodeTab[val1->nodeNr++] = + xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); + } else + val1->nodeTab[val1->nodeNr++] = n2; + } + + return(val1); +} + +#if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */ +/** + * xmlXPathNodeSetMergeUnique: + * @val1: the first NodeSet or NULL + * @val2: the second NodeSet + * + * Merges two nodesets, all nodes from @val2 are added to @val1 + * if @val1 is NULL, a new set is created and copied from @val2 + * + * Returns @val1 once extended or NULL in case of error. + */ +static xmlNodeSetPtr +xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) { + int i; + + if (val2 == NULL) return(val1); + if (val1 == NULL) { + val1 = xmlXPathNodeSetCreate(NULL); + } + if (val1 == NULL) + return (NULL); + + /* @@ with_ns to check whether namespace nodes should be looked at @@ */ + + for (i = 0;i < val2->nodeNr;i++) { + /* + * grow the nodeTab if needed + */ + if (val1->nodeMax == 0) { + val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * + sizeof(xmlNodePtr)); + if (val1->nodeTab == NULL) { + xmlXPathErrMemory(NULL, "merging nodeset\n"); + return(NULL); + } + memset(val1->nodeTab, 0 , + XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); + val1->nodeMax = XML_NODESET_DEFAULT; + } else if (val1->nodeNr == val1->nodeMax) { + xmlNodePtr *temp; + + val1->nodeMax *= 2; + temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * + sizeof(xmlNodePtr)); + if (temp == NULL) { + xmlXPathErrMemory(NULL, "merging nodeset\n"); + return(NULL); + } + val1->nodeTab = temp; + } + if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) { + xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i]; + + val1->nodeTab[val1->nodeNr++] = + xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); + } else + val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i]; + } + + return(val1); +} +#endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */ + +/** + * xmlXPathNodeSetMergeAndClear: + * @set1: the first NodeSet or NULL + * @set2: the second NodeSet + * @hasSet2NsNodes: 1 if set2 contains namespaces nodes + * + * Merges two nodesets, all nodes from @set2 are added to @set1 + * if @set1 is NULL, a new set is created and copied from @set2. + * Checks for duplicate nodes. Clears set2. + * + * Returns @set1 once extended or NULL in case of error. + */ +static xmlNodeSetPtr +xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2, + int hasNullEntries) +{ + if ((set1 == NULL) && (hasNullEntries == 0)) { + /* + * Note that doing a memcpy of the list, namespace nodes are + * just assigned to set1, since set2 is cleared anyway. + */ + set1 = xmlXPathNodeSetCreateSize(set2->nodeNr); + if (set1 == NULL) + return(NULL); + if (set2->nodeNr != 0) { + memcpy(set1->nodeTab, set2->nodeTab, + set2->nodeNr * sizeof(xmlNodePtr)); + set1->nodeNr = set2->nodeNr; + } + } else { + int i, j, initNbSet1; + xmlNodePtr n1, n2; + + if (set1 == NULL) + set1 = xmlXPathNodeSetCreate(NULL); + if (set1 == NULL) + return (NULL); + + initNbSet1 = set1->nodeNr; + for (i = 0;i < set2->nodeNr;i++) { + n2 = set2->nodeTab[i]; + /* + * Skip NULLed entries. + */ + if (n2 == NULL) + continue; + /* + * Skip duplicates. + */ + for (j = 0; j < initNbSet1; j++) { + n1 = set1->nodeTab[j]; + if (n1 == n2) { + goto skip_node; + } else if ((n1->type == XML_NAMESPACE_DECL) && + (n2->type == XML_NAMESPACE_DECL)) + { + if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) && + (xmlStrEqual(((xmlNsPtr) n1)->prefix, + ((xmlNsPtr) n2)->prefix))) + { + /* + * Free the namespace node. + */ + set2->nodeTab[i] = NULL; + xmlXPathNodeSetFreeNs((xmlNsPtr) n2); + goto skip_node; + } + } + } + /* + * grow the nodeTab if needed + */ + if (set1->nodeMax == 0) { + set1->nodeTab = (xmlNodePtr *) xmlMalloc( + XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); + if (set1->nodeTab == NULL) { + xmlXPathErrMemory(NULL, "merging nodeset\n"); + return(NULL); + } + memset(set1->nodeTab, 0, + XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); + set1->nodeMax = XML_NODESET_DEFAULT; + } else if (set1->nodeNr >= set1->nodeMax) { + xmlNodePtr *temp; + + temp = (xmlNodePtr *) xmlRealloc( + set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr)); + if (temp == NULL) { + xmlXPathErrMemory(NULL, "merging nodeset\n"); + return(NULL); + } + set1->nodeTab = temp; + set1->nodeMax *= 2; + } + if (n2->type == XML_NAMESPACE_DECL) { + xmlNsPtr ns = (xmlNsPtr) n2; + + set1->nodeTab[set1->nodeNr++] = + xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); + } else + set1->nodeTab[set1->nodeNr++] = n2; +skip_node: + {} + } + } + set2->nodeNr = 0; + return(set1); +} + +/** + * xmlXPathNodeSetMergeAndClearNoDupls: + * @set1: the first NodeSet or NULL + * @set2: the second NodeSet + * @hasSet2NsNodes: 1 if set2 contains namespaces nodes + * + * Merges two nodesets, all nodes from @set2 are added to @set1 + * if @set1 is NULL, a new set is created and copied from @set2. + * Doesn't chack for duplicate nodes. Clears set2. + * + * Returns @set1 once extended or NULL in case of error. + */ +static xmlNodeSetPtr +xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2, + int hasNullEntries) +{ + if (set2 == NULL) + return(set1); + if ((set1 == NULL) && (hasNullEntries == 0)) { + /* + * Note that doing a memcpy of the list, namespace nodes are + * just assigned to set1, since set2 is cleared anyway. + */ + set1 = xmlXPathNodeSetCreateSize(set2->nodeNr); + if (set1 == NULL) + return(NULL); + if (set2->nodeNr != 0) { + memcpy(set1->nodeTab, set2->nodeTab, + set2->nodeNr * sizeof(xmlNodePtr)); + set1->nodeNr = set2->nodeNr; + } + } else { + int i; + xmlNodePtr n2; + + if (set1 == NULL) + set1 = xmlXPathNodeSetCreate(NULL); + if (set1 == NULL) + return (NULL); + + for (i = 0;i < set2->nodeNr;i++) { + n2 = set2->nodeTab[i]; + /* + * Skip NULLed entries. + */ + if (n2 == NULL) + continue; + if (set1->nodeMax == 0) { + set1->nodeTab = (xmlNodePtr *) xmlMalloc( + XML_NODESET_DEFAULT * sizeof(xmlNodePtr)); + if (set1->nodeTab == NULL) { + xmlXPathErrMemory(NULL, "merging nodeset\n"); + return(NULL); + } + memset(set1->nodeTab, 0, + XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); + set1->nodeMax = XML_NODESET_DEFAULT; + } else if (set1->nodeNr >= set1->nodeMax) { + xmlNodePtr *temp; + + temp = (xmlNodePtr *) xmlRealloc( + set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr)); + if (temp == NULL) { + xmlXPathErrMemory(NULL, "merging nodeset\n"); + return(NULL); + } + set1->nodeTab = temp; + set1->nodeMax *= 2; + } + set1->nodeTab[set1->nodeNr++] = n2; + } + } + set2->nodeNr = 0; + return(set1); +} + +/** + * xmlXPathNodeSetDel: + * @cur: the initial node set + * @val: an xmlNodePtr + * + * Removes an xmlNodePtr from an existing NodeSet + */ +void +xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) { + int i; + + if (cur == NULL) return; + if (val == NULL) return; + + /* + * find node in nodeTab + */ + for (i = 0;i < cur->nodeNr;i++) + if (cur->nodeTab[i] == val) break; + + if (i >= cur->nodeNr) { /* not found */ +#ifdef DEBUG + xmlGenericError(xmlGenericErrorContext, + "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n", + val->name); +#endif + return; + } + if ((cur->nodeTab[i] != NULL) && + (cur->nodeTab[i]->type == XML_NAMESPACE_DECL)) + xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]); + cur->nodeNr--; + for (;i < cur->nodeNr;i++) + cur->nodeTab[i] = cur->nodeTab[i + 1]; + cur->nodeTab[cur->nodeNr] = NULL; +} + +/** + * xmlXPathNodeSetRemove: + * @cur: the initial node set + * @val: the index to remove + * + * Removes an entry from an existing NodeSet list. + */ +void +xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) { + if (cur == NULL) return; + if (val >= cur->nodeNr) return; + if ((cur->nodeTab[val] != NULL) && + (cur->nodeTab[val]->type == XML_NAMESPACE_DECL)) + xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]); + cur->nodeNr--; + for (;val < cur->nodeNr;val++) + cur->nodeTab[val] = cur->nodeTab[val + 1]; + cur->nodeTab[cur->nodeNr] = NULL; +} + +/** + * xmlXPathFreeNodeSet: + * @obj: the xmlNodeSetPtr to free + * + * Free the NodeSet compound (not the actual nodes !). + */ +void +xmlXPathFreeNodeSet(xmlNodeSetPtr obj) { + if (obj == NULL) return; + if (obj->nodeTab != NULL) { + int i; + + /* @@ with_ns to check whether namespace nodes should be looked at @@ */ + for (i = 0;i < obj->nodeNr;i++) + if ((obj->nodeTab[i] != NULL) && + (obj->nodeTab[i]->type == XML_NAMESPACE_DECL)) + xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]); + xmlFree(obj->nodeTab); + } + xmlFree(obj); +} + +/** + * xmlXPathNodeSetClear: + * @set: the node set to clear + * + * Clears the list from all temporary XPath objects (e.g. namespace nodes + * are feed), but does *not* free the list itself. Sets the length of the + * list to 0. + */ +static void +xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes) +{ + if ((set == NULL) || (set->nodeNr <= 0)) + return; + else if (hasNsNodes) { + int i; + xmlNodePtr node; + + for (i = 0; i < set->nodeNr; i++) { + node = set->nodeTab[i]; + if ((node != NULL) && + (node->type == XML_NAMESPACE_DECL)) + xmlXPathNodeSetFreeNs((xmlNsPtr) node); + } + } + set->nodeNr = 0; +} + +/** + * xmlXPathNodeSetClearFromPos: + * @set: the node set to be cleared + * @pos: the start position to clear from + * + * Clears the list from temporary XPath objects (e.g. namespace nodes + * are feed) starting with the entry at @pos, but does *not* free the list + * itself. Sets the length of the list to @pos. + */ +static void +xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes) +{ + if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr)) + return; + else if ((hasNsNodes)) { + int i; + xmlNodePtr node; + + for (i = pos; i < set->nodeNr; i++) { + node = set->nodeTab[i]; + if ((node != NULL) && + (node->type == XML_NAMESPACE_DECL)) + xmlXPathNodeSetFreeNs((xmlNsPtr) node); + } + } + set->nodeNr = pos; +} + +/** + * 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); +} + +#if defined(DEBUG) || defined(DEBUG_STEP) +/** + * xmlGenericErrorContextNodeSet: + * @output: a FILE * for the output + * @obj: the xmlNodeSetPtr to display + * + * Quick display of a NodeSet + */ +void +xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) { + int i; + + if (output == NULL) output = xmlGenericErrorContext; + if (obj == NULL) { + fprintf(output, "NodeSet == NULL !\n"); + return; + } + if (obj->nodeNr == 0) { + fprintf(output, "NodeSet is empty\n"); + return; + } + if (obj->nodeTab == NULL) { + fprintf(output, " nodeTab == NULL !\n"); + return; + } + for (i = 0; i < obj->nodeNr; i++) { + if (obj->nodeTab[i] == NULL) { + fprintf(output, " NULL !\n"); + return; + } + if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) || + (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE)) + fprintf(output, " /"); + else if (obj->nodeTab[i]->name == NULL) + fprintf(output, " noname!"); + else fprintf(output, " %s", obj->nodeTab[i]->name); + } + fprintf(output, "\n"); +} +#endif + +/** + * xmlXPathNewNodeSet: + * @val: the NodePtr value + * + * Create a new xmlXPathObjectPtr of type NodeSet and initialize + * it with the single Node @val + * + * Returns the newly created object. + */ +xmlXPathObjectPtr +xmlXPathNewNodeSet(xmlNodePtr val) { + xmlXPathObjectPtr ret; + + ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); + if (ret == NULL) { + xmlXPathErrMemory(NULL, "creating nodeset\n"); + return(NULL); + } + memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); + ret->type = XPATH_NODESET; + ret->boolval = 0; + ret->nodesetval = xmlXPathNodeSetCreate(val); + /* @@ with_ns to check whether namespace nodes should be looked at @@ */ +#ifdef XP_DEBUG_OBJ_USAGE + xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET); +#endif + return(ret); +} + +/** + * xmlXPathNewValueTree: + * @val: the NodePtr value + * + * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize + * it with the tree root @val + * + * Returns the newly created object. + */ +xmlXPathObjectPtr +xmlXPathNewValueTree(xmlNodePtr val) { + xmlXPathObjectPtr ret; + + ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); + if (ret == NULL) { + xmlXPathErrMemory(NULL, "creating result value tree\n"); + return(NULL); + } + memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); + ret->type = XPATH_XSLT_TREE; + ret->boolval = 1; + ret->user = (void *) val; + ret->nodesetval = xmlXPathNodeSetCreate(val); +#ifdef XP_DEBUG_OBJ_USAGE + xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE); +#endif + return(ret); +} + +/** + * xmlXPathNewNodeSetList: + * @val: an existing NodeSet + * + * Create a new xmlXPathObjectPtr of type NodeSet and initialize + * it with the Nodeset @val + * + * Returns the newly created object. + */ +xmlXPathObjectPtr +xmlXPathNewNodeSetList(xmlNodeSetPtr val) +{ + xmlXPathObjectPtr ret; + int i; + + if (val == NULL) + ret = NULL; + else if (val->nodeTab == NULL) + ret = xmlXPathNewNodeSet(NULL); + else { + ret = xmlXPathNewNodeSet(val->nodeTab[0]); + if (ret) + for (i = 1; i < val->nodeNr; ++i) + xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]); + } + + return (ret); +} + +/** + * xmlXPathWrapNodeSet: + * @val: the NodePtr value + * + * Wrap the Nodeset @val in a new xmlXPathObjectPtr + * + * Returns the newly created object. + */ +xmlXPathObjectPtr +xmlXPathWrapNodeSet(xmlNodeSetPtr val) { + xmlXPathObjectPtr ret; + + ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); + if (ret == NULL) { + xmlXPathErrMemory(NULL, "creating node set object\n"); + return(NULL); + } + memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); + ret->type = XPATH_NODESET; + ret->nodesetval = val; +#ifdef XP_DEBUG_OBJ_USAGE + xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET); +#endif + return(ret); +} + +/** + * xmlXPathFreeNodeSetList: + * @obj: an existing NodeSetList object + * + * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in + * the list contrary to xmlXPathFreeObject(). + */ +void +xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) { + if (obj == NULL) return; +#ifdef XP_DEBUG_OBJ_USAGE + xmlXPathDebugObjUsageReleased(NULL, obj->type); +#endif + xmlFree(obj); +} + +/** + * xmlXPathDifference: + * @nodes1: a node-set + * @nodes2: a node-set + * + * Implements the EXSLT - Sets difference() function: + * node-set set:difference (node-set, node-set) + * + * Returns the difference between the two node sets, or nodes1 if + * nodes2 is empty + */ +xmlNodeSetPtr +xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { + xmlNodeSetPtr ret; + int i, l1; + xmlNodePtr cur; + + if (xmlXPathNodeSetIsEmpty(nodes2)) + return(nodes1); + + ret = xmlXPathNodeSetCreate(NULL); + if (xmlXPathNodeSetIsEmpty(nodes1)) + return(ret); + + l1 = xmlXPathNodeSetGetLength(nodes1); + + for (i = 0; i < l1; i++) { + cur = xmlXPathNodeSetItem(nodes1, i); + if (!xmlXPathNodeSetContains(nodes2, cur)) + xmlXPathNodeSetAddUnique(ret, cur); + } + return(ret); +} + +/** + * xmlXPathIntersection: + * @nodes1: a node-set + * @nodes2: a node-set + * + * Implements the EXSLT - Sets intersection() function: + * node-set set:intersection (node-set, node-set) + * + * Returns a node set comprising the nodes that are within both the + * node sets passed as arguments + */ +xmlNodeSetPtr +xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { + xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL); + int i, l1; + xmlNodePtr cur; + + if (ret == NULL) + return(ret); + if (xmlXPathNodeSetIsEmpty(nodes1)) + return(ret); + if (xmlXPathNodeSetIsEmpty(nodes2)) + return(ret); + + l1 = xmlXPathNodeSetGetLength(nodes1); + + for (i = 0; i < l1; i++) { + cur = xmlXPathNodeSetItem(nodes1, i); + if (xmlXPathNodeSetContains(nodes2, cur)) + xmlXPathNodeSetAddUnique(ret, cur); + } + return(ret); +} + +/** + * xmlXPathDistinctSorted: + * @nodes: a node-set, sorted by document order + * + * Implements the EXSLT - Sets distinct() function: + * node-set set:distinct (node-set) + * + * Returns a subset of the nodes contained in @nodes, or @nodes if + * it is empty + */ +xmlNodeSetPtr +xmlXPathDistinctSorted (xmlNodeSetPtr nodes) { + xmlNodeSetPtr ret; + xmlHashTablePtr hash; + int i, l; + xmlChar * strval; + xmlNodePtr cur; + + if (xmlXPathNodeSetIsEmpty(nodes)) + return(nodes); + + ret = xmlXPathNodeSetCreate(NULL); + if (ret == NULL) + return(ret); + l = xmlXPathNodeSetGetLength(nodes); + hash = xmlHashCreate (l); + for (i = 0; i < l; i++) { + cur = xmlXPathNodeSetItem(nodes, i); + strval = xmlXPathCastNodeToString(cur); + if (xmlHashLookup(hash, strval) == NULL) { + xmlHashAddEntry(hash, strval, strval); + xmlXPathNodeSetAddUnique(ret, cur); + } else { + xmlFree(strval); + } + } + xmlHashFree(hash, (xmlHashDeallocator) xmlFree); + return(ret); +} + +/** + * xmlXPathDistinct: + * @nodes: a node-set + * + * Implements the EXSLT - Sets distinct() function: + * node-set set:distinct (node-set) + * @nodes is sorted by document order, then #exslSetsDistinctSorted + * is called with the sorted node-set + * + * Returns a subset of the nodes contained in @nodes, or @nodes if + * it is empty + */ +xmlNodeSetPtr +xmlXPathDistinct (xmlNodeSetPtr nodes) { + if (xmlXPathNodeSetIsEmpty(nodes)) + return(nodes); + + xmlXPathNodeSetSort(nodes); + return(xmlXPathDistinctSorted(nodes)); +} + +/** + * xmlXPathHasSameNodes: + * @nodes1: a node-set + * @nodes2: a node-set + * + * Implements the EXSLT - Sets has-same-nodes function: + * boolean set:has-same-node(node-set, node-set) + * + * Returns true (1) if @nodes1 shares any node with @nodes2, false (0) + * otherwise + */ +int +xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { + int i, l; + xmlNodePtr cur; + + if (xmlXPathNodeSetIsEmpty(nodes1) || + xmlXPathNodeSetIsEmpty(nodes2)) + return(0); + + l = xmlXPathNodeSetGetLength(nodes1); + for (i = 0; i < l; i++) { + cur = xmlXPathNodeSetItem(nodes1, i); + if (xmlXPathNodeSetContains(nodes2, cur)) + return(1); + } + return(0); +} + +/** + * xmlXPathNodeLeadingSorted: + * @nodes: a node-set, sorted by document order + * @node: a node + * + * Implements the EXSLT - Sets leading() function: + * node-set set:leading (node-set, node-set) + * + * Returns the nodes in @nodes that precede @node in document order, + * @nodes if @node is NULL or an empty node-set if @nodes + * doesn't contain @node + */ +xmlNodeSetPtr +xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) { + int i, l; + xmlNodePtr cur; + xmlNodeSetPtr ret; + + if (node == NULL) + return(nodes); + + ret = xmlXPathNodeSetCreate(NULL); + if (ret == NULL) + return(ret); + if (xmlXPathNodeSetIsEmpty(nodes) || + (!xmlXPathNodeSetContains(nodes, node))) + return(ret); + + l = xmlXPathNodeSetGetLength(nodes); + for (i = 0; i < l; i++) { + cur = xmlXPathNodeSetItem(nodes, i); + if (cur == node) + break; + xmlXPathNodeSetAddUnique(ret, cur); + } + return(ret); +} + +/** + * xmlXPathNodeLeading: + * @nodes: a node-set + * @node: a node + * + * Implements the EXSLT - Sets leading() function: + * node-set set:leading (node-set, node-set) + * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted + * is called. + * + * Returns the nodes in @nodes that precede @node in document order, + * @nodes if @node is NULL or an empty node-set if @nodes + * doesn't contain @node + */ +xmlNodeSetPtr +xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) { + xmlXPathNodeSetSort(nodes); + return(xmlXPathNodeLeadingSorted(nodes, node)); +} + +/** + * xmlXPathLeadingSorted: + * @nodes1: a node-set, sorted by document order + * @nodes2: a node-set, sorted by document order + * + * Implements the EXSLT - Sets leading() function: + * node-set set:leading (node-set, node-set) + * + * Returns the nodes in @nodes1 that precede the first node in @nodes2 + * in document order, @nodes1 if @nodes2 is NULL or empty or + * an empty node-set if @nodes1 doesn't contain @nodes2 + */ +xmlNodeSetPtr +xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { + if (xmlXPathNodeSetIsEmpty(nodes2)) + return(nodes1); + return(xmlXPathNodeLeadingSorted(nodes1, + xmlXPathNodeSetItem(nodes2, 1))); +} + +/** + * xmlXPathLeading: + * @nodes1: a node-set + * @nodes2: a node-set + * + * Implements the EXSLT - Sets leading() function: + * node-set set:leading (node-set, node-set) + * @nodes1 and @nodes2 are sorted by document order, then + * #exslSetsLeadingSorted is called. + * + * Returns the nodes in @nodes1 that precede the first node in @nodes2 + * in document order, @nodes1 if @nodes2 is NULL or empty or + * an empty node-set if @nodes1 doesn't contain @nodes2 + */ +xmlNodeSetPtr +xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { + if (xmlXPathNodeSetIsEmpty(nodes2)) + return(nodes1); + if (xmlXPathNodeSetIsEmpty(nodes1)) + return(xmlXPathNodeSetCreate(NULL)); + xmlXPathNodeSetSort(nodes1); + xmlXPathNodeSetSort(nodes2); + return(xmlXPathNodeLeadingSorted(nodes1, + xmlXPathNodeSetItem(nodes2, 1))); +} + +/** + * xmlXPathNodeTrailingSorted: + * @nodes: a node-set, sorted by document order + * @node: a node + * + * Implements the EXSLT - Sets trailing() function: + * node-set set:trailing (node-set, node-set) + * + * Returns the nodes in @nodes that follow @node in document order, + * @nodes if @node is NULL or an empty node-set if @nodes + * doesn't contain @node + */ +xmlNodeSetPtr +xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) { + int i, l; + xmlNodePtr cur; + xmlNodeSetPtr ret; + + if (node == NULL) + return(nodes); + + ret = xmlXPathNodeSetCreate(NULL); + if (ret == NULL) + return(ret); + if (xmlXPathNodeSetIsEmpty(nodes) || + (!xmlXPathNodeSetContains(nodes, node))) + return(ret); + + l = xmlXPathNodeSetGetLength(nodes); + for (i = l - 1; i >= 0; i--) { + cur = xmlXPathNodeSetItem(nodes, i); + if (cur == node) + break; + xmlXPathNodeSetAddUnique(ret, cur); + } + xmlXPathNodeSetSort(ret); /* bug 413451 */ + return(ret); +} + +/** + * xmlXPathNodeTrailing: + * @nodes: a node-set + * @node: a node + * + * Implements the EXSLT - Sets trailing() function: + * node-set set:trailing (node-set, node-set) + * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted + * is called. + * + * Returns the nodes in @nodes that follow @node in document order, + * @nodes if @node is NULL or an empty node-set if @nodes + * doesn't contain @node + */ +xmlNodeSetPtr +xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) { + xmlXPathNodeSetSort(nodes); + return(xmlXPathNodeTrailingSorted(nodes, node)); +} + +/** + * xmlXPathTrailingSorted: + * @nodes1: a node-set, sorted by document order + * @nodes2: a node-set, sorted by document order + * + * Implements the EXSLT - Sets trailing() function: + * node-set set:trailing (node-set, node-set) + * + * Returns the nodes in @nodes1 that follow the first node in @nodes2 + * in document order, @nodes1 if @nodes2 is NULL or empty or + * an empty node-set if @nodes1 doesn't contain @nodes2 + */ +xmlNodeSetPtr +xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { + if (xmlXPathNodeSetIsEmpty(nodes2)) + return(nodes1); + return(xmlXPathNodeTrailingSorted(nodes1, + xmlXPathNodeSetItem(nodes2, 0))); +} + +/** + * xmlXPathTrailing: + * @nodes1: a node-set + * @nodes2: a node-set + * + * Implements the EXSLT - Sets trailing() function: + * node-set set:trailing (node-set, node-set) + * @nodes1 and @nodes2 are sorted by document order, then + * #xmlXPathTrailingSorted is called. + * + * Returns the nodes in @nodes1 that follow the first node in @nodes2 + * in document order, @nodes1 if @nodes2 is NULL or empty or + * an empty node-set if @nodes1 doesn't contain @nodes2 + */ +xmlNodeSetPtr +xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { + if (xmlXPathNodeSetIsEmpty(nodes2)) + return(nodes1); + if (xmlXPathNodeSetIsEmpty(nodes1)) + return(xmlXPathNodeSetCreate(NULL)); + xmlXPathNodeSetSort(nodes1); + xmlXPathNodeSetSort(nodes2); + return(xmlXPathNodeTrailingSorted(nodes1, + xmlXPathNodeSetItem(nodes2, 0))); +} + +/************************************************************************ + * * + * Routines to handle extra functions * + * * + ************************************************************************/ + +/** + * xmlXPathRegisterFunc: + * @ctxt: the XPath context + * @name: the function name + * @f: the function implementation or NULL + * + * Register a new function. If @f is NULL it unregisters the function + * + * Returns 0 in case of success, -1 in case of error + */ +int +xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name, + xmlXPathFunction f) { + return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f)); +} + +/** + * xmlXPathRegisterFuncNS: + * @ctxt: the XPath context + * @name: the function name + * @ns_uri: the function namespace URI + * @f: the function implementation or NULL + * + * Register a new function. If @f is NULL it unregisters the function + * + * Returns 0 in case of success, -1 in case of error + */ +int +xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name, + const xmlChar *ns_uri, xmlXPathFunction f) { + if (ctxt == NULL) + return(-1); + if (name == NULL) + return(-1); + + if (ctxt->funcHash == NULL) + ctxt->funcHash = xmlHashCreate(0); + if (ctxt->funcHash == NULL) + return(-1); + if (f == NULL) + return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL)); + return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f))); +} + +/** + * xmlXPathRegisterFuncLookup: + * @ctxt: the XPath context + * @f: the lookup function + * @funcCtxt: the lookup data + * + * Registers an external mechanism to do function lookup. + */ +void +xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt, + xmlXPathFuncLookupFunc f, + void *funcCtxt) { + if (ctxt == NULL) + return; + ctxt->funcLookupFunc = f; + ctxt->funcLookupData = funcCtxt; +} + +/** + * xmlXPathFunctionLookup: + * @ctxt: the XPath context + * @name: the function name + * + * Search in the Function array of the context for the given + * function. + * + * Returns the xmlXPathFunction or NULL if not found + */ +xmlXPathFunction +xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) { + if (ctxt == NULL) + return (NULL); + + if (ctxt->funcLookupFunc != NULL) { + xmlXPathFunction ret; + xmlXPathFuncLookupFunc f; + + f = ctxt->funcLookupFunc; + ret = f(ctxt->funcLookupData, name, NULL); + if (ret != NULL) + return(ret); + } + return(xmlXPathFunctionLookupNS(ctxt, name, NULL)); +} + +/** + * xmlXPathFunctionLookupNS: + * @ctxt: the XPath context + * @name: the function name + * @ns_uri: the function namespace URI + * + * Search in the Function array of the context for the given + * function. + * + * Returns the xmlXPathFunction or NULL if not found + */ +xmlXPathFunction +xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name, + const xmlChar *ns_uri) { + xmlXPathFunction ret; + + if (ctxt == NULL) + return(NULL); + if (name == NULL) + return(NULL); + + if (ctxt->funcLookupFunc != NULL) { + xmlXPathFuncLookupFunc f; + + f = ctxt->funcLookupFunc; + ret = f(ctxt->funcLookupData, name, ns_uri); + if (ret != NULL) + return(ret); + } + + if (ctxt->funcHash == NULL) + return(NULL); + + XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri); + return(ret); +} + +/** + * xmlXPathRegisteredFuncsCleanup: + * @ctxt: the XPath context + * + * Cleanup the XPath context data associated to registered functions + */ +void +xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) { + if (ctxt == NULL) + return; + + xmlHashFree(ctxt->funcHash, NULL); + ctxt->funcHash = NULL; +} + +/************************************************************************ + * * + * Routines to handle Variables * + * * + ************************************************************************/ + +/** + * xmlXPathRegisterVariable: + * @ctxt: the XPath context + * @name: the variable name + * @value: the variable value or NULL + * + * Register a new variable value. If @value is NULL it unregisters + * the variable + * + * Returns 0 in case of success, -1 in case of error + */ +int +xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name, + xmlXPathObjectPtr value) { + return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value)); +} + +/** + * xmlXPathRegisterVariableNS: + * @ctxt: the XPath context + * @name: the variable name + * @ns_uri: the variable namespace URI + * @value: the variable value or NULL + * + * Register a new variable value. If @value is NULL it unregisters + * the variable + * + * Returns 0 in case of success, -1 in case of error + */ +int +xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name, + const xmlChar *ns_uri, + xmlXPathObjectPtr value) { + if (ctxt == NULL) + return(-1); + if (name == NULL) + return(-1); + + if (ctxt->varHash == NULL) + ctxt->varHash = xmlHashCreate(0); + if (ctxt->varHash == NULL) + return(-1); + if (value == NULL) + return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri, + (xmlHashDeallocator)xmlXPathFreeObject)); + return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri, + (void *) value, + (xmlHashDeallocator)xmlXPathFreeObject)); +} + +/** + * xmlXPathRegisterVariableLookup: + * @ctxt: the XPath context + * @f: the lookup function + * @data: the lookup data + * + * register an external mechanism to do variable lookup + */ +void +xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt, + xmlXPathVariableLookupFunc f, void *data) { + if (ctxt == NULL) + return; + ctxt->varLookupFunc = f; + ctxt->varLookupData = data; +} + +/** + * xmlXPathVariableLookup: + * @ctxt: the XPath context + * @name: the variable name + * + * Search in the Variable array of the context for the given + * variable value. + * + * Returns a copy of the value or NULL if not found + */ +xmlXPathObjectPtr +xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) { + if (ctxt == NULL) + return(NULL); + + if (ctxt->varLookupFunc != NULL) { + xmlXPathObjectPtr ret; + + ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc) + (ctxt->varLookupData, name, NULL); + return(ret); + } + return(xmlXPathVariableLookupNS(ctxt, name, NULL)); +} + +/** + * xmlXPathVariableLookupNS: + * @ctxt: the XPath context + * @name: the variable name + * @ns_uri: the variable namespace URI + * + * Search in the Variable array of the context for the given + * variable value. + * + * Returns the a copy of the value or NULL if not found + */ +xmlXPathObjectPtr +xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name, + const xmlChar *ns_uri) { + if (ctxt == NULL) + return(NULL); + + if (ctxt->varLookupFunc != NULL) { + xmlXPathObjectPtr ret; + + ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc) + (ctxt->varLookupData, name, ns_uri); + if (ret != NULL) return(ret); + } + + if (ctxt->varHash == NULL) + return(NULL); + if (name == NULL) + return(NULL); + + return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr) + xmlHashLookup2(ctxt->varHash, name, ns_uri))); +} + +/** + * xmlXPathRegisteredVariablesCleanup: + * @ctxt: the XPath context + * + * Cleanup the XPath context data associated to registered variables + */ +void +xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) { + if (ctxt == NULL) + return; + + xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject); + ctxt->varHash = NULL; +} + +/** + * xmlXPathRegisterNs: + * @ctxt: the XPath context + * @prefix: the namespace prefix cannot be NULL or empty string + * @ns_uri: the namespace name + * + * Register a new namespace. If @ns_uri is NULL it unregisters + * the namespace + * + * Returns 0 in case of success, -1 in case of error + */ +int +xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix, + const xmlChar *ns_uri) { + if (ctxt == NULL) + return(-1); + if (prefix == NULL) + return(-1); + if (prefix[0] == 0) + return(-1); + + if (ctxt->nsHash == NULL) + ctxt->nsHash = xmlHashCreate(10); + if (ctxt->nsHash == NULL) + return(-1); + if (ns_uri == NULL) + return(xmlHashRemoveEntry(ctxt->nsHash, prefix, + (xmlHashDeallocator)xmlFree)); + return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri), + (xmlHashDeallocator)xmlFree)); +} + +/** + * xmlXPathNsLookup: + * @ctxt: the XPath context + * @prefix: the namespace prefix value + * + * Search in the namespace declaration array of the context for the given + * namespace name associated to the given prefix + * + * Returns the value or NULL if not found + */ +const xmlChar * +xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) { + if (ctxt == NULL) + return(NULL); + 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; + + for (i = 0;i < ctxt->nsNr;i++) { + if ((ctxt->namespaces[i] != NULL) && + (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix))) + return(ctxt->namespaces[i]->href); + } + } + + return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix)); +} + +/** + * xmlXPathRegisteredNsCleanup: + * @ctxt: the XPath context + * + * Cleanup the XPath context data associated to registered variables + */ +void +xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) { + if (ctxt == NULL) + return; + + xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree); + ctxt->nsHash = NULL; +} + +/************************************************************************ + * * + * Routines to handle Values * + * * + ************************************************************************/ + +/* Allocations are terrible, one needs to optimize all this !!! */ + +/** + * xmlXPathNewFloat: + * @val: the double value + * + * Create a new xmlXPathObjectPtr of type double and of value @val + * + * Returns the newly created object. + */ +xmlXPathObjectPtr +xmlXPathNewFloat(double val) { + xmlXPathObjectPtr ret; + + ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); + if (ret == NULL) { + xmlXPathErrMemory(NULL, "creating float object\n"); + return(NULL); + } + memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); + ret->type = XPATH_NUMBER; + ret->floatval = val; +#ifdef XP_DEBUG_OBJ_USAGE + xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER); +#endif + return(ret); +} + +/** + * xmlXPathNewBoolean: + * @val: the boolean value + * + * Create a new xmlXPathObjectPtr of type boolean and of value @val + * + * Returns the newly created object. + */ +xmlXPathObjectPtr +xmlXPathNewBoolean(int val) { + xmlXPathObjectPtr ret; + + ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); + if (ret == NULL) { + xmlXPathErrMemory(NULL, "creating boolean object\n"); + return(NULL); + } + memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); + ret->type = XPATH_BOOLEAN; + ret->boolval = (val != 0); +#ifdef XP_DEBUG_OBJ_USAGE + xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN); +#endif + return(ret); +} + +/** + * xmlXPathNewString: + * @val: the xmlChar * value + * + * Create a new xmlXPathObjectPtr of type string and of value @val + * + * Returns the newly created object. + */ +xmlXPathObjectPtr +xmlXPathNewString(const xmlChar *val) { + xmlXPathObjectPtr ret; + + ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); + if (ret == NULL) { + xmlXPathErrMemory(NULL, "creating string object\n"); + return(NULL); + } + memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); + ret->type = XPATH_STRING; + if (val != NULL) + ret->stringval = xmlStrdup(val); + else + ret->stringval = xmlStrdup((const xmlChar *)""); +#ifdef XP_DEBUG_OBJ_USAGE + xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING); +#endif + return(ret); +} + +/** + * xmlXPathWrapString: + * @val: the xmlChar * value + * + * Wraps the @val string into an XPath object. + * + * Returns the newly created object. + */ +xmlXPathObjectPtr +xmlXPathWrapString (xmlChar *val) { + xmlXPathObjectPtr ret; + + ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); + if (ret == NULL) { + xmlXPathErrMemory(NULL, "creating string object\n"); + return(NULL); + } + memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); + ret->type = XPATH_STRING; + ret->stringval = val; +#ifdef XP_DEBUG_OBJ_USAGE + xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING); +#endif + return(ret); +} + +/** + * xmlXPathNewCString: + * @val: the char * value + * + * Create a new xmlXPathObjectPtr of type string and of value @val + * + * Returns the newly created object. + */ +xmlXPathObjectPtr +xmlXPathNewCString(const char *val) { + xmlXPathObjectPtr ret; + + ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); + if (ret == NULL) { + xmlXPathErrMemory(NULL, "creating string object\n"); + return(NULL); + } + memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); + ret->type = XPATH_STRING; + ret->stringval = xmlStrdup(BAD_CAST val); +#ifdef XP_DEBUG_OBJ_USAGE + xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING); +#endif + return(ret); +} + +/** + * xmlXPathWrapCString: + * @val: the char * value + * + * Wraps a string into an XPath object. + * + * Returns the newly created object. + */ +xmlXPathObjectPtr +xmlXPathWrapCString (char * val) { + return(xmlXPathWrapString((xmlChar *)(val))); +} + +/** + * xmlXPathWrapExternal: + * @val: the user data + * + * Wraps the @val data into an XPath object. + * + * Returns the newly created object. + */ +xmlXPathObjectPtr +xmlXPathWrapExternal (void *val) { + xmlXPathObjectPtr ret; + + ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); + if (ret == NULL) { + xmlXPathErrMemory(NULL, "creating user object\n"); + return(NULL); + } + memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); + ret->type = XPATH_USERS; + ret->user = val; +#ifdef XP_DEBUG_OBJ_USAGE + xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS); +#endif + return(ret); +} + +/** + * xmlXPathObjectCopy: + * @val: the original object + * + * allocate a new copy of a given object + * + * Returns the newly created object. + */ +xmlXPathObjectPtr +xmlXPathObjectCopy(xmlXPathObjectPtr val) { + xmlXPathObjectPtr ret; + + if (val == NULL) + return(NULL); + + ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); + if (ret == NULL) { + xmlXPathErrMemory(NULL, "copying object\n"); + return(NULL); + } + memcpy(ret, val , (size_t) sizeof(xmlXPathObject)); +#ifdef XP_DEBUG_OBJ_USAGE + xmlXPathDebugObjUsageRequested(NULL, val->type); +#endif + switch (val->type) { + case XPATH_BOOLEAN: + case XPATH_NUMBER: + case XPATH_POINT: + case XPATH_RANGE: + break; + case XPATH_STRING: + ret->stringval = xmlStrdup(val->stringval); + break; + case XPATH_XSLT_TREE: +#if 0 +/* + Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that + this previous handling is no longer correct, and can cause some serious + problems (ref. bug 145547) +*/ + if ((val->nodesetval != NULL) && + (val->nodesetval->nodeTab != NULL)) { + xmlNodePtr cur, tmp; + xmlDocPtr top; + + ret->boolval = 1; + top = xmlNewDoc(NULL); + top->name = (char *) + xmlStrdup(val->nodesetval->nodeTab[0]->name); + ret->user = top; + if (top != NULL) { + top->doc = top; + cur = val->nodesetval->nodeTab[0]->children; + while (cur != NULL) { + tmp = xmlDocCopyNode(cur, top, 1); + xmlAddChild((xmlNodePtr) top, tmp); + cur = cur->next; + } + } + + ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top); + } else + ret->nodesetval = xmlXPathNodeSetCreate(NULL); + /* Deallocate the copied tree value */ + break; +#endif + case XPATH_NODESET: + ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval); + /* Do not deallocate the copied tree value */ + ret->boolval = 0; + break; + case XPATH_LOCATIONSET: +#ifdef LIBXML_XPTR_ENABLED + { + xmlLocationSetPtr loc = val->user; + ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc); + break; + } +#endif + case XPATH_USERS: + ret->user = val->user; + break; + case XPATH_UNDEFINED: + xmlGenericError(xmlGenericErrorContext, + "xmlXPathObjectCopy: unsupported type %d\n", + val->type); + break; + } + return(ret); +} + +/** + * xmlXPathFreeObject: + * @obj: the object to free + * + * Free up an xmlXPathObjectPtr object. + */ +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); + } +#ifdef LIBXML_XPTR_ENABLED + } else if (obj->type == XPATH_LOCATIONSET) { + if (obj->user != NULL) + xmlXPtrFreeLocationSet(obj->user); +#endif + } else if (obj->type == XPATH_STRING) { + if (obj->stringval != NULL) + xmlFree(obj->stringval); + } +#ifdef XP_DEBUG_OBJ_USAGE + xmlXPathDebugObjUsageReleased(NULL, obj->type); +#endif + xmlFree(obj); +} + +/** + * xmlXPathReleaseObject: + * @obj: the xmlXPathObjectPtr to free or to cache + * + * Depending on the state of the cache this frees the given + * XPath object or stores it in the cache. + */ +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)) { + xmlXPathFreeObject(obj); + } else { + xmlXPathContextCachePtr cache = + (xmlXPathContextCachePtr) ctxt->cache; + + switch (obj->type) { + 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); + goto obj_cached; + } else { + xmlXPathFreeNodeSet(obj->nodesetval); + obj->nodesetval = NULL; + } + } + break; + 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; + } + 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_ENABLED + case XPATH_LOCATIONSET: + if (obj->user != NULL) { + xmlXPtrFreeLocationSet(obj->user); + } + goto free_obj; +#endif + default: + goto free_obj; + } + + /* + * Fallback to adding to the misc-objects slot. + */ + if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) { + XP_CACHE_ADD(cache->miscObjs, obj); + } else + goto free_obj; + +obj_cached: + +#ifdef XP_DEBUG_OBJ_USAGE + xmlXPathDebugObjUsageReleased(ctxt, obj->type); +#endif + + 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. + */ + if (tmpset->nodeNr > 1) { + int i; + xmlNodePtr node; + + for (i = 0; i < tmpset->nodeNr; i++) { + node = tmpset->nodeTab[i]; + if ((node != NULL) && + (node->type == XML_NAMESPACE_DECL)) + { + 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; + +free_obj: + /* + * Cache is full; free the object. + */ + if (obj->nodesetval != NULL) + xmlXPathFreeNodeSet(obj->nodesetval); +#ifdef XP_DEBUG_OBJ_USAGE + xmlXPathDebugObjUsageReleased(NULL, obj->type); +#endif + xmlFree(obj); + } + return; +} + + +/************************************************************************ + * * + * Type Casting Routines * + * * + ************************************************************************/ + +/** + * xmlXPathCastBooleanToString: + * @val: a boolean + * + * Converts a boolean to its string value. + * + * Returns a newly allocated string. + */ +xmlChar * +xmlXPathCastBooleanToString (int val) { + xmlChar *ret; + if (val) + ret = xmlStrdup((const xmlChar *) "true"); + else + ret = xmlStrdup((const xmlChar *) "false"); + return(ret); +} + +/** + * xmlXPathCastNumberToString: + * @val: a number + * + * Converts a number to its string value. + * + * Returns a newly allocated string. + */ +xmlChar * +xmlXPathCastNumberToString (double val) { + xmlChar *ret; + switch (xmlXPathIsInf(val)) { + case 1: + ret = xmlStrdup((const xmlChar *) "Infinity"); + break; + case -1: + ret = xmlStrdup((const xmlChar *) "-Infinity"); + break; + default: + if (xmlXPathIsNaN(val)) { + ret = xmlStrdup((const xmlChar *) "NaN"); + } else if (val == 0 && xmlXPathGetSign(val) != 0) { + ret = xmlStrdup((const xmlChar *) "0"); + } else { + /* could be improved */ + char buf[100]; + xmlXPathFormatNumber(val, buf, 99); + buf[99] = 0; + ret = xmlStrdup((const xmlChar *) buf); + } + } + return(ret); +} + +/** + * xmlXPathCastNodeToString: + * @node: a node + * + * Converts a node to its string value. + * + * Returns a newly allocated string. + */ +xmlChar * +xmlXPathCastNodeToString (xmlNodePtr node) { +xmlChar *ret; + if ((ret = xmlNodeGetContent(node)) == NULL) + ret = xmlStrdup((const xmlChar *) ""); + return(ret); +} + +/** + * xmlXPathCastNodeSetToString: + * @ns: a node-set + * + * Converts a node-set to its string value. + * + * Returns a newly allocated string. + */ +xmlChar * +xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) { + if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL)) + return(xmlStrdup((const xmlChar *) "")); + + if (ns->nodeNr > 1) + xmlXPathNodeSetSort(ns); + return(xmlXPathCastNodeToString(ns->nodeTab[0])); +} + +/** + * xmlXPathCastToString: + * @val: an XPath object + * + * Converts an existing object to its string() equivalent + * + * Returns the allocated string value of the object, NULL in case of error. + * It's up to the caller to free the string memory with xmlFree(). + */ +xmlChar * +xmlXPathCastToString(xmlXPathObjectPtr val) { + xmlChar *ret = NULL; + + if (val == NULL) + return(xmlStrdup((const xmlChar *) "")); + switch (val->type) { + case XPATH_UNDEFINED: +#ifdef DEBUG_EXPR + xmlGenericError(xmlGenericErrorContext, "String: undefined\n"); +#endif + ret = xmlStrdup((const xmlChar *) ""); + break; + case XPATH_NODESET: + case XPATH_XSLT_TREE: + ret = xmlXPathCastNodeSetToString(val->nodesetval); + break; + case XPATH_STRING: + return(xmlStrdup(val->stringval)); + case XPATH_BOOLEAN: + ret = xmlXPathCastBooleanToString(val->boolval); + break; + case XPATH_NUMBER: { + ret = xmlXPathCastNumberToString(val->floatval); + break; + } + case XPATH_USERS: + case XPATH_POINT: + case XPATH_RANGE: + case XPATH_LOCATIONSET: + TODO + ret = xmlStrdup((const xmlChar *) ""); + break; + } + return(ret); +} + +/** + * xmlXPathConvertString: + * @val: an XPath object + * + * Converts an existing object to its string() equivalent + * + * Returns the new object, the old one is freed (or the operation + * is done directly on @val) + */ +xmlXPathObjectPtr +xmlXPathConvertString(xmlXPathObjectPtr val) { + xmlChar *res = NULL; + + if (val == NULL) + return(xmlXPathNewCString("")); + + switch (val->type) { + case XPATH_UNDEFINED: +#ifdef DEBUG_EXPR + xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n"); +#endif + 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: + case XPATH_POINT: + case XPATH_RANGE: + case XPATH_LOCATIONSET: + TODO; + break; + } + xmlXPathFreeObject(val); + if (res == NULL) + return(xmlXPathNewCString("")); + return(xmlXPathWrapString(res)); +} + +/** + * xmlXPathCastBooleanToNumber: + * @val: a boolean + * + * Converts a boolean to its number value + * + * Returns the number value + */ +double +xmlXPathCastBooleanToNumber(int val) { + if (val) + return(1.0); + return(0.0); +} + +/** + * xmlXPathCastStringToNumber: + * @val: a string + * + * Converts a string to its number value + * + * Returns the number value + */ +double +xmlXPathCastStringToNumber(const xmlChar * val) { + return(xmlXPathStringEvalNumber(val)); +} + +/** + * xmlXPathCastNodeToNumber: + * @node: a node + * + * Converts a node to its number value + * + * Returns the number value + */ +double +xmlXPathCastNodeToNumber (xmlNodePtr node) { + xmlChar *strval; + double ret; + + if (node == NULL) + return(xmlXPathNAN); + strval = xmlXPathCastNodeToString(node); + if (strval == NULL) + return(xmlXPathNAN); + ret = xmlXPathCastStringToNumber(strval); + xmlFree(strval); + + return(ret); +} + +/** + * xmlXPathCastNodeSetToNumber: + * @ns: a node-set + * + * Converts a node-set 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); +} + +/** + * xmlXPathCastToNumber: + * @val: an XPath object + * + * Converts an XPath object to its number value + * + * Returns the number value + */ +double +xmlXPathCastToNumber(xmlXPathObjectPtr val) { + double ret = 0.0; + + if (val == NULL) + return(xmlXPathNAN); + switch (val->type) { + case XPATH_UNDEFINED: +#ifdef DEGUB_EXPR + xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n"); +#endif + 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: + case XPATH_POINT: + case XPATH_RANGE: + case XPATH_LOCATIONSET: + TODO; + ret = xmlXPathNAN; + break; + } + return(ret); +} + +/** + * xmlXPathConvertNumber: + * @val: an XPath object + * + * Converts an existing object to its number() equivalent + * + * Returns the new object, the old one is freed (or the operation + * is done directly on @val) + */ +xmlXPathObjectPtr +xmlXPathConvertNumber(xmlXPathObjectPtr val) { + xmlXPathObjectPtr ret; + + if (val == NULL) + return(xmlXPathNewFloat(0.0)); + if (val->type == XPATH_NUMBER) + return(val); + ret = xmlXPathNewFloat(xmlXPathCastToNumber(val)); + xmlXPathFreeObject(val); + return(ret); +} + +/** + * xmlXPathCastNumberToBoolean: + * @val: a number + * + * Converts a number to its boolean value + * + * Returns the boolean value + */ +int +xmlXPathCastNumberToBoolean (double val) { + if (xmlXPathIsNaN(val) || (val == 0.0)) + return(0); + return(1); +} + +/** + * xmlXPathCastStringToBoolean: + * @val: a string + * + * Converts a string to its boolean value + * + * Returns the boolean value + */ +int +xmlXPathCastStringToBoolean (const xmlChar *val) { + if ((val == NULL) || (xmlStrlen(val) == 0)) + return(0); + return(1); +} + +/** + * xmlXPathCastNodeSetToBoolean: + * @ns: a node-set + * + * Converts a node-set to its boolean value + * + * Returns the boolean value + */ +int +xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) { + if ((ns == NULL) || (ns->nodeNr == 0)) + return(0); + return(1); +} + +/** + * xmlXPathCastToBoolean: + * @val: an XPath object + * + * Converts an XPath object to its boolean value + * + * Returns the boolean value + */ +int +xmlXPathCastToBoolean (xmlXPathObjectPtr val) { + int ret = 0; + + if (val == NULL) + return(0); + switch (val->type) { + case XPATH_UNDEFINED: +#ifdef DEBUG_EXPR + xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n"); +#endif + ret = 0; + break; + case XPATH_NODESET: + case XPATH_XSLT_TREE: + ret = xmlXPathCastNodeSetToBoolean(val->nodesetval); + break; + case XPATH_STRING: + ret = xmlXPathCastStringToBoolean(val->stringval); + break; + case XPATH_NUMBER: + ret = xmlXPathCastNumberToBoolean(val->floatval); + break; + case XPATH_BOOLEAN: + ret = val->boolval; + break; + case XPATH_USERS: + case XPATH_POINT: + case XPATH_RANGE: + case XPATH_LOCATIONSET: + TODO; + ret = 0; + break; + } + return(ret); +} + + +/** + * xmlXPathConvertBoolean: + * @val: an XPath object + * + * Converts an existing object to its boolean() equivalent + * + * Returns the new object, the old one is freed (or the operation + * is done directly on @val) + */ +xmlXPathObjectPtr +xmlXPathConvertBoolean(xmlXPathObjectPtr val) { + xmlXPathObjectPtr ret; + + if (val == NULL) + return(xmlXPathNewBoolean(0)); + if (val->type == XPATH_BOOLEAN) + return(val); + ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val)); + xmlXPathFreeObject(val); + return(ret); +} + +/************************************************************************ + * * + * Routines to handle XPath contexts * + * * + ************************************************************************/ + +/** + * xmlXPathNewContext: + * @doc: the XML document + * + * Create a new xmlXPathContext + * + * Returns the xmlXPathContext just allocated. The caller will need to free it. + */ +xmlXPathContextPtr +xmlXPathNewContext(xmlDocPtr doc) { + xmlXPathContextPtr ret; + + ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext)); + if (ret == NULL) { + xmlXPathErrMemory(NULL, "creating context\n"); + return(NULL); + } + memset(ret, 0 , (size_t) sizeof(xmlXPathContext)); + ret->doc = doc; + ret->node = NULL; + + ret->varHash = NULL; + + ret->nb_types = 0; + ret->max_types = 0; + ret->types = NULL; + + ret->funcHash = xmlHashCreate(0); + + ret->nb_axis = 0; + ret->max_axis = 0; + ret->axis = NULL; + + ret->nsHash = NULL; + ret->user = NULL; + + ret->contextSize = -1; + ret->proximityPosition = -1; + +#ifdef XP_DEFAULT_CACHE_ON + if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) { + xmlXPathFreeContext(ret); + return(NULL); + } +#endif + + xmlXPathRegisterAllFunctions(ret); + + return(ret); +} + +/** + * xmlXPathFreeContext: + * @ctxt: the context to free + * + * Free up an xmlXPathContext + */ +void +xmlXPathFreeContext(xmlXPathContextPtr ctxt) { + if (ctxt == NULL) return; + + if (ctxt->cache != NULL) + xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache); + xmlXPathRegisteredNsCleanup(ctxt); + xmlXPathRegisteredFuncsCleanup(ctxt); + xmlXPathRegisteredVariablesCleanup(ctxt); + xmlResetError(&ctxt->lastError); + xmlFree(ctxt); +} + +/************************************************************************ + * * + * 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 + * @ctxt: the XPath context + * + * Create a new xmlXPathParserContext + * + * Returns the xmlXPathParserContext just allocated. + */ +xmlXPathParserContextPtr +xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) { + xmlXPathParserContextPtr ret; + + ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext)); + if (ret == NULL) { + xmlXPathErrMemory(ctxt, "creating parser context\n"); + return(NULL); + } + memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext)); + ret->cur = ret->base = str; + ret->context = ctxt; + + ret->comp = xmlXPathNewCompExpr(); + if (ret->comp == NULL) { + xmlFree(ret->valueTab); + xmlFree(ret); + return(NULL); + } + if ((ctxt != NULL) && (ctxt->dict != NULL)) { + ret->comp->dict = ctxt->dict; + xmlDictReference(ret->comp->dict); + } + + return(ret); +} + +/** + * xmlXPathCompParserContext: + * @comp: the XPath compiled expression + * @ctxt: the XPath context + * + * Create a new xmlXPathParserContext when processing a compiled expression + * + * Returns the xmlXPathParserContext just allocated. + */ +static xmlXPathParserContextPtr +xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) { + xmlXPathParserContextPtr ret; + + ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext)); + if (ret == NULL) { + xmlXPathErrMemory(ctxt, "creating evaluation context\n"); + return(NULL); + } + memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext)); + + /* Allocate the value stack */ + ret->valueTab = (xmlXPathObjectPtr *) + xmlMalloc(10 * sizeof(xmlXPathObjectPtr)); + if (ret->valueTab == NULL) { + xmlFree(ret); + xmlXPathErrMemory(ctxt, "creating evaluation context\n"); + return(NULL); + } + ret->valueNr = 0; + ret->valueMax = 10; + ret->value = NULL; + ret->valueFrame = 0; + + ret->context = ctxt; + ret->comp = comp; + + return(ret); +} + +/** + * xmlXPathFreeParserContext: + * @ctxt: the context to free + * + * Free up an xmlXPathParserContext + */ +void +xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) { + if (ctxt->valueTab != NULL) { + xmlFree(ctxt->valueTab); + } + if (ctxt->comp != NULL) { +#ifdef XPATH_STREAMING + if (ctxt->comp->stream != NULL) { + xmlFreePatternList(ctxt->comp->stream); + ctxt->comp->stream = NULL; + } +#endif + xmlXPathFreeCompExpr(ctxt->comp); + } + xmlFree(ctxt); +} + +/************************************************************************ + * * + * The implicit core function library * + * * + ************************************************************************/ + +/** + * xmlXPathNodeValHash: + * @node: a node pointer + * + * Function computing the beginning of the string value of the node, + * used to speed up comparisons + * + * Returns an int usable as a hash + */ +static unsigned int +xmlXPathNodeValHash(xmlNodePtr node) { + int len = 2; + const xmlChar * string = NULL; + xmlNodePtr tmp = NULL; + unsigned int ret = 0; + + if (node == NULL) + return(0); + + if (node->type == XML_DOCUMENT_NODE) { + tmp = xmlDocGetRootElement((xmlDocPtr) node); + if (tmp == NULL) + node = node->children; + else + node = tmp; + + if (node == NULL) + return(0); + } + + switch (node->type) { + case XML_COMMENT_NODE: + case XML_PI_NODE: + case XML_CDATA_SECTION_NODE: + case XML_TEXT_NODE: + string = node->content; + if (string == NULL) + return(0); + if (string[0] == 0) + return(0); + return(((unsigned int) string[0]) + + (((unsigned int) string[1]) << 8)); + case XML_NAMESPACE_DECL: + string = ((xmlNsPtr)node)->href; + if (string == NULL) + return(0); + if (string[0] == 0) + return(0); + return(((unsigned int) string[0]) + + (((unsigned int) string[1]) << 8)); + case XML_ATTRIBUTE_NODE: + tmp = ((xmlAttrPtr) node)->children; + break; + case XML_ELEMENT_NODE: + tmp = node->children; + break; + default: + return(0); + } + while (tmp != NULL) { + switch (tmp->type) { + case XML_COMMENT_NODE: + case XML_PI_NODE: + case XML_CDATA_SECTION_NODE: + case XML_TEXT_NODE: + string = tmp->content; + break; + case XML_NAMESPACE_DECL: + string = ((xmlNsPtr)tmp)->href; + break; + default: + break; + } + if ((string != NULL) && (string[0] != 0)) { + if (len == 1) { + return(ret + (((unsigned int) string[0]) << 8)); + } + if (string[1] == 0) { + len = 1; + ret = (unsigned int) string[0]; + } else { + return(((unsigned int) string[0]) + + (((unsigned int) string[1]) << 8)); + } + } + /* + * Skip to next node + */ + if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) { + if (tmp->children->type != XML_ENTITY_DECL) { + tmp = tmp->children; + continue; + } + } + if (tmp == node) + break; + + if (tmp->next != NULL) { + tmp = tmp->next; + continue; + } + + do { + tmp = tmp->parent; + if (tmp == NULL) + break; + if (tmp == node) { + tmp = NULL; + break; + } + if (tmp->next != NULL) { + tmp = tmp->next; + break; + } + } while (tmp != NULL); + } + return(ret); +} + +/** + * xmlXPathStringHash: + * @string: a string + * + * Function computing the beginning of the string value of the node, + * used to speed up comparisons + * + * Returns an int usable as a hash + */ +static unsigned int +xmlXPathStringHash(const xmlChar * string) { + if (string == NULL) + return((unsigned int) 0); + if (string[0] == 0) + return(0); + return(((unsigned int) string[0]) + + (((unsigned int) string[1]) << 8)); +} + +/** + * xmlXPathCompareNodeSetFloat: + * @ctxt: the XPath Parser context + * @inf: less than (1) or greater than (0) + * @strict: is the comparison strict + * @arg: the node set + * @f: the value + * + * Implement the compare operation between a nodeset and a number + * @ns < @val (1, 1, ... + * @ns <= @val (1, 0, ... + * @ns > @val (0, 1, ... + * @ns >= @val (0, 0, ... + * + * If one object to be compared is a node-set and the other is a number, + * then the comparison will be true if and only if there is a node in the + * node-set such that the result of performing the comparison on the number + * to be compared and on the result of converting the string-value of that + * node to a number using the number function is true. + * + * Returns 0 or 1 depending on the results of the test. + */ +static int +xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict, + xmlXPathObjectPtr arg, xmlXPathObjectPtr f) { + int i, ret = 0; + xmlNodeSetPtr ns; + xmlChar *str2; + + if ((f == NULL) || (arg == NULL) || + ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) { + xmlXPathReleaseObject(ctxt->context, arg); + xmlXPathReleaseObject(ctxt->context, f); + return(0); + } + ns = arg->nodesetval; + if (ns != NULL) { + for (i = 0;i < ns->nodeNr;i++) { + str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); + if (str2 != NULL) { + valuePush(ctxt, + xmlXPathCacheNewString(ctxt->context, str2)); + xmlFree(str2); + xmlXPathNumberFunction(ctxt, 1); + valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f)); + ret = xmlXPathCompareValues(ctxt, inf, strict); + if (ret) + break; + } + } + } + xmlXPathReleaseObject(ctxt->context, arg); + xmlXPathReleaseObject(ctxt->context, f); + return(ret); +} + +/** + * xmlXPathCompareNodeSetString: + * @ctxt: the XPath Parser context + * @inf: less than (1) or greater than (0) + * @strict: is the comparison strict + * @arg: the node set + * @s: the value + * + * Implement the compare operation between a nodeset and a string + * @ns < @val (1, 1, ... + * @ns <= @val (1, 0, ... + * @ns > @val (0, 1, ... + * @ns >= @val (0, 0, ... + * + * If one object to be compared is a node-set and the other is a string, + * then the comparison will be true if and only if there is a node in + * the node-set such that the result of performing the comparison on the + * string-value of the node and the other string is true. + * + * Returns 0 or 1 depending on the results of the test. + */ +static int +xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict, + xmlXPathObjectPtr arg, xmlXPathObjectPtr s) { + int i, ret = 0; + xmlNodeSetPtr ns; + xmlChar *str2; + + if ((s == NULL) || (arg == NULL) || + ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) { + xmlXPathReleaseObject(ctxt->context, arg); + xmlXPathReleaseObject(ctxt->context, s); + return(0); + } + ns = arg->nodesetval; + if (ns != NULL) { + for (i = 0;i < ns->nodeNr;i++) { + str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); + if (str2 != NULL) { + valuePush(ctxt, + xmlXPathCacheNewString(ctxt->context, str2)); + xmlFree(str2); + valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s)); + ret = xmlXPathCompareValues(ctxt, inf, strict); + if (ret) + break; + } + } + } + xmlXPathReleaseObject(ctxt->context, arg); + xmlXPathReleaseObject(ctxt->context, s); + return(ret); +} + +/** + * xmlXPathCompareNodeSets: + * @inf: less than (1) or greater than (0) + * @strict: is the comparison strict + * @arg1: the first node set object + * @arg2: the second node set object + * + * Implement the compare operation on nodesets: + * + * If both objects to be compared are node-sets, then the comparison + * will be true if and only if there is a node in the first node-set + * and a node in the second node-set such that the result of performing + * the comparison on the string-values of the two nodes is true. + * .... + * When neither object to be compared is a node-set and the operator + * is <=, <, >= or >, then the objects are compared by converting both + * objects to numbers and comparing the numbers according to IEEE 754. + * .... + * The number function converts its argument to a number as follows: + * - a string that consists of optional whitespace followed by an + * optional minus sign followed by a Number followed by whitespace + * is converted to the IEEE 754 number that is nearest (according + * to the IEEE 754 round-to-nearest rule) to the mathematical value + * represented by the string; any other string is converted to NaN + * + * Conclusion all nodes need to be converted first to their string value + * and then the comparison must be done when possible + */ +static int +xmlXPathCompareNodeSets(int inf, int strict, + xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) { + int i, j, init = 0; + double val1; + double *values2; + int ret = 0; + xmlNodeSetPtr ns1; + xmlNodeSetPtr ns2; + + if ((arg1 == NULL) || + ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) { + xmlXPathFreeObject(arg2); + return(0); + } + if ((arg2 == NULL) || + ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) { + xmlXPathFreeObject(arg1); + xmlXPathFreeObject(arg2); + return(0); + } + + ns1 = arg1->nodesetval; + ns2 = arg2->nodesetval; + + if ((ns1 == NULL) || (ns1->nodeNr <= 0)) { + xmlXPathFreeObject(arg1); + xmlXPathFreeObject(arg2); + return(0); + } + if ((ns2 == NULL) || (ns2->nodeNr <= 0)) { + xmlXPathFreeObject(arg1); + xmlXPathFreeObject(arg2); + return(0); + } + + values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double)); + if (values2 == NULL) { + xmlXPathErrMemory(NULL, "comparing nodesets\n"); + xmlXPathFreeObject(arg1); + xmlXPathFreeObject(arg2); + return(0); + } + for (i = 0;i < ns1->nodeNr;i++) { + val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]); + if (xmlXPathIsNaN(val1)) + continue; + for (j = 0;j < ns2->nodeNr;j++) { + if (init == 0) { + values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]); + } + if (xmlXPathIsNaN(values2[j])) + continue; + if (inf && strict) + ret = (val1 < values2[j]); + else if (inf && !strict) + ret = (val1 <= values2[j]); + else if (!inf && strict) + ret = (val1 > values2[j]); + else if (!inf && !strict) + ret = (val1 >= values2[j]); + if (ret) + break; + } + if (ret) + break; + init = 1; + } + xmlFree(values2); + xmlXPathFreeObject(arg1); + xmlXPathFreeObject(arg2); + return(ret); +} + +/** + * xmlXPathCompareNodeSetValue: + * @ctxt: the XPath Parser context + * @inf: less than (1) or greater than (0) + * @strict: is the comparison strict + * @arg: the node set + * @val: the value + * + * Implement the compare operation between a nodeset and a value + * @ns < @val (1, 1, ... + * @ns <= @val (1, 0, ... + * @ns > @val (0, 1, ... + * @ns >= @val (0, 0, ... + * + * If one object to be compared is a node-set and the other is a boolean, + * then the comparison will be true if and only if the result of performing + * the comparison on the boolean and on the result of converting + * the node-set to a boolean using the boolean function is true. + * + * Returns 0 or 1 depending on the results of the test. + */ +static int +xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict, + xmlXPathObjectPtr arg, xmlXPathObjectPtr val) { + if ((val == NULL) || (arg == NULL) || + ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) + return(0); + + switch(val->type) { + case XPATH_NUMBER: + return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val)); + case XPATH_NODESET: + case XPATH_XSLT_TREE: + return(xmlXPathCompareNodeSets(inf, strict, arg, val)); + case XPATH_STRING: + return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val)); + case XPATH_BOOLEAN: + valuePush(ctxt, arg); + xmlXPathBooleanFunction(ctxt, 1); + valuePush(ctxt, val); + return(xmlXPathCompareValues(ctxt, inf, strict)); + default: + TODO + } + return(0); +} + +/** + * xmlXPathEqualNodeSetString: + * @arg: the nodeset object argument + * @str: the string to compare to. + * @neq: flag to show whether for '=' (0) or '!=' (1) + * + * Implement the equal operation on XPath objects content: @arg1 == @arg2 + * If one object to be compared is a node-set and the other is a string, + * then the comparison will be true if and only if there is a node in + * the node-set such that the result of performing the comparison on the + * string-value of the node and the other string is true. + * + * Returns 0 or 1 depending on the results of the test. + */ +static int +xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq) +{ + int i; + xmlNodeSetPtr ns; + xmlChar *str2; + unsigned int hash; + + if ((str == NULL) || (arg == NULL) || + ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) + return (0); + ns = arg->nodesetval; + /* + * A NULL nodeset compared with a string is always false + * (since there is no node equal, and no node not equal) + */ + if ((ns == NULL) || (ns->nodeNr <= 0) ) + return (0); + hash = xmlXPathStringHash(str); + for (i = 0; i < ns->nodeNr; i++) { + if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) { + str2 = xmlNodeGetContent(ns->nodeTab[i]); + if ((str2 != NULL) && (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); + return (1); + } + if (str2 != NULL) + xmlFree(str2); + } else if (neq) + return (1); + } + return (0); +} + +/** + * xmlXPathEqualNodeSetFloat: + * @arg: the nodeset object argument + * @f: the float to compare to + * @neq: flag to show whether to compare '=' (0) or '!=' (1) + * + * Implement the equal operation on XPath objects content: @arg1 == @arg2 + * If one object to be compared is a node-set and the other is a number, + * then the comparison will be true if and only if there is a node in + * the node-set such that the result of performing the comparison on the + * number to be compared and on the result of converting the string-value + * of that node to a number using the number function is true. + * + * Returns 0 or 1 depending on the results of the test. + */ +static int +xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt, + xmlXPathObjectPtr arg, double f, int neq) { + int i, ret=0; + xmlNodeSetPtr ns; + xmlChar *str2; + xmlXPathObjectPtr val; + double v; + + if ((arg == NULL) || + ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) + return(0); + + ns = arg->nodesetval; + if (ns != NULL) { + for (i=0;inodeNr;i++) { + str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); + if (str2 != NULL) { + valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2)); + xmlFree(str2); + xmlXPathNumberFunction(ctxt, 1); + val = valuePop(ctxt); + v = val->floatval; + xmlXPathReleaseObject(ctxt->context, val); + if (!xmlXPathIsNaN(v)) { + if ((!neq) && (v==f)) { + ret = 1; + break; + } else if ((neq) && (v!=f)) { + ret = 1; + break; + } + } else { /* NaN is unequal to any value */ + if (neq) + ret = 1; + } + } + } + } + + return(ret); +} + + +/** + * xmlXPathEqualNodeSets: + * @arg1: first nodeset object argument + * @arg2: second nodeset object argument + * @neq: flag to show whether to test '=' (0) or '!=' (1) + * + * Implement the equal / not equal operation on XPath nodesets: + * @arg1 == @arg2 or @arg1 != @arg2 + * If both objects to be compared are node-sets, then the comparison + * will be true if and only if there is a node in the first node-set and + * a node in the second node-set such that the result of performing the + * comparison on the string-values of the two nodes is true. + * + * (needless to say, this is a costly operation) + * + * Returns 0 or 1 depending on the results of the test. + */ +static int +xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) { + int i, j; + unsigned int *hashs1; + unsigned int *hashs2; + xmlChar **values1; + xmlChar **values2; + int ret = 0; + xmlNodeSetPtr ns1; + xmlNodeSetPtr ns2; + + if ((arg1 == NULL) || + ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) + return(0); + if ((arg2 == NULL) || + ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) + return(0); + + ns1 = arg1->nodesetval; + ns2 = arg2->nodesetval; + + if ((ns1 == NULL) || (ns1->nodeNr <= 0)) + return(0); + if ((ns2 == NULL) || (ns2->nodeNr <= 0)) + return(0); + + /* + * for equal, check if there is a node pertaining to both sets + */ + if (neq == 0) + for (i = 0;i < ns1->nodeNr;i++) + for (j = 0;j < ns2->nodeNr;j++) + if (ns1->nodeTab[i] == ns2->nodeTab[j]) + return(1); + + values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *)); + if (values1 == NULL) { + xmlXPathErrMemory(NULL, "comparing nodesets\n"); + return(0); + } + hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int)); + if (hashs1 == NULL) { + xmlXPathErrMemory(NULL, "comparing nodesets\n"); + xmlFree(values1); + return(0); + } + memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *)); + values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *)); + if (values2 == NULL) { + xmlXPathErrMemory(NULL, "comparing nodesets\n"); + xmlFree(hashs1); + xmlFree(values1); + return(0); + } + hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int)); + if (hashs2 == NULL) { + xmlXPathErrMemory(NULL, "comparing nodesets\n"); + xmlFree(hashs1); + xmlFree(values1); + xmlFree(values2); + return(0); + } + memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *)); + for (i = 0;i < ns1->nodeNr;i++) { + hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]); + for (j = 0;j < ns2->nodeNr;j++) { + if (i == 0) + hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]); + if (hashs1[i] != hashs2[j]) { + if (neq) { + ret = 1; + break; + } + } + else { + if (values1[i] == NULL) + values1[i] = xmlNodeGetContent(ns1->nodeTab[i]); + if (values2[j] == NULL) + values2[j] = xmlNodeGetContent(ns2->nodeTab[j]); + ret = xmlStrEqual(values1[i], values2[j]) ^ neq; + if (ret) + break; + } + } + if (ret) + break; + } + for (i = 0;i < ns1->nodeNr;i++) + if (values1[i] != NULL) + xmlFree(values1[i]); + for (j = 0;j < ns2->nodeNr;j++) + if (values2[j] != NULL) + xmlFree(values2[j]); + xmlFree(values1); + xmlFree(values2); + xmlFree(hashs1); + xmlFree(hashs2); + return(ret); +} + +static int +xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt, + xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) { + int ret = 0; + /* + *At this point we are assured neither arg1 nor arg2 + *is a nodeset, so we can just pick the appropriate routine. + */ + switch (arg1->type) { + case XPATH_UNDEFINED: +#ifdef DEBUG_EXPR + xmlGenericError(xmlGenericErrorContext, + "Equal: undefined\n"); +#endif + break; + case XPATH_BOOLEAN: + switch (arg2->type) { + case XPATH_UNDEFINED: +#ifdef DEBUG_EXPR + xmlGenericError(xmlGenericErrorContext, + "Equal: undefined\n"); +#endif + break; + case XPATH_BOOLEAN: +#ifdef DEBUG_EXPR + xmlGenericError(xmlGenericErrorContext, + "Equal: %d boolean %d \n", + arg1->boolval, arg2->boolval); +#endif + ret = (arg1->boolval == arg2->boolval); + break; + case XPATH_NUMBER: + ret = (arg1->boolval == + xmlXPathCastNumberToBoolean(arg2->floatval)); + break; + case XPATH_STRING: + if ((arg2->stringval == NULL) || + (arg2->stringval[0] == 0)) ret = 0; + else + ret = 1; + ret = (arg1->boolval == ret); + break; + case XPATH_USERS: + case XPATH_POINT: + case XPATH_RANGE: + case XPATH_LOCATIONSET: + TODO + break; + case XPATH_NODESET: + case XPATH_XSLT_TREE: + break; + } + break; + case XPATH_NUMBER: + switch (arg2->type) { + case XPATH_UNDEFINED: +#ifdef DEBUG_EXPR + xmlGenericError(xmlGenericErrorContext, + "Equal: undefined\n"); +#endif + break; + case XPATH_BOOLEAN: + ret = (arg2->boolval== + xmlXPathCastNumberToBoolean(arg1->floatval)); + break; + case XPATH_STRING: + valuePush(ctxt, arg2); + xmlXPathNumberFunction(ctxt, 1); + arg2 = valuePop(ctxt); + /* no break on purpose */ + case XPATH_NUMBER: + /* Hand check NaN and Infinity equalities */ + if (xmlXPathIsNaN(arg1->floatval) || + xmlXPathIsNaN(arg2->floatval)) { + ret = 0; + } else if (xmlXPathIsInf(arg1->floatval) == 1) { + if (xmlXPathIsInf(arg2->floatval) == 1) + ret = 1; + else + ret = 0; + } else if (xmlXPathIsInf(arg1->floatval) == -1) { + if (xmlXPathIsInf(arg2->floatval) == -1) + ret = 1; + else + ret = 0; + } else if (xmlXPathIsInf(arg2->floatval) == 1) { + if (xmlXPathIsInf(arg1->floatval) == 1) + ret = 1; + else + ret = 0; + } else if (xmlXPathIsInf(arg2->floatval) == -1) { + if (xmlXPathIsInf(arg1->floatval) == -1) + ret = 1; + else + ret = 0; + } else { + ret = (arg1->floatval == arg2->floatval); + } + break; + case XPATH_USERS: + case XPATH_POINT: + case XPATH_RANGE: + case XPATH_LOCATIONSET: + TODO + break; + case XPATH_NODESET: + case XPATH_XSLT_TREE: + break; + } + break; + case XPATH_STRING: + switch (arg2->type) { + case XPATH_UNDEFINED: +#ifdef DEBUG_EXPR + xmlGenericError(xmlGenericErrorContext, + "Equal: undefined\n"); +#endif + break; + case XPATH_BOOLEAN: + if ((arg1->stringval == NULL) || + (arg1->stringval[0] == 0)) ret = 0; + else + ret = 1; + ret = (arg2->boolval == ret); + break; + case XPATH_STRING: + ret = xmlStrEqual(arg1->stringval, arg2->stringval); + break; + case XPATH_NUMBER: + valuePush(ctxt, arg1); + xmlXPathNumberFunction(ctxt, 1); + arg1 = valuePop(ctxt); + /* Hand check NaN and Infinity equalities */ + if (xmlXPathIsNaN(arg1->floatval) || + xmlXPathIsNaN(arg2->floatval)) { + ret = 0; + } else if (xmlXPathIsInf(arg1->floatval) == 1) { + if (xmlXPathIsInf(arg2->floatval) == 1) + ret = 1; + else + ret = 0; + } else if (xmlXPathIsInf(arg1->floatval) == -1) { + if (xmlXPathIsInf(arg2->floatval) == -1) + ret = 1; + else + ret = 0; + } else if (xmlXPathIsInf(arg2->floatval) == 1) { + if (xmlXPathIsInf(arg1->floatval) == 1) + ret = 1; + else + ret = 0; + } else if (xmlXPathIsInf(arg2->floatval) == -1) { + if (xmlXPathIsInf(arg1->floatval) == -1) + ret = 1; + else + ret = 0; + } else { + ret = (arg1->floatval == arg2->floatval); + } + break; + case XPATH_USERS: + case XPATH_POINT: + case XPATH_RANGE: + case XPATH_LOCATIONSET: + TODO + break; + case XPATH_NODESET: + case XPATH_XSLT_TREE: + break; + } + break; + case XPATH_USERS: + case XPATH_POINT: + case XPATH_RANGE: + case XPATH_LOCATIONSET: + TODO + break; + case XPATH_NODESET: + case XPATH_XSLT_TREE: + break; + } + xmlXPathReleaseObject(ctxt->context, arg1); + xmlXPathReleaseObject(ctxt->context, arg2); + return(ret); +} + +/** + * xmlXPathEqualValues: + * @ctxt: the XPath Parser context + * + * Implement the equal operation on XPath objects content: @arg1 == @arg2 + * + * Returns 0 or 1 depending on the results of the test. + */ +int +xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) { + xmlXPathObjectPtr arg1, arg2, argtmp; + int ret = 0; + + if ((ctxt == NULL) || (ctxt->context == NULL)) return(0); + arg2 = valuePop(ctxt); + arg1 = valuePop(ctxt); + if ((arg1 == NULL) || (arg2 == NULL)) { + if (arg1 != NULL) + xmlXPathReleaseObject(ctxt->context, arg1); + else + xmlXPathReleaseObject(ctxt->context, arg2); + XP_ERROR0(XPATH_INVALID_OPERAND); + } + + if (arg1 == arg2) { +#ifdef DEBUG_EXPR + xmlGenericError(xmlGenericErrorContext, + "Equal: by pointer\n"); +#endif + xmlXPathFreeObject(arg1); + return(1); + } + + /* + *If either argument is a nodeset, it's a 'special case' + */ + if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || + (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { + /* + *Hack it to assure arg1 is the nodeset + */ + if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) { + argtmp = arg2; + arg2 = arg1; + arg1 = argtmp; + } + switch (arg2->type) { + case XPATH_UNDEFINED: +#ifdef DEBUG_EXPR + xmlGenericError(xmlGenericErrorContext, + "Equal: undefined\n"); +#endif + break; + case XPATH_NODESET: + case XPATH_XSLT_TREE: + ret = xmlXPathEqualNodeSets(arg1, arg2, 0); + break; + case XPATH_BOOLEAN: + if ((arg1->nodesetval == NULL) || + (arg1->nodesetval->nodeNr == 0)) ret = 0; + else + ret = 1; + ret = (ret == arg2->boolval); + break; + case XPATH_NUMBER: + ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0); + break; + case XPATH_STRING: + ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0); + break; + case XPATH_USERS: + case XPATH_POINT: + case XPATH_RANGE: + case XPATH_LOCATIONSET: + TODO + break; + } + xmlXPathReleaseObject(ctxt->context, arg1); + xmlXPathReleaseObject(ctxt->context, arg2); + return(ret); + } + + return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2)); +} + +/** + * xmlXPathNotEqualValues: + * @ctxt: the XPath Parser context + * + * Implement the equal operation on XPath objects content: @arg1 == @arg2 + * + * Returns 0 or 1 depending on the results of the test. + */ +int +xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) { + xmlXPathObjectPtr arg1, arg2, argtmp; + int ret = 0; + + if ((ctxt == NULL) || (ctxt->context == NULL)) return(0); + arg2 = valuePop(ctxt); + arg1 = valuePop(ctxt); + if ((arg1 == NULL) || (arg2 == NULL)) { + if (arg1 != NULL) + xmlXPathReleaseObject(ctxt->context, arg1); + else + xmlXPathReleaseObject(ctxt->context, arg2); + XP_ERROR0(XPATH_INVALID_OPERAND); + } + + if (arg1 == arg2) { +#ifdef DEBUG_EXPR + xmlGenericError(xmlGenericErrorContext, + "NotEqual: by pointer\n"); +#endif + xmlXPathReleaseObject(ctxt->context, arg1); + return(0); + } + + /* + *If either argument is a nodeset, it's a 'special case' + */ + if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || + (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { + /* + *Hack it to assure arg1 is the nodeset + */ + if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) { + argtmp = arg2; + arg2 = arg1; + arg1 = argtmp; + } + switch (arg2->type) { + case XPATH_UNDEFINED: +#ifdef DEBUG_EXPR + xmlGenericError(xmlGenericErrorContext, + "NotEqual: undefined\n"); +#endif + break; + case XPATH_NODESET: + case XPATH_XSLT_TREE: + ret = xmlXPathEqualNodeSets(arg1, arg2, 1); + break; + case XPATH_BOOLEAN: + if ((arg1->nodesetval == NULL) || + (arg1->nodesetval->nodeNr == 0)) ret = 0; + else + ret = 1; + ret = (ret != arg2->boolval); + break; + case XPATH_NUMBER: + ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1); + break; + case XPATH_STRING: + ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1); + break; + case XPATH_USERS: + case XPATH_POINT: + case XPATH_RANGE: + case XPATH_LOCATIONSET: + TODO + break; + } + xmlXPathReleaseObject(ctxt->context, arg1); + xmlXPathReleaseObject(ctxt->context, arg2); + return(ret); + } + + return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2)); +} + +/** + * xmlXPathCompareValues: + * @ctxt: the XPath Parser context + * @inf: less than (1) or greater than (0) + * @strict: is the comparison strict + * + * Implement the compare operation on XPath objects: + * @arg1 < @arg2 (1, 1, ... + * @arg1 <= @arg2 (1, 0, ... + * @arg1 > @arg2 (0, 1, ... + * @arg1 >= @arg2 (0, 0, ... + * + * When neither object to be compared is a node-set and the operator is + * <=, <, >=, >, then the objects are compared by converted both objects + * to numbers and comparing the numbers according to IEEE 754. The < + * comparison will be true if and only if the first number is less than the + * second number. The <= comparison will be true if and only if the first + * number is less than or equal to the second number. The > comparison + * will be true if and only if the first number is greater than the second + * number. The >= comparison will be true if and only if the first number + * is greater than or equal to the second number. + * + * Returns 1 if the comparison succeeded, 0 if it failed + */ +int +xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) { + int ret = 0, arg1i = 0, arg2i = 0; + xmlXPathObjectPtr arg1, arg2; + + if ((ctxt == NULL) || (ctxt->context == NULL)) return(0); + arg2 = valuePop(ctxt); + arg1 = valuePop(ctxt); + if ((arg1 == NULL) || (arg2 == NULL)) { + if (arg1 != NULL) + xmlXPathReleaseObject(ctxt->context, arg1); + else + xmlXPathReleaseObject(ctxt->context, arg2); + XP_ERROR0(XPATH_INVALID_OPERAND); + } + + if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) || + (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { + /* + * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments + * are not freed from within this routine; they will be freed from the + * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue + */ + 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); + } else { + if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { + ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict, + arg1, arg2); + } else { + ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict, + arg2, arg1); + } + } + return(ret); + } + + if (arg1->type != XPATH_NUMBER) { + valuePush(ctxt, arg1); + xmlXPathNumberFunction(ctxt, 1); + arg1 = valuePop(ctxt); + } + if (arg1->type != XPATH_NUMBER) { + xmlXPathFreeObject(arg1); + xmlXPathFreeObject(arg2); + XP_ERROR0(XPATH_INVALID_OPERAND); + } + if (arg2->type != XPATH_NUMBER) { + valuePush(ctxt, arg2); + xmlXPathNumberFunction(ctxt, 1); + arg2 = valuePop(ctxt); + } + if (arg2->type != XPATH_NUMBER) { + xmlXPathReleaseObject(ctxt->context, arg1); + xmlXPathReleaseObject(ctxt->context, arg2); + XP_ERROR0(XPATH_INVALID_OPERAND); + } + /* + * Add tests for infinity and nan + * => feedback on 3.4 for Inf and NaN + */ + /* Hand check NaN and Infinity comparisons */ + if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) { + ret=0; + } else { + arg1i=xmlXPathIsInf(arg1->floatval); + arg2i=xmlXPathIsInf(arg2->floatval); + if (inf && strict) { + if ((arg1i == -1 && arg2i != -1) || + (arg2i == 1 && arg1i != 1)) { + ret = 1; + } else if (arg1i == 0 && arg2i == 0) { + ret = (arg1->floatval < arg2->floatval); + } else { + ret = 0; + } + } + else if (inf && !strict) { + if (arg1i == -1 || arg2i == 1) { + ret = 1; + } else if (arg1i == 0 && arg2i == 0) { + ret = (arg1->floatval <= arg2->floatval); + } else { + ret = 0; + } + } + else if (!inf && strict) { + if ((arg1i == 1 && arg2i != 1) || + (arg2i == -1 && arg1i != -1)) { + ret = 1; + } else if (arg1i == 0 && arg2i == 0) { + ret = (arg1->floatval > arg2->floatval); + } else { + ret = 0; + } + } + else if (!inf && !strict) { + if (arg1i == 1 || arg2i == -1) { + ret = 1; + } else if (arg1i == 0 && arg2i == 0) { + ret = (arg1->floatval >= arg2->floatval); + } else { + ret = 0; + } + } + } + xmlXPathReleaseObject(ctxt->context, arg1); + xmlXPathReleaseObject(ctxt->context, arg2); + return(ret); +} + +/** + * xmlXPathValueFlipSign: + * @ctxt: the XPath Parser context + * + * Implement the unary - operation on an XPath object + * The numeric operators convert their operands to numbers as if + * by calling the number function. + */ +void +xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) { + if ((ctxt == NULL) || (ctxt->context == NULL)) return; + CAST_TO_NUMBER; + CHECK_TYPE(XPATH_NUMBER); + if (xmlXPathIsNaN(ctxt->value->floatval)) + ctxt->value->floatval=xmlXPathNAN; + else if (xmlXPathIsInf(ctxt->value->floatval) == 1) + ctxt->value->floatval=xmlXPathNINF; + else if (xmlXPathIsInf(ctxt->value->floatval) == -1) + ctxt->value->floatval=xmlXPathPINF; + else if (ctxt->value->floatval == 0) { + if (xmlXPathGetSign(ctxt->value->floatval) == 0) + ctxt->value->floatval = xmlXPathNZERO; + else + ctxt->value->floatval = 0; + } + else + ctxt->value->floatval = - ctxt->value->floatval; +} + +/** + * xmlXPathAddValues: + * @ctxt: the XPath Parser context + * + * Implement the add operation on XPath objects: + * The numeric operators convert their operands to numbers as if + * by calling the number function. + */ +void +xmlXPathAddValues(xmlXPathParserContextPtr ctxt) { + xmlXPathObjectPtr arg; + double val; + + arg = valuePop(ctxt); + if (arg == NULL) + XP_ERROR(XPATH_INVALID_OPERAND); + val = xmlXPathCastToNumber(arg); + xmlXPathReleaseObject(ctxt->context, arg); + CAST_TO_NUMBER; + CHECK_TYPE(XPATH_NUMBER); + ctxt->value->floatval += val; +} + +/** + * xmlXPathSubValues: + * @ctxt: the XPath Parser context + * + * Implement the subtraction operation on XPath objects: + * The numeric operators convert their operands to numbers as if + * by calling the number function. + */ +void +xmlXPathSubValues(xmlXPathParserContextPtr ctxt) { + xmlXPathObjectPtr arg; + double val; + + arg = valuePop(ctxt); + if (arg == NULL) + XP_ERROR(XPATH_INVALID_OPERAND); + val = xmlXPathCastToNumber(arg); + xmlXPathReleaseObject(ctxt->context, arg); + CAST_TO_NUMBER; + CHECK_TYPE(XPATH_NUMBER); + ctxt->value->floatval -= val; +} + +/** + * xmlXPathMultValues: + * @ctxt: the XPath Parser context + * + * Implement the multiply operation on XPath objects: + * The numeric operators convert their operands to numbers as if + * by calling the number function. + */ +void +xmlXPathMultValues(xmlXPathParserContextPtr ctxt) { + xmlXPathObjectPtr arg; + double val; + + arg = valuePop(ctxt); + if (arg == NULL) + XP_ERROR(XPATH_INVALID_OPERAND); + val = xmlXPathCastToNumber(arg); + xmlXPathReleaseObject(ctxt->context, arg); + CAST_TO_NUMBER; + CHECK_TYPE(XPATH_NUMBER); + ctxt->value->floatval *= val; +} + +/** + * xmlXPathDivValues: + * @ctxt: the XPath Parser context + * + * Implement the div operation on XPath objects @arg1 / @arg2: + * The numeric operators convert their operands to numbers as if + * by calling the number function. + */ +void +xmlXPathDivValues(xmlXPathParserContextPtr ctxt) { + xmlXPathObjectPtr arg; + double val; + + arg = valuePop(ctxt); + if (arg == NULL) + XP_ERROR(XPATH_INVALID_OPERAND); + val = xmlXPathCastToNumber(arg); + xmlXPathReleaseObject(ctxt->context, arg); + CAST_TO_NUMBER; + CHECK_TYPE(XPATH_NUMBER); + if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval)) + ctxt->value->floatval = xmlXPathNAN; + else if (val == 0 && xmlXPathGetSign(val) != 0) { + if (ctxt->value->floatval == 0) + ctxt->value->floatval = xmlXPathNAN; + else if (ctxt->value->floatval > 0) + ctxt->value->floatval = xmlXPathNINF; + else if (ctxt->value->floatval < 0) + ctxt->value->floatval = xmlXPathPINF; + } + else if (val == 0) { + if (ctxt->value->floatval == 0) + ctxt->value->floatval = xmlXPathNAN; + else if (ctxt->value->floatval > 0) + ctxt->value->floatval = xmlXPathPINF; + else if (ctxt->value->floatval < 0) + ctxt->value->floatval = xmlXPathNINF; + } else + ctxt->value->floatval /= val; +} + +/** + * xmlXPathModValues: + * @ctxt: the XPath Parser context + * + * Implement the mod operation on XPath objects: @arg1 / @arg2 + * The numeric operators convert their operands to numbers as if + * by calling the number function. + */ +void +xmlXPathModValues(xmlXPathParserContextPtr ctxt) { + xmlXPathObjectPtr arg; + double arg1, arg2; + + arg = valuePop(ctxt); + if (arg == NULL) + XP_ERROR(XPATH_INVALID_OPERAND); + arg2 = xmlXPathCastToNumber(arg); + xmlXPathReleaseObject(ctxt->context, arg); + CAST_TO_NUMBER; + CHECK_TYPE(XPATH_NUMBER); + arg1 = ctxt->value->floatval; + if (arg2 == 0) + ctxt->value->floatval = xmlXPathNAN; + else { + ctxt->value->floatval = fmod(arg1, arg2); + } +} + +/************************************************************************ + * * + * The traversal functions * + * * + ************************************************************************/ + +/* + * A traversal function enumerates nodes along an axis. + * Initially it must be called with NULL, and it indicates + * termination on the axis by returning NULL. + */ +typedef xmlNodePtr (*xmlXPathTraversalFunction) + (xmlXPathParserContextPtr ctxt, xmlNodePtr cur); + +/* + * xmlXPathTraversalFunctionExt: + * A traversal function enumerates nodes along an axis. + * Initially it must be called with NULL, and it indicates + * termination on the axis by returning NULL. + * The context node of the traversal is specified via @contextNode. + */ +typedef xmlNodePtr (*xmlXPathTraversalFunctionExt) + (xmlNodePtr cur, xmlNodePtr contextNode); + +/* + * xmlXPathNodeSetMergeFunction: + * Used for merging node sets in xmlXPathCollectAndTest(). + */ +typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction) + (xmlNodeSetPtr, xmlNodeSetPtr, int); + + +/** + * xmlXPathNextSelf: + * @ctxt: the XPath Parser context + * @cur: the current node in the traversal + * + * Traversal function for the "self" direction + * The self axis contains just the context node itself + * + * Returns the next element following that axis + */ +xmlNodePtr +xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { + if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); + if (cur == NULL) + return(ctxt->context->node); + return(NULL); +} + +/** + * xmlXPathNextChild: + * @ctxt: the XPath Parser context + * @cur: the current node in the traversal + * + * Traversal function for the "child" direction + * The child axis contains the children of the context node in document order. + * + * Returns the next element following that axis + */ +xmlNodePtr +xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { + if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); + if (cur == NULL) { + if (ctxt->context->node == NULL) return(NULL); + switch (ctxt->context->node->type) { + case XML_ELEMENT_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_NOTATION_NODE: + case XML_DTD_NODE: + return(ctxt->context->node->children); + case XML_DOCUMENT_NODE: + case XML_DOCUMENT_TYPE_NODE: + case XML_DOCUMENT_FRAG_NODE: + case XML_HTML_DOCUMENT_NODE: +#ifdef LIBXML_DOCB_ENABLED + case XML_DOCB_DOCUMENT_NODE: +#endif + return(((xmlDocPtr) ctxt->context->node)->children); + case XML_ELEMENT_DECL: + case XML_ATTRIBUTE_DECL: + case XML_ENTITY_DECL: + case XML_ATTRIBUTE_NODE: + case XML_NAMESPACE_DECL: + case XML_XINCLUDE_START: + case XML_XINCLUDE_END: + return(NULL); + } + return(NULL); + } + if ((cur->type == XML_DOCUMENT_NODE) || + (cur->type == XML_HTML_DOCUMENT_NODE)) + return(NULL); + return(cur->next); +} + +/** + * xmlXPathNextChildElement: + * @ctxt: the XPath Parser context + * @cur: the current node in the traversal + * + * Traversal function for the "child" direction and nodes of type element. + * The child axis contains the children of the context node in document order. + * + * Returns the next element following that axis + */ +static xmlNodePtr +xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { + if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); + if (cur == NULL) { + cur = ctxt->context->node; + if (cur == NULL) return(NULL); + /* + * Get the first element child. + */ + switch (cur->type) { + case XML_ELEMENT_NODE: + case XML_DOCUMENT_FRAG_NODE: + case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */ + case XML_ENTITY_NODE: + cur = cur->children; + if (cur != NULL) { + if (cur->type == XML_ELEMENT_NODE) + return(cur); + do { + cur = cur->next; + } while ((cur != NULL) && + (cur->type != XML_ELEMENT_NODE)); + return(cur); + } + return(NULL); + case XML_DOCUMENT_NODE: + case XML_HTML_DOCUMENT_NODE: +#ifdef LIBXML_DOCB_ENABLED + case XML_DOCB_DOCUMENT_NODE: +#endif + return(xmlDocGetRootElement((xmlDocPtr) cur)); + default: + return(NULL); + } + return(NULL); + } + /* + * Get the next sibling element node. + */ + switch (cur->type) { + case XML_ELEMENT_NODE: + case XML_TEXT_NODE: + case XML_ENTITY_REF_NODE: + case XML_ENTITY_NODE: + case XML_CDATA_SECTION_NODE: + case XML_PI_NODE: + case XML_COMMENT_NODE: + case XML_XINCLUDE_END: + break; + /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */ + default: + return(NULL); + } + if (cur->next != NULL) { + if (cur->next->type == XML_ELEMENT_NODE) + return(cur->next); + cur = cur->next; + do { + cur = cur->next; + } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE)); + return(cur); + } + return(NULL); +} + +/** + * xmlXPathNextDescendantOrSelfElemParent: + * @ctxt: the XPath Parser context + * @cur: the current node in the traversal + * + * Traversal function for the "descendant-or-self" axis. + * Additionally it returns only nodes which can be parents of + * element nodes. + * + * + * Returns the next element following that axis + */ +static xmlNodePtr +xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur, + xmlNodePtr contextNode) +{ + if (cur == NULL) { + if (contextNode == NULL) + return(NULL); + switch (contextNode->type) { + case XML_ELEMENT_NODE: + case XML_XINCLUDE_START: + case XML_DOCUMENT_FRAG_NODE: + case XML_DOCUMENT_NODE: +#ifdef LIBXML_DOCB_ENABLED + case XML_DOCB_DOCUMENT_NODE: +#endif + case XML_HTML_DOCUMENT_NODE: + return(contextNode); + default: + return(NULL); + } + return(NULL); + } else { + xmlNodePtr start = cur; + + while (cur != NULL) { + switch (cur->type) { + case XML_ELEMENT_NODE: + /* TODO: OK to have XInclude here? */ + case XML_XINCLUDE_START: + case XML_DOCUMENT_FRAG_NODE: + if (cur != start) + return(cur); + if (cur->children != NULL) { + cur = cur->children; + continue; + } + break; + /* Not sure if we need those here. */ + case XML_DOCUMENT_NODE: +#ifdef LIBXML_DOCB_ENABLED + case XML_DOCB_DOCUMENT_NODE: +#endif + case XML_HTML_DOCUMENT_NODE: + if (cur != start) + return(cur); + return(xmlDocGetRootElement((xmlDocPtr) cur)); + default: + break; + } + +next_sibling: + if ((cur == NULL) || (cur == contextNode)) + return(NULL); + if (cur->next != NULL) { + cur = cur->next; + } else { + cur = cur->parent; + goto next_sibling; + } + } + } + return(NULL); +} + +/** + * xmlXPathNextDescendant: + * @ctxt: the XPath Parser context + * @cur: the current node in the traversal + * + * Traversal function for the "descendant" direction + * the descendant axis contains the descendants of the context node in document + * order; a descendant is a child or a child of a child and so on. + * + * Returns the next element following that axis + */ +xmlNodePtr +xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { + if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); + if (cur == NULL) { + if (ctxt->context->node == NULL) + return(NULL); + if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || + (ctxt->context->node->type == XML_NAMESPACE_DECL)) + return(NULL); + + if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc) + return(ctxt->context->doc->children); + return(ctxt->context->node->children); + } + + if (cur->children != NULL) { + /* + * Do not descend on entities declarations + */ + if (cur->children->type != XML_ENTITY_DECL) { + cur = cur->children; + /* + * Skip DTDs + */ + if (cur->type != XML_DTD_NODE) + return(cur); + } + } + + if (cur == ctxt->context->node) return(NULL); + + while (cur->next != NULL) { + cur = cur->next; + if ((cur->type != XML_ENTITY_DECL) && + (cur->type != XML_DTD_NODE)) + return(cur); + } + + do { + cur = cur->parent; + if (cur == NULL) break; + if (cur == ctxt->context->node) return(NULL); + if (cur->next != NULL) { + cur = cur->next; + return(cur); + } + } while (cur != NULL); + return(cur); +} + +/** + * xmlXPathNextDescendantOrSelf: + * @ctxt: the XPath Parser context + * @cur: the current node in the traversal + * + * Traversal function for the "descendant-or-self" direction + * the descendant-or-self axis contains the context node and the descendants + * of the context node in document order; thus the context node is the first + * node on the axis, and the first child of the context node is the second node + * on the axis + * + * Returns the next element following that axis + */ +xmlNodePtr +xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { + if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); + if (cur == NULL) { + if (ctxt->context->node == NULL) + return(NULL); + if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || + (ctxt->context->node->type == XML_NAMESPACE_DECL)) + return(NULL); + return(ctxt->context->node); + } + + return(xmlXPathNextDescendant(ctxt, cur)); +} + +/** + * xmlXPathNextParent: + * @ctxt: the XPath Parser context + * @cur: the current node in the traversal + * + * Traversal function for the "parent" direction + * The parent axis contains the parent of the context node, if there is one. + * + * Returns the next element following that axis + */ +xmlNodePtr +xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { + if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); + /* + * the parent of an attribute or namespace node is the element + * to which the attribute or namespace node is attached + * Namespace handling !!! + */ + if (cur == NULL) { + if (ctxt->context->node == NULL) return(NULL); + switch (ctxt->context->node->type) { + case XML_ELEMENT_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_NOTATION_NODE: + case XML_DTD_NODE: + case XML_ELEMENT_DECL: + case XML_ATTRIBUTE_DECL: + case XML_XINCLUDE_START: + case XML_XINCLUDE_END: + case XML_ENTITY_DECL: + if (ctxt->context->node->parent == NULL) + return((xmlNodePtr) ctxt->context->doc); + if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) && + ((ctxt->context->node->parent->name[0] == ' ') || + (xmlStrEqual(ctxt->context->node->parent->name, + BAD_CAST "fake node libxslt")))) + return(NULL); + return(ctxt->context->node->parent); + case XML_ATTRIBUTE_NODE: { + xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node; + + return(att->parent); + } + case XML_DOCUMENT_NODE: + case XML_DOCUMENT_TYPE_NODE: + case XML_DOCUMENT_FRAG_NODE: + case XML_HTML_DOCUMENT_NODE: +#ifdef LIBXML_DOCB_ENABLED + case XML_DOCB_DOCUMENT_NODE: +#endif + return(NULL); + case XML_NAMESPACE_DECL: { + xmlNsPtr ns = (xmlNsPtr) ctxt->context->node; + + if ((ns->next != NULL) && + (ns->next->type != XML_NAMESPACE_DECL)) + return((xmlNodePtr) ns->next); + return(NULL); + } + } + } + return(NULL); +} + +/** + * xmlXPathNextAncestor: + * @ctxt: the XPath Parser context + * @cur: the current node in the traversal + * + * Traversal function for the "ancestor" direction + * the ancestor axis contains the ancestors of the context node; the ancestors + * of the context node consist of the parent of context node and the parent's + * parent and so on; the nodes are ordered in reverse document order; thus the + * parent is the first node on the axis, and the parent's parent is the second + * node on the axis + * + * Returns the next element following that axis + */ +xmlNodePtr +xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { + if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); + /* + * the parent of an attribute or namespace node is the element + * to which the attribute or namespace node is attached + * !!!!!!!!!!!!! + */ + if (cur == NULL) { + if (ctxt->context->node == NULL) return(NULL); + switch (ctxt->context->node->type) { + case XML_ELEMENT_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: + case XML_ELEMENT_DECL: + case XML_ATTRIBUTE_DECL: + case XML_ENTITY_DECL: + case XML_NOTATION_NODE: + case XML_XINCLUDE_START: + case XML_XINCLUDE_END: + if (ctxt->context->node->parent == NULL) + return((xmlNodePtr) ctxt->context->doc); + if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) && + ((ctxt->context->node->parent->name[0] == ' ') || + (xmlStrEqual(ctxt->context->node->parent->name, + BAD_CAST "fake node libxslt")))) + return(NULL); + return(ctxt->context->node->parent); + case XML_ATTRIBUTE_NODE: { + xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node; + + return(tmp->parent); + } + case XML_DOCUMENT_NODE: + case XML_DOCUMENT_TYPE_NODE: + case XML_DOCUMENT_FRAG_NODE: + case XML_HTML_DOCUMENT_NODE: +#ifdef LIBXML_DOCB_ENABLED + case XML_DOCB_DOCUMENT_NODE: +#endif + return(NULL); + case XML_NAMESPACE_DECL: { + xmlNsPtr ns = (xmlNsPtr) ctxt->context->node; + + if ((ns->next != NULL) && + (ns->next->type != XML_NAMESPACE_DECL)) + return((xmlNodePtr) ns->next); + /* Bad, how did that namespace end up here ? */ + return(NULL); + } + } + return(NULL); + } + if (cur == ctxt->context->doc->children) + return((xmlNodePtr) ctxt->context->doc); + if (cur == (xmlNodePtr) ctxt->context->doc) + return(NULL); + switch (cur->type) { + case XML_ELEMENT_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_NOTATION_NODE: + case XML_DTD_NODE: + case XML_ELEMENT_DECL: + case XML_ATTRIBUTE_DECL: + case XML_ENTITY_DECL: + case XML_XINCLUDE_START: + case XML_XINCLUDE_END: + if (cur->parent == NULL) + return(NULL); + if ((cur->parent->type == XML_ELEMENT_NODE) && + ((cur->parent->name[0] == ' ') || + (xmlStrEqual(cur->parent->name, + BAD_CAST "fake node libxslt")))) + return(NULL); + return(cur->parent); + case XML_ATTRIBUTE_NODE: { + xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node; + + return(att->parent); + } + case XML_NAMESPACE_DECL: { + xmlNsPtr ns = (xmlNsPtr) ctxt->context->node; + + if ((ns->next != NULL) && + (ns->next->type != XML_NAMESPACE_DECL)) + return((xmlNodePtr) ns->next); + /* Bad, how did that namespace end up here ? */ + return(NULL); + } + case XML_DOCUMENT_NODE: + case XML_DOCUMENT_TYPE_NODE: + case XML_DOCUMENT_FRAG_NODE: + case XML_HTML_DOCUMENT_NODE: +#ifdef LIBXML_DOCB_ENABLED + case XML_DOCB_DOCUMENT_NODE: +#endif + return(NULL); + } + return(NULL); +} + +/** + * xmlXPathNextAncestorOrSelf: + * @ctxt: the XPath Parser context + * @cur: the current node in the traversal + * + * Traversal function for the "ancestor-or-self" direction + * he ancestor-or-self axis contains the context node and ancestors of + * the context node in reverse document order; thus the context node is + * the first node on the axis, and the context node's parent the second; + * parent here is defined the same as with the parent axis. + * + * Returns the next element following that axis + */ +xmlNodePtr +xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { + if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); + if (cur == NULL) + return(ctxt->context->node); + return(xmlXPathNextAncestor(ctxt, cur)); +} + +/** + * xmlXPathNextFollowingSibling: + * @ctxt: the XPath Parser context + * @cur: the current node in the traversal + * + * Traversal function for the "following-sibling" direction + * The following-sibling axis contains the following siblings of the context + * node in document order. + * + * Returns the next element following that axis + */ +xmlNodePtr +xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { + if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); + if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || + (ctxt->context->node->type == XML_NAMESPACE_DECL)) + return(NULL); + if (cur == (xmlNodePtr) ctxt->context->doc) + return(NULL); + if (cur == NULL) + return(ctxt->context->node->next); + return(cur->next); +} + +/** + * xmlXPathNextPrecedingSibling: + * @ctxt: the XPath Parser context + * @cur: the current node in the traversal + * + * Traversal function for the "preceding-sibling" direction + * The preceding-sibling axis contains the preceding siblings of the context + * node in reverse document order; the first preceding sibling is first on the + * axis; the sibling preceding that node is the second on the axis and so on. + * + * Returns the next element following that axis + */ +xmlNodePtr +xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { + if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); + if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || + (ctxt->context->node->type == XML_NAMESPACE_DECL)) + return(NULL); + if (cur == (xmlNodePtr) ctxt->context->doc) + return(NULL); + if (cur == NULL) + return(ctxt->context->node->prev); + if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) { + cur = cur->prev; + if (cur == NULL) + return(ctxt->context->node->prev); + } + return(cur->prev); +} + +/** + * xmlXPathNextFollowing: + * @ctxt: the XPath Parser context + * @cur: the current node in the traversal + * + * Traversal function for the "following" direction + * The following axis contains all nodes in the same document as the context + * node that are after the context node in document order, excluding any + * descendants and excluding attribute nodes and namespace nodes; the nodes + * are ordered in document order + * + * Returns the next element following that axis + */ +xmlNodePtr +xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { + if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); + if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) && + (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL)) + return(cur->children); + + if (cur == NULL) { + cur = ctxt->context->node; + if (cur->type == XML_NAMESPACE_DECL) + return(NULL); + if (cur->type == XML_ATTRIBUTE_NODE) + cur = cur->parent; + } + if (cur == NULL) return(NULL) ; /* ERROR */ + if (cur->next != NULL) return(cur->next) ; + do { + cur = cur->parent; + if (cur == NULL) break; + if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL); + if (cur->next != NULL) return(cur->next); + } while (cur != NULL); + return(cur); +} + +/* + * xmlXPathIsAncestor: + * @ancestor: the ancestor node + * @node: the current node + * + * Check that @ancestor is a @node's ancestor + * + * returns 1 if @ancestor is a @node's ancestor, 0 otherwise. + */ +static int +xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) { + if ((ancestor == NULL) || (node == NULL)) return(0); + /* nodes need to be in the same document */ + if (ancestor->doc != node->doc) return(0); + /* avoid searching if ancestor or node is the root node */ + if (ancestor == (xmlNodePtr) node->doc) return(1); + if (node == (xmlNodePtr) ancestor->doc) return(0); + while (node->parent != NULL) { + if (node->parent == ancestor) + return(1); + node = node->parent; + } + return(0); +} + +/** + * xmlXPathNextPreceding: + * @ctxt: the XPath Parser context + * @cur: the current node in the traversal + * + * Traversal function for the "preceding" direction + * the preceding axis contains all nodes in the same document as the context + * node that are before the context node in document order, excluding any + * ancestors and excluding attribute nodes and namespace nodes; the nodes are + * ordered in reverse document order + * + * Returns the next element following that axis + */ +xmlNodePtr +xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) +{ + if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); + if (cur == NULL) { + cur = ctxt->context->node; + if (cur->type == XML_NAMESPACE_DECL) + return(NULL); + if (cur->type == XML_ATTRIBUTE_NODE) + return(cur->parent); + } + if (cur == NULL) + return (NULL); + if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) + cur = cur->prev; + do { + if (cur->prev != NULL) { + for (cur = cur->prev; cur->last != NULL; cur = cur->last) ; + return (cur); + } + + cur = cur->parent; + if (cur == NULL) + return (NULL); + if (cur == ctxt->context->doc->children) + return (NULL); + } while (xmlXPathIsAncestor(cur, ctxt->context->node)); + return (cur); +} + +/** + * xmlXPathNextPrecedingInternal: + * @ctxt: the XPath Parser context + * @cur: the current node in the traversal + * + * Traversal function for the "preceding" direction + * the preceding axis contains all nodes in the same document as the context + * node that are before the context node in document order, excluding any + * ancestors and excluding attribute nodes and namespace nodes; the nodes are + * ordered in reverse document order + * This is a faster implementation but internal only since it requires a + * state kept in the parser context: ctxt->ancestor. + * + * Returns the next element following that axis + */ +static xmlNodePtr +xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt, + xmlNodePtr cur) +{ + if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); + if (cur == NULL) { + cur = ctxt->context->node; + if (cur == NULL) + return (NULL); + if (cur->type == XML_NAMESPACE_DECL) + return (NULL); + ctxt->ancestor = cur->parent; + } + if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) + cur = cur->prev; + while (cur->prev == NULL) { + cur = cur->parent; + if (cur == NULL) + return (NULL); + if (cur == ctxt->context->doc->children) + return (NULL); + if (cur != ctxt->ancestor) + return (cur); + ctxt->ancestor = cur->parent; + } + cur = cur->prev; + while (cur->last != NULL) + cur = cur->last; + return (cur); +} + +/** + * xmlXPathNextNamespace: + * @ctxt: the XPath Parser context + * @cur: the current attribute in the traversal + * + * Traversal function for the "namespace" direction + * the namespace axis contains the namespace nodes of the context node; + * the order of nodes on this axis is implementation-defined; the axis will + * be empty unless the context node is an element + * + * We keep the XML namespace node at the end of the list. + * + * Returns the next element following that axis + */ +xmlNodePtr +xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { + if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); + if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL); + if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) { + 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++; + } + } + return((xmlNodePtr) xmlXPathXMLNamespace); + } + if (ctxt->context->tmpNsNr > 0) { + return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr]; + } else { + if (ctxt->context->tmpNsList != NULL) + xmlFree(ctxt->context->tmpNsList); + ctxt->context->tmpNsList = NULL; + return(NULL); + } +} + +/** + * xmlXPathNextAttribute: + * @ctxt: the XPath Parser context + * @cur: the current attribute in the traversal + * + * Traversal function for the "attribute" direction + * TODO: support DTD inherited default attributes + * + * Returns the next element following that axis + */ +xmlNodePtr +xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { + if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); + if (ctxt->context->node == NULL) + return(NULL); + if (ctxt->context->node->type != XML_ELEMENT_NODE) + return(NULL); + if (cur == NULL) { + if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc) + return(NULL); + return((xmlNodePtr)ctxt->context->node->properties); + } + return((xmlNodePtr)cur->next); +} + +/************************************************************************ + * * + * NodeTest Functions * + * * + ************************************************************************/ + +#define IS_FUNCTION 200 + + +/************************************************************************ + * * + * Implicit tree core function library * + * * + ************************************************************************/ + +/** + * xmlXPathRoot: + * @ctxt: the XPath Parser context + * + * Initialize the context to the root of the document + */ +void +xmlXPathRoot(xmlXPathParserContextPtr ctxt) { + if ((ctxt == NULL) || (ctxt->context == NULL)) + return; + ctxt->context->node = (xmlNodePtr) ctxt->context->doc; + valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, + ctxt->context->node)); +} + +/************************************************************************ + * * + * The explicit core function library * + *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib * + * * + ************************************************************************/ + + +/** + * xmlXPathLastFunction: + * @ctxt: the XPath Parser context + * @nargs: the number of arguments + * + * Implement the last() XPath function + * number last() + * The last function returns the number of nodes in the context node list. + */ +void +xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) { + CHECK_ARITY(0); + if (ctxt->context->contextSize >= 0) { + valuePush(ctxt, + xmlXPathCacheNewFloat(ctxt->context, + (double) ctxt->context->contextSize)); +#ifdef DEBUG_EXPR + xmlGenericError(xmlGenericErrorContext, + "last() : %d\n", ctxt->context->contextSize); +#endif + } else { + XP_ERROR(XPATH_INVALID_CTXT_SIZE); + } +} + +/** + * xmlXPathPositionFunction: + * @ctxt: the XPath Parser context + * @nargs: the number of arguments + * + * Implement the position() XPath function + * number position() + * The position function returns the position of the context node in the + * context node list. The first position is 1, and so the last position + * will be equal to last(). + */ +void +xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) { + CHECK_ARITY(0); + if (ctxt->context->proximityPosition >= 0) { + valuePush(ctxt, + xmlXPathCacheNewFloat(ctxt->context, + (double) ctxt->context->proximityPosition)); +#ifdef DEBUG_EXPR + xmlGenericError(xmlGenericErrorContext, "position() : %d\n", + ctxt->context->proximityPosition); +#endif + } else { + XP_ERROR(XPATH_INVALID_CTXT_POSITION); + } +} + +/** + * xmlXPathCountFunction: + * @ctxt: the XPath Parser context + * @nargs: the number of arguments + * + * Implement the count() XPath function + * number count(node-set) + */ +void +xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) { + xmlXPathObjectPtr cur; + + CHECK_ARITY(1); + if ((ctxt->value == NULL) || + ((ctxt->value->type != XPATH_NODESET) && + (ctxt->value->type != XPATH_XSLT_TREE))) + XP_ERROR(XPATH_INVALID_TYPE); + cur = valuePop(ctxt); + + if ((cur == NULL) || (cur->nodesetval == NULL)) + valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0)); + else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) { + valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, + (double) cur->nodesetval->nodeNr)); + } else { + if ((cur->nodesetval->nodeNr != 1) || + (cur->nodesetval->nodeTab == NULL)) { + valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0)); + } else { + xmlNodePtr tmp; + int i = 0; + + tmp = cur->nodesetval->nodeTab[0]; + if (tmp != NULL) { + tmp = tmp->children; + while (tmp != NULL) { + tmp = tmp->next; + i++; + } + } + valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i)); + } + } + xmlXPathReleaseObject(ctxt->context, cur); +} + +/** + * xmlXPathGetElementsByIds: + * @doc: the document + * @ids: a whitespace separated list of IDs + * + * Selects elements by their unique ID. + * + * Returns a node-set of selected elements. + */ +static xmlNodeSetPtr +xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) { + xmlNodeSetPtr ret; + const xmlChar *cur = ids; + xmlChar *ID; + xmlAttrPtr attr; + xmlNodePtr elem = NULL; + + if (ids == NULL) return(NULL); + + ret = xmlXPathNodeSetCreate(NULL); + if (ret == NULL) + return(ret); + + while (IS_BLANK_CH(*cur)) cur++; + while (*cur != 0) { + while ((!IS_BLANK_CH(*cur)) && (*cur != 0)) + 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 + * constaint, 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; + if (elem != NULL) + xmlXPathNodeSetAdd(ret, elem); + } + xmlFree(ID); + } + + while (IS_BLANK_CH(*cur)) cur++; + ids = cur; + } + return(ret); +} + +/** + * xmlXPathIdFunction: + * @ctxt: the XPath Parser context + * @nargs: the number of arguments + * + * Implement the id() XPath function + * node-set id(object) + * The id function selects elements by their unique ID + * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set, + * then the result is the union of the result of applying id to the + * string value of each of the nodes in the argument node-set. When the + * argument to id is of any other type, the argument is converted to a + * string as if by a call to the string function; the string is split + * into a whitespace-separated list of tokens (whitespace is any sequence + * of characters matching the production S); the result is a node-set + * containing the elements in the same document as the context node that + * have a unique ID equal to any of the tokens in the list. + */ +void +xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) { + xmlChar *tokens; + xmlNodeSetPtr ret; + xmlXPathObjectPtr obj; + + CHECK_ARITY(1); + obj = valuePop(ctxt); + if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND); + if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) { + xmlNodeSetPtr ns; + int i; + + ret = xmlXPathNodeSetCreate(NULL); + /* + * FIXME -- in an out-of-memory condition this will behave badly. + * The solution is not clear -- we already popped an item from + * ctxt, so the object is in a corrupt state. + */ + + if (obj->nodesetval != NULL) { + for (i = 0; i < obj->nodesetval->nodeNr; i++) { + tokens = + xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]); + ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens); + ret = xmlXPathNodeSetMerge(ret, ns); + xmlXPathFreeNodeSet(ns); + if (tokens != NULL) + xmlFree(tokens); + } + } + xmlXPathReleaseObject(ctxt->context, obj); + valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret)); + return; + } + obj = xmlXPathCacheConvertString(ctxt->context, obj); + ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval); + valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret)); + xmlXPathReleaseObject(ctxt->context, obj); + return; +} + +/** + * xmlXPathLocalNameFunction: + * @ctxt: the XPath Parser context + * @nargs: the number of arguments + * + * Implement the local-name() XPath function + * string local-name(node-set?) + * The local-name function returns a string containing the local part + * of the name of the node in the argument node-set that is first in + * document order. If the node-set is empty or the first node has no + * name, an empty string is returned. If the argument is omitted it + * defaults to the context node. + */ +void +xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) { + xmlXPathObjectPtr cur; + + if (ctxt == NULL) return; + + if (nargs == 0) { + valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, + ctxt->context->node)); + nargs = 1; + } + + CHECK_ARITY(1); + if ((ctxt->value == NULL) || + ((ctxt->value->type != XPATH_NODESET) && + (ctxt->value->type != XPATH_XSLT_TREE))) + XP_ERROR(XPATH_INVALID_TYPE); + cur = valuePop(ctxt); + + if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { + valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); + } else { + int i = 0; /* Should be first in document order !!!!! */ + switch (cur->nodesetval->nodeTab[i]->type) { + case XML_ELEMENT_NODE: + case XML_ATTRIBUTE_NODE: + case XML_PI_NODE: + if (cur->nodesetval->nodeTab[i]->name[0] == ' ') + valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); + else + valuePush(ctxt, + xmlXPathCacheNewString(ctxt->context, + cur->nodesetval->nodeTab[i]->name)); + break; + case XML_NAMESPACE_DECL: + valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, + ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix)); + break; + default: + valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); + } + } + xmlXPathReleaseObject(ctxt->context, cur); +} + +/** + * xmlXPathNamespaceURIFunction: + * @ctxt: the XPath Parser context + * @nargs: the number of arguments + * + * Implement the namespace-uri() XPath function + * string namespace-uri(node-set?) + * The namespace-uri function returns a string containing the + * namespace URI of the expanded name of the node in the argument + * node-set that is first in document order. If the node-set is empty, + * the first node has no name, or the expanded name has no namespace + * URI, an empty string is returned. If the argument is omitted it + * defaults to the context node. + */ +void +xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) { + xmlXPathObjectPtr cur; + + if (ctxt == NULL) return; + + if (nargs == 0) { + valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, + ctxt->context->node)); + nargs = 1; + } + CHECK_ARITY(1); + if ((ctxt->value == NULL) || + ((ctxt->value->type != XPATH_NODESET) && + (ctxt->value->type != XPATH_XSLT_TREE))) + XP_ERROR(XPATH_INVALID_TYPE); + cur = valuePop(ctxt); + + if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { + valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); + } 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, "")); + else + valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, + cur->nodesetval->nodeTab[i]->ns->href)); + break; + default: + valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); + } + } + xmlXPathReleaseObject(ctxt->context, cur); +} + +/** + * xmlXPathNameFunction: + * @ctxt: the XPath Parser context + * @nargs: the number of arguments + * + * Implement the name() XPath function + * string name(node-set?) + * The name function returns a string containing a QName representing + * the name of the node in the argument node-set that is first in document + * order. The QName must represent the name with respect to the namespace + * declarations in effect on the node whose name is being represented. + * Typically, this will be the form in which the name occurred in the XML + * source. This need not be the case if there are namespace declarations + * in effect on the node that associate multiple prefixes with the same + * namespace. However, an implementation may include information about + * the original prefix in its representation of nodes; in this case, an + * implementation can ensure that the returned string is always the same + * as the QName used in the XML source. If the argument it omitted it + * defaults to the context node. + * Libxml keep the original prefix so the "real qualified name" used is + * returned. + */ +static void +xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) +{ + xmlXPathObjectPtr cur; + + if (nargs == 0) { + valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, + ctxt->context->node)); + nargs = 1; + } + + CHECK_ARITY(1); + if ((ctxt->value == NULL) || + ((ctxt->value->type != XPATH_NODESET) && + (ctxt->value->type != XPATH_XSLT_TREE))) + XP_ERROR(XPATH_INVALID_TYPE); + cur = valuePop(ctxt); + + if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { + valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); + } 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]->name[0] == ' ') + valuePush(ctxt, + xmlXPathCacheNewCString(ctxt->context, "")); + else if ((cur->nodesetval->nodeTab[i]->ns == NULL) || + (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) { + valuePush(ctxt, + xmlXPathCacheNewString(ctxt->context, + cur->nodesetval->nodeTab[i]->name)); + } else { + xmlChar *fullname; + + fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name, + cur->nodesetval->nodeTab[i]->ns->prefix, + NULL, 0); + if (fullname == cur->nodesetval->nodeTab[i]->name) + fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name); + if (fullname == NULL) { + XP_ERROR(XPATH_MEMORY_ERROR); + } + valuePush(ctxt, xmlXPathCacheWrapString( + ctxt->context, fullname)); + } + break; + default: + valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, + cur->nodesetval->nodeTab[i])); + xmlXPathLocalNameFunction(ctxt, 1); + } + } + xmlXPathReleaseObject(ctxt->context, cur); +} + + +/** + * xmlXPathStringFunction: + * @ctxt: the XPath Parser context + * @nargs: the number of arguments + * + * Implement the string() XPath function + * string string(object?) + * The string function converts an object to a string as follows: + * - A node-set is converted to a string by returning the value of + * the node in the node-set that is first in document order. + * If the node-set is empty, an empty string is returned. + * - A number is converted to a string as follows + * + NaN is converted to the string NaN + * + positive zero is converted to the string 0 + * + negative zero is converted to the string 0 + * + positive infinity is converted to the string Infinity + * + negative infinity is converted to the string -Infinity + * + if the number is an integer, the number is represented in + * decimal form as a Number with no decimal point and no leading + * zeros, preceded by a minus sign (-) if the number is negative + * + otherwise, the number is represented in decimal form as a + * Number including a decimal point with at least one digit + * before the decimal point and at least one digit after the + * decimal point, preceded by a minus sign (-) if the number + * is negative; there must be no leading zeros before the decimal + * point apart possibly from the one required digit immediately + * before the decimal point; beyond the one required digit + * after the decimal point there must be as many, but only as + * many, more digits as are needed to uniquely distinguish the + * number from all other IEEE 754 numeric values. + * - The boolean false value is converted to the string false. + * The boolean true value is converted to the string true. + * + * If the argument is omitted, it defaults to a node-set with the + * context node as its only member. + */ +void +xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) { + xmlXPathObjectPtr cur; + + if (ctxt == NULL) return; + if (nargs == 0) { + valuePush(ctxt, + xmlXPathCacheWrapString(ctxt->context, + xmlXPathCastNodeToString(ctxt->context->node))); + return; + } + + CHECK_ARITY(1); + cur = valuePop(ctxt); + if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND); + valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur)); +} + +/** + * xmlXPathStringLengthFunction: + * @ctxt: the XPath Parser context + * @nargs: the number of arguments + * + * Implement the string-length() XPath function + * number string-length(string?) + * The string-length returns the number of characters in the string + * (see [3.6 Strings]). If the argument is omitted, it defaults to + * the context node converted to a string, in other words the value + * of the context node. + */ +void +xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) { + xmlXPathObjectPtr cur; + + if (nargs == 0) { + if ((ctxt == NULL) || (ctxt->context == NULL)) + return; + if (ctxt->context->node == NULL) { + valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0)); + } else { + xmlChar *content; + + content = xmlXPathCastNodeToString(ctxt->context->node); + valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, + xmlUTF8Strlen(content))); + xmlFree(content); + } + return; + } + CHECK_ARITY(1); + CAST_TO_STRING; + CHECK_TYPE(XPATH_STRING); + cur = valuePop(ctxt); + valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, + xmlUTF8Strlen(cur->stringval))); + xmlXPathReleaseObject(ctxt->context, cur); +} + +/** + * xmlXPathConcatFunction: + * @ctxt: the XPath Parser context + * @nargs: the number of arguments + * + * Implement the concat() XPath function + * string concat(string, string, string*) + * The concat function returns the concatenation of its arguments. + */ +void +xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) { + xmlXPathObjectPtr cur, newobj; + xmlChar *tmp; + + if (ctxt == NULL) return; + if (nargs < 2) { + CHECK_ARITY(2); + } + + CAST_TO_STRING; + cur = valuePop(ctxt); + if ((cur == NULL) || (cur->type != XPATH_STRING)) { + xmlXPathReleaseObject(ctxt->context, cur); + return; + } + nargs--; + + while (nargs > 0) { + CAST_TO_STRING; + newobj = valuePop(ctxt); + if ((newobj == NULL) || (newobj->type != XPATH_STRING)) { + xmlXPathReleaseObject(ctxt->context, newobj); + xmlXPathReleaseObject(ctxt->context, cur); + XP_ERROR(XPATH_INVALID_TYPE); + } + tmp = xmlStrcat(newobj->stringval, cur->stringval); + newobj->stringval = cur->stringval; + cur->stringval = tmp; + xmlXPathReleaseObject(ctxt->context, newobj); + nargs--; + } + valuePush(ctxt, cur); +} + +/** + * xmlXPathContainsFunction: + * @ctxt: the XPath Parser context + * @nargs: the number of arguments + * + * Implement the contains() XPath function + * boolean contains(string, string) + * The contains function returns true if the first argument string + * contains the second argument string, and otherwise returns false. + */ +void +xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) { + xmlXPathObjectPtr hay, needle; + + CHECK_ARITY(2); + CAST_TO_STRING; + CHECK_TYPE(XPATH_STRING); + needle = valuePop(ctxt); + CAST_TO_STRING; + hay = valuePop(ctxt); + + if ((hay == NULL) || (hay->type != XPATH_STRING)) { + xmlXPathReleaseObject(ctxt->context, hay); + xmlXPathReleaseObject(ctxt->context, needle); + XP_ERROR(XPATH_INVALID_TYPE); + } + if (xmlStrstr(hay->stringval, needle->stringval)) + valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); + else + valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); + xmlXPathReleaseObject(ctxt->context, hay); + xmlXPathReleaseObject(ctxt->context, needle); +} + +/** + * xmlXPathStartsWithFunction: + * @ctxt: the XPath Parser context + * @nargs: the number of arguments + * + * Implement the starts-with() XPath function + * boolean starts-with(string, string) + * The starts-with function returns true if the first argument string + * starts with the second argument string, and otherwise returns false. + */ +void +xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) { + xmlXPathObjectPtr hay, needle; + int n; + + CHECK_ARITY(2); + CAST_TO_STRING; + CHECK_TYPE(XPATH_STRING); + needle = valuePop(ctxt); + CAST_TO_STRING; + hay = valuePop(ctxt); + + if ((hay == NULL) || (hay->type != XPATH_STRING)) { + xmlXPathReleaseObject(ctxt->context, hay); + xmlXPathReleaseObject(ctxt->context, needle); + XP_ERROR(XPATH_INVALID_TYPE); + } + n = xmlStrlen(needle->stringval); + if (xmlStrncmp(hay->stringval, needle->stringval, n)) + valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); + else + valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); + xmlXPathReleaseObject(ctxt->context, hay); + xmlXPathReleaseObject(ctxt->context, needle); +} + +/** + * xmlXPathSubstringFunction: + * @ctxt: the XPath Parser context + * @nargs: the number of arguments + * + * Implement the substring() XPath function + * string substring(string, number, number?) + * The substring function returns the substring of the first argument + * starting at the position specified in the second argument with + * length specified in the third argument. For example, + * substring("12345",2,3) returns "234". If the third argument is not + * specified, it returns the substring starting at the position specified + * in the second argument and continuing to the end of the string. For + * example, substring("12345",2) returns "2345". More precisely, each + * character in the string (see [3.6 Strings]) is considered to have a + * numeric position: the position of the first character is 1, the position + * of the second character is 2 and so on. The returned substring contains + * those characters for which the position of the character is greater than + * or equal to the second argument and, if the third argument is specified, + * less than the sum of the second and third arguments; the comparisons + * and addition used for the above follow the standard IEEE 754 rules. Thus: + * - substring("12345", 1.5, 2.6) returns "234" + * - substring("12345", 0, 3) returns "12" + * - substring("12345", 0 div 0, 3) returns "" + * - substring("12345", 1, 0 div 0) returns "" + * - substring("12345", -42, 1 div 0) returns "12345" + * - substring("12345", -1 div 0, 1 div 0) returns "" + */ +void +xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) { + xmlXPathObjectPtr str, start, len; + double le=0, in; + int i, l, m; + xmlChar *ret; + + if (nargs < 2) { + CHECK_ARITY(2); + } + if (nargs > 3) { + CHECK_ARITY(3); + } + /* + * take care of possible last (position) argument + */ + if (nargs == 3) { + CAST_TO_NUMBER; + CHECK_TYPE(XPATH_NUMBER); + len = valuePop(ctxt); + le = len->floatval; + xmlXPathReleaseObject(ctxt->context, len); + } + + CAST_TO_NUMBER; + CHECK_TYPE(XPATH_NUMBER); + start = valuePop(ctxt); + in = start->floatval; + xmlXPathReleaseObject(ctxt->context, start); + CAST_TO_STRING; + CHECK_TYPE(XPATH_STRING); + str = valuePop(ctxt); + m = xmlUTF8Strlen((const unsigned char *)str->stringval); + + /* + * If last pos not present, calculate last position + */ + if (nargs != 3) { + le = (double)m; + if (in < 1.0) + in = 1.0; + } + + /* Need to check for the special cases where either + * the index is NaN, the length is NaN, or both + * arguments are infinity (relying on Inf + -Inf = NaN) + */ + if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) { + /* + * To meet the requirements of the spec, the arguments + * must be converted to integer format before + * initial index calculations are done + * + * First we go to integer form, rounding up + * and checking for special cases + */ + i = (int) in; + if (((double)i)+0.5 <= in) i++; + + if (xmlXPathIsInf(le) == 1) { + l = m; + if (i < 1) + i = 1; + } + else if (xmlXPathIsInf(le) == -1 || le < 0.0) + l = 0; + else { + l = (int) le; + if (((double)l)+0.5 <= le) l++; + } + + /* Now we normalize inidices */ + i -= 1; + l += i; + if (i < 0) + i = 0; + if (l > m) + l = m; + + /* number of chars to copy */ + l -= i; + + ret = xmlUTF8Strsub(str->stringval, i, l); + } + else { + ret = NULL; + } + if (ret == NULL) + valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, "")); + else { + valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret)); + xmlFree(ret); + } + xmlXPathReleaseObject(ctxt->context, str); +} + +/** + * xmlXPathSubstringBeforeFunction: + * @ctxt: the XPath Parser context + * @nargs: the number of arguments + * + * Implement the substring-before() XPath function + * string substring-before(string, string) + * The substring-before function returns the substring of the first + * argument string that precedes the first occurrence of the second + * 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-before("1999/04/01","/") returns 1999. + */ +void +xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) { + xmlXPathObjectPtr str; + xmlXPathObjectPtr find; + xmlBufferPtr target; + const xmlChar *point; + int offset; + + CHECK_ARITY(2); + CAST_TO_STRING; + find = valuePop(ctxt); + CAST_TO_STRING; + str = valuePop(ctxt); + + target = xmlBufferCreate(); + if (target) { + point = xmlStrstr(str->stringval, find->stringval); + if (point) { + offset = (int)(point - str->stringval); + xmlBufferAdd(target, str->stringval, offset); + } + valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, + xmlBufferContent(target))); + xmlBufferFree(target); + } + xmlXPathReleaseObject(ctxt->context, str); + xmlXPathReleaseObject(ctxt->context, find); +} + +/** + * xmlXPathSubstringAfterFunction: + * @ctxt: the XPath Parser context + * @nargs: the number of arguments + * + * Implement the substring-after() XPath function + * 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 + * 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; + xmlBufferPtr target; + const xmlChar *point; + int offset; + + CHECK_ARITY(2); + CAST_TO_STRING; + find = valuePop(ctxt); + CAST_TO_STRING; + str = valuePop(ctxt); + + target = xmlBufferCreate(); + if (target) { + point = xmlStrstr(str->stringval, find->stringval); + if (point) { + offset = (int)(point - str->stringval) + xmlStrlen(find->stringval); + xmlBufferAdd(target, &str->stringval[offset], + xmlStrlen(str->stringval) - offset); + } + valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, + xmlBufferContent(target))); + xmlBufferFree(target); + } + xmlXPathReleaseObject(ctxt->context, str); + xmlXPathReleaseObject(ctxt->context, find); +} + +/** + * xmlXPathNormalizeFunction: + * @ctxt: the XPath Parser context + * @nargs: the number of arguments + * + * Implement the normalize-space() XPath function + * string normalize-space(string?) + * The normalize-space function returns the argument string with white + * space normalized by stripping leading and trailing whitespace + * and replacing sequences of whitespace characters by a single + * space. Whitespace characters are the same allowed by the S production + * in XML. If the argument is omitted, it defaults to the context + * node converted to a string, in other words the value of the context node. + */ +void +xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) { + xmlXPathObjectPtr obj = NULL; + xmlChar *source = NULL; + xmlBufferPtr target; + xmlChar blank; + + if (ctxt == NULL) return; + if (nargs == 0) { + /* Use current context node */ + valuePush(ctxt, + xmlXPathCacheWrapString(ctxt->context, + xmlXPathCastNodeToString(ctxt->context->node))); + nargs = 1; + } + + CHECK_ARITY(1); + CAST_TO_STRING; + CHECK_TYPE(XPATH_STRING); + obj = valuePop(ctxt); + source = obj->stringval; + + target = xmlBufferCreate(); + if (target && source) { + + /* Skip leading whitespaces */ + while (IS_BLANK_CH(*source)) + source++; + + /* Collapse intermediate whitespaces, and skip trailing whitespaces */ + blank = 0; + while (*source) { + if (IS_BLANK_CH(*source)) { + blank = 0x20; + } else { + if (blank) { + xmlBufferAdd(target, &blank, 1); + blank = 0; + } + xmlBufferAdd(target, source, 1); + } + source++; + } + valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, + xmlBufferContent(target))); + xmlBufferFree(target); + } + xmlXPathReleaseObject(ctxt->context, obj); +} + +/** + * xmlXPathTranslateFunction: + * @ctxt: the XPath Parser context + * @nargs: the number of arguments + * + * Implement the translate() XPath function + * string translate(string, string, string) + * The translate function returns the first argument string with + * occurrences of characters in the second argument string replaced + * by the character at the corresponding position in the third argument + * string. For example, translate("bar","abc","ABC") returns the string + * BAr. If there is a character in the second argument string with no + * character at a corresponding position in the third argument string + * (because the second argument string is longer than the third argument + * string), then occurrences of that character in the first argument + * string are removed. For example, translate("--aaa--","abc-","ABC") + * returns "AAA". If a character occurs more than once in second + * argument string, then the first occurrence determines the replacement + * character. If the third argument string is longer than the second + * argument string, then excess characters are ignored. + */ +void +xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) { + xmlXPathObjectPtr str; + xmlXPathObjectPtr from; + xmlXPathObjectPtr to; + xmlBufferPtr target; + int offset, max; + xmlChar ch; + const xmlChar *point; + xmlChar *cptr; + + CHECK_ARITY(3); + + CAST_TO_STRING; + to = valuePop(ctxt); + CAST_TO_STRING; + from = valuePop(ctxt); + CAST_TO_STRING; + str = valuePop(ctxt); + + target = xmlBufferCreate(); + 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) + xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1)); + } + } else + xmlBufferAdd(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; + } + } + } + valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, + xmlBufferContent(target))); + xmlBufferFree(target); + xmlXPathReleaseObject(ctxt->context, str); + xmlXPathReleaseObject(ctxt->context, from); + xmlXPathReleaseObject(ctxt->context, to); +} + +/** + * xmlXPathBooleanFunction: + * @ctxt: the XPath Parser context + * @nargs: the number of arguments + * + * Implement the boolean() XPath function + * boolean boolean(object) + * The boolean function converts its argument to a boolean as follows: + * - a number is true if and only if it is neither positive or + * negative zero nor NaN + * - a node-set is true if and only if it is non-empty + * - a string is true if and only if its length is non-zero + */ +void +xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) { + xmlXPathObjectPtr cur; + + CHECK_ARITY(1); + cur = valuePop(ctxt); + if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND); + cur = xmlXPathCacheConvertBoolean(ctxt->context, cur); + valuePush(ctxt, cur); +} + +/** + * xmlXPathNotFunction: + * @ctxt: the XPath Parser context + * @nargs: the number of arguments + * + * Implement the not() XPath function + * boolean not(boolean) + * The not function returns true if its argument is false, + * and false otherwise. + */ +void +xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) { + CHECK_ARITY(1); + CAST_TO_BOOLEAN; + CHECK_TYPE(XPATH_BOOLEAN); + ctxt->value->boolval = ! ctxt->value->boolval; +} + +/** + * xmlXPathTrueFunction: + * @ctxt: the XPath Parser context + * @nargs: the number of arguments + * + * Implement the true() XPath function + * boolean true() + */ +void +xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) { + CHECK_ARITY(0); + valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1)); +} + +/** + * xmlXPathFalseFunction: + * @ctxt: the XPath Parser context + * @nargs: the number of arguments + * + * Implement the false() XPath function + * boolean false() + */ +void +xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) { + CHECK_ARITY(0); + valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0)); +} + +/** + * xmlXPathLangFunction: + * @ctxt: the XPath Parser context + * @nargs: the number of arguments + * + * Implement the lang() XPath function + * boolean lang(string) + * The lang function returns true or false depending on whether the + * language of the context node as specified by xml:lang attributes + * is the same as or is a sublanguage of the language specified by + * the argument string. The language of the context node is determined + * by the value of the xml:lang attribute on the context node, or, if + * the context node has no xml:lang attribute, by the value of the + * xml:lang attribute on the nearest ancestor of the context node that + * has an xml:lang attribute. If there is no such attribute, then lang + * returns false. If there is such an attribute, then lang returns + * true if the attribute value is equal to the argument ignoring case, + * or if there is some suffix starting with - such that the attribute + * value is equal to the argument ignoring that suffix of the attribute + * value and ignoring case. + */ +void +xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) { + xmlXPathObjectPtr val = NULL; + const xmlChar *theLang = NULL; + const xmlChar *lang; + int ret = 0; + int i; + + CHECK_ARITY(1); + CAST_TO_STRING; + CHECK_TYPE(XPATH_STRING); + val = valuePop(ctxt); + lang = val->stringval; + theLang = xmlNodeGetLang(ctxt->context->node); + 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; + } +not_equal: + if (theLang != NULL) + xmlFree((void *)theLang); + + xmlXPathReleaseObject(ctxt->context, val); + valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret)); +} + +/** + * xmlXPathNumberFunction: + * @ctxt: the XPath Parser context + * @nargs: the number of arguments + * + * Implement the number() XPath function + * number number(object?) + */ +void +xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) { + xmlXPathObjectPtr cur; + double res; + + if (ctxt == NULL) return; + if (nargs == 0) { + if (ctxt->context->node == NULL) { + valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0)); + } else { + xmlChar* content = xmlNodeGetContent(ctxt->context->node); + + res = xmlXPathStringEvalNumber(content); + valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res)); + xmlFree(content); + } + return; + } + + CHECK_ARITY(1); + cur = valuePop(ctxt); + valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur)); +} + +/** + * xmlXPathSumFunction: + * @ctxt: the XPath Parser context + * @nargs: the number of arguments + * + * Implement the sum() XPath function + * number sum(node-set) + * The sum function returns the sum of the values of the nodes in + * the argument node-set. + */ +void +xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) { + xmlXPathObjectPtr cur; + int i; + double res = 0.0; + + CHECK_ARITY(1); + if ((ctxt->value == NULL) || + ((ctxt->value->type != XPATH_NODESET) && + (ctxt->value->type != XPATH_XSLT_TREE))) + XP_ERROR(XPATH_INVALID_TYPE); + cur = valuePop(ctxt); + + if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) { + for (i = 0; i < cur->nodesetval->nodeNr; i++) { + res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]); + } + } + valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res)); + xmlXPathReleaseObject(ctxt->context, cur); +} + +/* + * To assure working code on multiple platforms, we want to only depend + * upon the characteristic truncation of converting a floating point value + * to an integer. Unfortunately, because of the different storage sizes + * of our internal floating point value (double) and integer (int), we + * can't directly convert (see bug 301162). This macro is a messy + * 'workaround' + */ +#define XTRUNC(f, v) \ + f = fmod((v), INT_MAX); \ + f = (v) - (f) + (double)((int)(f)); + +/** + * xmlXPathFloorFunction: + * @ctxt: the XPath Parser context + * @nargs: the number of arguments + * + * Implement the floor() XPath function + * number floor(number) + * The floor function returns the largest (closest to positive infinity) + * number that is not greater than the argument and that is an integer. + */ +void +xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) { + double f; + + CHECK_ARITY(1); + CAST_TO_NUMBER; + CHECK_TYPE(XPATH_NUMBER); + + XTRUNC(f, ctxt->value->floatval); + if (f != ctxt->value->floatval) { + if (ctxt->value->floatval > 0) + ctxt->value->floatval = f; + else + ctxt->value->floatval = f - 1; + } +} + +/** + * xmlXPathCeilingFunction: + * @ctxt: the XPath Parser context + * @nargs: the number of arguments + * + * Implement the ceiling() XPath function + * number ceiling(number) + * The ceiling function returns the smallest (closest to negative infinity) + * number that is not less than the argument and that is an integer. + */ +void +xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) { + double f; + + CHECK_ARITY(1); + CAST_TO_NUMBER; + CHECK_TYPE(XPATH_NUMBER); + +#if 0 + ctxt->value->floatval = ceil(ctxt->value->floatval); +#else + XTRUNC(f, ctxt->value->floatval); + if (f != ctxt->value->floatval) { + if (ctxt->value->floatval > 0) + ctxt->value->floatval = f + 1; + else { + if (ctxt->value->floatval < 0 && f == 0) + ctxt->value->floatval = xmlXPathNZERO; + else + ctxt->value->floatval = f; + } + + } +#endif +} + +/** + * xmlXPathRoundFunction: + * @ctxt: the XPath Parser context + * @nargs: the number of arguments + * + * Implement the round() XPath function + * number round(number) + * The round function returns the number that is closest to the + * argument and that is an integer. If there are two such numbers, + * then the one that is even is returned. + */ +void +xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) { + double f; + + CHECK_ARITY(1); + CAST_TO_NUMBER; + CHECK_TYPE(XPATH_NUMBER); + + if ((xmlXPathIsNaN(ctxt->value->floatval)) || + (xmlXPathIsInf(ctxt->value->floatval) == 1) || + (xmlXPathIsInf(ctxt->value->floatval) == -1) || + (ctxt->value->floatval == 0.0)) + return; + + XTRUNC(f, ctxt->value->floatval); + if (ctxt->value->floatval < 0) { + if (ctxt->value->floatval < f - 0.5) + ctxt->value->floatval = f - 1; + else + ctxt->value->floatval = f; + if (ctxt->value->floatval == 0) + ctxt->value->floatval = xmlXPathNZERO; + } else { + if (ctxt->value->floatval < f + 0.5) + ctxt->value->floatval = f; + else + ctxt->value->floatval = f + 1; + } +} + +/************************************************************************ + * * + * The Parser * + * * + ************************************************************************/ + +/* + * a few forward declarations since we use a recursive call based + * implementation. + */ +static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort); +static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter); +static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt); +static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt); +static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, + int qualified); + +/** + * xmlXPathCurrentChar: + * @ctxt: the XPath parser context + * @cur: pointer to the beginning of the char + * @len: pointer to the length of the char read + * + * The current char value, if using UTF-8 this may actually span multiple + * bytes in the input buffer. + * + * Returns the current char value and its length + */ + +static int +xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) { + unsigned char c; + unsigned int val; + const xmlChar *cur; + + if (ctxt == NULL) + return(0); + cur = ctxt->cur; + + /* + * We are supposed to handle UTF8, check it's valid + * From rfc2044: encoding of the Unicode values on UTF-8: + * + * UCS-4 range (hex.) UTF-8 octet sequence (binary) + * 0000 0000-0000 007F 0xxxxxxx + * 0000 0080-0000 07FF 110xxxxx 10xxxxxx + * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx + * + * Check for the 0x110000 limit too + */ + c = *cur; + if (c & 0x80) { + if ((cur[1] & 0xc0) != 0x80) + goto encoding_error; + if ((c & 0xe0) == 0xe0) { + + if ((cur[2] & 0xc0) != 0x80) + goto encoding_error; + if ((c & 0xf0) == 0xf0) { + if (((c & 0xf8) != 0xf0) || + ((cur[3] & 0xc0) != 0x80)) + goto encoding_error; + /* 4-byte code */ + *len = 4; + val = (cur[0] & 0x7) << 18; + val |= (cur[1] & 0x3f) << 12; + val |= (cur[2] & 0x3f) << 6; + val |= cur[3] & 0x3f; + } else { + /* 3-byte code */ + *len = 3; + val = (cur[0] & 0xf) << 12; + val |= (cur[1] & 0x3f) << 6; + val |= cur[2] & 0x3f; + } + } else { + /* 2-byte code */ + *len = 2; + val = (cur[0] & 0x1f) << 6; + val |= cur[1] & 0x3f; + } + if (!IS_CHAR(val)) { + XP_ERROR0(XPATH_INVALID_CHAR_ERROR); + } + return(val); + } else { + /* 1-byte code */ + *len = 1; + return((int) *cur); + } +encoding_error: + /* + * If we detect an UTF8 error that probably means that the + * input encoding didn't get properly advertised in the + * declaration header. Report the error and switch the encoding + * to ISO-Latin-1 (if you don't like this policy, just declare the + * encoding !) + */ + *len = 0; + XP_ERROR0(XPATH_ENCODING_ERROR); +} + +/** + * xmlXPathParseNCName: + * @ctxt: the XPath Parser context + * + * parse an XML namespace non qualified name. + * + * [NS 3] NCName ::= (Letter | '_') (NCNameChar)* + * + * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' | + * CombiningChar | Extender + * + * Returns the namespace name or NULL + */ + +xmlChar * +xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) { + const xmlChar *in; + xmlChar *ret; + int count = 0; + + if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL); + /* + * Accelerator for simple ASCII names + */ + in = ctxt->cur; + if (((*in >= 0x61) && (*in <= 0x7A)) || + ((*in >= 0x41) && (*in <= 0x5A)) || + (*in == '_')) { + in++; + while (((*in >= 0x61) && (*in <= 0x7A)) || + ((*in >= 0x41) && (*in <= 0x5A)) || + ((*in >= 0x30) && (*in <= 0x39)) || + (*in == '_') || (*in == '.') || + (*in == '-')) + in++; + if ((*in == ' ') || (*in == '>') || (*in == '/') || + (*in == '[') || (*in == ']') || (*in == ':') || + (*in == '@') || (*in == '*')) { + count = in - ctxt->cur; + if (count == 0) + return(NULL); + ret = xmlStrndup(ctxt->cur, count); + ctxt->cur = in; + return(ret); + } + } + return(xmlXPathParseNameComplex(ctxt, 0)); +} + + +/** + * xmlXPathParseQName: + * @ctxt: the XPath Parser context + * @prefix: a xmlChar ** + * + * parse an XML qualified name + * + * [NS 5] QName ::= (Prefix ':')? LocalPart + * + * [NS 6] Prefix ::= NCName + * + * [NS 7] LocalPart ::= NCName + * + * Returns the function returns the local part, and prefix is updated + * to get the Prefix if any. + */ + +static xmlChar * +xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) { + xmlChar *ret = NULL; + + *prefix = NULL; + ret = xmlXPathParseNCName(ctxt); + if (ret && CUR == ':') { + *prefix = ret; + NEXT; + ret = xmlXPathParseNCName(ctxt); + } + return(ret); +} + +/** + * xmlXPathParseName: + * @ctxt: the XPath Parser context + * + * parse an XML name + * + * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | + * CombiningChar | Extender + * + * [5] Name ::= (Letter | '_' | ':') (NameChar)* + * + * Returns the namespace name or NULL + */ + +xmlChar * +xmlXPathParseName(xmlXPathParserContextPtr ctxt) { + const xmlChar *in; + xmlChar *ret; + int count = 0; + + if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL); + /* + * Accelerator for simple ASCII names + */ + in = ctxt->cur; + if (((*in >= 0x61) && (*in <= 0x7A)) || + ((*in >= 0x41) && (*in <= 0x5A)) || + (*in == '_') || (*in == ':')) { + in++; + while (((*in >= 0x61) && (*in <= 0x7A)) || + ((*in >= 0x41) && (*in <= 0x5A)) || + ((*in >= 0x30) && (*in <= 0x39)) || + (*in == '_') || (*in == '-') || + (*in == ':') || (*in == '.')) + in++; + if ((*in > 0) && (*in < 0x80)) { + count = in - ctxt->cur; + ret = xmlStrndup(ctxt->cur, count); + ctxt->cur = in; + return(ret); + } + } + return(xmlXPathParseNameComplex(ctxt, 1)); +} + +static xmlChar * +xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) { + xmlChar buf[XML_MAX_NAMELEN + 5]; + int len = 0, l; + int c; + + /* + * Handler for more complex cases + */ + c = CUR_CHAR(l); + if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */ + (c == '[') || (c == ']') || (c == '@') || /* accelerators */ + (c == '*') || /* accelerators */ + (!IS_LETTER(c) && (c != '_') && + ((qualified) && (c != ':')))) { + return(NULL); + } + + while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */ + ((IS_LETTER(c)) || (IS_DIGIT(c)) || + (c == '.') || (c == '-') || + (c == '_') || ((qualified) && (c == ':')) || + (IS_COMBINING(c)) || + (IS_EXTENDER(c)))) { + COPY_BUF(l,buf,len,c); + NEXTL(l); + c = CUR_CHAR(l); + if (len >= XML_MAX_NAMELEN) { + /* + * Okay someone managed to make a huge name, so he's ready to pay + * for the processing speed. + */ + xmlChar *buffer; + int max = len * 2; + + buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar)); + if (buffer == NULL) { + XP_ERRORNULL(XPATH_MEMORY_ERROR); + } + memcpy(buffer, buf, len); + while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */ + (c == '.') || (c == '-') || + (c == '_') || ((qualified) && (c == ':')) || + (IS_COMBINING(c)) || + (IS_EXTENDER(c))) { + if (len + 10 > max) { + max *= 2; + buffer = (xmlChar *) xmlRealloc(buffer, + max * sizeof(xmlChar)); + if (buffer == NULL) { + XP_ERRORNULL(XPATH_MEMORY_ERROR); + } + } + COPY_BUF(l,buffer,len,c); + NEXTL(l); + c = CUR_CHAR(l); + } + buffer[len] = 0; + return(buffer); + } + } + if (len == 0) + return(NULL); + return(xmlStrndup(buf, len)); +} + +#define MAX_FRAC 20 + +/* + * These are used as divisors for the fractional part of a number. + * Since the table includes 1.0 (representing '0' fractional digits), + * it must be dimensioned at MAX_FRAC+1 (bug 133921) + */ +static double my_pow10[MAX_FRAC+1] = { + 1.0, 10.0, 100.0, 1000.0, 10000.0, + 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0, + 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0, + 100000000000000.0, + 1000000000000000.0, 10000000000000000.0, 100000000000000000.0, + 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0 +}; + +/** + * xmlXPathStringEvalNumber: + * @str: A string to scan + * + * [30a] Float ::= Number ('e' Digits?)? + * + * [30] Number ::= Digits ('.' Digits?)? + * | '.' Digits + * [31] Digits ::= [0-9]+ + * + * Compile a Number in the string + * In complement of the Number expression, this function also handles + * negative values : '-' Number. + * + * Returns the double value. + */ +double +xmlXPathStringEvalNumber(const xmlChar *str) { + const xmlChar *cur = str; + double ret; + int ok = 0; + int isneg = 0; + int exponent = 0; + int is_exponent_negative = 0; +#ifdef __GNUC__ + unsigned long tmp = 0; + double temp; +#endif + if (cur == NULL) return(0); + while (IS_BLANK_CH(*cur)) cur++; + if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) { + return(xmlXPathNAN); + } + if (*cur == '-') { + isneg = 1; + cur++; + } + +#ifdef __GNUC__ + /* + * tmp/temp is a workaround against a gcc compiler bug + * http://veillard.com/gcc.bug + */ + ret = 0; + while ((*cur >= '0') && (*cur <= '9')) { + ret = ret * 10; + tmp = (*cur - '0'); + ok = 1; + cur++; + temp = (double) tmp; + ret = ret + temp; + } +#else + ret = 0; + while ((*cur >= '0') && (*cur <= '9')) { + ret = ret * 10 + (*cur - '0'); + ok = 1; + cur++; + } +#endif + + if (*cur == '.') { + int v, frac = 0; + double fraction = 0; + + cur++; + if (((*cur < '0') || (*cur > '9')) && (!ok)) { + return(xmlXPathNAN); + } + while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) { + v = (*cur - '0'); + fraction = fraction * 10 + v; + frac = frac + 1; + cur++; + } + fraction /= my_pow10[frac]; + ret = ret + fraction; + while ((*cur >= '0') && (*cur <= '9')) + cur++; + } + if ((*cur == 'e') || (*cur == 'E')) { + cur++; + if (*cur == '-') { + is_exponent_negative = 1; + cur++; + } else if (*cur == '+') { + cur++; + } + while ((*cur >= '0') && (*cur <= '9')) { + exponent = exponent * 10 + (*cur - '0'); + cur++; + } + } + while (IS_BLANK_CH(*cur)) cur++; + if (*cur != 0) return(xmlXPathNAN); + if (isneg) ret = -ret; + if (is_exponent_negative) exponent = -exponent; + ret *= pow(10.0, (double)exponent); + return(ret); +} + +/** + * xmlXPathCompNumber: + * @ctxt: the XPath Parser context + * + * [30] Number ::= Digits ('.' Digits?)? + * | '.' Digits + * [31] Digits ::= [0-9]+ + * + * Compile a Number, then push it on the stack + * + */ +static void +xmlXPathCompNumber(xmlXPathParserContextPtr ctxt) +{ + double ret = 0.0; + int ok = 0; + int exponent = 0; + int is_exponent_negative = 0; +#ifdef __GNUC__ + unsigned long tmp = 0; + double temp; +#endif + + CHECK_ERROR; + if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) { + XP_ERROR(XPATH_NUMBER_ERROR); + } +#ifdef __GNUC__ + /* + * tmp/temp is a workaround against a gcc compiler bug + * http://veillard.com/gcc.bug + */ + ret = 0; + while ((CUR >= '0') && (CUR <= '9')) { + ret = ret * 10; + tmp = (CUR - '0'); + ok = 1; + NEXT; + temp = (double) tmp; + ret = ret + temp; + } +#else + ret = 0; + while ((CUR >= '0') && (CUR <= '9')) { + ret = ret * 10 + (CUR - '0'); + ok = 1; + NEXT; + } +#endif + if (CUR == '.') { + int v, frac = 0; + double fraction = 0; + + NEXT; + if (((CUR < '0') || (CUR > '9')) && (!ok)) { + XP_ERROR(XPATH_NUMBER_ERROR); + } + while ((CUR >= '0') && (CUR <= '9') && (frac < MAX_FRAC)) { + v = (CUR - '0'); + fraction = fraction * 10 + v; + frac = frac + 1; + NEXT; + } + fraction /= my_pow10[frac]; + ret = ret + fraction; + while ((CUR >= '0') && (CUR <= '9')) + NEXT; + } + if ((CUR == 'e') || (CUR == 'E')) { + NEXT; + if (CUR == '-') { + is_exponent_negative = 1; + NEXT; + } else if (CUR == '+') { + NEXT; + } + while ((CUR >= '0') && (CUR <= '9')) { + exponent = exponent * 10 + (CUR - '0'); + NEXT; + } + if (is_exponent_negative) + exponent = -exponent; + ret *= pow(10.0, (double) exponent); + } + PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, + xmlXPathCacheNewFloat(ctxt->context, ret), NULL); +} + +/** + * xmlXPathParseLiteral: + * @ctxt: the XPath Parser context + * + * Parse a Literal + * + * [29] Literal ::= '"' [^"]* '"' + * | "'" [^']* "'" + * + * Returns the value found or NULL in case of error + */ +static xmlChar * +xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) { + const xmlChar *q; + xmlChar *ret = NULL; + + 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; + } + } 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; + } + } else { + XP_ERRORNULL(XPATH_START_LITERAL_ERROR); + } + return(ret); +} + +/** + * xmlXPathCompLiteral: + * @ctxt: the XPath Parser context + * + * Parse a Literal and push it on the stack. + * + * [29] Literal ::= '"' [^"]* '"' + * | "'" [^']* "'" + * + * TODO: xmlXPathCompLiteral memory allocation could be improved. + */ +static void +xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) { + const xmlChar *q; + xmlChar *ret = NULL; + + 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) return; + PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, + xmlXPathCacheNewString(ctxt->context, ret), NULL); + xmlFree(ret); +} + +/** + * xmlXPathCompVariableReference: + * @ctxt: the XPath Parser context + * + * Parse a VariableReference, evaluate it and push it on the stack. + * + * The variable bindings consist of a mapping from variable names + * to variable values. The value of a variable is an object, which can be + * of any of the types that are possible for the value of an expression, + * and may also be of additional types not specified here. + * + * Early evaluation is possible since: + * The variable bindings [...] used to evaluate a subexpression are + * always the same as those used to evaluate the containing expression. + * + * [36] VariableReference ::= '$' QName + */ +static void +xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) { + xmlChar *name; + xmlChar *prefix; + + SKIP_BLANKS; + if (CUR != '$') { + XP_ERROR(XPATH_VARIABLE_REF_ERROR); + } + NEXT; + name = xmlXPathParseQName(ctxt, &prefix); + if (name == NULL) { + XP_ERROR(XPATH_VARIABLE_REF_ERROR); + } + ctxt->comp->last = -1; + PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, + name, prefix); + SKIP_BLANKS; + if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) { + XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR); + } +} + +/** + * xmlXPathIsNodeType: + * @name: a name string + * + * Is the name given a NodeType one. + * + * [38] NodeType ::= 'comment' + * | 'text' + * | 'processing-instruction' + * | 'node' + * + * Returns 1 if true 0 otherwise + */ +int +xmlXPathIsNodeType(const xmlChar *name) { + if (name == NULL) + return(0); + + if (xmlStrEqual(name, BAD_CAST "node")) + return(1); + if (xmlStrEqual(name, BAD_CAST "text")) + return(1); + if (xmlStrEqual(name, BAD_CAST "comment")) + return(1); + if (xmlStrEqual(name, BAD_CAST "processing-instruction")) + return(1); + return(0); +} + +/** + * xmlXPathCompFunctionCall: + * @ctxt: the XPath Parser context + * + * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')' + * [17] Argument ::= Expr + * + * Compile a function call, the evaluation of all arguments are + * pushed on the stack + */ +static void +xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) { + xmlChar *name; + xmlChar *prefix; + int nbargs = 0; + int sort = 1; + + name = xmlXPathParseQName(ctxt, &prefix); + if (name == NULL) { + xmlFree(prefix); + XP_ERROR(XPATH_EXPR_ERROR); + } + SKIP_BLANKS; +#ifdef DEBUG_EXPR + if (prefix == NULL) + xmlGenericError(xmlGenericErrorContext, "Calling function %s\n", + name); + else + xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n", + prefix, name); +#endif + + if (CUR != '(') { + XP_ERROR(XPATH_EXPR_ERROR); + } + NEXT; + SKIP_BLANKS; + + /* + * Optimization for count(): we don't need the node-set to be sorted. + */ + if ((prefix == NULL) && (name[0] == 'c') && + xmlStrEqual(name, BAD_CAST "count")) + { + sort = 0; + } + ctxt->comp->last = -1; + if (CUR != ')') { + while (CUR != 0) { + int op1 = ctxt->comp->last; + ctxt->comp->last = -1; + xmlXPathCompileExpr(ctxt, sort); + if (ctxt->error != XPATH_EXPRESSION_OK) { + xmlFree(name); + xmlFree(prefix); + return; + } + PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0); + nbargs++; + if (CUR == ')') break; + if (CUR != ',') { + XP_ERROR(XPATH_EXPR_ERROR); + } + NEXT; + SKIP_BLANKS; + } + } + PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, + name, prefix); + NEXT; + SKIP_BLANKS; +} + +/** + * xmlXPathCompPrimaryExpr: + * @ctxt: the XPath Parser context + * + * [15] PrimaryExpr ::= VariableReference + * | '(' Expr ')' + * | Literal + * | Number + * | FunctionCall + * + * Compile a primary expression. + */ +static void +xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) { + SKIP_BLANKS; + if (CUR == '$') xmlXPathCompVariableReference(ctxt); + else if (CUR == '(') { + NEXT; + SKIP_BLANKS; + xmlXPathCompileExpr(ctxt, 1); + CHECK_ERROR; + if (CUR != ')') { + XP_ERROR(XPATH_EXPR_ERROR); + } + NEXT; + SKIP_BLANKS; + } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) { + xmlXPathCompNumber(ctxt); + } else if ((CUR == '\'') || (CUR == '"')) { + xmlXPathCompLiteral(ctxt); + } else { + xmlXPathCompFunctionCall(ctxt); + } + SKIP_BLANKS; +} + +/** + * xmlXPathCompFilterExpr: + * @ctxt: the XPath Parser context + * + * [20] FilterExpr ::= PrimaryExpr + * | FilterExpr Predicate + * + * Compile a filter expression. + * Square brackets are used to filter expressions in the same way that + * they are used in location paths. It is an error if the expression to + * be filtered does not evaluate to a node-set. The context node list + * used for evaluating the expression in square brackets is the node-set + * to be filtered listed in document order. + */ + +static void +xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) { + xmlXPathCompPrimaryExpr(ctxt); + CHECK_ERROR; + SKIP_BLANKS; + + while (CUR == '[') { + xmlXPathCompPredicate(ctxt, 1); + SKIP_BLANKS; + } + + +} + +/** + * xmlXPathScanName: + * @ctxt: the XPath Parser context + * + * Trickery: parse an XML name but without consuming the input flow + * Needed to avoid insanity in the parser state. + * + * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | + * CombiningChar | Extender + * + * [5] Name ::= (Letter | '_' | ':') (NameChar)* + * + * [6] Names ::= Name (S Name)* + * + * Returns the Name parsed or NULL + */ + +static xmlChar * +xmlXPathScanName(xmlXPathParserContextPtr ctxt) { + int len = 0, l; + int c; + const xmlChar *cur; + xmlChar *ret; + + cur = ctxt->cur; + + c = CUR_CHAR(l); + if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */ + (!IS_LETTER(c) && (c != '_') && + (c != ':'))) { + return(NULL); + } + + while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */ + ((IS_LETTER(c)) || (IS_DIGIT(c)) || + (c == '.') || (c == '-') || + (c == '_') || (c == ':') || + (IS_COMBINING(c)) || + (IS_EXTENDER(c)))) { + len += l; + NEXTL(l); + c = CUR_CHAR(l); + } + ret = xmlStrndup(cur, ctxt->cur - cur); + ctxt->cur = cur; + return(ret); +} + +/** + * xmlXPathCompPathExpr: + * @ctxt: the XPath Parser context + * + * [19] PathExpr ::= LocationPath + * | FilterExpr + * | FilterExpr '/' RelativeLocationPath + * | FilterExpr '//' RelativeLocationPath + * + * Compile a path expression. + * The / operator and // operators combine an arbitrary expression + * and a relative location path. It is an error if the expression + * does not evaluate to a node-set. + * The / operator does composition in the same way as when / is + * used in a location path. As in location paths, // is short for + * /descendant-or-self::node()/. + */ + +static void +xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) { + int lc = 1; /* Should we branch to LocationPath ? */ + xmlChar *name = NULL; /* we may have to preparse a name to find out */ + + SKIP_BLANKS; + if ((CUR == '$') || (CUR == '(') || + (IS_ASCII_DIGIT(CUR)) || + (CUR == '\'') || (CUR == '"') || + (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) { + lc = 0; + } else if (CUR == '*') { + /* relative or absolute location path */ + lc = 1; + } else if (CUR == '/') { + /* relative or absolute location path */ + lc = 1; + } else if (CUR == '@') { + /* relative abbreviated attribute location path */ + lc = 1; + } else if (CUR == '.') { + /* relative abbreviated attribute location path */ + lc = 1; + } else { + /* + * Problem is finding if we have a name here whether it's: + * - a nodetype + * - a function call in which case it's followed by '(' + * - an axis in which case it's followed by ':' + * - a element name + * We do an a priori analysis here rather than having to + * maintain parsed token content through the recursive function + * calls. This looks uglier but makes the code easier to + * read/write/debug. + */ + SKIP_BLANKS; + name = xmlXPathScanName(ctxt); + if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) { +#ifdef DEBUG_STEP + xmlGenericError(xmlGenericErrorContext, + "PathExpr: Axis\n"); +#endif + lc = 1; + xmlFree(name); + } else if (name != NULL) { + int len =xmlStrlen(name); + + + while (NXT(len) != 0) { + if (NXT(len) == '/') { + /* element name */ +#ifdef DEBUG_STEP + xmlGenericError(xmlGenericErrorContext, + "PathExpr: AbbrRelLocation\n"); +#endif + lc = 1; + break; + } else if (IS_BLANK_CH(NXT(len))) { + /* ignore blanks */ + ; + } else if (NXT(len) == ':') { +#ifdef DEBUG_STEP + xmlGenericError(xmlGenericErrorContext, + "PathExpr: AbbrRelLocation\n"); +#endif + lc = 1; + break; + } else if ((NXT(len) == '(')) { + /* Note Type or Function */ + if (xmlXPathIsNodeType(name)) { +#ifdef DEBUG_STEP + xmlGenericError(xmlGenericErrorContext, + "PathExpr: Type search\n"); +#endif + lc = 1; + } else { +#ifdef DEBUG_STEP + xmlGenericError(xmlGenericErrorContext, + "PathExpr: function call\n"); +#endif + lc = 0; + } + break; + } else if ((NXT(len) == '[')) { + /* element name */ +#ifdef DEBUG_STEP + xmlGenericError(xmlGenericErrorContext, + "PathExpr: AbbrRelLocation\n"); +#endif + lc = 1; + break; + } else if ((NXT(len) == '<') || (NXT(len) == '>') || + (NXT(len) == '=')) { + lc = 1; + break; + } else { + lc = 1; + break; + } + len++; + } + if (NXT(len) == 0) { +#ifdef DEBUG_STEP + xmlGenericError(xmlGenericErrorContext, + "PathExpr: AbbrRelLocation\n"); +#endif + /* element name */ + lc = 1; + } + xmlFree(name); + } else { + /* make sure all cases are covered explicitly */ + XP_ERROR(XPATH_EXPR_ERROR); + } + } + + if (lc) { + if (CUR == '/') { + PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0); + } else { + PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0); + } + xmlXPathCompLocationPath(ctxt); + } else { + xmlXPathCompFilterExpr(ctxt); + CHECK_ERROR; + if ((CUR == '/') && (NXT(1) == '/')) { + SKIP(2); + SKIP_BLANKS; + + PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, + NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); + PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0); + + xmlXPathCompRelativeLocationPath(ctxt); + } else if (CUR == '/') { + xmlXPathCompRelativeLocationPath(ctxt); + } + } + SKIP_BLANKS; +} + +/** + * xmlXPathCompUnionExpr: + * @ctxt: the XPath Parser context + * + * [18] UnionExpr ::= PathExpr + * | UnionExpr '|' PathExpr + * + * Compile an union expression. + */ + +static void +xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) { + xmlXPathCompPathExpr(ctxt); + CHECK_ERROR; + SKIP_BLANKS; + while (CUR == '|') { + int op1 = ctxt->comp->last; + PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0); + + NEXT; + SKIP_BLANKS; + xmlXPathCompPathExpr(ctxt); + + PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0); + + SKIP_BLANKS; + } +} + +/** + * xmlXPathCompUnaryExpr: + * @ctxt: the XPath Parser context + * + * [27] UnaryExpr ::= UnionExpr + * | '-' UnaryExpr + * + * Compile an unary expression. + */ + +static void +xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) { + int minus = 0; + int found = 0; + + SKIP_BLANKS; + while (CUR == '-') { + minus = 1 - minus; + found = 1; + NEXT; + SKIP_BLANKS; + } + + xmlXPathCompUnionExpr(ctxt); + CHECK_ERROR; + if (found) { + if (minus) + PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0); + else + PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0); + } +} + +/** + * xmlXPathCompMultiplicativeExpr: + * @ctxt: the XPath Parser context + * + * [26] MultiplicativeExpr ::= UnaryExpr + * | MultiplicativeExpr MultiplyOperator UnaryExpr + * | MultiplicativeExpr 'div' UnaryExpr + * | MultiplicativeExpr 'mod' UnaryExpr + * [34] MultiplyOperator ::= '*' + * + * Compile an Additive expression. + */ + +static void +xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) { + xmlXPathCompUnaryExpr(ctxt); + CHECK_ERROR; + SKIP_BLANKS; + while ((CUR == '*') || + ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) || + ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) { + int op = -1; + int op1 = ctxt->comp->last; + + if (CUR == '*') { + op = 0; + NEXT; + } else if (CUR == 'd') { + op = 1; + SKIP(3); + } else if (CUR == 'm') { + op = 2; + SKIP(3); + } + SKIP_BLANKS; + xmlXPathCompUnaryExpr(ctxt); + CHECK_ERROR; + PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0); + SKIP_BLANKS; + } +} + +/** + * xmlXPathCompAdditiveExpr: + * @ctxt: the XPath Parser context + * + * [25] AdditiveExpr ::= MultiplicativeExpr + * | AdditiveExpr '+' MultiplicativeExpr + * | AdditiveExpr '-' MultiplicativeExpr + * + * Compile an Additive expression. + */ + +static void +xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) { + + xmlXPathCompMultiplicativeExpr(ctxt); + CHECK_ERROR; + SKIP_BLANKS; + while ((CUR == '+') || (CUR == '-')) { + int plus; + int op1 = ctxt->comp->last; + + if (CUR == '+') plus = 1; + else plus = 0; + NEXT; + SKIP_BLANKS; + xmlXPathCompMultiplicativeExpr(ctxt); + CHECK_ERROR; + PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0); + SKIP_BLANKS; + } +} + +/** + * xmlXPathCompRelationalExpr: + * @ctxt: the XPath Parser context + * + * [24] RelationalExpr ::= AdditiveExpr + * | RelationalExpr '<' AdditiveExpr + * | RelationalExpr '>' AdditiveExpr + * | RelationalExpr '<=' AdditiveExpr + * | RelationalExpr '>=' AdditiveExpr + * + * A <= B > C is allowed ? Answer from James, yes with + * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr + * which is basically what got implemented. + * + * Compile a Relational expression, then push the result + * on the stack + */ + +static void +xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) { + xmlXPathCompAdditiveExpr(ctxt); + CHECK_ERROR; + SKIP_BLANKS; + while ((CUR == '<') || + (CUR == '>') || + ((CUR == '<') && (NXT(1) == '=')) || + ((CUR == '>') && (NXT(1) == '='))) { + int inf, strict; + int op1 = ctxt->comp->last; + + if (CUR == '<') inf = 1; + else inf = 0; + if (NXT(1) == '=') strict = 0; + else strict = 1; + NEXT; + if (!strict) NEXT; + SKIP_BLANKS; + xmlXPathCompAdditiveExpr(ctxt); + CHECK_ERROR; + PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict); + SKIP_BLANKS; + } +} + +/** + * xmlXPathCompEqualityExpr: + * @ctxt: the XPath Parser context + * + * [23] EqualityExpr ::= RelationalExpr + * | EqualityExpr '=' RelationalExpr + * | EqualityExpr '!=' RelationalExpr + * + * A != B != C is allowed ? Answer from James, yes with + * (RelationalExpr = RelationalExpr) = RelationalExpr + * (RelationalExpr != RelationalExpr) != RelationalExpr + * which is basically what got implemented. + * + * Compile an Equality expression. + * + */ +static void +xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) { + xmlXPathCompRelationalExpr(ctxt); + CHECK_ERROR; + SKIP_BLANKS; + while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) { + int eq; + int op1 = ctxt->comp->last; + + if (CUR == '=') eq = 1; + else eq = 0; + NEXT; + if (!eq) NEXT; + SKIP_BLANKS; + xmlXPathCompRelationalExpr(ctxt); + CHECK_ERROR; + PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0); + SKIP_BLANKS; + } +} + +/** + * xmlXPathCompAndExpr: + * @ctxt: the XPath Parser context + * + * [22] AndExpr ::= EqualityExpr + * | AndExpr 'and' EqualityExpr + * + * Compile an AND expression. + * + */ +static void +xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) { + xmlXPathCompEqualityExpr(ctxt); + CHECK_ERROR; + SKIP_BLANKS; + while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) { + int op1 = ctxt->comp->last; + SKIP(3); + SKIP_BLANKS; + xmlXPathCompEqualityExpr(ctxt); + CHECK_ERROR; + PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0); + SKIP_BLANKS; + } +} + +/** + * xmlXPathCompileExpr: + * @ctxt: the XPath Parser context + * + * [14] Expr ::= OrExpr + * [21] OrExpr ::= AndExpr + * | OrExpr 'or' AndExpr + * + * Parse and compile an expression + */ +static void +xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) { + xmlXPathCompAndExpr(ctxt); + CHECK_ERROR; + SKIP_BLANKS; + while ((CUR == 'o') && (NXT(1) == 'r')) { + int op1 = ctxt->comp->last; + SKIP(2); + SKIP_BLANKS; + xmlXPathCompAndExpr(ctxt); + CHECK_ERROR; + PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0); + SKIP_BLANKS; + } + if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) { + /* more ops could be optimized too */ + /* + * This is the main place to eliminate sorting for + * operations which don't require a sorted node-set. + * E.g. count(). + */ + PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0); + } +} + +/** + * xmlXPathCompPredicate: + * @ctxt: the XPath Parser context + * @filter: act as a filter + * + * [8] Predicate ::= '[' PredicateExpr ']' + * [9] PredicateExpr ::= Expr + * + * Compile a predicate expression + */ +static void +xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) { + int op1 = ctxt->comp->last; + + SKIP_BLANKS; + if (CUR != '[') { + XP_ERROR(XPATH_INVALID_PREDICATE_ERROR); + } + NEXT; + SKIP_BLANKS; + + ctxt->comp->last = -1; + /* + * This call to xmlXPathCompileExpr() will deactivate sorting + * of the predicate result. + * TODO: Sorting is still activated for filters, since I'm not + * sure if needed. Normally sorting should not be needed, since + * a filter can only diminish the number of items in a sequence, + * but won't change its order; so if the initial sequence is sorted, + * subsequent sorting is not needed. + */ + if (! filter) + xmlXPathCompileExpr(ctxt, 0); + else + xmlXPathCompileExpr(ctxt, 1); + CHECK_ERROR; + + if (CUR != ']') { + XP_ERROR(XPATH_INVALID_PREDICATE_ERROR); + } + + if (filter) + PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0); + else + PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0); + + NEXT; + SKIP_BLANKS; +} + +/** + * xmlXPathCompNodeTest: + * @ctxt: the XPath Parser context + * @test: pointer to a xmlXPathTestVal + * @type: pointer to a xmlXPathTypeVal + * @prefix: placeholder for a possible name prefix + * + * [7] NodeTest ::= NameTest + * | NodeType '(' ')' + * | 'processing-instruction' '(' Literal ')' + * + * [37] NameTest ::= '*' + * | NCName ':' '*' + * | QName + * [38] NodeType ::= 'comment' + * | 'text' + * | 'processing-instruction' + * | 'node' + * + * Returns the name found and updates @test, @type and @prefix appropriately + */ +static xmlChar * +xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test, + xmlXPathTypeVal *type, const xmlChar **prefix, + xmlChar *name) { + int blanks; + + if ((test == NULL) || (type == NULL) || (prefix == NULL)) { + STRANGE; + return(NULL); + } + *type = (xmlXPathTypeVal) 0; + *test = (xmlXPathTestVal) 0; + *prefix = NULL; + SKIP_BLANKS; + + if ((name == NULL) && (CUR == '*')) { + /* + * All elements + */ + NEXT; + *test = NODE_TEST_ALL; + return(NULL); + } + + if (name == NULL) + name = xmlXPathParseNCName(ctxt); + if (name == NULL) { + XP_ERRORNULL(XPATH_EXPR_ERROR); + } + + blanks = IS_BLANK_CH(CUR); + SKIP_BLANKS; + if (CUR == '(') { + NEXT; + /* + * NodeType or PI search + */ + if (xmlStrEqual(name, BAD_CAST "comment")) + *type = NODE_TYPE_COMMENT; + else if (xmlStrEqual(name, BAD_CAST "node")) + *type = NODE_TYPE_NODE; + else if (xmlStrEqual(name, BAD_CAST "processing-instruction")) + *type = NODE_TYPE_PI; + else if (xmlStrEqual(name, BAD_CAST "text")) + *type = NODE_TYPE_TEXT; + else { + if (name != NULL) + xmlFree(name); + XP_ERRORNULL(XPATH_EXPR_ERROR); + } + + *test = NODE_TEST_TYPE; + + SKIP_BLANKS; + if (*type == NODE_TYPE_PI) { + /* + * Specific case: search a PI by name. + */ + if (name != NULL) + xmlFree(name); + name = NULL; + if (CUR != ')') { + name = xmlXPathParseLiteral(ctxt); + CHECK_ERROR NULL; + *test = NODE_TEST_PI; + SKIP_BLANKS; + } + } + if (CUR != ')') { + if (name != NULL) + xmlFree(name); + XP_ERRORNULL(XPATH_UNCLOSED_ERROR); + } + NEXT; + return(name); + } + *test = NODE_TEST_NAME; + if ((!blanks) && (CUR == ':')) { + NEXT; + + /* + * Since currently the parser context don't have a + * namespace list associated: + * The namespace name for this prefix can be computed + * only at evaluation time. The compilation is done + * outside of any context. + */ +#if 0 + *prefix = xmlXPathNsLookup(ctxt->context, name); + if (name != NULL) + xmlFree(name); + if (*prefix == NULL) { + XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR); + } +#else + *prefix = name; +#endif + + if (CUR == '*') { + /* + * All elements + */ + NEXT; + *test = NODE_TEST_ALL; + return(NULL); + } + + name = xmlXPathParseNCName(ctxt); + if (name == NULL) { + XP_ERRORNULL(XPATH_EXPR_ERROR); + } + } + return(name); +} + +/** + * xmlXPathIsAxisName: + * @name: a preparsed name token + * + * [6] AxisName ::= 'ancestor' + * | 'ancestor-or-self' + * | 'attribute' + * | 'child' + * | 'descendant' + * | 'descendant-or-self' + * | 'following' + * | 'following-sibling' + * | 'namespace' + * | 'parent' + * | 'preceding' + * | 'preceding-sibling' + * | 'self' + * + * Returns the axis or 0 + */ +static xmlXPathAxisVal +xmlXPathIsAxisName(const xmlChar *name) { + xmlXPathAxisVal ret = (xmlXPathAxisVal) 0; + switch (name[0]) { + case 'a': + if (xmlStrEqual(name, BAD_CAST "ancestor")) + ret = AXIS_ANCESTOR; + if (xmlStrEqual(name, BAD_CAST "ancestor-or-self")) + ret = AXIS_ANCESTOR_OR_SELF; + if (xmlStrEqual(name, BAD_CAST "attribute")) + ret = AXIS_ATTRIBUTE; + break; + case 'c': + if (xmlStrEqual(name, BAD_CAST "child")) + ret = AXIS_CHILD; + break; + case 'd': + if (xmlStrEqual(name, BAD_CAST "descendant")) + ret = AXIS_DESCENDANT; + if (xmlStrEqual(name, BAD_CAST "descendant-or-self")) + ret = AXIS_DESCENDANT_OR_SELF; + break; + case 'f': + if (xmlStrEqual(name, BAD_CAST "following")) + ret = AXIS_FOLLOWING; + if (xmlStrEqual(name, BAD_CAST "following-sibling")) + ret = AXIS_FOLLOWING_SIBLING; + break; + case 'n': + if (xmlStrEqual(name, BAD_CAST "namespace")) + ret = AXIS_NAMESPACE; + break; + case 'p': + if (xmlStrEqual(name, BAD_CAST "parent")) + ret = AXIS_PARENT; + if (xmlStrEqual(name, BAD_CAST "preceding")) + ret = AXIS_PRECEDING; + if (xmlStrEqual(name, BAD_CAST "preceding-sibling")) + ret = AXIS_PRECEDING_SIBLING; + break; + case 's': + if (xmlStrEqual(name, BAD_CAST "self")) + ret = AXIS_SELF; + break; + } + return(ret); +} + +/** + * xmlXPathCompStep: + * @ctxt: the XPath Parser context + * + * [4] Step ::= AxisSpecifier NodeTest Predicate* + * | AbbreviatedStep + * + * [12] AbbreviatedStep ::= '.' | '..' + * + * [5] AxisSpecifier ::= AxisName '::' + * | AbbreviatedAxisSpecifier + * + * [13] AbbreviatedAxisSpecifier ::= '@'? + * + * Modified for XPtr range support as: + * + * [4xptr] Step ::= AxisSpecifier NodeTest Predicate* + * | AbbreviatedStep + * | 'range-to' '(' Expr ')' Predicate* + * + * Compile one step in a Location Path + * A location step of . is short for self::node(). This is + * particularly useful in conjunction with //. For example, the + * location path .//para is short for + * self::node()/descendant-or-self::node()/child::para + * and so will select all para descendant elements of the context + * node. + * Similarly, a location step of .. is short for parent::node(). + * For example, ../title is short for parent::node()/child::title + * and so will select the title children of the parent of the context + * node. + */ +static void +xmlXPathCompStep(xmlXPathParserContextPtr ctxt) { +#ifdef LIBXML_XPTR_ENABLED + int rangeto = 0; + int op2 = -1; +#endif + + SKIP_BLANKS; + if ((CUR == '.') && (NXT(1) == '.')) { + SKIP(2); + SKIP_BLANKS; + PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT, + NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); + } else if (CUR == '.') { + NEXT; + SKIP_BLANKS; + } else { + xmlChar *name = NULL; + const xmlChar *prefix = NULL; + xmlXPathTestVal test = (xmlXPathTestVal) 0; + xmlXPathAxisVal axis = (xmlXPathAxisVal) 0; + xmlXPathTypeVal type = (xmlXPathTypeVal) 0; + int op1; + + /* + * The modification needed for XPointer change to the production + */ +#ifdef LIBXML_XPTR_ENABLED + if (ctxt->xptr) { + name = xmlXPathParseNCName(ctxt); + if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) { + op2 = ctxt->comp->last; + xmlFree(name); + SKIP_BLANKS; + if (CUR != '(') { + XP_ERROR(XPATH_EXPR_ERROR); + } + NEXT; + SKIP_BLANKS; + + xmlXPathCompileExpr(ctxt, 1); + /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */ + CHECK_ERROR; + + SKIP_BLANKS; + if (CUR != ')') { + XP_ERROR(XPATH_EXPR_ERROR); + } + NEXT; + rangeto = 1; + goto eval_predicates; + } + } +#endif + if (CUR == '*') { + axis = AXIS_CHILD; + } else { + if (name == NULL) + name = xmlXPathParseNCName(ctxt); + if (name != NULL) { + axis = xmlXPathIsAxisName(name); + if (axis != 0) { + SKIP_BLANKS; + if ((CUR == ':') && (NXT(1) == ':')) { + SKIP(2); + xmlFree(name); + name = NULL; + } else { + /* an element name can conflict with an axis one :-\ */ + axis = AXIS_CHILD; + } + } else { + axis = AXIS_CHILD; + } + } else if (CUR == '@') { + NEXT; + axis = AXIS_ATTRIBUTE; + } else { + axis = AXIS_CHILD; + } + } + + if (ctxt->error != XPATH_EXPRESSION_OK) { + xmlFree(name); + return; + } + + name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name); + if (test == 0) + return; + + if ((prefix != NULL) && (ctxt->context != NULL) && + (ctxt->context->flags & XML_XPATH_CHECKNS)) { + if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) { + xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR); + } + } +#ifdef DEBUG_STEP + xmlGenericError(xmlGenericErrorContext, + "Basis : computing new set\n"); +#endif + +#ifdef DEBUG_STEP + xmlGenericError(xmlGenericErrorContext, "Basis : "); + if (ctxt->value == NULL) + xmlGenericError(xmlGenericErrorContext, "no value\n"); + else if (ctxt->value->nodesetval == NULL) + xmlGenericError(xmlGenericErrorContext, "Empty\n"); + else + xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval); +#endif + +#ifdef LIBXML_XPTR_ENABLED +eval_predicates: +#endif + op1 = ctxt->comp->last; + ctxt->comp->last = -1; + + SKIP_BLANKS; + while (CUR == '[') { + xmlXPathCompPredicate(ctxt, 0); + } + +#ifdef LIBXML_XPTR_ENABLED + if (rangeto) { + PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0); + } else +#endif + PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis, + test, type, (void *)prefix, (void *)name); + + } +#ifdef DEBUG_STEP + xmlGenericError(xmlGenericErrorContext, "Step : "); + if (ctxt->value == NULL) + xmlGenericError(xmlGenericErrorContext, "no value\n"); + else if (ctxt->value->nodesetval == NULL) + xmlGenericError(xmlGenericErrorContext, "Empty\n"); + else + xmlGenericErrorContextNodeSet(xmlGenericErrorContext, + ctxt->value->nodesetval); +#endif +} + +/** + * xmlXPathCompRelativeLocationPath: + * @ctxt: the XPath Parser context + * + * [3] RelativeLocationPath ::= Step + * | RelativeLocationPath '/' Step + * | AbbreviatedRelativeLocationPath + * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step + * + * Compile a relative location path. + */ +static void +xmlXPathCompRelativeLocationPath +(xmlXPathParserContextPtr ctxt) { + SKIP_BLANKS; + if ((CUR == '/') && (NXT(1) == '/')) { + SKIP(2); + SKIP_BLANKS; + PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, + NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); + } else if (CUR == '/') { + NEXT; + SKIP_BLANKS; + } + xmlXPathCompStep(ctxt); + CHECK_ERROR; + SKIP_BLANKS; + while (CUR == '/') { + if ((CUR == '/') && (NXT(1) == '/')) { + SKIP(2); + SKIP_BLANKS; + PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, + NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); + xmlXPathCompStep(ctxt); + } else if (CUR == '/') { + NEXT; + SKIP_BLANKS; + xmlXPathCompStep(ctxt); + } + SKIP_BLANKS; + } +} + +/** + * xmlXPathCompLocationPath: + * @ctxt: the XPath Parser context + * + * [1] LocationPath ::= RelativeLocationPath + * | AbsoluteLocationPath + * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath? + * | AbbreviatedAbsoluteLocationPath + * [10] AbbreviatedAbsoluteLocationPath ::= + * '//' RelativeLocationPath + * + * Compile a location path + * + * // is short for /descendant-or-self::node()/. For example, + * //para is short for /descendant-or-self::node()/child::para and + * so will select any para element in the document (even a para element + * that is a document element will be selected by //para since the + * document element node is a child of the root node); div//para is + * short for div/descendant-or-self::node()/child::para and so will + * select all para descendants of div children. + */ +static void +xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) { + SKIP_BLANKS; + if (CUR != '/') { + xmlXPathCompRelativeLocationPath(ctxt); + } else { + while (CUR == '/') { + if ((CUR == '/') && (NXT(1) == '/')) { + SKIP(2); + SKIP_BLANKS; + PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, + NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); + xmlXPathCompRelativeLocationPath(ctxt); + } else if (CUR == '/') { + NEXT; + SKIP_BLANKS; + if ((CUR != 0 ) && + ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') || + (CUR == '@') || (CUR == '*'))) + xmlXPathCompRelativeLocationPath(ctxt); + } + CHECK_ERROR; + } + } +} + +/************************************************************************ + * * + * XPath precompiled expression evaluation * + * * + ************************************************************************/ + +static int +xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op); + +#ifdef DEBUG_STEP +static void +xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op, + int nbNodes) +{ + xmlGenericError(xmlGenericErrorContext, "new step : "); + switch (op->value) { + case AXIS_ANCESTOR: + xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' "); + break; + case AXIS_ANCESTOR_OR_SELF: + xmlGenericError(xmlGenericErrorContext, + "axis 'ancestors-or-self' "); + break; + case AXIS_ATTRIBUTE: + xmlGenericError(xmlGenericErrorContext, "axis 'attributes' "); + break; + case AXIS_CHILD: + xmlGenericError(xmlGenericErrorContext, "axis 'child' "); + break; + case AXIS_DESCENDANT: + xmlGenericError(xmlGenericErrorContext, "axis 'descendant' "); + break; + case AXIS_DESCENDANT_OR_SELF: + xmlGenericError(xmlGenericErrorContext, + "axis 'descendant-or-self' "); + break; + case AXIS_FOLLOWING: + xmlGenericError(xmlGenericErrorContext, "axis 'following' "); + break; + case AXIS_FOLLOWING_SIBLING: + xmlGenericError(xmlGenericErrorContext, + "axis 'following-siblings' "); + break; + case AXIS_NAMESPACE: + xmlGenericError(xmlGenericErrorContext, "axis 'namespace' "); + break; + case AXIS_PARENT: + xmlGenericError(xmlGenericErrorContext, "axis 'parent' "); + break; + case AXIS_PRECEDING: + xmlGenericError(xmlGenericErrorContext, "axis 'preceding' "); + break; + case AXIS_PRECEDING_SIBLING: + xmlGenericError(xmlGenericErrorContext, + "axis 'preceding-sibling' "); + break; + case AXIS_SELF: + xmlGenericError(xmlGenericErrorContext, "axis 'self' "); + break; + } + xmlGenericError(xmlGenericErrorContext, + " context contains %d nodes\n", nbNodes); + switch (op->value2) { + case NODE_TEST_NONE: + xmlGenericError(xmlGenericErrorContext, + " searching for none !!!\n"); + break; + case NODE_TEST_TYPE: + xmlGenericError(xmlGenericErrorContext, + " searching for type %d\n", op->value3); + break; + case NODE_TEST_PI: + xmlGenericError(xmlGenericErrorContext, + " searching for PI !!!\n"); + break; + case NODE_TEST_ALL: + xmlGenericError(xmlGenericErrorContext, + " searching for *\n"); + break; + case NODE_TEST_NS: + xmlGenericError(xmlGenericErrorContext, + " searching for namespace %s\n", + op->value5); + break; + case NODE_TEST_NAME: + xmlGenericError(xmlGenericErrorContext, + " searching for name %s\n", op->value5); + if (op->value4) + xmlGenericError(xmlGenericErrorContext, + " with namespace %s\n", op->value4); + break; + } + xmlGenericError(xmlGenericErrorContext, "Testing : "); +} +#endif /* DEBUG_STEP */ + +static int +xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt, + xmlXPathStepOpPtr op, + xmlNodeSetPtr set, + int contextSize, + int hasNsNodes) +{ + if (op->ch1 != -1) { + xmlXPathCompExprPtr comp = ctxt->comp; + /* + * Process inner predicates first. + */ + if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) { + /* + * TODO: raise an internal error. + */ + } + contextSize = xmlXPathCompOpEvalPredicate(ctxt, + &comp->steps[op->ch1], set, contextSize, hasNsNodes); + CHECK_ERROR0; + if (contextSize <= 0) + return(0); + } + if (op->ch2 != -1) { + xmlXPathContextPtr xpctxt = ctxt->context; + xmlNodePtr contextNode, oldContextNode; + xmlDocPtr oldContextDoc; + int i, res, contextPos = 0, newContextSize; + xmlXPathStepOpPtr exprOp; + xmlXPathObjectPtr contextObj = NULL, exprRes = NULL; + +#ifdef LIBXML_XPTR_ENABLED + /* + * URGENT TODO: Check the following: + * We don't expect location sets if evaluating prediates, right? + * Only filters should expect location sets, right? + */ +#endif + /* + * SPEC XPath 1.0: + * "For each node in the node-set to be filtered, the + * PredicateExpr is evaluated with that node as the + * context node, with the number of nodes in the + * node-set as the context size, and with the proximity + * position of the node in the node-set with respect to + * the axis as the context position;" + * @oldset is the node-set" to be filtered. + * + * SPEC XPath 1.0: + * "only predicates change the context position and + * context size (see [2.4 Predicates])." + * Example: + * node-set context pos + * nA 1 + * nB 2 + * nC 3 + * After applying predicate [position() > 1] : + * node-set context pos + * nB 1 + * nC 2 + */ + oldContextNode = xpctxt->node; + oldContextDoc = xpctxt->doc; + /* + * Get the expression of this predicate. + */ + exprOp = &ctxt->comp->steps[op->ch2]; + newContextSize = 0; + for (i = 0; i < set->nodeNr; i++) { + if (set->nodeTab[i] == NULL) + continue; + + contextNode = set->nodeTab[i]; + xpctxt->node = contextNode; + xpctxt->contextSize = contextSize; + xpctxt->proximityPosition = ++contextPos; + + /* + * Also set the xpath document in case things like + * key() are evaluated in the predicate. + */ + if ((contextNode->type != XML_NAMESPACE_DECL) && + (contextNode->doc != NULL)) + xpctxt->doc = contextNode->doc; + /* + * Evaluate the predicate expression with 1 context node + * at a time; this node is packaged into a node set; this + * node set is handed over to the evaluation mechanism. + */ + if (contextObj == NULL) + contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode); + else + xmlXPathNodeSetAddUnique(contextObj->nodesetval, + contextNode); + + valuePush(ctxt, contextObj); + + res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1); + + if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) { + xmlXPathNodeSetClear(set, hasNsNodes); + newContextSize = 0; + goto evaluation_exit; + } + + if (res != 0) { + newContextSize++; + } else { + /* + * Remove the entry from the initial node set. + */ + set->nodeTab[i] = NULL; + if (contextNode->type == XML_NAMESPACE_DECL) + xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode); + } + if (ctxt->value == contextObj) { + /* + * Don't free the temporary XPath object holding the + * context node, in order to avoid massive recreation + * inside this loop. + */ + valuePop(ctxt); + xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes); + } else { + /* + * TODO: The object was lost in the evaluation machinery. + * Can this happen? Maybe in internal-error cases. + */ + contextObj = NULL; + } + } + + if (contextObj != NULL) { + if (ctxt->value == contextObj) + valuePop(ctxt); + xmlXPathReleaseObject(xpctxt, contextObj); + } +evaluation_exit: + if (exprRes != NULL) + xmlXPathReleaseObject(ctxt->context, exprRes); + /* + * Reset/invalidate the context. + */ + xpctxt->node = oldContextNode; + xpctxt->doc = oldContextDoc; + xpctxt->contextSize = -1; + xpctxt->proximityPosition = -1; + return(newContextSize); + } + return(contextSize); +} + +static int +xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt, + xmlXPathStepOpPtr op, + xmlNodeSetPtr set, + int contextSize, + int minPos, + int maxPos, + int hasNsNodes) +{ + if (op->ch1 != -1) { + xmlXPathCompExprPtr comp = ctxt->comp; + if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) { + /* + * TODO: raise an internal error. + */ + } + contextSize = xmlXPathCompOpEvalPredicate(ctxt, + &comp->steps[op->ch1], set, contextSize, hasNsNodes); + CHECK_ERROR0; + if (contextSize <= 0) + return(0); + } + /* + * Check if the node set contains a sufficient number of nodes for + * the requested range. + */ + if (contextSize < minPos) { + xmlXPathNodeSetClear(set, hasNsNodes); + return(0); + } + if (op->ch2 == -1) { + /* + * TODO: Can this ever happen? + */ + return (contextSize); + } else { + xmlDocPtr oldContextDoc; + int i, pos = 0, newContextSize = 0, contextPos = 0, res; + xmlXPathStepOpPtr exprOp; + xmlXPathObjectPtr contextObj = NULL, exprRes = NULL; + xmlNodePtr oldContextNode, contextNode = NULL; + xmlXPathContextPtr xpctxt = ctxt->context; + int frame; + +#ifdef LIBXML_XPTR_ENABLED + /* + * URGENT TODO: Check the following: + * We don't expect location sets if evaluating prediates, right? + * Only filters should expect location sets, right? + */ +#endif /* LIBXML_XPTR_ENABLED */ + + /* + * Save old context. + */ + oldContextNode = xpctxt->node; + oldContextDoc = xpctxt->doc; + /* + * Get the expression of this predicate. + */ + exprOp = &ctxt->comp->steps[op->ch2]; + for (i = 0; i < set->nodeNr; i++) { + xmlXPathObjectPtr tmp; + + if (set->nodeTab[i] == NULL) + continue; + + contextNode = set->nodeTab[i]; + xpctxt->node = contextNode; + xpctxt->contextSize = contextSize; + xpctxt->proximityPosition = ++contextPos; + + /* + * Initialize the new set. + * Also set the xpath document in case things like + * key() evaluation are attempted on the predicate + */ + if ((contextNode->type != XML_NAMESPACE_DECL) && + (contextNode->doc != NULL)) + xpctxt->doc = contextNode->doc; + /* + * Evaluate the predicate expression with 1 context node + * at a time; this node is packaged into a node set; this + * node set is handed over to the evaluation mechanism. + */ + if (contextObj == NULL) + contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode); + else + xmlXPathNodeSetAddUnique(contextObj->nodesetval, + contextNode); + + frame = xmlXPathSetFrame(ctxt); + valuePush(ctxt, contextObj); + res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1); + tmp = valuePop(ctxt); + xmlXPathPopFrame(ctxt, frame); + + if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) { + while (tmp != contextObj) { + /* + * Free up the result + * then pop off contextObj, which will be freed later + */ + xmlXPathReleaseObject(xpctxt, tmp); + tmp = valuePop(ctxt); + } + goto evaluation_error; + } + /* push the result back onto the stack */ + valuePush(ctxt, tmp); + + if (res) + pos++; + + if (res && (pos >= minPos) && (pos <= maxPos)) { + /* + * Fits in the requested range. + */ + newContextSize++; + if (minPos == maxPos) { + /* + * Only 1 node was requested. + */ + if (contextNode->type == XML_NAMESPACE_DECL) { + /* + * As always: take care of those nasty + * namespace nodes. + */ + set->nodeTab[i] = NULL; + } + xmlXPathNodeSetClear(set, hasNsNodes); + set->nodeNr = 1; + set->nodeTab[0] = contextNode; + goto evaluation_exit; + } + if (pos == maxPos) { + /* + * We are done. + */ + xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes); + goto evaluation_exit; + } + } else { + /* + * Remove the entry from the initial node set. + */ + set->nodeTab[i] = NULL; + if (contextNode->type == XML_NAMESPACE_DECL) + xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode); + } + if (exprRes != NULL) { + xmlXPathReleaseObject(ctxt->context, exprRes); + exprRes = NULL; + } + if (ctxt->value == contextObj) { + /* + * Don't free the temporary XPath object holding the + * context node, in order to avoid massive recreation + * inside this loop. + */ + valuePop(ctxt); + xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes); + } else { + /* + * The object was lost in the evaluation machinery. + * Can this happen? Maybe in case of internal-errors. + */ + contextObj = NULL; + } + } + goto evaluation_exit; + +evaluation_error: + xmlXPathNodeSetClear(set, hasNsNodes); + newContextSize = 0; + +evaluation_exit: + if (contextObj != NULL) { + if (ctxt->value == contextObj) + valuePop(ctxt); + xmlXPathReleaseObject(xpctxt, contextObj); + } + if (exprRes != NULL) + xmlXPathReleaseObject(ctxt->context, exprRes); + /* + * Reset/invalidate the context. + */ + xpctxt->node = oldContextNode; + xpctxt->doc = oldContextDoc; + xpctxt->contextSize = -1; + xpctxt->proximityPosition = -1; + return(newContextSize); + } + return(contextSize); +} + +static int +xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt, + xmlXPathStepOpPtr op, + int *maxPos) +{ + + xmlXPathStepOpPtr exprOp; + + /* + * BIG NOTE: This is not intended for XPATH_OP_FILTER yet! + */ + + /* + * If not -1, then ch1 will point to: + * 1) For predicates (XPATH_OP_PREDICATE): + * - an inner predicate operator + * 2) For filters (XPATH_OP_FILTER): + * - an inner filter operater OR + * - an expression selecting the node set. + * E.g. "key('a', 'b')" or "(//foo | //bar)". + */ + if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER)) + return(0); + + if (op->ch2 != -1) { + exprOp = &ctxt->comp->steps[op->ch2]; + } else + return(0); + + if ((exprOp != NULL) && + (exprOp->op == XPATH_OP_VALUE) && + (exprOp->value4 != NULL) && + (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER)) + { + /* + * We have a "[n]" predicate here. + * TODO: Unfortunately this simplistic test here is not + * able to detect a position() predicate in compound + * expressions like "[@attr = 'a" and position() = 1], + * and even not the usage of position() in + * "[position() = 1]"; thus - obviously - a position-range, + * like it "[position() < 5]", is also not detected. + * Maybe we could rewrite the AST to ease the optimization. + */ + *maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval; + + if (((xmlXPathObjectPtr) exprOp->value4)->floatval == + (float) *maxPos) + { + return(1); + } + } + return(0); +} + +static int +xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, + xmlXPathStepOpPtr op, + xmlNodePtr * first, xmlNodePtr * last, + int toBool) +{ + +#define XP_TEST_HIT \ + if (hasAxisRange != 0) { \ + if (++pos == maxPos) { \ + addNode(seq, cur); \ + goto axis_range_end; } \ + } else { \ + addNode(seq, cur); \ + if (breakOnFirstHit) goto first_hit; } + +#define XP_TEST_HIT_NS \ + if (hasAxisRange != 0) { \ + if (++pos == maxPos) { \ + hasNsNodes = 1; \ + xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \ + goto axis_range_end; } \ + } else { \ + hasNsNodes = 1; \ + xmlXPathNodeSetAddNs(seq, \ + xpctxt->node, (xmlNsPtr) cur); \ + if (breakOnFirstHit) goto first_hit; } + + xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value; + xmlXPathTestVal test = (xmlXPathTestVal) op->value2; + xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3; + const xmlChar *prefix = op->value4; + const xmlChar *name = op->value5; + const xmlChar *URI = NULL; + +#ifdef DEBUG_STEP + int nbMatches = 0, prevMatches = 0; +#endif + int total = 0, hasNsNodes = 0; + /* The popped object holding the context nodes */ + xmlXPathObjectPtr obj; + /* The set of context nodes for the node tests */ + xmlNodeSetPtr contextSeq; + int contextIdx; + xmlNodePtr contextNode; + /* The context node for a compound traversal */ + xmlNodePtr outerContextNode; + /* The final resulting node set wrt to all context nodes */ + xmlNodeSetPtr outSeq; + /* + * The temporary resulting node set wrt 1 context node. + * Used to feed predicate evaluation. + */ + xmlNodeSetPtr seq; + xmlNodePtr cur; + /* First predicate operator */ + xmlXPathStepOpPtr predOp; + int maxPos; /* The requested position() (when a "[n]" predicate) */ + int hasPredicateRange, hasAxisRange, pos, size, newSize; + int breakOnFirstHit; + + xmlXPathTraversalFunction next = NULL; + /* compound axis traversal */ + xmlXPathTraversalFunctionExt outerNext = NULL; + void (*addNode) (xmlNodeSetPtr, xmlNodePtr); + xmlXPathNodeSetMergeFunction mergeAndClear; + xmlNodePtr oldContextNode; + xmlXPathContextPtr xpctxt = ctxt->context; + + + CHECK_TYPE0(XPATH_NODESET); + obj = valuePop(ctxt); + /* + * Setup namespaces. + */ + if (prefix != NULL) { + URI = xmlXPathNsLookup(xpctxt, prefix); + if (URI == NULL) { + xmlXPathReleaseObject(xpctxt, obj); + XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR); + } + } + /* + * Setup axis. + * + * MAYBE FUTURE TODO: merging optimizations: + * - If the nodes to be traversed wrt to the initial nodes and + * the current axis cannot overlap, then we could avoid searching + * for duplicates during the merge. + * But the question is how/when to evaluate if they cannot overlap. + * Example: if we know that for two initial nodes, the one is + * not in the ancestor-or-self axis of the other, then we could safely + * avoid a duplicate-aware merge, if the axis to be traversed is e.g. + * the descendant-or-self axis. + */ + mergeAndClear = xmlXPathNodeSetMergeAndClear; + switch (axis) { + case AXIS_ANCESTOR: + first = NULL; + next = xmlXPathNextAncestor; + break; + case AXIS_ANCESTOR_OR_SELF: + first = NULL; + next = xmlXPathNextAncestorOrSelf; + break; + case AXIS_ATTRIBUTE: + first = NULL; + last = NULL; + next = xmlXPathNextAttribute; + mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; + break; + case AXIS_CHILD: + last = NULL; + if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) { + /* + * This iterator will give us only nodes which can + * hold element nodes. + */ + outerNext = xmlXPathNextDescendantOrSelfElemParent; + } + if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) && + (type == NODE_TYPE_NODE)) + { + /* + * Optimization if an element node type is 'element'. + */ + next = xmlXPathNextChildElement; + } else + next = xmlXPathNextChild; + mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; + break; + case AXIS_DESCENDANT: + last = NULL; + next = xmlXPathNextDescendant; + break; + case AXIS_DESCENDANT_OR_SELF: + last = NULL; + next = xmlXPathNextDescendantOrSelf; + break; + case AXIS_FOLLOWING: + last = NULL; + next = xmlXPathNextFollowing; + break; + case AXIS_FOLLOWING_SIBLING: + last = NULL; + next = xmlXPathNextFollowingSibling; + break; + case AXIS_NAMESPACE: + first = NULL; + last = NULL; + next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; + mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; + break; + case AXIS_PARENT: + first = NULL; + next = xmlXPathNextParent; + break; + case AXIS_PRECEDING: + first = NULL; + next = xmlXPathNextPrecedingInternal; + break; + case AXIS_PRECEDING_SIBLING: + first = NULL; + next = xmlXPathNextPrecedingSibling; + break; + case AXIS_SELF: + first = NULL; + last = NULL; + next = xmlXPathNextSelf; + mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls; + break; + } + +#ifdef DEBUG_STEP + xmlXPathDebugDumpStepAxis(op, + (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0); +#endif + + if (next == NULL) { + xmlXPathReleaseObject(xpctxt, obj); + return(0); + } + contextSeq = obj->nodesetval; + if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) { + xmlXPathReleaseObject(xpctxt, obj); + valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL)); + return(0); + } + /* + * Predicate optimization --------------------------------------------- + * If this step has a last predicate, which contains a position(), + * then we'll optimize (although not exactly "position()", but only + * the short-hand form, i.e., "[n]". + * + * Example - expression "/foo[parent::bar][1]": + * + * COLLECT 'child' 'name' 'node' foo -- op (we are here) + * ROOT -- op->ch1 + * PREDICATE -- op->ch2 (predOp) + * PREDICATE -- predOp->ch1 = [parent::bar] + * SORT + * COLLECT 'parent' 'name' 'node' bar + * NODE + * ELEM Object is a number : 1 -- predOp->ch2 = [1] + * + */ + maxPos = 0; + predOp = NULL; + hasPredicateRange = 0; + hasAxisRange = 0; + if (op->ch2 != -1) { + /* + * There's at least one predicate. 16 == XPATH_OP_PREDICATE + */ + predOp = &ctxt->comp->steps[op->ch2]; + if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) { + if (predOp->ch1 != -1) { + /* + * Use the next inner predicate operator. + */ + predOp = &ctxt->comp->steps[predOp->ch1]; + hasPredicateRange = 1; + } else { + /* + * There's no other predicate than the [n] predicate. + */ + predOp = NULL; + hasAxisRange = 1; + } + } + } + breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0; + /* + * Axis traversal ----------------------------------------------------- + */ + /* + * 2.3 Node Tests + * - For the attribute axis, the principal node type is attribute. + * - For the namespace axis, the principal node type is namespace. + * - For other axes, the principal node type is element. + * + * A node test * is true for any node of the + * principal node type. For example, child::* will + * select all element children of the context node + */ + oldContextNode = xpctxt->node; + addNode = xmlXPathNodeSetAddUnique; + outSeq = NULL; + seq = NULL; + outerContextNode = NULL; + contextNode = NULL; + contextIdx = 0; + + + while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) { + if (outerNext != NULL) { + /* + * This is a compound traversal. + */ + if (contextNode == NULL) { + /* + * Set the context for the outer traversal. + */ + outerContextNode = contextSeq->nodeTab[contextIdx++]; + contextNode = outerNext(NULL, outerContextNode); + } else + contextNode = outerNext(contextNode, outerContextNode); + if (contextNode == NULL) + continue; + /* + * Set the context for the main traversal. + */ + xpctxt->node = contextNode; + } else + xpctxt->node = contextSeq->nodeTab[contextIdx++]; + + if (seq == NULL) { + seq = xmlXPathNodeSetCreate(NULL); + if (seq == NULL) { + total = 0; + goto error; + } + } + /* + * Traverse the axis and test the nodes. + */ + pos = 0; + cur = NULL; + hasNsNodes = 0; + do { + cur = next(ctxt, cur); + if (cur == NULL) + break; + + /* + * QUESTION TODO: What does the "first" and "last" stuff do? + */ + if ((first != NULL) && (*first != NULL)) { + if (*first == cur) + break; + if (((total % 256) == 0) && +#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON + (xmlXPathCmpNodesExt(*first, cur) >= 0)) +#else + (xmlXPathCmpNodes(*first, cur) >= 0)) +#endif + { + break; + } + } + if ((last != NULL) && (*last != NULL)) { + if (*last == cur) + break; + if (((total % 256) == 0) && +#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON + (xmlXPathCmpNodesExt(cur, *last) >= 0)) +#else + (xmlXPathCmpNodes(cur, *last) >= 0)) +#endif + { + break; + } + } + + total++; + +#ifdef DEBUG_STEP + xmlGenericError(xmlGenericErrorContext, " %s", cur->name); +#endif + + switch (test) { + case NODE_TEST_NONE: + total = 0; + STRANGE + goto error; + case NODE_TEST_TYPE: + /* + * TODO: Don't we need to use + * xmlXPathNodeSetAddNs() for namespace nodes here? + * Surprisingly, some c14n tests fail, if we do this. + */ + if (type == NODE_TYPE_NODE) { + switch (cur->type) { + case XML_DOCUMENT_NODE: + case XML_HTML_DOCUMENT_NODE: +#ifdef LIBXML_DOCB_ENABLED + case XML_DOCB_DOCUMENT_NODE: +#endif + case XML_ELEMENT_NODE: + case XML_ATTRIBUTE_NODE: + case XML_PI_NODE: + case XML_COMMENT_NODE: + case XML_CDATA_SECTION_NODE: + case XML_TEXT_NODE: + case XML_NAMESPACE_DECL: + XP_TEST_HIT + break; + default: + break; + } + } else if (cur->type == type) { + if (type == XML_NAMESPACE_DECL) + XP_TEST_HIT_NS + else + XP_TEST_HIT + } else if ((type == NODE_TYPE_TEXT) && + (cur->type == XML_CDATA_SECTION_NODE)) + { + XP_TEST_HIT + } + break; + case NODE_TEST_PI: + if ((cur->type == XML_PI_NODE) && + ((name == NULL) || xmlStrEqual(name, cur->name))) + { + XP_TEST_HIT + } + break; + case NODE_TEST_ALL: + if (axis == AXIS_ATTRIBUTE) { + if (cur->type == XML_ATTRIBUTE_NODE) + { + XP_TEST_HIT + } + } else if (axis == AXIS_NAMESPACE) { + if (cur->type == XML_NAMESPACE_DECL) + { + XP_TEST_HIT_NS + } + } else { + if (cur->type == XML_ELEMENT_NODE) { + if (prefix == NULL) + { + XP_TEST_HIT + + } else if ((cur->ns != NULL) && + (xmlStrEqual(URI, cur->ns->href))) + { + XP_TEST_HIT + } + } + } + break; + case NODE_TEST_NS:{ + TODO; + break; + } + case NODE_TEST_NAME: + if (axis == AXIS_ATTRIBUTE) { + if (cur->type != XML_ATTRIBUTE_NODE) + break; + } else if (axis == AXIS_NAMESPACE) { + if (cur->type != XML_NAMESPACE_DECL) + break; + } else { + if (cur->type != XML_ELEMENT_NODE) + break; + } + switch (cur->type) { + case XML_ELEMENT_NODE: + if (xmlStrEqual(name, cur->name)) { + if (prefix == NULL) { + if (cur->ns == NULL) + { + XP_TEST_HIT + } + } else { + if ((cur->ns != NULL) && + (xmlStrEqual(URI, cur->ns->href))) + { + XP_TEST_HIT + } + } + } + break; + case XML_ATTRIBUTE_NODE:{ + xmlAttrPtr attr = (xmlAttrPtr) cur; + + if (xmlStrEqual(name, attr->name)) { + if (prefix == NULL) { + if ((attr->ns == NULL) || + (attr->ns->prefix == NULL)) + { + XP_TEST_HIT + } + } else { + if ((attr->ns != NULL) && + (xmlStrEqual(URI, + attr->ns->href))) + { + XP_TEST_HIT + } + } + } + break; + } + case XML_NAMESPACE_DECL: + if (cur->type == XML_NAMESPACE_DECL) { + xmlNsPtr ns = (xmlNsPtr) cur; + + if ((ns->prefix != NULL) && (name != NULL) + && (xmlStrEqual(ns->prefix, name))) + { + XP_TEST_HIT_NS + } + } + break; + default: + break; + } + break; + } /* switch(test) */ + } while (cur != NULL); + + goto apply_predicates; + +axis_range_end: /* ----------------------------------------------------- */ + /* + * We have a "/foo[n]", and position() = n was reached. + * Note that we can have as well "/foo/::parent::foo[1]", so + * a duplicate-aware merge is still needed. + * Merge with the result. + */ + if (outSeq == NULL) { + outSeq = seq; + seq = NULL; + } else + outSeq = mergeAndClear(outSeq, seq, 0); + /* + * Break if only a true/false result was requested. + */ + if (toBool) + break; + continue; + +first_hit: /* ---------------------------------------------------------- */ + /* + * Break if only a true/false result was requested and + * no predicates existed and a node test succeeded. + */ + if (outSeq == NULL) { + outSeq = seq; + seq = NULL; + } else + outSeq = mergeAndClear(outSeq, seq, 0); + break; + +#ifdef DEBUG_STEP + if (seq != NULL) + nbMatches += seq->nodeNr; +#endif + +apply_predicates: /* --------------------------------------------------- */ + /* + * Apply predicates. + */ + if ((predOp != NULL) && (seq->nodeNr > 0)) { + /* + * E.g. when we have a "/foo[some expression][n]". + */ + /* + * QUESTION TODO: The old predicate evaluation took into + * account location-sets. + * (E.g. ctxt->value->type == XPATH_LOCATIONSET) + * Do we expect such a set here? + * All what I learned now from the evaluation semantics + * does not indicate that a location-set will be processed + * here, so this looks OK. + */ + /* + * Iterate over all predicates, starting with the outermost + * predicate. + * TODO: Problem: we cannot execute the inner predicates first + * since we cannot go back *up* the operator tree! + * Options we have: + * 1) Use of recursive functions (like is it currently done + * via xmlXPathCompOpEval()) + * 2) Add a predicate evaluation information stack to the + * context struct + * 3) Change the way the operators are linked; we need a + * "parent" field on xmlXPathStepOp + * + * For the moment, I'll try to solve this with a recursive + * function: xmlXPathCompOpEvalPredicate(). + */ + size = seq->nodeNr; + if (hasPredicateRange != 0) + newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt, + predOp, seq, size, maxPos, maxPos, hasNsNodes); + else + newSize = xmlXPathCompOpEvalPredicate(ctxt, + predOp, seq, size, hasNsNodes); + + if (ctxt->error != XPATH_EXPRESSION_OK) { + total = 0; + goto error; + } + /* + * Add the filtered set of nodes to the result node set. + */ + if (newSize == 0) { + /* + * The predicates filtered all nodes out. + */ + xmlXPathNodeSetClear(seq, hasNsNodes); + } else if (seq->nodeNr > 0) { + /* + * Add to result set. + */ + if (outSeq == NULL) { + if (size != newSize) { + /* + * We need to merge and clear here, since + * the sequence will contained NULLed entries. + */ + outSeq = mergeAndClear(NULL, seq, 1); + } else { + outSeq = seq; + seq = NULL; + } + } else + outSeq = mergeAndClear(outSeq, seq, + (size != newSize) ? 1: 0); + /* + * Break if only a true/false result was requested. + */ + if (toBool) + break; + } + } else if (seq->nodeNr > 0) { + /* + * Add to result set. + */ + if (outSeq == NULL) { + outSeq = seq; + seq = NULL; + } else { + outSeq = mergeAndClear(outSeq, seq, 0); + } + } + } + +error: + if ((obj->boolval) && (obj->user != NULL)) { + /* + * QUESTION TODO: What does this do and why? + * TODO: Do we have to do this also for the "error" + * cleanup further down? + */ + ctxt->value->boolval = 1; + ctxt->value->user = obj->user; + obj->user = NULL; + obj->boolval = 0; + } + xmlXPathReleaseObject(xpctxt, obj); + + /* + * Ensure we return at least an emtpy set. + */ + if (outSeq == NULL) { + if ((seq != NULL) && (seq->nodeNr == 0)) + outSeq = seq; + else + outSeq = xmlXPathNodeSetCreate(NULL); + /* XXX what if xmlXPathNodeSetCreate returned NULL here? */ + } + if ((seq != NULL) && (seq != outSeq)) { + xmlXPathFreeNodeSet(seq); + } + /* + * Hand over the result. Better to push the set also in + * case of errors. + */ + valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq)); + /* + * Reset the context node. + */ + xpctxt->node = oldContextNode; + +#ifdef DEBUG_STEP + xmlGenericError(xmlGenericErrorContext, + "\nExamined %d nodes, found %d nodes at that step\n", + total, nbMatches); +#endif + + return(total); +} + +static int +xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt, + xmlXPathStepOpPtr op, xmlNodePtr * first); + +/** + * xmlXPathCompOpEvalFirst: + * @ctxt: the XPath parser context with the compiled expression + * @op: an XPath compiled operation + * @first: the first elem found so far + * + * Evaluate the Precompiled XPath operation searching only the first + * element in document order + * + * Returns the number of examined objects. + */ +static int +xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt, + xmlXPathStepOpPtr op, xmlNodePtr * first) +{ + int total = 0, cur; + xmlXPathCompExprPtr comp; + xmlXPathObjectPtr arg1, arg2; + + CHECK_ERROR0; + comp = ctxt->comp; + switch (op->op) { + case XPATH_OP_END: + return (0); + case XPATH_OP_UNION: + total = + xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1], + first); + CHECK_ERROR0; + if ((ctxt->value != NULL) + && (ctxt->value->type == XPATH_NODESET) + && (ctxt->value->nodesetval != NULL) + && (ctxt->value->nodesetval->nodeNr >= 1)) { + /* + * limit tree traversing to first node in the result + */ + /* + * OPTIMIZE TODO: This implicitely sorts + * the result, even if not needed. E.g. if the argument + * of the count() function, no sorting is needed. + * OPTIMIZE TODO: How do we know if the node-list wasn't + * aready sorted? + */ + if (ctxt->value->nodesetval->nodeNr > 1) + xmlXPathNodeSetSort(ctxt->value->nodesetval); + *first = ctxt->value->nodesetval->nodeTab[0]; + } + cur = + xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2], + first); + CHECK_ERROR0; + CHECK_TYPE0(XPATH_NODESET); + arg2 = valuePop(ctxt); + + CHECK_TYPE0(XPATH_NODESET); + arg1 = valuePop(ctxt); + + arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, + arg2->nodesetval); + valuePush(ctxt, arg1); + xmlXPathReleaseObject(ctxt->context, arg2); + /* optimizer */ + if (total > cur) + xmlXPathCompSwap(op); + return (total + cur); + case XPATH_OP_ROOT: + xmlXPathRoot(ctxt); + return (0); + case XPATH_OP_NODE: + if (op->ch1 != -1) + total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); + CHECK_ERROR0; + if (op->ch2 != -1) + total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); + CHECK_ERROR0; + valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, + ctxt->context->node)); + return (total); + case XPATH_OP_RESET: + if (op->ch1 != -1) + total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); + CHECK_ERROR0; + if (op->ch2 != -1) + total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); + CHECK_ERROR0; + ctxt->context->node = NULL; + return (total); + case XPATH_OP_COLLECT:{ + if (op->ch1 == -1) + return (total); + + total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); + CHECK_ERROR0; + + total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0); + return (total); + } + case XPATH_OP_VALUE: + valuePush(ctxt, + xmlXPathCacheObjectCopy(ctxt->context, + (xmlXPathObjectPtr) op->value4)); + return (0); + case XPATH_OP_SORT: + if (op->ch1 != -1) + total += + xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1], + first); + CHECK_ERROR0; + if ((ctxt->value != NULL) + && (ctxt->value->type == XPATH_NODESET) + && (ctxt->value->nodesetval != NULL) + && (ctxt->value->nodesetval->nodeNr > 1)) + xmlXPathNodeSetSort(ctxt->value->nodesetval); + return (total); +#ifdef XP_OPTIMIZED_FILTER_FIRST + case XPATH_OP_FILTER: + total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first); + return (total); +#endif + default: + return (xmlXPathCompOpEval(ctxt, op)); + } +} + +/** + * xmlXPathCompOpEvalLast: + * @ctxt: the XPath parser context with the compiled expression + * @op: an XPath compiled operation + * @last: the last elem found so far + * + * Evaluate the Precompiled XPath operation searching only the last + * element in document order + * + * Returns the number of nodes traversed + */ +static int +xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op, + xmlNodePtr * last) +{ + int total = 0, cur; + xmlXPathCompExprPtr comp; + xmlXPathObjectPtr arg1, arg2; + xmlNodePtr bak; + xmlDocPtr bakd; + int pp; + int cs; + + CHECK_ERROR0; + comp = ctxt->comp; + switch (op->op) { + case XPATH_OP_END: + return (0); + case XPATH_OP_UNION: + bakd = ctxt->context->doc; + bak = ctxt->context->node; + pp = ctxt->context->proximityPosition; + cs = ctxt->context->contextSize; + total = + xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last); + CHECK_ERROR0; + if ((ctxt->value != NULL) + && (ctxt->value->type == XPATH_NODESET) + && (ctxt->value->nodesetval != NULL) + && (ctxt->value->nodesetval->nodeNr >= 1)) { + /* + * limit tree traversing to first node in the result + */ + if (ctxt->value->nodesetval->nodeNr > 1) + xmlXPathNodeSetSort(ctxt->value->nodesetval); + *last = + ctxt->value->nodesetval->nodeTab[ctxt->value-> + nodesetval->nodeNr - + 1]; + } + ctxt->context->doc = bakd; + ctxt->context->node = bak; + ctxt->context->proximityPosition = pp; + ctxt->context->contextSize = cs; + cur = + xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last); + CHECK_ERROR0; + if ((ctxt->value != NULL) + && (ctxt->value->type == XPATH_NODESET) + && (ctxt->value->nodesetval != NULL) + && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */ + } + CHECK_TYPE0(XPATH_NODESET); + arg2 = valuePop(ctxt); + + CHECK_TYPE0(XPATH_NODESET); + arg1 = valuePop(ctxt); + + arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, + arg2->nodesetval); + valuePush(ctxt, arg1); + xmlXPathReleaseObject(ctxt->context, arg2); + /* optimizer */ + if (total > cur) + xmlXPathCompSwap(op); + return (total + cur); + case XPATH_OP_ROOT: + xmlXPathRoot(ctxt); + return (0); + case XPATH_OP_NODE: + if (op->ch1 != -1) + total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); + CHECK_ERROR0; + if (op->ch2 != -1) + total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); + CHECK_ERROR0; + valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, + ctxt->context->node)); + return (total); + case XPATH_OP_RESET: + if (op->ch1 != -1) + total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); + CHECK_ERROR0; + if (op->ch2 != -1) + total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); + CHECK_ERROR0; + ctxt->context->node = NULL; + return (total); + case XPATH_OP_COLLECT:{ + if (op->ch1 == -1) + return (0); + + total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); + CHECK_ERROR0; + + total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0); + return (total); + } + case XPATH_OP_VALUE: + valuePush(ctxt, + xmlXPathCacheObjectCopy(ctxt->context, + (xmlXPathObjectPtr) op->value4)); + return (0); + case XPATH_OP_SORT: + if (op->ch1 != -1) + total += + xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], + last); + CHECK_ERROR0; + if ((ctxt->value != NULL) + && (ctxt->value->type == XPATH_NODESET) + && (ctxt->value->nodesetval != NULL) + && (ctxt->value->nodesetval->nodeNr > 1)) + xmlXPathNodeSetSort(ctxt->value->nodesetval); + return (total); + default: + return (xmlXPathCompOpEval(ctxt, op)); + } +} + +#ifdef XP_OPTIMIZED_FILTER_FIRST +static int +xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt, + xmlXPathStepOpPtr op, xmlNodePtr * first) +{ + int total = 0; + xmlXPathCompExprPtr comp; + xmlXPathObjectPtr res; + xmlXPathObjectPtr obj; + xmlNodeSetPtr oldset; + xmlNodePtr oldnode; + xmlDocPtr oldDoc; + int i; + + CHECK_ERROR0; + comp = ctxt->comp; + /* + * Optimization for ()[last()] selection i.e. the last elem + */ + if ((op->ch1 != -1) && (op->ch2 != -1) && + (comp->steps[op->ch1].op == XPATH_OP_SORT) && + (comp->steps[op->ch2].op == XPATH_OP_SORT)) { + int f = comp->steps[op->ch2].ch1; + + if ((f != -1) && + (comp->steps[f].op == XPATH_OP_FUNCTION) && + (comp->steps[f].value5 == NULL) && + (comp->steps[f].value == 0) && + (comp->steps[f].value4 != NULL) && + (xmlStrEqual + (comp->steps[f].value4, BAD_CAST "last"))) { + xmlNodePtr last = NULL; + + total += + xmlXPathCompOpEvalLast(ctxt, + &comp->steps[op->ch1], + &last); + CHECK_ERROR0; + /* + * The nodeset should be in document order, + * Keep only the last value + */ + if ((ctxt->value != NULL) && + (ctxt->value->type == XPATH_NODESET) && + (ctxt->value->nodesetval != NULL) && + (ctxt->value->nodesetval->nodeTab != NULL) && + (ctxt->value->nodesetval->nodeNr > 1)) { + ctxt->value->nodesetval->nodeTab[0] = + ctxt->value->nodesetval->nodeTab[ctxt-> + value-> + nodesetval-> + nodeNr - + 1]; + ctxt->value->nodesetval->nodeNr = 1; + *first = *(ctxt->value->nodesetval->nodeTab); + } + return (total); + } + } + + if (op->ch1 != -1) + total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); + CHECK_ERROR0; + if (op->ch2 == -1) + return (total); + if (ctxt->value == NULL) + return (total); + +#ifdef LIBXML_XPTR_ENABLED + oldnode = ctxt->context->node; + /* + * Hum are we filtering the result of an XPointer expression + */ + if (ctxt->value->type == XPATH_LOCATIONSET) { + xmlXPathObjectPtr tmp = NULL; + xmlLocationSetPtr newlocset = NULL; + xmlLocationSetPtr oldlocset; + + /* + * Extract the old locset, and then evaluate the result of the + * expression for all the element in the locset. use it to grow + * up a new locset. + */ + CHECK_TYPE0(XPATH_LOCATIONSET); + obj = valuePop(ctxt); + oldlocset = obj->user; + ctxt->context->node = NULL; + + if ((oldlocset == NULL) || (oldlocset->locNr == 0)) { + ctxt->context->contextSize = 0; + ctxt->context->proximityPosition = 0; + if (op->ch2 != -1) + total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); + res = valuePop(ctxt); + if (res != NULL) { + xmlXPathReleaseObject(ctxt->context, res); + } + valuePush(ctxt, obj); + CHECK_ERROR0; + return (total); + } + newlocset = xmlXPtrLocationSetCreate(NULL); + + for (i = 0; i < oldlocset->locNr; i++) { + /* + * Run the evaluation with a node list made of a + * single item in the nodelocset. + */ + ctxt->context->node = oldlocset->locTab[i]->user; + ctxt->context->contextSize = oldlocset->locNr; + ctxt->context->proximityPosition = i + 1; + if (tmp == NULL) { + tmp = xmlXPathCacheNewNodeSet(ctxt->context, + ctxt->context->node); + } else { + xmlXPathNodeSetAddUnique(tmp->nodesetval, + ctxt->context->node); + } + valuePush(ctxt, tmp); + if (op->ch2 != -1) + total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); + if (ctxt->error != XPATH_EXPRESSION_OK) { + xmlXPathFreeObject(obj); + return(0); + } + /* + * The result of the evaluation need to be tested to + * decided whether the filter succeeded or not + */ + res = valuePop(ctxt); + if (xmlXPathEvaluatePredicateResult(ctxt, res)) { + xmlXPtrLocationSetAdd(newlocset, + xmlXPathCacheObjectCopy(ctxt->context, + oldlocset->locTab[i])); + } + /* + * Cleanup + */ + if (res != NULL) { + xmlXPathReleaseObject(ctxt->context, res); + } + if (ctxt->value == tmp) { + valuePop(ctxt); + xmlXPathNodeSetClear(tmp->nodesetval, 1); + /* + * REVISIT TODO: Don't create a temporary nodeset + * for everly iteration. + */ + /* OLD: xmlXPathFreeObject(res); */ + } else + tmp = NULL; + ctxt->context->node = NULL; + /* + * Only put the first node in the result, then leave. + */ + if (newlocset->locNr > 0) { + *first = (xmlNodePtr) oldlocset->locTab[i]->user; + break; + } + } + if (tmp != NULL) { + xmlXPathReleaseObject(ctxt->context, tmp); + } + /* + * The result is used as the new evaluation locset. + */ + xmlXPathReleaseObject(ctxt->context, obj); + ctxt->context->node = NULL; + ctxt->context->contextSize = -1; + ctxt->context->proximityPosition = -1; + valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset)); + ctxt->context->node = oldnode; + return (total); + } +#endif /* LIBXML_XPTR_ENABLED */ + + /* + * Extract the old set, and then evaluate the result of the + * expression for all the element in the set. use it to grow + * up a new set. + */ + CHECK_TYPE0(XPATH_NODESET); + obj = valuePop(ctxt); + oldset = obj->nodesetval; + + oldnode = ctxt->context->node; + oldDoc = ctxt->context->doc; + ctxt->context->node = NULL; + + if ((oldset == NULL) || (oldset->nodeNr == 0)) { + ctxt->context->contextSize = 0; + ctxt->context->proximityPosition = 0; + /* QUESTION TODO: Why was this code commented out? + if (op->ch2 != -1) + total += + xmlXPathCompOpEval(ctxt, + &comp->steps[op->ch2]); + CHECK_ERROR0; + res = valuePop(ctxt); + if (res != NULL) + xmlXPathFreeObject(res); + */ + valuePush(ctxt, obj); + ctxt->context->node = oldnode; + CHECK_ERROR0; + } else { + xmlNodeSetPtr newset; + xmlXPathObjectPtr tmp = NULL; + /* + * Initialize the new set. + * Also set the xpath document in case things like + * key() evaluation are attempted on the predicate + */ + newset = xmlXPathNodeSetCreate(NULL); + /* XXX what if xmlXPathNodeSetCreate returned NULL? */ + + for (i = 0; i < oldset->nodeNr; i++) { + /* + * Run the evaluation with a node list made of + * a single item in the nodeset. + */ + ctxt->context->node = oldset->nodeTab[i]; + if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) && + (oldset->nodeTab[i]->doc != NULL)) + ctxt->context->doc = oldset->nodeTab[i]->doc; + if (tmp == NULL) { + tmp = xmlXPathCacheNewNodeSet(ctxt->context, + ctxt->context->node); + } else { + xmlXPathNodeSetAddUnique(tmp->nodesetval, + ctxt->context->node); + } + valuePush(ctxt, tmp); + ctxt->context->contextSize = oldset->nodeNr; + ctxt->context->proximityPosition = i + 1; + if (op->ch2 != -1) + total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); + if (ctxt->error != XPATH_EXPRESSION_OK) { + xmlXPathFreeNodeSet(newset); + xmlXPathFreeObject(obj); + return(0); + } + /* + * The result of the evaluation needs to be tested to + * decide whether the filter succeeded or not + */ + res = valuePop(ctxt); + if (xmlXPathEvaluatePredicateResult(ctxt, res)) { + xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]); + } + /* + * Cleanup + */ + if (res != NULL) { + xmlXPathReleaseObject(ctxt->context, res); + } + if (ctxt->value == tmp) { + valuePop(ctxt); + /* + * Don't free the temporary nodeset + * in order to avoid massive recreation inside this + * loop. + */ + xmlXPathNodeSetClear(tmp->nodesetval, 1); + } else + tmp = NULL; + ctxt->context->node = NULL; + /* + * Only put the first node in the result, then leave. + */ + if (newset->nodeNr > 0) { + *first = *(newset->nodeTab); + break; + } + } + if (tmp != NULL) { + xmlXPathReleaseObject(ctxt->context, tmp); + } + /* + * The result is used as the new evaluation set. + */ + xmlXPathReleaseObject(ctxt->context, obj); + ctxt->context->node = NULL; + ctxt->context->contextSize = -1; + ctxt->context->proximityPosition = -1; + /* may want to move this past the '}' later */ + ctxt->context->doc = oldDoc; + valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset)); + } + ctxt->context->node = oldnode; + return(total); +} +#endif /* XP_OPTIMIZED_FILTER_FIRST */ + +/** + * xmlXPathCompOpEval: + * @ctxt: the XPath parser context with the compiled expression + * @op: an XPath compiled operation + * + * Evaluate the Precompiled XPath operation + * Returns the number of nodes traversed + */ +static int +xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) +{ + int total = 0; + int equal, ret; + xmlXPathCompExprPtr comp; + xmlXPathObjectPtr arg1, arg2; + xmlNodePtr bak; + xmlDocPtr bakd; + int pp; + int cs; + + CHECK_ERROR0; + comp = ctxt->comp; + switch (op->op) { + case XPATH_OP_END: + return (0); + case XPATH_OP_AND: + bakd = ctxt->context->doc; + bak = ctxt->context->node; + pp = ctxt->context->proximityPosition; + cs = ctxt->context->contextSize; + total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); + CHECK_ERROR0; + xmlXPathBooleanFunction(ctxt, 1); + if ((ctxt->value == NULL) || (ctxt->value->boolval == 0)) + return (total); + arg2 = valuePop(ctxt); + ctxt->context->doc = bakd; + ctxt->context->node = bak; + ctxt->context->proximityPosition = pp; + ctxt->context->contextSize = cs; + total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); + if (ctxt->error) { + xmlXPathFreeObject(arg2); + return(0); + } + xmlXPathBooleanFunction(ctxt, 1); + arg1 = valuePop(ctxt); + arg1->boolval &= arg2->boolval; + valuePush(ctxt, arg1); + xmlXPathReleaseObject(ctxt->context, arg2); + return (total); + case XPATH_OP_OR: + bakd = ctxt->context->doc; + bak = ctxt->context->node; + pp = ctxt->context->proximityPosition; + cs = ctxt->context->contextSize; + total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); + CHECK_ERROR0; + xmlXPathBooleanFunction(ctxt, 1); + if ((ctxt->value == NULL) || (ctxt->value->boolval == 1)) + return (total); + arg2 = valuePop(ctxt); + ctxt->context->doc = bakd; + ctxt->context->node = bak; + ctxt->context->proximityPosition = pp; + ctxt->context->contextSize = cs; + total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); + if (ctxt->error) { + xmlXPathFreeObject(arg2); + return(0); + } + xmlXPathBooleanFunction(ctxt, 1); + arg1 = valuePop(ctxt); + arg1->boolval |= arg2->boolval; + valuePush(ctxt, arg1); + xmlXPathReleaseObject(ctxt->context, arg2); + return (total); + case XPATH_OP_EQUAL: + bakd = ctxt->context->doc; + bak = ctxt->context->node; + pp = ctxt->context->proximityPosition; + cs = ctxt->context->contextSize; + total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); + CHECK_ERROR0; + ctxt->context->doc = bakd; + ctxt->context->node = bak; + ctxt->context->proximityPosition = pp; + ctxt->context->contextSize = cs; + total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); + CHECK_ERROR0; + if (op->value) + equal = xmlXPathEqualValues(ctxt); + else + equal = xmlXPathNotEqualValues(ctxt); + valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal)); + return (total); + case XPATH_OP_CMP: + bakd = ctxt->context->doc; + bak = ctxt->context->node; + pp = ctxt->context->proximityPosition; + cs = ctxt->context->contextSize; + total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); + CHECK_ERROR0; + ctxt->context->doc = bakd; + ctxt->context->node = bak; + ctxt->context->proximityPosition = pp; + ctxt->context->contextSize = cs; + total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); + CHECK_ERROR0; + ret = xmlXPathCompareValues(ctxt, op->value, op->value2); + valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret)); + return (total); + case XPATH_OP_PLUS: + bakd = ctxt->context->doc; + bak = ctxt->context->node; + pp = ctxt->context->proximityPosition; + cs = ctxt->context->contextSize; + total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); + CHECK_ERROR0; + if (op->ch2 != -1) { + ctxt->context->doc = bakd; + ctxt->context->node = bak; + ctxt->context->proximityPosition = pp; + ctxt->context->contextSize = cs; + total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); + } + CHECK_ERROR0; + if (op->value == 0) + xmlXPathSubValues(ctxt); + else if (op->value == 1) + xmlXPathAddValues(ctxt); + else if (op->value == 2) + xmlXPathValueFlipSign(ctxt); + else if (op->value == 3) { + CAST_TO_NUMBER; + CHECK_TYPE0(XPATH_NUMBER); + } + return (total); + case XPATH_OP_MULT: + bakd = ctxt->context->doc; + bak = ctxt->context->node; + pp = ctxt->context->proximityPosition; + cs = ctxt->context->contextSize; + total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); + CHECK_ERROR0; + ctxt->context->doc = bakd; + ctxt->context->node = bak; + ctxt->context->proximityPosition = pp; + ctxt->context->contextSize = cs; + total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); + CHECK_ERROR0; + if (op->value == 0) + xmlXPathMultValues(ctxt); + else if (op->value == 1) + xmlXPathDivValues(ctxt); + else if (op->value == 2) + xmlXPathModValues(ctxt); + return (total); + case XPATH_OP_UNION: + bakd = ctxt->context->doc; + bak = ctxt->context->node; + pp = ctxt->context->proximityPosition; + cs = ctxt->context->contextSize; + total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); + CHECK_ERROR0; + ctxt->context->doc = bakd; + ctxt->context->node = bak; + ctxt->context->proximityPosition = pp; + ctxt->context->contextSize = cs; + total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); + CHECK_ERROR0; + CHECK_TYPE0(XPATH_NODESET); + arg2 = valuePop(ctxt); + + CHECK_TYPE0(XPATH_NODESET); + arg1 = valuePop(ctxt); + + if ((arg1->nodesetval == NULL) || + ((arg2->nodesetval != NULL) && + (arg2->nodesetval->nodeNr != 0))) + { + arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, + arg2->nodesetval); + } + + valuePush(ctxt, arg1); + xmlXPathReleaseObject(ctxt->context, arg2); + return (total); + case XPATH_OP_ROOT: + xmlXPathRoot(ctxt); + return (total); + case XPATH_OP_NODE: + if (op->ch1 != -1) + total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); + CHECK_ERROR0; + if (op->ch2 != -1) + total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); + CHECK_ERROR0; + valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context, + ctxt->context->node)); + return (total); + case XPATH_OP_RESET: + if (op->ch1 != -1) + total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); + CHECK_ERROR0; + if (op->ch2 != -1) + total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); + CHECK_ERROR0; + ctxt->context->node = NULL; + return (total); + case XPATH_OP_COLLECT:{ + if (op->ch1 == -1) + return (total); + + total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); + CHECK_ERROR0; + + total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0); + return (total); + } + case XPATH_OP_VALUE: + valuePush(ctxt, + xmlXPathCacheObjectCopy(ctxt->context, + (xmlXPathObjectPtr) op->value4)); + return (total); + case XPATH_OP_VARIABLE:{ + xmlXPathObjectPtr val; + + if (op->ch1 != -1) + total += + xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); + if (op->value5 == NULL) { + val = xmlXPathVariableLookup(ctxt->context, op->value4); + if (val == NULL) { + ctxt->error = XPATH_UNDEF_VARIABLE_ERROR; + return(0); + } + valuePush(ctxt, val); + } else { + const xmlChar *URI; + + 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; + return (total); + } + val = xmlXPathVariableLookupNS(ctxt->context, + op->value4, URI); + if (val == NULL) { + ctxt->error = XPATH_UNDEF_VARIABLE_ERROR; + return(0); + } + valuePush(ctxt, val); + } + return (total); + } + case XPATH_OP_FUNCTION:{ + xmlXPathFunction func; + const xmlChar *oldFunc, *oldFuncURI; + int i; + int frame; + + frame = xmlXPathSetFrame(ctxt); + if (op->ch1 != -1) + total += + xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); + if (ctxt->valueNr < op->value) { + xmlGenericError(xmlGenericErrorContext, + "xmlXPathCompOpEval: parameter error\n"); + ctxt->error = XPATH_INVALID_OPERAND; + xmlXPathPopFrame(ctxt, frame); + return (total); + } + 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; + xmlXPathPopFrame(ctxt, frame); + return (total); + } + } + if (op->cache != NULL) + XML_CAST_FPTR(func) = op->cache; + else { + const xmlChar *URI = NULL; + + if (op->value5 == NULL) + func = + xmlXPathFunctionLookup(ctxt->context, + 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); + xmlXPathPopFrame(ctxt, frame); + ctxt->error = XPATH_UNDEF_PREFIX_ERROR; + return (total); + } + func = xmlXPathFunctionLookupNS(ctxt->context, + op->value4, URI); + } + if (func == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlXPathCompOpEval: function %s not found\n", + (char *)op->value4); + XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR); + } + op->cache = XML_CAST_FPTR(func); + op->cacheURI = (void *) URI; + } + oldFunc = ctxt->context->function; + oldFuncURI = ctxt->context->functionURI; + ctxt->context->function = op->value4; + ctxt->context->functionURI = op->cacheURI; + func(ctxt, op->value); + ctxt->context->function = oldFunc; + ctxt->context->functionURI = oldFuncURI; + xmlXPathPopFrame(ctxt, frame); + return (total); + } + case XPATH_OP_ARG: + bakd = ctxt->context->doc; + bak = ctxt->context->node; + pp = ctxt->context->proximityPosition; + cs = ctxt->context->contextSize; + if (op->ch1 != -1) + total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); + ctxt->context->contextSize = cs; + ctxt->context->proximityPosition = pp; + ctxt->context->node = bak; + ctxt->context->doc = bakd; + CHECK_ERROR0; + if (op->ch2 != -1) { + total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); + ctxt->context->doc = bakd; + ctxt->context->node = bak; + CHECK_ERROR0; + } + return (total); + case XPATH_OP_PREDICATE: + case XPATH_OP_FILTER:{ + xmlXPathObjectPtr res; + xmlXPathObjectPtr obj, tmp; + xmlNodeSetPtr newset = NULL; + xmlNodeSetPtr oldset; + xmlNodePtr oldnode; + xmlDocPtr oldDoc; + int i; + + /* + * Optimization for ()[1] selection i.e. the first elem + */ + if ((op->ch1 != -1) && (op->ch2 != -1) && +#ifdef XP_OPTIMIZED_FILTER_FIRST + /* + * FILTER TODO: Can we assume that the inner processing + * will result in an ordered list if we have an + * XPATH_OP_FILTER? + * What about an additional field or flag on + * xmlXPathObject like @sorted ? This way we wouln'd need + * to assume anything, so it would be more robust and + * easier to optimize. + */ + ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */ + (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */ +#else + (comp->steps[op->ch1].op == XPATH_OP_SORT) && +#endif + (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */ + xmlXPathObjectPtr val; + + val = comp->steps[op->ch2].value4; + if ((val != NULL) && (val->type == XPATH_NUMBER) && + (val->floatval == 1.0)) { + xmlNodePtr first = NULL; + + total += + xmlXPathCompOpEvalFirst(ctxt, + &comp->steps[op->ch1], + &first); + CHECK_ERROR0; + /* + * The nodeset should be in document order, + * Keep only the first value + */ + if ((ctxt->value != NULL) && + (ctxt->value->type == XPATH_NODESET) && + (ctxt->value->nodesetval != NULL) && + (ctxt->value->nodesetval->nodeNr > 1)) + ctxt->value->nodesetval->nodeNr = 1; + return (total); + } + } + /* + * Optimization for ()[last()] selection i.e. the last elem + */ + if ((op->ch1 != -1) && (op->ch2 != -1) && + (comp->steps[op->ch1].op == XPATH_OP_SORT) && + (comp->steps[op->ch2].op == XPATH_OP_SORT)) { + int f = comp->steps[op->ch2].ch1; + + if ((f != -1) && + (comp->steps[f].op == XPATH_OP_FUNCTION) && + (comp->steps[f].value5 == NULL) && + (comp->steps[f].value == 0) && + (comp->steps[f].value4 != NULL) && + (xmlStrEqual + (comp->steps[f].value4, BAD_CAST "last"))) { + xmlNodePtr last = NULL; + + total += + xmlXPathCompOpEvalLast(ctxt, + &comp->steps[op->ch1], + &last); + CHECK_ERROR0; + /* + * The nodeset should be in document order, + * Keep only the last value + */ + if ((ctxt->value != NULL) && + (ctxt->value->type == XPATH_NODESET) && + (ctxt->value->nodesetval != NULL) && + (ctxt->value->nodesetval->nodeTab != NULL) && + (ctxt->value->nodesetval->nodeNr > 1)) { + ctxt->value->nodesetval->nodeTab[0] = + ctxt->value->nodesetval->nodeTab[ctxt-> + value-> + nodesetval-> + nodeNr - + 1]; + ctxt->value->nodesetval->nodeNr = 1; + } + return (total); + } + } + /* + * Process inner predicates first. + * Example "index[parent::book][1]": + * ... + * PREDICATE <-- we are here "[1]" + * PREDICATE <-- process "[parent::book]" first + * SORT + * COLLECT 'parent' 'name' 'node' book + * NODE + * ELEM Object is a number : 1 + */ + if (op->ch1 != -1) + total += + xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); + CHECK_ERROR0; + if (op->ch2 == -1) + return (total); + if (ctxt->value == NULL) + return (total); + + oldnode = ctxt->context->node; + +#ifdef LIBXML_XPTR_ENABLED + /* + * Hum are we filtering the result of an XPointer expression + */ + if (ctxt->value->type == XPATH_LOCATIONSET) { + xmlLocationSetPtr newlocset = NULL; + xmlLocationSetPtr oldlocset; + + /* + * Extract the old locset, and then evaluate the result of the + * expression for all the element in the locset. use it to grow + * up a new locset. + */ + CHECK_TYPE0(XPATH_LOCATIONSET); + obj = valuePop(ctxt); + oldlocset = obj->user; + ctxt->context->node = NULL; + + if ((oldlocset == NULL) || (oldlocset->locNr == 0)) { + ctxt->context->contextSize = 0; + ctxt->context->proximityPosition = 0; + if (op->ch2 != -1) + total += + xmlXPathCompOpEval(ctxt, + &comp->steps[op->ch2]); + res = valuePop(ctxt); + if (res != NULL) { + xmlXPathReleaseObject(ctxt->context, res); + } + valuePush(ctxt, obj); + CHECK_ERROR0; + return (total); + } + newlocset = xmlXPtrLocationSetCreate(NULL); + + for (i = 0; i < oldlocset->locNr; i++) { + /* + * Run the evaluation with a node list made of a + * single item in the nodelocset. + */ + ctxt->context->node = oldlocset->locTab[i]->user; + ctxt->context->contextSize = oldlocset->locNr; + ctxt->context->proximityPosition = i + 1; + tmp = xmlXPathCacheNewNodeSet(ctxt->context, + ctxt->context->node); + valuePush(ctxt, tmp); + + if (op->ch2 != -1) + total += + xmlXPathCompOpEval(ctxt, + &comp->steps[op->ch2]); + if (ctxt->error != XPATH_EXPRESSION_OK) { + xmlXPathFreeObject(obj); + return(0); + } + + /* + * The result of the evaluation need to be tested to + * decided whether the filter succeeded or not + */ + res = valuePop(ctxt); + if (xmlXPathEvaluatePredicateResult(ctxt, res)) { + xmlXPtrLocationSetAdd(newlocset, + xmlXPathObjectCopy + (oldlocset->locTab[i])); + } + + /* + * Cleanup + */ + if (res != NULL) { + xmlXPathReleaseObject(ctxt->context, res); + } + if (ctxt->value == tmp) { + res = valuePop(ctxt); + xmlXPathReleaseObject(ctxt->context, res); + } + + ctxt->context->node = NULL; + } + + /* + * The result is used as the new evaluation locset. + */ + xmlXPathReleaseObject(ctxt->context, obj); + ctxt->context->node = NULL; + ctxt->context->contextSize = -1; + ctxt->context->proximityPosition = -1; + valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset)); + ctxt->context->node = oldnode; + return (total); + } +#endif /* LIBXML_XPTR_ENABLED */ + + /* + * Extract the old set, and then evaluate the result of the + * expression for all the element in the set. use it to grow + * up a new set. + */ + CHECK_TYPE0(XPATH_NODESET); + obj = valuePop(ctxt); + oldset = obj->nodesetval; + + oldnode = ctxt->context->node; + oldDoc = ctxt->context->doc; + ctxt->context->node = NULL; + + if ((oldset == NULL) || (oldset->nodeNr == 0)) { + ctxt->context->contextSize = 0; + ctxt->context->proximityPosition = 0; +/* + if (op->ch2 != -1) + total += + xmlXPathCompOpEval(ctxt, + &comp->steps[op->ch2]); + CHECK_ERROR0; + res = valuePop(ctxt); + if (res != NULL) + xmlXPathFreeObject(res); +*/ + valuePush(ctxt, obj); + ctxt->context->node = oldnode; + CHECK_ERROR0; + } else { + tmp = NULL; + /* + * Initialize the new set. + * Also set the xpath document in case things like + * key() evaluation are attempted on the predicate + */ + newset = xmlXPathNodeSetCreate(NULL); + /* + * SPEC XPath 1.0: + * "For each node in the node-set to be filtered, the + * PredicateExpr is evaluated with that node as the + * context node, with the number of nodes in the + * node-set as the context size, and with the proximity + * position of the node in the node-set with respect to + * the axis as the context position;" + * @oldset is the node-set" to be filtered. + * + * SPEC XPath 1.0: + * "only predicates change the context position and + * context size (see [2.4 Predicates])." + * Example: + * node-set context pos + * nA 1 + * nB 2 + * nC 3 + * After applying predicate [position() > 1] : + * node-set context pos + * nB 1 + * nC 2 + * + * removed the first node in the node-set, then + * the context position of the + */ + for (i = 0; i < oldset->nodeNr; i++) { + /* + * Run the evaluation with a node list made of + * a single item in the nodeset. + */ + ctxt->context->node = oldset->nodeTab[i]; + if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) && + (oldset->nodeTab[i]->doc != NULL)) + ctxt->context->doc = oldset->nodeTab[i]->doc; + if (tmp == NULL) { + tmp = xmlXPathCacheNewNodeSet(ctxt->context, + ctxt->context->node); + } else { + xmlXPathNodeSetAddUnique(tmp->nodesetval, + ctxt->context->node); + } + valuePush(ctxt, tmp); + ctxt->context->contextSize = oldset->nodeNr; + ctxt->context->proximityPosition = i + 1; + /* + * Evaluate the predicate against the context node. + * Can/should we optimize position() predicates + * here (e.g. "[1]")? + */ + if (op->ch2 != -1) + total += + xmlXPathCompOpEval(ctxt, + &comp->steps[op->ch2]); + if (ctxt->error != XPATH_EXPRESSION_OK) { + xmlXPathFreeNodeSet(newset); + xmlXPathFreeObject(obj); + return(0); + } + + /* + * The result of the evaluation needs to be tested to + * decide whether the filter succeeded or not + */ + /* + * OPTIMIZE TODO: Can we use + * xmlXPathNodeSetAdd*Unique()* instead? + */ + res = valuePop(ctxt); + if (xmlXPathEvaluatePredicateResult(ctxt, res)) { + xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]); + } + + /* + * Cleanup + */ + if (res != NULL) { + xmlXPathReleaseObject(ctxt->context, res); + } + if (ctxt->value == tmp) { + valuePop(ctxt); + xmlXPathNodeSetClear(tmp->nodesetval, 1); + /* + * Don't free the temporary nodeset + * in order to avoid massive recreation inside this + * loop. + */ + } else + tmp = NULL; + ctxt->context->node = NULL; + } + if (tmp != NULL) + xmlXPathReleaseObject(ctxt->context, tmp); + /* + * The result is used as the new evaluation set. + */ + xmlXPathReleaseObject(ctxt->context, obj); + ctxt->context->node = NULL; + ctxt->context->contextSize = -1; + ctxt->context->proximityPosition = -1; + /* may want to move this past the '}' later */ + ctxt->context->doc = oldDoc; + valuePush(ctxt, + xmlXPathCacheWrapNodeSet(ctxt->context, newset)); + } + ctxt->context->node = oldnode; + return (total); + } + case XPATH_OP_SORT: + if (op->ch1 != -1) + total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); + CHECK_ERROR0; + if ((ctxt->value != NULL) && + (ctxt->value->type == XPATH_NODESET) && + (ctxt->value->nodesetval != NULL) && + (ctxt->value->nodesetval->nodeNr > 1)) + { + xmlXPathNodeSetSort(ctxt->value->nodesetval); + } + return (total); +#ifdef LIBXML_XPTR_ENABLED + case XPATH_OP_RANGETO:{ + xmlXPathObjectPtr range; + xmlXPathObjectPtr res, obj; + xmlXPathObjectPtr tmp; + xmlLocationSetPtr newlocset = NULL; + xmlLocationSetPtr oldlocset; + xmlNodeSetPtr oldset; + int i, j; + + if (op->ch1 != -1) + total += + xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); + if (op->ch2 == -1) + return (total); + + if (ctxt->value->type == XPATH_LOCATIONSET) { + /* + * Extract the old locset, and then evaluate the result of the + * expression for all the element in the locset. use it to grow + * up a new locset. + */ + CHECK_TYPE0(XPATH_LOCATIONSET); + obj = valuePop(ctxt); + oldlocset = obj->user; + + if ((oldlocset == NULL) || (oldlocset->locNr == 0)) { + ctxt->context->node = NULL; + ctxt->context->contextSize = 0; + ctxt->context->proximityPosition = 0; + total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]); + res = valuePop(ctxt); + if (res != NULL) { + xmlXPathReleaseObject(ctxt->context, res); + } + valuePush(ctxt, obj); + CHECK_ERROR0; + return (total); + } + newlocset = xmlXPtrLocationSetCreate(NULL); + + for (i = 0; i < oldlocset->locNr; i++) { + /* + * Run the evaluation with a node list made of a + * single item in the nodelocset. + */ + ctxt->context->node = oldlocset->locTab[i]->user; + ctxt->context->contextSize = oldlocset->locNr; + ctxt->context->proximityPosition = i + 1; + tmp = xmlXPathCacheNewNodeSet(ctxt->context, + ctxt->context->node); + valuePush(ctxt, tmp); + + if (op->ch2 != -1) + total += + xmlXPathCompOpEval(ctxt, + &comp->steps[op->ch2]); + if (ctxt->error != XPATH_EXPRESSION_OK) { + xmlXPathFreeObject(obj); + return(0); + } + + res = valuePop(ctxt); + if (res->type == XPATH_LOCATIONSET) { + xmlLocationSetPtr rloc = + (xmlLocationSetPtr)res->user; + for (j=0; jlocNr; j++) { + range = xmlXPtrNewRange( + oldlocset->locTab[i]->user, + oldlocset->locTab[i]->index, + rloc->locTab[j]->user2, + rloc->locTab[j]->index2); + if (range != NULL) { + xmlXPtrLocationSetAdd(newlocset, range); + } + } + } else { + range = xmlXPtrNewRangeNodeObject( + (xmlNodePtr)oldlocset->locTab[i]->user, res); + if (range != NULL) { + xmlXPtrLocationSetAdd(newlocset,range); + } + } + + /* + * Cleanup + */ + if (res != NULL) { + xmlXPathReleaseObject(ctxt->context, res); + } + if (ctxt->value == tmp) { + res = valuePop(ctxt); + xmlXPathReleaseObject(ctxt->context, res); + } + + ctxt->context->node = NULL; + } + } else { /* Not a location set */ + CHECK_TYPE0(XPATH_NODESET); + obj = valuePop(ctxt); + oldset = obj->nodesetval; + ctxt->context->node = NULL; + + newlocset = xmlXPtrLocationSetCreate(NULL); + + if (oldset != NULL) { + for (i = 0; i < oldset->nodeNr; i++) { + /* + * Run the evaluation with a node list made of a single item + * in the nodeset. + */ + ctxt->context->node = oldset->nodeTab[i]; + /* + * OPTIMIZE TODO: Avoid recreation for every iteration. + */ + tmp = xmlXPathCacheNewNodeSet(ctxt->context, + ctxt->context->node); + valuePush(ctxt, tmp); + + if (op->ch2 != -1) + total += + xmlXPathCompOpEval(ctxt, + &comp->steps[op->ch2]); + if (ctxt->error != XPATH_EXPRESSION_OK) { + xmlXPathFreeObject(obj); + return(0); + } + + res = valuePop(ctxt); + range = + xmlXPtrNewRangeNodeObject(oldset->nodeTab[i], + res); + if (range != NULL) { + xmlXPtrLocationSetAdd(newlocset, range); + } + + /* + * Cleanup + */ + if (res != NULL) { + xmlXPathReleaseObject(ctxt->context, res); + } + if (ctxt->value == tmp) { + res = valuePop(ctxt); + xmlXPathReleaseObject(ctxt->context, res); + } + + ctxt->context->node = NULL; + } + } + } + + /* + * The result is used as the new evaluation set. + */ + xmlXPathReleaseObject(ctxt->context, obj); + ctxt->context->node = NULL; + ctxt->context->contextSize = -1; + ctxt->context->proximityPosition = -1; + valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset)); + return (total); + } +#endif /* LIBXML_XPTR_ENABLED */ + } + xmlGenericError(xmlGenericErrorContext, + "XPath: unknown precompiled operation %d\n", op->op); + ctxt->error = XPATH_INVALID_OPERAND; + return (total); +} + +/** + * xmlXPathCompOpEvalToBoolean: + * @ctxt: the XPath parser context + * + * Evaluates if the expression evaluates to true. + * + * Returns 1 if true, 0 if false and -1 on API or internal errors. + */ +static int +xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt, + xmlXPathStepOpPtr op, + int isPredicate) +{ + xmlXPathObjectPtr resObj = NULL; + +start: + /* comp = ctxt->comp; */ + switch (op->op) { + case XPATH_OP_END: + return (0); + case XPATH_OP_VALUE: + resObj = (xmlXPathObjectPtr) op->value4; + if (isPredicate) + return(xmlXPathEvaluatePredicateResult(ctxt, resObj)); + return(xmlXPathCastToBoolean(resObj)); + case XPATH_OP_SORT: + /* + * We don't need sorting for boolean results. Skip this one. + */ + if (op->ch1 != -1) { + op = &ctxt->comp->steps[op->ch1]; + goto start; + } + return(0); + case XPATH_OP_COLLECT: + if (op->ch1 == -1) + return(0); + + xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]); + if (ctxt->error != XPATH_EXPRESSION_OK) + return(-1); + + xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1); + if (ctxt->error != XPATH_EXPRESSION_OK) + return(-1); + + resObj = valuePop(ctxt); + if (resObj == NULL) + return(-1); + break; + default: + /* + * Fallback to call xmlXPathCompOpEval(). + */ + xmlXPathCompOpEval(ctxt, op); + if (ctxt->error != XPATH_EXPRESSION_OK) + return(-1); + + resObj = valuePop(ctxt); + if (resObj == NULL) + return(-1); + break; + } + + if (resObj) { + int res; + + if (resObj->type == XPATH_BOOLEAN) { + res = resObj->boolval; + } else if (isPredicate) { + /* + * For predicates a result of type "number" is handled + * differently: + * SPEC XPath 1.0: + * "If the result is a number, the result will be converted + * to true if the number is equal to the context position + * and will be converted to false otherwise;" + */ + res = xmlXPathEvaluatePredicateResult(ctxt, resObj); + } else { + res = xmlXPathCastToBoolean(resObj); + } + xmlXPathReleaseObject(ctxt->context, resObj); + return(res); + } + + return(0); +} + +#ifdef XPATH_STREAMING +/** + * xmlXPathRunStreamEval: + * @ctxt: 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, + xmlXPathObjectPtr *resultSeq, int toBool) +{ + int max_depth, min_depth; + int from_root; + int ret, depth; + int eval_all_nodes; + xmlNodePtr cur = NULL, limit = NULL; + xmlStreamCtxtPtr patstream = NULL; + + int nb_nodes = 0; + + if ((ctxt == NULL) || (comp == NULL)) + return(-1); + max_depth = xmlPatternMaxDepth(comp); + if (max_depth == -1) + return(-1); + if (max_depth == -2) + max_depth = 10000; + min_depth = xmlPatternMinDepth(comp); + if (min_depth == -1) + return(-1); + from_root = xmlPatternFromRoot(comp); + if (from_root < 0) + return(-1); +#if 0 + printf("stream eval: depth %d from root %d\n", max_depth, from_root); +#endif + + if (! toBool) { + if (resultSeq == NULL) + return(-1); + *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL); + if (*resultSeq == NULL) + return(-1); + } + + /* + * handle the special cases of "/" amd "." being matched + */ + if (min_depth == 0) { + if (from_root) { + /* Select "/" */ + if (toBool) + return(1); + xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, + (xmlNodePtr) ctxt->doc); + } else { + /* Select "self::node()" */ + if (toBool) + return(1); + xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node); + } + } + if (max_depth == 0) { + return(0); + } + + if (from_root) { + cur = (xmlNodePtr)ctxt->doc; + } else if (ctxt->node != NULL) { + switch (ctxt->node->type) { + case XML_ELEMENT_NODE: + case XML_DOCUMENT_NODE: + case XML_DOCUMENT_FRAG_NODE: + case XML_HTML_DOCUMENT_NODE: +#ifdef LIBXML_DOCB_ENABLED + case XML_DOCB_DOCUMENT_NODE: +#endif + cur = ctxt->node; + break; + case XML_ATTRIBUTE_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_NOTATION_NODE: + case XML_DTD_NODE: + case XML_DOCUMENT_TYPE_NODE: + case XML_ELEMENT_DECL: + case XML_ATTRIBUTE_DECL: + case XML_ENTITY_DECL: + case XML_NAMESPACE_DECL: + case XML_XINCLUDE_START: + case XML_XINCLUDE_END: + break; + } + limit = cur; + } + if (cur == NULL) { + return(0); + } + + patstream = xmlPatternGetStreamCtxt(comp); + if (patstream == NULL) { + /* + * QUESTION TODO: Is this an error? + */ + return(0); + } + + eval_all_nodes = xmlStreamWantsAnyNode(patstream); + + if (from_root) { + ret = xmlStreamPush(patstream, NULL, NULL); + if (ret < 0) { + } else if (ret == 1) { + if (toBool) + goto return_1; + xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur); + } + } + depth = 0; + goto scan_children; +next_node: + do { + nb_nodes++; + + switch (cur->type) { + case XML_ELEMENT_NODE: + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: + case XML_COMMENT_NODE: + case XML_PI_NODE: + if (cur->type == XML_ELEMENT_NODE) { + ret = xmlStreamPush(patstream, cur->name, + (cur->ns ? cur->ns->href : NULL)); + } else if (eval_all_nodes) + ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type); + else + break; + + if (ret < 0) { + /* NOP. */ + } else if (ret == 1) { + if (toBool) + goto return_1; + xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur); + } + if ((cur->children == NULL) || (depth >= max_depth)) { + ret = xmlStreamPop(patstream); + while (cur->next != NULL) { + cur = cur->next; + if ((cur->type != XML_ENTITY_DECL) && + (cur->type != XML_DTD_NODE)) + goto next_node; + } + } + default: + break; + } + +scan_children: + if ((cur->children != NULL) && (depth < max_depth)) { + /* + * Do not descend on entities declarations + */ + if (cur->children->type != XML_ENTITY_DECL) { + cur = cur->children; + depth++; + /* + * Skip DTDs + */ + if (cur->type != XML_DTD_NODE) + continue; + } + } + + if (cur == limit) + break; + + while (cur->next != NULL) { + cur = cur->next; + if ((cur->type != XML_ENTITY_DECL) && + (cur->type != XML_DTD_NODE)) + goto next_node; + } + + do { + cur = cur->parent; + depth--; + if ((cur == NULL) || (cur == limit)) + goto done; + if (cur->type == XML_ELEMENT_NODE) { + ret = xmlStreamPop(patstream); + } else if ((eval_all_nodes) && + ((cur->type == XML_TEXT_NODE) || + (cur->type == XML_CDATA_SECTION_NODE) || + (cur->type == XML_COMMENT_NODE) || + (cur->type == XML_PI_NODE))) + { + ret = xmlStreamPop(patstream); + } + if (cur->next != NULL) { + cur = cur->next; + break; + } + } while (cur != NULL); + + } while ((cur != NULL) && (depth >= 0)); + +done: + +#if 0 + printf("stream eval: checked %d nodes selected %d\n", + nb_nodes, retObj->nodesetval->nodeNr); +#endif + + if (patstream) + xmlFreeStreamCtxt(patstream); + return(0); + +return_1: + if (patstream) + xmlFreeStreamCtxt(patstream); + return(1); +} +#endif /* XPATH_STREAMING */ + +/** + * xmlXPathRunEval: + * @ctxt: the XPath parser context with the compiled expression + * @toBool: evaluate to a boolean result + * + * Evaluate the Precompiled XPath expression in the given context. + */ +static int +xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool) +{ + xmlXPathCompExprPtr comp; + + if ((ctxt == NULL) || (ctxt->comp == NULL)) + return(-1); + + if (ctxt->valueTab == NULL) { + /* Allocate the value stack */ + ctxt->valueTab = (xmlXPathObjectPtr *) + xmlMalloc(10 * sizeof(xmlXPathObjectPtr)); + if (ctxt->valueTab == NULL) { + xmlXPathPErrMemory(ctxt, "creating evaluation context\n"); + xmlFree(ctxt); + } + ctxt->valueNr = 0; + ctxt->valueMax = 10; + ctxt->value = NULL; + ctxt->valueFrame = 0; + } +#ifdef XPATH_STREAMING + if (ctxt->comp->stream) { + int res; + + if (toBool) { + /* + * Evaluation to boolean result. + */ + res = xmlXPathRunStreamEval(ctxt->context, + ctxt->comp->stream, NULL, 1); + if (res != -1) + return(res); + } else { + xmlXPathObjectPtr resObj = NULL; + + /* + * Evaluation to a sequence. + */ + res = xmlXPathRunStreamEval(ctxt->context, + ctxt->comp->stream, &resObj, 0); + + if ((res != -1) && (resObj != NULL)) { + valuePush(ctxt, resObj); + return(0); + } + if (resObj != NULL) + xmlXPathReleaseObject(ctxt->context, resObj); + } + /* + * QUESTION TODO: This falls back to normal XPath evaluation + * if res == -1. Is this intended? + */ + } +#endif + comp = ctxt->comp; + if (comp->last < 0) { + xmlGenericError(xmlGenericErrorContext, + "xmlXPathRunEval: last is less than zero\n"); + return(-1); + } + if (toBool) + return(xmlXPathCompOpEvalToBoolean(ctxt, + &comp->steps[comp->last], 0)); + else + xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]); + + return(0); +} + +/************************************************************************ + * * + * Public interfaces * + * * + ************************************************************************/ + +/** + * xmlXPathEvalPredicate: + * @ctxt: the XPath context + * @res: the Predicate Expression evaluation result + * + * Evaluate a predicate result for the current node. + * A PredicateExpr is evaluated by evaluating the Expr and converting + * the result to a boolean. If the result is a number, the result will + * be converted to true if the number is equal to the position of the + * context node in the context node list (as returned by the position + * function) and will be converted to false otherwise; if the result + * is not a number, then the result will be converted as if by a call + * to the boolean function. + * + * Returns 1 if predicate is true, 0 otherwise + */ +int +xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) { + if ((ctxt == NULL) || (res == NULL)) return(0); + switch (res->type) { + case XPATH_BOOLEAN: + return(res->boolval); + case XPATH_NUMBER: + return(res->floatval == ctxt->proximityPosition); + case XPATH_NODESET: + case XPATH_XSLT_TREE: + if (res->nodesetval == NULL) + return(0); + return(res->nodesetval->nodeNr != 0); + case XPATH_STRING: + return((res->stringval != NULL) && + (xmlStrlen(res->stringval) != 0)); + default: + STRANGE + } + return(0); +} + +/** + * xmlXPathEvaluatePredicateResult: + * @ctxt: the XPath Parser context + * @res: the Predicate Expression evaluation result + * + * Evaluate a predicate result for the current node. + * A PredicateExpr is evaluated by evaluating the Expr and converting + * the result to a boolean. If the result is a number, the result will + * be converted to true if the number is equal to the position of the + * context node in the context node list (as returned by the position + * function) and will be converted to false otherwise; if the result + * is not a number, then the result will be converted as if by a call + * to the boolean function. + * + * Returns 1 if predicate is true, 0 otherwise + */ +int +xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt, + xmlXPathObjectPtr res) { + if ((ctxt == NULL) || (res == NULL)) return(0); + switch (res->type) { + case XPATH_BOOLEAN: + return(res->boolval); + case XPATH_NUMBER: +#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200)) + return((res->floatval == ctxt->context->proximityPosition) && + (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/ +#else + return(res->floatval == ctxt->context->proximityPosition); +#endif + case XPATH_NODESET: + case XPATH_XSLT_TREE: + if (res->nodesetval == NULL) + return(0); + return(res->nodesetval->nodeNr != 0); + case XPATH_STRING: + return((res->stringval != NULL) && (res->stringval[0] != 0)); +#ifdef LIBXML_XPTR_ENABLED + case XPATH_LOCATIONSET:{ + xmlLocationSetPtr ptr = res->user; + if (ptr == NULL) + return(0); + return (ptr->locNr != 0); + } +#endif + default: + STRANGE + } + return(0); +} + +#ifdef XPATH_STREAMING +/** + * xmlXPathTryStreamCompile: + * @ctxt: an XPath context + * @str: the XPath expression + * + * Try to compile the XPath expression as a streamable subset. + * + * Returns the compiled expression or NULL if failed to compile. + */ +static xmlXPathCompExprPtr +xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) { + /* + * Optimization: use streaming patterns when the XPath expression can + * be compiled to a stream lookup + */ + xmlPatternPtr stream; + xmlXPathCompExprPtr comp; + xmlDictPtr dict = NULL; + const xmlChar **namespaces = NULL; + xmlNsPtr ns; + int i, j; + + if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) && + (!xmlStrchr(str, '@'))) { + const xmlChar *tmp; + + /* + * We don't try to handle expressions using the verbose axis + * specifiers ("::"), just the simplied form at this point. + * Additionally, if there is no list of namespaces available and + * there's a ":" in the expression, indicating a prefixed QName, + * then we won't try to compile either. xmlPatterncompile() needs + * to have a list of namespaces at compilation time in order to + * compile prefixed name tests. + */ + tmp = xmlStrchr(str, ':'); + if ((tmp != NULL) && + ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':'))) + return(NULL); + + if (ctxt != NULL) { + dict = ctxt->dict; + if (ctxt->nsNr > 0) { + namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*)); + if (namespaces == NULL) { + xmlXPathErrMemory(ctxt, "allocating namespaces array\n"); + return(NULL); + } + for (i = 0, j = 0; (j < ctxt->nsNr); j++) { + ns = ctxt->namespaces[j]; + namespaces[i++] = ns->href; + namespaces[i++] = ns->prefix; + } + namespaces[i++] = NULL; + namespaces[i] = NULL; + } + } + + stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, + &namespaces[0]); + if (namespaces != NULL) { + xmlFree((xmlChar **)namespaces); + } + if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) { + comp = xmlXPathNewCompExpr(); + if (comp == NULL) { + xmlXPathErrMemory(ctxt, "allocating streamable expression\n"); + return(NULL); + } + comp->stream = stream; + comp->dict = dict; + if (comp->dict) + xmlDictReference(comp->dict); + return(comp); + } + xmlFreePattern(stream); + } + return(NULL); +} +#endif /* XPATH_STREAMING */ + +static int +xmlXPathCanRewriteDosExpression(xmlChar *expr) +{ + if (expr == NULL) + return(0); + do { + if ((*expr == '/') && (*(++expr) == '/')) + return(1); + } while (*expr++); + return(0); +} +static void +xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op) +{ + /* + * Try to rewrite "descendant-or-self::node()/foo" to an optimized + * internal representation. + */ + if (op->ch1 != -1) { + if ((op->op == XPATH_OP_COLLECT /* 11 */) && + ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) && + ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) && + ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */)) + { + /* + * This is a "child::foo" + */ + xmlXPathStepOpPtr prevop = &comp->steps[op->ch1]; + + if ((prevop->op == XPATH_OP_COLLECT /* 11 */) && + (prevop->ch1 != -1) && + ((xmlXPathAxisVal) prevop->value == + AXIS_DESCENDANT_OR_SELF) && + (prevop->ch2 == -1) && + ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) && + ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) && + (comp->steps[prevop->ch1].op == XPATH_OP_ROOT)) + { + /* + * This is a "/descendant-or-self::node()" without predicates. + * Eliminate it. + */ + op->ch1 = prevop->ch1; + op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM; + } + } + if (op->ch1 != -1) + xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]); + } + if (op->ch2 != -1) + xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]); +} + +/** + * xmlXPathCtxtCompile: + * @ctxt: an XPath context + * @str: the XPath expression + * + * Compile an XPath expression + * + * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL. + * the caller has to free the object. + */ +xmlXPathCompExprPtr +xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) { + xmlXPathParserContextPtr pctxt; + xmlXPathCompExprPtr comp; + +#ifdef XPATH_STREAMING + comp = xmlXPathTryStreamCompile(ctxt, str); + if (comp != NULL) + return(comp); +#endif + + xmlXPathInit(); + + pctxt = xmlXPathNewParserContext(str, ctxt); + if (pctxt == NULL) + return NULL; + xmlXPathCompileExpr(pctxt, 1); + + if( pctxt->error != XPATH_EXPRESSION_OK ) + { + xmlXPathFreeParserContext(pctxt); + return(NULL); + } + + if (*pctxt->cur != 0) { + /* + * aleksey: in some cases this line prints *second* error message + * (see bug #78858) and probably this should be fixed. + * However, we are not sure that all error messages are printed + * out in other places. It's not critical so we leave it as-is for now + */ + xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR); + comp = NULL; + } else { + comp = pctxt->comp; + pctxt->comp = NULL; + } + xmlXPathFreeParserContext(pctxt); + + if (comp != NULL) { + comp->expr = xmlStrdup(str); +#ifdef DEBUG_EVAL_COUNTS + comp->string = xmlStrdup(str); + comp->nb = 0; +#endif + if ((comp->expr != NULL) && + (comp->nbStep > 2) && + (comp->last >= 0) && + (xmlXPathCanRewriteDosExpression(comp->expr) == 1)) + { + xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]); + } + } + return(comp); +} + +/** + * xmlXPathCompile: + * @str: the XPath expression + * + * Compile an XPath expression + * + * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL. + * the caller has to free the object. + */ +xmlXPathCompExprPtr +xmlXPathCompile(const xmlChar *str) { + return(xmlXPathCtxtCompile(NULL, str)); +} + +/** + * xmlXPathCompiledEvalInternal: + * @comp: the compiled XPath expression + * @ctxt: the XPath context + * @resObj: the resulting XPath object or NULL + * @toBool: 1 if only a boolean result is requested + * + * Evaluate the Precompiled XPath expression in the given context. + * The caller has to free @resObj. + * + * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. + * the caller has to free the object. + */ +static int +xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp, + xmlXPathContextPtr ctxt, + xmlXPathObjectPtr *resObj, + int toBool) +{ + xmlXPathParserContextPtr pctxt; +#ifndef LIBXML_THREAD_ENABLED + static int reentance = 0; +#endif + int res; + + CHECK_CTXT_NEG(ctxt) + + if (comp == NULL) + return(-1); + xmlXPathInit(); + +#ifndef LIBXML_THREAD_ENABLED + reentance++; + if (reentance > 1) + xmlXPathDisableOptimizer = 1; +#endif + +#ifdef DEBUG_EVAL_COUNTS + comp->nb++; + if ((comp->string != NULL) && (comp->nb > 100)) { + fprintf(stderr, "100 x %s\n", comp->string); + comp->nb = 0; + } +#endif + pctxt = xmlXPathCompParserContext(comp, ctxt); + res = xmlXPathRunEval(pctxt, toBool); + + if (resObj) { + if (pctxt->value == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlXPathCompiledEval: evaluation failed\n"); + *resObj = NULL; + } else { + *resObj = valuePop(pctxt); + } + } + + /* + * Pop all remaining objects from the stack. + */ + if (pctxt->valueNr > 0) { + xmlXPathObjectPtr tmp; + int stack = 0; + + do { + tmp = valuePop(pctxt); + if (tmp != NULL) { + stack++; + xmlXPathReleaseObject(ctxt, tmp); + } + } while (tmp != NULL); + if ((stack != 0) && + ((toBool) || ((resObj) && (*resObj)))) + { + xmlGenericError(xmlGenericErrorContext, + "xmlXPathCompiledEval: %d objects left on the stack.\n", + stack); + } + } + + if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) { + xmlXPathFreeObject(*resObj); + *resObj = NULL; + } + pctxt->comp = NULL; + xmlXPathFreeParserContext(pctxt); +#ifndef LIBXML_THREAD_ENABLED + reentance--; +#endif + + return(res); +} + +/** + * xmlXPathCompiledEval: + * @comp: the compiled XPath expression + * @ctx: the XPath context + * + * Evaluate the Precompiled XPath expression in the given context. + * + * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. + * the caller has to free the object. + */ +xmlXPathObjectPtr +xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) +{ + xmlXPathObjectPtr res = NULL; + + xmlXPathCompiledEvalInternal(comp, ctx, &res, 0); + return(res); +} + +/** + * xmlXPathCompiledEvalToBoolean: + * @comp: the compiled XPath expression + * @ctxt: the XPath context + * + * Applies the XPath boolean() function on the result of the given + * compiled expression. + * + * Returns 1 if the expression evaluated to true, 0 if to false and + * -1 in API and internal errors. + */ +int +xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp, + xmlXPathContextPtr ctxt) +{ + return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1)); +} + +/** + * xmlXPathEvalExpr: + * @ctxt: the XPath Parser context + * + * Parse and evaluate an XPath expression in the given context, + * then push the result on the context stack + */ +void +xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) { +#ifdef XPATH_STREAMING + xmlXPathCompExprPtr comp; +#endif + + if (ctxt == NULL) return; + +#ifdef XPATH_STREAMING + comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base); + if (comp != NULL) { + if (ctxt->comp != NULL) + xmlXPathFreeCompExpr(ctxt->comp); + ctxt->comp = comp; + if (ctxt->cur != NULL) + while (*ctxt->cur != 0) ctxt->cur++; + } else +#endif + { + xmlXPathCompileExpr(ctxt, 1); + /* + * In this scenario the expression string will sit in ctxt->base. + */ + if ((ctxt->error == XPATH_EXPRESSION_OK) && + (ctxt->comp != NULL) && + (ctxt->base != NULL) && + (ctxt->comp->nbStep > 2) && + (ctxt->comp->last >= 0) && + (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1)) + { + xmlXPathRewriteDOSExpression(ctxt->comp, + &ctxt->comp->steps[ctxt->comp->last]); + } + } + CHECK_ERROR; + xmlXPathRunEval(ctxt, 0); +} + +/** + * xmlXPathEval: + * @str: the XPath expression + * @ctx: the XPath context + * + * Evaluate the XPath Location Path in the given context. + * + * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. + * the caller has to free the object. + */ +xmlXPathObjectPtr +xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) { + xmlXPathParserContextPtr ctxt; + xmlXPathObjectPtr res, tmp, init = NULL; + int stack = 0; + + CHECK_CTXT(ctx) + + xmlXPathInit(); + + ctxt = xmlXPathNewParserContext(str, ctx); + if (ctxt == NULL) + return NULL; + xmlXPathEvalExpr(ctxt); + + if (ctxt->value == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xmlXPathEval: evaluation failed\n"); + res = NULL; + } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL) +#ifdef XPATH_STREAMING + && (ctxt->comp->stream == NULL) +#endif + ) { + xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR); + res = NULL; + } else { + res = valuePop(ctxt); + } + + do { + tmp = valuePop(ctxt); + if (tmp != NULL) { + if (tmp != init) + stack++; + xmlXPathReleaseObject(ctx, tmp); + } + } while (tmp != NULL); + if ((stack != 0) && (res != NULL)) { + xmlGenericError(xmlGenericErrorContext, + "xmlXPathEval: %d object left on the stack\n", + stack); + } + if (ctxt->error != XPATH_EXPRESSION_OK) { + xmlXPathFreeObject(res); + res = NULL; + } + + xmlXPathFreeParserContext(ctxt); + return(res); +} + +/** + * xmlXPathEvalExpression: + * @str: the XPath expression + * @ctxt: the XPath context + * + * Evaluate the XPath expression in the given context. + * + * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. + * the caller has to free the object. + */ +xmlXPathObjectPtr +xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) { + xmlXPathParserContextPtr pctxt; + xmlXPathObjectPtr res, tmp; + int stack = 0; + + CHECK_CTXT(ctxt) + + xmlXPathInit(); + + pctxt = xmlXPathNewParserContext(str, ctxt); + if (pctxt == NULL) + return NULL; + xmlXPathEvalExpr(pctxt); + + if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) { + xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR); + res = NULL; + } else { + res = valuePop(pctxt); + } + do { + tmp = valuePop(pctxt); + if (tmp != NULL) { + xmlXPathReleaseObject(ctxt, tmp); + stack++; + } + } while (tmp != NULL); + if ((stack != 0) && (res != NULL)) { + xmlGenericError(xmlGenericErrorContext, + "xmlXPathEvalExpression: %d object left on the stack\n", + stack); + } + xmlXPathFreeParserContext(pctxt); + return(res); +} + +/************************************************************************ + * * + * Extra functions not pertaining to the XPath spec * + * * + ************************************************************************/ +/** + * xmlXPathEscapeUriFunction: + * @ctxt: the XPath Parser context + * @nargs: the number of arguments + * + * Implement the escape-uri() XPath function + * string escape-uri(string $str, bool $escape-reserved) + * + * This function applies the URI escaping rules defined in section 2 of [RFC + * 2396] to the string supplied as $uri-part, which typically represents all + * or part of a URI. The effect of the function is to replace any special + * character in the string by an escape sequence of the form %xx%yy..., + * where xxyy... is the hexadecimal representation of the octets used to + * represent the character in UTF-8. + * + * The set of characters that are escaped depends on the setting of the + * boolean argument $escape-reserved. + * + * If $escape-reserved is true, all characters are escaped other than lower + * case letters a-z, upper case letters A-Z, digits 0-9, and the characters + * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!" + * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only + * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and + * A-F). + * + * If $escape-reserved is false, the behavior differs in that characters + * referred to in [RFC 2396] as reserved characters are not escaped. These + * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",". + * + * [RFC 2396] does not define whether escaped URIs should use lower case or + * upper case for hexadecimal digits. To ensure that escaped URIs can be + * compared using string comparison functions, this function must always use + * the upper-case letters A-F. + * + * Generally, $escape-reserved should be set to true when escaping a string + * that is to form a single part of a URI, and to false when escaping an + * entire URI or URI reference. + * + * In the case of non-ascii characters, the string is encoded according to + * utf-8 and then converted according to RFC 2396. + * + * Examples + * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true()) + * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean" + * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false()) + * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean" + * + */ +static void +xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) { + xmlXPathObjectPtr str; + int escape_reserved; + xmlBufferPtr target; + xmlChar *cptr; + xmlChar escape[4]; + + CHECK_ARITY(2); + + escape_reserved = xmlXPathPopBoolean(ctxt); + + CAST_TO_STRING; + str = valuePop(ctxt); + + target = xmlBufferCreate(); + + escape[0] = '%'; + escape[3] = 0; + + if (target) { + for (cptr = str->stringval; *cptr; cptr++) { + if ((*cptr >= 'A' && *cptr <= 'Z') || + (*cptr >= 'a' && *cptr <= 'z') || + (*cptr >= '0' && *cptr <= '9') || + *cptr == '-' || *cptr == '_' || *cptr == '.' || + *cptr == '!' || *cptr == '~' || *cptr == '*' || + *cptr == '\''|| *cptr == '(' || *cptr == ')' || + (*cptr == '%' && + ((cptr[1] >= 'A' && cptr[1] <= 'F') || + (cptr[1] >= 'a' && cptr[1] <= 'f') || + (cptr[1] >= '0' && cptr[1] <= '9')) && + ((cptr[2] >= 'A' && cptr[2] <= 'F') || + (cptr[2] >= 'a' && cptr[2] <= 'f') || + (cptr[2] >= '0' && cptr[2] <= '9'))) || + (!escape_reserved && + (*cptr == ';' || *cptr == '/' || *cptr == '?' || + *cptr == ':' || *cptr == '@' || *cptr == '&' || + *cptr == '=' || *cptr == '+' || *cptr == '$' || + *cptr == ','))) { + xmlBufferAdd(target, cptr, 1); + } else { + if ((*cptr >> 4) < 10) + escape[1] = '0' + (*cptr >> 4); + else + escape[1] = 'A' - 10 + (*cptr >> 4); + if ((*cptr & 0xF) < 10) + escape[2] = '0' + (*cptr & 0xF); + else + escape[2] = 'A' - 10 + (*cptr & 0xF); + + xmlBufferAdd(target, &escape[0], 3); + } + } + } + valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, + xmlBufferContent(target))); + xmlBufferFree(target); + xmlXPathReleaseObject(ctxt->context, str); +} + +/** + * xmlXPathRegisterAllFunctions: + * @ctxt: the XPath context + * + * Registers all default XPath functions in this context + */ +void +xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt) +{ + xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean", + xmlXPathBooleanFunction); + xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling", + xmlXPathCeilingFunction); + xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count", + xmlXPathCountFunction); + xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat", + xmlXPathConcatFunction); + xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains", + xmlXPathContainsFunction); + xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id", + xmlXPathIdFunction); + xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false", + xmlXPathFalseFunction); + xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor", + xmlXPathFloorFunction); + xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last", + xmlXPathLastFunction); + xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang", + xmlXPathLangFunction); + xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name", + xmlXPathLocalNameFunction); + xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not", + xmlXPathNotFunction); + xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name", + xmlXPathNameFunction); + xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri", + xmlXPathNamespaceURIFunction); + xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space", + xmlXPathNormalizeFunction); + xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number", + xmlXPathNumberFunction); + xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position", + xmlXPathPositionFunction); + xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round", + xmlXPathRoundFunction); + xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string", + xmlXPathStringFunction); + xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length", + xmlXPathStringLengthFunction); + xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with", + xmlXPathStartsWithFunction); + xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring", + xmlXPathSubstringFunction); + xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before", + xmlXPathSubstringBeforeFunction); + xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after", + xmlXPathSubstringAfterFunction); + xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum", + xmlXPathSumFunction); + xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true", + xmlXPathTrueFunction); + xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate", + xmlXPathTranslateFunction); + + xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri", + (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions", + xmlXPathEscapeUriFunction); +} + +#endif /* LIBXML_XPATH_ENABLED */ +#define bottom_xpath +#include "elfgcchack.h" diff --git a/android/native/libxml2/xpointer.c b/android/native/libxml2/xpointer.c new file mode 100644 index 0000000000..37afa3a142 --- /dev/null +++ b/android/native/libxml2/xpointer.c @@ -0,0 +1,3012 @@ +/* + * xpointer.c : Code to handle XML Pointer + * + * Base implementation was made accordingly to + * W3C Candidate Recommendation 7 June 2000 + * http://www.w3.org/TR/2000/CR-xptr-20000607 + * + * Added support for the element() scheme described in: + * W3C Proposed Recommendation 13 November 2002 + * http://www.w3.org/TR/2002/PR-xptr-element-20021113/ + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + */ + +#define IN_LIBXML +#include "libxml.h" + +/* + * TODO: better handling of error cases, the full expression should + * be parsed beforehand instead of a progressive evaluation + * TODO: Access into entities references are not supported now ... + * need a start to be able to pop out of entities refs since + * parent is the endity declaration, not the ref. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef LIBXML_XPTR_ENABLED + +/* Add support of the xmlns() xpointer scheme to initialize the namespaces */ +#define XPTR_XMLNS_SCHEME + +/* #define DEBUG_RANGES */ +#ifdef DEBUG_RANGES +#ifdef LIBXML_DEBUG_ENABLED +#include +#endif +#endif + +#define TODO \ + xmlGenericError(xmlGenericErrorContext, \ + "Unimplemented block at %s:%d\n", \ + __FILE__, __LINE__); + +#define STRANGE \ + xmlGenericError(xmlGenericErrorContext, \ + "Internal error at %s:%d\n", \ + __FILE__, __LINE__); + +/************************************************************************ + * * + * Some factorized error routines * + * * + ************************************************************************/ + +/** + * xmlXPtrErrMemory: + * @extra: extra informations + * + * 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 informations + * + * Handle a redefinition of attribute error + */ +static void +xmlXPtrErr(xmlXPathParserContextPtr ctxt, int error, + 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; + } + 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); + } +} + +/************************************************************************ + * * + * A few helper functions for child sequences * + * * + ************************************************************************/ +/* xmlXPtrAdvanceNode is a private function, but used by xinclude.c */ +xmlNodePtr xmlXPtrAdvanceNode(xmlNodePtr cur, int *level); +/** + * xmlXPtrGetArity: + * @cur: the node + * + * Returns the number of child for an element, -1 in case of error + */ +static int +xmlXPtrGetArity(xmlNodePtr cur) { + int i; + if (cur == NULL) + return(-1); + cur = cur->children; + for (i = 0;cur != NULL;cur = cur->next) { + if ((cur->type == XML_ELEMENT_NODE) || + (cur->type == XML_DOCUMENT_NODE) || + (cur->type == XML_HTML_DOCUMENT_NODE)) { + i++; + } + } + return(i); +} + +/** + * xmlXPtrGetIndex: + * @cur: the node + * + * Returns the index of the node in its parent children list, -1 + * in case of error + */ +static int +xmlXPtrGetIndex(xmlNodePtr cur) { + int i; + if (cur == NULL) + return(-1); + for (i = 1;cur != NULL;cur = cur->prev) { + if ((cur->type == XML_ELEMENT_NODE) || + (cur->type == XML_DOCUMENT_NODE) || + (cur->type == XML_HTML_DOCUMENT_NODE)) { + i++; + } + } + return(i); +} + +/** + * xmlXPtrGetNthChild: + * @cur: the node + * @no: the child number + * + * Returns the @no'th element child of @cur or NULL + */ +static xmlNodePtr +xmlXPtrGetNthChild(xmlNodePtr cur, int no) { + int i; + if (cur == NULL) + return(cur); + cur = cur->children; + for (i = 0;i <= no;cur = cur->next) { + if (cur == NULL) + return(cur); + if ((cur->type == XML_ELEMENT_NODE) || + (cur->type == XML_DOCUMENT_NODE) || + (cur->type == XML_HTML_DOCUMENT_NODE)) { + i++; + if (i == no) + break; + } + } + return(cur); +} + +/************************************************************************ + * * + * Handling of XPointer specific types * + * * + ************************************************************************/ + +/** + * xmlXPtrCmpPoints: + * @node1: the first node + * @index1: the first index + * @node2: the second node + * @index2: the second index + * + * Compare two points w.r.t document order + * + * Returns -2 in case of error 1 if first point < second point, 0 if + * that's the same point, -1 otherwise + */ +static int +xmlXPtrCmpPoints(xmlNodePtr node1, int index1, xmlNodePtr node2, int index2) { + if ((node1 == NULL) || (node2 == NULL)) + return(-2); + /* + * a couple of optimizations which will avoid computations in most cases + */ + if (node1 == node2) { + if (index1 < index2) + return(1); + if (index1 > index2) + return(-1); + return(0); + } + return(xmlXPathCmpNodes(node1, node2)); +} + +/** + * xmlXPtrNewPoint: + * @node: the xmlNodePtr + * @indx: the indx within the node + * + * Create a new xmlXPathObjectPtr of type point + * + * Returns the newly created object. + */ +static xmlXPathObjectPtr +xmlXPtrNewPoint(xmlNodePtr node, int indx) { + xmlXPathObjectPtr ret; + + if (node == NULL) + return(NULL); + if (indx < 0) + return(NULL); + + ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); + if (ret == NULL) { + xmlXPtrErrMemory("allocating point"); + return(NULL); + } + memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); + ret->type = XPATH_POINT; + ret->user = (void *) node; + ret->index = indx; + return(ret); +} + +/** + * xmlXPtrRangeCheckOrder: + * @range: an object range + * + * Make sure the points in the range are in the right order + */ +static void +xmlXPtrRangeCheckOrder(xmlXPathObjectPtr range) { + int tmp; + xmlNodePtr tmp2; + if (range == NULL) + return; + if (range->type != XPATH_RANGE) + return; + if (range->user2 == NULL) + return; + tmp = xmlXPtrCmpPoints(range->user, range->index, + range->user2, range->index2); + if (tmp == -1) { + tmp2 = range->user; + range->user = range->user2; + range->user2 = tmp2; + tmp = range->index; + range->index = range->index2; + range->index2 = tmp; + } +} + +/** + * xmlXPtrRangesEqual: + * @range1: the first range + * @range2: the second range + * + * Compare two ranges + * + * Returns 1 if equal, 0 otherwise + */ +static int +xmlXPtrRangesEqual(xmlXPathObjectPtr range1, xmlXPathObjectPtr range2) { + if (range1 == range2) + return(1); + if ((range1 == NULL) || (range2 == NULL)) + return(0); + if (range1->type != range2->type) + return(0); + if (range1->type != XPATH_RANGE) + return(0); + if (range1->user != range2->user) + return(0); + if (range1->index != range2->index) + return(0); + if (range1->user2 != range2->user2) + return(0); + if (range1->index2 != range2->index2) + return(0); + return(1); +} + +/** + * xmlXPtrNewRange: + * @start: the starting node + * @startindex: the start index + * @end: the ending point + * @endindex: the ending index + * + * Create a new xmlXPathObjectPtr of type range + * + * Returns the newly created object. + */ +xmlXPathObjectPtr +xmlXPtrNewRange(xmlNodePtr start, int startindex, + xmlNodePtr end, int endindex) { + xmlXPathObjectPtr ret; + + if (start == NULL) + return(NULL); + if (end == NULL) + return(NULL); + if (startindex < 0) + return(NULL); + if (endindex < 0) + return(NULL); + + ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); + if (ret == NULL) { + xmlXPtrErrMemory("allocating range"); + return(NULL); + } + memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); + ret->type = XPATH_RANGE; + ret->user = start; + ret->index = startindex; + ret->user2 = end; + ret->index2 = endindex; + xmlXPtrRangeCheckOrder(ret); + return(ret); +} + +/** + * xmlXPtrNewRangePoints: + * @start: the starting point + * @end: the ending point + * + * Create a new xmlXPathObjectPtr of type range using 2 Points + * + * Returns the newly created object. + */ +xmlXPathObjectPtr +xmlXPtrNewRangePoints(xmlXPathObjectPtr start, xmlXPathObjectPtr end) { + xmlXPathObjectPtr ret; + + if (start == NULL) + return(NULL); + if (end == NULL) + return(NULL); + if (start->type != XPATH_POINT) + return(NULL); + if (end->type != XPATH_POINT) + return(NULL); + + ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); + if (ret == NULL) { + xmlXPtrErrMemory("allocating range"); + return(NULL); + } + memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); + ret->type = XPATH_RANGE; + ret->user = start->user; + ret->index = start->index; + ret->user2 = end->user; + ret->index2 = end->index; + xmlXPtrRangeCheckOrder(ret); + return(ret); +} + +/** + * xmlXPtrNewRangePointNode: + * @start: the starting point + * @end: the ending node + * + * Create a new xmlXPathObjectPtr of type range from a point to a node + * + * Returns the newly created object. + */ +xmlXPathObjectPtr +xmlXPtrNewRangePointNode(xmlXPathObjectPtr start, xmlNodePtr end) { + xmlXPathObjectPtr ret; + + if (start == NULL) + return(NULL); + if (end == NULL) + return(NULL); + if (start->type != XPATH_POINT) + return(NULL); + + ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); + if (ret == NULL) { + xmlXPtrErrMemory("allocating range"); + return(NULL); + } + memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); + ret->type = XPATH_RANGE; + ret->user = start->user; + ret->index = start->index; + ret->user2 = end; + ret->index2 = -1; + xmlXPtrRangeCheckOrder(ret); + return(ret); +} + +/** + * xmlXPtrNewRangeNodePoint: + * @start: the starting node + * @end: the ending point + * + * Create a new xmlXPathObjectPtr of type range from a node to a point + * + * Returns the newly created object. + */ +xmlXPathObjectPtr +xmlXPtrNewRangeNodePoint(xmlNodePtr start, xmlXPathObjectPtr end) { + xmlXPathObjectPtr ret; + + if (start == NULL) + return(NULL); + if (end == NULL) + return(NULL); + if (start->type != XPATH_POINT) + return(NULL); + if (end->type != XPATH_POINT) + return(NULL); + + ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); + if (ret == NULL) { + xmlXPtrErrMemory("allocating range"); + return(NULL); + } + memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); + ret->type = XPATH_RANGE; + ret->user = start; + ret->index = -1; + ret->user2 = end->user; + ret->index2 = end->index; + xmlXPtrRangeCheckOrder(ret); + return(ret); +} + +/** + * xmlXPtrNewRangeNodes: + * @start: the starting node + * @end: the ending node + * + * Create a new xmlXPathObjectPtr of type range using 2 nodes + * + * Returns the newly created object. + */ +xmlXPathObjectPtr +xmlXPtrNewRangeNodes(xmlNodePtr start, xmlNodePtr end) { + xmlXPathObjectPtr ret; + + if (start == NULL) + return(NULL); + if (end == NULL) + return(NULL); + + ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); + if (ret == NULL) { + xmlXPtrErrMemory("allocating range"); + return(NULL); + } + memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); + ret->type = XPATH_RANGE; + ret->user = start; + ret->index = -1; + ret->user2 = end; + ret->index2 = -1; + xmlXPtrRangeCheckOrder(ret); + return(ret); +} + +/** + * xmlXPtrNewCollapsedRange: + * @start: the starting and ending node + * + * Create a new xmlXPathObjectPtr of type range using a single nodes + * + * Returns the newly created object. + */ +xmlXPathObjectPtr +xmlXPtrNewCollapsedRange(xmlNodePtr start) { + xmlXPathObjectPtr ret; + + if (start == NULL) + return(NULL); + + ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); + if (ret == NULL) { + xmlXPtrErrMemory("allocating range"); + return(NULL); + } + memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); + ret->type = XPATH_RANGE; + ret->user = start; + ret->index = -1; + ret->user2 = NULL; + ret->index2 = -1; + return(ret); +} + +/** + * xmlXPtrNewRangeNodeObject: + * @start: the starting node + * @end: the ending object + * + * Create a new xmlXPathObjectPtr of type range from a not to an object + * + * Returns the newly created object. + */ +xmlXPathObjectPtr +xmlXPtrNewRangeNodeObject(xmlNodePtr start, xmlXPathObjectPtr end) { + xmlXPathObjectPtr ret; + + if (start == NULL) + return(NULL); + if (end == NULL) + return(NULL); + switch (end->type) { + case XPATH_POINT: + case XPATH_RANGE: + break; + case XPATH_NODESET: + /* + * Empty set ... + */ + if (end->nodesetval->nodeNr <= 0) + return(NULL); + break; + default: + /* TODO */ + return(NULL); + } + + ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); + if (ret == NULL) { + xmlXPtrErrMemory("allocating range"); + return(NULL); + } + memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); + ret->type = XPATH_RANGE; + ret->user = start; + ret->index = -1; + switch (end->type) { + case XPATH_POINT: + ret->user2 = end->user; + ret->index2 = end->index; + break; + case XPATH_RANGE: + ret->user2 = end->user2; + ret->index2 = end->index2; + break; + case XPATH_NODESET: { + ret->user2 = end->nodesetval->nodeTab[end->nodesetval->nodeNr - 1]; + ret->index2 = -1; + break; + } + default: + STRANGE + return(NULL); + } + xmlXPtrRangeCheckOrder(ret); + return(ret); +} + +#define XML_RANGESET_DEFAULT 10 + +/** + * xmlXPtrLocationSetCreate: + * @val: an initial xmlXPathObjectPtr, or NULL + * + * Create a new xmlLocationSetPtr of type double and of value @val + * + * Returns the newly created object. + */ +xmlLocationSetPtr +xmlXPtrLocationSetCreate(xmlXPathObjectPtr val) { + xmlLocationSetPtr ret; + + ret = (xmlLocationSetPtr) xmlMalloc(sizeof(xmlLocationSet)); + if (ret == NULL) { + xmlXPtrErrMemory("allocating locationset"); + return(NULL); + } + memset(ret, 0 , (size_t) sizeof(xmlLocationSet)); + if (val != NULL) { + ret->locTab = (xmlXPathObjectPtr *) xmlMalloc(XML_RANGESET_DEFAULT * + sizeof(xmlXPathObjectPtr)); + if (ret->locTab == NULL) { + xmlXPtrErrMemory("allocating locationset"); + xmlFree(ret); + return(NULL); + } + memset(ret->locTab, 0 , + XML_RANGESET_DEFAULT * (size_t) sizeof(xmlXPathObjectPtr)); + ret->locMax = XML_RANGESET_DEFAULT; + ret->locTab[ret->locNr++] = val; + } + return(ret); +} + +/** + * xmlXPtrLocationSetAdd: + * @cur: the initial range set + * @val: a new xmlXPathObjectPtr + * + * add a new xmlXPathObjectPtr to an existing LocationSet + * If the location already exist in the set @val is freed. + */ +void +xmlXPtrLocationSetAdd(xmlLocationSetPtr cur, xmlXPathObjectPtr val) { + int i; + + if ((cur == NULL) || (val == NULL)) return; + + /* + * check against doublons + */ + for (i = 0;i < cur->locNr;i++) { + if (xmlXPtrRangesEqual(cur->locTab[i], val)) { + xmlXPathFreeObject(val); + return; + } + } + + /* + * grow the locTab if needed + */ + if (cur->locMax == 0) { + cur->locTab = (xmlXPathObjectPtr *) xmlMalloc(XML_RANGESET_DEFAULT * + sizeof(xmlXPathObjectPtr)); + if (cur->locTab == NULL) { + xmlXPtrErrMemory("adding location to set"); + return; + } + memset(cur->locTab, 0 , + XML_RANGESET_DEFAULT * (size_t) sizeof(xmlXPathObjectPtr)); + cur->locMax = XML_RANGESET_DEFAULT; + } else if (cur->locNr == cur->locMax) { + xmlXPathObjectPtr *temp; + + cur->locMax *= 2; + temp = (xmlXPathObjectPtr *) xmlRealloc(cur->locTab, cur->locMax * + sizeof(xmlXPathObjectPtr)); + if (temp == NULL) { + xmlXPtrErrMemory("adding location to set"); + return; + } + cur->locTab = temp; + } + cur->locTab[cur->locNr++] = val; +} + +/** + * xmlXPtrLocationSetMerge: + * @val1: the first LocationSet + * @val2: the second LocationSet + * + * Merges two rangesets, all ranges from @val2 are added to @val1 + * + * Returns val1 once extended or NULL in case of error. + */ +xmlLocationSetPtr +xmlXPtrLocationSetMerge(xmlLocationSetPtr val1, xmlLocationSetPtr val2) { + int i; + + if (val1 == NULL) return(NULL); + if (val2 == NULL) return(val1); + + /* + * !!!!! this can be optimized a lot, knowing that both + * val1 and val2 already have unicity of their values. + */ + + for (i = 0;i < val2->locNr;i++) + xmlXPtrLocationSetAdd(val1, val2->locTab[i]); + + return(val1); +} + +/** + * xmlXPtrLocationSetDel: + * @cur: the initial range set + * @val: an xmlXPathObjectPtr + * + * Removes an xmlXPathObjectPtr from an existing LocationSet + */ +void +xmlXPtrLocationSetDel(xmlLocationSetPtr cur, xmlXPathObjectPtr val) { + int i; + + if (cur == NULL) return; + if (val == NULL) return; + + /* + * check against doublons + */ + for (i = 0;i < cur->locNr;i++) + if (cur->locTab[i] == val) break; + + if (i >= cur->locNr) { +#ifdef DEBUG + xmlGenericError(xmlGenericErrorContext, + "xmlXPtrLocationSetDel: Range wasn't found in RangeList\n"); +#endif + return; + } + cur->locNr--; + for (;i < cur->locNr;i++) + cur->locTab[i] = cur->locTab[i + 1]; + cur->locTab[cur->locNr] = NULL; +} + +/** + * xmlXPtrLocationSetRemove: + * @cur: the initial range set + * @val: the index to remove + * + * Removes an entry from an existing LocationSet list. + */ +void +xmlXPtrLocationSetRemove(xmlLocationSetPtr cur, int val) { + if (cur == NULL) return; + if (val >= cur->locNr) return; + cur->locNr--; + for (;val < cur->locNr;val++) + cur->locTab[val] = cur->locTab[val + 1]; + cur->locTab[cur->locNr] = NULL; +} + +/** + * xmlXPtrFreeLocationSet: + * @obj: the xmlLocationSetPtr to free + * + * Free the LocationSet compound (not the actual ranges !). + */ +void +xmlXPtrFreeLocationSet(xmlLocationSetPtr obj) { + int i; + + if (obj == NULL) return; + if (obj->locTab != NULL) { + for (i = 0;i < obj->locNr; i++) { + xmlXPathFreeObject(obj->locTab[i]); + } + xmlFree(obj->locTab); + } + xmlFree(obj); +} + +/** + * xmlXPtrNewLocationSetNodes: + * @start: the start NodePtr value + * @end: the end NodePtr value or NULL + * + * Create a new xmlXPathObjectPtr of type LocationSet and initialize + * it with the single range made of the two nodes @start and @end + * + * Returns the newly created object. + */ +xmlXPathObjectPtr +xmlXPtrNewLocationSetNodes(xmlNodePtr start, xmlNodePtr end) { + xmlXPathObjectPtr ret; + + ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); + if (ret == NULL) { + xmlXPtrErrMemory("allocating locationset"); + return(NULL); + } + memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); + ret->type = XPATH_LOCATIONSET; + if (end == NULL) + ret->user = xmlXPtrLocationSetCreate(xmlXPtrNewCollapsedRange(start)); + else + ret->user = xmlXPtrLocationSetCreate(xmlXPtrNewRangeNodes(start,end)); + return(ret); +} + +/** + * xmlXPtrNewLocationSetNodeSet: + * @set: a node set + * + * Create a new xmlXPathObjectPtr of type LocationSet and initialize + * it with all the nodes from @set + * + * Returns the newly created object. + */ +xmlXPathObjectPtr +xmlXPtrNewLocationSetNodeSet(xmlNodeSetPtr set) { + xmlXPathObjectPtr ret; + + ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); + if (ret == NULL) { + xmlXPtrErrMemory("allocating locationset"); + return(NULL); + } + memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); + ret->type = XPATH_LOCATIONSET; + if (set != NULL) { + int i; + xmlLocationSetPtr newset; + + newset = xmlXPtrLocationSetCreate(NULL); + if (newset == NULL) + return(ret); + + for (i = 0;i < set->nodeNr;i++) + xmlXPtrLocationSetAdd(newset, + xmlXPtrNewCollapsedRange(set->nodeTab[i])); + + ret->user = (void *) newset; + } + return(ret); +} + +/** + * xmlXPtrWrapLocationSet: + * @val: the LocationSet value + * + * Wrap the LocationSet @val in a new xmlXPathObjectPtr + * + * Returns the newly created object. + */ +xmlXPathObjectPtr +xmlXPtrWrapLocationSet(xmlLocationSetPtr val) { + xmlXPathObjectPtr ret; + + ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); + if (ret == NULL) { + xmlXPtrErrMemory("allocating locationset"); + return(NULL); + } + memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); + ret->type = XPATH_LOCATIONSET; + ret->user = (void *) val; + return(ret); +} + +/************************************************************************ + * * + * The parser * + * * + ************************************************************************/ + +static void xmlXPtrEvalChildSeq(xmlXPathParserContextPtr ctxt, xmlChar *name); + +/* + * Macros for accessing the content. Those should be used only by the parser, + * and not exported. + * + * Dirty macros, i.e. one need to make assumption on the context to use them + * + * CUR_PTR return the current pointer to the xmlChar to be parsed. + * CUR returns the current xmlChar value, i.e. a 8 bit value + * in ISO-Latin or UTF-8. + * This should be used internally by the parser + * only to compare to ASCII values otherwise it would break when + * running with UTF-8 encoding. + * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only + * to compare on ASCII based substring. + * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined + * strings within the parser. + * CURRENT Returns the current char value, with the full decoding of + * UTF-8 if we are using this mode. It returns an int. + * NEXT Skip to the next character, this does the proper decoding + * in UTF-8 mode. It also pop-up unfinished entities on the fly. + * It returns the pointer to the current xmlChar. + */ + +#define CUR (*ctxt->cur) +#define SKIP(val) ctxt->cur += (val) +#define NXT(val) ctxt->cur[(val)] +#define CUR_PTR ctxt->cur + +#define SKIP_BLANKS \ + while (IS_BLANK_CH(*(ctxt->cur))) NEXT + +#define CURRENT (*ctxt->cur) +#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur) + +/* + * xmlXPtrGetChildNo: + * @ctxt: the XPointer Parser context + * @index: the child number + * + * Move the current node of the nodeset on the stack to the + * given child if found + */ +static void +xmlXPtrGetChildNo(xmlXPathParserContextPtr ctxt, int indx) { + xmlNodePtr cur = NULL; + xmlXPathObjectPtr obj; + xmlNodeSetPtr oldset; + + CHECK_TYPE(XPATH_NODESET); + obj = valuePop(ctxt); + oldset = obj->nodesetval; + if ((indx <= 0) || (oldset == NULL) || (oldset->nodeNr != 1)) { + xmlXPathFreeObject(obj); + valuePush(ctxt, xmlXPathNewNodeSet(NULL)); + return; + } + cur = xmlXPtrGetNthChild(oldset->nodeTab[0], indx); + if (cur == NULL) { + xmlXPathFreeObject(obj); + valuePush(ctxt, xmlXPathNewNodeSet(NULL)); + return; + } + oldset->nodeTab[0] = cur; + valuePush(ctxt, obj); +} + +/** + * xmlXPtrEvalXPtrPart: + * @ctxt: the XPointer Parser context + * @name: the preparsed Scheme for the XPtrPart + * + * XPtrPart ::= 'xpointer' '(' XPtrExpr ')' + * | Scheme '(' SchemeSpecificExpr ')' + * + * Scheme ::= NCName - 'xpointer' [VC: Non-XPointer schemes] + * + * SchemeSpecificExpr ::= StringWithBalancedParens + * + * StringWithBalancedParens ::= + * [^()]* ('(' StringWithBalancedParens ')' [^()]*)* + * [VC: Parenthesis escaping] + * + * XPtrExpr ::= Expr [VC: Parenthesis escaping] + * + * VC: Parenthesis escaping: + * The end of an XPointer part is signaled by the right parenthesis ")" + * character that is balanced with the left parenthesis "(" character + * that began the part. Any unbalanced parenthesis character inside the + * expression, even within literals, must be escaped with a circumflex (^) + * character preceding it. If the expression contains any literal + * occurrences of the circumflex, each must be escaped with an additional + * circumflex (that is, ^^). If the unescaped parentheses in the expression + * are not balanced, a syntax error results. + * + * Parse and evaluate an XPtrPart. Basically it generates the unescaped + * string and if the scheme is 'xpointer' it will call the XPath interpreter. + * + * TODO: there is no new scheme registration mechanism + */ + +static void +xmlXPtrEvalXPtrPart(xmlXPathParserContextPtr ctxt, xmlChar *name) { + xmlChar *buffer, *cur; + int len; + int level; + + if (name == NULL) + name = xmlXPathParseName(ctxt); + if (name == NULL) + XP_ERROR(XPATH_EXPR_ERROR); + + if (CUR != '(') + XP_ERROR(XPATH_EXPR_ERROR); + NEXT; + level = 1; + + len = xmlStrlen(ctxt->cur); + len++; + buffer = (xmlChar *) xmlMallocAtomic(len * sizeof (xmlChar)); + if (buffer == NULL) { + xmlXPtrErrMemory("allocating buffer"); + return; + } + + cur = buffer; + while (CUR != 0) { + if (CUR == ')') { + level--; + if (level == 0) { + NEXT; + break; + } + *cur++ = CUR; + } else if (CUR == '(') { + level++; + *cur++ = CUR; + } else if (CUR == '^') { + NEXT; + if ((CUR == ')') || (CUR == '(') || (CUR == '^')) { + *cur++ = CUR; + } else { + *cur++ = '^'; + *cur++ = CUR; + } + } else { + *cur++ = CUR; + } + NEXT; + } + *cur = 0; + + if ((level != 0) && (CUR == 0)) { + xmlFree(buffer); + XP_ERROR(XPTR_SYNTAX_ERROR); + } + + if (xmlStrEqual(name, (xmlChar *) "xpointer")) { + const xmlChar *left = CUR_PTR; + + CUR_PTR = buffer; + /* + * To evaluate an xpointer scheme element (4.3) we need: + * context initialized to the root + * context position initalized to 1 + * context size initialized to 1 + */ + ctxt->context->node = (xmlNodePtr)ctxt->context->doc; + ctxt->context->proximityPosition = 1; + ctxt->context->contextSize = 1; + xmlXPathEvalExpr(ctxt); + CUR_PTR=left; + } else if (xmlStrEqual(name, (xmlChar *) "element")) { + const xmlChar *left = CUR_PTR; + xmlChar *name2; + + CUR_PTR = buffer; + if (buffer[0] == '/') { + xmlXPathRoot(ctxt); + xmlXPtrEvalChildSeq(ctxt, NULL); + } else { + name2 = xmlXPathParseName(ctxt); + if (name2 == NULL) { + CUR_PTR = left; + xmlFree(buffer); + XP_ERROR(XPATH_EXPR_ERROR); + } + xmlXPtrEvalChildSeq(ctxt, name2); + } + CUR_PTR = left; +#ifdef XPTR_XMLNS_SCHEME + } else if (xmlStrEqual(name, (xmlChar *) "xmlns")) { + const xmlChar *left = CUR_PTR; + xmlChar *prefix; + xmlChar *URI; + xmlURIPtr value; + + CUR_PTR = buffer; + prefix = xmlXPathParseNCName(ctxt); + if (prefix == NULL) { + xmlFree(buffer); + xmlFree(name); + XP_ERROR(XPTR_SYNTAX_ERROR); + } + SKIP_BLANKS; + if (CUR != '=') { + xmlFree(prefix); + xmlFree(buffer); + xmlFree(name); + XP_ERROR(XPTR_SYNTAX_ERROR); + } + NEXT; + SKIP_BLANKS; + /* @@ check escaping in the XPointer WD */ + + value = xmlParseURI((const char *)ctxt->cur); + if (value == NULL) { + xmlFree(prefix); + xmlFree(buffer); + xmlFree(name); + XP_ERROR(XPTR_SYNTAX_ERROR); + } + URI = xmlSaveUri(value); + xmlFreeURI(value); + if (URI == NULL) { + xmlFree(prefix); + xmlFree(buffer); + xmlFree(name); + XP_ERROR(XPATH_MEMORY_ERROR); + } + + xmlXPathRegisterNs(ctxt->context, prefix, URI); + CUR_PTR = left; + xmlFree(URI); + xmlFree(prefix); +#endif /* XPTR_XMLNS_SCHEME */ + } else { + xmlXPtrErr(ctxt, XML_XPTR_UNKNOWN_SCHEME, + "unsupported scheme '%s'\n", name); + } + xmlFree(buffer); + xmlFree(name); +} + +/** + * xmlXPtrEvalFullXPtr: + * @ctxt: the XPointer Parser context + * @name: the preparsed Scheme for the first XPtrPart + * + * FullXPtr ::= XPtrPart (S? XPtrPart)* + * + * As the specs says: + * ----------- + * When multiple XPtrParts are provided, they must be evaluated in + * left-to-right order. If evaluation of one part fails, the nexti + * is evaluated. The following conditions cause XPointer part failure: + * + * - An unknown scheme + * - A scheme that does not locate any sub-resource present in the resource + * - A scheme that is not applicable to the media type of the resource + * + * The XPointer application must consume a failed XPointer part and + * attempt to evaluate the next one, if any. The result of the first + * XPointer part whose evaluation succeeds is taken to be the fragment + * located by the XPointer as a whole. If all the parts fail, the result + * for the XPointer as a whole is a sub-resource error. + * ----------- + * + * Parse and evaluate a Full XPtr i.e. possibly a cascade of XPath based + * expressions or other schemes. + */ +static void +xmlXPtrEvalFullXPtr(xmlXPathParserContextPtr ctxt, xmlChar *name) { + if (name == NULL) + name = xmlXPathParseName(ctxt); + if (name == NULL) + XP_ERROR(XPATH_EXPR_ERROR); + while (name != NULL) { + ctxt->error = XPATH_EXPRESSION_OK; + xmlXPtrEvalXPtrPart(ctxt, name); + + /* in case of syntax error, break here */ + if ((ctxt->error != XPATH_EXPRESSION_OK) && + (ctxt->error != XML_XPTR_UNKNOWN_SCHEME)) + return; + + /* + * If the returned value is a non-empty nodeset + * or location set, return here. + */ + if (ctxt->value != NULL) { + xmlXPathObjectPtr obj = ctxt->value; + + switch (obj->type) { + case XPATH_LOCATIONSET: { + xmlLocationSetPtr loc = ctxt->value->user; + if ((loc != NULL) && (loc->locNr > 0)) + return; + break; + } + case XPATH_NODESET: { + xmlNodeSetPtr loc = ctxt->value->nodesetval; + if ((loc != NULL) && (loc->nodeNr > 0)) + return; + break; + } + default: + break; + } + + /* + * Evaluating to improper values is equivalent to + * a sub-resource error, clean-up the stack + */ + do { + obj = valuePop(ctxt); + if (obj != NULL) { + xmlXPathFreeObject(obj); + } + } while (obj != NULL); + } + + /* + * Is there another XPointer part. + */ + SKIP_BLANKS; + name = xmlXPathParseName(ctxt); + } +} + +/** + * xmlXPtrEvalChildSeq: + * @ctxt: the XPointer Parser context + * @name: a possible ID name of the child sequence + * + * ChildSeq ::= '/1' ('/' [0-9]*)* + * | Name ('/' [0-9]*)+ + * + * Parse and evaluate a Child Sequence. This routine also handle the + * case of a Bare Name used to get a document ID. + */ +static void +xmlXPtrEvalChildSeq(xmlXPathParserContextPtr ctxt, xmlChar *name) { + /* + * XPointer don't allow by syntax to address in mutirooted trees + * this might prove useful in some cases, warn about it. + */ + if ((name == NULL) && (CUR == '/') && (NXT(1) != '1')) { + xmlXPtrErr(ctxt, XML_XPTR_CHILDSEQ_START, + "warning: ChildSeq not starting by /1\n", NULL); + } + + if (name != NULL) { + valuePush(ctxt, xmlXPathNewString(name)); + xmlFree(name); + xmlXPathIdFunction(ctxt, 1); + CHECK_ERROR; + } + + while (CUR == '/') { + int child = 0; + NEXT; + + while ((CUR >= '0') && (CUR <= '9')) { + child = child * 10 + (CUR - '0'); + NEXT; + } + xmlXPtrGetChildNo(ctxt, child); + } +} + + +/** + * xmlXPtrEvalXPointer: + * @ctxt: the XPointer Parser context + * + * XPointer ::= Name + * | ChildSeq + * | FullXPtr + * + * Parse and evaluate an XPointer + */ +static void +xmlXPtrEvalXPointer(xmlXPathParserContextPtr ctxt) { + if (ctxt->valueTab == NULL) { + /* Allocate the value stack */ + ctxt->valueTab = (xmlXPathObjectPtr *) + xmlMalloc(10 * sizeof(xmlXPathObjectPtr)); + if (ctxt->valueTab == NULL) { + xmlXPtrErrMemory("allocating evaluation context"); + return; + } + ctxt->valueNr = 0; + ctxt->valueMax = 10; + ctxt->value = NULL; + ctxt->valueFrame = 0; + } + SKIP_BLANKS; + if (CUR == '/') { + xmlXPathRoot(ctxt); + xmlXPtrEvalChildSeq(ctxt, NULL); + } else { + xmlChar *name; + + name = xmlXPathParseName(ctxt); + if (name == NULL) + XP_ERROR(XPATH_EXPR_ERROR); + if (CUR == '(') { + xmlXPtrEvalFullXPtr(ctxt, name); + /* Short evaluation */ + return; + } else { + /* this handle both Bare Names and Child Sequences */ + xmlXPtrEvalChildSeq(ctxt, name); + } + } + SKIP_BLANKS; + if (CUR != 0) + XP_ERROR(XPATH_EXPR_ERROR); +} + + +/************************************************************************ + * * + * General routines * + * * + ************************************************************************/ + +static +void xmlXPtrStringRangeFunction(xmlXPathParserContextPtr ctxt, int nargs); +static +void xmlXPtrStartPointFunction(xmlXPathParserContextPtr ctxt, int nargs); +static +void xmlXPtrEndPointFunction(xmlXPathParserContextPtr ctxt, int nargs); +static +void xmlXPtrHereFunction(xmlXPathParserContextPtr ctxt, int nargs); +static +void xmlXPtrOriginFunction(xmlXPathParserContextPtr ctxt, int nargs); +static +void xmlXPtrRangeInsideFunction(xmlXPathParserContextPtr ctxt, int nargs); +static +void xmlXPtrRangeFunction(xmlXPathParserContextPtr ctxt, int nargs); + +/** + * xmlXPtrNewContext: + * @doc: the XML document + * @here: the node that directly contains the XPointer being evaluated or NULL + * @origin: the element from which a user or program initiated traversal of + * the link, or NULL. + * + * Create a new XPointer context + * + * Returns the xmlXPathContext just allocated. + */ +xmlXPathContextPtr +xmlXPtrNewContext(xmlDocPtr doc, xmlNodePtr here, xmlNodePtr origin) { + xmlXPathContextPtr ret; + + ret = xmlXPathNewContext(doc); + if (ret == NULL) + return(ret); + ret->xptr = 1; + ret->here = here; + ret->origin = origin; + + xmlXPathRegisterFunc(ret, (xmlChar *)"range-to", + xmlXPtrRangeToFunction); + xmlXPathRegisterFunc(ret, (xmlChar *)"range", + xmlXPtrRangeFunction); + xmlXPathRegisterFunc(ret, (xmlChar *)"range-inside", + xmlXPtrRangeInsideFunction); + xmlXPathRegisterFunc(ret, (xmlChar *)"string-range", + xmlXPtrStringRangeFunction); + xmlXPathRegisterFunc(ret, (xmlChar *)"start-point", + xmlXPtrStartPointFunction); + xmlXPathRegisterFunc(ret, (xmlChar *)"end-point", + xmlXPtrEndPointFunction); + xmlXPathRegisterFunc(ret, (xmlChar *)"here", + xmlXPtrHereFunction); + xmlXPathRegisterFunc(ret, (xmlChar *)" origin", + xmlXPtrOriginFunction); + + return(ret); +} + +/** + * xmlXPtrEval: + * @str: the XPointer expression + * @ctx: the XPointer context + * + * Evaluate the XPath Location Path in the given context. + * + * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. + * the caller has to free the object. + */ +xmlXPathObjectPtr +xmlXPtrEval(const xmlChar *str, xmlXPathContextPtr ctx) { + xmlXPathParserContextPtr ctxt; + xmlXPathObjectPtr res = NULL, tmp; + xmlXPathObjectPtr init = NULL; + int stack = 0; + + xmlXPathInit(); + + if ((ctx == NULL) || (str == NULL)) + return(NULL); + + ctxt = xmlXPathNewParserContext(str, ctx); + ctxt->xptr = 1; + xmlXPtrEvalXPointer(ctxt); + + if ((ctxt->value != NULL) && + (ctxt->value->type != XPATH_NODESET) && + (ctxt->value->type != XPATH_LOCATIONSET)) { + xmlXPtrErr(ctxt, XML_XPTR_EVAL_FAILED, + "xmlXPtrEval: evaluation failed to return a node set\n", + NULL); + } else { + res = valuePop(ctxt); + } + + do { + tmp = valuePop(ctxt); + if (tmp != NULL) { + if (tmp != init) { + if (tmp->type == XPATH_NODESET) { + /* + * Evaluation may push a root nodeset which is unused + */ + xmlNodeSetPtr set; + set = tmp->nodesetval; + if ((set->nodeNr != 1) || + (set->nodeTab[0] != (xmlNodePtr) ctx->doc)) + stack++; + } else + stack++; + } + xmlXPathFreeObject(tmp); + } + } while (tmp != NULL); + if (stack != 0) { + xmlXPtrErr(ctxt, XML_XPTR_EXTRA_OBJECTS, + "xmlXPtrEval: object(s) left on the eval stack\n", + NULL); + } + if (ctxt->error != XPATH_EXPRESSION_OK) { + xmlXPathFreeObject(res); + res = NULL; + } + + xmlXPathFreeParserContext(ctxt); + return(res); +} + +/** + * xmlXPtrBuildRangeNodeList: + * @range: a range object + * + * Build a node list tree copy of the range + * + * Returns an xmlNodePtr list or NULL. + * the caller has to free the node tree. + */ +static xmlNodePtr +xmlXPtrBuildRangeNodeList(xmlXPathObjectPtr range) { + /* pointers to generated nodes */ + xmlNodePtr list = NULL, last = NULL, parent = NULL, tmp; + /* pointers to traversal nodes */ + xmlNodePtr start, cur, end; + int index1, index2; + + if (range == NULL) + return(NULL); + if (range->type != XPATH_RANGE) + return(NULL); + start = (xmlNodePtr) range->user; + + if (start == NULL) + return(NULL); + end = range->user2; + if (end == NULL) + return(xmlCopyNode(start, 1)); + + cur = start; + index1 = range->index; + index2 = range->index2; + while (cur != NULL) { + if (cur == end) { + if (cur->type == XML_TEXT_NODE) { + const xmlChar *content = cur->content; + int len; + + if (content == NULL) { + tmp = xmlNewTextLen(NULL, 0); + } else { + len = index2; + if ((cur == start) && (index1 > 1)) { + content += (index1 - 1); + len -= (index1 - 1); + index1 = 0; + } else { + len = index2; + } + tmp = xmlNewTextLen(content, len); + } + /* single sub text node selection */ + if (list == NULL) + return(tmp); + /* prune and return full set */ + if (last != NULL) + xmlAddNextSibling(last, tmp); + else + xmlAddChild(parent, tmp); + return(list); + } else { + tmp = xmlCopyNode(cur, 0); + if (list == NULL) + list = tmp; + else { + if (last != NULL) + xmlAddNextSibling(last, tmp); + else + xmlAddChild(parent, tmp); + } + last = NULL; + parent = tmp; + + if (index2 > 1) { + end = xmlXPtrGetNthChild(cur, index2 - 1); + index2 = 0; + } + if ((cur == start) && (index1 > 1)) { + cur = xmlXPtrGetNthChild(cur, index1 - 1); + index1 = 0; + } else { + cur = cur->children; + } + /* + * Now gather the remaining nodes from cur to end + */ + continue; /* while */ + } + } else if ((cur == start) && + (list == NULL) /* looks superfluous but ... */ ) { + if ((cur->type == XML_TEXT_NODE) || + (cur->type == XML_CDATA_SECTION_NODE)) { + const xmlChar *content = cur->content; + + if (content == NULL) { + tmp = xmlNewTextLen(NULL, 0); + } else { + if (index1 > 1) { + content += (index1 - 1); + } + tmp = xmlNewText(content); + } + last = list = tmp; + } else { + if ((cur == start) && (index1 > 1)) { + tmp = xmlCopyNode(cur, 0); + list = tmp; + parent = tmp; + last = NULL; + cur = xmlXPtrGetNthChild(cur, index1 - 1); + index1 = 0; + /* + * Now gather the remaining nodes from cur to end + */ + continue; /* while */ + } + tmp = xmlCopyNode(cur, 1); + list = tmp; + parent = NULL; + last = tmp; + } + } else { + tmp = NULL; + switch (cur->type) { + case XML_DTD_NODE: + case XML_ELEMENT_DECL: + case XML_ATTRIBUTE_DECL: + case XML_ENTITY_NODE: + /* Do not copy DTD informations */ + break; + case XML_ENTITY_DECL: + TODO /* handle crossing entities -> stack needed */ + break; + case XML_XINCLUDE_START: + case XML_XINCLUDE_END: + /* don't consider it part of the tree content */ + break; + case XML_ATTRIBUTE_NODE: + /* Humm, should not happen ! */ + STRANGE + break; + default: + tmp = xmlCopyNode(cur, 1); + break; + } + if (tmp != NULL) { + if ((list == NULL) || ((last == NULL) && (parent == NULL))) { + STRANGE + return(NULL); + } + if (last != NULL) + xmlAddNextSibling(last, tmp); + else { + xmlAddChild(parent, tmp); + last = tmp; + } + } + } + /* + * Skip to next node in document order + */ + if ((list == NULL) || ((last == NULL) && (parent == NULL))) { + STRANGE + return(NULL); + } + cur = xmlXPtrAdvanceNode(cur, NULL); + } + return(list); +} + +/** + * xmlXPtrBuildNodeList: + * @obj: the XPointer result from the evaluation. + * + * Build a node list tree copy of the XPointer result. + * This will drop Attributes and Namespace declarations. + * + * Returns an xmlNodePtr list or NULL. + * the caller has to free the node tree. + */ +xmlNodePtr +xmlXPtrBuildNodeList(xmlXPathObjectPtr obj) { + xmlNodePtr list = NULL, last = NULL; + int i; + + if (obj == NULL) + return(NULL); + switch (obj->type) { + case XPATH_NODESET: { + xmlNodeSetPtr set = obj->nodesetval; + if (set == NULL) + return(NULL); + for (i = 0;i < set->nodeNr;i++) { + if (set->nodeTab[i] == NULL) + continue; + switch (set->nodeTab[i]->type) { + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: + case XML_ELEMENT_NODE: + case XML_ENTITY_REF_NODE: + case XML_ENTITY_NODE: + case XML_PI_NODE: + case XML_COMMENT_NODE: + case XML_DOCUMENT_NODE: + case XML_HTML_DOCUMENT_NODE: +#ifdef LIBXML_DOCB_ENABLED + case XML_DOCB_DOCUMENT_NODE: +#endif + case XML_XINCLUDE_START: + case XML_XINCLUDE_END: + break; + case XML_ATTRIBUTE_NODE: + case XML_NAMESPACE_DECL: + 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: + continue; /* for */ + } + if (last == NULL) + list = last = xmlCopyNode(set->nodeTab[i], 1); + else { + xmlAddNextSibling(last, xmlCopyNode(set->nodeTab[i], 1)); + if (last->next != NULL) + last = last->next; + } + } + break; + } + case XPATH_LOCATIONSET: { + xmlLocationSetPtr set = (xmlLocationSetPtr) obj->user; + if (set == NULL) + return(NULL); + for (i = 0;i < set->locNr;i++) { + if (last == NULL) + list = last = xmlXPtrBuildNodeList(set->locTab[i]); + else + xmlAddNextSibling(last, + xmlXPtrBuildNodeList(set->locTab[i])); + if (last != NULL) { + while (last->next != NULL) + last = last->next; + } + } + break; + } + case XPATH_RANGE: + return(xmlXPtrBuildRangeNodeList(obj)); + case XPATH_POINT: + return(xmlCopyNode(obj->user, 0)); + default: + break; + } + return(list); +} + +/************************************************************************ + * * + * XPointer functions * + * * + ************************************************************************/ + +/** + * xmlXPtrNbLocChildren: + * @node: an xmlNodePtr + * + * Count the number of location children of @node or the length of the + * string value in case of text/PI/Comments nodes + * + * Returns the number of location children + */ +static int +xmlXPtrNbLocChildren(xmlNodePtr node) { + int ret = 0; + if (node == NULL) + return(-1); + switch (node->type) { + case XML_HTML_DOCUMENT_NODE: + case XML_DOCUMENT_NODE: + case XML_ELEMENT_NODE: + node = node->children; + while (node != NULL) { + if (node->type == XML_ELEMENT_NODE) + ret++; + node = node->next; + } + break; + case XML_ATTRIBUTE_NODE: + return(-1); + + case XML_PI_NODE: + case XML_COMMENT_NODE: + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: + case XML_ENTITY_REF_NODE: + ret = xmlStrlen(node->content); + break; + default: + return(-1); + } + return(ret); +} + +/** + * xmlXPtrHereFunction: + * @ctxt: the XPointer Parser context + * @nargs: the number of args + * + * Function implementing here() operation + * as described in 5.4.3 + */ +static void +xmlXPtrHereFunction(xmlXPathParserContextPtr ctxt, int nargs) { + CHECK_ARITY(0); + + if (ctxt->context->here == NULL) + XP_ERROR(XPTR_SYNTAX_ERROR); + + valuePush(ctxt, xmlXPtrNewLocationSetNodes(ctxt->context->here, NULL)); +} + +/** + * xmlXPtrOriginFunction: + * @ctxt: the XPointer Parser context + * @nargs: the number of args + * + * Function implementing origin() operation + * as described in 5.4.3 + */ +static void +xmlXPtrOriginFunction(xmlXPathParserContextPtr ctxt, int nargs) { + CHECK_ARITY(0); + + if (ctxt->context->origin == NULL) + XP_ERROR(XPTR_SYNTAX_ERROR); + + valuePush(ctxt, xmlXPtrNewLocationSetNodes(ctxt->context->origin, NULL)); +} + +/** + * xmlXPtrStartPointFunction: + * @ctxt: the XPointer Parser context + * @nargs: the number of args + * + * Function implementing start-point() operation + * as described in 5.4.3 + * ---------------- + * location-set start-point(location-set) + * + * For each location x in the argument location-set, start-point adds a + * location of type point to the result location-set. That point represents + * the start point of location x and is determined by the following rules: + * + * - If x is of type point, the start point is x. + * - If x is of type range, the start point is the start point of x. + * - If x is of type root, element, text, comment, or processing instruction, + * - the container node of the start point is x and the index is 0. + * - If x is of type attribute or namespace, the function must signal a + * syntax error. + * ---------------- + * + */ +static void +xmlXPtrStartPointFunction(xmlXPathParserContextPtr ctxt, int nargs) { + xmlXPathObjectPtr tmp, obj, point; + xmlLocationSetPtr newset = NULL; + xmlLocationSetPtr oldset = NULL; + + CHECK_ARITY(1); + if ((ctxt->value == NULL) || + ((ctxt->value->type != XPATH_LOCATIONSET) && + (ctxt->value->type != XPATH_NODESET))) + XP_ERROR(XPATH_INVALID_TYPE) + + obj = valuePop(ctxt); + if (obj->type == XPATH_NODESET) { + /* + * First convert to a location set + */ + tmp = xmlXPtrNewLocationSetNodeSet(obj->nodesetval); + xmlXPathFreeObject(obj); + obj = tmp; + } + + newset = xmlXPtrLocationSetCreate(NULL); + if (newset == NULL) { + xmlXPathFreeObject(obj); + XP_ERROR(XPATH_MEMORY_ERROR); + } + oldset = (xmlLocationSetPtr) obj->user; + if (oldset != NULL) { + int i; + + for (i = 0; i < oldset->locNr; i++) { + tmp = oldset->locTab[i]; + if (tmp == NULL) + continue; + point = NULL; + switch (tmp->type) { + case XPATH_POINT: + point = xmlXPtrNewPoint(tmp->user, tmp->index); + break; + case XPATH_RANGE: { + xmlNodePtr node = tmp->user; + if (node != NULL) { + if (node->type == XML_ATTRIBUTE_NODE) { + /* TODO: Namespace Nodes ??? */ + xmlXPathFreeObject(obj); + xmlXPtrFreeLocationSet(newset); + XP_ERROR(XPTR_SYNTAX_ERROR); + } + point = xmlXPtrNewPoint(node, tmp->index); + } + break; + } + default: + /*** Should we raise an error ? + xmlXPathFreeObject(obj); + xmlXPathFreeObject(newset); + XP_ERROR(XPATH_INVALID_TYPE) + ***/ + break; + } + if (point != NULL) + xmlXPtrLocationSetAdd(newset, point); + } + } + xmlXPathFreeObject(obj); + valuePush(ctxt, xmlXPtrWrapLocationSet(newset)); +} + +/** + * xmlXPtrEndPointFunction: + * @ctxt: the XPointer Parser context + * @nargs: the number of args + * + * Function implementing end-point() operation + * as described in 5.4.3 + * ---------------------------- + * location-set end-point(location-set) + * + * For each location x in the argument location-set, end-point adds a + * location of type point to the result location-set. That point represents + * the end point of location x and is determined by the following rules: + * + * - If x is of type point, the resulting point is x. + * - If x is of type range, the resulting point is the end point of x. + * - If x is of type root or element, the container node of the resulting + * point is x and the index is the number of location children of x. + * - If x is of type text, comment, or processing instruction, the container + * node of the resulting point is x and the index is the length of the + * string-value of x. + * - If x is of type attribute or namespace, the function must signal a + * syntax error. + * ---------------------------- + */ +static void +xmlXPtrEndPointFunction(xmlXPathParserContextPtr ctxt, int nargs) { + xmlXPathObjectPtr tmp, obj, point; + xmlLocationSetPtr newset = NULL; + xmlLocationSetPtr oldset = NULL; + + CHECK_ARITY(1); + if ((ctxt->value == NULL) || + ((ctxt->value->type != XPATH_LOCATIONSET) && + (ctxt->value->type != XPATH_NODESET))) + XP_ERROR(XPATH_INVALID_TYPE) + + obj = valuePop(ctxt); + if (obj->type == XPATH_NODESET) { + /* + * First convert to a location set + */ + tmp = xmlXPtrNewLocationSetNodeSet(obj->nodesetval); + xmlXPathFreeObject(obj); + obj = tmp; + } + + newset = xmlXPtrLocationSetCreate(NULL); + oldset = (xmlLocationSetPtr) obj->user; + if (oldset != NULL) { + int i; + + for (i = 0; i < oldset->locNr; i++) { + tmp = oldset->locTab[i]; + if (tmp == NULL) + continue; + point = NULL; + switch (tmp->type) { + case XPATH_POINT: + point = xmlXPtrNewPoint(tmp->user, tmp->index); + break; + case XPATH_RANGE: { + xmlNodePtr node = tmp->user2; + if (node != NULL) { + if (node->type == XML_ATTRIBUTE_NODE) { + /* TODO: Namespace Nodes ??? */ + xmlXPathFreeObject(obj); + xmlXPtrFreeLocationSet(newset); + XP_ERROR(XPTR_SYNTAX_ERROR); + } + point = xmlXPtrNewPoint(node, tmp->index2); + } else if (tmp->user == NULL) { + point = xmlXPtrNewPoint(node, + xmlXPtrNbLocChildren(node)); + } + break; + } + default: + /*** Should we raise an error ? + xmlXPathFreeObject(obj); + xmlXPathFreeObject(newset); + XP_ERROR(XPATH_INVALID_TYPE) + ***/ + break; + } + if (point != NULL) + xmlXPtrLocationSetAdd(newset, point); + } + } + xmlXPathFreeObject(obj); + valuePush(ctxt, xmlXPtrWrapLocationSet(newset)); +} + + +/** + * xmlXPtrCoveringRange: + * @ctxt: the XPointer Parser context + * @loc: the location for which the covering range must be computed + * + * A covering range is a range that wholly encompasses a location + * Section 5.3.3. Covering Ranges for All Location Types + * http://www.w3.org/TR/xptr#N2267 + * + * Returns a new location or NULL in case of error + */ +static xmlXPathObjectPtr +xmlXPtrCoveringRange(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr loc) { + if (loc == NULL) + return(NULL); + if ((ctxt == NULL) || (ctxt->context == NULL) || + (ctxt->context->doc == NULL)) + return(NULL); + switch (loc->type) { + case XPATH_POINT: + return(xmlXPtrNewRange(loc->user, loc->index, + loc->user, loc->index)); + case XPATH_RANGE: + if (loc->user2 != NULL) { + return(xmlXPtrNewRange(loc->user, loc->index, + loc->user2, loc->index2)); + } else { + xmlNodePtr node = (xmlNodePtr) loc->user; + if (node == (xmlNodePtr) ctxt->context->doc) { + return(xmlXPtrNewRange(node, 0, node, + xmlXPtrGetArity(node))); + } else { + switch (node->type) { + case XML_ATTRIBUTE_NODE: + /* !!! our model is slightly different than XPath */ + return(xmlXPtrNewRange(node, 0, node, + xmlXPtrGetArity(node))); + case XML_ELEMENT_NODE: + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: + case XML_ENTITY_REF_NODE: + case XML_PI_NODE: + case XML_COMMENT_NODE: + case XML_DOCUMENT_NODE: + case XML_NOTATION_NODE: + case XML_HTML_DOCUMENT_NODE: { + int indx = xmlXPtrGetIndex(node); + + node = node->parent; + return(xmlXPtrNewRange(node, indx - 1, + node, indx + 1)); + } + default: + return(NULL); + } + } + } + default: + TODO /* missed one case ??? */ + } + return(NULL); +} + +/** + * xmlXPtrRangeFunction: + * @ctxt: the XPointer Parser context + * @nargs: the number of args + * + * Function implementing the range() function 5.4.3 + * location-set range(location-set ) + * + * The range function returns ranges covering the locations in + * the argument location-set. For each location x in the argument + * location-set, a range location representing the covering range of + * x is added to the result location-set. + */ +static void +xmlXPtrRangeFunction(xmlXPathParserContextPtr ctxt, int nargs) { + int i; + xmlXPathObjectPtr set; + xmlLocationSetPtr oldset; + xmlLocationSetPtr newset; + + CHECK_ARITY(1); + if ((ctxt->value == NULL) || + ((ctxt->value->type != XPATH_LOCATIONSET) && + (ctxt->value->type != XPATH_NODESET))) + XP_ERROR(XPATH_INVALID_TYPE) + + set = valuePop(ctxt); + if (set->type == XPATH_NODESET) { + xmlXPathObjectPtr tmp; + + /* + * First convert to a location set + */ + tmp = xmlXPtrNewLocationSetNodeSet(set->nodesetval); + xmlXPathFreeObject(set); + set = tmp; + } + oldset = (xmlLocationSetPtr) set->user; + + /* + * The loop is to compute the covering range for each item and add it + */ + newset = xmlXPtrLocationSetCreate(NULL); + for (i = 0;i < oldset->locNr;i++) { + xmlXPtrLocationSetAdd(newset, + xmlXPtrCoveringRange(ctxt, oldset->locTab[i])); + } + + /* + * Save the new value and cleanup + */ + valuePush(ctxt, xmlXPtrWrapLocationSet(newset)); + xmlXPathFreeObject(set); +} + +/** + * xmlXPtrInsideRange: + * @ctxt: the XPointer Parser context + * @loc: the location for which the inside range must be computed + * + * A inside range is a range described in the range-inside() description + * + * Returns a new location or NULL in case of error + */ +static xmlXPathObjectPtr +xmlXPtrInsideRange(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr loc) { + if (loc == NULL) + return(NULL); + if ((ctxt == NULL) || (ctxt->context == NULL) || + (ctxt->context->doc == NULL)) + return(NULL); + switch (loc->type) { + case XPATH_POINT: { + xmlNodePtr node = (xmlNodePtr) loc->user; + switch (node->type) { + case XML_PI_NODE: + case XML_COMMENT_NODE: + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: { + if (node->content == NULL) { + return(xmlXPtrNewRange(node, 0, node, 0)); + } else { + return(xmlXPtrNewRange(node, 0, node, + xmlStrlen(node->content))); + } + } + case XML_ATTRIBUTE_NODE: + case XML_ELEMENT_NODE: + case XML_ENTITY_REF_NODE: + case XML_DOCUMENT_NODE: + case XML_NOTATION_NODE: + case XML_HTML_DOCUMENT_NODE: { + return(xmlXPtrNewRange(node, 0, node, + xmlXPtrGetArity(node))); + } + default: + break; + } + return(NULL); + } + case XPATH_RANGE: { + xmlNodePtr node = (xmlNodePtr) loc->user; + if (loc->user2 != NULL) { + return(xmlXPtrNewRange(node, loc->index, + loc->user2, loc->index2)); + } else { + switch (node->type) { + case XML_PI_NODE: + case XML_COMMENT_NODE: + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: { + if (node->content == NULL) { + return(xmlXPtrNewRange(node, 0, node, 0)); + } else { + return(xmlXPtrNewRange(node, 0, node, + xmlStrlen(node->content))); + } + } + case XML_ATTRIBUTE_NODE: + case XML_ELEMENT_NODE: + case XML_ENTITY_REF_NODE: + case XML_DOCUMENT_NODE: + case XML_NOTATION_NODE: + case XML_HTML_DOCUMENT_NODE: { + return(xmlXPtrNewRange(node, 0, node, + xmlXPtrGetArity(node))); + } + default: + break; + } + return(NULL); + } + } + default: + TODO /* missed one case ??? */ + } + return(NULL); +} + +/** + * xmlXPtrRangeInsideFunction: + * @ctxt: the XPointer Parser context + * @nargs: the number of args + * + * Function implementing the range-inside() function 5.4.3 + * location-set range-inside(location-set ) + * + * The range-inside function returns ranges covering the contents of + * the locations in the argument location-set. For each location x in + * the argument location-set, a range location is added to the result + * location-set. If x is a range location, then x is added to the + * result location-set. If x is not a range location, then x is used + * as the container location of the start and end points of the range + * location to be added; the index of the start point of the range is + * zero; if the end point is a character point then its index is the + * length of the string-value of x, and otherwise is the number of + * location children of x. + * + */ +static void +xmlXPtrRangeInsideFunction(xmlXPathParserContextPtr ctxt, int nargs) { + int i; + xmlXPathObjectPtr set; + xmlLocationSetPtr oldset; + xmlLocationSetPtr newset; + + CHECK_ARITY(1); + if ((ctxt->value == NULL) || + ((ctxt->value->type != XPATH_LOCATIONSET) && + (ctxt->value->type != XPATH_NODESET))) + XP_ERROR(XPATH_INVALID_TYPE) + + set = valuePop(ctxt); + if (set->type == XPATH_NODESET) { + xmlXPathObjectPtr tmp; + + /* + * First convert to a location set + */ + tmp = xmlXPtrNewLocationSetNodeSet(set->nodesetval); + xmlXPathFreeObject(set); + set = tmp; + } + oldset = (xmlLocationSetPtr) set->user; + + /* + * The loop is to compute the covering range for each item and add it + */ + newset = xmlXPtrLocationSetCreate(NULL); + for (i = 0;i < oldset->locNr;i++) { + xmlXPtrLocationSetAdd(newset, + xmlXPtrInsideRange(ctxt, oldset->locTab[i])); + } + + /* + * Save the new value and cleanup + */ + valuePush(ctxt, xmlXPtrWrapLocationSet(newset)); + xmlXPathFreeObject(set); +} + +/** + * xmlXPtrRangeToFunction: + * @ctxt: the XPointer Parser context + * @nargs: the number of args + * + * Implement the range-to() XPointer function + */ +void +xmlXPtrRangeToFunction(xmlXPathParserContextPtr ctxt, int nargs) { + xmlXPathObjectPtr range; + const xmlChar *cur; + xmlXPathObjectPtr res, obj; + xmlXPathObjectPtr tmp; + xmlLocationSetPtr newset = NULL; + xmlNodeSetPtr oldset; + int i; + + if (ctxt == NULL) return; + CHECK_ARITY(1); + /* + * Save the expression pointer since we will have to evaluate + * it multiple times. Initialize the new set. + */ + CHECK_TYPE(XPATH_NODESET); + obj = valuePop(ctxt); + oldset = obj->nodesetval; + ctxt->context->node = NULL; + + cur = ctxt->cur; + newset = xmlXPtrLocationSetCreate(NULL); + + for (i = 0; i < oldset->nodeNr; i++) { + ctxt->cur = cur; + + /* + * Run the evaluation with a node list made of a single item + * in the nodeset. + */ + ctxt->context->node = oldset->nodeTab[i]; + tmp = xmlXPathNewNodeSet(ctxt->context->node); + valuePush(ctxt, tmp); + + xmlXPathEvalExpr(ctxt); + CHECK_ERROR; + + /* + * The result of the evaluation need to be tested to + * decided whether the filter succeeded or not + */ + res = valuePop(ctxt); + range = xmlXPtrNewRangeNodeObject(oldset->nodeTab[i], res); + if (range != NULL) { + xmlXPtrLocationSetAdd(newset, range); + } + + /* + * Cleanup + */ + if (res != NULL) + xmlXPathFreeObject(res); + if (ctxt->value == tmp) { + res = valuePop(ctxt); + xmlXPathFreeObject(res); + } + + ctxt->context->node = NULL; + } + + /* + * The result is used as the new evaluation set. + */ + xmlXPathFreeObject(obj); + ctxt->context->node = NULL; + ctxt->context->contextSize = -1; + ctxt->context->proximityPosition = -1; + valuePush(ctxt, xmlXPtrWrapLocationSet(newset)); +} + +/** + * xmlXPtrAdvanceNode: + * @cur: the node + * @level: incremented/decremented to show level in tree + * + * Advance to the next element or text node in document order + * TODO: add a stack for entering/exiting entities + * + * Returns -1 in case of failure, 0 otherwise + */ +xmlNodePtr +xmlXPtrAdvanceNode(xmlNodePtr cur, int *level) { +next: + if (cur == NULL) + return(NULL); + if (cur->children != NULL) { + cur = cur->children ; + if (level != NULL) + (*level)++; + goto found; + } +skip: /* This label should only be needed if something is wrong! */ + if (cur->next != NULL) { + cur = cur->next; + goto found; + } + do { + cur = cur->parent; + if (level != NULL) + (*level)--; + if (cur == NULL) return(NULL); + if (cur->next != NULL) { + cur = cur->next; + goto found; + } + } while (cur != NULL); + +found: + if ((cur->type != XML_ELEMENT_NODE) && + (cur->type != XML_TEXT_NODE) && + (cur->type != XML_DOCUMENT_NODE) && + (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; + } + return(cur); +} + +/** + * xmlXPtrAdvanceChar: + * @node: the node + * @indx: the indx + * @bytes: the number of bytes + * + * Advance a point of the associated number of bytes (not UTF8 chars) + * + * Returns -1 in case of failure, 0 otherwise + */ +static int +xmlXPtrAdvanceChar(xmlNodePtr *node, int *indx, int bytes) { + xmlNodePtr cur; + int pos; + int len; + + if ((node == NULL) || (indx == NULL)) + return(-1); + cur = *node; + if (cur == NULL) + return(-1); + pos = *indx; + + while (bytes >= 0) { + /* + * First position to the beginning of the first text node + * corresponding to this point + */ + while ((cur != NULL) && + ((cur->type == XML_ELEMENT_NODE) || + (cur->type == XML_DOCUMENT_NODE) || + (cur->type == XML_HTML_DOCUMENT_NODE))) { + if (pos > 0) { + cur = xmlXPtrGetNthChild(cur, pos); + pos = 0; + } else { + cur = xmlXPtrAdvanceNode(cur, NULL); + pos = 0; + } + } + + if (cur == NULL) { + *node = NULL; + *indx = 0; + return(-1); + } + + /* + * if there is no move needed return the current value. + */ + if (pos == 0) pos = 1; + if (bytes == 0) { + *node = cur; + *indx = pos; + return(0); + } + /* + * We should have a text (or cdata) node ... + */ + len = 0; + if ((cur->type != XML_ELEMENT_NODE) && + (cur->content != NULL)) { + len = xmlStrlen(cur->content); + } + if (pos > len) { + /* Strange, the indx in the text node is greater than it's len */ + STRANGE + pos = len; + } + if (pos + bytes >= len) { + bytes -= (len - pos); + cur = xmlXPtrAdvanceNode(cur, NULL); + pos = 0; + } else if (pos + bytes < len) { + pos += bytes; + *node = cur; + *indx = pos; + return(0); + } + } + return(-1); +} + +/** + * xmlXPtrMatchString: + * @string: the string to search + * @start: the start textnode + * @startindex: the start index + * @end: the end textnode IN/OUT + * @endindex: the end index IN/OUT + * + * Check whether the document contains @string at the position + * (@start, @startindex) and limited by the (@end, @endindex) point + * + * Returns -1 in case of failure, 0 if not found, 1 if found in which case + * (@start, @startindex) will indicate the position of the beginning + * of the range and (@end, @endindex) will indicate the end + * of the range + */ +static int +xmlXPtrMatchString(const xmlChar *string, xmlNodePtr start, int startindex, + xmlNodePtr *end, int *endindex) { + xmlNodePtr cur; + int pos; /* 0 based */ + int len; /* in bytes */ + int stringlen; /* in bytes */ + int match; + + if (string == NULL) + return(-1); + if (start == NULL) + return(-1); + if ((end == NULL) || (endindex == NULL)) + return(-1); + cur = start; + if (cur == NULL) + return(-1); + pos = startindex - 1; + stringlen = xmlStrlen(string); + + while (stringlen > 0) { + if ((cur == *end) && (pos + stringlen > *endindex)) + return(0); + + if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) { + len = xmlStrlen(cur->content); + if (len >= pos + stringlen) { + match = (!xmlStrncmp(&cur->content[pos], string, stringlen)); + if (match) { +#ifdef DEBUG_RANGES + xmlGenericError(xmlGenericErrorContext, + "found range %d bytes at index %d of ->", + stringlen, pos + 1); + xmlDebugDumpString(stdout, cur->content); + xmlGenericError(xmlGenericErrorContext, "\n"); +#endif + *end = cur; + *endindex = pos + stringlen; + return(1); + } else { + return(0); + } + } else { + int sub = len - pos; + match = (!xmlStrncmp(&cur->content[pos], string, sub)); + if (match) { +#ifdef DEBUG_RANGES + xmlGenericError(xmlGenericErrorContext, + "found subrange %d bytes at index %d of ->", + sub, pos + 1); + xmlDebugDumpString(stdout, cur->content); + xmlGenericError(xmlGenericErrorContext, "\n"); +#endif + string = &string[sub]; + stringlen -= sub; + } else { + return(0); + } + } + } + cur = xmlXPtrAdvanceNode(cur, NULL); + if (cur == NULL) + return(0); + pos = 0; + } + return(1); +} + +/** + * xmlXPtrSearchString: + * @string: the string to search + * @start: the start textnode IN/OUT + * @startindex: the start index IN/OUT + * @end: the end textnode + * @endindex: the end index + * + * Search the next occurrence of @string within the document content + * until the (@end, @endindex) point is reached + * + * Returns -1 in case of failure, 0 if not found, 1 if found in which case + * (@start, @startindex) will indicate the position of the beginning + * of the range and (@end, @endindex) will indicate the end + * of the range + */ +static int +xmlXPtrSearchString(const xmlChar *string, xmlNodePtr *start, int *startindex, + xmlNodePtr *end, int *endindex) { + xmlNodePtr cur; + const xmlChar *str; + int pos; /* 0 based */ + int len; /* in bytes */ + xmlChar first; + + if (string == NULL) + return(-1); + if ((start == NULL) || (startindex == NULL)) + return(-1); + if ((end == NULL) || (endindex == NULL)) + return(-1); + cur = *start; + if (cur == NULL) + return(-1); + pos = *startindex - 1; + first = string[0]; + + while (cur != NULL) { + if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) { + len = xmlStrlen(cur->content); + while (pos <= len) { + if (first != 0) { + str = xmlStrchr(&cur->content[pos], first); + if (str != NULL) { + pos = (str - (xmlChar *)(cur->content)); +#ifdef DEBUG_RANGES + xmlGenericError(xmlGenericErrorContext, + "found '%c' at index %d of ->", + first, pos + 1); + xmlDebugDumpString(stdout, cur->content); + xmlGenericError(xmlGenericErrorContext, "\n"); +#endif + if (xmlXPtrMatchString(string, cur, pos + 1, + end, endindex)) { + *start = cur; + *startindex = pos + 1; + return(1); + } + pos++; + } else { + pos = len + 1; + } + } else { + /* + * An empty string is considered to match before each + * character of the string-value and after the final + * character. + */ +#ifdef DEBUG_RANGES + xmlGenericError(xmlGenericErrorContext, + "found '' at index %d of ->", + pos + 1); + xmlDebugDumpString(stdout, cur->content); + xmlGenericError(xmlGenericErrorContext, "\n"); +#endif + *start = cur; + *startindex = pos + 1; + *end = cur; + *endindex = pos + 1; + return(1); + } + } + } + if ((cur == *end) && (pos >= *endindex)) + return(0); + cur = xmlXPtrAdvanceNode(cur, NULL); + if (cur == NULL) + return(0); + pos = 1; + } + return(0); +} + +/** + * xmlXPtrGetLastChar: + * @node: the node + * @index: the index + * + * Computes the point coordinates of the last char of this point + * + * Returns -1 in case of failure, 0 otherwise + */ +static int +xmlXPtrGetLastChar(xmlNodePtr *node, int *indx) { + xmlNodePtr cur; + int pos, len = 0; + + if ((node == NULL) || (indx == NULL)) + return(-1); + cur = *node; + pos = *indx; + + if (cur == NULL) + return(-1); + + if ((cur->type == XML_ELEMENT_NODE) || + (cur->type == XML_DOCUMENT_NODE) || + (cur->type == XML_HTML_DOCUMENT_NODE)) { + if (pos > 0) { + cur = xmlXPtrGetNthChild(cur, pos); + } + } + while (cur != NULL) { + if (cur->last != NULL) + cur = cur->last; + else if ((cur->type != XML_ELEMENT_NODE) && + (cur->content != NULL)) { + len = xmlStrlen(cur->content); + break; + } else { + return(-1); + } + } + if (cur == NULL) + return(-1); + *node = cur; + *indx = len; + return(0); +} + +/** + * xmlXPtrGetStartPoint: + * @obj: an range + * @node: the resulting node + * @indx: the resulting index + * + * read the object and return the start point coordinates. + * + * Returns -1 in case of failure, 0 otherwise + */ +static int +xmlXPtrGetStartPoint(xmlXPathObjectPtr obj, xmlNodePtr *node, int *indx) { + if ((obj == NULL) || (node == NULL) || (indx == NULL)) + return(-1); + + switch (obj->type) { + case XPATH_POINT: + *node = obj->user; + if (obj->index <= 0) + *indx = 0; + else + *indx = obj->index; + return(0); + case XPATH_RANGE: + *node = obj->user; + if (obj->index <= 0) + *indx = 0; + else + *indx = obj->index; + return(0); + default: + break; + } + return(-1); +} + +/** + * xmlXPtrGetEndPoint: + * @obj: an range + * @node: the resulting node + * @indx: the resulting indx + * + * read the object and return the end point coordinates. + * + * Returns -1 in case of failure, 0 otherwise + */ +static int +xmlXPtrGetEndPoint(xmlXPathObjectPtr obj, xmlNodePtr *node, int *indx) { + if ((obj == NULL) || (node == NULL) || (indx == NULL)) + return(-1); + + switch (obj->type) { + case XPATH_POINT: + *node = obj->user; + if (obj->index <= 0) + *indx = 0; + else + *indx = obj->index; + return(0); + case XPATH_RANGE: + *node = obj->user; + if (obj->index <= 0) + *indx = 0; + else + *indx = obj->index; + return(0); + default: + break; + } + return(-1); +} + +/** + * xmlXPtrStringRangeFunction: + * @ctxt: the XPointer Parser context + * @nargs: the number of args + * + * Function implementing the string-range() function + * range as described in 5.4.2 + * + * ------------------------------ + * [Definition: For each location in the location-set argument, + * string-range returns a set of string ranges, a set of substrings in a + * string. Specifically, the string-value of the location is searched for + * substrings that match the string argument, and the resulting location-set + * will contain a range location for each non-overlapping match.] + * An empty string is considered to match before each character of the + * string-value and after the final character. Whitespace in a string + * is matched literally, with no normalization except that provided by + * XML for line ends. The third argument gives the position of the first + * character to be in the resulting range, relative to the start of the + * match. The default value is 1, which makes the range start immediately + * before the first character of the matched string. The fourth argument + * gives the number of characters in the range; the default is that the + * range extends to the end of the matched string. + * + * Element boundaries, as well as entire embedded nodes such as processing + * instructions and comments, are ignored as defined in [XPath]. + * + * If the string in the second argument is not found in the string-value + * of the location, or if a value in the third or fourth argument indicates + * a string that is beyond the beginning or end of the document, the + * expression fails. + * + * The points of the range-locations in the returned location-set will + * all be character points. + * ------------------------------ + */ +static void +xmlXPtrStringRangeFunction(xmlXPathParserContextPtr ctxt, int nargs) { + int i, startindex, endindex = 0, fendindex; + xmlNodePtr start, end = 0, fend; + xmlXPathObjectPtr set; + xmlLocationSetPtr oldset; + xmlLocationSetPtr newset; + xmlXPathObjectPtr string; + xmlXPathObjectPtr position = NULL; + xmlXPathObjectPtr number = NULL; + int found, pos = 0, num = 0; + + /* + * Grab the arguments + */ + if ((nargs < 2) || (nargs > 4)) + XP_ERROR(XPATH_INVALID_ARITY); + + if (nargs >= 4) { + CHECK_TYPE(XPATH_NUMBER); + number = valuePop(ctxt); + if (number != NULL) + num = (int) number->floatval; + } + if (nargs >= 3) { + CHECK_TYPE(XPATH_NUMBER); + position = valuePop(ctxt); + if (position != NULL) + pos = (int) position->floatval; + } + CHECK_TYPE(XPATH_STRING); + string = valuePop(ctxt); + if ((ctxt->value == NULL) || + ((ctxt->value->type != XPATH_LOCATIONSET) && + (ctxt->value->type != XPATH_NODESET))) + XP_ERROR(XPATH_INVALID_TYPE) + + set = valuePop(ctxt); + newset = xmlXPtrLocationSetCreate(NULL); + if (set->nodesetval == NULL) { + goto error; + } + if (set->type == XPATH_NODESET) { + xmlXPathObjectPtr tmp; + + /* + * First convert to a location set + */ + tmp = xmlXPtrNewLocationSetNodeSet(set->nodesetval); + xmlXPathFreeObject(set); + set = tmp; + } + oldset = (xmlLocationSetPtr) set->user; + + /* + * The loop is to search for each element in the location set + * the list of location set corresponding to that search + */ + for (i = 0;i < oldset->locNr;i++) { +#ifdef DEBUG_RANGES + xmlXPathDebugDumpObject(stdout, oldset->locTab[i], 0); +#endif + + xmlXPtrGetStartPoint(oldset->locTab[i], &start, &startindex); + xmlXPtrGetEndPoint(oldset->locTab[i], &end, &endindex); + xmlXPtrAdvanceChar(&start, &startindex, 0); + xmlXPtrGetLastChar(&end, &endindex); + +#ifdef DEBUG_RANGES + xmlGenericError(xmlGenericErrorContext, + "from index %d of ->", startindex); + xmlDebugDumpString(stdout, start->content); + xmlGenericError(xmlGenericErrorContext, "\n"); + xmlGenericError(xmlGenericErrorContext, + "to index %d of ->", endindex); + xmlDebugDumpString(stdout, end->content); + xmlGenericError(xmlGenericErrorContext, "\n"); +#endif + do { + fend = end; + fendindex = endindex; + found = xmlXPtrSearchString(string->stringval, &start, &startindex, + &fend, &fendindex); + if (found == 1) { + if (position == NULL) { + xmlXPtrLocationSetAdd(newset, + xmlXPtrNewRange(start, startindex, fend, fendindex)); + } else if (xmlXPtrAdvanceChar(&start, &startindex, + pos - 1) == 0) { + if ((number != NULL) && (num > 0)) { + int rindx; + xmlNodePtr rend; + rend = start; + rindx = startindex - 1; + if (xmlXPtrAdvanceChar(&rend, &rindx, + num) == 0) { + xmlXPtrLocationSetAdd(newset, + xmlXPtrNewRange(start, startindex, + rend, rindx)); + } + } else if ((number != NULL) && (num <= 0)) { + xmlXPtrLocationSetAdd(newset, + xmlXPtrNewRange(start, startindex, + start, startindex)); + } else { + xmlXPtrLocationSetAdd(newset, + xmlXPtrNewRange(start, startindex, + fend, fendindex)); + } + } + start = fend; + startindex = fendindex; + if (string->stringval[0] == 0) + startindex++; + } + } while (found == 1); + } + + /* + * Save the new value and cleanup + */ +error: + valuePush(ctxt, xmlXPtrWrapLocationSet(newset)); + xmlXPathFreeObject(set); + xmlXPathFreeObject(string); + if (position) xmlXPathFreeObject(position); + if (number) xmlXPathFreeObject(number); +} + +/** + * xmlXPtrEvalRangePredicate: + * @ctxt: the XPointer Parser context + * + * [8] Predicate ::= '[' PredicateExpr ']' + * [9] PredicateExpr ::= Expr + * + * Evaluate a predicate as in xmlXPathEvalPredicate() but for + * a Location Set instead of a node set + */ +void +xmlXPtrEvalRangePredicate(xmlXPathParserContextPtr ctxt) { + const xmlChar *cur; + xmlXPathObjectPtr res; + xmlXPathObjectPtr obj, tmp; + xmlLocationSetPtr newset = NULL; + xmlLocationSetPtr oldset; + int i; + + if (ctxt == NULL) return; + + SKIP_BLANKS; + if (CUR != '[') { + XP_ERROR(XPATH_INVALID_PREDICATE_ERROR); + } + NEXT; + SKIP_BLANKS; + + /* + * Extract the old set, and then evaluate the result of the + * expression for all the element in the set. use it to grow + * up a new set. + */ + CHECK_TYPE(XPATH_LOCATIONSET); + obj = valuePop(ctxt); + oldset = obj->user; + ctxt->context->node = NULL; + + if ((oldset == NULL) || (oldset->locNr == 0)) { + ctxt->context->contextSize = 0; + ctxt->context->proximityPosition = 0; + xmlXPathEvalExpr(ctxt); + res = valuePop(ctxt); + if (res != NULL) + xmlXPathFreeObject(res); + valuePush(ctxt, obj); + CHECK_ERROR; + } else { + /* + * Save the expression pointer since we will have to evaluate + * it multiple times. Initialize the new set. + */ + cur = ctxt->cur; + newset = xmlXPtrLocationSetCreate(NULL); + + for (i = 0; i < oldset->locNr; i++) { + ctxt->cur = cur; + + /* + * Run the evaluation with a node list made of a single item + * in the nodeset. + */ + ctxt->context->node = oldset->locTab[i]->user; + tmp = xmlXPathNewNodeSet(ctxt->context->node); + valuePush(ctxt, tmp); + ctxt->context->contextSize = oldset->locNr; + ctxt->context->proximityPosition = i + 1; + + xmlXPathEvalExpr(ctxt); + CHECK_ERROR; + + /* + * The result of the evaluation need to be tested to + * decided whether the filter succeeded or not + */ + res = valuePop(ctxt); + if (xmlXPathEvaluatePredicateResult(ctxt, res)) { + xmlXPtrLocationSetAdd(newset, + xmlXPathObjectCopy(oldset->locTab[i])); + } + + /* + * Cleanup + */ + if (res != NULL) + xmlXPathFreeObject(res); + if (ctxt->value == tmp) { + res = valuePop(ctxt); + xmlXPathFreeObject(res); + } + + ctxt->context->node = NULL; + } + + /* + * The result is used as the new evaluation set. + */ + xmlXPathFreeObject(obj); + ctxt->context->node = NULL; + ctxt->context->contextSize = -1; + ctxt->context->proximityPosition = -1; + valuePush(ctxt, xmlXPtrWrapLocationSet(newset)); + } + if (CUR != ']') { + XP_ERROR(XPATH_INVALID_PREDICATE_ERROR); + } + + NEXT; + SKIP_BLANKS; +} + +#define bottom_xpointer +#include "elfgcchack.h" +#endif + diff --git a/console/griffin/griffin.c b/console/griffin/griffin.c index 9f97f4d75c..ef971816ab 100644 --- a/console/griffin/griffin.c +++ b/console/griffin/griffin.c @@ -96,6 +96,14 @@ CONFIG FILE #include "../../conf/config_file.c" #endif +/*============================================================ +CHEATS +============================================================ */ +#ifdef HAVE_XML +#include "../../cheats.c" +#include "../../hash.c" +#endif + /*============================================================ VIDEO CONTEXT ============================================================ */ @@ -137,6 +145,8 @@ VIDEO IMAGE #include "../../ps3/image.c" #elif defined(_XBOX1) #include "../../xbox1/image.c" +#elif defined(ANDROID) +#include "../../gfx/image.c" #endif /*============================================================ diff --git a/console/griffin/hook.h b/console/griffin/hook.h index ff750a166d..30af7ee275 100644 --- a/console/griffin/hook.h +++ b/console/griffin/hook.h @@ -58,6 +58,7 @@ #define video_set_aspect_ratio_func(aspectratio_idx) gfx_ctx_set_aspect_ratio(driver.video_data, aspectratio_idx) #define video_stop_func() gl_stop() #define video_start_func() gl_start() +#define video_set_shader_func(type, path) gl_set_shader(driver.video_data, type, path) #define gfx_ctx_window_has_focus() (true)